← Files FactIQARCHIVED FILE
evals/mocks/factiq/_tools.json
57.2 KB · Nov 2, 2026 · 12:30 UTC
{
"tools": [
{
"name": "get_data_catalog",
"description": "List the data sources FactIQ has, plus the shared table structure.\n\nCall this once before exploring. Returns the visible schemas (organization +\ncountry), the ones with no data loaded yet (`schemas_without_data` — skip\nthem), a per-schema dataset index, and the shared DDL for the `series`,\n`data_points`, `dimensions` and `compound_series` tables.\n\nschemas: optional comma-separated filter (e.g. \"bls,bea\").\nfull: heavy per-dataset descriptions instead of the compact index.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"schemas": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"full": {
"default": false,
"type": "boolean"
}
},
"type": "object"
}
},
{
"name": "search_datasets",
"description": "Find datasets by keyword across every schema — the first discovery step.\n\nKeyword ranking (not semantic) over dataset titles and topics. Returns ranked\n{schema, dataset_code, title, topic}. Follow up with `describe_dataset` for\ndetail, or `run_sql` on the series/dimensions tables for exact series.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"query": {
"type": "string"
},
"schemas": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null
},
"limit": {
"default": 15,
"type": "integer"
}
},
"required": [
"query"
],
"type": "object"
}
},
{
"name": "describe_dataset",
"description": "Full metadata for one dataset: topic, methodology, discontinuities,\nany base-change notice, plus the live dimensions and example series.\nCall after `search_datasets` narrows you to a dataset.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"schema": {
"type": "string"
},
"dataset_code": {
"type": "string"
}
},
"required": [
"schema",
"dataset_code"
],
"type": "object"
}
},
{
"name": "search_series",
"description": "Find series in one schema by title terms (substring match, not semantic).\n\nSupply already-decomposed terms; prefer short stems (e.g. \"rare\" over \"rare\nearth\"). Includes active COMPOUND:: series. For anything this misses, fall\nback to `run_sql` exploration on the `series` and `dimensions` tables.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"schema": {
"type": "string"
},
"terms": {
"items": {
"type": "string"
},
"type": "array"
},
"limit": {
"default": 15,
"type": "integer"
},
"include_compound": {
"default": true,
"type": "boolean"
}
},
"required": [
"schema",
"terms"
],
"type": "object"
}
},
{
"name": "search_company_filings",
"description": "This is FactIQ's central tool for company filings. It searches structured\nfacts and report metadata from one company's filed reports, for every company\nin the filings store: US SEC filers (10-K, 10-Q, 8-K, plus 20-F, 40-F, 6-K\nfor foreign filers) and companies listed in Germany, the UK and France\n(annual, half-year, Q1, and Q3 reports; for example company=\"BAS\" for BASF SE\nfrom German issuer reports in EUR, company=\"ULVR\" for Unilever plc from the\nFCA National Storage Mechanism, and company=\"MC\" for LVMH from the AMF via\ninfo-financiere.gouv.fr; UK values are in the issuer's reporting currency,\nGBP, USD or EUR, and French values in EUR). The search is deterministic and does not call a language model. Every\nsuccessful response is a tree and does not expose database row IDs. Set\nformat=\"json\" for the structured tree field. Set format=\"pretty\" for only a\nhuman-readable rendered_tree text. The two formats are never returned together.\nJSON filing and fact nodes retain source_url and add a standardized source_link\nobject for the original filing/report; the pretty rendering ends with a\n\"Source documents\" list mapping each cited filing to its URL. When using a\nreturned figure, place its source URL beside the claim as a Markdown link, for\nexample: FY2025 revenue was $40.0B\n([Visa Inc. FY2025 10-K](https://www.sec.gov/Archives/...)). A sources line\nthat names the filing without linking its URL is not sufficient. Do not make\na second call solely to find a citation or substitute a related press release.\nsource_precision=\"document\" means the URL opens the source document, not an\nexact passage.\n\nUse an exact ticker when possible. A company name is accepted only when it\nidentifies one issuer. A share-class sibling ticker resolves to the same SEC\nfiler (for example GOOGL resolves to the stored GOOG). If a ticker has several\nexact matches, possible_matches lists every tied company and its identifiers.\nWhen nothing matches, possible_matches lists the closest stored companies.\n\nconcept selects one registered financial concept and returns it over time. For\nexample, concept=\"revenue\" selects the best revenue concept stored for that\ncompany. The response states the selected concept. Use query instead for a\nbroad search across several concepts.\n\nsearch_target controls the tree content. coverage shows available report types\nand dates. filings shows report records and source URLs. metrics shows available\nconcepts, dimensions, units, and period coverage. facts shows reported numeric\nvalues. An empty facts browse is filing-first. A facts search with query or\nconcept is concept-first so that values across reporting periods stay together.\n\ncommentary and risk_changes return qualitative statements extracted from SEC\nfilings when each filing was processed; every statement carries a verbatim\nquote from the filing. commentary returns management's explanatory statements\nfrom MD&A sections and earnings press releases: growth drivers, demand and\npricing commentary, capacity and execution milestones, strategy changes, and\nvaguely quantified statements such as \"grew mid-teens\" with a numeric range\nattached. risk_changes returns year-over-year changes in the stated risk\nfactors of annual reports (Item 1A or Item 3.D): new, modified, and removed\nrisks, with the changed passage quoted. A period with no risk_changes rows\nmeans the risk factors were unchanged from the prior year or that filing is\nnot yet processed — never that the company reported no risks. Both targets\ncover US SEC filers only; commentary and risk_changes remain SEC-only and\nreturn no rows for German, UK, or French issuer reports.\n\nquery searches concept names, source labels, source codes, XBRL concepts,\naliases, definitions, and segment names. For commentary and risk_changes it\nsearches topics, statements, and quotes. Filters are applied before search.\nreport_type accepts a common report type (annual, quarterly, half_year) or a\nsource form such as 10-K or 10-Q. For German, UK, and French filers,\nquarterly covers the Q1, half-year, and Q3 reports; their source forms are\nthe document codes of the source (FCA ACS, FR, IR; AMF AMF-RFA, AMF-RFS,\nAMF-IT, AMF-URD, AMF-RES).\nfiscal_year and fiscal_period accept company reporting labels such as 2026 and\nQ3. Earnings 8-Ks take their quarter from the 10-Q or 10-K whose period ended\nwithin the 80 days before the 8-K, and keep the 8-K filing date as the\nreported date. A freshly announced 8-K whose periodic filing has not arrived\nyet carries a quarter estimated from the company's fiscal calendar, replaced\nby the exact period when the filing lands. If neither is available, the tool\nomits the fiscal label instead of guessing.\n\nSome companies file the same concept twice for one period and segment — for\nexample a gross segment total next to a net-of-eliminations figure. Both are\nserved: the extra line is its own series node whose name ends in \"(reported\nline 2)\", and its evidence_note says so. The two lines are alternative\nstatements of the same item. Never add a \"reported line 2\" series to its\nordinary counterpart — that double-counts.\n\nFor non-admin callers, active_only is always enforced by the tool endpoint.\nWith active_only enabled, every target is limited to facts currently marked\nactive and serving; coverage and filings omit reports with no such facts.\n\nIf an exact-ticker metrics or facts request has no matching serving data, the\ntool falls back to Twelve Data standardized consolidated statements. A resolved\nissuer listed in Germany, the UK, or France is sent to the vendor with its\nexchange suffix (.DE, .L, .PA) appended to a bare stored ticker; a stored\nticker that already carries the suffix (MC.PA) is sent as is. Company names\nand bare tickers without a resolved issuer remain filings-database-only so\nvendor data cannot be attributed to a different issuer with the same ticker.\nA request that names no report_type or fiscal_period tries quarterly statements\nand then annual, so\nannual-only vendor coverage still answers. A concept the filings database\nalready holds is never answered from the vendor, even when the other filters\nleave no rows. Fallback values carry no filing-document, source-page, or\nsegment evidence. coverage, filings, and segment-filtered requests remain\nfilings-database-only.\n",
"inputSchema": {
"additionalProperties": false,
"properties": {
"company": {
"description": "Required company identifier. Use an exact ticker, full company name, LEI, or another stored identifier. A share-class sibling ticker such as GOOGL resolves to the same SEC filer as the stored GOOG. A company listed in Germany, the UK, or France resolves by its local ticker (BAS for BASF SE, ULVR for Unilever plc, MC for LVMH), full name, or LEI; when a bare symbol also belongs to a US filer the stored ticker carries the exchange suffix (MC.PA, BA.L). A tied ticker match returns every possible company instead of selecting one.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"query": {
"default": "",
"description": "Broad lexical search across concept names, labels, codes, aliases, definitions, and segment names. For commentary and risk_changes it searches statement topics, summaries, and verbatim quotes. It applies to every target except coverage. Normally leave it empty when concept is set.",
"maxLength": 500,
"type": "string"
},
"concept": {
"anyOf": [
{
"maxLength": 200,
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "One requested metric, such as Revenue. The tool selects the best stored concept for this company, reports what it selected, and returns that concept across periods. Valid only for metrics or facts."
},
"search_target": {
"default": "facts",
"description": "Result type. coverage shows available report dates, types, and metric classes. filings shows report records and source URLs. metrics shows available concepts and series. facts shows numeric reported values. commentary shows management's qualitative statements from MD&A sections and earnings press releases. risk_changes shows year-over-year risk-factor changes from annual reports; no rows for a year means unchanged risk factors, not no risks.",
"enum": [
"coverage",
"filings",
"metrics",
"facts",
"commentary",
"risk_changes"
],
"type": "string"
},
"report_type": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional report filter for every target except coverage. Accepts a common type such as annual, quarterly, or half_year, or a source form such as 10-K or 10-Q (or a source document code such as ACS, FR, IR, AMF-RFA, AMF-RES). For German, UK, and French filers, quarterly covers Q1, half-year, and Q3 reports. For commentary and risk_changes, annual covers 10-K and 20-F, quarterly covers 10-Q, and current covers 8-K."
},
"fiscal_year": {
"anyOf": [
{
"maximum": 2200,
"minimum": 1900,
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional company fiscal-year label, such as 2026. It applies to filings, metrics, and facts."
},
"fiscal_period": {
"anyOf": [
{
"maxLength": 40,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional company fiscal-period label, such as Q1, Q2, Q3, Q4, or FY. It applies to filings, metrics, and facts."
},
"metric_class": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional metric class for metrics or facts, such as financial, ifrs, segment, kpi, or apm. Matching ignores letter case, so Product and product select the same facts."
},
"segment": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional case-insensitive filter for a business segment, product, region, dimension member, dimension axis, or source label. It applies to metrics and facts."
},
"date_from": {
"anyOf": [
{
"format": "date",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional inclusive earliest period-end date for filings, metrics, or facts."
},
"date_to": {
"anyOf": [
{
"format": "date",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional inclusive latest period-end date for filings, metrics, or facts."
},
"active_only": {
"default": true,
"description": "Return only current serving facts. This is always enforced for non-admin users; admins may set false to inspect inactive rows. When true, coverage and filings also omit reports with no serving facts.",
"type": "boolean"
},
"format": {
"default": "json",
"description": "Response form for a successful tree result. json returns only the JSON tree. pretty returns only readable rendered_tree text. The forms are never combined.",
"enum": [
"json",
"pretty"
],
"type": "string"
},
"limit": {
"default": 20,
"description": "Maximum matched rows before tree grouping. For facts, each numeric observation is one row, so one series with many periods uses many rows — filter by period, metric class, or segment instead of raising the limit. The range is 1 to 50 and the default is 20. For coverage, it limits the latest filing records.",
"maximum": 50,
"minimum": 1,
"type": "integer"
}
},
"required": [
"company"
],
"type": "object"
}
},
{
"name": "get_series",
"description": "Fetch one series' data: timeseries, tabular, or COMPOUND:: all work.\n\nReturns title, units, frequency, notes and data points, with source metadata.\n`transform=\"yoy_pct\"` (percent change) or `\"yoy_diff\"` (difference, for rates)\nadds a column with the change versus the same period one year earlier,\nmatched by calendar date — use it for inflation or growth from one series\ninstead of a `LAG(value, 12)` query, which goes wrong after any missing\nmonth. The cell is null where the prior-year period is absent, and\n`transform.periods_without_prior` lists those periods.\nIf the result carries a `coverage_note`, the series has periods with no\nobservation (listed in `missing_periods`): say so in the answer, leave them\nblank rather than interpolating, and label any aggregate that spans them\nas partial.\nSEC-backed results include `row_sources` keyed by `result_index`; each entry\nidentifies the supporting filing, accession/form/publication date, whether\nthe observation is reported or derived, and its standardized `source_link`.\nCite that row's source URL beside any figure and label derived observations\nas derived. A document-precision link does not open an exact passage.\nAt most 50 points come back; if the series is longer the result is flagged\n`\"truncated\": true` — narrow it with `from_year`/`to_year`, or pull the series\nthrough `run_sql` with an aggregation (e.g. monthly/quarterly via\n`date_trunc`) rather than trying to fetch every point.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"schema": {
"type": "string"
},
"series_id": {
"type": "string"
},
"from_year": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null
},
"to_year": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null
},
"transform": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
}
},
"required": [
"schema",
"series_id"
],
"type": "object"
}
},
{
"name": "run_sql",
"description": "Run a read-only SELECT against the FactIQ data warehouse, scoped to one\nschema — the power tool for joins, pivots and aggregation.\n\nRead-only role, 30s statement timeout, with FactIQ's query transforms and\nseries-metadata enrichment. Resolve ids from `series` before filtering\n`data_points`. `auto_retry=true` opts into a server-side reviser on zero\nrows. See the `factiq://guide/sql` resource.\n\nReturns at most 50 rows. If the query matches more, the result is flagged\n`\"truncated\": true` — that is your cue to **aggregate or compute in SQL**\n(`GROUP BY`, `date_trunc`, a SUM/AVG/rank/ratio) and return that, NOT to try\nto fetch the raw rows. A chart or a summary needs the aggregated result, and\nlarge raw results don't fit in context anyway.\n\nYear-over-year and other period comparisons must join on the calendar\nperiod (`date_trunc('month', prior.time) = date_trunc('month', cur.time) -\ninterval '1 year'` — the stored day of the month varies by source, so never\ncompare exact dates), never on a row offset such as\n`LAG(value, 12) OVER (ORDER BY time)`: a series with one missing month\ncompares the wrong periods for the twelve rows after the gap (LEAD: the\ntwelve before it) and the numbers still look plausible. For one series prefer `get_series` with `transform`. When\nthe result carries a `coverage_note`, the rows have periods with no\nobservation (listed in `missing_periods`, per series): name them in the\nanswer, do not interpolate, and label any aggregate that spans them as\npartial.\n\n`page` is the one exception and works only on the `nasa_fires` schema, where\na row is a single fire detection that belongs to no series and so cannot be\naggregated into one. Each page holds 50 rows; the answer carries `page` and\n`has_more`, and you read the next block with `page=2`, `page=3` and so on.\nGive the query an ORDER BY, otherwise Postgres may return the same row on\ntwo pages and never return another. Still prefer a count or a total when\nthat answers the question — paging through thousands of detections does not.\n\nRuns through FactIQ's read-only database role, which rejects any attempt to\nmodify data (INSERT/UPDATE/DELETE/DROP/…).",
"inputSchema": {
"additionalProperties": false,
"properties": {
"schema": {
"type": "string"
},
"sql": {
"type": "string"
},
"question": {
"default": "",
"type": "string"
},
"explore": {
"default": false,
"type": "boolean"
},
"auto_retry": {
"default": false,
"type": "boolean"
},
"page": {
"default": 1,
"type": "integer"
}
},
"required": [
"schema",
"sql"
],
"type": "object"
}
},
{
"name": "get_market_data",
"description": "Recent market data the warehouse lags on: quotes, OHLCV, company\nprofiles, FX, and commodities.\n\nSet data_type to price_history for stocks, currency pairs, and commodities;\nthe asset format determines which market is queried. Use\nsearch_company_filings for financial statements and reported facts.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"asset": {
"description": "Ticker, currency pair, commodity, or company-search text. Examples: \"AAPL\", \"EUR/USD\", \"WTI\", \"Brent\", \"NVIDIA\".",
"type": "string"
},
"data_type": {
"default": "price_history",
"description": "The market or profile data to return.",
"enum": [
"price_history",
"quote",
"company_profile",
"etf_profile",
"symbol_search"
],
"type": "string"
},
"frequency": {
"default": "daily",
"description": "Price-history frequency. Defaults to daily.",
"enum": [
"daily",
"weekly",
"monthly"
],
"type": "string"
},
"limit": {
"default": 100,
"description": "Maximum number of historical price rows to request.",
"maximum": 5000,
"minimum": 1,
"type": "integer"
}
},
"required": [
"asset"
],
"type": "object"
}
},
{
"name": "get_geo_data",
"description": "Get satellite-derived indicators aggregated over a country, one\nstate/province, or a bounding box. Use for fires, emissions-based activity,\nrainfall, vegetation, temperature, and soil-moisture questions.\n\nFor a sub-national area, call one state/province at a time. Informal regions\nsuch as \"north India\" or \"the Midwest\" have no boundary, so cover them with\none call per state or a bounding box; using the whole country answers a\ndifferent question. Grid cells and fire detections are activity snapshots,\nnever fire perimeters. For ndvi_s2 and *_tropomi grids, drop or flag cells\nwith low valid_obs_share. Results include units, source attribution, and\ncaveats; cite the attribution. External-provider calls can take about 30\nseconds, and rainfall or grid calls can take longer.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"dataset": {
"description": "Satellite dataset. One of:\n- \"fires_viirs\": active fire detections and fire radiative power (NASA FIRMS, 2012->, one day behind). Covers crop-residue burning, forest fires, and flaring.\n- \"no2_tropomi\": tropospheric NO2 column (Sentinel-5P, 2018->, ~3 days), an industrial/traffic activity proxy. Check valid_obs_share; cloudy intervals below 0.2 are weakly supported.\n- \"so2_tropomi\": SO2 column (Sentinel-5P, 2018->, ~3 days) for coal power, smelting, refining, and volcanoes. Noisy away from strong sources; track trends rather than absolute background levels.\n- \"co_tropomi\": CO column (Sentinel-5P, 2018->, ~3 days) for biomass/crop burning and industrial combustion. CO drifts across borders and is seasonal, so compare the same season across years.\n- \"aerosol_index_tropomi\": UV aerosol index (Sentinel-5P, 2018->, ~3 days) for smoke, dust, and haze. It is dimensionless; sustained values above ~1 indicate heavy smoke or dust, and it works over clouds.\n- \"ndvi_s2\": cloud-masked vegetation NDVI (Sentinel-2, 2017->, ~2-5 days), a crop-condition signal. Check valid_obs_share and compare the same season across years.\n- \"precip_chirps\": gauge-calibrated rainfall (CHIRPS, 1981->, ~2 days, 50S-50N) for monsoon, drought, and flood risk.\n- \"precip_imerg\": rainfall totals (NASA IMERG V07 Late, 2000->, ~1-2 days, global at 0.1 degree). Use where CHIRPS has no coverage; daily and monthly values are rainfall totals.\n- \"temperature_power\": mean/max/min 2m air temperature (NASA POWER, 1981->, ~3 days) for heatwaves and energy demand.\n- \"soil_moisture_power\": root-zone soil wetness from 0 to 1 (NASA POWER, 1981->, ~3 days) for agricultural drought.",
"type": "string"
},
"region": {
"description": "Region as an ISO3 code or country name (\"IND\" or \"India\"); \"Country/State\" or \"ISO3/State\" (\"India/Punjab\" or \"CHN/Guangdong\") for a state/province; or \"bbox:west,south,east,north\" in degrees. State/province boundaries are available for IND, CHN, IDN, VNM, THA, MYS, PHL, PAK, BGD, LKA, MMR, KHM, NPL, KOR, JPN, TWN, and USA.",
"type": "string"
},
"start_date": {
"description": "Inclusive start date in ISO YYYY-MM-DD format.",
"type": "string"
},
"end_date": {
"description": "Inclusive end date in ISO YYYY-MM-DD format.",
"type": "string"
},
"aggregation": {
"default": "monthly",
"description": "Aggregation mode. \"monthly\" (default) or \"daily\" returns a time series. Most datasets allow at most 50 intervals per call (~4 years monthly or ~7 weeks daily); fires_viirs allows 200 (~16 years monthly or ~7 months daily). fires_viirs, ndvi_s2, and *_tropomi also accept \"grid\": one spatial row per lat/lon cell over the whole window, at most 500 rows, with a 92-day maximum window (366 days for fires). fires_viirs also accepts \"seasons\", which repeats the requested calendar window in every year since 2012 and returns one row per year, and \"points\", which returns exact detections only when the window contains at most 500; otherwise use grid or narrow the window.",
"type": "string"
},
"resolution": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional fires_viirs grid-cell size in degrees when aggregation=\"grid\"; one of 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, or 5. Omit it to choose a size automatically from the region. Values finer than 0.1 read individual detections and return the 500 busiest cells. Not accepted by other datasets or aggregation modes."
},
"include_flares": {
"default": false,
"description": "fires_viirs only. False by default, excluding gas flares, other permanent industrial heat sources, volcanoes, and offshore detections so only vegetation fires are counted. Set true over a gas field or to count every detection NASA publishes.",
"type": "boolean"
}
},
"required": [
"dataset",
"region",
"start_date",
"end_date"
],
"type": "object"
}
},
{
"name": "search_earnings_transcripts",
"description": "Search earnings-call intelligence from live calls,\ndecomposed into atomic, quote-anchored claims and Q&A pressure points — never\na raw transcript dump.\n\nRetrieval for \"claims\" and \"pressure_points\" is lexical, not semantic. A\nnonempty query uses an OR-of-tokens full-text candidate set; strict\nwebsearch_to_tsquery matches receive a fixed ranking boost, so strict matches\nrank ahead of loose partial-term matches. Lower-ranked rows may match only\nsome query terms. If that filtered full-text search returns no rows, a trigram\nfallback handles typos and sub-word variants. Quoted phrases use websearch\nsyntax, but synonyms are not inferred: try the company's own vocabulary\n(\"capex\" and \"capital expenditure\", segment names, abbreviations). An empty\nor partial result is not proof that management did not discuss a topic;\ncoverage and vocabulary both matter.\n\nTarget and filter semantics:\n- \"claims\" (default) searches or browses normalized management/analyst claim\n rows. ticker, quarter_filter, claim_family, section, detail, and\n limit apply. claim_family matches primary or secondary families; section is\n \"prepared_remarks\" or \"qa\". Base rows include direction/value/unit where\n checkable, assertion_status, canonical_statement, verbatim_quote, speaker,\n speaker_role, section, transcript_id, source_block_index, qa_turn_id, and a\n source_link object.\n- \"pressure_points\" searches or browses what analysts pressed for and whether\n management confirmed, declined, deflected, or partially answered. ticker,\n quarter_filter, claim_family (the linked family), detail, and limit apply.\n section is ignored because every pressure point is from Q&A. Base rows\n include specific_ask, response_quality, refused_number, linked_family,\n linked_claim_id, verbatim_quote, transcript_id, source_block_index,\n qa_turn_id, and a source_link object.\n- \"disclosure_profile\" is a direct company lookup, not text search. The ticker\n is the first ticker value, or query when ticker is empty.\n Profiles are curated separately from transcript coverage, so a covered company\n may not have one; availability is \"available\" or \"unavailable\" accordingly.\n quarter_filter, claim_family, section, detail, and limit do not narrow it.\n- \"coverage\" is corpus inventory, not text search. ticker and limit\n apply; query, quarter_filter, claim_family, section, and detail do not narrow\n it. Rows report calls_covered, earliest_period, latest_period,\n latest_call_date, claims, and pressure_points.\n\nAn empty query is a capped browse, not a completeness guarantee. Rows are\nordered by newest fiscal period/call and then source-block (spoken) order\nwithin one call. Every response is limited to at most 50 rows, and a browse\nthat reaches its limit may omit additional rows even if no truncation flag is\npresent. For a latest-call note: (1) call \"coverage\" with one ticker, (2) read\nlatest_period, (3) call \"claims\" with that ticker, quarter_filter=latest_period,\nquery=\"\", detail=true, and a deliberate limit, then (4) call\n\"pressure_points\" with the same ticker and quarter. Treat both browses as\ncapped evidence, not a complete transcript. Narrow large result sets with\nticker, quarter, target, claim_family, and (for claims) section; the restricted\n`transcripts` schema cannot be queried through run_sql.\n\nEvidence rules: canonical_statement is normalized and must not be quoted as\nverbatim. Quote only verbatim_quote, with its speaker, role, ticker, and fiscal\nperiod. A […] inside verbatim_quote marks omitted transcript sentences between\nnon-adjacent evidence spans: preserve it exactly when quoting, and never\npresent text on either side of it as one continuous statement. When a quote is used, render source_link.source_label as the Markdown\nlink text for source_link.source_url beside the claim. The label names the\ncompany, fiscal period, and earnings call transcript; never replace it with an\ningestion vendor. Do not make a second call just to find a citation, do not\ninvent a replacement when source_url is null, and do not call a document-level\nlink exact context. source_locator still identifies the stored transcript block\nor Q&A turn. assertion_status is load-bearing: analyst_hypothesized is the\nanalyst's framing, while mgmt_declined_to_confirm is a refusal, not a management\nassertion. Spoken call claims are a different source class from filed XBRL\nactuals (`run_sql` on the `sec` schema) and formally issued targets (the\n`sec_guidance` dataset); label them separately.\n\nExamples:\n- Latest call: search_earnings_transcripts(query=\"\", search_target=\"coverage\",\n ticker=\"MU\"), then repeat with search_target=\"claims\",\n quarter_filter=<latest_period>, detail=true, limit=50, and finally with\n search_target=\"pressure_points\" for the same ticker and quarter.\n- Cross-company theme: search_earnings_transcripts(query=\"capital expenditure\n capacity\", search_target=\"claims\", ticker=\"MU,NVDA\", detail=true);\n inspect each returned row for topical support, do not assume every term\n matched, and retry vocabulary as needed.\n- Disclosure habits: search_earnings_transcripts(query=\"\",\n search_target=\"disclosure_profile\", ticker=\"MU\").\n\nclaim_family codes: driver_attribution, forward_conviction, prior_view_revision, strategic_agreement, pricing_mechanics, demand_magnitude, capacity_milestone, competitive_positioning, cohort_behavior, cost_margin_bridge, capital_allocation, stated_risk_constraint, qa_dynamics, regulatory_policy, pipeline_backlog, commodity_hedging, ma_deal, labor_org.\nTopic paths (topic_path column) are rooted at: demand, supply_capacity, pricing, cost_margin, capital, competition, customer, product_roadmap, risk, governance.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"query": {
"default": "",
"description": "For claims/pressure_points: lexical websearch text; strict matches rank above loose partial-term matches, with trigram fallback only when FTS returns no rows. Empty text browses capped rows. For disclosure_profile, it can supply the ticker when ticker is empty. Ignored by coverage.",
"type": "string"
},
"search_target": {
"default": "claims",
"description": "claims or pressure_points perform lexical retrieval/browse; disclosure_profile is a direct company lookup; coverage is corpus inventory.",
"enum": [
"claims",
"pressure_points",
"disclosure_profile",
"coverage"
],
"type": "string"
},
"ticker": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Ticker, or a comma-separated list of tickers, for claims, pressure_points, and coverage; case-insensitive. Company names belong in company_name; pass only one of the two. A name passed here is still read as a name when it fits a stored company, and the response says so. The response lists possible matches for a value that is not in the transcript corpus. disclosure_profile uses only the first ticker."
},
"company_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Company name, or a comma-separated list of names, for claims, pressure_points, and coverage; case-insensitive ('nvidia', 'HP Inc', 'Ford Motor'). Each name resolves to the stored ticker(s) that match it best; the response reports the resolution and lists possible matches for a name that resolved to nothing. Pass either company_name or ticker, not both. disclosure_profile uses only the first resolved ticker."
},
"quarter_filter": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Exact fiscal period such as FY2026Q3; applies to claims and pressure_points. Ignored by disclosure_profile and coverage. Pin this after coverage for a single-call browse."
},
"claim_family": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Claim-family code. Matches primary/secondary families on claims and the linked family on pressure_points; ignored by disclosure_profile and coverage."
},
"section": {
"anyOf": [
{
"enum": [
"prepared_remarks",
"qa"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "prepared_remarks or qa; applies only to claims. Ignored for pressure_points because those rows are all Q&A, and ignored by lookup/inventory targets."
},
"detail": {
"default": false,
"description": "For claims, add structured_fields, secondary_families, period, time_horizon, conviction_qualifier, denominator, and falsifiable; for pressure_points, add tone_note. Ignored by disclosure_profile and coverage. The extractor's quantified flag is not published: it only records that the extractor wrote something into value, which the caller can already see in value itself.",
"type": "boolean"
},
"limit": {
"default": 15,
"description": "Maximum 1-50 rows (default 15). This is a hard cap, not proof the result is complete; narrow by ticker, quarter, target, family, and claims section.",
"maximum": 50,
"minimum": 1,
"type": "integer"
},
"company_filter": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Deprecated alias of ticker, kept for clients installed before the parameter was renamed. Pass ticker instead."
}
},
"type": "object"
}
},
{
"name": "search_media_appearances",
"description": "Deterministically search precomputed intelligence from\ncompany executives' podcasts, TV interviews, and conference appearances outside\nearnings calls. No serving-time model interprets or expands the query.\n\nRetrieval for structured findings is lexical, not semantic: strict full-text\nmatching is tried first, loose any-term full-text matching only when strict\nmatching returns no candidates, then trigram matching only when both full-text\nstages are empty. Natural-language questions work because person names and\ncommon question scaffolding are normalized. Prefer concise topical terms; retry\nsynonyms or the speaker's own vocabulary before concluding there is no coverage.\n\nCanonical search_target values:\n- \"search\" (default): blended structured claims and broad passage cards.\n- \"claims\": normalized decision-relevant claims only.\n- \"passages\": broad substantive paraphrase cards only.\n- \"pressure_points\": stored refusal and declined-to-confirm claim rows.\n- \"appearances\": video-level catalog rows.\n- \"coverage\": company-level structured-corpus inventory.\n\nCompatibility aliases remain accepted for older clients: \"all\" maps to\n\"search\", \"videos\" to \"appearances\", and \"companies\" to \"coverage\". New\ncallers should use the six canonical values; \"search\" is the primary blended\ntarget, not a legacy alias.\n\nResult contracts:\n- search/claims/passages/pressure_points return result_kind, canonical_paraphrase,\n speaker, primary ticker, topic labels, video/channel/publication metadata,\n lexical relevance, and source_url (a timestamped YouTube deep link, or the\n episode page for a podcast). detail=true adds normalized\n claim and attribution fields but never raw transcript text or evidence spans.\n- appearances returns video metadata, primary ticker, attribution metadata,\n matching claim count, URL, and relevance score. detail has no effect.\n- coverage returns company-level appearance, publication-date-span, channel,\n claim, and low-confidence-attribution counts. It is structured coverage, not\n a per-person acquired-video/hour inventory; query, sort, and detail have no\n effect.\n\nFilter and ordering semantics:\n- company_filter is comma-separated exact primary tickers for structured\n findings. Catalog targets also match exact stored entity-reference tokens.\n- person is a case-insensitive substring over the finding speaker and/or\n appearance speaker metadata. appearance_type applies to every target.\n- claim_family restricts structured claims. With blended search it suppresses\n passage cards; pairing it with search_target=\"passages\" is an error. For\n appearances/coverage it requires videos with matching structured claims.\n- date_from/date_to are inclusive YYYY-MM-DD bounds on the video's stored\n publication/upload date, which can differ from the recording or event date.\n- relevance orders lexical score first, then publication date; newest orders\n publication date first, then lexical score. Coverage has fixed inventory\n ordering by latest covered publication date.\n\nWith an empty query, search and claims browse recent high-signal claims without\ngeneric passage cards; passages browses recent passage cards; pressure_points\nbrowses recent refusal rows; appearances browses the video catalog; coverage\nreturns the company inventory. Each result set is capped at 1-50 rows.\n\nEvidence safety: canonical_paraphrase is a normalized paraphrase, not a\ntranscript quotation. Cite source_url (timestamped for YouTube) with the returned\nspeaker, publication date, and video metadata. Do not put canonical_paraphrase\nin quotation marks unless you independently verify the wording at the source\nlink. The tool never returns raw transcript text.\n\nDetail-field safety: detail adds normalized claim fields only. The extraction\npipeline's internal audit flags are not published, because they describe how a\nrow was built rather than anything checkable about the claim; judge a claim from\nvalue, assertion_status, and the timestamped source link instead.\ncompany_attribution_confidence and company_attribution_source concern only the\nvideo-to-company/ticker assignment; inferred attribution is not independent\nconfirmation.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"query": {
"default": "",
"description": "Lexical search text. Natural-language questions are accepted because person/question scaffolding is normalized, not because a serving-time model interprets them. Use concise topical vocabulary and retry synonyms or the speaker's own terminology if needed. Ignored by coverage; appearances matches only video title/channel metadata.",
"type": "string"
},
"search_target": {
"default": "search",
"description": "Canonical targets: \"search\" (default blended claims + passages), \"claims\" (normalized decision-relevant claims), \"passages\" (broad substantive paraphrase cards), \"pressure_points\" (refusals and declined-to-confirm claims), \"appearances\" (video catalog), and \"coverage\" (company-level structured-corpus inventory). Compatibility aliases are \"all\" -> \"search\", \"videos\" -> \"appearances\", and \"companies\" -> \"coverage\"; new callers should use the canonical values.",
"enum": [
"search",
"claims",
"passages",
"pressure_points",
"appearances",
"coverage",
"all",
"videos",
"companies"
],
"type": "string"
},
"company_filter": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Comma-separated exact primary tickers or company names (for example, 'MU,NVDA' or 'NVDA,MiniMax'). Names match the companies a podcast section is about, so a private or non-US-listed company (MiniMax, Manycore Tech, Alibaba Group) is found by name. Appearance/coverage catalog lookup also accepts exact stored entity-reference tokens."
},
"person": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Case-insensitive name substring matched against the result speaker and/or the appearance speaker metadata."
},
"sort": {
"default": "relevance",
"description": "\"relevance\" orders lexical score first and publication date second; \"newest\" orders publication date first and lexical score second. Coverage uses its fixed company-inventory ordering.",
"enum": [
"relevance",
"newest"
],
"type": "string"
},
"appearance_type": {
"anyOf": [
{
"enum": [
"podcast",
"tv_interview",
"conference",
"other"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional appearance-type filter: podcast, tv_interview, conference, or other. Applies to every canonical target."
},
"claim_family": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional claim-ontology code. Blended search then returns structured claims only; appearances/coverage require matching claims. It is incompatible with search_target='passages'. Invalid codes return the valid vocabulary."
},
"date_from": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Inclusive YYYY-MM-DD lower bound on the video's stored publication/upload date, which may differ from its recording or event date."
},
"date_to": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Inclusive YYYY-MM-DD upper bound on the video's stored publication/upload date, which may differ from its recording or event date."
},
"detail": {
"default": false,
"description": "For search/claims/passages/pressure_points, add normalized claim and company-attribution fields. Internal audit flags use bounded public names and include field_semantics; raw transcript text and evidence spans remain excluded. Has no effect on appearances or coverage rows.",
"type": "boolean"
},
"limit": {
"default": 15,
"description": "Maximum rows returned, from 1 through 50.",
"maximum": 50,
"minimum": 1,
"type": "integer"
}
},
"type": "object"
}
},
{
"name": "search_news",
"description": "Search the curated news feed FactIQ continuously ingests: Bloomberg, the\nFinancial Times, and the Wall Street Journal RSS sections, plus India-macro\n(Zerodha Daily Brief, ET HealthWorld) and global-health sources (WHO, ECDC,\nCDC MMWR, STAT, KFF, and others). Each result is the article's headline, its\nshort publisher-written summary, and the link to the publisher — full article\nbodies are never stored or returned — plus FactIQ-derived metadata: tickers of\nlisted companies explicitly named in the text ({symbol, exchange, country})\nand an `analysis` block: keywords, a geography, and an `angle` — one sentence\non why the story matters to an investor. Pivot macro stories into\nsearch_series / run_sql, and company stories into get_market_data /\nsearch_earnings_transcripts / run_sql on the sec schema.\n\nCoverage is recent news, not an archive: most feeds start late 2025 to\nmid 2026 (Bloomberg back to Dec 2024). All arguments combine (AND).\n\n- query: full-text search over headline + summary. Lexical, not semantic —\n every word must match, so start with ONE distinctive term (\"Novartis\",\n \"copper\") and add words only to narrow. If a multi-word query matches\n nothing, the tool automatically retries matching ANY of the words, ranked\n so rare words and multi-word matches come first (meta.query_mode =\n \"any_term\" when that happened). Supports quoted \"exact phrases\" and\n -exclusion.\n- tickers: match articles naming any of these companies (bare symbols, e.g.\n [\"NVDA\", \"RELIANCE\"]). Share classes and cross-listings of major companies\n match automatically (GOOG also matches GOOGL; TSM also matches its Taiwan\n listing 2330) — pass whichever symbol you know. Most macro stories\n legitimately name no listed company.\n- topic: one of markets, economics, companies, technology, politics, world, energy, health, india, opinion. Combined with a query, topic is a\n ranking preference — articles from that topic's feeds rank first, but\n matches from other sections still return (feed sections are coarse; an\n energy story often runs in a markets feed). Without a query it is a hard\n filter on the topic's feeds.\n- start_date / end_date: ISO dates (YYYY-MM-DD) on publication time,\n inclusive. Start wide or omit; narrow only after seeing results.\n- sources: publisher slugs, any of bloomberg, cdc-mmwr, ecdc, et-healthworld, fierce-pharma, ft, global-fund, kff, stat-news, un-news, who, wsj, zerodha.\n- sort: \"latest\" (default, newest first) or \"relevance\" (text-match rank;\n needs a non-empty query, otherwise falls back to latest).\n- limit: max rows (1-50, default 20).\n\nReturns {rows: [{id, published_at, source, feed, topics, title, summary, url,\ntickers, analysis}], meta: {matched, returned, sort, query_mode?,\ntopic_mode?}}. `analysis` is null for articles not yet analysed or with no\nbusiness/economic content.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"query": {
"default": "",
"type": "string"
},
"tickers": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null
},
"topic": {
"anyOf": [
{
"enum": [
"markets",
"economics",
"companies",
"technology",
"politics",
"world",
"energy",
"health",
"india",
"opinion"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"sources": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null
},
"start_date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"end_date": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null
},
"sort": {
"default": "latest",
"enum": [
"latest",
"relevance"
],
"type": "string"
},
"limit": {
"default": 20,
"maximum": 50,
"minimum": 1,
"type": "integer"
}
},
"type": "object"
}
},
{
"name": "get_style_guides",
"description": "Fetch FactIQ's house-style authoring guides so anything you build matches\nFactIQ's conventions and look. Call this before producing a chart, a report,\nor written analysis from FactIQ data, and follow what it returns. By default,\nuse FactIQ's style for all FactIQ work unless the user asks otherwise.\n\nYou can fetch several at once. Pass any combination of:\n- \"chart\" — how to build and style a FactIQ chart: which chart type, finding-\n style titles, data hygiene, the FactIQ colour palette and plot\n surface, and sourcing\n- \"report\" — report structure, voice, and per-chart sourcing\n- \"sql\" — query idioms and pitfalls for FactIQ's tables\n- \"earnings\" — quoting discipline, spoken-vs-filed sourcing, guidance\n tables, and claim-verification patterns for anything built\n from search_earnings_transcripts\n- \"all\" — every guide\n\nReturns each requested guide's markdown text, keyed by name. This is free —\nit does not count against your tool quota.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"guides": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"guides"
],
"type": "object"
}
},
{
"name": "send_feedback",
"description": "Report a problem with FactIQ's data or tools to the FactIQ team.\n\nCall this when a tool result looks broken:\n- \"data_issue\" — a value that contradicts the official source, wrong units\n or scale, duplicated or missing periods, an obviously wrong label.\n- \"tool_error\" — a tool that errors, times out repeatedly, or returns\n malformed or self-contradictory results.\n- \"missing_data\" — a dataset or series the catalog advertises but that\n returns nothing, or coverage that ends far earlier than the source's.\n- \"other\" — a concrete defect in the published tool contract, such as the\n documented arguments or result shape contradicting actual behavior.\n\nWrite one short, specific message with the concrete identifiers: the\nschema, dataset_code or series_id, the SQL you ran, and what you expected\nvs. what you got (with the official source's value or URL if you have one).\nDo not include the user's personal details or your conversation.\n\nDo not call this for intentional capability boundaries or simply because a\nuser requested an unsupported action. FactIQ cannot mutate warehouse data,\nreturn complete raw transcripts, or publicly publish charts/reports; those\nlimits are expected behavior, not defects. A concrete tool result must show\nthe reported malfunction or data problem.\n\nThis is one-way: the FactIQ team reviews every report, but nothing comes\nback to you. File it and continue with the user's task — never block on it.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"message": {
"maxLength": 4000,
"minLength": 1,
"type": "string"
},
"category": {
"default": "other",
"enum": [
"data_issue",
"tool_error",
"missing_data",
"other"
],
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
}
}
]
}SHA-256: b867d3bc2218c923d117350a8d19391578e31aaba251d806b766f711c4083373