@revealui/ai 0.2.9 → 0.4.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 (82) hide show
  1. package/README.md +200 -26
  2. package/dist/a2a/handler.d.ts +3 -1
  3. package/dist/a2a/handler.d.ts.map +1 -1
  4. package/dist/a2a/handler.js +24 -7
  5. package/dist/a2a/task-store.d.ts.map +1 -1
  6. package/dist/a2a/task-store.js +5 -1
  7. package/dist/client/hooks/useAgentStream.d.ts +84 -1
  8. package/dist/client/hooks/useAgentStream.d.ts.map +1 -1
  9. package/dist/client/hooks/useAgentStream.js +106 -10
  10. package/dist/index.d.ts +4 -6
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -15
  13. package/dist/ingestion/admin-indexer.js +1 -1
  14. package/dist/ingestion/pipeline.d.ts +1 -1
  15. package/dist/ingestion/pipeline.d.ts.map +1 -1
  16. package/dist/llm/client.d.ts +33 -10
  17. package/dist/llm/client.d.ts.map +1 -1
  18. package/dist/llm/client.js +70 -57
  19. package/dist/llm/key-validator.d.ts.map +1 -1
  20. package/dist/llm/key-validator.js +0 -27
  21. package/dist/llm/providers/inference-snaps.d.ts +7 -5
  22. package/dist/llm/providers/inference-snaps.d.ts.map +1 -1
  23. package/dist/llm/providers/inference-snaps.js +7 -5
  24. package/dist/llm/providers/openai-compat.d.ts +1 -1
  25. package/dist/llm/providers/openai-compat.js +1 -1
  26. package/dist/llm/response-cache.d.ts +1 -2
  27. package/dist/llm/response-cache.d.ts.map +1 -1
  28. package/dist/llm/response-cache.js +1 -2
  29. package/dist/llm/server.d.ts +1 -1
  30. package/dist/llm/server.d.ts.map +1 -1
  31. package/dist/llm/server.js +3 -1
  32. package/dist/memory/crdt/lww-register.js +1 -1
  33. package/dist/memory/preferences/user-preferences-manager.d.ts.map +1 -1
  34. package/dist/memory/preferences/user-preferences-manager.js +1 -1
  35. package/dist/memory/services/index.d.ts +2 -0
  36. package/dist/memory/services/index.d.ts.map +1 -1
  37. package/dist/memory/services/index.js +1 -0
  38. package/dist/memory/services/reconciliation-service.d.ts +64 -0
  39. package/dist/memory/services/reconciliation-service.d.ts.map +1 -0
  40. package/dist/memory/services/reconciliation-service.js +127 -0
  41. package/dist/memory/stores/working-memory.d.ts.map +1 -1
  42. package/dist/memory/stores/working-memory.js +1 -1
  43. package/dist/memory/utils/index.d.ts +1 -2
  44. package/dist/memory/utils/index.d.ts.map +1 -1
  45. package/dist/memory/utils/index.js +1 -2
  46. package/dist/memory/utils/sql-helpers.d.ts +21 -66
  47. package/dist/memory/utils/sql-helpers.d.ts.map +1 -1
  48. package/dist/memory/utils/sql-helpers.js +34 -169
  49. package/dist/memory/vector/vector-memory-service.d.ts.map +1 -1
  50. package/dist/memory/vector/vector-memory-service.js +6 -1
  51. package/dist/orchestration/runtime.d.ts +30 -1
  52. package/dist/orchestration/runtime.d.ts.map +1 -1
  53. package/dist/orchestration/runtime.js +20 -3
  54. package/dist/orchestration/streaming-runtime.d.ts +48 -1
  55. package/dist/orchestration/streaming-runtime.d.ts.map +1 -1
  56. package/dist/orchestration/ticket-agent.d.ts +10 -1
  57. package/dist/orchestration/ticket-agent.d.ts.map +1 -1
  58. package/dist/orchestration/ticket-agent.js +11 -2
  59. package/dist/skills/catalog/vercel-catalog.d.ts.map +1 -1
  60. package/dist/skills/catalog/vercel-catalog.js +13 -7
  61. package/dist/tools/mcp-adapter.d.ts +192 -1
  62. package/dist/tools/mcp-adapter.d.ts.map +1 -1
  63. package/dist/tools/mcp-adapter.js +434 -1
  64. package/dist/tools/mcp-elicitation.d.ts +128 -0
  65. package/dist/tools/mcp-elicitation.d.ts.map +1 -0
  66. package/dist/tools/mcp-elicitation.js +121 -0
  67. package/dist/tools/mcp-events.d.ts +270 -0
  68. package/dist/tools/mcp-events.d.ts.map +1 -0
  69. package/dist/tools/mcp-events.js +165 -0
  70. package/dist/tools/mcp-sampling.d.ts +155 -0
  71. package/dist/tools/mcp-sampling.d.ts.map +1 -0
  72. package/dist/tools/mcp-sampling.js +171 -0
  73. package/dist/tools/ticket-tools.d.ts +35 -2
  74. package/dist/tools/ticket-tools.d.ts.map +1 -1
  75. package/dist/tools/ticket-tools.js +32 -2
  76. package/package.json +38 -12
  77. package/dist/llm/providers/vultr.d.ts +0 -18
  78. package/dist/llm/providers/vultr.d.ts.map +0 -1
  79. package/dist/llm/providers/vultr.js +0 -169
  80. package/dist/memory/utils/deep-clone.d.ts +0 -10
  81. package/dist/memory/utils/deep-clone.d.ts.map +0 -1
  82. package/dist/memory/utils/deep-clone.js +0 -9
package/README.md CHANGED
@@ -8,13 +8,211 @@ AI system for RevealUI - memory, LLM, orchestration, and tools.
8
8
  ## Features
9
9
 
10
10
  - **Memory System**: CRDT-based persistent memory (Working, Episodic, Semantic)
11
- - **LLM Integration**: Provider abstractions for Anthropic, GROQ, Ollama, and more
11
+ - **LLM Integration**: Provider abstractions for Anthropic, GROQ, Ollama, Canonical Inference Snaps, and more
12
12
  - **Agent Orchestration**: Runtime and execution engine for AI agents
13
- - **Tool Calling**: Tool registry and execution system
13
+ - **Tool Calling**: Tool registry + standard-MCP-client integration (Stage 5.1a)
14
14
  - **Vector Search**: Semantic search with pgvector
15
15
  - **Type-safe**: Full TypeScript support
16
16
  - **Performant**: Optimized for low-latency operations
17
17
 
18
+ ## Reference stack (Ubuntu)
19
+
20
+ The recommended on-prem / on-device stack pairs `@revealui/ai` with a
21
+ **Canonical Inference Snap** for local LLM inference:
22
+
23
+ ```
24
+ @revealui/ai (this package)
25
+
26
+ ├── agent runtime + tool-calling loop
27
+
28
+ ├── MCP client → @revealui/mcp/client → tools/resources/prompts from MCP servers
29
+
30
+ └── LLM provider → OpenAI-compatible HTTP → localhost:<port>/v1
31
+
32
+
33
+ Canonical Inference Snap
34
+ (DeepSeek R1, Qwen 2.5 VL,
35
+ Gemma 3, Nemotron Nano —
36
+ silicon-optimized on Intel/
37
+ Ampere/NVIDIA/NPU)
38
+ ```
39
+
40
+ Quick setup:
41
+
42
+ ```bash
43
+ sudo snap install gemma3 # or deepseek-r1, qwen-vl, etc.
44
+ gemma3 set http.port=9090
45
+ gemma3 status # confirms base URL
46
+ ```
47
+
48
+ ```typescript
49
+ import { InferenceSnapsProvider, LLMClient } from '@revealui/ai'
50
+
51
+ const provider = new InferenceSnapsProvider({
52
+ baseURL: 'http://localhost:9090/v1',
53
+ model: 'gemma3',
54
+ })
55
+
56
+ const client = new LLMClient({ provider })
57
+ ```
58
+
59
+ Cloud providers (Anthropic, OpenAI, GROQ) remain supported; the local
60
+ inference path is the documented default for self-hosted deployments.
61
+
62
+ ## MCP tool integration
63
+
64
+ Standard MCP servers plug into the agent runtime as tool sources. Construct
65
+ an `McpClient` (from `@revealui/mcp/client`), connect it, and pass it to
66
+ `AgentRuntime`:
67
+
68
+ ```typescript
69
+ import { McpClient } from '@revealui/mcp/client'
70
+ import { AgentRuntime } from '@revealui/ai'
71
+
72
+ const contentClient = new McpClient({
73
+ clientInfo: { name: 'my-agent', version: '1.0.0' },
74
+ transport: { kind: 'streamable-http', url: 'https://admin.example.com/api/mcp/content' },
75
+ })
76
+ await contentClient.connect()
77
+
78
+ const runtime = new AgentRuntime({
79
+ mcpClients: [{ name: 'content', client: contentClient }],
80
+ })
81
+ ```
82
+
83
+ Tools from each client are namespaced as `mcp_<name>__<toolName>` so multiple
84
+ clients coexist without collisions.
85
+
86
+ ### Resources + prompts (Stage 5.1b)
87
+
88
+ When an MCP client advertises resources and/or prompts, the adapter
89
+ additionally emits per-server meta-tools so the agent can read them on
90
+ demand without any bespoke wiring:
91
+
92
+ | Meta-tool | Calls | Returns |
93
+ |---|---|---|
94
+ | `mcp_<ns>__list_resources` | `client.listResources()` | `[{ uri, name?, description?, mimeType? }, …]` |
95
+ | `mcp_<ns>__read_resource({ uri })` | `client.readResource(uri)` | resource contents; text parts flattened into the `content` field for token-efficient LLM context |
96
+ | `mcp_<ns>__list_prompts` | `client.listPrompts()` | `[{ name, description?, arguments? }, …]` |
97
+ | `mcp_<ns>__get_prompt({ name, args? })` | `client.getPrompt(name, args)` | `{ description?, messages }`; text messages flattened to `<role>: <text>` |
98
+
99
+ All four are opt-out via `include` on `createToolsFromMcpClient()`. Meta-tools
100
+ are silently skipped when the client doesn't implement the underlying
101
+ method (e.g. servers that don't advertise the resources capability).
102
+
103
+ ```typescript
104
+ // Include every primitive (default)
105
+ const tools = await createToolsFromMcpClient(client, { namespace: 'content' })
106
+
107
+ // Tools only, skip the resources/prompts meta-tools
108
+ const toolsOnly = await createToolsFromMcpClient(client, {
109
+ namespace: 'content',
110
+ include: { tools: true, resources: false, prompts: false },
111
+ })
112
+ ```
113
+
114
+ ### Elicitation, progress, cancellation (Stage 5.3)
115
+
116
+ MCP servers can ask the user for structured input mid-flow
117
+ (`elicitation/create`), report progress on long-running tool calls, and
118
+ respect cancellation. `@revealui/ai` wires all three through consumer
119
+ callbacks — the agent package stays UI-agnostic:
120
+
121
+ ```typescript
122
+ import { McpClient } from '@revealui/mcp/client'
123
+ import { createElicitationHandler, createToolsFromMcpClient } from '@revealui/ai'
124
+
125
+ const controller = new AbortController() // wire to a UI cancel button
126
+
127
+ const client = new McpClient({
128
+ clientInfo: { name: 'my-agent', version: '1.0.0' },
129
+ transport: { kind: 'streamable-http', url: '…' },
130
+ elicitationHandler: createElicitationHandler({
131
+ onElicit: async ({ message, requestedSchema }) => {
132
+ const form = await showFormDialog({ title: message, schema: requestedSchema })
133
+ if (!form) return { action: 'cancel' }
134
+ return { action: 'accept', content: form.values }
135
+ },
136
+ timeoutMs: 60_000, // auto-cancel if no response
137
+ // allowUrlMode: false // default — URL-mode auto-declines
138
+ }),
139
+ })
140
+ await client.connect()
141
+
142
+ const tools = await createToolsFromMcpClient(client, {
143
+ namespace: 'content',
144
+ signal: controller.signal, // cancel all MCP RPC when aborted
145
+ onProgress: (event) => { // per-tool-call progress events
146
+ progressBar.update(event.toolName, event.progress.progress, event.progress.total)
147
+ },
148
+ })
149
+ ```
150
+
151
+ **Elicitation safety:**
152
+ - `mode: 'url'` (out-of-band consent) is auto-declined unless
153
+ `allowUrlMode: true`. URL-mode is a phishing vector when users can't
154
+ easily verify the target domain.
155
+ - `timeoutMs` auto-cancels (not declines) when no response arrives.
156
+ Useful in headless automation.
157
+ - Errors thrown inside `onElicit` map to `{ action: 'cancel' }` — the
158
+ server sees a clean non-response, not a crashed protocol.
159
+
160
+ **Progress events** are forwarded from the server's
161
+ `notifications/progress` stream with the namespace + tool name stamped
162
+ for multi-client attribution. Resource + prompt meta-tools also emit
163
+ (via their own `notifications/progress` flows).
164
+
165
+ **Cancellation** uses the MCP spec's `notifications/cancelled` — aborting
166
+ the `AbortSignal` propagates to in-flight RPC calls on the wire, so
167
+ long-running operations stop instead of just being ignored.
168
+
169
+ ### Recursive sampling (Stage 5.2)
170
+
171
+ Some MCP servers need LLM capabilities without bundling a provider. The
172
+ spec lets servers issue `sampling/createMessage` requests — the *client*
173
+ runs the inference, keeps cost + context control, and returns the result.
174
+ On the Ubuntu reference stack, that means servers get LLM access via the
175
+ developer's local Canonical Inference Snap — no cloud round-trip required.
176
+
177
+ ```typescript
178
+ import { McpClient } from '@revealui/mcp/client'
179
+ import { InferenceSnapsProvider, createSamplingHandler } from '@revealui/ai'
180
+
181
+ const llm = new InferenceSnapsProvider({
182
+ baseURL: 'http://localhost:9090/v1',
183
+ model: 'gemma3',
184
+ })
185
+
186
+ const client = new McpClient({
187
+ clientInfo: { name: 'my-agent', version: '1.0.0' },
188
+ transport: { kind: 'streamable-http', url: 'https://example.com/mcp' },
189
+ samplingHandler: createSamplingHandler({
190
+ llm,
191
+ defaultModel: 'gemma3',
192
+ allowedModels: ['gemma3', 'deepseek-r1'], // strongly recommended
193
+ onSamplingRequest: (info) => {
194
+ // metering / audit trail
195
+ metrics.incr('mcp.sampling', { model: info.model })
196
+ },
197
+ }),
198
+ })
199
+ await client.connect()
200
+ ```
201
+
202
+ `allowedModels` filters `modelPreferences.hints` from the server — hints
203
+ outside the list are ignored so a malicious server can't escalate costs.
204
+ The handler reports the resolved model back in `result.model`.
205
+
206
+ **Scope in 5.2:** text-only messages (non-text content throws with a clear
207
+ error). Multimodal sampling lands with the provider interface's content
208
+ parts extension. `stopSequences` aren't forwarded to the LLM yet (the
209
+ current `LLMChatOptions` doesn't expose that field); this is advisory per
210
+ spec, so omission is compliant.
211
+
212
+ The legacy `mcpToolSource` path (hypervisor-backed) still works and is
213
+ kept for backwards compatibility, but new integrations should prefer the
214
+ `mcpClients` path.
215
+
18
216
  ## Installation
19
217
 
20
218
  ```bash
@@ -118,30 +316,6 @@ const response = await client.chat([
118
316
  ])
119
317
  ```
120
318
 
121
- #### Vultr (Vultr AI / Serverless Inference)
122
-
123
- You can configure the client to use Vultr Serverless Inference by setting `LLM_PROVIDER=vultr` and providing the `VULTR_API_KEY` and optionally `VULTR_BASE_URL` env vars. Example:
124
-
125
- ```
126
- LLM_PROVIDER=vultr
127
- VULTR_API_KEY=your_inference_api_key
128
- VULTR_BASE_URL=https://api.vultrinference.com/v1 # optional
129
- ```
130
-
131
- The `VultrProvider` supports the chat and (if available for the selected model) embeddings endpoints. Streaming is attempted via the chat streaming endpoint when supported by the API.
132
-
133
- Demo: quick test script
134
-
135
- You can run a quick demo script that exercises chat and embeddings endpoints. From the repository root:
136
-
137
- ```bash
138
- # replace with real values
139
- VULTR_API_KEY=your_key VULTR_MODEL=your-model-id ts-node packages/ai/scripts/test-vultr.ts
140
- ```
141
-
142
- The script prints the raw API responses and a simplified assistant output.
143
-
144
-
145
319
  ### Agent Orchestration
146
320
 
147
321
  Agent runtime and execution engine for autonomous agents.
@@ -21,6 +21,8 @@ declare const RPC_INVALID_REQUEST = -32600;
21
21
  * @param agentId - Optional agent ID (from X-Agent-ID header)
22
22
  * @param llmClient - Optional LLM client for real inference (BYOK)
23
23
  */
24
- export declare function handleA2AJsonRpc(req: A2AJsonRpcRequest, agentId?: string, llmClient?: LLMClient): Promise<A2AJsonRpcResponse>;
24
+ export declare function handleA2AJsonRpc(req: A2AJsonRpcRequest, agentId?: string, llmClient?: LLMClient, options?: {
25
+ paymentVerified?: boolean;
26
+ }): Promise<A2AJsonRpcResponse>;
25
27
  export { RPC_INVALID_REQUEST, RPC_PARSE_ERROR };
26
28
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/a2a/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAGnB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAgBlD,QAAA,MAAM,eAAe,SAAS,CAAC;AAC/B,QAAA,MAAM,mBAAmB,SAAS,CAAC;AA0JnC;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,iBAAiB,EACtB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,SAAS,GACpB,OAAO,CAAC,kBAAkB,CAAC,CAoB7B;AAED,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/a2a/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAGnB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAgBlD,QAAA,MAAM,eAAe,SAAS,CAAC;AAC/B,QAAA,MAAM,mBAAmB,SAAS,CAAC;AA6KnC;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,iBAAiB,EACtB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,SAAS,EACrB,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACtC,OAAO,CAAC,kBAAkB,CAAC,CAoB7B;AAED,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,CAAC"}
@@ -36,7 +36,7 @@ function err(id, code, message, data) {
36
36
  // =============================================================================
37
37
  // Method handlers
38
38
  // =============================================================================
39
- async function handleTasksSend(id, params, agentId, llmClient) {
39
+ async function handleTasksSend(id, params, agentId, llmClient, options) {
40
40
  const parsed = A2ASendTaskParamsSchema.safeParse(params);
41
41
  if (!parsed.success) {
42
42
  return err(id, RPC_INVALID_PARAMS, 'Invalid tasks/send params', parsed.error.issues);
@@ -46,6 +46,26 @@ async function handleTasksSend(id, params, agentId, llmClient) {
46
46
  if (agentId && !agentCardRegistry.has(agentId)) {
47
47
  return err(id, RPC_AGENT_NOT_FOUND, `Agent '${agentId}' not found`);
48
48
  }
49
+ // Resolve agent definition early — needed for the pricing gate below AND
50
+ // for execution context (system prompt, capabilities) further down.
51
+ const agentDef = agentId
52
+ ? agentCardRegistry.getDef(agentId)
53
+ : agentCardRegistry.getDef('revealui-creator');
54
+ // x402 payment gate: when an agent has pricing AND payment was not
55
+ // verified upstream by the route, emit a 'pending-payment' task. The
56
+ // route layer translates this state into HTTP 402 with a fresh
57
+ // X-PAYMENT-REQUIRED header. Pricing rides in task.metadata so the
58
+ // route can build the requirements without re-querying the registry.
59
+ if (agentDef?.pricing && !options?.paymentVerified) {
60
+ const task = createTask({
61
+ id: p.id,
62
+ sessionId: p.sessionId,
63
+ message: p.message,
64
+ metadata: { ...p.metadata, pricing: agentDef.pricing },
65
+ });
66
+ const pending = updateTaskState(task.id, 'pending-payment');
67
+ return ok(id, pending);
68
+ }
49
69
  // Create task in submitted state
50
70
  const task = createTask({
51
71
  id: p.id,
@@ -59,9 +79,6 @@ async function handleTasksSend(id, params, agentId, llmClient) {
59
79
  updateTaskState(task.id, 'working');
60
80
  // Execute via orchestration - for now, produce a direct text response.
61
81
  // Full AgentRuntime integration wires in when an LLM provider is configured.
62
- const agentDef = agentId
63
- ? agentCardRegistry.getDef(agentId)
64
- : agentCardRegistry.getDef('revealui-creator');
65
82
  if (signal?.aborted) {
66
83
  return ok(id, getTask(task.id));
67
84
  }
@@ -151,18 +168,18 @@ function handleTasksCancel(id, params) {
151
168
  * @param agentId - Optional agent ID (from X-Agent-ID header)
152
169
  * @param llmClient - Optional LLM client for real inference (BYOK)
153
170
  */
154
- export async function handleA2AJsonRpc(req, agentId, llmClient) {
171
+ export async function handleA2AJsonRpc(req, agentId, llmClient, options) {
155
172
  const { id, method, params } = req;
156
173
  switch (method) {
157
174
  case 'tasks/send':
158
- return handleTasksSend(id, params, agentId, llmClient);
175
+ return handleTasksSend(id, params, agentId, llmClient, options);
159
176
  case 'tasks/get':
160
177
  return handleTasksGet(id, params);
161
178
  case 'tasks/cancel':
162
179
  return handleTasksCancel(id, params);
163
180
  case 'tasks/sendSubscribe':
164
181
  // SSE streaming is handled at the Hono route level; return a reference task here
165
- return handleTasksSend(id, params, agentId, llmClient);
182
+ return handleTasksSend(id, params, agentId, llmClient, options);
166
183
  default:
167
184
  return err(id, RPC_METHOD_NOT_FOUND, `Method '${method}' not found`);
168
185
  }
@@ -1 +1 @@
1
- {"version":3,"file":"task-store.d.ts","sourceRoot":"","sources":["../../src/a2a/task-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAU1F;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GAAG,OAAO,CAeV;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAElD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,GAAG,IAAI,CAehB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,GAAG,IAAI,CAUhF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAY9C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAE5D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAG1C"}
1
+ {"version":3,"file":"task-store.d.ts","sourceRoot":"","sources":["../../src/a2a/task-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAU1F;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GAAG,OAAO,CAeV;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAElD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,GAAG,IAAI,CAehB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,GAAG,IAAI,CAUhF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAiB9C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAE5D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAG1C"}
@@ -76,7 +76,11 @@ export function cancelTask(id) {
76
76
  const task = _tasks.get(id);
77
77
  if (!task)
78
78
  return false;
79
- const cancelable = task.status.state === 'submitted' || task.status.state === 'working';
79
+ // 'pending-payment' is cancelable so a requester who decides not to pay
80
+ // can release the task slot rather than leaving it dangling.
81
+ const cancelable = task.status.state === 'submitted' ||
82
+ task.status.state === 'working' ||
83
+ task.status.state === 'pending-payment';
80
84
  if (!cancelable)
81
85
  return false;
82
86
  // Signal abort to any running execution
@@ -7,10 +7,20 @@
7
7
  * - chunks: all received chunks in order
8
8
  * - isStreaming: true while the stream is open
9
9
  * - error: last error message, if any
10
+ * - sessionId: agent-run session id from the leading session_info chunk (A.2b)
11
+ * - pendingElicitations: outstanding form-mode elicitation requests by id (A.2b)
12
+ * - submitElicitation: POST a response to /api/agent-stream/elicit (A.2b)
10
13
  * - abort(): cancels the stream
11
14
  */
15
+ /**
16
+ * Mirror of `AgentStreamChunk` in
17
+ * `@revealui/ai/orchestration/streaming-runtime`. Duplicated here (rather
18
+ * than imported) so client bundles don't pull in server-only orchestration
19
+ * code through the type graph. Keep these in lockstep — when a new chunk
20
+ * type lands in the runtime, mirror it here.
21
+ */
12
22
  export interface AgentStreamChunk {
13
- type: 'text' | 'tool_call_start' | 'tool_call_result' | 'error' | 'done';
23
+ type: 'text' | 'tool_call_start' | 'tool_call_result' | 'error' | 'done' | 'session_info' | 'sampling_request' | 'elicitation_request';
14
24
  content?: string;
15
25
  toolCall?: {
16
26
  name: string;
@@ -22,23 +32,96 @@ export interface AgentStreamChunk {
22
32
  tokensUsed?: number;
23
33
  executionTime?: number;
24
34
  };
35
+ /** Present on session_info / sampling_request / elicitation_request. */
36
+ sessionId?: string;
37
+ /** MCP server id. Present on sampling_request / elicitation_request. */
38
+ namespace?: string;
39
+ /** Present on sampling_request — the request shape sent to the LLM. */
40
+ sampling?: {
41
+ model: string;
42
+ messageCount: number;
43
+ maxTokens: number;
44
+ };
45
+ /** Present on elicitation_request — the form payload for the UI. */
46
+ elicitation?: {
47
+ elicitationId: string;
48
+ requestedSchema: unknown;
49
+ message?: string;
50
+ };
25
51
  }
26
52
  export interface AgentStreamRequest {
27
53
  instruction: string;
28
54
  boardId?: string;
29
55
  workspaceId?: string;
30
56
  priority?: 'low' | 'medium' | 'high' | 'critical';
57
+ /**
58
+ * Agent mode. `'admin'` (default) gives the agent the admin-tools surface;
59
+ * `'coding'` adds file-read/write/grep + shell + git tools (Pro-tier;
60
+ * free-tier sees read-only subset). Mirrors `mode?` in the `/api/agent-stream`
61
+ * request schema.
62
+ */
63
+ mode?: 'admin' | 'coding';
31
64
  }
65
+ /**
66
+ * Outstanding elicitation request awaiting a UI response. The hook keeps
67
+ * one entry per `elicitationId`; entries are removed when
68
+ * `submitElicitation()` lands successfully or when the stream ends.
69
+ */
70
+ export interface PendingElicitation {
71
+ elicitationId: string;
72
+ namespace: string;
73
+ requestedSchema: unknown;
74
+ message?: string;
75
+ }
76
+ export type ElicitationAction = 'accept' | 'decline' | 'cancel';
77
+ /**
78
+ * Permitted primitive value types per the MCP spec (`ElicitResult.content`).
79
+ * The hook is a thin transport — the server-side zod schema at
80
+ * `apps/server/src/routes/agent-stream-elicit.ts` is the authoritative
81
+ * validator. We accept a wider input shape so callers can pass
82
+ * `Record<string, unknown>` from generic form serializers without
83
+ * up-front narrowing; non-primitive values get rejected by the server.
84
+ */
85
+ export type ElicitationContentValue = string | number | boolean | string[];
86
+ export type ElicitationContent = Record<string, unknown>;
32
87
  export interface UseAgentStreamState {
33
88
  text: string;
34
89
  chunks: AgentStreamChunk[];
35
90
  isStreaming: boolean;
36
91
  error: string | null;
92
+ /** Set when the leading `session_info` chunk arrives. Null otherwise. */
93
+ sessionId: string | null;
94
+ /** Map of pending elicitations keyed by elicitationId. */
95
+ pendingElicitations: PendingElicitation[];
37
96
  }
38
97
  export interface UseAgentStreamReturn extends UseAgentStreamState {
39
98
  start: (request: AgentStreamRequest, apiBase?: string) => Promise<void>;
40
99
  abort: () => void;
41
100
  reset: () => void;
101
+ /**
102
+ * POST an elicitation response to `/api/agent-stream/elicit` and remove
103
+ * the entry from `pendingElicitations` on success. Throws if the network
104
+ * call fails or the server returns a non-2xx status.
105
+ */
106
+ submitElicitation: (elicitationId: string, action: ElicitationAction, content?: ElicitationContent) => Promise<void>;
42
107
  }
43
108
  export declare function useAgentStream(): UseAgentStreamReturn;
109
+ /**
110
+ * Pure reducer applying one SSE chunk to the hook's state. Extracted for
111
+ * test-friendliness — call sites can simulate `start()` by feeding chunks
112
+ * to `applyChunk()` against `INITIAL_STATE`.
113
+ *
114
+ * @internal
115
+ */
116
+ declare function applyChunk(s: UseAgentStreamState, chunk: AgentStreamChunk): UseAgentStreamState;
117
+ /**
118
+ * Pure reducer used internally to apply a chunk to state. Exported for
119
+ * unit tests so the chunk → state mapping can be verified without
120
+ * mounting a React component or stubbing `fetch`.
121
+ *
122
+ * @internal
123
+ */
124
+ export declare const _applyChunkForTesting: typeof applyChunk;
125
+ export declare const _initialStateForTesting: UseAgentStreamState;
126
+ export {};
44
127
  //# sourceMappingURL=useAgentStream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAgentStream.d.ts","sourceRoot":"","sources":["../../../src/client/hooks/useAgentStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,OAAO,GAAG,MAAM,CAAC;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5D;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;CACnD;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,KAAK,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AASD,wBAAgB,cAAc,IAAI,oBAAoB,CA2FrD"}
1
+ {"version":3,"file":"useAgentStream.d.ts","sourceRoot":"","sources":["../../../src/client/hooks/useAgentStream.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,9 @@
7
7
  * - chunks: all received chunks in order
8
8
  * - isStreaming: true while the stream is open
9
9
  * - error: last error message, if any
10
+ * - sessionId: agent-run session id from the leading session_info chunk (A.2b)
11
+ * - pendingElicitations: outstanding form-mode elicitation requests by id (A.2b)
12
+ * - submitElicitation: POST a response to /api/agent-stream/elicit (A.2b)
10
13
  * - abort(): cancels the stream
11
14
  */
12
15
  'use client';
@@ -16,6 +19,8 @@ const INITIAL_STATE = {
16
19
  chunks: [],
17
20
  isStreaming: false,
18
21
  error: null,
22
+ sessionId: null,
23
+ pendingElicitations: [],
19
24
  };
20
25
  export function useAgentStream() {
21
26
  const [state, setState] = useState(INITIAL_STATE);
@@ -32,12 +37,13 @@ export function useAgentStream() {
32
37
  controllerRef.current?.abort();
33
38
  const controller = new AbortController();
34
39
  controllerRef.current = controller;
35
- setState({ text: '', chunks: [], isStreaming: true, error: null });
40
+ setState({ ...INITIAL_STATE, isStreaming: true });
36
41
  try {
37
42
  const response = await fetch(apiBase, {
38
43
  method: 'POST',
39
44
  headers: { 'Content-Type': 'application/json' },
40
45
  body: JSON.stringify(request),
46
+ credentials: 'include',
41
47
  signal: controller.signal,
42
48
  });
43
49
  if (!response.ok) {
@@ -69,19 +75,15 @@ export function useAgentStream() {
69
75
  if (!dataLine)
70
76
  continue;
71
77
  const jsonStr = dataLine.slice(6);
78
+ let chunk;
72
79
  try {
73
- const chunk = JSON.parse(jsonStr);
74
- setState((s) => ({
75
- ...s,
76
- chunks: [...s.chunks, chunk],
77
- text: chunk.type === 'text' ? s.text + (chunk.content ?? '') : s.text,
78
- error: chunk.type === 'error' ? (chunk.error ?? 'Unknown error') : s.error,
79
- isStreaming: chunk.type !== 'done' && chunk.type !== 'error',
80
- }));
80
+ chunk = JSON.parse(jsonStr);
81
81
  }
82
82
  catch {
83
83
  // Malformed SSE data - skip
84
+ continue;
84
85
  }
86
+ setState((s) => applyChunk(s, chunk));
85
87
  }
86
88
  }
87
89
  }
@@ -97,5 +99,99 @@ export function useAgentStream() {
97
99
  }));
98
100
  }
99
101
  }, []);
100
- return { ...state, start, abort, reset };
102
+ const submitElicitation = useCallback(async (elicitationId, action, content) => {
103
+ const sessionId = stateRef.current.sessionId;
104
+ if (!sessionId) {
105
+ throw new Error('useAgentStream: no sessionId — start() must run before submitElicitation()');
106
+ }
107
+ const body = { sessionId, elicitationId, action };
108
+ if (action === 'accept' && content)
109
+ body.content = content;
110
+ const response = await fetch('/api/agent-stream/elicit', {
111
+ method: 'POST',
112
+ headers: { 'Content-Type': 'application/json' },
113
+ body: JSON.stringify(body),
114
+ credentials: 'include',
115
+ });
116
+ if (!response.ok) {
117
+ const errText = await response.text();
118
+ throw new Error(`elicit response failed: HTTP ${response.status}: ${errText}`);
119
+ }
120
+ // Remove the resolved entry from pendingElicitations
121
+ setState((s) => ({
122
+ ...s,
123
+ pendingElicitations: s.pendingElicitations.filter((p) => p.elicitationId !== elicitationId),
124
+ }));
125
+ }, []);
126
+ // submitElicitation needs the *current* sessionId at call time, so we
127
+ // mirror state into a ref. Avoids stale-closure bugs without making the
128
+ // callback's dependencies churn on every chunk.
129
+ const stateRef = useRef(state);
130
+ stateRef.current = state;
131
+ return { ...state, start, abort, reset, submitElicitation };
132
+ }
133
+ /**
134
+ * Pure reducer applying one SSE chunk to the hook's state. Extracted for
135
+ * test-friendliness — call sites can simulate `start()` by feeding chunks
136
+ * to `applyChunk()` against `INITIAL_STATE`.
137
+ *
138
+ * @internal
139
+ */
140
+ function applyChunk(s, chunk) {
141
+ const next = {
142
+ ...s,
143
+ chunks: [...s.chunks, chunk],
144
+ };
145
+ switch (chunk.type) {
146
+ case 'session_info':
147
+ if (chunk.sessionId)
148
+ next.sessionId = chunk.sessionId;
149
+ break;
150
+ case 'text':
151
+ next.text = s.text + (chunk.content ?? '');
152
+ break;
153
+ case 'error':
154
+ next.error = chunk.error ?? 'Unknown error';
155
+ next.isStreaming = false;
156
+ // Cancel all pending elicitations on stream error — the server-side
157
+ // session is being torn down so any open form is no longer
158
+ // resolvable.
159
+ next.pendingElicitations = [];
160
+ break;
161
+ case 'done':
162
+ next.isStreaming = false;
163
+ next.pendingElicitations = [];
164
+ break;
165
+ case 'elicitation_request':
166
+ if (chunk.elicitation && chunk.namespace) {
167
+ next.pendingElicitations = [
168
+ ...s.pendingElicitations,
169
+ {
170
+ elicitationId: chunk.elicitation.elicitationId,
171
+ namespace: chunk.namespace,
172
+ requestedSchema: chunk.elicitation.requestedSchema,
173
+ ...(chunk.elicitation.message ? { message: chunk.elicitation.message } : {}),
174
+ },
175
+ ];
176
+ }
177
+ break;
178
+ // tool_call_start / tool_call_result / sampling_request: no state
179
+ // mutation beyond appending to `chunks`. Consumers render from the
180
+ // chunk list directly.
181
+ default:
182
+ break;
183
+ }
184
+ return next;
101
185
  }
186
+ // ---------------------------------------------------------------------------
187
+ // Test-only export
188
+ // ---------------------------------------------------------------------------
189
+ /**
190
+ * Pure reducer used internally to apply a chunk to state. Exported for
191
+ * unit tests so the chunk → state mapping can be verified without
192
+ * mounting a React component or stubbing `fetch`.
193
+ *
194
+ * @internal
195
+ */
196
+ export const _applyChunkForTesting = applyChunk;
197
+ export const _initialStateForTesting = INITIAL_STATE;
package/dist/index.d.ts CHANGED
@@ -45,12 +45,6 @@
45
45
  *
46
46
  * @packageDocumentation
47
47
  */
48
- /**
49
- * Check if the AI package is licensed for use.
50
- * Returns false with a warning log if no Pro/Enterprise license is active.
51
- * Call at application startup to verify licensing.
52
- */
53
- export declare function checkAiLicense(): boolean;
54
48
  export * from './a2a/index.js';
55
49
  export * from './audit/index.js';
56
50
  export * from './embeddings/index.js';
@@ -58,6 +52,7 @@ export * from './ingestion/index.js';
58
52
  export * from './llm/client.js';
59
53
  export * from './llm/provider-health.js';
60
54
  export * from './llm/providers/base.js';
55
+ export * from './llm/providers/inference-snaps.js';
61
56
  export * from './llm/providers/openai-compat.js';
62
57
  export * from './llm/token-counter.js';
63
58
  export * from './llm/workspace-provider-config.js';
@@ -75,6 +70,9 @@ export * from './tools/base.js';
75
70
  export * from './tools/deduplicator.js';
76
71
  export * from './tools/document-summarizer.js';
77
72
  export * from './tools/mcp-adapter.js';
73
+ export * from './tools/mcp-elicitation.js';
74
+ export * from './tools/mcp-events.js';
75
+ export * from './tools/mcp-sampling.js';
78
76
  export * from './tools/memory/index.js';
79
77
  export * from './tools/registry.js';
80
78
  export * from './tools/ticket-tools.js';