@perstack/runtime 0.0.70 → 0.0.72

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.
@@ -1,3 +1,8 @@
1
+ import { getSkillManagersFromLockfile, getSkillManagers, closeSkillManagers, getSkillManagerByToolName, getToolSet } from './chunk-RG4QHAGG.js';
2
+ import { readFileSync } from 'fs';
3
+ import path from 'path';
4
+ import { parseWithFriendlyError, lockfileSchema, runParamsSchema, createRuntimeEvent, knownModels, stopRunByExceededMaxSteps, continueToNextStep, stopRunByDelegate, stopRunByInteractiveTool, stopRunByError, retry, completeRun, finishToolCall, resolveToolResults, attemptCompletion, callDelegate, callInteractiveTool, callTools, resumeToolCalls, finishAllToolCalls, startGeneration, startRun } from '@perstack/core';
5
+ import TOML from 'smol-toml';
1
6
  import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
2
7
  import { createAnthropic } from '@ai-sdk/anthropic';
3
8
  import { createAzure } from '@ai-sdk/azure';
@@ -5,24 +10,19 @@ import { createDeepSeek } from '@ai-sdk/deepseek';
5
10
  import { createGoogleGenerativeAI } from '@ai-sdk/google';
6
11
  import { createVertex } from '@ai-sdk/google-vertex';
7
12
  import { createOpenAI } from '@ai-sdk/openai';
8
- import { runParamsSchema, createRuntimeEvent, knownModels, getFilteredEnv, stopRunByExceededMaxSteps, continueToNextStep, stopRunByDelegate, stopRunByInteractiveTool, retry, completeRun, finishToolCall, resolveToolResults, attemptCompletion, callDelegate, callInteractiveTool, callTools, resumeToolCalls, finishAllToolCalls, startGeneration, startRun } from '@perstack/core';
9
13
  import { createOllama } from 'ollama-ai-provider-v2';
10
14
  import { ProxyAgent, fetch } from 'undici';
15
+ import { createApiClient } from '@perstack/api-client';
11
16
  import { setup, assign, createActor } from 'xstate';
12
- import { generateText, tool, jsonSchema } from 'ai';
13
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
14
- import { McpError } from '@modelcontextprotocol/sdk/types.js';
15
- import { createId } from '@paralleldrive/cuid2';
16
- import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
17
- import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
18
17
  import { readFile } from 'fs/promises';
18
+ import { createId } from '@paralleldrive/cuid2';
19
19
  import { dedent } from 'ts-dedent';
20
- import { ApiV1Client } from '@perstack/api-client/v1';
20
+ import { APICallError, generateText, streamText } from 'ai';
21
21
 
22
22
  // package.json
23
23
  var package_default = {
24
24
  name: "@perstack/runtime",
25
- version: "0.0.70",
25
+ version: "0.0.72",
26
26
  description: "Perstack Runtime",
27
27
  author: "Wintermute Technologies, Inc.",
28
28
  license: "Apache-2.0",
@@ -54,21 +54,22 @@ var package_default = {
54
54
  typecheck: "tsc --noEmit"
55
55
  },
56
56
  dependencies: {
57
- "@ai-sdk/amazon-bedrock": "^3.0.71",
58
- "@ai-sdk/anthropic": "^2.0.56",
59
- "@ai-sdk/azure": "^2.0.90",
60
- "@ai-sdk/deepseek": "^1.0.32",
61
- "@ai-sdk/google": "^2.0.49",
62
- "@ai-sdk/google-vertex": "^3.0.94",
63
- "@ai-sdk/openai": "^2.0.88",
57
+ "@ai-sdk/amazon-bedrock": "^3.0.0",
58
+ "@ai-sdk/anthropic": "^2.0.0",
59
+ "@ai-sdk/azure": "^2.0.0",
60
+ "@ai-sdk/deepseek": "^1.0.0",
61
+ "@ai-sdk/google": "^2.0.0",
62
+ "@ai-sdk/google-vertex": "^3.0.0",
63
+ "@ai-sdk/openai": "^2.0.0",
64
64
  "@modelcontextprotocol/sdk": "^1.25.1",
65
65
  "@paralleldrive/cuid2": "^3.0.4",
66
66
  "@perstack/api-client": "workspace:*",
67
+ "@perstack/base": "workspace:*",
67
68
  "@perstack/core": "workspace:*",
68
69
  ai: "^5.0.115",
70
+ "ollama-ai-provider-v2": "^1.5.5",
69
71
  commander: "^14.0.2",
70
72
  dotenv: "^17.2.3",
71
- "ollama-ai-provider-v2": "^1.5.5",
72
73
  "smol-toml": "^1.5.2",
73
74
  "ts-dedent": "^2.2.0",
74
75
  undici: "^7.16.0",
@@ -86,6 +87,56 @@ var package_default = {
86
87
  node: ">=22.0.0"
87
88
  }
88
89
  };
90
+ function loadLockfile(lockfilePath) {
91
+ try {
92
+ const content = readFileSync(lockfilePath, "utf-8");
93
+ const parsed = TOML.parse(content);
94
+ return parseWithFriendlyError(lockfileSchema, parsed, "perstack.lock");
95
+ } catch {
96
+ return null;
97
+ }
98
+ }
99
+ function isRemoteUrl(configPath) {
100
+ const lower = configPath.toLowerCase();
101
+ return lower.startsWith("https://") || lower.startsWith("http://");
102
+ }
103
+ function findLockfile(configPath) {
104
+ if (configPath) {
105
+ if (isRemoteUrl(configPath)) {
106
+ return null;
107
+ }
108
+ const configDir = path.dirname(path.resolve(process.cwd(), configPath));
109
+ return path.join(configDir, "perstack.lock");
110
+ }
111
+ return findLockfileRecursively(process.cwd());
112
+ }
113
+ function findLockfileRecursively(cwd) {
114
+ const lockfilePath = path.resolve(cwd, "perstack.lock");
115
+ try {
116
+ readFileSync(lockfilePath);
117
+ return lockfilePath;
118
+ } catch {
119
+ if (cwd === path.parse(cwd).root) {
120
+ return null;
121
+ }
122
+ return findLockfileRecursively(path.dirname(cwd));
123
+ }
124
+ }
125
+ function getLockfileExpertToolDefinitions(lockfileExpert) {
126
+ const result = {};
127
+ for (const toolDef of lockfileExpert.toolDefinitions) {
128
+ if (!result[toolDef.skillName]) {
129
+ result[toolDef.skillName] = [];
130
+ }
131
+ result[toolDef.skillName].push({
132
+ skillName: toolDef.skillName,
133
+ name: toolDef.name,
134
+ description: toolDef.description,
135
+ inputSchema: toolDef.inputSchema
136
+ });
137
+ }
138
+ return result;
139
+ }
89
140
  function createProxyFetch(proxyUrl) {
90
141
  const agent = new ProxyAgent(proxyUrl);
91
142
  return (input, init) => {
@@ -217,523 +268,136 @@ function sumUsage(a, b) {
217
268
  };
218
269
  }
219
270
 
220
- // src/skill-manager/base.ts
221
- var BaseSkillManager = class {
222
- _toolDefinitions = [];
223
- _initialized = false;
224
- _initializing;
225
- skill;
226
- interactiveSkill;
227
- expert;
228
- _jobId;
229
- _runId;
230
- _eventListener;
231
- constructor(jobId, runId, eventListener) {
232
- this._jobId = jobId;
233
- this._runId = runId;
234
- this._eventListener = eventListener;
235
- }
236
- async init() {
237
- if (this._initialized) {
238
- throw new Error(`Skill ${this.name} is already initialized`);
239
- }
240
- if (this._initializing) {
241
- throw new Error(`Skill ${this.name} is already initializing`);
242
- }
243
- const initPromise = this._performInit();
244
- this._initializing = initPromise;
245
- if (!this.lazyInit) {
246
- try {
247
- await initPromise;
248
- } catch (error) {
249
- this._initialized = false;
250
- this._initializing = void 0;
251
- throw error;
252
- }
253
- }
254
- }
255
- isInitialized() {
256
- return this._initialized;
257
- }
258
- async _performInit() {
259
- await this._doInit();
260
- this._initialized = true;
261
- this._initializing = void 0;
262
- }
263
- async getToolDefinitions() {
264
- if (!this.isInitialized() && this._initializing) {
265
- await this._initializing;
266
- }
267
- if (!this.isInitialized()) {
268
- throw new Error(`Skill ${this.name} is not initialized`);
269
- }
270
- return this._filterTools(this._toolDefinitions);
271
- }
272
- _filterTools(tools) {
273
- return tools;
274
- }
275
- };
276
-
277
- // src/skill-manager/command-args.ts
278
- function getCommandArgs(skill) {
279
- const { name, command, packageName, args } = skill;
280
- if (!packageName && (!args || args.length === 0)) {
281
- throw new Error(`Skill ${name} has no packageName or args. Please provide one of them.`);
282
- }
283
- if (packageName && args && args.length > 0) {
284
- throw new Error(`Skill ${name} has both packageName and args. Please provide only one of them.`);
285
- }
286
- let newArgs = args && args.length > 0 ? args : [packageName];
287
- if (command === "npx" && !newArgs.includes("-y")) {
288
- newArgs = ["-y", ...newArgs];
289
- }
290
- return { command, args: newArgs };
271
+ // src/helpers/checkpoint.ts
272
+ function createInitialCheckpoint(checkpointId, params) {
273
+ return {
274
+ id: checkpointId,
275
+ jobId: params.jobId,
276
+ runId: params.runId,
277
+ expert: {
278
+ key: params.expertKey,
279
+ name: params.expert.name,
280
+ version: params.expert.version
281
+ },
282
+ stepNumber: 1,
283
+ status: "init",
284
+ messages: [],
285
+ usage: createEmptyUsage(),
286
+ contextWindow: params.contextWindow,
287
+ contextWindowUsage: params.contextWindow ? 0 : void 0
288
+ };
291
289
  }
292
-
293
- // src/skill-manager/delegate.ts
294
- var DelegateSkillManager = class extends BaseSkillManager {
295
- name;
296
- type = "delegate";
297
- lazyInit = false;
298
- expert;
299
- constructor(expert, jobId, runId, eventListener) {
300
- super(jobId, runId, eventListener);
301
- this.name = expert.name;
302
- this.expert = expert;
303
- }
304
- async _doInit() {
305
- this._toolDefinitions = [
306
- {
307
- skillName: this.expert.name,
308
- name: this.expert.name.split("/").pop() ?? this.expert.name,
309
- description: this.expert.description,
310
- inputSchema: {
311
- type: "object",
312
- properties: {
313
- query: { type: "string" }
314
- },
315
- required: ["query"]
316
- },
317
- interactive: false
318
- }
319
- ];
320
- }
321
- async close() {
322
- }
323
- async callTool(_toolName, _input) {
324
- return [];
325
- }
326
- };
327
-
328
- // src/skill-manager/interactive.ts
329
- var InteractiveSkillManager = class extends BaseSkillManager {
330
- name;
331
- type = "interactive";
332
- lazyInit = false;
333
- interactiveSkill;
334
- constructor(interactiveSkill, jobId, runId, eventListener) {
335
- super(jobId, runId, eventListener);
336
- this.name = interactiveSkill.name;
337
- this.interactiveSkill = interactiveSkill;
338
- }
339
- async _doInit() {
340
- this._toolDefinitions = Object.values(this.interactiveSkill.tools).map((tool2) => ({
341
- skillName: this.interactiveSkill.name,
342
- name: tool2.name,
343
- description: tool2.description,
344
- inputSchema: JSON.parse(tool2.inputJsonSchema),
345
- interactive: true
346
- }));
347
- }
348
- async close() {
349
- }
350
- async callTool(_toolName, _input) {
351
- return [];
352
- }
353
- };
354
-
355
- // src/skill-manager/ip-validator.ts
356
- function isPrivateOrLocalIP(hostname) {
357
- if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "0.0.0.0") {
358
- return true;
359
- }
360
- const ipv4Match = hostname.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
361
- if (ipv4Match) {
362
- const [, a, b] = ipv4Match.map(Number);
363
- if (a === 10) return true;
364
- if (a === 172 && b >= 16 && b <= 31) return true;
365
- if (a === 192 && b === 168) return true;
366
- if (a === 169 && b === 254) return true;
367
- if (a === 127) return true;
368
- }
369
- if (hostname.includes(":")) {
370
- if (hostname.startsWith("fe80:")) return true;
371
- if (hostname.startsWith("fc") || hostname.startsWith("fd")) return true;
372
- }
373
- if (hostname.startsWith("::ffff:")) {
374
- const ipv4Part = hostname.slice(7);
375
- if (isPrivateOrLocalIP(ipv4Part)) {
376
- return true;
377
- }
378
- }
379
- return false;
290
+ function createNextStepCheckpoint(checkpointId, checkpoint) {
291
+ return {
292
+ ...checkpoint,
293
+ id: checkpointId,
294
+ stepNumber: checkpoint.stepNumber + 1
295
+ };
380
296
  }
381
- function handleToolError(error, toolName, McpErrorClass) {
382
- if (error instanceof McpErrorClass) {
383
- return [
384
- {
385
- type: "textPart",
386
- text: `Error calling tool ${toolName}: ${error.message}`,
387
- id: createId()
388
- }
389
- ];
297
+ function buildDelegationReturnState(currentSetting, resultCheckpoint, parentCheckpoint) {
298
+ const { messages, delegatedBy } = resultCheckpoint;
299
+ if (!delegatedBy) {
300
+ throw new Error("delegatedBy is required for buildDelegationReturnState");
390
301
  }
391
- throw error;
392
- }
393
- function convertToolResult(result, toolName, input) {
394
- if (!result.content || result.content.length === 0) {
395
- return [
396
- {
397
- type: "textPart",
398
- text: `Tool ${toolName} returned nothing with arguments: ${JSON.stringify(input)}`,
399
- id: createId()
400
- }
401
- ];
302
+ const delegateResultMessage = messages[messages.length - 1];
303
+ if (!delegateResultMessage || delegateResultMessage.type !== "expertMessage") {
304
+ throw new Error("Delegation error: delegation result message is incorrect");
402
305
  }
403
- return result.content.filter((part) => part.type !== "audio" && part.type !== "resource_link").map((part) => convertPart(part));
404
- }
405
- function convertPart(part) {
406
- switch (part.type) {
407
- case "text":
408
- if (!part.text || part.text === "") {
409
- return { type: "textPart", text: "Error: No content", id: createId() };
410
- }
411
- return { type: "textPart", text: part.text, id: createId() };
412
- case "image":
413
- if (!part.data || !part.mimeType) {
414
- throw new Error("Image part must have both data and mimeType");
415
- }
416
- return {
417
- type: "imageInlinePart",
418
- encodedData: part.data,
419
- mimeType: part.mimeType,
420
- id: createId()
421
- };
422
- case "resource":
423
- if (!part.resource) {
424
- throw new Error("Resource part must have resource content");
425
- }
426
- return convertResource(part.resource);
306
+ const delegateText = delegateResultMessage.contents.find((content) => content.type === "textPart");
307
+ if (!delegateText) {
308
+ console.warn(
309
+ `Delegation result from ${resultCheckpoint.expert.key} has no text content. Parent expert ${delegatedBy.expert.key} will receive empty string.`
310
+ );
427
311
  }
312
+ const { expert, toolCallId, toolName } = delegatedBy;
313
+ return {
314
+ setting: {
315
+ ...currentSetting,
316
+ expertKey: expert.key,
317
+ input: {
318
+ interactiveToolCallResult: {
319
+ toolCallId,
320
+ toolName,
321
+ skillName: `delegate/${resultCheckpoint.expert.key}`,
322
+ text: delegateText?.text ?? ""
323
+ }
324
+ }
325
+ },
326
+ checkpoint: {
327
+ ...parentCheckpoint,
328
+ stepNumber: resultCheckpoint.stepNumber,
329
+ usage: resultCheckpoint.usage,
330
+ pendingToolCalls: parentCheckpoint.pendingToolCalls,
331
+ partialToolResults: parentCheckpoint.partialToolResults
332
+ }
333
+ };
428
334
  }
429
- function convertResource(resource) {
430
- if (!resource.mimeType) {
431
- throw new Error(`Resource ${JSON.stringify(resource)} has no mimeType`);
432
- }
433
- if (resource.text && typeof resource.text === "string") {
434
- return { type: "textPart", text: resource.text, id: createId() };
335
+ async function resolveExpertToRun(expertKey, experts, clientOptions) {
336
+ if (experts[expertKey]) {
337
+ return experts[expertKey];
435
338
  }
436
- if (resource.blob && typeof resource.blob === "string") {
437
- return {
438
- type: "fileInlinePart",
439
- encodedData: resource.blob,
440
- mimeType: resource.mimeType,
441
- id: createId()
442
- };
339
+ const client = createApiClient({
340
+ baseUrl: clientOptions.perstackApiBaseUrl,
341
+ apiKey: clientOptions.perstackApiKey
342
+ });
343
+ const result = await client.registry.experts.get(expertKey);
344
+ if (!result.ok) {
345
+ throw new Error(`Failed to resolve expert "${expertKey}": ${result.error.message}`);
443
346
  }
444
- throw new Error(`Unsupported resource type: ${JSON.stringify(resource)}`);
347
+ return toRuntimeExpert(result.data);
445
348
  }
446
- var DefaultTransportFactory = class {
447
- createStdio(options) {
448
- return new StdioClientTransport({
449
- command: options.command,
450
- args: options.args,
451
- env: options.env,
452
- stderr: options.stderr
453
- });
454
- }
455
- createSse(options) {
456
- return new SSEClientTransport(options.url);
457
- }
458
- };
459
- var defaultTransportFactory = new DefaultTransportFactory();
460
-
461
- // src/skill-manager/mcp.ts
462
- var McpSkillManager = class extends BaseSkillManager {
463
- name;
464
- type = "mcp";
465
- lazyInit;
466
- skill;
467
- _mcpClient;
468
- _env;
469
- _transportFactory;
470
- constructor(skill, env, jobId, runId, eventListener, options) {
471
- super(jobId, runId, eventListener);
472
- this.name = skill.name;
473
- this.skill = skill;
474
- this._env = env;
475
- this._transportFactory = options?.transportFactory ?? defaultTransportFactory;
476
- this.lazyInit = skill.type === "mcpStdioSkill" && skill.lazyInit && skill.name !== "@perstack/base";
477
- }
478
- async _doInit() {
479
- this._mcpClient = new Client({
480
- name: `${this.skill.name}-mcp-client`,
481
- version: "1.0.0"
482
- });
483
- let timingInfo;
484
- if (this.skill.type === "mcpStdioSkill") {
485
- timingInfo = await this._initStdio(this.skill);
486
- } else {
487
- await this._initSse(this.skill);
488
- }
489
- const toolDiscoveryStartTime = Date.now();
490
- const { tools } = await this._mcpClient.listTools();
491
- const toolDiscoveryDurationMs = Date.now() - toolDiscoveryStartTime;
492
- this._toolDefinitions = tools.map((tool2) => ({
493
- skillName: this.skill.name,
494
- name: tool2.name,
495
- description: tool2.description,
496
- inputSchema: tool2.inputSchema,
497
- interactive: false
498
- }));
499
- if (this._eventListener && timingInfo) {
500
- const totalDurationMs = Date.now() - timingInfo.startTime;
501
- const event = createRuntimeEvent("skillConnected", this._jobId, this._runId, {
502
- skillName: this.skill.name,
503
- serverInfo: timingInfo.serverInfo,
504
- spawnDurationMs: timingInfo.spawnDurationMs,
505
- handshakeDurationMs: timingInfo.handshakeDurationMs,
506
- toolDiscoveryDurationMs,
507
- connectDurationMs: timingInfo.spawnDurationMs + timingInfo.handshakeDurationMs,
508
- totalDurationMs
509
- });
510
- this._eventListener(event);
511
- }
512
- }
513
- async _initStdio(skill) {
514
- if (!skill.command) {
515
- throw new Error(`Skill ${skill.name} has no command`);
516
- }
517
- const requiredEnv = {};
518
- for (const envName of skill.requiredEnv) {
519
- if (!this._env[envName]) {
520
- throw new Error(`Skill ${skill.name} requires environment variable ${envName}`);
521
- }
522
- requiredEnv[envName] = this._env[envName];
523
- }
524
- const env = getFilteredEnv(requiredEnv);
525
- const startTime = Date.now();
526
- const { command, args } = getCommandArgs(skill);
527
- if (this._eventListener) {
528
- const event = createRuntimeEvent("skillStarting", this._jobId, this._runId, {
529
- skillName: skill.name,
530
- command,
531
- args
532
- });
533
- this._eventListener(event);
534
- }
535
- const transport = this._transportFactory.createStdio({ command, args, env, stderr: "pipe" });
536
- const spawnDurationMs = Date.now() - startTime;
537
- if (transport.stderr) {
538
- transport.stderr.on("data", (chunk) => {
539
- if (this._eventListener) {
540
- const event = createRuntimeEvent("skillStderr", this._jobId, this._runId, {
541
- skillName: skill.name,
542
- message: chunk.toString().trim()
543
- });
544
- this._eventListener(event);
349
+ function toRuntimeExpert(expert) {
350
+ const skills = Object.fromEntries(
351
+ Object.entries(expert.skills).map(([name, skill]) => {
352
+ switch (skill.type) {
353
+ case "mcpStdioSkill":
354
+ return [name, { ...skill, name }];
355
+ case "mcpSseSkill":
356
+ return [name, { ...skill, name }];
357
+ case "interactiveSkill":
358
+ return [name, { ...skill, name }];
359
+ default: {
360
+ throw new Error(`Unknown skill type: ${skill.type}`);
545
361
  }
546
- });
547
- }
548
- const connectStartTime = Date.now();
549
- await this._mcpClient.connect(transport);
550
- const handshakeDurationMs = Date.now() - connectStartTime;
551
- const serverVersion = this._mcpClient.getServerVersion();
552
- return {
553
- startTime,
554
- spawnDurationMs,
555
- handshakeDurationMs,
556
- serverInfo: serverVersion ? { name: serverVersion.name, version: serverVersion.version } : void 0
557
- };
558
- }
559
- async _initSse(skill) {
560
- if (!skill.endpoint) {
561
- throw new Error(`Skill ${skill.name} has no endpoint`);
562
- }
563
- const url = new URL(skill.endpoint);
564
- if (url.protocol !== "https:") {
565
- throw new Error(`Skill ${skill.name} SSE endpoint must use HTTPS: ${skill.endpoint}`);
566
- }
567
- if (isPrivateOrLocalIP(url.hostname)) {
568
- throw new Error(
569
- `Skill ${skill.name} SSE endpoint cannot use private/local IP: ${skill.endpoint}`
570
- );
571
- }
572
- const transport = this._transportFactory.createSse({ url });
573
- await this._mcpClient.connect(transport);
574
- }
575
- async close() {
576
- if (this._mcpClient) {
577
- await this._mcpClient.close();
578
- if (this._eventListener && this.skill) {
579
- const event = createRuntimeEvent("skillDisconnected", this._jobId, this._runId, {
580
- skillName: this.skill.name
581
- });
582
- this._eventListener(event);
583
362
  }
584
- }
585
- }
586
- _filterTools(tools) {
587
- const omit = this.skill.omit ?? [];
588
- const pick = this.skill.pick ?? [];
589
- return tools.filter((tool2) => omit.length > 0 ? !omit.includes(tool2.name) : true).filter((tool2) => pick.length > 0 ? pick.includes(tool2.name) : true);
590
- }
591
- async callTool(toolName, input) {
592
- if (!this.isInitialized() || !this._mcpClient) {
593
- throw new Error(`${this.name} is not initialized`);
594
- }
595
- try {
596
- const result = await this._mcpClient.callTool({
597
- name: toolName,
598
- arguments: input
599
- });
600
- return convertToolResult(result, toolName, input);
601
- } catch (error) {
602
- return handleToolError(error, toolName, McpError);
603
- }
604
- }
605
- };
606
-
607
- // src/skill-manager/skill-manager-factory.ts
608
- var DefaultSkillManagerFactory = class {
609
- createMcp(skill, context) {
610
- return new McpSkillManager(
611
- skill,
612
- context.env,
613
- context.jobId,
614
- context.runId,
615
- context.eventListener,
616
- context.mcpOptions
617
- );
618
- }
619
- createInteractive(skill, context) {
620
- return new InteractiveSkillManager(skill, context.jobId, context.runId, context.eventListener);
621
- }
622
- createDelegate(expert, context) {
623
- return new DelegateSkillManager(expert, context.jobId, context.runId, context.eventListener);
624
- }
625
- };
626
- var defaultSkillManagerFactory = new DefaultSkillManagerFactory();
363
+ })
364
+ );
365
+ return { ...expert, skills };
366
+ }
627
367
 
628
- // src/skill-manager/helpers.ts
629
- async function initSkillManagersWithCleanup(managers, allManagers) {
630
- const results = await Promise.allSettled(managers.map((m) => m.init()));
631
- const firstRejected = results.find((r) => r.status === "rejected");
632
- if (firstRejected) {
633
- await Promise.all(allManagers.map((m) => m.close().catch(() => {
634
- })));
635
- throw firstRejected.reason;
636
- }
637
- }
638
- async function getSkillManagers(expert, experts, setting, eventListener, options) {
639
- const { perstackBaseSkillCommand, env, jobId, runId } = setting;
640
- const { skills } = expert;
641
- const factory = options?.factory ?? defaultSkillManagerFactory;
642
- if (!skills["@perstack/base"]) {
643
- throw new Error("Base skill is not defined");
644
- }
645
- const factoryContext = {
646
- env,
647
- jobId,
648
- runId,
649
- eventListener
368
+ // src/helpers/setup-experts.ts
369
+ async function setupExperts(setting, resolveExpertToRun2 = resolveExpertToRun) {
370
+ const { expertKey } = setting;
371
+ const experts = { ...setting.experts };
372
+ const clientOptions = {
373
+ perstackApiBaseUrl: setting.perstackApiBaseUrl,
374
+ perstackApiKey: setting.perstackApiKey
650
375
  };
651
- const allManagers = [];
652
- const mcpSkills = Object.values(skills).filter(
653
- (skill) => skill.type === "mcpStdioSkill" || skill.type === "mcpSseSkill"
654
- ).map((skill) => {
655
- if (perstackBaseSkillCommand && skill.type === "mcpStdioSkill") {
656
- const matchesBaseByPackage = skill.command === "npx" && skill.packageName === "@perstack/base";
657
- const matchesBaseByArgs = skill.command === "npx" && Array.isArray(skill.args) && skill.args.includes("@perstack/base");
658
- if (matchesBaseByPackage || matchesBaseByArgs) {
659
- const [overrideCommand, ...overrideArgs] = perstackBaseSkillCommand;
660
- if (!overrideCommand) {
661
- throw new Error("perstackBaseSkillCommand must have at least one element");
662
- }
663
- return {
664
- ...skill,
665
- command: overrideCommand,
666
- packageName: void 0,
667
- args: overrideArgs,
668
- lazyInit: false
669
- };
670
- }
671
- }
672
- return skill;
673
- });
674
- const mcpSkillManagers = mcpSkills.map((skill) => {
675
- const manager = factory.createMcp(skill, factoryContext);
676
- allManagers.push(manager);
677
- return manager;
678
- });
679
- await initSkillManagersWithCleanup(mcpSkillManagers, allManagers);
680
- if (!options?.isDelegatedRun) {
681
- const interactiveSkills = Object.values(skills).filter(
682
- (skill) => skill.type === "interactiveSkill"
683
- );
684
- const interactiveSkillManagers = interactiveSkills.map((interactiveSkill) => {
685
- const manager = factory.createInteractive(interactiveSkill, factoryContext);
686
- allManagers.push(manager);
687
- return manager;
688
- });
689
- await initSkillManagersWithCleanup(interactiveSkillManagers, allManagers);
690
- }
691
- const delegateSkillManagers = [];
692
- for (const delegateExpertName of expert.delegates) {
693
- const delegate = experts[delegateExpertName];
376
+ const expertToRun = await resolveExpertToRun2(expertKey, experts, clientOptions);
377
+ experts[expertKey] = expertToRun;
378
+ for (const delegateName of expertToRun.delegates) {
379
+ const delegate = await resolveExpertToRun2(delegateName, experts, clientOptions);
694
380
  if (!delegate) {
695
- await Promise.all(allManagers.map((m) => m.close().catch(() => {
696
- })));
697
- throw new Error(`Delegate expert "${delegateExpertName}" not found in experts`);
698
- }
699
- const manager = factory.createDelegate(delegate, factoryContext);
700
- allManagers.push(manager);
701
- delegateSkillManagers.push(manager);
702
- }
703
- await initSkillManagersWithCleanup(delegateSkillManagers, allManagers);
704
- const skillManagers = {};
705
- for (const manager of allManagers) {
706
- skillManagers[manager.name] = manager;
707
- }
708
- return skillManagers;
709
- }
710
- async function closeSkillManagers(skillManagers) {
711
- await Promise.all(Object.values(skillManagers).map((m) => m.close().catch(() => {
712
- })));
713
- }
714
- async function getSkillManagerByToolName(skillManagers, toolName) {
715
- for (const skillManager of Object.values(skillManagers)) {
716
- const toolDefinitions = await skillManager.getToolDefinitions();
717
- for (const toolDefinition of toolDefinitions) {
718
- if (toolDefinition.name === toolName) {
719
- return skillManager;
720
- }
381
+ throw new Error(`Delegate ${delegateName} not found`);
721
382
  }
383
+ experts[delegateName] = delegate;
722
384
  }
723
- throw new Error(`Tool ${toolName} not found`);
385
+ return { expertToRun, experts };
724
386
  }
725
- async function getToolSet(skillManagers) {
726
- const tools = {};
727
- for (const skillManager of Object.values(skillManagers)) {
728
- const toolDefinitions = await skillManager.getToolDefinitions();
729
- for (const toolDefinition of toolDefinitions) {
730
- tools[toolDefinition.name] = tool({
731
- description: toolDefinition.description,
732
- inputSchema: jsonSchema(toolDefinition.inputSchema)
733
- });
734
- }
735
- }
736
- return tools;
387
+
388
+ // src/helpers/thinking.ts
389
+ function extractThinkingParts(reasoning) {
390
+ if (!reasoning) return [];
391
+ return reasoning.map((r) => ({
392
+ type: "thinkingPart",
393
+ thinking: r.text,
394
+ // Signature is in providerMetadata for Anthropic (output from API)
395
+ signature: r.providerMetadata?.anthropic?.signature
396
+ }));
397
+ }
398
+ function extractThinkingText(reasoning) {
399
+ if (!reasoning) return "";
400
+ return reasoning.filter((r) => r.text).map((r) => r.text).join("\n");
737
401
  }
738
402
  function isFileInfo(value) {
739
403
  return typeof value === "object" && value !== null && "path" in value && "mimeType" in value && "size" in value && typeof value.path === "string" && typeof value.mimeType === "string" && typeof value.size === "number";
@@ -759,9 +423,9 @@ async function processFileToolResult(toolResult, toolName) {
759
423
  processedContents.push(part);
760
424
  continue;
761
425
  }
762
- const { path, mimeType } = fileInfo;
426
+ const { path: path2, mimeType } = fileInfo;
763
427
  try {
764
- const buffer = await readFile(path);
428
+ const buffer = await readFile(path2);
765
429
  if (toolName === "readImageFile") {
766
430
  processedContents.push({
767
431
  type: "imageInlinePart",
@@ -781,7 +445,7 @@ async function processFileToolResult(toolResult, toolName) {
781
445
  processedContents.push({
782
446
  type: "textPart",
783
447
  id: part.id,
784
- text: `Failed to read file "${path}": ${error instanceof Error ? error.message : String(error)}`
448
+ text: `Failed to read file "${path2}": ${error instanceof Error ? error.message : String(error)}`
785
449
  });
786
450
  }
787
451
  }
@@ -1157,6 +821,8 @@ function expertContentsToCoreContent(contents) {
1157
821
  return textPartToCoreTextPart(part);
1158
822
  case "toolCallPart":
1159
823
  return toolCallPartToCoreToolCallPart(part);
824
+ case "thinkingPart":
825
+ return thinkingPartToCoreThinkingPart(part);
1160
826
  default:
1161
827
  throw new Error(`Unknown expert content type: ${part.type}`);
1162
828
  }
@@ -1228,6 +894,13 @@ function toolCallPartToCoreToolCallPart(part) {
1228
894
  input: part.args
1229
895
  };
1230
896
  }
897
+ function thinkingPartToCoreThinkingPart(part) {
898
+ return {
899
+ type: "reasoning",
900
+ text: part.thinking,
901
+ providerOptions: part.signature ? { anthropic: { signature: part.signature } } : void 0
902
+ };
903
+ }
1231
904
  function toolResultPartToCoreToolResultPart(part) {
1232
905
  const { contents } = part;
1233
906
  if (contents.length === 1 && contents[0].type === "textPart") {
@@ -1256,7 +929,9 @@ function toolResultPartToCoreToolResultPart(part) {
1256
929
  async function generatingRunResultLogic({
1257
930
  setting,
1258
931
  checkpoint,
1259
- step
932
+ step,
933
+ eventListener,
934
+ llmExecutor
1260
935
  }) {
1261
936
  if (!step.toolCalls || !step.toolResults || step.toolResults.length === 0) {
1262
937
  throw new Error("No tool calls or tool results found");
@@ -1273,37 +948,90 @@ async function generatingRunResultLogic({
1273
948
  };
1274
949
  });
1275
950
  const toolMessage = createToolMessage(toolResultParts);
1276
- const model = getModel(setting.model, setting.providerConfig, { proxyUrl: setting.proxyUrl });
1277
951
  const { messages } = checkpoint;
1278
- let generationResult;
1279
- try {
1280
- generationResult = await generateText({
1281
- model,
1282
- messages: [...messages, toolMessage].map(messageToCoreMessage),
1283
- temperature: setting.temperature,
952
+ const coreMessages = [...messages, toolMessage].map(messageToCoreMessage);
953
+ let reasoningCompletedViaCallback = false;
954
+ const callbacks = {
955
+ onReasoningStart: () => {
956
+ eventListener(createRuntimeEvent("startReasoning", setting.jobId, setting.runId, {}));
957
+ },
958
+ onReasoningDelta: (delta) => {
959
+ eventListener(createRuntimeEvent("streamReasoning", setting.jobId, setting.runId, { delta }));
960
+ },
961
+ onReasoningComplete: (text2) => {
962
+ eventListener(createRuntimeEvent("completeReasoning", setting.jobId, setting.runId, { text: text2 }));
963
+ reasoningCompletedViaCallback = true;
964
+ },
965
+ onResultStart: () => {
966
+ eventListener(createRuntimeEvent("startRunResult", setting.jobId, setting.runId, {}));
967
+ },
968
+ onResultDelta: (delta) => {
969
+ eventListener(createRuntimeEvent("streamRunResult", setting.jobId, setting.runId, { delta }));
970
+ }
971
+ };
972
+ const executionResult = await llmExecutor.streamText(
973
+ {
974
+ messages: coreMessages,
1284
975
  maxRetries: setting.maxRetries,
1285
- abortSignal: AbortSignal.timeout(setting.timeout)
1286
- });
1287
- } catch (error) {
1288
- if (error instanceof Error) {
1289
- const reason = JSON.stringify({ error: error.name, message: error.message });
1290
- return retry(setting, checkpoint, {
1291
- reason,
1292
- newMessages: [toolMessage, createUserMessage([{ type: "textPart", text: reason }])],
1293
- usage: createEmptyUsage()
976
+ tools: {},
977
+ // No tools for run result generation
978
+ abortSignal: AbortSignal.timeout(setting.timeout),
979
+ reasoningBudget: setting.reasoningBudget
980
+ },
981
+ callbacks
982
+ );
983
+ if (!executionResult.success) {
984
+ const { error, isRetryable } = executionResult;
985
+ const currentRetryCount = checkpoint.retryCount ?? 0;
986
+ if (!isRetryable || currentRetryCount >= setting.maxRetries) {
987
+ return stopRunByError(setting, checkpoint, {
988
+ checkpoint: {
989
+ ...checkpoint,
990
+ status: "stoppedByError"
991
+ },
992
+ step: {
993
+ ...step,
994
+ finishedAt: Date.now()
995
+ },
996
+ error: {
997
+ name: error.name ?? "Error",
998
+ message: currentRetryCount >= setting.maxRetries ? `Max retries (${setting.maxRetries}) exceeded: ${error.message}` : error.message,
999
+ statusCode: error.statusCode,
1000
+ isRetryable: false
1001
+ }
1294
1002
  });
1295
1003
  }
1296
- throw error;
1004
+ const reason = JSON.stringify({ error: error.name ?? "Error", message: error.message });
1005
+ return retry(setting, checkpoint, {
1006
+ reason,
1007
+ newMessages: [toolMessage, createUserMessage([{ type: "textPart", text: reason }])],
1008
+ usage: createEmptyUsage()
1009
+ });
1297
1010
  }
1011
+ const generationResult = executionResult.result;
1298
1012
  const usage = usageFromGenerateTextResult(generationResult);
1299
- const { text } = generationResult;
1300
- const newMessages = [toolMessage, createExpertMessage(text ? [{ type: "textPart", text }] : [])];
1013
+ const { text, reasoning } = generationResult;
1014
+ const thinkingParts = extractThinkingParts(reasoning);
1015
+ const thinkingText = extractThinkingText(reasoning);
1016
+ const expertContents = [
1017
+ ...thinkingParts,
1018
+ { type: "textPart", text: text ?? "" }
1019
+ ];
1020
+ const newMessages = [toolMessage, createExpertMessage(expertContents)];
1021
+ if (thinkingText && !reasoningCompletedViaCallback) {
1022
+ await eventListener(
1023
+ createRuntimeEvent("completeReasoning", setting.jobId, setting.runId, {
1024
+ text: thinkingText
1025
+ })
1026
+ );
1027
+ }
1028
+ const newUsage = sumUsage(checkpoint.usage, usage);
1301
1029
  return completeRun(setting, checkpoint, {
1302
1030
  checkpoint: {
1303
1031
  ...checkpoint,
1304
1032
  messages: [...messages, ...newMessages],
1305
- usage: sumUsage(checkpoint.usage, usage),
1306
- contextWindowUsage: checkpoint.contextWindow ? calculateContextWindowUsage(usage, checkpoint.contextWindow) : void 0,
1033
+ usage: newUsage,
1034
+ contextWindowUsage: checkpoint.contextWindow ? calculateContextWindowUsage(newUsage, checkpoint.contextWindow) : void 0,
1307
1035
  status: "completed"
1308
1036
  },
1309
1037
  step: {
@@ -1354,38 +1082,121 @@ function buildToolCalls(toolCalls) {
1354
1082
  async function generatingToolCallLogic({
1355
1083
  setting,
1356
1084
  checkpoint,
1357
- skillManagers
1085
+ step,
1086
+ skillManagers,
1087
+ eventListener,
1088
+ llmExecutor
1358
1089
  }) {
1359
1090
  const { messages } = checkpoint;
1360
- const model = getModel(setting.model, setting.providerConfig, { proxyUrl: setting.proxyUrl });
1361
- let result;
1362
- try {
1363
- result = await generateText({
1364
- model,
1365
- messages: messages.map(messageToCoreMessage),
1366
- temperature: setting.temperature,
1367
- maxRetries: setting.maxRetries,
1091
+ let reasoningCompletedViaCallback = false;
1092
+ const callbacks = {
1093
+ onReasoningStart: () => {
1094
+ eventListener(createRuntimeEvent("startReasoning", setting.jobId, setting.runId, {}));
1095
+ },
1096
+ onReasoningDelta: (delta) => {
1097
+ eventListener(createRuntimeEvent("streamReasoning", setting.jobId, setting.runId, { delta }));
1098
+ },
1099
+ onReasoningComplete: (text2) => {
1100
+ eventListener(createRuntimeEvent("completeReasoning", setting.jobId, setting.runId, { text: text2 }));
1101
+ reasoningCompletedViaCallback = true;
1102
+ }
1103
+ // onResultStart and onResultDelta intentionally not set - result streaming only in GeneratingRunResult
1104
+ };
1105
+ const executionResult = await llmExecutor.streamText(
1106
+ {
1107
+ messages: messages.map(messageToCoreMessage),
1108
+ maxRetries: setting.maxRetries,
1368
1109
  tools: await getToolSet(skillManagers),
1369
- toolChoice: "required",
1370
- abortSignal: AbortSignal.timeout(setting.timeout)
1371
- });
1372
- } catch (error) {
1373
- if (error instanceof Error) {
1374
- const reason = JSON.stringify({ error: error.name, message: error.message });
1375
- return retry(setting, checkpoint, {
1376
- reason,
1377
- newMessages: [createUserMessage([{ type: "textPart", text: reason }])],
1378
- usage: createEmptyUsage()
1110
+ toolChoice: "auto",
1111
+ abortSignal: AbortSignal.timeout(setting.timeout),
1112
+ reasoningBudget: setting.reasoningBudget
1113
+ },
1114
+ callbacks
1115
+ );
1116
+ if (!executionResult.success) {
1117
+ const { error, isRetryable } = executionResult;
1118
+ const currentRetryCount = checkpoint.retryCount ?? 0;
1119
+ if (!isRetryable || currentRetryCount >= setting.maxRetries) {
1120
+ return stopRunByError(setting, checkpoint, {
1121
+ checkpoint: {
1122
+ ...checkpoint,
1123
+ status: "stoppedByError"
1124
+ },
1125
+ step: {
1126
+ ...step,
1127
+ finishedAt: Date.now()
1128
+ },
1129
+ error: {
1130
+ name: error.name ?? "Error",
1131
+ message: currentRetryCount >= setting.maxRetries ? `Max retries (${setting.maxRetries}) exceeded: ${error.message}` : error.message,
1132
+ statusCode: error.statusCode,
1133
+ isRetryable: false
1134
+ }
1379
1135
  });
1380
1136
  }
1381
- throw error;
1137
+ const reason = JSON.stringify({ error: error.name ?? "Error", message: error.message });
1138
+ return retry(setting, checkpoint, {
1139
+ reason,
1140
+ newMessages: [createUserMessage([{ type: "textPart", text: reason }])],
1141
+ usage: createEmptyUsage()
1142
+ });
1382
1143
  }
1144
+ const result = executionResult.result;
1383
1145
  const usage = usageFromGenerateTextResult(result);
1384
- const { text, toolCalls, finishReason } = result;
1146
+ const { text, toolCalls, finishReason, reasoning } = result;
1147
+ const thinkingParts = extractThinkingParts(reasoning);
1148
+ const thinkingText = extractThinkingText(reasoning);
1149
+ if (toolCalls.length === 0 && text) {
1150
+ const contents = [...thinkingParts, { type: "textPart", text }];
1151
+ const newMessage = createExpertMessage(contents);
1152
+ const newUsage = sumUsage(checkpoint.usage, usage);
1153
+ if (thinkingText && !reasoningCompletedViaCallback) {
1154
+ await eventListener(
1155
+ createRuntimeEvent("completeReasoning", setting.jobId, setting.runId, {
1156
+ text: thinkingText
1157
+ })
1158
+ );
1159
+ }
1160
+ return completeRun(setting, checkpoint, {
1161
+ checkpoint: {
1162
+ ...checkpoint,
1163
+ messages: [...messages, newMessage],
1164
+ usage: newUsage,
1165
+ contextWindowUsage: checkpoint.contextWindow ? calculateContextWindowUsage(newUsage, checkpoint.contextWindow) : void 0,
1166
+ status: "completed"
1167
+ },
1168
+ step: {
1169
+ ...step,
1170
+ newMessages: [...step.newMessages, newMessage],
1171
+ finishedAt: Date.now(),
1172
+ usage: sumUsage(step.usage, usage)
1173
+ },
1174
+ text,
1175
+ usage
1176
+ });
1177
+ }
1385
1178
  if (toolCalls.length === 0) {
1179
+ const currentRetryCount = checkpoint.retryCount ?? 0;
1180
+ if (currentRetryCount >= setting.maxRetries) {
1181
+ return stopRunByError(setting, checkpoint, {
1182
+ checkpoint: {
1183
+ ...checkpoint,
1184
+ status: "stoppedByError"
1185
+ },
1186
+ step: {
1187
+ ...step,
1188
+ finishedAt: Date.now()
1189
+ },
1190
+ error: {
1191
+ name: "MaxRetriesExceeded",
1192
+ message: `Max retries (${setting.maxRetries}) exceeded: No tool call or text generated`,
1193
+ isRetryable: false
1194
+ }
1195
+ });
1196
+ }
1386
1197
  const reason = JSON.stringify({
1387
- error: "Error: No tool call generated",
1388
- message: "You must generate a tool call. Try again."
1198
+ error: "Error: No tool call or text generated",
1199
+ message: "You must generate a tool call or provide a response. Try again."
1389
1200
  });
1390
1201
  return retry(setting, checkpoint, {
1391
1202
  reason,
@@ -1397,11 +1208,15 @@ async function generatingToolCallLogic({
1397
1208
  const sorted = sortToolCallsByPriority(classified);
1398
1209
  if (finishReason === "tool-calls" || finishReason === "stop") {
1399
1210
  const toolCallParts = buildToolCallParts(sorted);
1400
- const contents = [...toolCallParts];
1401
- if (text) {
1402
- contents.push({ type: "textPart", text });
1403
- }
1211
+ const contents = [...thinkingParts, ...text ? [{ type: "textPart", text }] : [], ...toolCallParts];
1404
1212
  const allToolCalls = buildToolCalls(sorted);
1213
+ if (thinkingText && !reasoningCompletedViaCallback) {
1214
+ await eventListener(
1215
+ createRuntimeEvent("completeReasoning", setting.jobId, setting.runId, {
1216
+ text: thinkingText
1217
+ })
1218
+ );
1219
+ }
1405
1220
  return callTools(setting, checkpoint, {
1406
1221
  newMessage: createExpertMessage(contents),
1407
1222
  toolCalls: allToolCalls,
@@ -1413,6 +1228,24 @@ async function generatingToolCallLogic({
1413
1228
  if (!firstToolCall) {
1414
1229
  throw new Error("No tool call found");
1415
1230
  }
1231
+ const currentRetryCount = checkpoint.retryCount ?? 0;
1232
+ if (currentRetryCount >= setting.maxRetries) {
1233
+ return stopRunByError(setting, checkpoint, {
1234
+ checkpoint: {
1235
+ ...checkpoint,
1236
+ status: "stoppedByError"
1237
+ },
1238
+ step: {
1239
+ ...step,
1240
+ finishedAt: Date.now()
1241
+ },
1242
+ error: {
1243
+ name: "MaxRetriesExceeded",
1244
+ message: `Max retries (${setting.maxRetries}) exceeded: Generation length exceeded`,
1245
+ isRetryable: false
1246
+ }
1247
+ });
1248
+ }
1416
1249
  const reason = JSON.stringify({
1417
1250
  error: "Error: Tool call generation failed",
1418
1251
  message: "Generation length exceeded. Try again."
@@ -1662,11 +1495,6 @@ async function resolvingToolResultLogic({
1662
1495
  });
1663
1496
  }
1664
1497
 
1665
- // src/state-machine/states/resolving-thought.ts
1666
- async function resolvingThoughtLogic(context) {
1667
- return resolvingToolResultLogic(context);
1668
- }
1669
-
1670
1498
  // src/state-machine/machine.ts
1671
1499
  var runtimeStateMachine = setup({
1672
1500
  types: {
@@ -1689,7 +1517,8 @@ var runtimeStateMachine = setup({
1689
1517
  startedAt: Date.now()
1690
1518
  },
1691
1519
  eventListener: input.eventListener,
1692
- skillManagers: input.skillManagers
1520
+ skillManagers: input.skillManagers,
1521
+ llmExecutor: input.llmExecutor
1693
1522
  }),
1694
1523
  states: {
1695
1524
  Init: {
@@ -1768,7 +1597,8 @@ var runtimeStateMachine = setup({
1768
1597
  checkpoint: ({ context, event }) => ({
1769
1598
  ...context.checkpoint,
1770
1599
  messages: [...context.checkpoint.messages, ...event.newMessages],
1771
- usage: sumUsage(context.checkpoint.usage, event.usage)
1600
+ usage: sumUsage(context.checkpoint.usage, event.usage),
1601
+ retryCount: (context.checkpoint.retryCount ?? 0) + 1
1772
1602
  }),
1773
1603
  step: ({ context, event }) => ({
1774
1604
  ...context.step,
@@ -1779,15 +1609,42 @@ var runtimeStateMachine = setup({
1779
1609
  })
1780
1610
  })
1781
1611
  },
1612
+ stopRunByError: {
1613
+ target: "Stopped",
1614
+ actions: assign({
1615
+ checkpoint: ({ event }) => ({
1616
+ ...event.checkpoint,
1617
+ error: event.error
1618
+ }),
1619
+ step: ({ event }) => ({
1620
+ ...event.step,
1621
+ inputMessages: void 0
1622
+ })
1623
+ })
1624
+ },
1625
+ completeRun: {
1626
+ target: "Stopped",
1627
+ actions: assign({
1628
+ checkpoint: ({ event }) => ({ ...event.checkpoint, retryCount: 0 }),
1629
+ step: ({ event }) => ({
1630
+ ...event.step,
1631
+ inputMessages: void 0
1632
+ })
1633
+ })
1634
+ },
1782
1635
  callTools: {
1783
1636
  target: "CallingTool",
1784
1637
  actions: assign({
1785
- checkpoint: ({ context, event }) => ({
1786
- ...context.checkpoint,
1787
- messages: [...context.checkpoint.messages, event.newMessage],
1788
- usage: sumUsage(context.checkpoint.usage, event.usage),
1789
- contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(event.usage, context.checkpoint.contextWindow) : void 0
1790
- }),
1638
+ checkpoint: ({ context, event }) => {
1639
+ const newUsage = sumUsage(context.checkpoint.usage, event.usage);
1640
+ return {
1641
+ ...context.checkpoint,
1642
+ messages: [...context.checkpoint.messages, event.newMessage],
1643
+ usage: newUsage,
1644
+ contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(newUsage, context.checkpoint.contextWindow) : void 0,
1645
+ retryCount: 0
1646
+ };
1647
+ },
1791
1648
  step: ({ context, event }) => ({
1792
1649
  ...context.step,
1793
1650
  newMessages: [event.newMessage],
@@ -1799,12 +1656,17 @@ var runtimeStateMachine = setup({
1799
1656
  callInteractiveTool: {
1800
1657
  target: "CallingInteractiveTool",
1801
1658
  actions: assign({
1802
- checkpoint: ({ context, event }) => ({
1803
- ...context.checkpoint,
1804
- messages: [...context.checkpoint.messages, event.newMessage],
1805
- usage: sumUsage(context.checkpoint.usage, event.usage),
1806
- contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(event.usage, context.checkpoint.contextWindow) : void 0
1807
- }),
1659
+ checkpoint: ({ context, event }) => {
1660
+ const newUsage = sumUsage(context.checkpoint.usage, event.usage);
1661
+ return {
1662
+ ...context.checkpoint,
1663
+ messages: [...context.checkpoint.messages, event.newMessage],
1664
+ usage: newUsage,
1665
+ contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(newUsage, context.checkpoint.contextWindow) : void 0,
1666
+ retryCount: 0
1667
+ // Reset on successful generation
1668
+ };
1669
+ },
1808
1670
  step: ({ context, event }) => ({
1809
1671
  ...context.step,
1810
1672
  newMessages: [event.newMessage],
@@ -1816,12 +1678,17 @@ var runtimeStateMachine = setup({
1816
1678
  callDelegate: {
1817
1679
  target: "CallingDelegate",
1818
1680
  actions: assign({
1819
- checkpoint: ({ context, event }) => ({
1820
- ...context.checkpoint,
1821
- messages: [...context.checkpoint.messages, event.newMessage],
1822
- usage: sumUsage(context.checkpoint.usage, event.usage),
1823
- contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(event.usage, context.checkpoint.contextWindow) : void 0
1824
- }),
1681
+ checkpoint: ({ context, event }) => {
1682
+ const newUsage = sumUsage(context.checkpoint.usage, event.usage);
1683
+ return {
1684
+ ...context.checkpoint,
1685
+ messages: [...context.checkpoint.messages, event.newMessage],
1686
+ usage: newUsage,
1687
+ contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(newUsage, context.checkpoint.contextWindow) : void 0,
1688
+ retryCount: 0
1689
+ // Reset on successful generation
1690
+ };
1691
+ },
1825
1692
  step: ({ context, event }) => ({
1826
1693
  ...context.step,
1827
1694
  newMessages: [event.newMessage],
@@ -1844,15 +1711,6 @@ var runtimeStateMachine = setup({
1844
1711
  })
1845
1712
  })
1846
1713
  },
1847
- resolveThought: {
1848
- target: "ResolvingThought",
1849
- actions: assign({
1850
- step: ({ context, event }) => ({
1851
- ...context.step,
1852
- toolResults: [event.toolResult]
1853
- })
1854
- })
1855
- },
1856
1714
  attemptCompletion: {
1857
1715
  target: "GeneratingRunResult",
1858
1716
  actions: assign({
@@ -1905,23 +1763,6 @@ var runtimeStateMachine = setup({
1905
1763
  }
1906
1764
  }
1907
1765
  },
1908
- ResolvingThought: {
1909
- on: {
1910
- finishToolCall: {
1911
- target: "FinishingStep",
1912
- actions: assign({
1913
- checkpoint: ({ context, event }) => ({
1914
- ...context.checkpoint,
1915
- messages: [...context.checkpoint.messages, ...event.newMessages]
1916
- }),
1917
- step: ({ context, event }) => ({
1918
- ...context.step,
1919
- newMessages: [...context.step.newMessages, ...event.newMessages]
1920
- })
1921
- })
1922
- }
1923
- }
1924
- },
1925
1766
  GeneratingRunResult: {
1926
1767
  on: {
1927
1768
  retry: {
@@ -1930,7 +1771,8 @@ var runtimeStateMachine = setup({
1930
1771
  checkpoint: ({ context, event }) => ({
1931
1772
  ...context.checkpoint,
1932
1773
  messages: [...context.checkpoint.messages, ...event.newMessages],
1933
- usage: sumUsage(context.checkpoint.usage, event.usage)
1774
+ usage: sumUsage(context.checkpoint.usage, event.usage),
1775
+ retryCount: (context.checkpoint.retryCount ?? 0) + 1
1934
1776
  }),
1935
1777
  step: ({ context, event }) => ({
1936
1778
  ...context.step,
@@ -1941,10 +1783,23 @@ var runtimeStateMachine = setup({
1941
1783
  })
1942
1784
  })
1943
1785
  },
1786
+ stopRunByError: {
1787
+ target: "Stopped",
1788
+ actions: assign({
1789
+ checkpoint: ({ event }) => ({
1790
+ ...event.checkpoint,
1791
+ error: event.error
1792
+ }),
1793
+ step: ({ event }) => ({
1794
+ ...event.step,
1795
+ inputMessages: void 0
1796
+ })
1797
+ })
1798
+ },
1944
1799
  completeRun: {
1945
1800
  target: "Stopped",
1946
1801
  actions: assign({
1947
- checkpoint: ({ event }) => event.checkpoint,
1802
+ checkpoint: ({ event }) => ({ ...event.checkpoint, retryCount: 0 }),
1948
1803
  step: ({ event }) => ({
1949
1804
  ...event.step,
1950
1805
  inputMessages: void 0
@@ -2017,7 +1872,6 @@ var StateMachineLogics = {
2017
1872
  GeneratingToolCall: generatingToolCallLogic,
2018
1873
  CallingTool: callingToolLogic,
2019
1874
  ResolvingToolResult: resolvingToolResultLogic,
2020
- ResolvingThought: resolvingThoughtLogic,
2021
1875
  GeneratingRunResult: generatingRunResultLogic,
2022
1876
  CallingInteractiveTool: callingInteractiveToolLogic,
2023
1877
  CallingDelegate: callingDelegateLogic,
@@ -2048,13 +1902,14 @@ var StateMachineCoordinator = class {
2048
1902
  * Execute the state machine and return the final checkpoint.
2049
1903
  */
2050
1904
  async execute() {
2051
- const { setting, initialCheckpoint, eventListener, skillManagers } = this.params;
1905
+ const { setting, initialCheckpoint, eventListener, skillManagers, llmExecutor } = this.params;
2052
1906
  this.actor = this.actorFactory.create({
2053
1907
  input: {
2054
1908
  setting,
2055
1909
  initialCheckpoint,
2056
1910
  eventListener,
2057
- skillManagers
1911
+ skillManagers,
1912
+ llmExecutor
2058
1913
  }
2059
1914
  });
2060
1915
  return new Promise((resolve, reject) => {
@@ -2131,118 +1986,6 @@ async function executeStateMachine(params) {
2131
1986
  const coordinator = new StateMachineCoordinator(params);
2132
1987
  return coordinator.execute();
2133
1988
  }
2134
-
2135
- // src/helpers/checkpoint.ts
2136
- function createInitialCheckpoint(checkpointId, params) {
2137
- return {
2138
- id: checkpointId,
2139
- jobId: params.jobId,
2140
- runId: params.runId,
2141
- expert: {
2142
- key: params.expertKey,
2143
- name: params.expert.name,
2144
- version: params.expert.version
2145
- },
2146
- stepNumber: 1,
2147
- status: "init",
2148
- messages: [],
2149
- usage: createEmptyUsage(),
2150
- contextWindow: params.contextWindow,
2151
- contextWindowUsage: params.contextWindow ? 0 : void 0
2152
- };
2153
- }
2154
- function createNextStepCheckpoint(checkpointId, checkpoint) {
2155
- return {
2156
- ...checkpoint,
2157
- id: checkpointId,
2158
- stepNumber: checkpoint.stepNumber + 1
2159
- };
2160
- }
2161
- function buildDelegationReturnState(currentSetting, resultCheckpoint, parentCheckpoint) {
2162
- const { messages, delegatedBy } = resultCheckpoint;
2163
- if (!delegatedBy) {
2164
- throw new Error("delegatedBy is required for buildDelegationReturnState");
2165
- }
2166
- const delegateResultMessage = messages[messages.length - 1];
2167
- if (!delegateResultMessage || delegateResultMessage.type !== "expertMessage") {
2168
- throw new Error("Delegation error: delegation result message is incorrect");
2169
- }
2170
- const delegateText = delegateResultMessage.contents.find((content) => content.type === "textPart");
2171
- if (!delegateText) {
2172
- throw new Error("Delegation error: delegation result message does not contain a text");
2173
- }
2174
- const { expert, toolCallId, toolName } = delegatedBy;
2175
- return {
2176
- setting: {
2177
- ...currentSetting,
2178
- expertKey: expert.key,
2179
- input: {
2180
- interactiveToolCallResult: {
2181
- toolCallId,
2182
- toolName,
2183
- skillName: `delegate/${resultCheckpoint.expert.key}`,
2184
- text: delegateText.text
2185
- }
2186
- }
2187
- },
2188
- checkpoint: {
2189
- ...parentCheckpoint,
2190
- stepNumber: resultCheckpoint.stepNumber,
2191
- usage: resultCheckpoint.usage,
2192
- pendingToolCalls: parentCheckpoint.pendingToolCalls,
2193
- partialToolResults: parentCheckpoint.partialToolResults
2194
- }
2195
- };
2196
- }
2197
- async function resolveExpertToRun(expertKey, experts, clientOptions) {
2198
- if (experts[expertKey]) {
2199
- return experts[expertKey];
2200
- }
2201
- const client = new ApiV1Client({
2202
- baseUrl: clientOptions.perstackApiBaseUrl,
2203
- apiKey: clientOptions.perstackApiKey
2204
- });
2205
- const { expert } = await client.registry.experts.get({ expertKey });
2206
- return toRuntimeExpert(expert);
2207
- }
2208
- function toRuntimeExpert(expert) {
2209
- const skills = Object.fromEntries(
2210
- Object.entries(expert.skills).map(([name, skill]) => {
2211
- switch (skill.type) {
2212
- case "mcpStdioSkill":
2213
- return [name, { ...skill, name }];
2214
- case "mcpSseSkill":
2215
- return [name, { ...skill, name }];
2216
- case "interactiveSkill":
2217
- return [name, { ...skill, name }];
2218
- default: {
2219
- throw new Error(`Unknown skill type: ${skill.type}`);
2220
- }
2221
- }
2222
- })
2223
- );
2224
- return { ...expert, skills };
2225
- }
2226
-
2227
- // src/helpers/setup-experts.ts
2228
- async function setupExperts(setting, resolveExpertToRun2 = resolveExpertToRun) {
2229
- const { expertKey } = setting;
2230
- const experts = { ...setting.experts };
2231
- const clientOptions = {
2232
- perstackApiBaseUrl: setting.perstackApiBaseUrl,
2233
- perstackApiKey: setting.perstackApiKey
2234
- };
2235
- const expertToRun = await resolveExpertToRun2(expertKey, experts, clientOptions);
2236
- experts[expertKey] = expertToRun;
2237
- for (const delegateName of expertToRun.delegates) {
2238
- const delegate = await resolveExpertToRun2(delegateName, experts, clientOptions);
2239
- if (!delegate) {
2240
- throw new Error(`Delegate ${delegateName} not found`);
2241
- }
2242
- experts[delegateName] = delegate;
2243
- }
2244
- return { expertToRun, experts };
2245
- }
2246
1989
  var SingleDelegationStrategy = class {
2247
1990
  async execute(delegations, setting, context, parentExpert, _runFn, _parentOptions) {
2248
1991
  if (delegations.length !== 1) {
@@ -2409,13 +2152,15 @@ var ParallelDelegationStrategy = class {
2409
2152
  }
2410
2153
  const textPart = lastMessage.contents.find((c) => c.type === "textPart");
2411
2154
  if (!textPart || textPart.type !== "textPart") {
2412
- throw new Error("Delegation error: delegation result message does not contain text");
2155
+ console.warn(
2156
+ `Delegation result from ${expertKey} has no text content. Parent expert will receive empty string.`
2157
+ );
2413
2158
  }
2414
2159
  return {
2415
2160
  toolCallId,
2416
2161
  toolName,
2417
2162
  expertKey,
2418
- text: textPart.text,
2163
+ text: textPart?.type === "textPart" ? textPart.text : "",
2419
2164
  stepNumber: checkpoint.stepNumber,
2420
2165
  deltaUsage: checkpoint.usage
2421
2166
  };
@@ -2468,22 +2213,1298 @@ var RunEventEmitter = class {
2468
2213
  }
2469
2214
  };
2470
2215
 
2471
- // src/orchestration/single-run-executor.ts
2472
- var SingleRunExecutor = class {
2473
- constructor(options = {}) {
2216
+ // src/helpers/provider-adapter-factory.ts
2217
+ var PROVIDER_PACKAGE_NAMES = {
2218
+ anthropic: "anthropic-provider",
2219
+ openai: "openai-provider",
2220
+ google: "google-provider",
2221
+ ollama: "ollama-provider",
2222
+ "azure-openai": "azure-openai-provider",
2223
+ "amazon-bedrock": "bedrock-provider",
2224
+ "google-vertex": "vertex-provider",
2225
+ deepseek: "deepseek-provider"
2226
+ };
2227
+ var ProviderNotInstalledError = class extends Error {
2228
+ constructor(providerName) {
2229
+ const packageName = PROVIDER_PACKAGE_NAMES[providerName];
2230
+ super(
2231
+ `Provider "${providerName}" is not installed. Run: npm install @perstack/${packageName}`
2232
+ );
2233
+ this.name = "ProviderNotInstalledError";
2234
+ }
2235
+ };
2236
+ var adapterRegistry = /* @__PURE__ */ new Map();
2237
+ var adapterInstances = /* @__PURE__ */ new Map();
2238
+ var pendingCreations = /* @__PURE__ */ new Map();
2239
+ function getCacheKey(config, options) {
2240
+ return JSON.stringify({
2241
+ providerName: config.providerName,
2242
+ apiKey: "apiKey" in config ? config.apiKey : void 0,
2243
+ baseUrl: "baseUrl" in config ? config.baseUrl : void 0,
2244
+ proxyUrl: options?.proxyUrl
2245
+ });
2246
+ }
2247
+ function registerProviderAdapter(providerName, loader) {
2248
+ adapterRegistry.set(providerName, loader);
2249
+ }
2250
+ async function createProviderAdapter(config, options) {
2251
+ const cacheKey = getCacheKey(config, options);
2252
+ const cached = adapterInstances.get(cacheKey);
2253
+ if (cached) return cached;
2254
+ const pending = pendingCreations.get(cacheKey);
2255
+ if (pending) return pending;
2256
+ const loader = adapterRegistry.get(config.providerName);
2257
+ if (!loader) {
2258
+ throw new ProviderNotInstalledError(config.providerName);
2259
+ }
2260
+ const creationPromise = (async () => {
2261
+ try {
2262
+ const AdapterClass = await loader();
2263
+ const adapter = new AdapterClass(config, options);
2264
+ adapterInstances.set(cacheKey, adapter);
2265
+ return adapter;
2266
+ } finally {
2267
+ pendingCreations.delete(cacheKey);
2268
+ }
2269
+ })();
2270
+ pendingCreations.set(cacheKey, creationPromise);
2271
+ return creationPromise;
2272
+ }
2273
+ var BaseProviderAdapter = class {
2274
+ options;
2275
+ constructor(options) {
2474
2276
  this.options = options;
2475
2277
  }
2476
- async execute(setting, checkpoint) {
2477
- const contextWindow = getContextWindow(setting.providerConfig.providerName, setting.model);
2478
- const { expertToRun, experts } = await setupExperts(setting, this.options.resolveExpertToRun);
2479
- this.emitInitEvent(setting, expertToRun, experts);
2480
- const skillManagers = await getSkillManagers(
2481
- expertToRun,
2482
- experts,
2483
- setting,
2484
- this.options.eventListener,
2485
- { isDelegatedRun: !!checkpoint?.delegatedBy }
2486
- );
2278
+ getProviderTools(_toolNames, _options) {
2279
+ return {};
2280
+ }
2281
+ getProviderOptions(_config) {
2282
+ return void 0;
2283
+ }
2284
+ getReasoningOptions(_budget) {
2285
+ return void 0;
2286
+ }
2287
+ normalizeError(error) {
2288
+ if (error instanceof Error) {
2289
+ return {
2290
+ name: error.name,
2291
+ message: error.message,
2292
+ isRetryable: this.isRetryable(error),
2293
+ provider: this.providerName,
2294
+ originalError: error
2295
+ };
2296
+ }
2297
+ return {
2298
+ name: "UnknownError",
2299
+ message: String(error),
2300
+ isRetryable: false,
2301
+ provider: this.providerName,
2302
+ originalError: error
2303
+ };
2304
+ }
2305
+ isRetryable(error) {
2306
+ if (error instanceof Error) {
2307
+ const retryablePatterns = [
2308
+ /rate limit/i,
2309
+ /timeout/i,
2310
+ /overloaded/i,
2311
+ /service unavailable/i,
2312
+ /internal server error/i,
2313
+ /bad gateway/i,
2314
+ /gateway timeout/i
2315
+ ];
2316
+ return retryablePatterns.some((pattern) => pattern.test(error.message));
2317
+ }
2318
+ return false;
2319
+ }
2320
+ createProxyFetch(proxyUrl) {
2321
+ const agent = new ProxyAgent(proxyUrl);
2322
+ return (input, init) => {
2323
+ return fetch(input, { ...init, dispatcher: agent });
2324
+ };
2325
+ }
2326
+ };
2327
+ function normalizeAnthropicError(error) {
2328
+ if (error instanceof APICallError) {
2329
+ return {
2330
+ name: error.name,
2331
+ message: error.message,
2332
+ statusCode: error.statusCode,
2333
+ isRetryable: isAnthropicRetryable(error),
2334
+ provider: "anthropic",
2335
+ originalError: error
2336
+ };
2337
+ }
2338
+ if (error instanceof Error) {
2339
+ return {
2340
+ name: error.name,
2341
+ message: error.message,
2342
+ isRetryable: isAnthropicRetryable(error),
2343
+ provider: "anthropic",
2344
+ originalError: error
2345
+ };
2346
+ }
2347
+ return {
2348
+ name: "UnknownError",
2349
+ message: String(error),
2350
+ isRetryable: false,
2351
+ provider: "anthropic",
2352
+ originalError: error
2353
+ };
2354
+ }
2355
+ function isAnthropicRetryable(error) {
2356
+ if (error instanceof APICallError) {
2357
+ if (error.isRetryable) return true;
2358
+ const statusCode = error.statusCode;
2359
+ if (statusCode === 429) return true;
2360
+ if (statusCode === 500) return true;
2361
+ if (statusCode === 502) return true;
2362
+ if (statusCode === 503) return true;
2363
+ if (statusCode === 504) return true;
2364
+ }
2365
+ if (error instanceof Error) {
2366
+ const message = error.message.toLowerCase();
2367
+ if (message.includes("rate limit")) return true;
2368
+ if (message.includes("overloaded")) return true;
2369
+ if (message.includes("timeout")) return true;
2370
+ if (message.includes("service unavailable")) return true;
2371
+ }
2372
+ return false;
2373
+ }
2374
+
2375
+ // ../../packages/providers/anthropic/src/skills.ts
2376
+ function convertSkill(skill) {
2377
+ if (skill.type === "builtin") {
2378
+ return {
2379
+ type: "builtin",
2380
+ name: skill.skillId
2381
+ };
2382
+ }
2383
+ try {
2384
+ return {
2385
+ type: "custom",
2386
+ name: skill.name,
2387
+ mcp_config: JSON.parse(skill.definition)
2388
+ };
2389
+ } catch (error) {
2390
+ throw new Error(
2391
+ `Invalid JSON in custom skill definition for "${skill.name}": ${error instanceof Error ? error.message : String(error)}`
2392
+ );
2393
+ }
2394
+ }
2395
+ function buildProviderOptions(skills) {
2396
+ if (!skills || skills.length === 0) {
2397
+ return void 0;
2398
+ }
2399
+ return {
2400
+ anthropic: {
2401
+ container: {
2402
+ skills: skills.map(convertSkill)
2403
+ }
2404
+ }
2405
+ };
2406
+ }
2407
+
2408
+ // ../../packages/providers/anthropic/src/tools.ts
2409
+ function buildAnthropicTools(client, toolNames, options) {
2410
+ const tools = {};
2411
+ for (const name of toolNames) {
2412
+ switch (name) {
2413
+ case "webSearch": {
2414
+ const webSearchTool = client.tools.webSearch_20250305({
2415
+ maxUses: options?.webSearch?.maxUses,
2416
+ allowedDomains: options?.webSearch?.allowedDomains
2417
+ });
2418
+ tools["web_search"] = webSearchTool;
2419
+ break;
2420
+ }
2421
+ case "webFetch": {
2422
+ const webFetchTool = client.tools.webFetch_20250910({
2423
+ maxUses: options?.webFetch?.maxUses
2424
+ });
2425
+ tools["web_fetch"] = webFetchTool;
2426
+ break;
2427
+ }
2428
+ case "codeExecution": {
2429
+ const codeExecutionTool = client.tools.codeExecution_20250522();
2430
+ tools["code_execution"] = codeExecutionTool;
2431
+ break;
2432
+ }
2433
+ }
2434
+ }
2435
+ return tools;
2436
+ }
2437
+
2438
+ // ../../packages/providers/anthropic/src/adapter.ts
2439
+ var AnthropicProviderAdapter = class extends BaseProviderAdapter {
2440
+ constructor(config, options) {
2441
+ super(options);
2442
+ this.config = config;
2443
+ this.client = createAnthropic({
2444
+ apiKey: config.apiKey,
2445
+ baseURL: config.baseUrl,
2446
+ headers: config.headers,
2447
+ fetch: options?.proxyUrl ? this.createProxyFetch(options.proxyUrl) : void 0
2448
+ });
2449
+ }
2450
+ providerName = "anthropic";
2451
+ client;
2452
+ createModel(modelId) {
2453
+ return this.client(modelId);
2454
+ }
2455
+ getProviderTools(toolNames, options) {
2456
+ return buildAnthropicTools(this.client, toolNames, options);
2457
+ }
2458
+ getProviderOptions(config) {
2459
+ return buildProviderOptions(config?.skills);
2460
+ }
2461
+ getReasoningOptions(budget) {
2462
+ const budgetTokens = this.budgetToTokens(budget);
2463
+ return {
2464
+ anthropic: {
2465
+ thinking: { type: "enabled", budgetTokens }
2466
+ }
2467
+ };
2468
+ }
2469
+ budgetToTokens(budget) {
2470
+ if (typeof budget === "number") return budget;
2471
+ const map = {
2472
+ minimal: 1024,
2473
+ low: 2048,
2474
+ medium: 5e3,
2475
+ high: 1e4
2476
+ };
2477
+ return map[budget] ?? 5e3;
2478
+ }
2479
+ normalizeError(error) {
2480
+ return normalizeAnthropicError(error);
2481
+ }
2482
+ isRetryable(error) {
2483
+ return isAnthropicRetryable(error);
2484
+ }
2485
+ };
2486
+ function normalizeAzureOpenAIError(error) {
2487
+ if (error instanceof APICallError) {
2488
+ return {
2489
+ name: error.name,
2490
+ message: error.message,
2491
+ statusCode: error.statusCode,
2492
+ isRetryable: isAzureOpenAIRetryable(error),
2493
+ provider: "azure-openai",
2494
+ originalError: error
2495
+ };
2496
+ }
2497
+ if (error instanceof Error) {
2498
+ return {
2499
+ name: error.name,
2500
+ message: error.message,
2501
+ isRetryable: isAzureOpenAIRetryable(error),
2502
+ provider: "azure-openai",
2503
+ originalError: error
2504
+ };
2505
+ }
2506
+ return {
2507
+ name: "UnknownError",
2508
+ message: String(error),
2509
+ isRetryable: false,
2510
+ provider: "azure-openai",
2511
+ originalError: error
2512
+ };
2513
+ }
2514
+ function isAzureOpenAIRetryable(error) {
2515
+ if (error instanceof APICallError) {
2516
+ if (error.isRetryable) return true;
2517
+ const statusCode = error.statusCode;
2518
+ if (statusCode === 429) return true;
2519
+ if (statusCode === 500) return true;
2520
+ if (statusCode === 502) return true;
2521
+ if (statusCode === 503) return true;
2522
+ if (statusCode === 504) return true;
2523
+ }
2524
+ if (error instanceof Error) {
2525
+ const message = error.message.toLowerCase();
2526
+ if (message.includes("rate limit")) return true;
2527
+ if (message.includes("timeout")) return true;
2528
+ if (message.includes("service unavailable")) return true;
2529
+ }
2530
+ return false;
2531
+ }
2532
+
2533
+ // ../../packages/providers/azure-openai/src/tools.ts
2534
+ function buildAzureOpenAITools(client, toolNames, options) {
2535
+ const tools = {};
2536
+ for (const name of toolNames) {
2537
+ switch (name) {
2538
+ case "webSearchPreview": {
2539
+ const webSearchTool = client.tools.webSearchPreview({});
2540
+ tools["web_search_preview"] = webSearchTool;
2541
+ break;
2542
+ }
2543
+ case "fileSearch": {
2544
+ const vectorStoreIds = options?.fileSearch?.vectorStoreIds;
2545
+ if (!vectorStoreIds || vectorStoreIds.length === 0) {
2546
+ console.warn(
2547
+ "Azure OpenAI fileSearch tool requires vectorStoreIds. Set providerToolOptions.fileSearch.vectorStoreIds to use this tool."
2548
+ );
2549
+ break;
2550
+ }
2551
+ const fileSearchTool = client.tools.fileSearch({
2552
+ vectorStoreIds,
2553
+ maxNumResults: options?.fileSearch?.maxNumResults
2554
+ });
2555
+ tools["file_search"] = fileSearchTool;
2556
+ break;
2557
+ }
2558
+ case "codeInterpreter": {
2559
+ const codeInterpreterTool = client.tools.codeInterpreter();
2560
+ tools["code_interpreter"] = codeInterpreterTool;
2561
+ break;
2562
+ }
2563
+ case "imageGeneration": {
2564
+ const imageGenerationTool = client.tools.imageGeneration();
2565
+ tools["image_generation"] = imageGenerationTool;
2566
+ break;
2567
+ }
2568
+ }
2569
+ }
2570
+ return tools;
2571
+ }
2572
+
2573
+ // ../../packages/providers/azure-openai/src/adapter.ts
2574
+ var AzureOpenAIProviderAdapter = class extends BaseProviderAdapter {
2575
+ constructor(config, options) {
2576
+ super(options);
2577
+ this.config = config;
2578
+ this.client = createAzure({
2579
+ apiKey: config.apiKey,
2580
+ resourceName: config.resourceName,
2581
+ apiVersion: config.apiVersion,
2582
+ baseURL: config.baseUrl,
2583
+ headers: config.headers,
2584
+ useDeploymentBasedUrls: config.useDeploymentBasedUrls,
2585
+ fetch: options?.proxyUrl ? this.createProxyFetch(options.proxyUrl) : void 0
2586
+ });
2587
+ }
2588
+ providerName = "azure-openai";
2589
+ client;
2590
+ createModel(modelId) {
2591
+ return this.client(modelId);
2592
+ }
2593
+ getProviderTools(toolNames, options) {
2594
+ return buildAzureOpenAITools(this.client, toolNames, options);
2595
+ }
2596
+ normalizeError(error) {
2597
+ return normalizeAzureOpenAIError(error);
2598
+ }
2599
+ isRetryable(error) {
2600
+ return isAzureOpenAIRetryable(error);
2601
+ }
2602
+ };
2603
+ function normalizeBedrockError(error) {
2604
+ if (error instanceof APICallError) {
2605
+ return {
2606
+ name: error.name,
2607
+ message: error.message,
2608
+ statusCode: error.statusCode,
2609
+ isRetryable: isBedrockRetryable(error),
2610
+ provider: "amazon-bedrock",
2611
+ originalError: error
2612
+ };
2613
+ }
2614
+ if (error instanceof Error) {
2615
+ return {
2616
+ name: error.name,
2617
+ message: error.message,
2618
+ isRetryable: isBedrockRetryable(error),
2619
+ provider: "amazon-bedrock",
2620
+ originalError: error
2621
+ };
2622
+ }
2623
+ return {
2624
+ name: "UnknownError",
2625
+ message: String(error),
2626
+ isRetryable: false,
2627
+ provider: "amazon-bedrock",
2628
+ originalError: error
2629
+ };
2630
+ }
2631
+ function isBedrockRetryable(error) {
2632
+ if (error instanceof APICallError) {
2633
+ if (error.isRetryable) return true;
2634
+ const statusCode = error.statusCode;
2635
+ if (statusCode === 429) return true;
2636
+ if (statusCode === 500) return true;
2637
+ if (statusCode === 502) return true;
2638
+ if (statusCode === 503) return true;
2639
+ if (statusCode === 504) return true;
2640
+ }
2641
+ if (error instanceof Error) {
2642
+ const message = error.message.toLowerCase();
2643
+ if (message.includes("rate limit")) return true;
2644
+ if (message.includes("throttl")) return true;
2645
+ if (message.includes("timeout")) return true;
2646
+ if (message.includes("service unavailable")) return true;
2647
+ }
2648
+ return false;
2649
+ }
2650
+
2651
+ // ../../packages/providers/bedrock/src/adapter.ts
2652
+ var BedrockProviderAdapter = class extends BaseProviderAdapter {
2653
+ constructor(config, options) {
2654
+ super(options);
2655
+ this.config = config;
2656
+ this.client = createAmazonBedrock({
2657
+ accessKeyId: config.accessKeyId,
2658
+ secretAccessKey: config.secretAccessKey,
2659
+ region: config.region,
2660
+ sessionToken: config.sessionToken,
2661
+ fetch: options?.proxyUrl ? this.createProxyFetch(options.proxyUrl) : void 0
2662
+ });
2663
+ }
2664
+ providerName = "amazon-bedrock";
2665
+ client;
2666
+ createModel(modelId) {
2667
+ return this.client(modelId);
2668
+ }
2669
+ getProviderOptions(config) {
2670
+ if (!config?.guardrails && !config?.cachePoint) {
2671
+ return void 0;
2672
+ }
2673
+ const bedrockOptions = {};
2674
+ if (config.guardrails) {
2675
+ const guardrailConfig = {
2676
+ guardrailIdentifier: config.guardrails.guardrailIdentifier,
2677
+ guardrailVersion: config.guardrails.guardrailVersion
2678
+ };
2679
+ if (config.guardrails.trace) {
2680
+ guardrailConfig["trace"] = config.guardrails.trace;
2681
+ }
2682
+ bedrockOptions["guardrailConfig"] = guardrailConfig;
2683
+ }
2684
+ if (config.cachePoint) {
2685
+ bedrockOptions["cachePoint"] = { type: config.cachePoint.type };
2686
+ }
2687
+ return { bedrock: bedrockOptions };
2688
+ }
2689
+ getReasoningOptions(budget) {
2690
+ if (budget === "none" || budget === 0) {
2691
+ return void 0;
2692
+ }
2693
+ const budgetTokens = this.budgetToTokens(budget);
2694
+ return {
2695
+ bedrock: {
2696
+ reasoning: {
2697
+ budgetTokens
2698
+ }
2699
+ }
2700
+ };
2701
+ }
2702
+ budgetToTokens(budget) {
2703
+ if (typeof budget === "number") return budget;
2704
+ const map = {
2705
+ minimal: 1024,
2706
+ low: 2048,
2707
+ medium: 5e3,
2708
+ high: 1e4
2709
+ };
2710
+ return map[budget] ?? 5e3;
2711
+ }
2712
+ normalizeError(error) {
2713
+ return normalizeBedrockError(error);
2714
+ }
2715
+ isRetryable(error) {
2716
+ return isBedrockRetryable(error);
2717
+ }
2718
+ };
2719
+ function normalizeDeepSeekError(error) {
2720
+ if (error instanceof APICallError) {
2721
+ return {
2722
+ name: error.name,
2723
+ message: error.message,
2724
+ statusCode: error.statusCode,
2725
+ isRetryable: isDeepSeekRetryable(error),
2726
+ provider: "deepseek",
2727
+ originalError: error
2728
+ };
2729
+ }
2730
+ if (error instanceof Error) {
2731
+ return {
2732
+ name: error.name,
2733
+ message: error.message,
2734
+ isRetryable: isDeepSeekRetryable(error),
2735
+ provider: "deepseek",
2736
+ originalError: error
2737
+ };
2738
+ }
2739
+ return {
2740
+ name: "UnknownError",
2741
+ message: String(error),
2742
+ isRetryable: false,
2743
+ provider: "deepseek",
2744
+ originalError: error
2745
+ };
2746
+ }
2747
+ function isDeepSeekRetryable(error) {
2748
+ if (error instanceof APICallError) {
2749
+ if (error.isRetryable) return true;
2750
+ const statusCode = error.statusCode;
2751
+ if (statusCode === 429) return true;
2752
+ if (statusCode === 500) return true;
2753
+ if (statusCode === 502) return true;
2754
+ if (statusCode === 503) return true;
2755
+ if (statusCode === 504) return true;
2756
+ }
2757
+ if (error instanceof Error) {
2758
+ const message = error.message.toLowerCase();
2759
+ if (message.includes("rate limit")) return true;
2760
+ if (message.includes("timeout")) return true;
2761
+ if (message.includes("service unavailable")) return true;
2762
+ }
2763
+ return false;
2764
+ }
2765
+
2766
+ // ../../packages/providers/deepseek/src/adapter.ts
2767
+ var DeepseekProviderAdapter = class extends BaseProviderAdapter {
2768
+ constructor(config, options) {
2769
+ super(options);
2770
+ this.config = config;
2771
+ this.client = createDeepSeek({
2772
+ apiKey: config.apiKey,
2773
+ baseURL: config.baseUrl,
2774
+ headers: config.headers,
2775
+ fetch: options?.proxyUrl ? this.createProxyFetch(options.proxyUrl) : void 0
2776
+ });
2777
+ }
2778
+ providerName = "deepseek";
2779
+ client;
2780
+ createModel(modelId) {
2781
+ return this.client(modelId);
2782
+ }
2783
+ normalizeError(error) {
2784
+ return normalizeDeepSeekError(error);
2785
+ }
2786
+ isRetryable(error) {
2787
+ return isDeepSeekRetryable(error);
2788
+ }
2789
+ };
2790
+ function normalizeGoogleError(error) {
2791
+ if (error instanceof APICallError) {
2792
+ return {
2793
+ name: error.name,
2794
+ message: error.message,
2795
+ statusCode: error.statusCode,
2796
+ isRetryable: isGoogleRetryable(error),
2797
+ provider: "google",
2798
+ originalError: error
2799
+ };
2800
+ }
2801
+ if (error instanceof Error) {
2802
+ return {
2803
+ name: error.name,
2804
+ message: error.message,
2805
+ isRetryable: isGoogleRetryable(error),
2806
+ provider: "google",
2807
+ originalError: error
2808
+ };
2809
+ }
2810
+ return {
2811
+ name: "UnknownError",
2812
+ message: String(error),
2813
+ isRetryable: false,
2814
+ provider: "google",
2815
+ originalError: error
2816
+ };
2817
+ }
2818
+ function isGoogleRetryable(error) {
2819
+ if (error instanceof APICallError) {
2820
+ if (error.isRetryable) return true;
2821
+ const statusCode = error.statusCode;
2822
+ if (statusCode === 429) return true;
2823
+ if (statusCode === 500) return true;
2824
+ if (statusCode === 502) return true;
2825
+ if (statusCode === 503) return true;
2826
+ if (statusCode === 504) return true;
2827
+ }
2828
+ if (error instanceof Error) {
2829
+ const message = error.message.toLowerCase();
2830
+ if (message.includes("rate limit")) return true;
2831
+ if (message.includes("quota exceeded")) return true;
2832
+ if (message.includes("timeout")) return true;
2833
+ if (message.includes("service unavailable")) return true;
2834
+ }
2835
+ return false;
2836
+ }
2837
+
2838
+ // ../../packages/providers/google/src/tools.ts
2839
+ function buildGoogleTools(client, toolNames, options) {
2840
+ const tools = {};
2841
+ for (const name of toolNames) {
2842
+ switch (name) {
2843
+ case "googleSearch": {
2844
+ const googleSearchTool = client.tools.googleSearch({});
2845
+ tools["google_search"] = googleSearchTool;
2846
+ break;
2847
+ }
2848
+ case "codeExecution": {
2849
+ const codeExecutionTool = client.tools.codeExecution({});
2850
+ tools["code_execution"] = codeExecutionTool;
2851
+ break;
2852
+ }
2853
+ case "urlContext": {
2854
+ const urlContextTool = client.tools.urlContext({});
2855
+ tools["url_context"] = urlContextTool;
2856
+ break;
2857
+ }
2858
+ case "fileSearch": {
2859
+ const storeNames = options?.fileSearch?.vectorStoreIds;
2860
+ if (!storeNames || storeNames.length === 0) {
2861
+ console.warn(
2862
+ "Google fileSearch tool requires fileSearchStoreNames. Set providerToolOptions.fileSearch.vectorStoreIds to use this tool."
2863
+ );
2864
+ break;
2865
+ }
2866
+ const fileSearchTool = client.tools.fileSearch({
2867
+ fileSearchStoreNames: storeNames,
2868
+ topK: options?.fileSearch?.maxNumResults
2869
+ });
2870
+ tools["file_search"] = fileSearchTool;
2871
+ break;
2872
+ }
2873
+ case "googleMaps": {
2874
+ const googleMapsTool = client.tools.googleMaps(options?.googleMaps?.retrievalConfig ?? {});
2875
+ tools["google_maps"] = googleMapsTool;
2876
+ break;
2877
+ }
2878
+ }
2879
+ }
2880
+ return tools;
2881
+ }
2882
+
2883
+ // ../../packages/providers/google/src/adapter.ts
2884
+ var GoogleProviderAdapter = class extends BaseProviderAdapter {
2885
+ constructor(config, options) {
2886
+ super(options);
2887
+ this.config = config;
2888
+ this.client = createGoogleGenerativeAI({
2889
+ apiKey: config.apiKey,
2890
+ baseURL: config.baseUrl,
2891
+ headers: config.headers,
2892
+ fetch: options?.proxyUrl ? this.createProxyFetch(options.proxyUrl) : void 0
2893
+ });
2894
+ }
2895
+ providerName = "google";
2896
+ client;
2897
+ createModel(modelId) {
2898
+ return this.client(modelId);
2899
+ }
2900
+ getProviderTools(toolNames, options) {
2901
+ return buildGoogleTools(this.client, toolNames, options);
2902
+ }
2903
+ normalizeError(error) {
2904
+ return normalizeGoogleError(error);
2905
+ }
2906
+ isRetryable(error) {
2907
+ return isGoogleRetryable(error);
2908
+ }
2909
+ getReasoningOptions(budget) {
2910
+ const budgetTokens = this.budgetToTokens(budget);
2911
+ return {
2912
+ google: {
2913
+ thinkingConfig: {
2914
+ thinkingBudget: budgetTokens,
2915
+ includeThoughts: true
2916
+ }
2917
+ }
2918
+ };
2919
+ }
2920
+ budgetToTokens(budget) {
2921
+ if (typeof budget === "number") return budget;
2922
+ const map = {
2923
+ minimal: 1024,
2924
+ low: 2048,
2925
+ medium: 5e3,
2926
+ high: 1e4
2927
+ };
2928
+ return map[budget] ?? 5e3;
2929
+ }
2930
+ };
2931
+ function normalizeOllamaError(error) {
2932
+ if (error instanceof APICallError) {
2933
+ return {
2934
+ name: error.name,
2935
+ message: error.message,
2936
+ statusCode: error.statusCode,
2937
+ isRetryable: isOllamaRetryable(error),
2938
+ provider: "ollama",
2939
+ originalError: error
2940
+ };
2941
+ }
2942
+ if (error instanceof Error) {
2943
+ return {
2944
+ name: error.name,
2945
+ message: error.message,
2946
+ isRetryable: isOllamaRetryable(error),
2947
+ provider: "ollama",
2948
+ originalError: error
2949
+ };
2950
+ }
2951
+ return {
2952
+ name: "UnknownError",
2953
+ message: String(error),
2954
+ isRetryable: false,
2955
+ provider: "ollama",
2956
+ originalError: error
2957
+ };
2958
+ }
2959
+ function isOllamaRetryable(error) {
2960
+ if (error instanceof APICallError) {
2961
+ if (error.isRetryable) return true;
2962
+ const statusCode = error.statusCode;
2963
+ if (statusCode === 429) return true;
2964
+ if (statusCode === 500) return true;
2965
+ if (statusCode === 502) return true;
2966
+ if (statusCode === 503) return true;
2967
+ if (statusCode === 504) return true;
2968
+ }
2969
+ if (error instanceof Error) {
2970
+ const message = error.message.toLowerCase();
2971
+ if (message.includes("rate limit")) return true;
2972
+ if (message.includes("timeout")) return true;
2973
+ if (message.includes("service unavailable")) return true;
2974
+ if (message.includes("connection refused")) return true;
2975
+ }
2976
+ return false;
2977
+ }
2978
+
2979
+ // ../../packages/providers/ollama/src/adapter.ts
2980
+ var OllamaProviderAdapter = class extends BaseProviderAdapter {
2981
+ constructor(config, options) {
2982
+ super(options);
2983
+ this.config = config;
2984
+ this.client = createOllama({
2985
+ baseURL: config.baseUrl,
2986
+ headers: config.headers,
2987
+ fetch: options?.proxyUrl ? this.createProxyFetch(options.proxyUrl) : void 0
2988
+ });
2989
+ }
2990
+ providerName = "ollama";
2991
+ client;
2992
+ createModel(modelId) {
2993
+ return this.client(modelId);
2994
+ }
2995
+ getProviderOptions(config) {
2996
+ if (config?.think === void 0) {
2997
+ return void 0;
2998
+ }
2999
+ return {
3000
+ ollama: {
3001
+ think: config.think
3002
+ }
3003
+ };
3004
+ }
3005
+ getReasoningOptions(budget) {
3006
+ if (budget === "none" || budget === 0) {
3007
+ return void 0;
3008
+ }
3009
+ return {
3010
+ ollama: {
3011
+ think: true
3012
+ }
3013
+ };
3014
+ }
3015
+ normalizeError(error) {
3016
+ return normalizeOllamaError(error);
3017
+ }
3018
+ isRetryable(error) {
3019
+ return isOllamaRetryable(error);
3020
+ }
3021
+ };
3022
+ function normalizeOpenAIError(error) {
3023
+ if (error instanceof APICallError) {
3024
+ return {
3025
+ name: error.name,
3026
+ message: error.message,
3027
+ statusCode: error.statusCode,
3028
+ isRetryable: isOpenAIRetryable(error),
3029
+ provider: "openai",
3030
+ originalError: error
3031
+ };
3032
+ }
3033
+ if (error instanceof Error) {
3034
+ return {
3035
+ name: error.name,
3036
+ message: error.message,
3037
+ isRetryable: isOpenAIRetryable(error),
3038
+ provider: "openai",
3039
+ originalError: error
3040
+ };
3041
+ }
3042
+ return {
3043
+ name: "UnknownError",
3044
+ message: String(error),
3045
+ isRetryable: false,
3046
+ provider: "openai",
3047
+ originalError: error
3048
+ };
3049
+ }
3050
+ function isOpenAIRetryable(error) {
3051
+ if (error instanceof APICallError) {
3052
+ if (error.isRetryable) return true;
3053
+ const statusCode = error.statusCode;
3054
+ if (statusCode === 429) return true;
3055
+ if (statusCode === 500) return true;
3056
+ if (statusCode === 502) return true;
3057
+ if (statusCode === 503) return true;
3058
+ if (statusCode === 504) return true;
3059
+ }
3060
+ if (error instanceof Error) {
3061
+ const message = error.message.toLowerCase();
3062
+ if (message.includes("rate limit")) return true;
3063
+ if (message.includes("timeout")) return true;
3064
+ if (message.includes("service unavailable")) return true;
3065
+ }
3066
+ return false;
3067
+ }
3068
+
3069
+ // ../../packages/providers/openai/src/tools.ts
3070
+ function buildOpenAITools(client, toolNames, options) {
3071
+ const tools = {};
3072
+ for (const name of toolNames) {
3073
+ switch (name) {
3074
+ case "webSearch": {
3075
+ const webSearchTool = client.tools.webSearch();
3076
+ tools["web_search"] = webSearchTool;
3077
+ break;
3078
+ }
3079
+ case "fileSearch": {
3080
+ const vectorStoreIds = options?.fileSearch?.vectorStoreIds;
3081
+ if (!vectorStoreIds || vectorStoreIds.length === 0) {
3082
+ console.warn(
3083
+ "OpenAI fileSearch tool requires vectorStoreIds. Set providerToolOptions.fileSearch.vectorStoreIds to use this tool."
3084
+ );
3085
+ break;
3086
+ }
3087
+ const fileSearchTool = client.tools.fileSearch({
3088
+ vectorStoreIds,
3089
+ maxNumResults: options?.fileSearch?.maxNumResults
3090
+ });
3091
+ tools["file_search"] = fileSearchTool;
3092
+ break;
3093
+ }
3094
+ case "codeInterpreter": {
3095
+ const codeInterpreterTool = client.tools.codeInterpreter();
3096
+ tools["code_interpreter"] = codeInterpreterTool;
3097
+ break;
3098
+ }
3099
+ case "imageGeneration": {
3100
+ const imageGenerationTool = client.tools.imageGeneration();
3101
+ tools["image_generation"] = imageGenerationTool;
3102
+ break;
3103
+ }
3104
+ }
3105
+ }
3106
+ return tools;
3107
+ }
3108
+
3109
+ // ../../packages/providers/openai/src/adapter.ts
3110
+ var OpenAIProviderAdapter = class extends BaseProviderAdapter {
3111
+ constructor(config, options) {
3112
+ super(options);
3113
+ this.config = config;
3114
+ this.client = createOpenAI({
3115
+ apiKey: config.apiKey,
3116
+ baseURL: config.baseUrl,
3117
+ organization: config.organization,
3118
+ project: config.project,
3119
+ name: config.name,
3120
+ headers: config.headers,
3121
+ fetch: options?.proxyUrl ? this.createProxyFetch(options.proxyUrl) : void 0
3122
+ });
3123
+ }
3124
+ providerName = "openai";
3125
+ client;
3126
+ createModel(modelId) {
3127
+ return this.client(modelId);
3128
+ }
3129
+ getProviderTools(toolNames, options) {
3130
+ return buildOpenAITools(this.client, toolNames, options);
3131
+ }
3132
+ getReasoningOptions(budget) {
3133
+ const effort = this.budgetToEffort(budget);
3134
+ return {
3135
+ openai: { reasoningEffort: effort }
3136
+ };
3137
+ }
3138
+ budgetToEffort(budget) {
3139
+ if (typeof budget === "number") {
3140
+ if (budget <= 2048) return "low";
3141
+ if (budget <= 5e3) return "medium";
3142
+ return "high";
3143
+ }
3144
+ if (budget === "minimal") return "low";
3145
+ return budget;
3146
+ }
3147
+ normalizeError(error) {
3148
+ return normalizeOpenAIError(error);
3149
+ }
3150
+ isRetryable(error) {
3151
+ return isOpenAIRetryable(error);
3152
+ }
3153
+ };
3154
+ function normalizeVertexError(error) {
3155
+ if (error instanceof APICallError) {
3156
+ return {
3157
+ name: error.name,
3158
+ message: error.message,
3159
+ statusCode: error.statusCode,
3160
+ isRetryable: isVertexRetryable(error),
3161
+ provider: "google-vertex",
3162
+ originalError: error
3163
+ };
3164
+ }
3165
+ if (error instanceof Error) {
3166
+ return {
3167
+ name: error.name,
3168
+ message: error.message,
3169
+ isRetryable: isVertexRetryable(error),
3170
+ provider: "google-vertex",
3171
+ originalError: error
3172
+ };
3173
+ }
3174
+ return {
3175
+ name: "UnknownError",
3176
+ message: String(error),
3177
+ isRetryable: false,
3178
+ provider: "google-vertex",
3179
+ originalError: error
3180
+ };
3181
+ }
3182
+ function isVertexRetryable(error) {
3183
+ if (error instanceof APICallError) {
3184
+ if (error.isRetryable) return true;
3185
+ const statusCode = error.statusCode;
3186
+ if (statusCode === 429) return true;
3187
+ if (statusCode === 500) return true;
3188
+ if (statusCode === 502) return true;
3189
+ if (statusCode === 503) return true;
3190
+ if (statusCode === 504) return true;
3191
+ }
3192
+ if (error instanceof Error) {
3193
+ const message = error.message.toLowerCase();
3194
+ if (message.includes("rate limit")) return true;
3195
+ if (message.includes("quota exceeded")) return true;
3196
+ if (message.includes("timeout")) return true;
3197
+ if (message.includes("service unavailable")) return true;
3198
+ }
3199
+ return false;
3200
+ }
3201
+
3202
+ // ../../packages/providers/vertex/src/tools.ts
3203
+ function buildVertexTools(client, toolNames, options) {
3204
+ const tools = {};
3205
+ for (const name of toolNames) {
3206
+ switch (name) {
3207
+ case "googleSearch": {
3208
+ const googleSearchTool = client.tools.googleSearch({});
3209
+ tools["google_search"] = googleSearchTool;
3210
+ break;
3211
+ }
3212
+ case "codeExecution": {
3213
+ const codeExecutionTool = client.tools.codeExecution({});
3214
+ tools["code_execution"] = codeExecutionTool;
3215
+ break;
3216
+ }
3217
+ case "urlContext": {
3218
+ const urlContextTool = client.tools.urlContext({});
3219
+ tools["url_context"] = urlContextTool;
3220
+ break;
3221
+ }
3222
+ case "enterpriseWebSearch": {
3223
+ const enterpriseWebSearchTool = client.tools.enterpriseWebSearch({});
3224
+ tools["enterprise_web_search"] = enterpriseWebSearchTool;
3225
+ break;
3226
+ }
3227
+ case "googleMaps": {
3228
+ const googleMapsTool = client.tools.googleMaps(options?.googleMaps?.retrievalConfig ?? {});
3229
+ tools["google_maps"] = googleMapsTool;
3230
+ break;
3231
+ }
3232
+ }
3233
+ }
3234
+ return tools;
3235
+ }
3236
+
3237
+ // ../../packages/providers/vertex/src/adapter.ts
3238
+ var VertexProviderAdapter = class extends BaseProviderAdapter {
3239
+ constructor(config, options) {
3240
+ super(options);
3241
+ this.config = config;
3242
+ this.client = createVertex({
3243
+ project: config.project,
3244
+ location: config.location,
3245
+ baseURL: config.baseUrl,
3246
+ headers: config.headers,
3247
+ fetch: options?.proxyUrl ? this.createProxyFetch(options.proxyUrl) : void 0
3248
+ });
3249
+ }
3250
+ providerName = "google-vertex";
3251
+ client;
3252
+ createModel(modelId) {
3253
+ return this.client(modelId);
3254
+ }
3255
+ getProviderTools(toolNames, options) {
3256
+ return buildVertexTools(this.client, toolNames, options);
3257
+ }
3258
+ getProviderOptions(config) {
3259
+ if (!config?.safetySettings || config.safetySettings.length === 0) {
3260
+ return void 0;
3261
+ }
3262
+ return {
3263
+ vertex: {
3264
+ safetySettings: config.safetySettings
3265
+ }
3266
+ };
3267
+ }
3268
+ getReasoningOptions(budget) {
3269
+ if (budget === "none" || budget === 0) {
3270
+ return void 0;
3271
+ }
3272
+ const budgetTokens = this.budgetToTokens(budget);
3273
+ return {
3274
+ vertex: {
3275
+ thinkingConfig: {
3276
+ thinkingBudget: budgetTokens,
3277
+ includeThoughts: true
3278
+ }
3279
+ }
3280
+ };
3281
+ }
3282
+ budgetToTokens(budget) {
3283
+ if (typeof budget === "number") return budget;
3284
+ const map = {
3285
+ minimal: 1024,
3286
+ low: 2048,
3287
+ medium: 5e3,
3288
+ high: 1e4
3289
+ };
3290
+ return map[budget] ?? 5e3;
3291
+ }
3292
+ normalizeError(error) {
3293
+ return normalizeVertexError(error);
3294
+ }
3295
+ isRetryable(error) {
3296
+ return isVertexRetryable(error);
3297
+ }
3298
+ };
3299
+
3300
+ // src/helpers/register-providers.ts
3301
+ registerProviderAdapter(
3302
+ "anthropic",
3303
+ async () => AnthropicProviderAdapter
3304
+ );
3305
+ registerProviderAdapter(
3306
+ "openai",
3307
+ async () => OpenAIProviderAdapter
3308
+ );
3309
+ registerProviderAdapter(
3310
+ "google",
3311
+ async () => GoogleProviderAdapter
3312
+ );
3313
+ registerProviderAdapter(
3314
+ "ollama",
3315
+ async () => OllamaProviderAdapter
3316
+ );
3317
+ registerProviderAdapter(
3318
+ "azure-openai",
3319
+ async () => AzureOpenAIProviderAdapter
3320
+ );
3321
+ registerProviderAdapter(
3322
+ "amazon-bedrock",
3323
+ async () => BedrockProviderAdapter
3324
+ );
3325
+ registerProviderAdapter(
3326
+ "google-vertex",
3327
+ async () => VertexProviderAdapter
3328
+ );
3329
+ registerProviderAdapter(
3330
+ "deepseek",
3331
+ async () => DeepseekProviderAdapter
3332
+ );
3333
+ var shouldEnableReasoning = (budget) => budget !== void 0 && budget !== "none" && budget !== 0;
3334
+ var LLMExecutor = class {
3335
+ constructor(adapter, model) {
3336
+ this.adapter = adapter;
3337
+ this.model = model;
3338
+ }
3339
+ async generateText(params) {
3340
+ const providerTools = this.adapter.getProviderTools(
3341
+ params.providerToolNames ?? [],
3342
+ params.providerToolOptions
3343
+ );
3344
+ const baseProviderOptions = this.adapter.getProviderOptions(params.providerOptionsConfig);
3345
+ const reasoningEnabled = shouldEnableReasoning(params.reasoningBudget);
3346
+ const reasoningOptions = reasoningEnabled && params.reasoningBudget ? this.adapter.getReasoningOptions(params.reasoningBudget) : void 0;
3347
+ const providerOptions = this.mergeProviderOptions(baseProviderOptions, reasoningOptions);
3348
+ try {
3349
+ const result = await generateText({
3350
+ model: this.model,
3351
+ messages: params.messages,
3352
+ maxRetries: params.maxRetries,
3353
+ tools: { ...params.tools, ...providerTools },
3354
+ toolChoice: params.toolChoice,
3355
+ abortSignal: params.abortSignal,
3356
+ providerOptions
3357
+ });
3358
+ return { success: true, result };
3359
+ } catch (error) {
3360
+ const providerError = this.adapter.normalizeError(error);
3361
+ return {
3362
+ success: false,
3363
+ error: providerError,
3364
+ isRetryable: this.adapter.isRetryable(error)
3365
+ };
3366
+ }
3367
+ }
3368
+ mergeProviderOptions(...options) {
3369
+ const defined = options.filter(Boolean);
3370
+ if (defined.length === 0) return void 0;
3371
+ const result = {};
3372
+ for (const opt of defined) {
3373
+ for (const [provider, settings] of Object.entries(opt)) {
3374
+ result[provider] = { ...result[provider], ...settings };
3375
+ }
3376
+ }
3377
+ return result;
3378
+ }
3379
+ async generateTextWithoutTools(params) {
3380
+ const baseProviderOptions = this.adapter.getProviderOptions(params.providerOptionsConfig);
3381
+ const reasoningEnabled = shouldEnableReasoning(params.reasoningBudget);
3382
+ const reasoningOptions = reasoningEnabled && params.reasoningBudget ? this.adapter.getReasoningOptions(params.reasoningBudget) : void 0;
3383
+ const providerOptions = this.mergeProviderOptions(baseProviderOptions, reasoningOptions);
3384
+ try {
3385
+ const result = await generateText({
3386
+ model: this.model,
3387
+ messages: params.messages,
3388
+ maxRetries: params.maxRetries,
3389
+ abortSignal: params.abortSignal,
3390
+ providerOptions
3391
+ });
3392
+ return { success: true, result };
3393
+ } catch (error) {
3394
+ const providerError = this.adapter.normalizeError(error);
3395
+ return {
3396
+ success: false,
3397
+ error: providerError,
3398
+ isRetryable: this.adapter.isRetryable(error)
3399
+ };
3400
+ }
3401
+ }
3402
+ async streamText(params, callbacks) {
3403
+ const providerTools = this.adapter.getProviderTools(
3404
+ params.providerToolNames ?? [],
3405
+ params.providerToolOptions
3406
+ );
3407
+ const baseProviderOptions = this.adapter.getProviderOptions(params.providerOptionsConfig);
3408
+ const reasoningEnabled = shouldEnableReasoning(params.reasoningBudget);
3409
+ const reasoningOptions = reasoningEnabled && params.reasoningBudget ? this.adapter.getReasoningOptions(params.reasoningBudget) : void 0;
3410
+ const providerOptions = this.mergeProviderOptions(baseProviderOptions, reasoningOptions);
3411
+ const streamResult = streamText({
3412
+ model: this.model,
3413
+ messages: params.messages,
3414
+ maxRetries: params.maxRetries,
3415
+ tools: { ...params.tools, ...providerTools },
3416
+ toolChoice: params.toolChoice,
3417
+ abortSignal: params.abortSignal,
3418
+ providerOptions
3419
+ });
3420
+ let reasoningStarted = false;
3421
+ let reasoningCompleted = false;
3422
+ let resultStarted = false;
3423
+ let accumulatedReasoning = "";
3424
+ try {
3425
+ for await (const part of streamResult.fullStream) {
3426
+ if (part.type === "reasoning-delta") {
3427
+ if (!reasoningStarted) {
3428
+ callbacks.onReasoningStart?.();
3429
+ reasoningStarted = true;
3430
+ }
3431
+ accumulatedReasoning += part.text;
3432
+ callbacks.onReasoningDelta?.(part.text);
3433
+ }
3434
+ if (part.type === "text-delta") {
3435
+ if (reasoningStarted && !reasoningCompleted) {
3436
+ callbacks.onReasoningComplete?.(accumulatedReasoning);
3437
+ reasoningCompleted = true;
3438
+ }
3439
+ if (!resultStarted) {
3440
+ callbacks.onResultStart?.();
3441
+ resultStarted = true;
3442
+ }
3443
+ callbacks.onResultDelta?.(part.text);
3444
+ }
3445
+ }
3446
+ if (reasoningStarted && !reasoningCompleted) {
3447
+ callbacks.onReasoningComplete?.(accumulatedReasoning);
3448
+ reasoningCompleted = true;
3449
+ }
3450
+ const text = await streamResult.text;
3451
+ const toolCalls = await streamResult.toolCalls;
3452
+ const finishReason = await streamResult.finishReason;
3453
+ const usage = await streamResult.usage;
3454
+ const reasoning = await streamResult.reasoning;
3455
+ const response = await streamResult.response;
3456
+ const result = {
3457
+ text,
3458
+ toolCalls,
3459
+ finishReason,
3460
+ usage,
3461
+ reasoning,
3462
+ response,
3463
+ // These properties are required by GenerateTextResult but not available in streamText
3464
+ // They're optional or have safe defaults
3465
+ toolResults: [],
3466
+ steps: [],
3467
+ experimental_output: void 0,
3468
+ providerMetadata: void 0,
3469
+ request: { body: "" }
3470
+ };
3471
+ return { success: true, result };
3472
+ } catch (error) {
3473
+ const providerError = this.adapter.normalizeError(error);
3474
+ return {
3475
+ success: false,
3476
+ error: providerError,
3477
+ isRetryable: this.adapter.isRetryable(error)
3478
+ };
3479
+ }
3480
+ }
3481
+ };
3482
+
3483
+ // src/orchestration/single-run-executor.ts
3484
+ var SingleRunExecutor = class {
3485
+ constructor(options = {}) {
3486
+ this.options = options;
3487
+ }
3488
+ async execute(setting, checkpoint) {
3489
+ const adapter = await createProviderAdapter(setting.providerConfig, {
3490
+ proxyUrl: setting.proxyUrl
3491
+ });
3492
+ const model = adapter.createModel(setting.model);
3493
+ const llmExecutor = new LLMExecutor(adapter, model);
3494
+ const contextWindow = getContextWindow(setting.providerConfig.providerName, setting.model);
3495
+ const { expertToRun, experts } = await setupExperts(setting, this.options.resolveExpertToRun);
3496
+ this.emitInitEvent(setting, expertToRun, experts);
3497
+ const lockfileExpert = this.options.lockfile?.experts[setting.expertKey];
3498
+ const skillManagers = lockfileExpert ? await getSkillManagersFromLockfile(
3499
+ expertToRun,
3500
+ experts,
3501
+ setting,
3502
+ getLockfileExpertToolDefinitions(lockfileExpert),
3503
+ this.options.eventListener,
3504
+ { isDelegatedRun: !!checkpoint?.delegatedBy }
3505
+ ) : await getSkillManagers(expertToRun, experts, setting, this.options.eventListener, {
3506
+ isDelegatedRun: !!checkpoint?.delegatedBy
3507
+ });
2487
3508
  const initialCheckpoint = checkpoint ? createNextStepCheckpoint(createId(), checkpoint) : createInitialCheckpoint(createId(), {
2488
3509
  jobId: setting.jobId,
2489
3510
  runId: setting.runId,
@@ -2499,6 +3520,7 @@ var SingleRunExecutor = class {
2499
3520
  initialCheckpoint,
2500
3521
  eventListener,
2501
3522
  skillManagers,
3523
+ llmExecutor,
2502
3524
  eventEmitter,
2503
3525
  storeCheckpoint: this.options.storeCheckpoint ?? (async () => {
2504
3526
  }),
@@ -2524,7 +3546,6 @@ var SingleRunExecutor = class {
2524
3546
  expertName: expertToRun.name,
2525
3547
  experts: Object.keys(experts),
2526
3548
  model: setting.model,
2527
- temperature: setting.temperature,
2528
3549
  maxSteps: setting.maxSteps,
2529
3550
  maxRetries: setting.maxRetries,
2530
3551
  timeout: setting.timeout,
@@ -2565,7 +3586,8 @@ async function run(runInput, options) {
2565
3586
  storeCheckpoint: options?.storeCheckpoint,
2566
3587
  storeEvent: options?.storeEvent,
2567
3588
  eventListener: options?.eventListener,
2568
- resolveExpertToRun: options?.resolveExpertToRun
3589
+ resolveExpertToRun: options?.resolveExpertToRun,
3590
+ lockfile: options?.lockfile
2569
3591
  });
2570
3592
  while (true) {
2571
3593
  const runResult = await runExecutor.execute(setting, checkpoint);
@@ -2633,6 +3655,6 @@ async function run(runInput, options) {
2633
3655
  }
2634
3656
  }
2635
3657
 
2636
- export { getModel, package_default, run, runtimeStateMachine };
2637
- //# sourceMappingURL=chunk-3RWT2GPO.js.map
2638
- //# sourceMappingURL=chunk-3RWT2GPO.js.map
3658
+ export { findLockfile, getLockfileExpertToolDefinitions, getModel, loadLockfile, package_default, run, runtimeStateMachine };
3659
+ //# sourceMappingURL=chunk-BXJGGA3Q.js.map
3660
+ //# sourceMappingURL=chunk-BXJGGA3Q.js.map