@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
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/types.ts
|
|
4
|
+
function getTextContent(content) {
|
|
5
|
+
if (typeof content === "string") return content;
|
|
6
|
+
return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/errors.ts
|
|
10
|
+
var AgentSDKError = class extends Error {
|
|
11
|
+
constructor(message, options) {
|
|
12
|
+
super(message, options);
|
|
13
|
+
this.name = "AgentSDKError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var ReentrancyError = class extends AgentSDKError {
|
|
17
|
+
constructor() {
|
|
18
|
+
super("Agent is already running. Await the current run before starting another.");
|
|
19
|
+
this.name = "ReentrancyError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var DisposedError = class extends AgentSDKError {
|
|
23
|
+
constructor(entity) {
|
|
24
|
+
super(`${entity} has been disposed and cannot be used.`);
|
|
25
|
+
this.name = "DisposedError";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var DependencyError = class extends AgentSDKError {
|
|
29
|
+
packageName;
|
|
30
|
+
constructor(packageName) {
|
|
31
|
+
super(`${packageName} is not installed. Install it: npm install ${packageName}`);
|
|
32
|
+
this.name = "DependencyError";
|
|
33
|
+
this.packageName = packageName;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var AbortError = class extends AgentSDKError {
|
|
37
|
+
constructor() {
|
|
38
|
+
super("Agent run was aborted.");
|
|
39
|
+
this.name = "AbortError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var ToolExecutionError = class extends AgentSDKError {
|
|
43
|
+
toolName;
|
|
44
|
+
constructor(toolName, message, options) {
|
|
45
|
+
super(`Tool "${toolName}" failed: ${message}`, options);
|
|
46
|
+
this.name = "ToolExecutionError";
|
|
47
|
+
this.toolName = toolName;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/base-agent.ts
|
|
52
|
+
var BaseAgent = class {
|
|
53
|
+
state = "idle";
|
|
54
|
+
abortController = null;
|
|
55
|
+
config;
|
|
56
|
+
constructor(config) {
|
|
57
|
+
this.config = Object.freeze({ ...config });
|
|
58
|
+
}
|
|
59
|
+
// ─── Public Interface ─────────────────────────────────────────
|
|
60
|
+
async run(prompt, options) {
|
|
61
|
+
this.guardReentrancy();
|
|
62
|
+
this.guardDisposed();
|
|
63
|
+
const ac = this.createAbortController(options?.signal);
|
|
64
|
+
this.state = "running";
|
|
65
|
+
try {
|
|
66
|
+
const messages = [{ role: "user", content: prompt }];
|
|
67
|
+
return await this.executeRun(messages, options, ac.signal);
|
|
68
|
+
} finally {
|
|
69
|
+
this.state = "idle";
|
|
70
|
+
this.abortController = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async runWithContext(messages, options) {
|
|
74
|
+
this.guardReentrancy();
|
|
75
|
+
this.guardDisposed();
|
|
76
|
+
const ac = this.createAbortController(options?.signal);
|
|
77
|
+
this.state = "running";
|
|
78
|
+
try {
|
|
79
|
+
return await this.executeRun(messages, options, ac.signal);
|
|
80
|
+
} finally {
|
|
81
|
+
this.state = "idle";
|
|
82
|
+
this.abortController = null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async runStructured(prompt, schema, options) {
|
|
86
|
+
this.guardReentrancy();
|
|
87
|
+
this.guardDisposed();
|
|
88
|
+
const ac = this.createAbortController(options?.signal);
|
|
89
|
+
this.state = "running";
|
|
90
|
+
try {
|
|
91
|
+
const messages = [{ role: "user", content: prompt }];
|
|
92
|
+
return await this.executeRunStructured(
|
|
93
|
+
messages,
|
|
94
|
+
schema,
|
|
95
|
+
options,
|
|
96
|
+
ac.signal
|
|
97
|
+
);
|
|
98
|
+
} finally {
|
|
99
|
+
this.state = "idle";
|
|
100
|
+
this.abortController = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async *stream(prompt, options) {
|
|
104
|
+
this.guardReentrancy();
|
|
105
|
+
this.guardDisposed();
|
|
106
|
+
const ac = this.createAbortController(options?.signal);
|
|
107
|
+
this.state = "streaming";
|
|
108
|
+
try {
|
|
109
|
+
const messages = [{ role: "user", content: prompt }];
|
|
110
|
+
yield* this.executeStream(messages, options, ac.signal);
|
|
111
|
+
} finally {
|
|
112
|
+
this.state = "idle";
|
|
113
|
+
this.abortController = null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
abort() {
|
|
117
|
+
if (this.abortController) {
|
|
118
|
+
this.abortController.abort();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
getState() {
|
|
122
|
+
return this.state;
|
|
123
|
+
}
|
|
124
|
+
getConfig() {
|
|
125
|
+
return this.config;
|
|
126
|
+
}
|
|
127
|
+
/** Mark agent as disposed. Override to add cleanup. */
|
|
128
|
+
dispose() {
|
|
129
|
+
this.abort();
|
|
130
|
+
this.state = "disposed";
|
|
131
|
+
}
|
|
132
|
+
// ─── Guards ───────────────────────────────────────────────────
|
|
133
|
+
guardReentrancy() {
|
|
134
|
+
if (this.state === "running" || this.state === "streaming") {
|
|
135
|
+
throw new ReentrancyError();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
guardDisposed() {
|
|
139
|
+
if (this.state === "disposed") {
|
|
140
|
+
throw new DisposedError("Agent");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Throw AbortError if signal is already aborted */
|
|
144
|
+
checkAbort(signal) {
|
|
145
|
+
if (signal.aborted) {
|
|
146
|
+
throw new AbortError();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// ─── Internal Helpers ─────────────────────────────────────────
|
|
150
|
+
createAbortController(externalSignal) {
|
|
151
|
+
const ac = new AbortController();
|
|
152
|
+
this.abortController = ac;
|
|
153
|
+
if (externalSignal) {
|
|
154
|
+
if (externalSignal.aborted) {
|
|
155
|
+
ac.abort();
|
|
156
|
+
} else {
|
|
157
|
+
externalSignal.addEventListener("abort", () => ac.abort(), {
|
|
158
|
+
once: true
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return ac;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// src/utils/schema.ts
|
|
167
|
+
function zodToJsonSchema(schema) {
|
|
168
|
+
const schemaAny = schema;
|
|
169
|
+
if ("jsonSchema" in schema && typeof schemaAny.jsonSchema === "function") {
|
|
170
|
+
return schemaAny.jsonSchema();
|
|
171
|
+
}
|
|
172
|
+
return extractSchemaFromDef(schema);
|
|
173
|
+
}
|
|
174
|
+
function extractSchemaFromDef(schema) {
|
|
175
|
+
const def = schema._def;
|
|
176
|
+
const typeName = def.typeName;
|
|
177
|
+
switch (typeName) {
|
|
178
|
+
case "ZodString":
|
|
179
|
+
return { type: "string" };
|
|
180
|
+
case "ZodNumber":
|
|
181
|
+
return { type: "number" };
|
|
182
|
+
case "ZodBoolean":
|
|
183
|
+
return { type: "boolean" };
|
|
184
|
+
case "ZodNull":
|
|
185
|
+
return { type: "null" };
|
|
186
|
+
case "ZodArray":
|
|
187
|
+
return {
|
|
188
|
+
type: "array",
|
|
189
|
+
items: extractSchemaFromDef(def.type)
|
|
190
|
+
};
|
|
191
|
+
case "ZodObject": {
|
|
192
|
+
const shape = schema.shape;
|
|
193
|
+
const properties = {};
|
|
194
|
+
const required = [];
|
|
195
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
196
|
+
const valueDef = value._def;
|
|
197
|
+
if (valueDef.typeName === "ZodOptional") {
|
|
198
|
+
properties[key] = extractSchemaFromDef(valueDef.innerType);
|
|
199
|
+
} else {
|
|
200
|
+
properties[key] = extractSchemaFromDef(value);
|
|
201
|
+
required.push(key);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
type: "object",
|
|
206
|
+
properties,
|
|
207
|
+
...required.length > 0 ? { required } : {}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
case "ZodOptional":
|
|
211
|
+
return extractSchemaFromDef(def.innerType);
|
|
212
|
+
case "ZodEnum":
|
|
213
|
+
return { type: "string", enum: def.values };
|
|
214
|
+
default:
|
|
215
|
+
return {};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/backends/vercel-ai.ts
|
|
220
|
+
var sdkModule = null;
|
|
221
|
+
var compatModule = null;
|
|
222
|
+
async function loadSDK() {
|
|
223
|
+
if (sdkModule) return sdkModule;
|
|
224
|
+
try {
|
|
225
|
+
sdkModule = await import('ai');
|
|
226
|
+
return sdkModule;
|
|
227
|
+
} catch {
|
|
228
|
+
throw new DependencyError("ai");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function loadCompat() {
|
|
232
|
+
if (compatModule) return compatModule;
|
|
233
|
+
try {
|
|
234
|
+
compatModule = await import('@ai-sdk/openai-compatible');
|
|
235
|
+
return compatModule;
|
|
236
|
+
} catch {
|
|
237
|
+
throw new DependencyError("@ai-sdk/openai-compatible");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function _injectSDK(mock) {
|
|
241
|
+
sdkModule = mock;
|
|
242
|
+
}
|
|
243
|
+
function _injectCompat(mock) {
|
|
244
|
+
compatModule = mock;
|
|
245
|
+
}
|
|
246
|
+
function _resetSDK() {
|
|
247
|
+
sdkModule = null;
|
|
248
|
+
compatModule = null;
|
|
249
|
+
}
|
|
250
|
+
var DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
251
|
+
var DEFAULT_PROVIDER = "openrouter";
|
|
252
|
+
var DEFAULT_MAX_TURNS = 10;
|
|
253
|
+
function mapToolsToSDK(sdk, tools, config, sessionApprovals, permissionStore, signal) {
|
|
254
|
+
const toolMap = {};
|
|
255
|
+
const supervisor = config.supervisor;
|
|
256
|
+
for (const ourTool of tools) {
|
|
257
|
+
const jsonSchema = zodToJsonSchema(ourTool.parameters);
|
|
258
|
+
toolMap[ourTool.name] = sdk.tool({
|
|
259
|
+
description: ourTool.description,
|
|
260
|
+
parameters: sdk.jsonSchema(jsonSchema),
|
|
261
|
+
execute: wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal),
|
|
262
|
+
...ourTool.needsApproval && supervisor?.onPermission ? {
|
|
263
|
+
needsApproval: async (_args) => {
|
|
264
|
+
if (permissionStore && await permissionStore.isApproved(ourTool.name)) return false;
|
|
265
|
+
if (sessionApprovals.has(ourTool.name)) return false;
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
} : {}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
if (supervisor?.onAskUser) {
|
|
272
|
+
const onAskUser = supervisor.onAskUser;
|
|
273
|
+
toolMap["ask_user"] = sdk.tool({
|
|
274
|
+
description: "Ask the user a question and wait for their response",
|
|
275
|
+
parameters: sdk.jsonSchema({
|
|
276
|
+
type: "object",
|
|
277
|
+
properties: {
|
|
278
|
+
question: { type: "string", description: "The question to ask the user" }
|
|
279
|
+
},
|
|
280
|
+
required: ["question"]
|
|
281
|
+
}),
|
|
282
|
+
execute: async (args) => {
|
|
283
|
+
const response = await onAskUser(
|
|
284
|
+
{ question: args.question, allowFreeform: true },
|
|
285
|
+
signal
|
|
286
|
+
);
|
|
287
|
+
return response.answer;
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
return toolMap;
|
|
292
|
+
}
|
|
293
|
+
function wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal) {
|
|
294
|
+
return async (args) => {
|
|
295
|
+
if (ourTool.needsApproval && supervisor?.onPermission) {
|
|
296
|
+
const storeApproved = permissionStore && await permissionStore.isApproved(ourTool.name);
|
|
297
|
+
if (!storeApproved && !sessionApprovals.has(ourTool.name)) {
|
|
298
|
+
const request = {
|
|
299
|
+
toolName: ourTool.name,
|
|
300
|
+
toolArgs: args ?? {}
|
|
301
|
+
};
|
|
302
|
+
const decision = await supervisor.onPermission(
|
|
303
|
+
request,
|
|
304
|
+
signal
|
|
305
|
+
);
|
|
306
|
+
if (!decision.allowed) {
|
|
307
|
+
throw new ToolExecutionError(
|
|
308
|
+
ourTool.name,
|
|
309
|
+
decision.reason ?? "Permission denied"
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
if (permissionStore && decision.scope) {
|
|
313
|
+
await permissionStore.approve(ourTool.name, decision.scope);
|
|
314
|
+
}
|
|
315
|
+
if (decision.scope === "session" || decision.scope === "always" || decision.scope === "project") {
|
|
316
|
+
sessionApprovals.add(ourTool.name);
|
|
317
|
+
}
|
|
318
|
+
if (decision.modifiedInput) {
|
|
319
|
+
args = decision.modifiedInput;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
const result = await ourTool.execute(args);
|
|
325
|
+
return result;
|
|
326
|
+
} catch (e) {
|
|
327
|
+
if (e instanceof ToolExecutionError) throw e;
|
|
328
|
+
throw new ToolExecutionError(
|
|
329
|
+
ourTool.name,
|
|
330
|
+
e instanceof Error ? e.message : String(e)
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function messagesToSDK(messages) {
|
|
336
|
+
return messages.map((msg) => {
|
|
337
|
+
switch (msg.role) {
|
|
338
|
+
case "user":
|
|
339
|
+
return { role: "user", content: getTextContent(msg.content) };
|
|
340
|
+
case "assistant":
|
|
341
|
+
return { role: "assistant", content: getTextContent(msg.content) };
|
|
342
|
+
case "system":
|
|
343
|
+
return { role: "system", content: msg.content };
|
|
344
|
+
case "tool":
|
|
345
|
+
return { role: "tool", content: msg.content ?? "" };
|
|
346
|
+
default:
|
|
347
|
+
return { role: "user", content: "" };
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
function mapStreamPart(part) {
|
|
352
|
+
switch (part.type) {
|
|
353
|
+
case "text-delta":
|
|
354
|
+
return { type: "text_delta", text: part.text ?? "" };
|
|
355
|
+
case "tool-call":
|
|
356
|
+
return {
|
|
357
|
+
type: "tool_call_start",
|
|
358
|
+
toolName: part.toolName ?? "unknown",
|
|
359
|
+
args: part.args ?? {}
|
|
360
|
+
};
|
|
361
|
+
case "tool-result":
|
|
362
|
+
return {
|
|
363
|
+
type: "tool_call_end",
|
|
364
|
+
toolName: part.toolName ?? "unknown",
|
|
365
|
+
result: part.result ?? null
|
|
366
|
+
};
|
|
367
|
+
case "tool-error":
|
|
368
|
+
return {
|
|
369
|
+
type: "error",
|
|
370
|
+
error: part.error instanceof Error ? part.error.message : String(part.error ?? "Tool execution failed"),
|
|
371
|
+
recoverable: true
|
|
372
|
+
};
|
|
373
|
+
case "reasoning-start":
|
|
374
|
+
return { type: "thinking_start" };
|
|
375
|
+
case "reasoning-end":
|
|
376
|
+
return { type: "thinking_end" };
|
|
377
|
+
case "reasoning-delta":
|
|
378
|
+
return { type: "text_delta", text: part.text ?? "" };
|
|
379
|
+
case "finish-step":
|
|
380
|
+
return {
|
|
381
|
+
type: "usage_update",
|
|
382
|
+
promptTokens: Number(part.usage?.inputTokens ?? 0),
|
|
383
|
+
completionTokens: Number(part.usage?.outputTokens ?? 0)
|
|
384
|
+
};
|
|
385
|
+
case "error":
|
|
386
|
+
return {
|
|
387
|
+
type: "error",
|
|
388
|
+
error: part.error instanceof Error ? part.error.message : String(part.error ?? "Unknown error"),
|
|
389
|
+
recoverable: false
|
|
390
|
+
};
|
|
391
|
+
default:
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
var VercelAIAgent = class extends BaseAgent {
|
|
396
|
+
backendOptions;
|
|
397
|
+
sessionApprovals = /* @__PURE__ */ new Set();
|
|
398
|
+
model = null;
|
|
399
|
+
constructor(config, backendOptions) {
|
|
400
|
+
super(config);
|
|
401
|
+
this.backendOptions = backendOptions;
|
|
402
|
+
}
|
|
403
|
+
async getModel() {
|
|
404
|
+
if (this.model) return this.model;
|
|
405
|
+
const compat = await loadCompat();
|
|
406
|
+
const provider = compat.createOpenAICompatible({
|
|
407
|
+
name: this.backendOptions.provider ?? DEFAULT_PROVIDER,
|
|
408
|
+
baseURL: this.backendOptions.baseUrl ?? DEFAULT_BASE_URL,
|
|
409
|
+
apiKey: this.backendOptions.apiKey
|
|
410
|
+
});
|
|
411
|
+
const modelId = this.config.model ?? "anthropic/claude-sonnet-4-5";
|
|
412
|
+
this.model = provider.chatModel(modelId);
|
|
413
|
+
return this.model;
|
|
414
|
+
}
|
|
415
|
+
async getSDKTools(signal) {
|
|
416
|
+
const sdk = await loadSDK();
|
|
417
|
+
return mapToolsToSDK(sdk, this.config.tools, this.config, this.sessionApprovals, this.config.permissionStore, signal);
|
|
418
|
+
}
|
|
419
|
+
// ─── executeRun ─────────────────────────────────────────────────
|
|
420
|
+
async executeRun(messages, _options, signal) {
|
|
421
|
+
this.checkAbort(signal);
|
|
422
|
+
const sdk = await loadSDK();
|
|
423
|
+
const model = await this.getModel();
|
|
424
|
+
const tools = await this.getSDKTools(signal);
|
|
425
|
+
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
426
|
+
const sdkMessages = messagesToSDK(messages);
|
|
427
|
+
const hasTools = Object.keys(tools).length > 0;
|
|
428
|
+
const result = await sdk.generateText({
|
|
429
|
+
model,
|
|
430
|
+
system: this.config.systemPrompt,
|
|
431
|
+
messages: sdkMessages,
|
|
432
|
+
tools: hasTools ? tools : void 0,
|
|
433
|
+
maxSteps: maxTurns,
|
|
434
|
+
abortSignal: signal,
|
|
435
|
+
...this.config.modelParams?.temperature !== void 0 && {
|
|
436
|
+
temperature: this.config.modelParams.temperature
|
|
437
|
+
},
|
|
438
|
+
...this.config.modelParams?.maxTokens !== void 0 && {
|
|
439
|
+
maxTokens: this.config.modelParams.maxTokens
|
|
440
|
+
},
|
|
441
|
+
...this.config.modelParams?.topP !== void 0 && {
|
|
442
|
+
topP: this.config.modelParams.topP
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
const toolCalls = [];
|
|
446
|
+
for (const step of result.steps) {
|
|
447
|
+
for (const tc of step.toolCalls) {
|
|
448
|
+
const matchingResult = step.toolResults.find(
|
|
449
|
+
(tr) => tr.toolCallId === tc.toolCallId
|
|
450
|
+
);
|
|
451
|
+
toolCalls.push({
|
|
452
|
+
toolName: tc.toolName,
|
|
453
|
+
args: tc.args ?? {},
|
|
454
|
+
result: matchingResult?.result ?? null,
|
|
455
|
+
approved: true
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
const usage = {
|
|
460
|
+
promptTokens: Number(result.totalUsage?.inputTokens ?? 0),
|
|
461
|
+
completionTokens: Number(result.totalUsage?.outputTokens ?? 0)
|
|
462
|
+
};
|
|
463
|
+
return {
|
|
464
|
+
output: result.text || null,
|
|
465
|
+
structuredOutput: void 0,
|
|
466
|
+
toolCalls,
|
|
467
|
+
messages: [
|
|
468
|
+
...messages,
|
|
469
|
+
...result.text ? [{ role: "assistant", content: result.text }] : []
|
|
470
|
+
],
|
|
471
|
+
usage
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
// ─── executeRunStructured ───────────────────────────────────────
|
|
475
|
+
async executeRunStructured(messages, schema, _options, signal) {
|
|
476
|
+
this.checkAbort(signal);
|
|
477
|
+
const sdk = await loadSDK();
|
|
478
|
+
const model = await this.getModel();
|
|
479
|
+
const sdkMessages = messagesToSDK(messages);
|
|
480
|
+
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
481
|
+
const result = await sdk.generateObject({
|
|
482
|
+
model,
|
|
483
|
+
system: this.config.systemPrompt,
|
|
484
|
+
messages: sdkMessages,
|
|
485
|
+
schema: sdk.jsonSchema(jsonSchema),
|
|
486
|
+
schemaName: schema.name,
|
|
487
|
+
schemaDescription: schema.description,
|
|
488
|
+
abortSignal: signal,
|
|
489
|
+
...this.config.modelParams?.temperature !== void 0 && {
|
|
490
|
+
temperature: this.config.modelParams.temperature
|
|
491
|
+
},
|
|
492
|
+
...this.config.modelParams?.maxTokens !== void 0 && {
|
|
493
|
+
maxTokens: this.config.modelParams.maxTokens
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
let structuredOutput;
|
|
497
|
+
try {
|
|
498
|
+
structuredOutput = schema.schema.parse(result.object);
|
|
499
|
+
} catch {
|
|
500
|
+
}
|
|
501
|
+
const usage = {
|
|
502
|
+
promptTokens: Number(result.usage?.inputTokens ?? 0),
|
|
503
|
+
completionTokens: Number(result.usage?.outputTokens ?? 0)
|
|
504
|
+
};
|
|
505
|
+
return {
|
|
506
|
+
output: JSON.stringify(result.object),
|
|
507
|
+
structuredOutput,
|
|
508
|
+
toolCalls: [],
|
|
509
|
+
messages: [
|
|
510
|
+
...messages,
|
|
511
|
+
...result.object != null ? [{ role: "assistant", content: JSON.stringify(result.object) }] : []
|
|
512
|
+
],
|
|
513
|
+
usage
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
// ─── executeStream ──────────────────────────────────────────────
|
|
517
|
+
async *executeStream(messages, _options, signal) {
|
|
518
|
+
this.checkAbort(signal);
|
|
519
|
+
const sdk = await loadSDK();
|
|
520
|
+
const model = await this.getModel();
|
|
521
|
+
const tools = await this.getSDKTools(signal);
|
|
522
|
+
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
523
|
+
const sdkMessages = messagesToSDK(messages);
|
|
524
|
+
const hasTools = Object.keys(tools).length > 0;
|
|
525
|
+
const result = sdk.streamText({
|
|
526
|
+
model,
|
|
527
|
+
system: this.config.systemPrompt,
|
|
528
|
+
messages: sdkMessages,
|
|
529
|
+
tools: hasTools ? tools : void 0,
|
|
530
|
+
maxSteps: maxTurns,
|
|
531
|
+
abortSignal: signal,
|
|
532
|
+
...this.config.modelParams?.temperature !== void 0 && {
|
|
533
|
+
temperature: this.config.modelParams.temperature
|
|
534
|
+
},
|
|
535
|
+
...this.config.modelParams?.maxTokens !== void 0 && {
|
|
536
|
+
maxTokens: this.config.modelParams.maxTokens
|
|
537
|
+
},
|
|
538
|
+
...this.config.modelParams?.topP !== void 0 && {
|
|
539
|
+
topP: this.config.modelParams.topP
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
let finalText = "";
|
|
543
|
+
try {
|
|
544
|
+
for await (const part of result.fullStream) {
|
|
545
|
+
if (signal.aborted) throw new AbortError();
|
|
546
|
+
const event = mapStreamPart(part);
|
|
547
|
+
if (event) yield event;
|
|
548
|
+
if (part.type === "text-delta") {
|
|
549
|
+
finalText += part.text ?? "";
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
const totalUsage = await result.totalUsage;
|
|
553
|
+
yield {
|
|
554
|
+
type: "usage_update",
|
|
555
|
+
promptTokens: Number(totalUsage?.inputTokens ?? 0),
|
|
556
|
+
completionTokens: Number(totalUsage?.outputTokens ?? 0)
|
|
557
|
+
};
|
|
558
|
+
yield {
|
|
559
|
+
type: "done",
|
|
560
|
+
finalOutput: finalText || null
|
|
561
|
+
};
|
|
562
|
+
} catch (e) {
|
|
563
|
+
if (signal.aborted) throw new AbortError();
|
|
564
|
+
throw e;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
dispose() {
|
|
568
|
+
this.sessionApprovals.clear();
|
|
569
|
+
this.model = null;
|
|
570
|
+
super.dispose();
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
var VercelAIAgentService = class {
|
|
574
|
+
name = "vercel-ai";
|
|
575
|
+
disposed = false;
|
|
576
|
+
options;
|
|
577
|
+
constructor(options) {
|
|
578
|
+
this.options = options;
|
|
579
|
+
}
|
|
580
|
+
createAgent(config) {
|
|
581
|
+
if (this.disposed) throw new DisposedError("VercelAIAgentService");
|
|
582
|
+
return new VercelAIAgent(config, this.options);
|
|
583
|
+
}
|
|
584
|
+
async listModels() {
|
|
585
|
+
if (this.disposed) throw new DisposedError("VercelAIAgentService");
|
|
586
|
+
return [];
|
|
587
|
+
}
|
|
588
|
+
async validate() {
|
|
589
|
+
if (this.disposed) throw new DisposedError("VercelAIAgentService");
|
|
590
|
+
const errors = [];
|
|
591
|
+
if (!this.options.apiKey) {
|
|
592
|
+
errors.push("apiKey is required for Vercel AI backend.");
|
|
593
|
+
}
|
|
594
|
+
try {
|
|
595
|
+
await loadSDK();
|
|
596
|
+
} catch (e) {
|
|
597
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
598
|
+
}
|
|
599
|
+
try {
|
|
600
|
+
await loadCompat();
|
|
601
|
+
} catch (e) {
|
|
602
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
603
|
+
}
|
|
604
|
+
return { valid: errors.length === 0, errors };
|
|
605
|
+
}
|
|
606
|
+
async dispose() {
|
|
607
|
+
if (this.disposed) return;
|
|
608
|
+
this.disposed = true;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
function createVercelAIService(options) {
|
|
612
|
+
return new VercelAIAgentService(options);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
exports._injectCompat = _injectCompat;
|
|
616
|
+
exports._injectSDK = _injectSDK;
|
|
617
|
+
exports._resetSDK = _resetSDK;
|
|
618
|
+
exports.createVercelAIService = createVercelAIService;
|
|
619
|
+
//# sourceMappingURL=vercel-ai.cjs.map
|
|
620
|
+
//# sourceMappingURL=vercel-ai.cjs.map
|