@cogitator-ai/next 0.4.2 → 0.6.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 (50) hide show
  1. package/README.md +120 -3
  2. package/dist/client/index.d.ts +1 -1
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/use-agent.d.ts.map +1 -1
  5. package/dist/client/use-agent.js +25 -5
  6. package/dist/client/use-agent.js.map +1 -1
  7. package/dist/client/use-chat-state.d.ts +9 -1
  8. package/dist/client/use-chat-state.d.ts.map +1 -1
  9. package/dist/client/use-chat-state.js +11 -0
  10. package/dist/client/use-chat-state.js.map +1 -1
  11. package/dist/client/use-chat.d.ts.map +1 -1
  12. package/dist/client/use-chat.js +96 -17
  13. package/dist/client/use-chat.js.map +1 -1
  14. package/dist/handlers/agent.d.ts.map +1 -1
  15. package/dist/handlers/agent.js +4 -18
  16. package/dist/handlers/agent.js.map +1 -1
  17. package/dist/handlers/chat.d.ts.map +1 -1
  18. package/dist/handlers/chat.js +13 -104
  19. package/dist/handlers/chat.js.map +1 -1
  20. package/dist/handlers/http.d.ts +7 -0
  21. package/dist/handlers/http.d.ts.map +1 -1
  22. package/dist/handlers/http.js +22 -0
  23. package/dist/handlers/http.js.map +1 -1
  24. package/dist/handlers/result.d.ts +7 -0
  25. package/dist/handlers/result.d.ts.map +1 -0
  26. package/dist/handlers/result.js +42 -0
  27. package/dist/handlers/result.js.map +1 -0
  28. package/dist/handlers/resume.d.ts +23 -0
  29. package/dist/handlers/resume.d.ts.map +1 -0
  30. package/dist/handlers/resume.js +131 -0
  31. package/dist/handlers/resume.js.map +1 -0
  32. package/dist/handlers/stream-run.d.ts +18 -0
  33. package/dist/handlers/stream-run.d.ts.map +1 -0
  34. package/dist/handlers/stream-run.js +139 -0
  35. package/dist/handlers/stream-run.js.map +1 -0
  36. package/dist/index.d.ts +2 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/streaming/protocol.d.ts +33 -1
  41. package/dist/streaming/protocol.d.ts.map +1 -1
  42. package/dist/streaming/protocol.js +12 -0
  43. package/dist/streaming/protocol.js.map +1 -1
  44. package/dist/streaming/stream-writer.d.ts +5 -1
  45. package/dist/streaming/stream-writer.d.ts.map +1 -1
  46. package/dist/streaming/stream-writer.js +15 -1
  47. package/dist/streaming/stream-writer.js.map +1 -1
  48. package/dist/types.d.ts +62 -2
  49. package/dist/types.d.ts.map +1 -1
  50. package/package.json +3 -3
package/README.md CHANGED
@@ -159,10 +159,92 @@ Response format:
159
159
  "totalTokens": 650
160
160
  },
161
161
  "toolCalls": [...],
162
- "trace": { "traceId": "trace-xyz", "spans": [...] }
162
+ "trace": { "traceId": "trace-xyz", "spans": [...] },
163
+ "status": "completed"
163
164
  }
164
165
  ```
165
166
 
167
+ A run waiting for [approvals](#approvals) answers `"status": "paused"` with its `pendingApprovals`. A failed run answers `{ "error": message, "code": code }` with the status of its `CogitatorError` (for example `429 LLM_RATE_LIMITED`), and `500` for anything else.
168
+
169
+ ### Multiple users
170
+
171
+ When several people share a server, return the caller's `userId` from `beforeRun`. It reaches `cogitator.run`, which keeps every `threadId` to the user whose run created it:
172
+
173
+ ```typescript
174
+ export const POST = createChatHandler(cogitator, agent, {
175
+ beforeRun: async (req) => {
176
+ const user = await getSession(req);
177
+ if (!user) throw Object.assign(new Error('Unauthorized'), { status: 401 });
178
+ return { userId: user.id };
179
+ },
180
+ });
181
+ ```
182
+
183
+ A `threadId` that belongs to another user is refused before the model is called: `createAgentHandler` answers `403` with `code: "THREAD_ACCESS_DENIED"`, and `createChatHandler` ends the stream with an `error` event carrying that code. Without a `userId`, a caller can use only threads that have no owner.
184
+
185
+ ### Approvals
186
+
187
+ A tool with `requiresApproval` pauses the run before it executes. The runtime keeps the run's checkpoint on the server, per thread; clients only see what waits for a decision:
188
+
189
+ - `createAgentHandler` answers with `"status": "paused"` and `pendingApprovals` (`toolCallId`, `toolName`, `arguments`, `description`, `sideEffects`).
190
+ - `createChatHandler` sends `{"type":"approval-required","threadId":"…","approvals":[…]}` right before `finish`.
191
+
192
+ `createResumeHandler` continues the run. It takes `{ threadId, decisions?, defaultDecision? }`, where a decision is `{ approved: true }` or `{ approved: false, reason? }` by tool call id. Approved calls run, declined ones answer the model with the reason, and calls left undecided pause the run again. Return the caller's `userId` from `beforeRun` as for the other handlers: only the user the run belongs to may resume it.
193
+
194
+ ```typescript
195
+ // app/api/chat/resume/route.ts
196
+ import { createResumeHandler } from '@cogitator-ai/next';
197
+
198
+ export const POST = createResumeHandler(cogitator, agent, {
199
+ stream: true,
200
+ beforeRun: async (req) => ({ userId: (await getSession(req)).id }),
201
+ });
202
+ ```
203
+
204
+ By default it answers like `createAgentHandler`; with `stream: true` it streams the rest of the run like `createChatHandler`, which is what `useCogitatorChat` wants. Another user's run answers `403 THREAD_ACCESS_DENIED`, a thread without a paused run `409 RUN_NOT_PAUSED` (an `error` event when streaming).
205
+
206
+ On the client, `useCogitatorChat({ api, resumeApi })` exposes `pendingApprovals` and continues the run into a new assistant message:
207
+
208
+ ```tsx
209
+ 'use client';
210
+
211
+ import { useCogitatorChat } from '@cogitator-ai/next/client';
212
+
213
+ export function Chat() {
214
+ const { messages, pendingApprovals, approve, deny, isLoading } = useCogitatorChat({
215
+ api: '/api/chat',
216
+ resumeApi: '/api/chat/resume',
217
+ });
218
+
219
+ return (
220
+ <div>
221
+ {messages.map((m) => (
222
+ <p key={m.id}>{m.content}</p>
223
+ ))}
224
+ {pendingApprovals.length > 0 && (
225
+ <div>
226
+ {pendingApprovals.map((call) => (
227
+ <p key={call.toolCallId}>
228
+ {call.toolName}: {JSON.stringify(call.arguments)}
229
+ </p>
230
+ ))}
231
+ <button disabled={isLoading} onClick={() => approve()}>
232
+ Approve
233
+ </button>
234
+ <button disabled={isLoading} onClick={() => deny('Not approved')}>
235
+ Deny
236
+ </button>
237
+ </div>
238
+ )}
239
+ </div>
240
+ );
241
+ }
242
+ ```
243
+
244
+ For one decision per call, use `resume({ decisions: { [toolCallId]: { approved: true } }, defaultDecision: { approved: false } })`.
245
+
246
+ `approve()` and `deny(reason?)` answer every pending call. The approvals clear once the resume is accepted, when the server has nothing paused anymore (`409`), or when the user sends a new message instead, which declines the waiting calls on the server. A JSON `resumeApi` works too: its answer is appended as one assistant message. `useCogitatorAgent({ api, resumeApi })` exposes `pendingApprovals` of the last result and `resume(decisions)`.
247
+
166
248
  ## Client Hooks
167
249
 
168
250
  ### `useCogitatorChat`
@@ -189,6 +271,12 @@ const {
189
271
  appendMessage, // (message: ChatMessage) => void
190
272
  clearMessages, // () => void
191
273
  setMessages, // (messages: ChatMessage[]) => void
274
+
275
+ // Approvals (see "Approvals")
276
+ pendingApprovals, // PendingApproval[]
277
+ resume, // (decisions: ResumeDecisions) => Promise<void>
278
+ approve, // () => Promise<void>
279
+ deny, // (reason?: string) => Promise<void>
192
280
  } = useCogitatorChat({
193
281
  api: '/api/chat',
194
282
  threadId: 'optional-thread-id',
@@ -200,6 +288,11 @@ const {
200
288
  onFinish: (message) => console.log('Done:', message),
201
289
  onToolCall: (toolCall) => console.log('Tool called:', toolCall.name),
202
290
  onToolResult: (result) => console.log('Tool result:', result),
291
+ onReasoning: (delta) => console.log('Thinking:', delta),
292
+ onApprovalRequired: (approvals) => console.log('Waiting for approval:', approvals),
293
+
294
+ // Endpoint of a createResumeHandler, for resume/approve/deny
295
+ resumeApi: '/api/chat/resume',
203
296
 
204
297
  // Retry configuration
205
298
  retry: {
@@ -252,11 +345,15 @@ Hook for non-streaming batch requests (research, analysis, etc).
252
345
  const {
253
346
  run, // (input: AgentInput) => Promise<void>
254
347
  result, // AgentResponse | null
348
+ reasoning, // string | undefined — result?.reasoning
349
+ pendingApprovals, // PendingApproval[] — result?.pendingApprovals
350
+ resume, // (decisions: ResumeDecisions) => Promise<void>
255
351
  isLoading, // boolean
256
352
  error, // Error | null
257
353
  reset, // () => void
258
354
  } = useCogitatorAgent({
259
355
  api: '/api/research',
356
+ resumeApi: '/api/research/resume',
260
357
  headers: { Authorization: 'Bearer token' },
261
358
 
262
359
  onError: (error) => console.error(error),
@@ -309,7 +406,11 @@ data: {"type":"finish","messageId":"msg-1","usage":{...},"threadId":"thread-abc"
309
406
  data: [DONE]
310
407
  ```
311
408
 
312
- If the run fails, the open text block is closed and an `{"type":"error","message":"..."}` event is sent instead of `finish`.
409
+ An agent with `reasoning: { summary: true }` also streams its reasoning summary as `reasoning-start`, `reasoning-delta` and `reasoning-end` events. A text or reasoning block opens with its first delta and is closed before a block of the other kind, a tool call or `finish`, so blocks never overlap. `useCogitatorChat` collects the deltas into `message.reasoning` (and calls `onReasoning` with each one), and `createAgentHandler` returns the summary as `reasoning` next to `usage.reasoningTokens`, `usage.cachedInputTokens` and `usage.cacheWriteTokens` when the provider reports them.
410
+
411
+ A run that pauses for [approvals](#approvals) sends `{"type":"approval-required","threadId":"…","approvals":[…]}` after the open block is closed and before `finish`.
412
+
413
+ If the run fails, the open text or reasoning block is closed and an `{"type":"error","message":"..."}` event is sent instead of `finish`.
313
414
 
314
415
  The server-side building blocks are exported for custom handlers:
315
416
 
@@ -346,6 +447,22 @@ interface AgentResponse {
346
447
  };
347
448
  toolCalls: ToolCall[];
348
449
  trace?: { traceId: string; spans: unknown[] };
450
+ reasoning?: string;
451
+ status?: 'completed' | 'paused';
452
+ pendingApprovals?: PendingApproval[];
453
+ }
454
+
455
+ interface PendingApproval {
456
+ toolCallId: string;
457
+ toolName: string;
458
+ arguments: Record<string, unknown>;
459
+ description: string;
460
+ sideEffects?: string[];
461
+ }
462
+
463
+ interface ResumeDecisions {
464
+ decisions?: Record<string, { approved: true } | { approved: false; reason?: string }>;
465
+ defaultDecision?: { approved: true } | { approved: false; reason?: string };
349
466
  }
350
467
 
351
468
  interface RetryConfig {
@@ -372,7 +489,7 @@ if (error) {
372
489
  }
373
490
  ```
374
491
 
375
- HTTP failures are thrown as `HttpError` (exported from `@cogitator-ai/next/client`) with a `status` property and a message like `Request failed: 400 - No user message provided`. Stream-level `error` events call `onError` and skip `onFinish`.
492
+ HTTP failures are thrown as `HttpError` (exported from `@cogitator-ai/next/client`) with a `status` property and a message like `Request failed: 400 - No user message provided`. Stream-level `error` events call `onError` and skip `onFinish`; when the runtime failed with a `CogitatorError`, the event carries its `code`.
376
493
 
377
494
  With retry enabled, transient errors (network failures, 408/429/502/503/504) are automatically retried; the backoff wait is cancelled by `stop()`:
378
495
 
@@ -1,5 +1,5 @@
1
1
  export { useCogitatorChat } from './use-chat.js';
2
2
  export { useCogitatorAgent } from './use-agent.js';
3
3
  export { HttpError } from './http-error.js';
4
- export type { ChatMessage, ToolCall, UseChatOptions, UseChatReturn, AgentInput, AgentResponse, UseAgentOptions, UseAgentReturn, RetryConfig, ToolResultEvent, } from '../types.js';
4
+ export type { ChatMessage, ToolCall, UseChatOptions, UseChatReturn, AgentInput, AgentResponse, UseAgentOptions, UseAgentReturn, RetryConfig, ToolResultEvent, PendingApproval, ResumeDecisions, ToolApprovalDecision, } from '../types.js';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,YAAY,EACV,WAAW,EACX,QAAQ,EACR,cAAc,EACd,aAAa,EACb,UAAU,EACV,aAAa,EACb,eAAe,EACf,cAAc,EACd,WAAW,EACX,eAAe,GAChB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,YAAY,EACV,WAAW,EACX,QAAQ,EACR,cAAc,EACd,aAAa,EACb,UAAU,EACV,aAAa,EACb,eAAe,EACf,cAAc,EACd,WAAW,EACX,eAAe,EACf,eAAe,EACf,eAAe,EACf,oBAAoB,GACrB,MAAM,aAAa,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-agent.d.ts","sourceRoot":"","sources":["../../src/client/use-agent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA6B,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAI9F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc,CA+E1E"}
1
+ {"version":3,"file":"use-agent.d.ts","sourceRoot":"","sources":["../../src/client/use-agent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAKV,eAAe,EACf,cAAc,EACf,MAAM,aAAa,CAAC;AAMrB,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc,CAyG1E"}
@@ -2,32 +2,34 @@
2
2
  import { useState, useCallback, useEffect, useRef } from 'react';
3
3
  import { withRetry } from './retry.js';
4
4
  import { toHttpError } from './http-error.js';
5
+ const NO_APPROVALS = [];
5
6
  export function useCogitatorAgent(options) {
6
- const { api, headers, onError, onSuccess, retry } = options;
7
+ const { api, resumeApi, headers, onError, onSuccess, retry } = options;
7
8
  const [result, setResult] = useState(null);
8
9
  const [isLoading, setIsLoading] = useState(false);
9
10
  const [error, setError] = useState(null);
10
11
  const activeRequestRef = useRef(null);
12
+ const resultRef = useRef(null);
11
13
  useEffect(() => {
12
14
  return () => {
13
15
  activeRequestRef.current?.abort();
14
16
  activeRequestRef.current = null;
15
17
  };
16
18
  }, []);
17
- const run = useCallback(async (input) => {
19
+ const request = useCallback(async (url, body) => {
18
20
  activeRequestRef.current?.abort();
19
21
  const controller = new AbortController();
20
22
  activeRequestRef.current = controller;
21
23
  setIsLoading(true);
22
24
  setError(null);
23
25
  const executeRequest = async () => {
24
- const response = await fetch(api, {
26
+ const response = await fetch(url, {
25
27
  method: 'POST',
26
28
  headers: {
27
29
  'Content-Type': 'application/json',
28
30
  ...headers,
29
31
  },
30
- body: JSON.stringify(input),
32
+ body: JSON.stringify(body),
31
33
  signal: controller.signal,
32
34
  });
33
35
  if (!response.ok) {
@@ -39,6 +41,7 @@ export function useCogitatorAgent(options) {
39
41
  const data = await withRetry(executeRequest, retry, controller.signal);
40
42
  if (activeRequestRef.current !== controller)
41
43
  return;
44
+ resultRef.current = data;
42
45
  setResult(data);
43
46
  onSuccess?.(data);
44
47
  }
@@ -57,10 +60,24 @@ export function useCogitatorAgent(options) {
57
60
  setIsLoading(false);
58
61
  }
59
62
  }
60
- }, [api, headers, onError, onSuccess, retry]);
63
+ }, [headers, onError, onSuccess, retry]);
64
+ const run = useCallback((input) => request(api, input), [api, request]);
65
+ const resume = useCallback(async (decisions) => {
66
+ const threadId = resultRef.current?.threadId;
67
+ if (!resumeApi || !threadId) {
68
+ const e = new Error(resumeApi
69
+ ? 'There is no result with a paused run to resume'
70
+ : 'useCogitatorAgent needs resumeApi to resume a paused run');
71
+ setError(e);
72
+ onError?.(e);
73
+ return;
74
+ }
75
+ await request(resumeApi, { threadId, ...decisions });
76
+ }, [onError, request, resumeApi]);
61
77
  const reset = useCallback(() => {
62
78
  activeRequestRef.current?.abort();
63
79
  activeRequestRef.current = null;
80
+ resultRef.current = null;
64
81
  setResult(null);
65
82
  setError(null);
66
83
  setIsLoading(false);
@@ -68,6 +85,9 @@ export function useCogitatorAgent(options) {
68
85
  return {
69
86
  run,
70
87
  result,
88
+ reasoning: result?.reasoning,
89
+ pendingApprovals: result?.pendingApprovals ?? NO_APPROVALS,
90
+ resume,
71
91
  isLoading,
72
92
  error,
73
93
  reset,
@@ -1 +1 @@
1
- {"version":3,"file":"use-agent.js","sourceRoot":"","sources":["../../src/client/use-agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-agent.js","sourceRoot":"","sources":["../../src/client/use-agent.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { ChatMessage, ToolCall } from '../types.js';
1
+ import type { ChatMessage, PendingApproval, ToolCall } from '../types.js';
2
2
  export interface ChatState {
3
3
  messages: ChatMessage[];
4
4
  input: string;
@@ -7,7 +7,9 @@ export interface ChatState {
7
7
  threadId: string | undefined;
8
8
  currentMessageId: string | null;
9
9
  currentContent: string;
10
+ currentReasoning: string;
10
11
  currentToolCalls: ToolCall[];
12
+ pendingApprovals: PendingApproval[];
11
13
  }
12
14
  export type ChatAction = {
13
15
  type: 'SET_INPUT';
@@ -34,11 +36,17 @@ export type ChatAction = {
34
36
  } | {
35
37
  type: 'APPEND_CONTENT';
36
38
  payload: string;
39
+ } | {
40
+ type: 'APPEND_REASONING';
41
+ payload: string;
37
42
  } | {
38
43
  type: 'ADD_TOOL_CALL';
39
44
  payload: ToolCall;
40
45
  } | {
41
46
  type: 'FINISH_ASSISTANT_MESSAGE';
47
+ } | {
48
+ type: 'SET_PENDING_APPROVALS';
49
+ payload: PendingApproval[];
42
50
  } | {
43
51
  type: 'SET_MESSAGES';
44
52
  payload: ChatMessage[];
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-state.d.ts","sourceRoot":"","sources":["../../src/client/use-chat-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,QAAQ,EAAE,CAAC;CAC9B;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,0BAA0B,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE/B,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CAkE3E;AAED,wBAAgB,kBAAkB,CAAC,eAAe,CAAC,EAAE,WAAW,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAWhG"}
1
+ {"version":3,"file":"use-chat-state.d.ts","sourceRoot":"","sources":["../../src/client/use-chat-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1E,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,QAAQ,EAAE,CAAC;IAC7B,gBAAgB,EAAE,eAAe,EAAE,CAAC;CACrC;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,0BAA0B,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,OAAO,EAAE,eAAe,EAAE,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE/B,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CA4E3E;AAED,wBAAgB,kBAAkB,CAAC,eAAe,CAAC,EAAE,WAAW,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAahG"}
@@ -19,10 +19,13 @@ export function chatReducer(state, action) {
19
19
  ...state,
20
20
  currentMessageId: action.payload,
21
21
  currentContent: '',
22
+ currentReasoning: '',
22
23
  currentToolCalls: [],
23
24
  };
24
25
  case 'APPEND_CONTENT':
25
26
  return { ...state, currentContent: state.currentContent + action.payload };
27
+ case 'APPEND_REASONING':
28
+ return { ...state, currentReasoning: state.currentReasoning + action.payload };
26
29
  case 'ADD_TOOL_CALL':
27
30
  return { ...state, currentToolCalls: [...state.currentToolCalls, action.payload] };
28
31
  case 'FINISH_ASSISTANT_MESSAGE': {
@@ -32,6 +35,7 @@ export function chatReducer(state, action) {
32
35
  id: state.currentMessageId,
33
36
  role: 'assistant',
34
37
  content: state.currentContent,
38
+ ...(state.currentReasoning && { reasoning: state.currentReasoning }),
35
39
  toolCalls: state.currentToolCalls.length > 0 ? state.currentToolCalls : undefined,
36
40
  createdAt: new Date(),
37
41
  };
@@ -40,9 +44,14 @@ export function chatReducer(state, action) {
40
44
  messages: [...state.messages, assistantMessage],
41
45
  currentMessageId: null,
42
46
  currentContent: '',
47
+ currentReasoning: '',
43
48
  currentToolCalls: [],
44
49
  };
45
50
  }
51
+ case 'SET_PENDING_APPROVALS':
52
+ if (action.payload.length === 0 && state.pendingApprovals.length === 0)
53
+ return state;
54
+ return { ...state, pendingApprovals: action.payload };
46
55
  case 'SET_MESSAGES':
47
56
  return { ...state, messages: action.payload };
48
57
  case 'CLEAR_MESSAGES':
@@ -60,7 +69,9 @@ export function createInitialState(initialMessages, threadId) {
60
69
  threadId,
61
70
  currentMessageId: null,
62
71
  currentContent: '',
72
+ currentReasoning: '',
63
73
  currentToolCalls: [],
74
+ pendingApprovals: [],
64
75
  };
65
76
  }
66
77
  //# sourceMappingURL=use-chat-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-state.js","sourceRoot":"","sources":["../../src/client/use-chat-state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-chat-state.js","sourceRoot":"","sources":["../../src/client/use-chat-state.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat.d.ts","sourceRoot":"","sources":["../../src/client/use-chat.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAId,MAAM,aAAa,CAAC;AAyCrB,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CAiSvE"}
1
+ {"version":3,"file":"use-chat.d.ts","sourceRoot":"","sources":["../../src/client/use-chat.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,cAAc,EACd,aAAa,EAMd,MAAM,aAAa,CAAC;AAgDrB,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CAkavE"}
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useReducer, useRef } from 'react';
3
3
  import { parseSSEStream } from './sse-parser.js';
4
4
  import { chatReducer, createInitialState, } from './use-chat-state.js';
5
5
  import { withRetry } from './retry.js';
6
- import { toHttpError } from './http-error.js';
6
+ import { HttpError, toHttpError } from './http-error.js';
7
7
  let idCounter = 0;
8
8
  function generateClientId() {
9
9
  return `msg_${Date.now().toString(36)}_${(idCounter++).toString(36)}`;
@@ -21,6 +21,9 @@ function parseToolArguments(raw) {
21
21
  catch { }
22
22
  return {};
23
23
  }
24
+ function isEventStream(response) {
25
+ return response.headers.get('Content-Type')?.includes('text/event-stream') ?? false;
26
+ }
24
27
  function pendingAssistantMessage(state) {
25
28
  if (!state.currentMessageId)
26
29
  return null;
@@ -28,11 +31,12 @@ function pendingAssistantMessage(state) {
28
31
  id: state.currentMessageId,
29
32
  role: 'assistant',
30
33
  content: state.currentContent,
34
+ ...(state.currentReasoning && { reasoning: state.currentReasoning }),
31
35
  toolCalls: state.currentToolCalls.length > 0 ? state.currentToolCalls : undefined,
32
36
  };
33
37
  }
34
38
  export function useCogitatorChat(options) {
35
- const { api, initialMessages, headers, onError, onFinish, onToolCall, onToolResult, retry } = options;
39
+ const { api, initialMessages, headers, onError, onFinish, onToolCall, onToolResult, onReasoning, onApprovalRequired, resumeApi, retry, } = options;
36
40
  const [state, dispatch] = useReducer(chatReducer, createInitialState(initialMessages, options.threadId));
37
41
  const stateRef = useRef(state);
38
42
  const activeRequestRef = useRef(null);
@@ -55,6 +59,13 @@ export function useCogitatorChat(options) {
55
59
  apply({ type: 'FINISH_ASSISTANT_MESSAGE' });
56
60
  apply({ type: 'STOP_LOADING' });
57
61
  }, [apply]);
62
+ const requireApproval = useCallback((approvals, threadId) => {
63
+ if (threadId && threadId !== stateRef.current.threadId) {
64
+ apply({ type: 'SET_THREAD_ID', payload: threadId });
65
+ }
66
+ apply({ type: 'SET_PENDING_APPROVALS', payload: approvals });
67
+ onApprovalRequired?.(approvals);
68
+ }, [apply, onApprovalRequired]);
58
69
  const handleStreamEvent = useCallback((event, toolCalls) => {
59
70
  switch (event.type) {
60
71
  case 'start':
@@ -63,6 +74,10 @@ export function useCogitatorChat(options) {
63
74
  case 'text-delta':
64
75
  apply({ type: 'APPEND_CONTENT', payload: event.delta });
65
76
  return false;
77
+ case 'reasoning-delta':
78
+ apply({ type: 'APPEND_REASONING', payload: event.delta });
79
+ onReasoning?.(event.delta);
80
+ return false;
66
81
  case 'tool-call-start':
67
82
  toolCalls.set(event.id, { name: event.toolName, args: '' });
68
83
  return false;
@@ -95,6 +110,9 @@ export function useCogitatorChat(options) {
95
110
  onToolResult?.(toolResult);
96
111
  return false;
97
112
  }
113
+ case 'approval-required':
114
+ requireApproval(event.approvals, event.threadId);
115
+ return false;
98
116
  case 'finish':
99
117
  if (event.threadId && event.threadId !== stateRef.current.threadId) {
100
118
  apply({ type: 'SET_THREAD_ID', payload: event.threadId });
@@ -109,7 +127,7 @@ export function useCogitatorChat(options) {
109
127
  default:
110
128
  return false;
111
129
  }
112
- }, [apply, onError, onToolCall, onToolResult]);
130
+ }, [apply, onError, onReasoning, onToolCall, onToolResult, requireApproval]);
113
131
  const processStream = useCallback(async (response, controller) => {
114
132
  if (!response.body) {
115
133
  throw new Error('Response body is null');
@@ -138,27 +156,41 @@ export function useCogitatorChat(options) {
138
156
  onFinish?.(finished);
139
157
  }
140
158
  }, [apply, handleStreamEvent, onFinish]);
141
- const sendWithMessages = useCallback(async (messages, threadId, metadata) => {
159
+ const processResult = useCallback(async (response, controller) => {
160
+ const result = (await response.json());
161
+ if (activeRequestRef.current !== controller)
162
+ return;
163
+ activeRequestRef.current = null;
164
+ const message = {
165
+ id: generateClientId(),
166
+ role: 'assistant',
167
+ content: result.output,
168
+ ...(result.reasoning && { reasoning: result.reasoning }),
169
+ toolCalls: result.toolCalls.length > 0 ? result.toolCalls : undefined,
170
+ createdAt: new Date(),
171
+ };
172
+ apply({ type: 'APPEND_MESSAGE', payload: message });
173
+ if (result.status === 'paused') {
174
+ requireApproval(result.pendingApprovals ?? [], result.threadId);
175
+ }
176
+ else if (result.threadId && result.threadId !== stateRef.current.threadId) {
177
+ apply({ type: 'SET_THREAD_ID', payload: result.threadId });
178
+ }
179
+ apply({ type: 'STOP_LOADING' });
180
+ onFinish?.(message);
181
+ }, [apply, onFinish, requireApproval]);
182
+ const request = useCallback(async (url, body, handle, onFailure) => {
142
183
  const controller = new AbortController();
143
184
  activeRequestRef.current = controller;
144
185
  apply({ type: 'START_LOADING' });
145
186
  const doFetch = async () => {
146
- const response = await fetch(api, {
187
+ const response = await fetch(url, {
147
188
  method: 'POST',
148
189
  headers: {
149
190
  'Content-Type': 'application/json',
150
191
  ...headers,
151
192
  },
152
- body: JSON.stringify({
153
- messages: messages.map((m) => ({
154
- id: m.id,
155
- role: m.role,
156
- content: m.content,
157
- metadata: m.metadata,
158
- })),
159
- threadId,
160
- metadata,
161
- }),
193
+ body: JSON.stringify(body),
162
194
  signal: controller.signal,
163
195
  });
164
196
  if (!response.ok) {
@@ -168,7 +200,7 @@ export function useCogitatorChat(options) {
168
200
  };
169
201
  try {
170
202
  const response = await withRetry(doFetch, retry, controller.signal);
171
- await processStream(response, controller);
203
+ await handle(response, controller);
172
204
  }
173
205
  catch (err) {
174
206
  if (activeRequestRef.current !== controller)
@@ -180,10 +212,24 @@ export function useCogitatorChat(options) {
180
212
  return;
181
213
  }
182
214
  const error = err instanceof Error ? err : new Error('Unknown error');
215
+ onFailure?.(error);
183
216
  apply({ type: 'SET_ERROR', payload: error });
184
217
  onError?.(error);
185
218
  }
186
- }, [api, apply, headers, onError, processStream, retry]);
219
+ }, [apply, headers, onError, retry]);
220
+ const sendWithMessages = useCallback(async (messages, threadId, metadata) => {
221
+ apply({ type: 'SET_PENDING_APPROVALS', payload: [] });
222
+ await request(api, {
223
+ messages: messages.map((m) => ({
224
+ id: m.id,
225
+ role: m.role,
226
+ content: m.content,
227
+ metadata: m.metadata,
228
+ })),
229
+ threadId,
230
+ metadata,
231
+ }, processStream);
232
+ }, [api, apply, processStream, request]);
187
233
  const send = useCallback(async (inputOverride, metadata) => {
188
234
  const messageContent = inputOverride ?? stateRef.current.input;
189
235
  if (!messageContent.trim())
@@ -221,6 +267,35 @@ export function useCogitatorChat(options) {
221
267
  apply({ type: 'SET_MESSAGES', payload: messages });
222
268
  await sendWithMessages(messages, current.threadId, lastUserMessage.metadata);
223
269
  }, [apply, interrupt, sendWithMessages]);
270
+ const fail = useCallback((message) => {
271
+ const error = new Error(message);
272
+ apply({ type: 'SET_ERROR', payload: error });
273
+ onError?.(error);
274
+ }, [apply, onError]);
275
+ const resume = useCallback(async (decisions) => {
276
+ const { threadId } = stateRef.current;
277
+ if (!resumeApi) {
278
+ fail('useCogitatorChat needs resumeApi to resume a paused run');
279
+ return;
280
+ }
281
+ if (!threadId) {
282
+ fail('There is no thread with a paused run to resume');
283
+ return;
284
+ }
285
+ interrupt();
286
+ await request(resumeApi, { threadId, ...decisions }, async (response, controller) => {
287
+ apply({ type: 'SET_PENDING_APPROVALS', payload: [] });
288
+ await (isEventStream(response) ? processStream : processResult)(response, controller);
289
+ }, (error) => {
290
+ if (error instanceof HttpError && error.status === 409) {
291
+ apply({ type: 'SET_PENDING_APPROVALS', payload: [] });
292
+ }
293
+ });
294
+ }, [apply, fail, interrupt, processResult, processStream, request, resumeApi]);
295
+ const approve = useCallback(() => resume({ defaultDecision: { approved: true } }), [resume]);
296
+ const deny = useCallback((reason) => resume({
297
+ defaultDecision: reason === undefined ? { approved: false } : { approved: false, reason },
298
+ }), [resume]);
224
299
  const setInput = useCallback((value) => {
225
300
  apply({ type: 'SET_INPUT', payload: value });
226
301
  }, [apply]);
@@ -252,6 +327,10 @@ export function useCogitatorChat(options) {
252
327
  appendMessage,
253
328
  clearMessages,
254
329
  setMessages,
330
+ pendingApprovals: state.pendingApprovals,
331
+ resume,
332
+ approve,
333
+ deny,
255
334
  };
256
335
  }
257
336
  //# sourceMappingURL=use-chat.js.map