@witqq/agent-sdk 0.1.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/LICENSE +21 -0
- package/README.md +310 -0
- package/dist/backends/claude.cjs +718 -0
- package/dist/backends/claude.cjs.map +1 -0
- package/dist/backends/claude.d.cts +118 -0
- package/dist/backends/claude.d.ts +118 -0
- package/dist/backends/claude.js +714 -0
- package/dist/backends/claude.js.map +1 -0
- package/dist/backends/copilot.cjs +651 -0
- package/dist/backends/copilot.cjs.map +1 -0
- package/dist/backends/copilot.d.cts +121 -0
- package/dist/backends/copilot.d.ts +121 -0
- package/dist/backends/copilot.js +647 -0
- package/dist/backends/copilot.js.map +1 -0
- package/dist/backends/vercel-ai.cjs +620 -0
- package/dist/backends/vercel-ai.cjs.map +1 -0
- package/dist/backends/vercel-ai.d.cts +99 -0
- package/dist/backends/vercel-ai.d.ts +99 -0
- package/dist/backends/vercel-ai.js +615 -0
- package/dist/backends/vercel-ai.js.map +1 -0
- package/dist/index.cjs +505 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +444 -0
- package/dist/index.d.ts +444 -0
- package/dist/index.js +453 -0
- package/dist/index.js.map +1 -0
- package/dist/types-JVBEqeDw.d.cts +288 -0
- package/dist/types-JVBEqeDw.d.ts +288 -0
- package/package.json +110 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# agent-sdk
|
|
2
|
+
|
|
3
|
+
Multi-backend AI agent abstraction layer for Node.js. Switch between Copilot CLI, Claude CLI, and Vercel AI SDK backends with a unified API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @witqq/agent-sdk zod
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Backends
|
|
12
|
+
|
|
13
|
+
| Backend | Peer dependency | Type |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `copilot` | `@github/copilot-sdk` | CLI subprocess |
|
|
16
|
+
| `claude` | `@anthropic-ai/claude-agent-sdk` | CLI subprocess |
|
|
17
|
+
| `vercel-ai` | `ai` + `@ai-sdk/openai-compatible` | API-based |
|
|
18
|
+
|
|
19
|
+
Install only the backend you need:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @github/copilot-sdk # copilot
|
|
23
|
+
npm install @anthropic-ai/claude-agent-sdk # claude
|
|
24
|
+
npm install ai @ai-sdk/openai-compatible # vercel-ai
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { createAgentService } from "@witqq/agent-sdk";
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
|
|
33
|
+
const service = await createAgentService("copilot", { useLoggedInUser: true });
|
|
34
|
+
|
|
35
|
+
const agent = service.createAgent({
|
|
36
|
+
systemPrompt: "You are a helpful assistant.",
|
|
37
|
+
tools: [
|
|
38
|
+
{
|
|
39
|
+
name: "search",
|
|
40
|
+
description: "Search the web",
|
|
41
|
+
parameters: z.object({ query: z.string() }),
|
|
42
|
+
execute: async ({ query }) => ({ results: [`Result for: ${query}`] }),
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const result = await agent.run("Find news about AI");
|
|
48
|
+
console.log(result.output);
|
|
49
|
+
|
|
50
|
+
agent.dispose();
|
|
51
|
+
await service.dispose();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Tool Definition
|
|
55
|
+
|
|
56
|
+
Tools are defined with a Zod schema for parameters and an `execute` function:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { z } from "zod";
|
|
60
|
+
import type { ToolDefinition } from "@witqq/agent-sdk";
|
|
61
|
+
|
|
62
|
+
// Basic tool
|
|
63
|
+
const searchTool: ToolDefinition = {
|
|
64
|
+
name: "search",
|
|
65
|
+
description: "Search the web",
|
|
66
|
+
parameters: z.object({ query: z.string() }),
|
|
67
|
+
execute: async ({ query }) => ({ results: [`Result for: ${query}`] }),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Tool requiring user approval before execution
|
|
71
|
+
const writeFileTool: ToolDefinition = {
|
|
72
|
+
name: "write_file",
|
|
73
|
+
description: "Write content to a file",
|
|
74
|
+
parameters: z.object({ path: z.string(), content: z.string() }),
|
|
75
|
+
needsApproval: true,
|
|
76
|
+
execute: async ({ path, content }) => ({ written: true, path }),
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
When `needsApproval: true`, the `supervisor.onPermission` callback is invoked before execution. Without a supervisor, approval-required tools are denied by default.
|
|
81
|
+
|
|
82
|
+
## Permission Handling
|
|
83
|
+
|
|
84
|
+
The `supervisor` hooks intercept permission requests and user-facing questions:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const agent = service.createAgent({
|
|
88
|
+
systemPrompt: "File assistant",
|
|
89
|
+
tools: [writeFileTool],
|
|
90
|
+
supervisor: {
|
|
91
|
+
onPermission: async (req, signal) => {
|
|
92
|
+
// req.toolName, req.toolArgs, req.suggestedScope
|
|
93
|
+
console.log(`${req.toolName} wants to run with`, req.toolArgs);
|
|
94
|
+
return {
|
|
95
|
+
allowed: true,
|
|
96
|
+
scope: "session", // "once" | "session" | "project" | "always"
|
|
97
|
+
// modifiedInput: { ... }, // optionally modify args before execution
|
|
98
|
+
// reason: "...", // denial reason (if allowed: false)
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
onAskUser: async (req, signal) => {
|
|
102
|
+
// req.question, req.choices, req.allowFreeform
|
|
103
|
+
return { answer: "yes", wasFreeform: false };
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Permission Store
|
|
110
|
+
|
|
111
|
+
Persist permission decisions across runs so approved tools don't re-prompt:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { createDefaultPermissionStore } from "@witqq/agent-sdk";
|
|
115
|
+
|
|
116
|
+
const store = createDefaultPermissionStore("./my-project");
|
|
117
|
+
const agent = service.createAgent({
|
|
118
|
+
systemPrompt: "File assistant",
|
|
119
|
+
permissionStore: store,
|
|
120
|
+
tools: [writeFileTool],
|
|
121
|
+
supervisor: {
|
|
122
|
+
onPermission: async (req) => ({ allowed: true, scope: "project" }),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Scopes control persistence:
|
|
128
|
+
- `"once"` — not stored, one-time approval
|
|
129
|
+
- `"session"` — in-memory, cleared on dispose
|
|
130
|
+
- `"project"` — persisted to `<projectDir>/.agent-sdk/permissions.json`
|
|
131
|
+
- `"always"` — persisted to `~/.agent-sdk/permissions.json`
|
|
132
|
+
|
|
133
|
+
Custom stores implement `IPermissionStore`:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
interface IPermissionStore {
|
|
137
|
+
isApproved(toolName: string): Promise<boolean>;
|
|
138
|
+
approve(toolName: string, scope: PermissionScope): Promise<void>;
|
|
139
|
+
revoke(toolName: string): Promise<void>;
|
|
140
|
+
clear(): Promise<void>;
|
|
141
|
+
dispose(): Promise<void>;
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Structured Output
|
|
146
|
+
|
|
147
|
+
Extract typed data from LLM responses using `runStructured`:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { z } from "zod";
|
|
151
|
+
|
|
152
|
+
const result = await agent.runStructured(
|
|
153
|
+
"What is the capital of France?",
|
|
154
|
+
{
|
|
155
|
+
schema: z.object({
|
|
156
|
+
city: z.string(),
|
|
157
|
+
country: z.string(),
|
|
158
|
+
population: z.number(),
|
|
159
|
+
}),
|
|
160
|
+
name: "city_info", // optional, helps the LLM
|
|
161
|
+
description: "City details", // optional
|
|
162
|
+
},
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
console.log(result.structuredOutput);
|
|
166
|
+
// { city: "Paris", country: "France", population: 2161000 }
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The Vercel AI backend uses `generateObject()` for structured output. Copilot and Claude backends extract structured data from the LLM text response.
|
|
170
|
+
|
|
171
|
+
## Streaming Events
|
|
172
|
+
|
|
173
|
+
All backends emit the same event types:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
for await (const event of agent.stream("Tell me a story")) {
|
|
177
|
+
switch (event.type) {
|
|
178
|
+
case "text_delta":
|
|
179
|
+
process.stdout.write(event.text);
|
|
180
|
+
break;
|
|
181
|
+
case "tool_call_start":
|
|
182
|
+
console.log(`Calling ${event.toolName}`, event.args);
|
|
183
|
+
break;
|
|
184
|
+
case "tool_call_end":
|
|
185
|
+
console.log(`${event.toolName} returned`, event.result);
|
|
186
|
+
break;
|
|
187
|
+
case "error":
|
|
188
|
+
console.error(event.error, "recoverable:", event.recoverable);
|
|
189
|
+
break;
|
|
190
|
+
case "done":
|
|
191
|
+
console.log("Final:", event.finalOutput);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
| Event | Fields | Description |
|
|
198
|
+
|-------|--------|-------------|
|
|
199
|
+
| `text_delta` | `text` | Incremental text output |
|
|
200
|
+
| `thinking_start` | — | Model started reasoning |
|
|
201
|
+
| `thinking_end` | — | Model finished reasoning |
|
|
202
|
+
| `tool_call_start` | `toolName`, `args` | Tool invocation began |
|
|
203
|
+
| `tool_call_end` | `toolName`, `result` | Tool invocation completed |
|
|
204
|
+
| `permission_request` | `request` | Permission check initiated |
|
|
205
|
+
| `permission_response` | `toolName`, `decision` | Permission decision made |
|
|
206
|
+
| `ask_user` | `request` | User input requested |
|
|
207
|
+
| `ask_user_response` | `answer` | User response received |
|
|
208
|
+
| `usage_update` | `promptTokens`, `completionTokens` | Token usage |
|
|
209
|
+
| `error` | `error`, `recoverable` | Error during execution |
|
|
210
|
+
| `done` | `finalOutput`, `structuredOutput?` | Execution completed |
|
|
211
|
+
|
|
212
|
+
## Backend-Specific Options
|
|
213
|
+
|
|
214
|
+
### Copilot
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { createCopilotService } from "@witqq/agent-sdk/copilot";
|
|
218
|
+
|
|
219
|
+
const service = createCopilotService({
|
|
220
|
+
useLoggedInUser: true, // use GitHub CLI auth
|
|
221
|
+
cliPath: "/path/to/copilot", // optional custom CLI path
|
|
222
|
+
workingDirectory: process.cwd(),
|
|
223
|
+
githubToken: "ghp_...", // optional, alternative to useLoggedInUser
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Claude
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { createClaudeService } from "@witqq/agent-sdk/claude";
|
|
231
|
+
|
|
232
|
+
const service = createClaudeService({
|
|
233
|
+
cliPath: "/path/to/claude", // optional custom CLI path
|
|
234
|
+
workingDirectory: process.cwd(),
|
|
235
|
+
maxTurns: 10,
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`supervisor.onAskUser` is not supported by the Claude backend; a warning is emitted if set.
|
|
240
|
+
|
|
241
|
+
### Vercel AI (OpenRouter / OpenAI-compatible)
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
import { createVercelAIService } from "@witqq/agent-sdk/vercel-ai";
|
|
245
|
+
|
|
246
|
+
const service = createVercelAIService({
|
|
247
|
+
apiKey: process.env.OPENROUTER_API_KEY!,
|
|
248
|
+
baseUrl: "https://openrouter.ai/api/v1", // default
|
|
249
|
+
provider: "openrouter", // default
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const agent = service.createAgent({
|
|
253
|
+
model: "anthropic/claude-sonnet-4-5",
|
|
254
|
+
systemPrompt: "You are a helpful assistant.",
|
|
255
|
+
tools: [searchTool],
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Uses `generateText()` for runs, `generateObject()` for structured output, `streamText()` for streaming. Supports `supervisor.onAskUser` via an injected `ask_user` tool.
|
|
260
|
+
|
|
261
|
+
## Switching Backends
|
|
262
|
+
|
|
263
|
+
All backends share the same `AgentConfig` and return the same `AgentResult`. To switch backends, change only the service creation:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { createAgentService } from "@witqq/agent-sdk";
|
|
267
|
+
import { z } from "zod";
|
|
268
|
+
|
|
269
|
+
const tools = [
|
|
270
|
+
{
|
|
271
|
+
name: "greet",
|
|
272
|
+
description: "Greet a user",
|
|
273
|
+
parameters: z.object({ name: z.string() }),
|
|
274
|
+
execute: async ({ name }) => ({ message: `Hello, ${name}!` }),
|
|
275
|
+
},
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
const config = {
|
|
279
|
+
systemPrompt: "You are a helpful assistant.",
|
|
280
|
+
tools,
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// Switch backend by changing the first argument:
|
|
284
|
+
const service = await createAgentService("copilot", { useLoggedInUser: true });
|
|
285
|
+
// const service = await createAgentService("claude", { workingDirectory: "." });
|
|
286
|
+
// const service = await createAgentService("vercel-ai", { apiKey: "..." });
|
|
287
|
+
|
|
288
|
+
const agent = service.createAgent(config);
|
|
289
|
+
const result = await agent.run("Greet Alice");
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Or use direct backend imports to avoid lazy loading:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { createCopilotService } from "@witqq/agent-sdk/copilot";
|
|
296
|
+
import { createClaudeService } from "@witqq/agent-sdk/claude";
|
|
297
|
+
import { createVercelAIService } from "@witqq/agent-sdk/vercel-ai";
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Build
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
npm run build # tsup → ESM + CJS
|
|
304
|
+
npm run test # vitest
|
|
305
|
+
npm run typecheck # tsc --noEmit
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
MIT
|