@cogitator-ai/next 0.5.0 → 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 (46) hide show
  1. package/README.md +102 -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 +2 -15
  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 +14 -109
  19. package/dist/handlers/chat.js.map +1 -1
  20. package/dist/handlers/result.d.ts +7 -0
  21. package/dist/handlers/result.d.ts.map +1 -0
  22. package/dist/handlers/result.js +42 -0
  23. package/dist/handlers/result.js.map +1 -0
  24. package/dist/handlers/resume.d.ts +23 -0
  25. package/dist/handlers/resume.d.ts.map +1 -0
  26. package/dist/handlers/resume.js +131 -0
  27. package/dist/handlers/resume.js.map +1 -0
  28. package/dist/handlers/stream-run.d.ts +18 -0
  29. package/dist/handlers/stream-run.d.ts.map +1 -0
  30. package/dist/handlers/stream-run.js +139 -0
  31. package/dist/handlers/stream-run.js.map +1 -0
  32. package/dist/index.d.ts +2 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +1 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/streaming/protocol.d.ts +33 -1
  37. package/dist/streaming/protocol.d.ts.map +1 -1
  38. package/dist/streaming/protocol.js +12 -0
  39. package/dist/streaming/protocol.js.map +1 -1
  40. package/dist/streaming/stream-writer.d.ts +5 -1
  41. package/dist/streaming/stream-writer.d.ts.map +1 -1
  42. package/dist/streaming/stream-writer.js +15 -1
  43. package/dist/streaming/stream-writer.js.map +1 -1
  44. package/dist/types.d.ts +62 -2
  45. package/dist/types.d.ts.map +1 -1
  46. package/package.json +3 -3
package/README.md CHANGED
@@ -159,11 +159,12 @@ 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
 
166
- 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.
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.
167
168
 
168
169
  ### Multiple users
169
170
 
@@ -181,6 +182,69 @@ export const POST = createChatHandler(cogitator, agent, {
181
182
 
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.
183
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
+
184
248
  ## Client Hooks
185
249
 
186
250
  ### `useCogitatorChat`
@@ -207,6 +271,12 @@ const {
207
271
  appendMessage, // (message: ChatMessage) => void
208
272
  clearMessages, // () => void
209
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>
210
280
  } = useCogitatorChat({
211
281
  api: '/api/chat',
212
282
  threadId: 'optional-thread-id',
@@ -218,6 +288,11 @@ const {
218
288
  onFinish: (message) => console.log('Done:', message),
219
289
  onToolCall: (toolCall) => console.log('Tool called:', toolCall.name),
220
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',
221
296
 
222
297
  // Retry configuration
223
298
  retry: {
@@ -270,11 +345,15 @@ Hook for non-streaming batch requests (research, analysis, etc).
270
345
  const {
271
346
  run, // (input: AgentInput) => Promise<void>
272
347
  result, // AgentResponse | null
348
+ reasoning, // string | undefined — result?.reasoning
349
+ pendingApprovals, // PendingApproval[] — result?.pendingApprovals
350
+ resume, // (decisions: ResumeDecisions) => Promise<void>
273
351
  isLoading, // boolean
274
352
  error, // Error | null
275
353
  reset, // () => void
276
354
  } = useCogitatorAgent({
277
355
  api: '/api/research',
356
+ resumeApi: '/api/research/resume',
278
357
  headers: { Authorization: 'Bearer token' },
279
358
 
280
359
  onError: (error) => console.error(error),
@@ -327,7 +406,11 @@ data: {"type":"finish","messageId":"msg-1","usage":{...},"threadId":"thread-abc"
327
406
  data: [DONE]
328
407
  ```
329
408
 
330
- 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`.
331
414
 
332
415
  The server-side building blocks are exported for custom handlers:
333
416
 
@@ -364,6 +447,22 @@ interface AgentResponse {
364
447
  };
365
448
  toolCalls: ToolCall[];
366
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 };
367
466
  }
368
467
 
369
468
  interface RetryConfig {
@@ -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