fodda-mcp 1.7.0 → 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/LICENSE +31 -0
  2. package/README.md +176 -18
  3. package/dist/a2aHandler.d.ts +20 -0
  4. package/dist/a2aHandler.d.ts.map +1 -0
  5. package/dist/a2aHandler.js +247 -0
  6. package/dist/a2aHandler.js.map +1 -0
  7. package/dist/agents/fodda-researcher/index.d.ts +35 -0
  8. package/dist/agents/fodda-researcher/index.d.ts.map +1 -0
  9. package/dist/agents/fodda-researcher/index.js +62 -0
  10. package/dist/agents/fodda-researcher/index.js.map +1 -0
  11. package/dist/agents/fodda-researcher/skills.d.ts +16 -0
  12. package/dist/agents/fodda-researcher/skills.d.ts.map +1 -0
  13. package/dist/agents/fodda-researcher/skills.js +163 -0
  14. package/dist/agents/fodda-researcher/skills.js.map +1 -0
  15. package/dist/brandTemplate.d.ts +14 -0
  16. package/dist/brandTemplate.d.ts.map +1 -0
  17. package/dist/brandTemplate.js +742 -0
  18. package/dist/brandTemplate.js.map +1 -0
  19. package/dist/catalogCache.d.ts +177 -0
  20. package/dist/catalogCache.d.ts.map +1 -0
  21. package/dist/catalogCache.js +708 -0
  22. package/dist/catalogCache.js.map +1 -0
  23. package/dist/editorialFill.d.ts +44 -0
  24. package/dist/editorialFill.d.ts.map +1 -0
  25. package/dist/editorialFill.js +377 -0
  26. package/dist/editorialFill.js.map +1 -0
  27. package/dist/enrichment.d.ts +74 -0
  28. package/dist/enrichment.d.ts.map +1 -0
  29. package/dist/enrichment.js +211 -0
  30. package/dist/enrichment.js.map +1 -0
  31. package/dist/errorHandling.d.ts +52 -0
  32. package/dist/errorHandling.d.ts.map +1 -0
  33. package/dist/errorHandling.js +327 -0
  34. package/dist/errorHandling.js.map +1 -0
  35. package/dist/index.d.ts +0 -1
  36. package/dist/index.js +595 -581
  37. package/dist/index.js.map +1 -1
  38. package/dist/pricingCache.d.ts +99 -0
  39. package/dist/pricingCache.d.ts.map +1 -0
  40. package/dist/pricingCache.js +414 -0
  41. package/dist/pricingCache.js.map +1 -0
  42. package/dist/queryCache.d.ts +25 -0
  43. package/dist/queryCache.d.ts.map +1 -0
  44. package/dist/queryCache.js +194 -0
  45. package/dist/queryCache.js.map +1 -0
  46. package/dist/searchTemplate.d.ts +16 -0
  47. package/dist/searchTemplate.d.ts.map +1 -0
  48. package/dist/searchTemplate.js +318 -0
  49. package/dist/searchTemplate.js.map +1 -0
  50. package/dist/sessionTracker.d.ts +39 -0
  51. package/dist/sessionTracker.d.ts.map +1 -0
  52. package/dist/sessionTracker.js +187 -0
  53. package/dist/sessionTracker.js.map +1 -0
  54. package/dist/skillClient.d.ts +142 -0
  55. package/dist/skillClient.d.ts.map +1 -0
  56. package/dist/skillClient.js +256 -0
  57. package/dist/skillClient.js.map +1 -0
  58. package/dist/svgVisuals.d.ts +77 -0
  59. package/dist/svgVisuals.d.ts.map +1 -0
  60. package/dist/svgVisuals.js +323 -0
  61. package/dist/svgVisuals.js.map +1 -0
  62. package/dist/systemPrompt.d.ts +26 -0
  63. package/dist/systemPrompt.d.ts.map +1 -0
  64. package/dist/systemPrompt.js +546 -0
  65. package/dist/systemPrompt.js.map +1 -0
  66. package/dist/test-waverunner-response.d.ts +2 -0
  67. package/dist/test-waverunner-response.d.ts.map +1 -0
  68. package/dist/test-waverunner-response.js +20 -0
  69. package/dist/test-waverunner-response.js.map +1 -0
  70. package/dist/test_analyst.d.ts +2 -0
  71. package/dist/test_analyst.d.ts.map +1 -0
  72. package/dist/test_analyst.js +39 -0
  73. package/dist/test_analyst.js.map +1 -0
  74. package/dist/test_analyst_local.d.ts +2 -0
  75. package/dist/test_analyst_local.d.ts.map +1 -0
  76. package/dist/test_analyst_local.js +51 -0
  77. package/dist/test_analyst_local.js.map +1 -0
  78. package/dist/test_live_mcp.js +1 -1
  79. package/dist/test_skills.d.ts +9 -0
  80. package/dist/test_skills.d.ts.map +1 -0
  81. package/dist/test_skills.js +267 -0
  82. package/dist/test_skills.js.map +1 -0
  83. package/dist/toolHandlers.d.ts +11 -0
  84. package/dist/toolHandlers.d.ts.map +1 -0
  85. package/dist/toolHandlers.js +2829 -0
  86. package/dist/toolHandlers.js.map +1 -0
  87. package/dist/tools.d.ts +78 -3
  88. package/dist/tools.d.ts.map +1 -1
  89. package/dist/tools.js +85 -292
  90. package/dist/tools.js.map +1 -1
  91. package/dist/trialTracker.d.ts +58 -0
  92. package/dist/trialTracker.d.ts.map +1 -0
  93. package/dist/trialTracker.js +179 -0
  94. package/dist/trialTracker.js.map +1 -0
  95. package/dist/types.d.ts +1 -0
  96. package/dist/types.d.ts.map +1 -1
  97. package/dist/verify_hmac.js +1 -1
  98. package/dist/verify_hmac.js.map +1 -1
  99. package/dist/verify_tools_endpoint.js +5 -5
  100. package/dist/verify_tools_endpoint.js.map +1 -1
  101. package/dist/widgetShell.d.ts +15 -0
  102. package/dist/widgetShell.d.ts.map +1 -0
  103. package/dist/widgetShell.js +151 -0
  104. package/dist/widgetShell.js.map +1 -0
  105. package/package.json +8 -4
  106. package/server.json +11 -2
package/LICENSE ADDED
@@ -0,0 +1,31 @@
1
+ Copyright (c) 2026 Fodda / PSFK. All rights reserved.
2
+
3
+ PROPRIETARY SOFTWARE LICENSE
4
+
5
+ This software and associated documentation files (the "Software") are the
6
+ proprietary and confidential property of Fodda / PSFK ("Fodda"). The Software
7
+ is licensed, not sold.
8
+
9
+ 1. Grant. Subject to your compliance with these terms and the Fodda Terms of
10
+ Service (https://www.fodda.ai), Fodda grants you a limited, non-exclusive,
11
+ non-transferable, revocable license to install and run the Software solely
12
+ to connect to the Fodda service using a valid Fodda API key.
13
+
14
+ 2. Restrictions. You may not (a) copy, modify, or create derivative works of
15
+ the Software except as required to run it as intended; (b) sell, sublicense,
16
+ rent, lease, or otherwise commercially exploit the Software; (c) reverse
17
+ engineer or attempt to derive the source of any non-public component; or
18
+ (d) remove or alter any proprietary notices.
19
+
20
+ 3. Ownership. Fodda retains all right, title, and interest in and to the
21
+ Software, including all intellectual property rights.
22
+
23
+ 4. No Warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
26
+
27
+ 5. Limitation of Liability. IN NO EVENT SHALL FODDA BE LIABLE FOR ANY CLAIM,
28
+ DAMAGES, OR OTHER LIABILITY ARISING FROM OR IN CONNECTION WITH THE SOFTWARE
29
+ OR ITS USE.
30
+
31
+ For licensing inquiries, contact hello@fodda.ai.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  [![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.piers--fawkes%2Ffodda-blue)](https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.piers-fawkes/fodda)
9
9
  [![npm](https://img.shields.io/npm/v/fodda-mcp)](https://www.npmjs.com/package/fodda-mcp)
10
- [![Version](https://img.shields.io/badge/version-1.4.0-green)](./CHANGELOG.md)
10
+ [![Version](https://img.shields.io/badge/version-1.29.0-green)](./CHANGELOG.md)
11
11
  [![License](https://img.shields.io/badge/license-Proprietary-red)](https://fodda.ai)
12
12
 
13
13
  </div>
@@ -16,16 +16,82 @@
16
16
 
17
17
  ## Quick Start
18
18
 
19
- ### Claude Code (Streamable HTTP fallback to SSE)
19
+ ### Claude (Web — Pro, Max, Team, Enterprise)
20
+
21
+ **⚡ Quick Connect:** Use this [Add to Claude](https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=Fodda&connectorUrl=https%3A%2F%2Fmcp.fodda.ai%2Fmcp%3Fapi_key%3DYOUR_API_KEY%26user_id%3DYOUR_EMAIL) quick link (replace `YOUR_API_KEY` and `YOUR_EMAIL` in the URL before pressing enter).
22
+
23
+ **Manual Setup:**
24
+ 1. In Claude, go to **Settings → Connectors → Add custom connector**
25
+ 2. Enter URL: `https://mcp.fodda.ai/mcp?api_key=YOUR_API_KEY&user_id=YOUR_EMAIL`
26
+ 3. Under **Advanced settings** — leave OAuth Client ID and Secret **blank** (Fodda uses API key auth, not OAuth)
27
+ 4. Click **Add** — then start chatting with your Fodda knowledge graphs
28
+
29
+ > Get your API key at [app.fodda.ai](https://app.fodda.ai) → Account → MCP Integration.
30
+ > Your API key starts with `sk_live_...`
31
+ > Use the email address associated with your Fodda account for `user_id`.
32
+
33
+ ### Claude Code (CLI — SSE)
20
34
 
21
35
  ```bash
22
36
  claude mcp add --transport sse fodda https://mcp.fodda.ai/sse \
23
37
  --header "Authorization: Bearer YOUR_API_KEY"
24
38
  ```
25
39
 
26
- ### OpenAI Frontier or Streamable HTTP Client
27
- Connect to the `/mcp` endpoint using HTTP `GET` to establish a stream and `POST` to execute:
28
- ```bash
40
+ ### Claude Enterprise
41
+
42
+ For Claude Enterprise with admin-managed connectors, your workspace admin can register the Fodda MCP server using the same Streamable HTTP endpoint (`https://mcp.fodda.ai/mcp`) via the Admin Console. See [Enterprise MCP Setup](./Enterprise_MCP_Setup.md) for full details.
43
+
44
+ ### OpenAI (Responses API — Recommended)
45
+
46
+ Use OpenAI's native MCP support — no function definitions needed:
47
+
48
+ ```python
49
+ from openai import OpenAI
50
+ client = OpenAI()
51
+
52
+ resp = client.responses.create(
53
+ model="gpt-5",
54
+ tools=[{
55
+ "type": "mcp",
56
+ "server_label": "fodda",
57
+ "server_description": "Expert-curated knowledge graphs for retail, beauty, sports trends and earnings intelligence.",
58
+ "server_url": "https://mcp.fodda.ai/mcp",
59
+ "authorization": "Bearer YOUR_API_KEY",
60
+ "require_approval": "never",
61
+ }],
62
+ input="What are the top emerging retail trends?",
63
+ )
64
+ print(resp.output_text)
65
+ ```
66
+
67
+ ```javascript
68
+ import OpenAI from "openai";
69
+ const client = new OpenAI();
70
+
71
+ const resp = await client.responses.create({
72
+ model: "gpt-5",
73
+ tools: [{
74
+ type: "mcp",
75
+ server_label: "fodda",
76
+ server_description: "Expert-curated knowledge graphs for retail, beauty, sports trends and earnings intelligence.",
77
+ server_url: "https://mcp.fodda.ai/mcp",
78
+ authorization: "Bearer YOUR_API_KEY",
79
+ require_approval: "never",
80
+ }],
81
+ input: "What are the top emerging retail trends?",
82
+ });
83
+ console.log(resp.output_text);
84
+ ```
85
+
86
+ > **Tip:** To reduce latency with 30+ tools, use `allowed_tools` to filter:
87
+ > `"allowed_tools": ["search_graph", "search_statistics", "brand_tracker"]`
88
+
89
+ > **Legacy:** If you're using `chat.completions.create()` with function calling, define a custom function that calls the Fodda REST API. See [fodda.ai/connect](https://app.fodda.ai) for details.
90
+
91
+ ### Generic Streamable HTTP Client
92
+
93
+ Connect to the `/mcp` endpoint using HTTP `POST` (Streamable HTTP) with `Authorization: Bearer YOUR_API_KEY`:
94
+ ```
29
95
  https://mcp.fodda.ai/mcp
30
96
  ```
31
97
 
@@ -50,16 +116,63 @@ Connect to `https://mcp.fodda.ai/sse` with an `Authorization: Bearer YOUR_API_KE
50
116
 
51
117
  ## Available Tools
52
118
 
119
+ The Fodda MCP server exposes a rich suite of 30 tools to search, analyze, brainstorm, and visualize trends, expert-curated knowledge graphs, and corporate documents.
120
+
121
+ ### Discovery & Search
122
+ | Tool | Description | Deterministic |
123
+ |------|-------------|:---:|
124
+ | `list_graphs` | Discover available knowledge graphs, metadata, and routing instructions. | ✅ |
125
+ | `search_graph` | Hybrid keyword + semantic search across curated graphs for trend clusters and evidence. | ❌ |
126
+ | `search_statistics` | Search for specific quantitative metrics, indicators, and numeric data points. | ❌ |
127
+ | `search_insights` | Search expert quotes, qualitative signals, and professional interpretations. | ❌ |
128
+ | `get_label_values` | Discover valid values for a node label or category. | ✅ |
129
+
130
+ ### Traversal & Graph Operations
131
+ | Tool | Description | Deterministic |
132
+ |------|-------------|:---:|
133
+ | `get_neighbors` | Traverse from seed nodes to discover related concept nodes and links. | ✅ |
134
+ | `get_node` | Retrieve detailed metadata, properties, and attributes for a single node by ID. | ✅ |
135
+ | `get_evidence` | Retrieve source signals, articles, citations, and provenance for a trend or node. | ✅ |
136
+ | `discover_adjacent_trends` | Find semantically similar trends to a given trend node. | ✅ |
137
+
138
+ ### Intelligence Domains
139
+ | Tool | Description | Deterministic |
140
+ |------|-------------|:---:|
141
+ | `get_domain_intelligence` | Search all PSFK curated domain graphs (retail, beauty, sports, fashion, consumer electronics, F&B) in parallel. | ❌ |
142
+ | `get_expert_intelligence` | Query specialist industry graphs built by leading strategists and experts. | ❌ |
143
+ | `get_report_intelligence` | Search institutional report insights from DHL, PwC, Delta, and other partners. | ❌ |
144
+
145
+ ### Earnings & Corporate Insights
53
146
  | Tool | Description | Deterministic |
54
147
  |------|-------------|:---:|
55
- | `search_graph` | Hybrid keyword + semantic search on a knowledge graph | ❌ |
56
- | `get_neighbors` | Traverse from seed nodes to discover related concepts | ✅ |
57
- | `get_evidence` | Source signals, articles, and provenance for a node | ✅ |
58
- | `get_node` | Retrieve metadata for a single node by ID | ✅ |
59
- | `get_label_values` | Discover valid values for a node label/category | ✅ |
60
- | `psfk_overview` | Structured macro overview across industries and sectors | ❌ |
148
+ | `get_earnings_intelligence` | Query management commentary, business guidance, and Q&A from company earnings calls. | ❌ |
149
+ | `get_earnings_divergence` | Detect deflections, gaps, and divergence between analyst concerns and executive responses in earnings calls. | ❌ |
61
150
 
62
- All tools require `userId` and — except `psfk_overview` — a `graphId`.
151
+ ### Brand & Ideation
152
+ | Tool | Description | Deterministic |
153
+ |------|-------------|:---:|
154
+ | `brand_tracker` | Compile a comprehensive Brand Intelligence Profile across all knowledge graphs. | ❌ |
155
+ | `brainstorm_topic` | Graph-powered brainstorm map discovering unexpected connections and adjacent territories. | ❌ |
156
+
157
+ ### Deep Research & Execution Agents
158
+ | Tool | Description | Deterministic |
159
+ |------|-------------|:---:|
160
+ | `deep_research_topic` | Launch an autonomous research session combining graphs with live web search. | ❌ |
161
+ | `check_research_status` | Check progress or retrieve the final narrative report of a deep research job. | ✅ |
162
+ | `get_supplemental_context` | Fetch macro context from up to 10 institutional data sources in a single query. | ❌ |
163
+ | `check_supplemental_status` | Retrieve output from a supplemental context job. | ✅ |
164
+
165
+ ### Synthetic Analyst & Visualization
166
+ | Tool | Description | Deterministic |
167
+ |------|-------------|:---:|
168
+ | `list_analysts` | List available Synthetic Analyst expert personas. | ✅ |
169
+ | `consult_analyst` | Engage a Synthetic Analyst persona to synthesize answers with specialized voice. | ❌ |
170
+ | `generate_visual` | Generate branded SVG data visualizations (Cultural Shifts, Competitive Compass, Innovation Pathway, etc.). | ❌ |
171
+ > **Note on Dynamic Partner Skills:** When partner skills (such as Paralogy or Igloo) are enabled for a user's account, additional specialized tools (e.g. `paralogy_analyze_trends`, ideation tools) are dynamically registered on the MCP server and made available automatically.
172
+ >
173
+ > **Note on System Utilities:** The server also registers several helper and account management utilities (e.g., `get_my_account`, `toggle_graph_preference`, `update_user_profile`, `manage_scheduled_reports`, `send_feedback`) to allow the AI assistant to query subscription status, manage scheduled briefings, or save personalization settings directly.
174
+
175
+ ---
63
176
 
64
177
  ### Discovery Endpoints
65
178
 
@@ -73,17 +186,26 @@ All tools require `userId` and — except `psfk_overview` — a `graphId`.
73
186
 
74
187
  ## Authentication
75
188
 
189
+ **Preferred — HTTP header (used by the directory connection and all header-capable clients).**
76
190
  Pass your Fodda API key as a Bearer token:
77
191
 
78
192
  ```
79
- Authorization: Bearer fk_live_...
193
+ Authorization: Bearer sk_live_...
80
194
  ```
81
195
 
196
+ The server also accepts the key via an `X-API-Key: sk_live_...` header.
197
+
82
198
  In MCP request `_meta`:
83
199
  ```json
84
- { "_meta": { "authorization": "Bearer fk_live_..." } }
200
+ { "_meta": { "authorization": "Bearer sk_live_..." } }
85
201
  ```
86
202
 
203
+ **Fallback — URL query parameter.** Some clients (e.g. the Claude.ai web *custom
204
+ connector* UI) cannot set custom request headers. For those, the key may be passed as
205
+ `?api_key=...`. This is provided only for compatibility; prefer header-based auth
206
+ wherever the client supports it, since URLs are more likely to be logged by
207
+ intermediaries. The server never returns your API key in tool output.
208
+
87
209
  ---
88
210
 
89
211
  ## Configuration
@@ -92,11 +214,8 @@ In MCP request `_meta`:
92
214
  |----------|-------------|---------|
93
215
  | `PORT` | HTTP server port (omit for stdio mode) | — |
94
216
  | `FODDA_API_URL` | Upstream API base URL | `https://api.fodda.ai` |
95
- | `FODDA_MCP_SECRET` | HMAC signing secret | — |
96
- | `ALLOWED_TOOLS` | Comma-separated allowlist of Enterprise Tool scope | `search_graph,get_node,...` |
217
+ | `FODDA_MCP_SECRET` | HMAC signing secret for API requests | — |
97
218
  | `NODE_ENV` | Environment (`development` / `production`) | `production` |
98
- | `INTERNAL_TEST_KEYS` | Comma-separated keys for simulation mode | — |
99
- | `RATE_LIMIT_RPM` | Requests per minute per API key | `60` |
100
219
 
101
220
  ---
102
221
 
@@ -133,6 +252,45 @@ curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.pie
133
252
 
134
253
  ---
135
254
 
255
+ ## Privacy Policy
256
+
257
+ Full policy: **[https://www.fodda.ai/privacy](https://www.fodda.ai/privacy)**
258
+
259
+ Summary of how the Fodda MCP server handles data:
260
+
261
+ - **What we collect.** Your Fodda API key (for authentication and billing) and the
262
+ `user_id`/email associated with your Fodda account. Tool calls you make (queries,
263
+ parameters, and the graphs/skills accessed) are processed to return results and may
264
+ be logged for reliability, abuse prevention, and usage metering.
265
+ - **How it's used and stored.** Requests are proxied to the Fodda API
266
+ (`https://api.fodda.ai`) over HTTPS. Session and account state is stored in Fodda's
267
+ managed infrastructure. Your API key is transmitted only to authenticate your
268
+ requests and is never returned in tool output.
269
+ - **Third-party sharing.** We do not sell your data. Query content may be processed by
270
+ sub-processors strictly to deliver the service (e.g. model inference and
271
+ transactional email providers). Partner "skills," when enabled by you, process only
272
+ the queries you direct to them.
273
+ - **Retention.** Account and usage records are retained while your account is active
274
+ and for the period required for billing, security, and legal obligations. See the
275
+ hosted policy for specifics.
276
+ - **Contact.** Privacy questions: **[hello@fodda.ai](mailto:hello@fodda.ai)**.
277
+
278
+ See the [full hosted Privacy Policy](https://www.fodda.ai/privacy) for the complete,
279
+ authoritative terms.
280
+
281
+ ---
282
+
283
+ ## Support
284
+
285
+ - **Email:** [hello@fodda.ai](mailto:hello@fodda.ai)
286
+ - **Account & API keys:** [app.fodda.ai](https://app.fodda.ai) → Account → MCP Integration
287
+ - **Documentation:** [fodda.ai](https://www.fodda.ai)
288
+
289
+ To report a security issue, email **[hello@fodda.ai](mailto:hello@fodda.ai)** with
290
+ "SECURITY" in the subject line.
291
+
292
+ ---
293
+
136
294
  ## License
137
295
 
138
296
  Proprietary — [fodda.ai](https://www.fodda.ai)
@@ -0,0 +1,20 @@
1
+ /**
2
+ * A2A (Agent-to-Agent) Protocol Handler
3
+ *
4
+ * Implements JSON-RPC 2.0 over HTTP per the A2A v1.0 specification.
5
+ * MVP: Supports `message/send` only — receives a natural language task,
6
+ * routes it through Fodda's existing tool handlers, and returns
7
+ * structured results as A2A Task artifacts.
8
+ *
9
+ * A2A vs MCP:
10
+ * - MCP: client agent calls Fodda tools directly (tool-level granularity)
11
+ * - A2A: client agent delegates a *task* in natural language; Fodda decides
12
+ * which tools to use and returns the synthesized result
13
+ *
14
+ * Spec: https://a2a-protocol.org/latest/specification/
15
+ */
16
+ import type { Express } from 'express';
17
+ type FoddaRequestFn = (method: 'GET' | 'POST' | 'PATCH', path: string, apiKey: string, userId: string, body?: any) => Promise<any>;
18
+ export declare function registerA2ARoute(app: Express, foddaRequest: FoddaRequestFn): void;
19
+ export {};
20
+ //# sourceMappingURL=a2aHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a2aHandler.d.ts","sourceRoot":"","sources":["../src/a2aHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAsF1D,KAAK,cAAc,GAAG,CAClB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,EAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,GAAG,KACT,OAAO,CAAC,GAAG,CAAC,CAAC;AAgIlB,wBAAgB,gBAAgB,CAC5B,GAAG,EAAE,OAAO,EACZ,YAAY,EAAE,cAAc,GAC7B,IAAI,CAwIN"}
@@ -0,0 +1,247 @@
1
+ /**
2
+ * A2A (Agent-to-Agent) Protocol Handler
3
+ *
4
+ * Implements JSON-RPC 2.0 over HTTP per the A2A v1.0 specification.
5
+ * MVP: Supports `message/send` only — receives a natural language task,
6
+ * routes it through Fodda's existing tool handlers, and returns
7
+ * structured results as A2A Task artifacts.
8
+ *
9
+ * A2A vs MCP:
10
+ * - MCP: client agent calls Fodda tools directly (tool-level granularity)
11
+ * - A2A: client agent delegates a *task* in natural language; Fodda decides
12
+ * which tools to use and returns the synthesized result
13
+ *
14
+ * Spec: https://a2a-protocol.org/latest/specification/
15
+ */
16
+ import crypto from 'crypto';
17
+ function classifyIntent(text) {
18
+ const lower = text.toLowerCase();
19
+ // Brand-focused queries
20
+ const brandMatch = lower.match(/(?:what is |what's |tell me about |brand (?:intelligence|profile|tracker) (?:for |on )?|track )([a-z][a-z0-9 &'.-]{1,30}?)(?:\s+(?:doing|strategy|innovation|positioning|trends?))?$/i);
21
+ if (brandMatch && brandMatch[1]) {
22
+ return { tool: 'brand_tracker', params: { brand_name: brandMatch[1].trim() } };
23
+ }
24
+ // Explicit brand mentions with "what is X doing" pattern
25
+ const doingMatch = text.match(/what (?:is|are) ([A-Z][A-Za-z0-9 &'.-]{1,30}?) doing/);
26
+ if (doingMatch && doingMatch[1]) {
27
+ return { tool: 'brand_tracker', params: { brand_name: doingMatch[1].trim() } };
28
+ }
29
+ // Deep research triggers
30
+ if (lower.includes('deep research') || lower.includes('comprehensive report') ||
31
+ lower.includes('write me a report') || lower.includes('detailed analysis')) {
32
+ return { tool: 'deep_research', params: { query: text, depth: 'light' } };
33
+ }
34
+ // Earnings triggers
35
+ if (lower.includes('earnings') || lower.includes('q1 ') || lower.includes('q2 ') ||
36
+ lower.includes('q3 ') || lower.includes('q4 ') || lower.match(/what (?:are|did) .+ (?:companies|brands) say/)) {
37
+ return { tool: 'earnings', params: { query: text } };
38
+ }
39
+ // Default: search_graph (the most general tool)
40
+ return { tool: 'search_graph', params: { query: text } };
41
+ }
42
+ async function executeQuery(route, apiKey, userId, foddaRequest) {
43
+ switch (route.tool) {
44
+ case 'search_graph': {
45
+ // Search ALL graphs (no graphId = all-graph parallel search)
46
+ const body = {
47
+ query: route.params.query,
48
+ limit: 10,
49
+ use_semantic: true,
50
+ include_evidence: true,
51
+ };
52
+ const result = await foddaRequest('POST', '/v1/graphs/search', apiKey, userId, body);
53
+ const rows = result?.rows || [];
54
+ if (rows.length === 0) {
55
+ return { text: `No trends found for: "${route.params.query}". Fodda's knowledge graphs may not have coverage on this specific topic.`, data: result };
56
+ }
57
+ // Build a concise markdown summary
58
+ const lines = [];
59
+ lines.push(`## Fodda Trend Intelligence: ${route.params.query}\n`);
60
+ lines.push(`_${rows.length} trends found across Fodda's expert-curated knowledge graphs._\n`);
61
+ for (const row of rows.slice(0, 8)) {
62
+ const score = row.signal_score ? ` (signal: ${row.signal_score})` : '';
63
+ const lifecycle = row.trendLifecycle ? ` · ${row.trendLifecycle}` : '';
64
+ const graph = row.graphName ? ` — _${row.graphName}_` : '';
65
+ lines.push(`### ${row.title || row.trendName}${score}${lifecycle}`);
66
+ if (row.summary || row.description) {
67
+ lines.push((row.summary || row.description).substring(0, 300));
68
+ }
69
+ if (row.evidence && row.evidence.length > 0) {
70
+ lines.push('');
71
+ for (const ev of row.evidence.slice(0, 3)) {
72
+ const link = ev.sourceUrl ? ` — [source](${ev.sourceUrl})` : '';
73
+ lines.push(`- ${(ev.title || ev.snippet || '').substring(0, 150)}${link}`);
74
+ }
75
+ }
76
+ lines.push(`${graph}\n`);
77
+ }
78
+ return { text: lines.join('\n'), data: result };
79
+ }
80
+ case 'brand_tracker': {
81
+ const body = { brand_name: route.params.brand_name };
82
+ const result = await foddaRequest('POST', '/v1/brands/intelligence', apiKey, userId, body);
83
+ const lines = [];
84
+ lines.push(`## Brand Intelligence: ${route.params.brand_name}\n`);
85
+ if (result?.trend_footprint) {
86
+ lines.push(`_Appears in ${result.trend_footprint.length} trends across ${result.cross_graph_presence?.length || 0} knowledge graphs._\n`);
87
+ for (const t of (result.trend_footprint || []).slice(0, 6)) {
88
+ const score = t.signal_score ? ` (signal: ${t.signal_score})` : '';
89
+ lines.push(`- **${t.trend_name}**${score} · ${t.lifecycle || 'unknown'} — ${t.graph_name || ''}`);
90
+ }
91
+ }
92
+ if (result?.competitive_context?.co_occurring?.length > 0) {
93
+ lines.push(`\n### Competitive Context`);
94
+ for (const c of result.competitive_context.co_occurring.slice(0, 5)) {
95
+ lines.push(`- ${c.brand} (${c.pressure_type})`);
96
+ }
97
+ }
98
+ return { text: lines.join('\n') || JSON.stringify(result, null, 2), data: result };
99
+ }
100
+ case 'earnings': {
101
+ const body = { query: route.params.query, limit: 10 };
102
+ const result = await foddaRequest('POST', '/v1/earnings/search', apiKey, userId, body);
103
+ return {
104
+ text: result?.summary || JSON.stringify(result, null, 2),
105
+ data: result,
106
+ };
107
+ }
108
+ case 'deep_research': {
109
+ // For A2A MVP, we do a synchronous search (not the async deep_research job)
110
+ // because A2A registries expect a timely response for health probes.
111
+ const body = {
112
+ query: route.params.query,
113
+ limit: 15,
114
+ use_semantic: true,
115
+ include_evidence: true,
116
+ };
117
+ const result = await foddaRequest('POST', '/v1/graphs/search', apiKey, userId, body);
118
+ const rows = result?.rows || [];
119
+ const lines = [];
120
+ lines.push(`## Research Summary: ${route.params.query}\n`);
121
+ lines.push(`_${rows.length} trends analyzed from Fodda's knowledge graph network._\n`);
122
+ for (const row of rows.slice(0, 10)) {
123
+ const score = row.signal_score ? ` (signal: ${row.signal_score})` : '';
124
+ lines.push(`### ${row.title || row.trendName}${score}`);
125
+ if (row.summary || row.description) {
126
+ lines.push((row.summary || row.description).substring(0, 400));
127
+ }
128
+ lines.push('');
129
+ }
130
+ return { text: lines.join('\n'), data: result };
131
+ }
132
+ }
133
+ }
134
+ // ---------------------------------------------------------------------------
135
+ // JSON-RPC helpers
136
+ // ---------------------------------------------------------------------------
137
+ function jsonRpcSuccess(id, result) {
138
+ return { jsonrpc: '2.0', id, result };
139
+ }
140
+ function jsonRpcError(id, code, message, data) {
141
+ return { jsonrpc: '2.0', id, error: { code, message, ...(data ? { data } : {}) } };
142
+ }
143
+ // ---------------------------------------------------------------------------
144
+ // Route registration
145
+ // ---------------------------------------------------------------------------
146
+ export function registerA2ARoute(app, foddaRequest) {
147
+ app.post('/a2a', async (req, res) => {
148
+ // ── Parse & validate JSON-RPC envelope ──
149
+ const body = req.body;
150
+ if (!body || body.jsonrpc !== '2.0') {
151
+ return res.status(400).json(jsonRpcError(body?.id ?? null, -32600, 'Invalid Request: missing jsonrpc 2.0 field'));
152
+ }
153
+ const requestId = body.id ?? null;
154
+ // ── Method dispatch ──
155
+ switch (body.method) {
156
+ case 'message/send':
157
+ break; // handled below
158
+ // Stubs for future methods — return Method Not Found
159
+ case 'message/stream':
160
+ case 'tasks/get':
161
+ case 'tasks/cancel':
162
+ case 'tasks/list':
163
+ return res.json(jsonRpcError(requestId, -32601, `Method not found: ${body.method}. Only message/send is supported in this version.`));
164
+ default:
165
+ return res.json(jsonRpcError(requestId, -32601, `Method not found: ${body.method}`));
166
+ }
167
+ // ── Extract user text from message parts ──
168
+ const message = body.params?.message;
169
+ if (!message?.parts?.length) {
170
+ return res.json(jsonRpcError(requestId, -32602, 'Invalid params: message.parts is required and must be non-empty'));
171
+ }
172
+ const textPart = message.parts.find(p => p.kind === 'text' && p.text);
173
+ if (!textPart?.text) {
174
+ return res.json(jsonRpcError(requestId, -32602, 'Invalid params: no text part found in message'));
175
+ }
176
+ const queryText = textPart.text;
177
+ // ── Authentication ──
178
+ // Accept: Authorization: Bearer <key>, X-API-Key header, or api_key query param
179
+ const apiKey = (req.headers['authorization']?.toString().replace(/^Bearer\s+/i, ''))
180
+ || req.headers['x-api-key']
181
+ || req.query.api_key
182
+ || '';
183
+ const userId = req.headers['x-user-id']
184
+ || req.query.user_id
185
+ || 'a2a-agent';
186
+ // For unauthenticated requests (health probes), return a minimal valid response
187
+ if (!apiKey) {
188
+ const taskId = `task-${crypto.randomUUID().slice(0, 8)}`;
189
+ const contextId = `ctx-${crypto.randomUUID().slice(0, 8)}`;
190
+ return res.json(jsonRpcSuccess(requestId, {
191
+ id: taskId,
192
+ contextId,
193
+ status: { state: 'completed' },
194
+ artifacts: [{
195
+ name: 'health_check',
196
+ parts: [{
197
+ kind: 'text',
198
+ text: 'Fodda A2A endpoint is operational. Provide an API key via Authorization: Bearer <key> for full access to trend intelligence. Get a key at https://app.fodda.ai',
199
+ }],
200
+ }],
201
+ }));
202
+ }
203
+ // ── Route and execute ──
204
+ try {
205
+ const route = classifyIntent(queryText);
206
+ console.error(`[a2a] message/send: "${queryText.substring(0, 80)}" → ${route.tool}`);
207
+ const result = await executeQuery(route, apiKey, userId, foddaRequest);
208
+ const taskId = `task-${crypto.randomUUID().slice(0, 8)}`;
209
+ const contextId = `ctx-${crypto.randomUUID().slice(0, 8)}`;
210
+ // Build artifacts — always include markdown text, optionally raw JSON
211
+ const artifacts = [
212
+ {
213
+ name: 'research_result',
214
+ description: `Fodda intelligence for: ${queryText.substring(0, 100)}`,
215
+ parts: [{ kind: 'text', text: result.text }],
216
+ },
217
+ ];
218
+ // Include raw data as a structured artifact if the client accepts JSON
219
+ const acceptedOutputs = body.params?.configuration?.acceptedOutputModes || [];
220
+ if (acceptedOutputs.includes('application/json') && result.data) {
221
+ artifacts.push({
222
+ name: 'raw_data',
223
+ description: 'Structured JSON data from Fodda knowledge graphs',
224
+ parts: [{ kind: 'data', data: result.data, mimeType: 'application/json' }],
225
+ });
226
+ }
227
+ return res.json(jsonRpcSuccess(requestId, {
228
+ id: taskId,
229
+ contextId,
230
+ status: { state: 'completed' },
231
+ artifacts,
232
+ }));
233
+ }
234
+ catch (err) {
235
+ const statusCode = err.response?.status;
236
+ const errMsg = err.response?.data?.error?.message || err.message || 'Internal error';
237
+ console.error(`[a2a] Error: ${errMsg}`);
238
+ // Map known error types to appropriate JSON-RPC error codes
239
+ if (statusCode === 401 || statusCode === 403) {
240
+ return res.json(jsonRpcError(requestId, -32001, `Unauthorized: ${errMsg}`));
241
+ }
242
+ return res.json(jsonRpcError(requestId, -32603, `Fodda query failed: ${errMsg}`));
243
+ }
244
+ });
245
+ console.error('[a2a] A2A endpoint registered at POST /a2a');
246
+ }
247
+ //# sourceMappingURL=a2aHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a2aHandler.js","sourceRoot":"","sources":["../src/a2aHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAkD5B,SAAS,cAAc,CAAC,IAAY;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAEjC,wBAAwB;IACxB,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAC1B,uLAAuL,CAC1L,CAAC;IACF,IAAI,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC;IACnF,CAAC;IAED,yDAAyD;IACzD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;IACtF,IAAI,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC;IACnF,CAAC;IAED,yBAAyB;IACzB,IAAI,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACzE,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC7E,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;IAC9E,CAAC;IAED,oBAAoB;IACpB,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC5E,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,8CAA8C,CAAC,EAAE,CAAC;QAChH,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;IACzD,CAAC;IAED,gDAAgD;IAChD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;AAC7D,CAAC;AAcD,KAAK,UAAU,YAAY,CACvB,KAAgB,EAChB,MAAc,EACd,MAAc,EACd,YAA4B;IAE5B,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,cAAc,CAAC,CAAC,CAAC;YAClB,6DAA6D;YAC7D,MAAM,IAAI,GAAG;gBACT,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;gBACzB,KAAK,EAAE,EAAE;gBACT,YAAY,EAAE,IAAI;gBAClB,gBAAgB,EAAE,IAAI;aACzB,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YACrF,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;YAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpB,OAAO,EAAE,IAAI,EAAE,yBAAyB,KAAK,CAAC,MAAM,CAAC,KAAK,2EAA2E,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC1J,CAAC;YAED,mCAAmC;YACnC,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,gCAAgC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;YACnE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,kEAAkE,CAAC,CAAC;YAE9F,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACjC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,MAAM,SAAS,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3D,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,SAAS,GAAG,KAAK,GAAG,SAAS,EAAE,CAAC,CAAC;gBACpE,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;oBACjC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBACnE,CAAC;gBACD,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACf,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;wBACxC,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;wBAChE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;oBAC/E,CAAC;gBACL,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;YAC7B,CAAC;YAED,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACpD,CAAC;QAED,KAAK,eAAe,CAAC,CAAC,CAAC;YACnB,MAAM,IAAI,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACrD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,yBAAyB,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YAE3F,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,0BAA0B,KAAK,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC;YAElE,IAAI,MAAM,EAAE,eAAe,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,eAAe,CAAC,MAAM,kBAAkB,MAAM,CAAC,oBAAoB,EAAE,MAAM,IAAI,CAAC,uBAAuB,CAAC,CAAC;gBAC1I,KAAK,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;oBACzD,MAAM,KAAK,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBACnE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,UAAU,KAAK,KAAK,MAAM,CAAC,CAAC,SAAS,IAAI,SAAS,MAAM,CAAC,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC;gBACtG,CAAC;YACL,CAAC;YAED,IAAI,MAAM,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxD,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;gBACxC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,mBAAmB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;oBAClE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC;gBACpD,CAAC;YACL,CAAC;YAED,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACvF,CAAC;QAED,KAAK,UAAU,CAAC,CAAC,CAAC;YACd,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;YACtD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YACvF,OAAO;gBACH,IAAI,EAAE,MAAM,EAAE,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;gBACxD,IAAI,EAAE,MAAM;aACf,CAAC;QACN,CAAC;QAED,KAAK,eAAe,CAAC,CAAC,CAAC;YACnB,4EAA4E;YAC5E,qEAAqE;YACrE,MAAM,IAAI,GAAG;gBACT,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;gBACzB,KAAK,EAAE,EAAE;gBACT,YAAY,EAAE,IAAI;gBAClB,gBAAgB,EAAE,IAAI;aACzB,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YACrF,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;YAChC,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;YAC3D,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,2DAA2D,CAAC,CAAC;YAEvF,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;gBAClC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,SAAS,GAAG,KAAK,EAAE,CAAC,CAAC;gBACxD,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;oBACjC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBACnE,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;YAED,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACpD,CAAC;IACL,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,SAAS,cAAc,CAAC,EAA0B,EAAE,MAAW;IAC3D,OAAO,EAAE,OAAO,EAAE,KAAc,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AACnD,CAAC;AAED,SAAS,YAAY,CAAC,EAA0B,EAAE,IAAY,EAAE,OAAe,EAAE,IAAU;IACvF,OAAO,EAAE,OAAO,EAAE,KAAc,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AAChG,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,MAAM,UAAU,gBAAgB,CAC5B,GAAY,EACZ,YAA4B;IAE5B,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QACnD,2CAA2C;QAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAyB,CAAC;QAE3C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;YAClC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CACvB,YAAY,CAAC,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,4CAA4C,CAAC,CACvF,CAAC;QACN,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC;QAElC,wBAAwB;QACxB,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YAClB,KAAK,cAAc;gBACf,MAAM,CAAC,gBAAgB;YAE3B,qDAAqD;YACrD,KAAK,gBAAgB,CAAC;YACtB,KAAK,WAAW,CAAC;YACjB,KAAK,cAAc,CAAC;YACpB,KAAK,YAAY;gBACb,OAAO,GAAG,CAAC,IAAI,CACX,YAAY,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,qBAAqB,IAAI,CAAC,MAAM,mDAAmD,CAAC,CACvH,CAAC;YAEN;gBACI,OAAO,GAAG,CAAC,IAAI,CACX,YAAY,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,qBAAqB,IAAI,CAAC,MAAM,EAAE,CAAC,CACtE,CAAC;QACV,CAAC;QAED,6CAA6C;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,OAAiC,CAAC;QAC/D,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YAC1B,OAAO,GAAG,CAAC,IAAI,CACX,YAAY,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,iEAAiE,CAAC,CACrG,CAAC;QACN,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QACtE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;YAClB,OAAO,GAAG,CAAC,IAAI,CACX,YAAY,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,+CAA+C,CAAC,CACnF,CAAC;QACN,CAAC;QAED,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC;QAEhC,uBAAuB;QACvB,gFAAgF;QAChF,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;eAC5E,GAAG,CAAC,OAAO,CAAC,WAAW,CAAY;eACnC,GAAG,CAAC,KAAK,CAAC,OAAkB;eAC7B,EAAE,CAAC;QAEV,MAAM,MAAM,GAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAY;eAC3C,GAAG,CAAC,KAAK,CAAC,OAAkB;eAC7B,WAAW,CAAC;QAEnB,gFAAgF;QAChF,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,QAAQ,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACzD,MAAM,SAAS,GAAG,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAE3D,OAAO,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE;gBACtC,EAAE,EAAE,MAAM;gBACV,SAAS;gBACT,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE;gBAC9B,SAAS,EAAE,CAAC;wBACR,IAAI,EAAE,cAAc;wBACpB,KAAK,EAAE,CAAC;gCACJ,IAAI,EAAE,MAAM;gCACZ,IAAI,EAAE,gKAAgK;6BACzK,CAAC;qBACL,CAAC;aACM,CAAC,CAAC,CAAC;QACnB,CAAC;QAED,0BAA0B;QAC1B,IAAI,CAAC;YACD,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;YACxC,OAAO,CAAC,KAAK,CAAC,wBAAwB,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAErF,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,QAAQ,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACzD,MAAM,SAAS,GAAG,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAE3D,sEAAsE;YACtE,MAAM,SAAS,GAAyB;gBACpC;oBACI,IAAI,EAAE,iBAAiB;oBACvB,WAAW,EAAE,2BAA2B,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;oBACrE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;iBAC/C;aACJ,CAAC;YAEF,uEAAuE;YACvE,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,mBAAmB,IAAI,EAAE,CAAC;YAC9E,IAAI,eAAe,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC9D,SAAS,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,UAAU;oBAChB,WAAW,EAAE,kDAAkD;oBAC/D,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,CAAC;iBAC7E,CAAC,CAAC;YACP,CAAC;YAED,OAAO,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE;gBACtC,EAAE,EAAE,MAAM;gBACV,SAAS;gBACT,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE;gBAC9B,SAAS;aACD,CAAC,CAAC,CAAC;QAEnB,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAChB,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;YACxC,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,GAAG,CAAC,OAAO,IAAI,gBAAgB,CAAC;YAErF,OAAO,CAAC,KAAK,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;YAExC,4DAA4D;YAC5D,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;gBAC3C,OAAO,GAAG,CAAC,IAAI,CACX,YAAY,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,iBAAiB,MAAM,EAAE,CAAC,CAC7D,CAAC;YACN,CAAC;YAED,OAAO,GAAG,CAAC,IAAI,CACX,YAAY,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,uBAAuB,MAAM,EAAE,CAAC,CACnE,CAAC;QACN,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Fodda Research Agent — System Instruction Builder
3
+ *
4
+ * Loads the 5 skill files and assembles a system instruction for the
5
+ * Gemini Interactions API. This is the "agent" — a skill-injected system
6
+ * prompt that tells Gemini how to conduct Fodda-style research.
7
+ *
8
+ * Usage:
9
+ * import { buildResearcherInstruction } from './agents/fodda-researcher/index.js';
10
+ * const systemInstruction = buildResearcherInstruction(query, graphContext);
11
+ */
12
+ /**
13
+ * Context about pre-fetched Fodda graph results, injected into the
14
+ * system instruction so the agent can reference existing knowledge.
15
+ */
16
+ export interface GraphContext {
17
+ /** Pre-fetched trends from Fodda graphs, stringified JSON */
18
+ graphResults?: string;
19
+ /** Which graphs were searched */
20
+ graphsSearched?: string[];
21
+ /** Total trends found across all graphs */
22
+ totalTrends?: number;
23
+ /** Total evidence pieces collected */
24
+ totalEvidence?: number;
25
+ /** Optional specific graph to focus on (undefined = search all) */
26
+ focusGraphId?: string | undefined;
27
+ }
28
+ /**
29
+ * Build the complete system instruction for the Fodda Research Agent.
30
+ *
31
+ * Concatenates all 5 skill files with a mission preamble and any
32
+ * graph context that was pre-fetched from Fodda's knowledge graphs.
33
+ */
34
+ export declare function buildResearcherInstruction(query: string, context?: GraphContext): string;
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agents/fodda-researcher/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,YAAY,GACvB,MAAM,CA8CR"}