@witqq/agent-sdk 0.7.0 → 0.8.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.
- package/README.md +140 -34
- package/dist/{types-CqvUAYxt.d.cts → agent-CW9XbmG_.d.ts} +137 -102
- package/dist/{types-CqvUAYxt.d.ts → agent-DxY68NZL.d.cts} +137 -102
- package/dist/auth/index.cjs +72 -1
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +21 -154
- package/dist/auth/index.d.ts +21 -154
- package/dist/auth/index.js +72 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/backends/claude.cjs +480 -261
- package/dist/backends/claude.cjs.map +1 -1
- package/dist/backends/claude.d.cts +3 -1
- package/dist/backends/claude.d.ts +3 -1
- package/dist/backends/claude.js +480 -261
- package/dist/backends/claude.js.map +1 -1
- package/dist/backends/copilot.cjs +329 -97
- package/dist/backends/copilot.cjs.map +1 -1
- package/dist/backends/copilot.d.cts +12 -4
- package/dist/backends/copilot.d.ts +12 -4
- package/dist/backends/copilot.js +329 -97
- package/dist/backends/copilot.js.map +1 -1
- package/dist/backends/vercel-ai.cjs +294 -61
- package/dist/backends/vercel-ai.cjs.map +1 -1
- package/dist/backends/vercel-ai.d.cts +3 -1
- package/dist/backends/vercel-ai.d.ts +3 -1
- package/dist/backends/vercel-ai.js +294 -61
- package/dist/backends/vercel-ai.js.map +1 -1
- package/dist/backends-BSrsBYFn.d.cts +39 -0
- package/dist/backends-BSrsBYFn.d.ts +39 -0
- package/dist/chat/accumulator.cjs +1 -1
- package/dist/chat/accumulator.cjs.map +1 -1
- package/dist/chat/accumulator.d.cts +5 -2
- package/dist/chat/accumulator.d.ts +5 -2
- package/dist/chat/accumulator.js +1 -1
- package/dist/chat/accumulator.js.map +1 -1
- package/dist/chat/backends.cjs +736 -746
- package/dist/chat/backends.cjs.map +1 -1
- package/dist/chat/backends.d.cts +10 -6
- package/dist/chat/backends.d.ts +10 -6
- package/dist/chat/backends.js +736 -725
- package/dist/chat/backends.js.map +1 -1
- package/dist/chat/context.cjs +50 -0
- package/dist/chat/context.cjs.map +1 -1
- package/dist/chat/context.d.cts +27 -3
- package/dist/chat/context.d.ts +27 -3
- package/dist/chat/context.js +50 -0
- package/dist/chat/context.js.map +1 -1
- package/dist/chat/core.cjs +25 -2
- package/dist/chat/core.cjs.map +1 -1
- package/dist/chat/core.d.cts +30 -381
- package/dist/chat/core.d.ts +30 -381
- package/dist/chat/core.js +24 -3
- package/dist/chat/core.js.map +1 -1
- package/dist/chat/errors.cjs +48 -26
- package/dist/chat/errors.cjs.map +1 -1
- package/dist/chat/errors.d.cts +6 -31
- package/dist/chat/errors.d.ts +6 -31
- package/dist/chat/errors.js +48 -25
- package/dist/chat/errors.js.map +1 -1
- package/dist/chat/events.cjs.map +1 -1
- package/dist/chat/events.d.cts +6 -2
- package/dist/chat/events.d.ts +6 -2
- package/dist/chat/events.js.map +1 -1
- package/dist/chat/index.cjs +1199 -1008
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +35 -10
- package/dist/chat/index.d.ts +35 -10
- package/dist/chat/index.js +1196 -987
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react/theme.css +2517 -0
- package/dist/chat/react.cjs +2003 -1153
- package/dist/chat/react.cjs.map +1 -1
- package/dist/chat/react.d.cts +590 -121
- package/dist/chat/react.d.ts +590 -121
- package/dist/chat/react.js +1984 -1151
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/runtime.cjs +401 -186
- package/dist/chat/runtime.cjs.map +1 -1
- package/dist/chat/runtime.d.cts +92 -28
- package/dist/chat/runtime.d.ts +92 -28
- package/dist/chat/runtime.js +401 -186
- package/dist/chat/runtime.js.map +1 -1
- package/dist/chat/server.cjs +2234 -209
- package/dist/chat/server.cjs.map +1 -1
- package/dist/chat/server.d.cts +451 -90
- package/dist/chat/server.d.ts +451 -90
- package/dist/chat/server.js +2221 -210
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/sessions.cjs +25 -43
- package/dist/chat/sessions.cjs.map +1 -1
- package/dist/chat/sessions.d.cts +37 -118
- package/dist/chat/sessions.d.ts +37 -118
- package/dist/chat/sessions.js +25 -43
- package/dist/chat/sessions.js.map +1 -1
- package/dist/chat/sqlite.cjs +441 -0
- package/dist/chat/sqlite.cjs.map +1 -0
- package/dist/chat/sqlite.d.cts +128 -0
- package/dist/chat/sqlite.d.ts +128 -0
- package/dist/chat/sqlite.js +435 -0
- package/dist/chat/sqlite.js.map +1 -0
- package/dist/chat/state.cjs +14 -1
- package/dist/chat/state.cjs.map +1 -1
- package/dist/chat/state.d.cts +5 -2
- package/dist/chat/state.d.ts +5 -2
- package/dist/chat/state.js +14 -1
- package/dist/chat/state.js.map +1 -1
- package/dist/chat/storage.cjs +19 -10
- package/dist/chat/storage.cjs.map +1 -1
- package/dist/chat/storage.d.cts +11 -5
- package/dist/chat/storage.d.ts +11 -5
- package/dist/chat/storage.js +19 -10
- package/dist/chat/storage.js.map +1 -1
- package/dist/errors-C-so0M4t.d.cts +33 -0
- package/dist/errors-C-so0M4t.d.ts +33 -0
- package/dist/errors-CmVvczxZ.d.cts +28 -0
- package/dist/errors-CmVvczxZ.d.ts +28 -0
- package/dist/{in-process-transport-C2oPTYs6.d.ts → in-process-transport-C1JnJGVR.d.ts} +28 -23
- package/dist/{in-process-transport-DG-w5G6k.d.cts → in-process-transport-C7DSqPyX.d.cts} +28 -23
- package/dist/index.cjs +340 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +292 -123
- package/dist/index.d.ts +292 -123
- package/dist/index.js +334 -47
- package/dist/index.js.map +1 -1
- package/dist/provider-types-PTSlRPNB.d.cts +39 -0
- package/dist/provider-types-PTSlRPNB.d.ts +39 -0
- package/dist/refresh-manager-B81PpYBr.d.cts +153 -0
- package/dist/refresh-manager-Dlv_iNZi.d.ts +153 -0
- package/dist/testing.cjs +383 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +132 -0
- package/dist/testing.d.ts +132 -0
- package/dist/testing.js +377 -0
- package/dist/testing.js.map +1 -0
- package/dist/token-store-CSUBgYwn.d.ts +48 -0
- package/dist/token-store-CuC4hB9Z.d.cts +48 -0
- package/dist/{transport-DX1Nhm4N.d.cts → transport-Cdh3M0tS.d.cts} +5 -4
- package/dist/{transport-D1OaUgRk.d.ts → transport-Ciap4PWK.d.ts} +5 -4
- package/dist/{types-CGF7AEX1.d.cts → types-4vbcmPTp.d.cts} +4 -2
- package/dist/{types-Bh5AhqD-.d.ts → types-BxggH0Yh.d.ts} +4 -2
- package/dist/types-DRgd_9R7.d.cts +363 -0
- package/dist/types-ajANVzf7.d.ts +363 -0
- package/package.json +31 -6
- package/dist/errors-BDLbNu9w.d.cts +0 -13
- package/dist/errors-BDLbNu9w.d.ts +0 -13
- package/dist/types-DLZzlJxt.d.ts +0 -39
- package/dist/types-tE0CXwBl.d.cts +0 -39
package/README.md
CHANGED
|
@@ -53,6 +53,24 @@ agent.dispose();
|
|
|
53
53
|
await service.dispose();
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
### Retry on Transient Errors
|
|
57
|
+
|
|
58
|
+
`BaseAgent` supports automatic retry for transient failures:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
const agent = service.createAgent({ systemPrompt: "..." });
|
|
62
|
+
const result = await agent.run("prompt", {
|
|
63
|
+
model: "gpt-5-mini",
|
|
64
|
+
retry: {
|
|
65
|
+
maxRetries: 3,
|
|
66
|
+
initialDelayMs: 1000,
|
|
67
|
+
backoffMultiplier: 2,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Retries on transient error codes: `TIMEOUT`, `RATE_LIMIT`, `NETWORK`, `MODEL_OVERLOADED`. Never retries `AbortError`, `ReentrancyError`, or `DisposedError`.
|
|
73
|
+
|
|
56
74
|
## Tool Definition
|
|
57
75
|
|
|
58
76
|
Tools are defined with a Zod schema for parameters and an `execute` function:
|
|
@@ -161,6 +179,8 @@ interface IPermissionStore {
|
|
|
161
179
|
}
|
|
162
180
|
```
|
|
163
181
|
|
|
182
|
+
Built-in stores: `InMemoryPermissionStore` (session-scoped), `FilePermissionStore` (persists to JSON file), `CompositePermissionStore` (chains multiple stores — first match wins, writes to the store matching the scope). `createDefaultPermissionStore(projectDir)` returns a `CompositePermissionStore` combining project-level and global `FilePermissionStore` instances.
|
|
183
|
+
|
|
164
184
|
## Structured Output
|
|
165
185
|
|
|
166
186
|
Extract typed data from LLM responses using `runStructured`:
|
|
@@ -541,32 +561,92 @@ manager.start();
|
|
|
541
561
|
|
|
542
562
|
Higher-level primitives for building AI chat applications on top of agent-sdk.
|
|
543
563
|
|
|
564
|
+
### Composable Architecture
|
|
565
|
+
|
|
566
|
+
The SDK is layered — use only what you need:
|
|
567
|
+
|
|
568
|
+
**Standalone agent** (no server, no UI):
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
import { createAgentService } from "@witqq/agent-sdk";
|
|
572
|
+
const service = await createAgentService("copilot", { useLoggedInUser: true });
|
|
573
|
+
const agent = service.createAgent({ systemPrompt: "You are helpful." });
|
|
574
|
+
const result = await agent.run("Hello");
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
**Server with runtime** (add HTTP layer):
|
|
578
|
+
|
|
579
|
+
```typescript
|
|
580
|
+
import * as http from "node:http";
|
|
581
|
+
import { createAgentService } from "@witqq/agent-sdk";
|
|
582
|
+
import type { AuthToken } from "@witqq/agent-sdk/auth";
|
|
583
|
+
import { CopilotAuth } from "@witqq/agent-sdk/auth";
|
|
584
|
+
import { CopilotChatAdapter } from "@witqq/agent-sdk/chat/backends";
|
|
585
|
+
import { createChatRuntime } from "@witqq/agent-sdk/chat/runtime";
|
|
586
|
+
import { createChatServer } from "@witqq/agent-sdk/chat/server";
|
|
587
|
+
import { createSQLiteStorage } from "@witqq/agent-sdk/chat/sqlite";
|
|
588
|
+
|
|
589
|
+
const { sessionStore, providerStore, tokenStore } = createSQLiteStorage("chat.db");
|
|
590
|
+
|
|
591
|
+
const runtime = createChatRuntime({
|
|
592
|
+
backends: {
|
|
593
|
+
copilot: async (credentials: AuthToken) => {
|
|
594
|
+
const svc = await createAgentService("copilot", { githubToken: credentials.accessToken });
|
|
595
|
+
return new CopilotChatAdapter({ agentConfig: { systemPrompt: "Hello" }, agentService: svc });
|
|
596
|
+
},
|
|
597
|
+
},
|
|
598
|
+
defaultBackend: "copilot", sessionStore,
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
const handler = createChatServer({
|
|
602
|
+
runtime,
|
|
603
|
+
auth: { tokenStore, createCopilotAuth: () => new CopilotAuth() },
|
|
604
|
+
providers: { providerStore },
|
|
605
|
+
});
|
|
606
|
+
http.createServer(handler).listen(3000);
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
**Full-stack with React** (add frontend):
|
|
610
|
+
|
|
611
|
+
```typescript
|
|
612
|
+
// frontend — 4 lines
|
|
613
|
+
import { ChatUI, RemoteChatClient } from "@witqq/agent-sdk/chat/react";
|
|
614
|
+
|
|
615
|
+
const runtime = new RemoteChatClient({ baseUrl: "/api/chat" });
|
|
616
|
+
<ChatUI runtime={runtime} authBaseUrl="/api" />
|
|
617
|
+
```
|
|
618
|
+
|
|
544
619
|
### Barrel Import
|
|
545
620
|
|
|
546
|
-
For most consumer apps, import common types from
|
|
621
|
+
For most consumer apps, import common types from the barrel:
|
|
547
622
|
|
|
548
623
|
```typescript
|
|
624
|
+
// Core types and runtime (barrel export)
|
|
549
625
|
import {
|
|
550
626
|
ChatMessage, ChatSession, ChatEvent, IChatRuntime,
|
|
551
627
|
createChatRuntime, ChatError, classifyError,
|
|
628
|
+
MessageAccumulator, SSEChatTransport,
|
|
629
|
+
} from "@witqq/agent-sdk/chat";
|
|
630
|
+
|
|
631
|
+
// React hooks and components (separate import — not in barrel)
|
|
632
|
+
import {
|
|
552
633
|
useChat, useRemoteChat, useRemoteAuth,
|
|
553
634
|
ChatProvider, Thread, Composer,
|
|
554
|
-
|
|
555
|
-
} from "@witqq/agent-sdk/chat";
|
|
635
|
+
} from "@witqq/agent-sdk/chat/react";
|
|
556
636
|
```
|
|
557
637
|
|
|
558
638
|
### Individual Module Imports
|
|
559
639
|
|
|
560
640
|
```typescript
|
|
561
|
-
import { ChatMessage, ChatSession,
|
|
641
|
+
import { ChatMessage, ChatSession, isChatMessage } from "@witqq/agent-sdk/chat/core";
|
|
642
|
+
import type { IChatBackend } from "@witqq/agent-sdk/chat/backends";
|
|
562
643
|
import {
|
|
563
644
|
classifyError, withRetry, isRetryable,
|
|
564
|
-
|
|
645
|
+
ChatError, ErrorCode,
|
|
565
646
|
ExponentialBackoffStrategy
|
|
566
647
|
} from "@witqq/agent-sdk/chat/errors";
|
|
567
|
-
import {
|
|
568
|
-
|
|
569
|
-
} from "@witqq/agent-sdk/chat/events";
|
|
648
|
+
import { ChatEventBus } from "@witqq/agent-sdk/chat/events";
|
|
649
|
+
import { filterEvents, collectText } from "@witqq/agent-sdk/chat/events";
|
|
570
650
|
import {
|
|
571
651
|
InMemoryStorage, FileStorage,
|
|
572
652
|
type IStorageAdapter, StorageError
|
|
@@ -582,7 +662,7 @@ import {
|
|
|
582
662
|
CopilotChatAdapter, VercelAIChatAdapter, BaseBackendAdapter,
|
|
583
663
|
SSEChatTransport, WsChatTransport, InProcessChatTransport,
|
|
584
664
|
streamToTransport, withInterceptors,
|
|
585
|
-
type
|
|
665
|
+
type IResumableBackend, type BackendAdapterOptions, type IChatTransport
|
|
586
666
|
} from "@witqq/agent-sdk/chat/backends";
|
|
587
667
|
```
|
|
588
668
|
|
|
@@ -593,8 +673,8 @@ try {
|
|
|
593
673
|
await provider.send(message);
|
|
594
674
|
} catch (err) {
|
|
595
675
|
const classified = classifyError(err);
|
|
596
|
-
if (classified
|
|
597
|
-
console.log(`Rate limited, retry after ${classified.
|
|
676
|
+
if (classified.code === ErrorCode.RATE_LIMIT) {
|
|
677
|
+
console.log(`Rate limited, retry after ${classified.retryAfter}ms`);
|
|
598
678
|
}
|
|
599
679
|
}
|
|
600
680
|
```
|
|
@@ -626,7 +706,7 @@ bus.use((ctx) => {
|
|
|
626
706
|
else ctx.next();
|
|
627
707
|
});
|
|
628
708
|
|
|
629
|
-
bus.on("
|
|
709
|
+
bus.on("message:delta", (event) => console.log(event.text));
|
|
630
710
|
```
|
|
631
711
|
|
|
632
712
|
### Storage Adapters
|
|
@@ -659,8 +739,8 @@ const session = await store.createSession({
|
|
|
659
739
|
tags: ["work"],
|
|
660
740
|
});
|
|
661
741
|
|
|
662
|
-
await store.
|
|
663
|
-
const page = await store.
|
|
742
|
+
await store.appendMessage(session.id, message);
|
|
743
|
+
const page = await store.loadMessages(session.id, { limit: 20, offset: 0 });
|
|
664
744
|
// page.messages, page.total, page.hasMore
|
|
665
745
|
|
|
666
746
|
const results = await store.searchSessions({ query: "typescript" });
|
|
@@ -698,7 +778,7 @@ const tokens = estimateTokens(message); // ~chars/4
|
|
|
698
778
|
|
|
699
779
|
### Backend Adapters
|
|
700
780
|
|
|
701
|
-
Backend adapters bridge `IAgentService` to `
|
|
781
|
+
Backend adapters bridge `IAgentService` to `IChatBackend`, adding session management and resume support:
|
|
702
782
|
|
|
703
783
|
```typescript
|
|
704
784
|
import { CopilotChatAdapter } from "@witqq/agent-sdk/chat/backends";
|
|
@@ -725,7 +805,7 @@ if (adapter.canResume()) {
|
|
|
725
805
|
adapter.dispose();
|
|
726
806
|
```
|
|
727
807
|
|
|
728
|
-
`
|
|
808
|
+
`IResumableBackend` extends `IChatBackend` with `canResume()`, `resume()`, and `backendSessionId`. Built-in adapters: `CopilotChatAdapter`, `ClaudeChatAdapter`, `VercelAIChatAdapter` (stateless, no resume). Create custom adapters by extending `BaseBackendAdapter`.
|
|
729
809
|
|
|
730
810
|
Service ownership: when `agentService` is passed via options, the adapter does **not** dispose it — the caller retains ownership. When omitted, the adapter creates and owns its service internally.
|
|
731
811
|
|
|
@@ -780,12 +860,14 @@ import { createChatRuntime } from "@witqq/agent-sdk/chat/runtime";
|
|
|
780
860
|
|
|
781
861
|
const runtime = createChatRuntime({
|
|
782
862
|
backends: {
|
|
783
|
-
copilot: () => new CopilotChatAdapter({
|
|
784
|
-
|
|
863
|
+
copilot: async (credentials) => new CopilotChatAdapter({
|
|
864
|
+
agentConfig: { systemPrompt: "Hello" },
|
|
865
|
+
agentService: await createAgentService("copilot", { githubToken: credentials.accessToken }),
|
|
866
|
+
}),
|
|
785
867
|
},
|
|
786
868
|
defaultBackend: "copilot",
|
|
787
869
|
sessionStore: new InMemorySessionStore(),
|
|
788
|
-
|
|
870
|
+
context: { maxTokens: 8000 },
|
|
789
871
|
});
|
|
790
872
|
|
|
791
873
|
// Create session, send message, stream events
|
|
@@ -795,20 +877,20 @@ for await (const event of runtime.send(session.id, "Hello")) {
|
|
|
795
877
|
}
|
|
796
878
|
```
|
|
797
879
|
|
|
798
|
-
Key capabilities: session delegation (create/get/list/delete
|
|
880
|
+
Key capabilities: session delegation (create/get/list/delete), tool registration via `registerTool(def)` / `removeTool(name)` / `registeredTools` (readonly Map, persists across switches), middleware pipeline (`use(middleware)`), state machine (`status` property), abort support (`abort()`), pre-stream retry with `StreamRetryConfig`, session lifecycle events via `onSessionChange(callback)`, generic `<TMetadata>` for typed session metadata, context stats via `getContextStats(sessionId)`, and `dispose()`. Model and backend are passed per-call via `send(sessionId, msg, { model, backend, credentials })`.
|
|
799
881
|
|
|
800
882
|
Context monitoring:
|
|
801
883
|
|
|
802
884
|
```typescript
|
|
803
885
|
// Query context usage after send
|
|
804
886
|
const stats = runtime.getContextStats(session.id);
|
|
805
|
-
// stats: { totalTokens, removedCount, wasTruncated, availableBudget } | null
|
|
887
|
+
// stats: { totalTokens, removedCount, wasTruncated, availableBudget, realPromptTokens?, realCompletionTokens?, modelContextWindow? } | null
|
|
806
888
|
|
|
807
|
-
//
|
|
889
|
+
// Handle trimmed messages via callback
|
|
808
890
|
const runtime = createChatRuntime({
|
|
809
|
-
// ...backends, sessionStore,
|
|
891
|
+
// ...backends, sessionStore, context
|
|
810
892
|
onContextTrimmed: (sessionId, removedMessages) => {
|
|
811
|
-
db.
|
|
893
|
+
db.saveRemovedMessages(sessionId, removedMessages);
|
|
812
894
|
},
|
|
813
895
|
});
|
|
814
896
|
```
|
|
@@ -844,11 +926,11 @@ const handler = createChatServer({
|
|
|
844
926
|
});
|
|
845
927
|
```
|
|
846
928
|
|
|
847
|
-
`createChatHandler` maps all 10 `
|
|
929
|
+
`createChatHandler` maps all 10 `RemoteChatClient` endpoints (session CRUD, send via SSE, abort, models, backend/model switch). `createAuthHandler` handles Copilot Device Flow, Claude OAuth+PKCE, and API key auth with persistent token storage via `ITokenStore`. `corsMiddleware` supports multi-origin configuration.
|
|
848
930
|
|
|
849
931
|
## Interactive Demo
|
|
850
932
|
|
|
851
|
-
|
|
933
|
+
Complete chat app showcasing the full SDK.
|
|
852
934
|
|
|
853
935
|
```bash
|
|
854
936
|
npm run demo # Build & start in Docker (http://localhost:3456)
|
|
@@ -858,7 +940,9 @@ npm run demo -- restart # Rebuild & restart
|
|
|
858
940
|
npm run demo -- dev # Local dev without Docker
|
|
859
941
|
```
|
|
860
942
|
|
|
861
|
-
Features:
|
|
943
|
+
Features: multi-backend auth (Copilot Device Flow, Claude OAuth+PKCE, Vercel AI API key), provider management, model selection, SSE streaming with thinking blocks, tool calls with approval, token usage display, error handling, session management, SQLite persistence.
|
|
944
|
+
|
|
945
|
+
Server uses `createChatServer` for zero custom routing with stateless backend factories (credentials per-request). Frontend uses `ChatUI` for zero custom components. See [demo README](examples/demo/README.md) for details.
|
|
862
946
|
|
|
863
947
|
## React Bindings
|
|
864
948
|
|
|
@@ -900,12 +984,12 @@ function App() {
|
|
|
900
984
|
}
|
|
901
985
|
```
|
|
902
986
|
|
|
903
|
-
Or use `
|
|
987
|
+
Or use `RemoteChatClient` directly for lower-level control:
|
|
904
988
|
|
|
905
989
|
```typescript
|
|
906
|
-
import {
|
|
990
|
+
import { RemoteChatClient } from "@witqq/agent-sdk/chat/react";
|
|
907
991
|
|
|
908
|
-
const runtime = new
|
|
992
|
+
const runtime = new RemoteChatClient({ baseUrl: "/api/chat" });
|
|
909
993
|
```
|
|
910
994
|
|
|
911
995
|
Reactive session list (replaces manual polling):
|
|
@@ -915,7 +999,7 @@ import { useSessions } from "@witqq/agent-sdk/chat/react";
|
|
|
915
999
|
|
|
916
1000
|
function SessionList() {
|
|
917
1001
|
const { sessions, loading } = useSessions();
|
|
918
|
-
// Auto-updates on create, delete,
|
|
1002
|
+
// Auto-updates on create, delete, and message send
|
|
919
1003
|
return sessions.map(s => <div key={s.id}>{s.title}</div>);
|
|
920
1004
|
}
|
|
921
1005
|
```
|
|
@@ -929,6 +1013,30 @@ const auth = useRemoteAuth({ backend: "copilot", baseUrl: "/api" });
|
|
|
929
1013
|
// auth.startDeviceFlow(), auth.startOAuthFlow(), auth.submitApiKey()
|
|
930
1014
|
```
|
|
931
1015
|
|
|
1016
|
+
`ContextStatsDisplay` renders context window usage:
|
|
1017
|
+
|
|
1018
|
+
```typescript
|
|
1019
|
+
import { ContextStatsDisplay } from "@witqq/agent-sdk/chat/react";
|
|
1020
|
+
|
|
1021
|
+
// Headless component rendering context window stats
|
|
1022
|
+
// Props: { stats: ContextStats | null }
|
|
1023
|
+
// Data attributes: data-context-stats, data-context-tokens, data-context-budget,
|
|
1024
|
+
// data-context-usage, data-context-removed, data-context-truncated
|
|
1025
|
+
<ContextStatsDisplay stats={runtime.getContextStats(sessionId)} />
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
`ThreadList` supports search:
|
|
1029
|
+
|
|
1030
|
+
```typescript
|
|
1031
|
+
<ThreadList
|
|
1032
|
+
sessions={sessions}
|
|
1033
|
+
onSelect={handleSelect}
|
|
1034
|
+
onDelete={handleDelete}
|
|
1035
|
+
searchQuery={query} // controlled search input
|
|
1036
|
+
onSearchChange={setQuery} // search input change handler
|
|
1037
|
+
/>
|
|
1038
|
+
```
|
|
1039
|
+
|
|
932
1040
|
See [Chat SDK docs](docs/chat-sdk/README.md) for the full React API reference.
|
|
933
1041
|
|
|
934
1042
|
## Documentation
|
|
@@ -936,11 +1044,9 @@ See [Chat SDK docs](docs/chat-sdk/README.md) for the full React API reference.
|
|
|
936
1044
|
| Document | Description |
|
|
937
1045
|
|----------|-------------|
|
|
938
1046
|
| [Chat SDK Modules](docs/chat-sdk/README.md) | Module-by-module API docs for chat primitives |
|
|
939
|
-
| [Chat SDK Architecture](docs/chat-sdk/ARCHITECTURE.md) | Architecture specification and design decisions |
|
|
940
1047
|
| [Custom Transports](docs/chat-sdk/custom-transports.md) | Guide to building custom IChatTransport implementations |
|
|
941
1048
|
| [Custom Renderers](docs/chat-sdk/custom-renderers.md) | Three approaches to customizing React UI components |
|
|
942
|
-
| [
|
|
943
|
-
| [Project Checklist](PROJECT_CHECKLIST.md) | Implementation checklist with completion status |
|
|
1049
|
+
| [Demo App](examples/demo/README.md) | Full-stack demo with architecture and API reference |
|
|
944
1050
|
| [Changelog](CHANGELOG.md) | Release history and breaking changes |
|
|
945
1051
|
|
|
946
1052
|
## License
|
|
@@ -1,34 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
/** Pluggable store for persisting permission (scope) decisions across runs. */
|
|
4
|
-
interface IPermissionStore {
|
|
5
|
-
/** Check if tool is already approved */
|
|
6
|
-
isApproved(toolName: string): Promise<boolean>;
|
|
7
|
-
/** Store an approval decision */
|
|
8
|
-
approve(toolName: string, scope: PermissionScope): Promise<void>;
|
|
9
|
-
/** Revoke approval for a tool */
|
|
10
|
-
revoke(toolName: string): Promise<void>;
|
|
11
|
-
/** Clear all approvals */
|
|
12
|
-
clear(): Promise<void>;
|
|
13
|
-
/** Dispose resources */
|
|
14
|
-
dispose(): Promise<void>;
|
|
15
|
-
}
|
|
2
|
+
import { E as ErrorCode } from './errors-C-so0M4t.js';
|
|
16
3
|
|
|
17
4
|
/** JSON-serializable value used for tool arguments and results */
|
|
18
5
|
type JSONValue = string | number | boolean | null | JSONValue[] | {
|
|
19
6
|
[key: string]: JSONValue;
|
|
20
7
|
};
|
|
21
|
-
|
|
22
|
-
type MessageContent = string | Array<ContentPart>;
|
|
23
|
-
/** Individual content part within a multi-part message */
|
|
24
|
-
type ContentPart = {
|
|
25
|
-
type: "text";
|
|
26
|
-
text: string;
|
|
27
|
-
} | {
|
|
28
|
-
type: "image";
|
|
29
|
-
data: string;
|
|
30
|
-
mimeType: string;
|
|
31
|
-
};
|
|
8
|
+
|
|
32
9
|
/** What the LLM sees — name, description, schema. Passed to all backends. */
|
|
33
10
|
interface ToolDeclaration<TParams = unknown> {
|
|
34
11
|
name: string;
|
|
@@ -46,7 +23,7 @@ interface ToolDeclaration<TParams = unknown> {
|
|
|
46
23
|
* The optional second parameter receives request-scoped context
|
|
47
24
|
* when invoked through ChatRuntime (session ID, user data, custom metadata). */
|
|
48
25
|
interface ToolDefinition<TParams = unknown> extends ToolDeclaration<TParams> {
|
|
49
|
-
execute: (params: TParams, context?: ToolContext) => Promise<
|
|
26
|
+
execute: (params: TParams, context?: ToolContext) => Promise<unknown> | unknown;
|
|
50
27
|
}
|
|
51
28
|
/** Request-scoped context passed to tool execute functions via ChatRuntime.
|
|
52
29
|
* Contains session identity and user-defined metadata from the current session. */
|
|
@@ -69,6 +46,18 @@ interface ToolResult {
|
|
|
69
46
|
result: JSONValue;
|
|
70
47
|
isError?: boolean;
|
|
71
48
|
}
|
|
49
|
+
|
|
50
|
+
/** Message content — plain string or array of text/image parts */
|
|
51
|
+
type MessageContent = string | Array<ContentPart>;
|
|
52
|
+
/** Individual content part within a multi-part message */
|
|
53
|
+
type ContentPart = {
|
|
54
|
+
type: "text";
|
|
55
|
+
text: string;
|
|
56
|
+
} | {
|
|
57
|
+
type: "image";
|
|
58
|
+
data: string;
|
|
59
|
+
mimeType: string;
|
|
60
|
+
};
|
|
72
61
|
/** Conversation message — discriminated union on `role` */
|
|
73
62
|
type Message = {
|
|
74
63
|
role: "user";
|
|
@@ -85,12 +74,15 @@ type Message = {
|
|
|
85
74
|
role: "system";
|
|
86
75
|
content: string;
|
|
87
76
|
};
|
|
77
|
+
|
|
88
78
|
/** Scope for "remember this decision" */
|
|
89
79
|
type PermissionScope = "once" | "session" | "project" | "always";
|
|
90
80
|
/** What the permission callback receives */
|
|
91
81
|
interface PermissionRequest {
|
|
92
82
|
toolName: string;
|
|
93
83
|
toolArgs: Record<string, unknown>;
|
|
84
|
+
/** Unique identifier for this specific tool call */
|
|
85
|
+
toolCallId?: string;
|
|
94
86
|
/** SDK-suggested scope (from Claude CLI's suggestions) */
|
|
95
87
|
suggestedScope?: PermissionScope;
|
|
96
88
|
/** Original SDK permission request (for pass-through) */
|
|
@@ -128,12 +120,32 @@ interface SupervisorHooks {
|
|
|
128
120
|
onPermission?: PermissionCallback;
|
|
129
121
|
onAskUser?: (request: UserInputRequest, signal: AbortSignal) => Promise<UserInputResponse>;
|
|
130
122
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
123
|
+
|
|
124
|
+
/** Model metadata returned by listModels() */
|
|
125
|
+
interface ModelInfo {
|
|
126
|
+
id: string;
|
|
134
127
|
name?: string;
|
|
135
|
-
|
|
128
|
+
provider?: string;
|
|
129
|
+
/** Model tier for UI categorization and cost hints */
|
|
130
|
+
tier?: "fast" | "standard" | "premium";
|
|
131
|
+
/** Context window size in tokens */
|
|
132
|
+
contextWindow?: number;
|
|
133
|
+
/** Model capabilities (e.g. "vision", "tools", "structured") */
|
|
134
|
+
capabilities?: string[];
|
|
135
|
+
}
|
|
136
|
+
/** LLM model parameters */
|
|
137
|
+
interface ModelParams {
|
|
138
|
+
temperature?: number;
|
|
139
|
+
maxTokens?: number;
|
|
140
|
+
topP?: number;
|
|
141
|
+
stopSequences?: string[];
|
|
142
|
+
}
|
|
143
|
+
/** Result of backend validation check */
|
|
144
|
+
interface ValidationResult {
|
|
145
|
+
valid: boolean;
|
|
146
|
+
errors: string[];
|
|
136
147
|
}
|
|
148
|
+
|
|
137
149
|
/** Usage data from LLM execution — tokens consumed plus optional metadata */
|
|
138
150
|
interface UsageData {
|
|
139
151
|
promptTokens: number;
|
|
@@ -192,24 +204,78 @@ type AgentEvent = {
|
|
|
192
204
|
type: "error";
|
|
193
205
|
error: string;
|
|
194
206
|
recoverable: boolean;
|
|
207
|
+
code?: ErrorCode;
|
|
195
208
|
} | {
|
|
196
209
|
type: "done";
|
|
197
210
|
finalOutput: string | null;
|
|
198
211
|
structuredOutput?: unknown;
|
|
212
|
+
streamed?: boolean;
|
|
199
213
|
};
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
214
|
+
|
|
215
|
+
/** Pluggable store for persisting permission (scope) decisions across runs. */
|
|
216
|
+
interface IPermissionStore {
|
|
217
|
+
/** Check if tool is already approved */
|
|
218
|
+
isApproved(toolName: string): Promise<boolean>;
|
|
219
|
+
/** Store an approval decision */
|
|
220
|
+
approve(toolName: string, scope: PermissionScope): Promise<void>;
|
|
221
|
+
/** Revoke approval for a tool */
|
|
222
|
+
revoke(toolName: string): Promise<void>;
|
|
223
|
+
/** Clear all approvals */
|
|
224
|
+
clear(): Promise<void>;
|
|
225
|
+
/** Dispose resources */
|
|
226
|
+
dispose(): Promise<void>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Per-call overrides passed to run(), stream(), runStructured().
|
|
230
|
+
* Allows overriding the model, tools, signal, and other parameters
|
|
231
|
+
* on a per-request basis without modifying the agent configuration. */
|
|
232
|
+
interface CallOptions {
|
|
233
|
+
/** Override the default model for this call */
|
|
234
|
+
model?: string;
|
|
235
|
+
/** Override/extend tools for this call */
|
|
236
|
+
tools?: ToolDefinition[];
|
|
237
|
+
/** Per-call abort signal */
|
|
203
238
|
signal?: AbortSignal;
|
|
239
|
+
/** Override system message for this call */
|
|
240
|
+
systemMessage?: string;
|
|
241
|
+
/** Provider-specific options passed through to the underlying SDK */
|
|
242
|
+
providerOptions?: Record<string, unknown>;
|
|
243
|
+
/** Per-call timeout in milliseconds */
|
|
244
|
+
timeout?: number;
|
|
245
|
+
/** Per-call token limit */
|
|
246
|
+
maxTokens?: number;
|
|
247
|
+
/** Retry configuration for this call */
|
|
248
|
+
retry?: RetryConfig;
|
|
249
|
+
}
|
|
250
|
+
/** Configuration for automatic retries on transient errors */
|
|
251
|
+
interface RetryConfig {
|
|
252
|
+
/** Maximum number of retries (default: 0 — no retry) */
|
|
253
|
+
maxRetries?: number;
|
|
254
|
+
/** Initial delay in ms before first retry (default: 1000) */
|
|
255
|
+
initialDelayMs?: number;
|
|
256
|
+
/** Backoff multiplier (default: 2) */
|
|
257
|
+
backoffMultiplier?: number;
|
|
258
|
+
/** Which error codes to retry (default: all recoverable codes) */
|
|
259
|
+
retryableErrors?: ErrorCode[];
|
|
260
|
+
}
|
|
261
|
+
/** Configuration for typed structured output from LLM */
|
|
262
|
+
interface StructuredOutputConfig<T = unknown> {
|
|
263
|
+
schema: z.ZodType<T>;
|
|
264
|
+
name?: string;
|
|
265
|
+
description?: string;
|
|
266
|
+
}
|
|
267
|
+
/** Options passed to agent.run() / agent.stream().
|
|
268
|
+
* Extends CallOptions with run-specific fields (context, activityTimeoutMs).
|
|
269
|
+
* model is REQUIRED — every agent call must specify the model explicitly. */
|
|
270
|
+
interface RunOptions extends CallOptions {
|
|
271
|
+
/** Model to use for this call (required — no implicit defaults) */
|
|
272
|
+
model: string;
|
|
204
273
|
/** Arbitrary context passed to the agent run */
|
|
205
274
|
context?: Record<string, unknown>;
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
maxTokens?: number;
|
|
211
|
-
topP?: number;
|
|
212
|
-
stopSequences?: string[];
|
|
275
|
+
/** Inactivity timeout for streaming (ms). When set, the stream aborts if no
|
|
276
|
+
* event (including heartbeats/progress) arrives within this period. Resets on
|
|
277
|
+
* every received event. Default: no timeout. Only affects stream()/streamWithContext(). */
|
|
278
|
+
activityTimeoutMs?: number;
|
|
213
279
|
}
|
|
214
280
|
/** Timeout configuration for agent operations */
|
|
215
281
|
interface TimeoutConfig {
|
|
@@ -234,12 +300,10 @@ interface ErrorHandlingConfig {
|
|
|
234
300
|
phase: "tool" | "llm" | "permission" | "ask-user";
|
|
235
301
|
}) => void;
|
|
236
302
|
}
|
|
237
|
-
/**
|
|
303
|
+
/** Identity-only agent configuration — defines the agent's behavior, NOT per-call defaults.
|
|
304
|
+
* For creating an agent with model/tools defaults, use FullAgentConfig. */
|
|
238
305
|
interface AgentConfig {
|
|
239
|
-
model?: string;
|
|
240
|
-
modelParams?: ModelParams;
|
|
241
306
|
systemPrompt: string;
|
|
242
|
-
tools: ToolDefinition[];
|
|
243
307
|
supervisor?: SupervisorHooks;
|
|
244
308
|
maxTurns?: number;
|
|
245
309
|
timeout?: TimeoutConfig;
|
|
@@ -249,8 +313,14 @@ interface AgentConfig {
|
|
|
249
313
|
/** How to apply systemPrompt: "append" adds to backend default, "replace" overrides it.
|
|
250
314
|
* Default: "append". Currently used by the Copilot backend. */
|
|
251
315
|
systemMessageMode?: "append" | "replace";
|
|
252
|
-
/**
|
|
253
|
-
*
|
|
316
|
+
/**
|
|
317
|
+
* Filter for backend built-in tools (e.g. `["web_search", "web_fetch"]` for Copilot).
|
|
318
|
+
* When set, only listed built-in tools are available. Backend-specific.
|
|
319
|
+
*
|
|
320
|
+
* **Security note**: This is a trust boundary — it controls which backend-native tools
|
|
321
|
+
* the AI agent can invoke. By default, backends expose ALL their built-in tools.
|
|
322
|
+
* Set this to restrict access (e.g. prevent file system access in a web-facing agent).
|
|
323
|
+
*/
|
|
254
324
|
availableTools?: string[];
|
|
255
325
|
/** Callback invoked with usage data after run completion or during streaming.
|
|
256
326
|
* Fire-and-forget: errors are logged but not propagated. */
|
|
@@ -264,11 +334,24 @@ interface AgentConfig {
|
|
|
264
334
|
* "persistent": reuses the same CLI session across calls, preserving conversation
|
|
265
335
|
* history natively in the CLI backend. Session is destroyed on agent dispose(). */
|
|
266
336
|
sessionMode?: "per-call" | "persistent";
|
|
337
|
+
}
|
|
338
|
+
/** Per-call defaults that can be provided at agent creation time.
|
|
339
|
+
* Each field can also be overridden on individual calls via RunOptions. */
|
|
340
|
+
interface CallDefaults {
|
|
341
|
+
/** Default model (overridable per-call via RunOptions.model) */
|
|
342
|
+
model?: string;
|
|
343
|
+
/** Default model parameters */
|
|
344
|
+
modelParams?: ModelParams;
|
|
345
|
+
/** Default tools (overridable per-call via RunOptions.tools) */
|
|
346
|
+
tools?: ToolDefinition[];
|
|
267
347
|
/** Provider-specific options passed through to the underlying SDK.
|
|
268
348
|
* For Vercel AI: passed as providerOptions to generateText/streamText.
|
|
269
349
|
* Example: { google: { thinkingConfig: { thinkingBudget: 1024 } } } */
|
|
270
350
|
providerOptions?: Record<string, Record<string, unknown>>;
|
|
271
351
|
}
|
|
352
|
+
/** Full agent configuration: identity + per-call defaults.
|
|
353
|
+
* This is what createAgent() accepts. Backward-compatible with the old AgentConfig shape. */
|
|
354
|
+
type FullAgentConfig = AgentConfig & CallDefaults;
|
|
272
355
|
/** Result of an agent run, generic over structured output type T */
|
|
273
356
|
interface AgentResult<T = void> {
|
|
274
357
|
output: string | null;
|
|
@@ -290,15 +373,15 @@ interface IAgent {
|
|
|
290
373
|
* or before the first call. Can be stored externally for session resume. */
|
|
291
374
|
readonly sessionId: string | undefined;
|
|
292
375
|
/** Run a single prompt and return the result. Wraps prompt in a user message. */
|
|
293
|
-
run(prompt: MessageContent, options
|
|
376
|
+
run(prompt: MessageContent, options: RunOptions): Promise<AgentResult>;
|
|
294
377
|
/** Run with full conversation history. Messages are passed directly to the backend. */
|
|
295
|
-
runWithContext(messages: Message[], options
|
|
378
|
+
runWithContext(messages: Message[], options: RunOptions): Promise<AgentResult>;
|
|
296
379
|
/** Run with structured output validated against a Zod schema. */
|
|
297
|
-
runStructured<T>(prompt: MessageContent, schema: StructuredOutputConfig<T>, options
|
|
380
|
+
runStructured<T>(prompt: MessageContent, schema: StructuredOutputConfig<T>, options: RunOptions): Promise<AgentResult<T>>;
|
|
298
381
|
/** Stream events for a single prompt. Wraps prompt in a user message. */
|
|
299
|
-
stream(prompt: MessageContent, options
|
|
382
|
+
stream(prompt: MessageContent, options: RunOptions): AsyncIterable<AgentEvent>;
|
|
300
383
|
/** Stream events with full conversation history. Messages are passed directly to the backend. */
|
|
301
|
-
streamWithContext(messages: Message[], options
|
|
384
|
+
streamWithContext(messages: Message[], options: RunOptions): AsyncIterable<AgentEvent>;
|
|
302
385
|
/** Abort the current operation. No-op if not running. */
|
|
303
386
|
abort(): void;
|
|
304
387
|
/** Gracefully interrupt the current operation. Resolves when the backend acknowledges. */
|
|
@@ -306,65 +389,17 @@ interface IAgent {
|
|
|
306
389
|
/** Get current agent lifecycle state. */
|
|
307
390
|
getState(): AgentState;
|
|
308
391
|
/** Get frozen agent configuration. */
|
|
309
|
-
getConfig(): Readonly<
|
|
392
|
+
getConfig(): Readonly<FullAgentConfig>;
|
|
310
393
|
/** Release resources. After dispose(), agent must not be used. */
|
|
311
394
|
dispose(): void;
|
|
312
395
|
}
|
|
313
|
-
/** Model metadata returned by listModels() */
|
|
314
|
-
interface ModelInfo {
|
|
315
|
-
id: string;
|
|
316
|
-
name?: string;
|
|
317
|
-
provider?: string;
|
|
318
|
-
}
|
|
319
|
-
/** Result of backend validation check */
|
|
320
|
-
interface ValidationResult {
|
|
321
|
-
valid: boolean;
|
|
322
|
-
errors: string[];
|
|
323
|
-
}
|
|
324
396
|
/** Backend service interface — creates agents, lists models, validates config */
|
|
325
397
|
interface IAgentService {
|
|
326
398
|
readonly name: string;
|
|
327
|
-
createAgent(config:
|
|
399
|
+
createAgent(config: FullAgentConfig): IAgent;
|
|
328
400
|
listModels(): Promise<ModelInfo[]>;
|
|
329
401
|
validate(): Promise<ValidationResult>;
|
|
330
402
|
dispose(): Promise<void>;
|
|
331
403
|
}
|
|
332
|
-
/** Options for Copilot CLI backend */
|
|
333
|
-
interface CopilotBackendOptions {
|
|
334
|
-
cliPath?: string;
|
|
335
|
-
workingDirectory?: string;
|
|
336
|
-
githubToken?: string;
|
|
337
|
-
useLoggedInUser?: boolean;
|
|
338
|
-
/** Extra CLI arguments passed to the Copilot subprocess (e.g. ["--allow-all"]) */
|
|
339
|
-
cliArgs?: string[];
|
|
340
|
-
/** Timeout in milliseconds for sendAndWait() calls. When undefined, uses copilot-sdk default (60s). */
|
|
341
|
-
timeout?: number;
|
|
342
|
-
/** Timeout in milliseconds for CLI startup and auth check (default: 30000). */
|
|
343
|
-
startupTimeoutMs?: number;
|
|
344
|
-
/** Custom environment variables merged into the subprocess env */
|
|
345
|
-
env?: Record<string, string | undefined>;
|
|
346
|
-
/** Session ID to resume after server restart. On startup, the backend attempts
|
|
347
|
-
* to resume this session before creating a new one. */
|
|
348
|
-
resumeSessionId?: string;
|
|
349
|
-
}
|
|
350
|
-
/** Options for Claude CLI backend */
|
|
351
|
-
interface ClaudeBackendOptions {
|
|
352
|
-
cliPath?: string;
|
|
353
|
-
workingDirectory?: string;
|
|
354
|
-
maxTurns?: number;
|
|
355
|
-
/** OAuth token for Claude authentication (set as CLAUDE_CODE_OAUTH_TOKEN env var) */
|
|
356
|
-
oauthToken?: string;
|
|
357
|
-
/** Custom environment variables merged into the subprocess env */
|
|
358
|
-
env?: Record<string, string | undefined>;
|
|
359
|
-
/** Session ID to resume after server restart. On startup, the backend attempts
|
|
360
|
-
* to resume this session before creating a new one. */
|
|
361
|
-
resumeSessionId?: string;
|
|
362
|
-
}
|
|
363
|
-
/** Options for Vercel AI SDK backend */
|
|
364
|
-
interface VercelAIBackendOptions {
|
|
365
|
-
apiKey: string;
|
|
366
|
-
provider?: string;
|
|
367
|
-
baseUrl?: string;
|
|
368
|
-
}
|
|
369
404
|
|
|
370
|
-
export type { AgentEvent as A,
|
|
405
|
+
export type { AgentEvent as A, FullAgentConfig as F, IAgentService as I, ModelInfo as M, RunOptions as R, ToolDefinition as T, UsageData as U, ValidationResult as V, MessageContent as a, AgentResult as b, IAgent as c, Message as d, ToolResult as e };
|