@perstack/runtime 0.0.23 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,828 +1,81 @@
1
- // src/runtime.ts
2
- import { existsSync } from "fs";
3
- import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
4
- import path from "path";
5
- import { createId as createId8 } from "@paralleldrive/cuid2";
6
- import TOML from "smol-toml";
7
- import { createActor } from "xstate";
8
-
9
- // src/default-store.ts
10
- import { mkdir, readFile, readdir, writeFile } from "fs/promises";
11
-
12
- // src/schemas/runtime.ts
13
- import { createId } from "@paralleldrive/cuid2";
14
- import { z as z2 } from "zod";
15
-
16
- // src/model.ts
17
- import { anthropic } from "@ai-sdk/anthropic";
18
- import { google } from "@ai-sdk/google";
19
- import { openai } from "@ai-sdk/openai";
20
- var DefaultModel = "claude-4-sonnet-20250514";
21
- var AnthropicModels = [
22
- "claude-4-opus-20250514",
23
- "claude-4-sonnet-20250514",
24
- "claude-3-7-sonnet-20250219",
25
- "claude-3-5-sonnet-latest",
26
- "claude-3-5-sonnet-20241022",
27
- "claude-3-5-sonnet-20240620",
28
- "claude-3-5-haiku-latest",
29
- "claude-3-5-haiku-20241022"
30
- // "claude-3-opus-latest", - No pdf support
31
- // "claude-3-opus-20240229", - No pdf support
32
- // "claude-3-sonnet-20240229", - No pdf support
33
- // "claude-3-haiku-20240307", - No pdf support
34
- ];
35
- var GoogleModels = [
36
- "gemini-1.5-flash",
37
- "gemini-1.5-flash-latest",
38
- "gemini-1.5-flash-001",
39
- "gemini-1.5-flash-002",
40
- "gemini-1.5-flash-8b",
41
- "gemini-1.5-flash-8b-latest",
42
- "gemini-1.5-flash-8b-001",
43
- "gemini-1.5-pro",
44
- "gemini-1.5-pro-latest",
45
- "gemini-1.5-pro-001",
46
- "gemini-1.5-pro-002",
47
- "gemini-2.0-flash",
48
- "gemini-2.0-flash-001",
49
- "gemini-2.0-flash-live-001",
50
- "gemini-2.0-flash-lite",
51
- "gemini-2.0-pro-exp-02-05",
52
- "gemini-2.0-flash-thinking-exp-01-21",
53
- "gemini-2.0-flash-exp",
54
- "gemini-2.5-pro",
55
- "gemini-2.5-flash",
56
- "gemini-2.5-flash-lite",
57
- "gemini-2.5-pro-exp-03-25",
58
- "gemini-2.5-flash-preview-04-17"
59
- ];
60
- var OpenAIModels = [
61
- "o4-mini",
62
- "o4-mini-2025-04-16",
63
- "o3",
64
- "o3-2025-04-16",
65
- "o3-mini",
66
- "o3-mini-2025-01-31",
67
- "o1",
68
- "o1-2024-12-17",
69
- "o1-mini",
70
- "o1-mini-2024-09-12",
71
- // "o1-preview", - No tool support
72
- // "o1-preview-2024-09-12", - No tool support
73
- "gpt-4.5-preview",
74
- "gpt-4.5-preview-2025-02-27",
75
- "gpt-4.1",
76
- "gpt-4.1-2025-04-14",
77
- "gpt-4.1-mini",
78
- "gpt-4.1-mini-2025-04-14",
79
- "gpt-4.1-nano",
80
- "gpt-4.1-nano-2025-04-14",
81
- "gpt-4o",
82
- "gpt-4o-2024-05-13",
83
- "gpt-4o-2024-08-06",
84
- "gpt-4o-2024-11-20",
85
- "gpt-4o-audio-preview",
86
- "gpt-4o-audio-preview-2024-10-01",
87
- "gpt-4o-audio-preview-2024-12-17",
88
- "gpt-4o-search-preview",
89
- "gpt-4o-search-preview-2025-03-11",
90
- "gpt-4o-mini-search-preview",
91
- "gpt-4o-mini-search-preview-2025-03-11",
92
- "gpt-4o-mini",
93
- "gpt-4o-mini-2024-07-18"
94
- // "gpt-4-turbo", - Legacy model
95
- // "gpt-4-turbo-2024-04-09", - Legacy model
96
- // "gpt-4-turbo-preview", - Legacy model
97
- // "gpt-4-0125-preview", - No image input support
98
- // "gpt-4-1106-preview", - No image input support
99
- // "gpt-4", - No image input support
100
- // "gpt-4-0613", - No image input support
101
- // "gpt-3.5-turbo-0125", - Legacy model
102
- // "gpt-3.5-turbo", - Legacy model
103
- // "gpt-3.5-turbo-1106", - Legacy model
104
- // "chatgpt-4o-latest", - No tool support
105
- ];
106
- var SupportedModels = Object.fromEntries(
107
- [...AnthropicModels, ...GoogleModels, ...OpenAIModels].map((model) => [
108
- model,
109
- { default: model === DefaultModel, model }
110
- ])
111
- );
112
- function getDefaultModelName() {
113
- const model = Object.values(SupportedModels).find((model2) => model2.default);
114
- if (!model) {
115
- throw new Error("No default model found");
116
- }
117
- return model.model;
118
- }
119
- function getModel(modelId) {
120
- const unwrappedModelId = modelId ?? getDefaultModelName();
121
- if (AnthropicModels.includes(unwrappedModelId)) {
122
- return anthropic(unwrappedModelId);
123
- }
124
- if (GoogleModels.includes(unwrappedModelId)) {
125
- return google(unwrappedModelId);
126
- }
127
- if (OpenAIModels.includes(unwrappedModelId)) {
128
- return openai(unwrappedModelId);
129
- }
130
- throw new Error(`Unsupported model: ${unwrappedModelId}`);
131
- }
132
-
133
- // src/schemas/messages.ts
134
- import { z } from "zod";
135
- var BasePartSchema = z.object({
136
- id: z.string()
137
- });
138
- var TextPartSchema = BasePartSchema.extend({
139
- type: z.literal("textPart"),
140
- text: z.string()
141
- });
142
- var ImageUrlPartSchema = BasePartSchema.extend({
143
- type: z.literal("imageUrlPart"),
144
- url: z.string().url(),
145
- mimeType: z.string()
146
- });
147
- var ImageInlinePartSchema = BasePartSchema.extend({
148
- type: z.literal("imageInlinePart"),
149
- encodedData: z.string(),
150
- mimeType: z.string()
151
- });
152
- var ImageBinaryPartSchema = BasePartSchema.extend({
153
- type: z.literal("imageBinaryPart"),
154
- data: z.string(),
155
- mimeType: z.string()
156
- });
157
- var FileUrlPartSchema = BasePartSchema.extend({
158
- type: z.literal("fileUrlPart"),
159
- url: z.string().url(),
160
- mimeType: z.string()
161
- });
162
- var FileInlinePartSchema = BasePartSchema.extend({
163
- type: z.literal("fileInlinePart"),
164
- encodedData: z.string(),
165
- mimeType: z.string()
166
- });
167
- var FileBinaryPartSchema = BasePartSchema.extend({
168
- type: z.literal("fileBinaryPart"),
169
- data: z.string(),
170
- mimeType: z.string()
171
- });
172
- var ToolCallPartSchema = BasePartSchema.extend({
173
- type: z.literal("toolCallPart"),
174
- toolCallId: z.string(),
175
- toolName: z.string(),
176
- args: z.unknown()
177
- });
178
- var ToolResultPartSchema = BasePartSchema.extend({
179
- type: z.literal("toolResultPart"),
180
- toolCallId: z.string(),
181
- toolName: z.string(),
182
- contents: z.array(z.union([TextPartSchema, ImageInlinePartSchema])),
183
- isError: z.boolean().optional()
184
- });
185
- var BaseMessageSchema = z.object({
186
- id: z.string()
187
- });
188
- var InstructionMessageSchema = BaseMessageSchema.extend({
189
- type: z.literal("instructionMessage"),
190
- contents: z.array(TextPartSchema),
191
- cache: z.boolean().optional()
192
- });
193
- var UserMessageSchema = BaseMessageSchema.extend({
194
- type: z.literal("userMessage"),
195
- contents: z.array(
196
- z.union([
197
- TextPartSchema,
198
- ImageUrlPartSchema,
199
- ImageInlinePartSchema,
200
- ImageBinaryPartSchema,
201
- FileUrlPartSchema,
202
- FileInlinePartSchema,
203
- FileBinaryPartSchema
204
- ])
205
- ),
206
- cache: z.boolean().optional()
207
- });
208
- var ExpertMessageSchema = BaseMessageSchema.extend({
209
- type: z.literal("expertMessage"),
210
- contents: z.array(z.union([TextPartSchema, ToolCallPartSchema])),
211
- cache: z.boolean().optional()
212
- });
213
- var ToolMessageSchema = BaseMessageSchema.extend({
214
- type: z.literal("toolMessage"),
215
- contents: z.array(ToolResultPartSchema),
216
- cache: z.boolean().optional()
217
- });
218
- var MessageSchema = z.union([
219
- InstructionMessageSchema,
220
- UserMessageSchema,
221
- ExpertMessageSchema,
222
- ToolMessageSchema
223
- ]);
224
-
225
- // src/schemas/runtime.ts
226
- var expertNameRegex = /^(@[a-z0-9][a-z0-9_-]*\/)?[a-z0-9][a-z0-9_-]*$/;
227
- var versionRegex = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
228
- var tagNameRegex = /^[a-z0-9][a-z0-9_-]*$/;
229
- var expertKeyRegex = /^((?:@[a-z0-9][a-z0-9_\.-]*\/)?[a-z0-9][a-z0-9_\.-]*)(?:@((?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?)|@([a-z0-9][a-z0-9_\.-]*))?$/;
230
- var skillNameRegex = /^[a-z0-9][a-z0-9._-]*$/;
231
- var maxNameLength = 214;
232
- function parseExpertKey(expertKey) {
233
- const match = expertKey.match(expertKeyRegex);
234
- if (!match) {
235
- throw new Error(`Invalid expert key format: ${expertKey}`);
236
- }
237
- const [key, name, version, tag] = match;
238
- return {
239
- key,
240
- name,
241
- version,
242
- tag
243
- };
244
- }
245
- var McpStdioSkillSchema = z2.object({
246
- type: z2.literal("mcpStdioSkill"),
247
- name: z2.string(),
248
- description: z2.string().optional(),
249
- rule: z2.string().optional(),
250
- pick: z2.array(z2.string()).optional().default([]),
251
- omit: z2.array(z2.string()).optional().default([]),
252
- command: z2.string(),
253
- packageName: z2.string().optional(),
254
- args: z2.array(z2.string()).optional().default([]),
255
- requiredEnv: z2.array(z2.string()).optional().default([])
256
- });
257
- var McpSseSkillSchema = z2.object({
258
- type: z2.literal("mcpSseSkill"),
259
- name: z2.string(),
260
- description: z2.string().optional(),
261
- rule: z2.string().optional(),
262
- pick: z2.array(z2.string()).optional().default([]),
263
- omit: z2.array(z2.string()).optional().default([]),
264
- endpoint: z2.string()
265
- });
266
- var InteractiveToolSchema = z2.object({
267
- name: z2.string(),
268
- description: z2.string().optional(),
269
- inputJsonSchema: z2.string()
270
- });
271
- var InteractiveSkillSchema = z2.object({
272
- type: z2.literal("interactiveSkill"),
273
- name: z2.string(),
274
- description: z2.string().optional(),
275
- rule: z2.string().optional(),
276
- tools: z2.record(z2.string(), InteractiveToolSchema.omit({ name: true })).transform((tools) => {
277
- return Object.fromEntries(
278
- Object.entries(tools).map(([key, toolWithoutName]) => [
279
- key,
280
- InteractiveToolSchema.parse({ ...toolWithoutName, name: key })
281
- ])
282
- );
283
- })
284
- });
285
- var ExpertSchema = z2.object({
286
- key: z2.string().regex(expertKeyRegex).min(1),
287
- name: z2.string().regex(expertNameRegex).min(1).max(maxNameLength),
288
- version: z2.string().regex(versionRegex),
289
- description: z2.string().min(1).max(1024 * 2).optional(),
290
- instruction: z2.string().min(1).max(1024 * 20),
291
- skills: z2.record(
292
- z2.string(),
293
- z2.discriminatedUnion("type", [
294
- McpStdioSkillSchema.omit({ name: true }),
295
- McpSseSkillSchema.omit({ name: true }),
296
- InteractiveSkillSchema.omit({ name: true })
297
- ])
298
- ).optional().default({
299
- "@perstack/base": {
300
- type: "mcpStdioSkill",
301
- description: "Base skill",
302
- command: "npx",
303
- args: ["-y", "@perstack/base"],
304
- pick: [],
305
- omit: [],
306
- requiredEnv: []
307
- }
308
- }).transform((skills) => {
309
- return Object.fromEntries(
310
- Object.entries(skills).map(([key, skillWithoutName]) => [
311
- key,
312
- z2.discriminatedUnion("type", [
313
- McpStdioSkillSchema,
314
- McpSseSkillSchema,
315
- InteractiveSkillSchema
316
- ]).parse({ ...skillWithoutName, name: key })
317
- ])
318
- );
319
- }),
320
- delegates: z2.array(z2.string().regex(expertKeyRegex).min(1)).optional().default([]),
321
- tags: z2.array(z2.string().regex(tagNameRegex).min(1)).optional().default([])
322
- });
323
- var UsageSchema = z2.object({
324
- promptTokens: z2.number(),
325
- completionTokens: z2.number(),
326
- totalTokens: z2.number(),
327
- cacheCreationInputTokens: z2.number(),
328
- cacheReadInputTokens: z2.number()
329
- });
330
- var CheckpointStatusSchema = z2.enum([
331
- "init",
332
- "proceeding",
333
- "completed",
334
- "stoppedByInteractiveTool",
335
- "stoppedByDelegate",
336
- "stoppedByExceededMaxSteps",
337
- "stoppedByError"
338
- ]);
339
- var CheckpointSchema = z2.object({
340
- id: z2.string(),
341
- runId: z2.string(),
342
- status: CheckpointStatusSchema,
343
- stepNumber: z2.number(),
344
- messages: z2.array(MessageSchema),
345
- expert: z2.object({
346
- key: z2.string(),
347
- name: z2.string(),
348
- version: z2.string()
349
- }),
350
- delegateTo: z2.object({
351
- expert: z2.object({
352
- key: z2.string(),
353
- name: z2.string(),
354
- version: z2.string()
355
- }),
356
- toolCallId: z2.string(),
357
- toolName: z2.string(),
358
- query: z2.string()
359
- }).optional(),
360
- delegatedBy: z2.object({
361
- expert: z2.object({
362
- key: z2.string(),
363
- name: z2.string(),
364
- version: z2.string()
365
- }),
366
- toolCallId: z2.string(),
367
- toolName: z2.string(),
368
- checkpointId: z2.string()
369
- }).optional(),
370
- usage: UsageSchema
371
- });
372
- var RunParamsSchema = z2.object({
373
- setting: z2.object({
374
- runId: z2.string().optional().transform((value) => value ?? createId()),
375
- expertKey: z2.string().regex(expertKeyRegex).min(1),
376
- input: z2.object({
377
- text: z2.string().optional(),
378
- interactiveToolCallResult: z2.object({
379
- toolCallId: z2.string(),
380
- toolName: z2.string(),
381
- text: z2.string()
382
- }).optional()
383
- }),
384
- experts: z2.record(z2.string().regex(expertKeyRegex).min(1), ExpertSchema.omit({ key: true })).optional().default({}).transform(
385
- (experts) => Object.fromEntries(
386
- Object.entries(experts).map(([key, expertWithoutKey]) => [
387
- key,
388
- ExpertSchema.parse({
389
- ...expertWithoutKey,
390
- key
391
- })
392
- ])
393
- )
394
- ),
395
- model: z2.string().optional().default(getDefaultModelName()),
396
- temperature: z2.number().min(0).max(1).optional().default(0.3),
397
- maxSteps: z2.number().min(1).optional(),
398
- maxRetries: z2.number().min(0).optional().default(5),
399
- timeout: z2.number().min(0).optional().default(1e3 * 60),
400
- workspace: z2.string().optional(),
401
- startedAt: z2.number().optional().default(Date.now()),
402
- updatedAt: z2.number().optional().default(Date.now())
403
- }),
404
- checkpoint: CheckpointSchema.optional()
405
- });
406
- function createEvent(type) {
407
- return (setting, checkpoint, data) => {
408
- return {
409
- type,
410
- id: createId(),
411
- expertKey: checkpoint.expert.key,
412
- timestamp: Date.now(),
413
- runId: setting.runId,
414
- stepNumber: checkpoint.stepNumber,
415
- ...data
416
- };
417
- };
418
- }
419
- var startRun = createEvent("startRun");
420
- var startGeneration = createEvent("startGeneration");
421
- var retry = createEvent("retry");
422
- var callTool = createEvent("callTool");
423
- var callInteractiveTool = createEvent("callInteractiveTool");
424
- var callDelegate = createEvent("callDelegate");
425
- var resolveToolResult = createEvent("resolveToolResult");
426
- var resolveThought = createEvent("resolveThought");
427
- var resolvePdfFile = createEvent("resolvePdfFile");
428
- var resolveImageFile = createEvent("resolveImageFile");
429
- var attemptCompletion = createEvent("attemptCompletion");
430
- var finishToolCall = createEvent("finishToolCall");
431
- var completeRun = createEvent("completeRun");
432
- var stopRunByInteractiveTool = createEvent("stopRunByInteractiveTool");
433
- var stopRunByDelegate = createEvent("stopRunByDelegate");
434
- var stopRunByExceededMaxSteps = createEvent("stopRunByExceededMaxSteps");
435
- var continueToNextStep = createEvent("continueToNextStep");
436
-
437
- // src/default-store.ts
438
- async function defaultRetrieveCheckpoint(runId, checkpointId) {
439
- const runDir = getRunDir(runId);
440
- const checkpointFiles = await readdir(runDir, { withFileTypes: true }).then(
441
- (files) => files.filter((file) => file.isFile() && file.name.startsWith("checkpoint-"))
442
- );
443
- const checkpointFile = checkpointFiles.find((file) => file.name.endsWith(`-${checkpointId}.json`));
444
- if (!checkpointFile) {
445
- throw new Error(`checkpoint not found: ${runId} ${checkpointId}`);
446
- }
447
- const checkpointPath = `${runDir}/${checkpointFile.name}`;
448
- const checkpoint = await readFile(checkpointPath, "utf8");
449
- return CheckpointSchema.parse(JSON.parse(checkpoint));
450
- }
451
- async function defaultStoreCheckpoint(checkpoint, timestamp) {
452
- const { id, runId, stepNumber } = checkpoint;
453
- const runDir = getRunDir(runId);
454
- const checkpointPath = `${runDir}/checkpoint-${timestamp}-${stepNumber}-${id}.json`;
455
- await mkdir(runDir, { recursive: true });
456
- await writeFile(checkpointPath, JSON.stringify(checkpoint, null, 2));
457
- }
458
- async function defaultStoreEvent(event) {
459
- const { timestamp, runId, stepNumber, type } = event;
460
- const runDir = getRunDir(runId);
461
- const eventPath = `${runDir}/event-${timestamp}-${stepNumber}-${type}.json`;
462
- await mkdir(runDir, { recursive: true });
463
- await writeFile(eventPath, JSON.stringify(event, null, 2));
464
- }
1
+ import { setup, assign, createActor } from 'xstate';
2
+ import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
3
+ import { createAnthropic } from '@ai-sdk/anthropic';
4
+ import { createAzure } from '@ai-sdk/azure';
5
+ import { createGoogleGenerativeAI } from '@ai-sdk/google';
6
+ import { createOpenAI } from '@ai-sdk/openai';
7
+ import { knownModels, stopRunByDelegate, stopRunByInteractiveTool, resolveThought, attemptCompletion, resolvePdfFile, resolveImageFile, resolveToolResult, stopRunByExceededMaxSteps, continueToNextStep, retry, completeRun, callDelegate, callInteractiveTool, callTool, startRun, startGeneration, finishToolCall, runParamsSchema, checkpointSchema } from '@perstack/core';
8
+ import { createOllama } from 'ollama-ai-provider-v2';
9
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
10
+ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
11
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
12
+ import { McpError } from '@modelcontextprotocol/sdk/types.js';
13
+ import { createId } from '@paralleldrive/cuid2';
14
+ import { generateText, tool, jsonSchema } from 'ai';
15
+ import { dedent } from 'ts-dedent';
16
+ import { readFile, writeFile, mkdir, readdir } from 'fs/promises';
17
+ import { existsSync } from 'fs';
18
+ import path from 'path';
19
+ import { ApiV1Client } from '@perstack/api-client/v1';
465
20
 
466
- // package.json
467
- var package_default = {
468
- name: "@perstack/runtime",
469
- version: "0.0.23",
470
- description: "PerStack Runtime",
471
- author: "Wintermute Technologies, Inc.",
472
- license: "Apache-2.0",
473
- type: "module",
474
- exports: {
475
- ".": "./src/index.ts"
476
- },
477
- publishConfig: {
478
- exports: {
479
- ".": "./dist/index.js"
480
- },
481
- types: "./dist/index.d.ts"
482
- },
483
- files: [
484
- "dist"
485
- ],
486
- scripts: {
487
- clean: "rm -rf dist",
488
- dev: "tsup --watch --config ../../tsup.config.ts",
489
- build: "npm run clean && tsup --config ../../tsup.config.ts",
490
- prepublishOnly: "npm run clean && npm run build"
491
- },
492
- dependencies: {
493
- "@ai-sdk/anthropic": "^2.0.1",
494
- "@ai-sdk/google": "^2.0.2",
495
- "@ai-sdk/openai": "^2.0.3",
496
- "@modelcontextprotocol/sdk": "^1.17.1",
497
- "@paralleldrive/cuid2": "^2.2.2",
498
- ai: "^5.0.4",
499
- "smol-toml": "^1.4.1",
500
- "ts-dedent": "^2.2.0",
501
- xstate: "^5.20.1",
502
- zod: "^4.0.14"
503
- },
504
- devDependencies: {
505
- "@tsconfig/node22": "^22.0.2",
506
- "@types/node": "^24.2.0",
507
- tsup: "^8.5.0",
508
- typescript: "^5.9.2",
509
- vitest: "^3.2.4"
510
- },
511
- engines: {
512
- node: ">=22.0.0"
513
- }
514
- };
515
-
516
- // src/events/default-event-listener.ts
517
- var log = console.info;
518
- var debug = console.debug;
519
- var header = (e) => {
520
- const t = (/* @__PURE__ */ new Date()).toISOString();
521
- const stepNumber = e.stepNumber;
522
- const key = e.expertKey;
523
- return `${t} ${stepNumber} ${key}`;
524
- };
525
- async function defaultEventListener(e) {
526
- await defaultStoreEvent(e);
527
- switch (e.type) {
528
- case "startRun": {
529
- log(`${header(e)} Perstack@${package_default.version} started`);
530
- const { inputMessages } = e;
531
- for (const message of inputMessages) {
532
- if (message.type === "userMessage") {
533
- logUserMessage(message);
534
- } else if (message.type === "toolMessage") {
535
- logToolMessage(message);
536
- }
537
- }
538
- break;
539
- }
540
- case "startGeneration": {
541
- log(`${header(e)} Generating tool call`);
542
- break;
543
- }
544
- case "retry": {
545
- logUsage(e);
546
- log(`${header(e)} Retrying tool call generation`);
547
- break;
548
- }
549
- case "callTool": {
550
- logUsage(e);
551
- log(`${header(e)} Calling tool`);
552
- if (e.toolCall.skillName === "@perstack/base") {
553
- switch (e.toolCall.toolName) {
554
- case "think": {
555
- const thought = e.toolCall.args.thought;
556
- log(`${header(e)} Thought Updated:`);
557
- debug(thought);
558
- break;
559
- }
560
- case "readPdfFile": {
561
- const path2 = e.toolCall.args.path;
562
- log(`${header(e)} Reading PDF: ${path2}`);
563
- break;
564
- }
565
- case "readImageFile": {
566
- const path2 = e.toolCall.args.path;
567
- log(`${header(e)} Reading Image: ${path2}`);
568
- break;
569
- }
570
- default: {
571
- log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
572
- debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
573
- break;
574
- }
575
- }
576
- } else {
577
- log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
578
- debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
579
- }
580
- break;
581
- }
582
- case "callInteractiveTool": {
583
- logUsage(e);
584
- log(`${header(e)} Calling interactive tool`);
585
- log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
586
- debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
587
- break;
588
- }
589
- case "callDelegate": {
590
- logUsage(e);
591
- log(`${header(e)} Calling delegate`);
592
- log(`${header(e)} Tool: ${e.toolCall.toolName}`);
593
- debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
594
- break;
595
- }
596
- case "resolveToolResult": {
597
- log(`${header(e)} Resolved Tool Result`);
598
- if (e.toolResult.skillName === "@perstack/base") {
599
- switch (e.toolResult.toolName) {
600
- case "todo": {
601
- const text = e.toolResult.result.find((r) => r.type === "textPart")?.text;
602
- const { todos } = JSON.parse(text ?? "{}");
603
- log(`${header(e)} Todo:`);
604
- for (const todo of todos) {
605
- debug(`${todo.completed ? "[x]" : "[ ]"} ${todo.id}: ${todo.title}`);
606
- }
607
- break;
608
- }
609
- default: {
610
- log(`${header(e)} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
611
- debug(`${header(e)} Result: ${JSON.stringify(e.toolResult.result, null, 2)}`);
612
- break;
613
- }
614
- }
615
- } else {
616
- log(`${header(e)} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
617
- debug(`${header(e)} Result: ${JSON.stringify(e.toolResult.result, null, 2)}`);
618
- }
619
- break;
620
- }
621
- case "resolveThought": {
622
- log(`${header(e)} Resolved Thought:`, e.toolResult);
623
- break;
624
- }
625
- case "resolvePdfFile": {
626
- log(`${header(e)} Resolved PDF:`, e.toolResult);
627
- break;
628
- }
629
- case "resolveImageFile": {
630
- log(`${header(e)} Resolved Image:`, e.toolResult);
631
- break;
632
- }
633
- case "attemptCompletion": {
634
- log(`${header(e)} Attempting completion`);
635
- break;
636
- }
637
- case "completeRun": {
638
- logUsage(e);
639
- log(`${header(e)} Completing run`);
640
- debug(`${header(e)} Result:`, e.text);
641
- break;
642
- }
643
- case "stopRunByInteractiveTool": {
644
- log(`${header(e)} Stopping run by interactive tool`);
645
- break;
646
- }
647
- case "stopRunByDelegate": {
648
- log(`${header(e)} Stopping run by delegate`);
649
- break;
650
- }
651
- case "stopRunByExceededMaxSteps": {
652
- log(`${header(e)} Stopping run by exceeded max steps`);
653
- break;
21
+ // src/runtime-state-machine.ts
22
+ function getModel(modelId, providerConfig) {
23
+ switch (providerConfig.name) {
24
+ case "anthropic": {
25
+ const anthropic = createAnthropic({
26
+ apiKey: providerConfig.apiKey,
27
+ baseURL: providerConfig.baseUrl
28
+ });
29
+ return anthropic(modelId);
654
30
  }
655
- case "continueToNextStep": {
656
- log(`${header(e)} Continuing to next step`);
657
- break;
31
+ case "google": {
32
+ const google = createGoogleGenerativeAI({
33
+ apiKey: providerConfig.apiKey,
34
+ baseURL: providerConfig.baseUrl
35
+ });
36
+ return google(modelId);
37
+ }
38
+ case "openai": {
39
+ const openai = createOpenAI({
40
+ apiKey: providerConfig.apiKey,
41
+ baseURL: providerConfig.baseUrl,
42
+ organization: providerConfig.organization,
43
+ project: providerConfig.project
44
+ });
45
+ return openai(modelId);
658
46
  }
659
- }
660
- }
661
- function logUserMessage(message) {
662
- const t = (/* @__PURE__ */ new Date()).toISOString();
663
- const contents = message.contents;
664
- for (const content of contents) {
665
- if (content.type === "textPart") {
666
- log(`${t} User: ${content.text}`);
667
- } else if (content.type === "imageUrlPart") {
668
- log(`${t} User: ${content.url}`);
669
- } else if (content.type === "imageInlinePart") {
670
- log(`${t} User: Inline image`);
671
- } else if (content.type === "imageBinaryPart") {
672
- log(`${t} User: Binary image`);
673
- } else if (content.type === "fileUrlPart") {
674
- log(`${t} User: ${content.url}`);
675
- } else if (content.type === "fileInlinePart") {
676
- log(`${t} User: Inline file`);
677
- } else if (content.type === "fileBinaryPart") {
678
- log(`${t} User: Binary file`);
47
+ case "ollama": {
48
+ const ollama = createOllama({
49
+ baseURL: providerConfig.baseUrl
50
+ });
51
+ return ollama(modelId);
679
52
  }
680
- }
681
- }
682
- function logToolMessage(message) {
683
- const t = (/* @__PURE__ */ new Date()).toISOString();
684
- const contents = message.contents;
685
- for (const content of contents) {
686
- if (content.type === "toolResultPart") {
687
- const { contents: contents2 } = content;
688
- for (const content2 of contents2) {
689
- if (content2.type === "textPart") {
690
- log(`${t} Tool Result: ${content2.text}`);
691
- } else if (content2.type === "imageInlinePart") {
692
- log(`${t} Tool Result: Inline image`);
693
- }
694
- }
53
+ case "azure-openai": {
54
+ const azure = createAzure({
55
+ apiKey: providerConfig.apiKey,
56
+ resourceName: providerConfig.resourceName,
57
+ apiVersion: providerConfig.apiVersion
58
+ });
59
+ return azure(modelId);
60
+ }
61
+ case "amazon-bedrock": {
62
+ const amazonBedrock = createAmazonBedrock({
63
+ accessKeyId: providerConfig.accessKeyId,
64
+ secretAccessKey: providerConfig.secretAccessKey,
65
+ region: providerConfig.region,
66
+ sessionToken: providerConfig.sessionToken
67
+ });
68
+ return amazonBedrock(modelId);
695
69
  }
696
70
  }
697
71
  }
698
- function logUsage(e) {
699
- const usageByGeneration = [
700
- `In: ${e.usage.promptTokens.toLocaleString()}`,
701
- `Out: ${e.usage.completionTokens.toLocaleString()}`,
702
- `Total: ${e.usage.totalTokens.toLocaleString()}`,
703
- `Cache-read: ${e.usage.cacheReadInputTokens.toLocaleString()}`,
704
- `Cache-write: ${e.usage.cacheCreationInputTokens.toLocaleString()}`
705
- ].join(", ");
706
- log(`${header(e)} Tokens usage: ${usageByGeneration}`);
707
- const usageByRun = [
708
- `In: ${e.usage.promptTokens.toLocaleString()}`,
709
- `Out: ${e.usage.completionTokens.toLocaleString()}`,
710
- `Total: ${e.usage.totalTokens.toLocaleString()}`,
711
- `Cache-read: ${e.usage.cacheReadInputTokens.toLocaleString()}`,
712
- `Cache-write: ${e.usage.cacheCreationInputTokens.toLocaleString()}`
713
- ].join(", ");
714
- log(`${header(e)} Total usage: ${usageByRun}`);
72
+ function getContextWindow(providerName, modelId) {
73
+ const modelConfig = knownModels.find((model) => model.provider === providerName)?.models.find((model) => model.name === modelId);
74
+ return modelConfig?.contextWindow;
715
75
  }
716
-
717
- // src/events/event-emitter.ts
718
- import { createId as createId2 } from "@paralleldrive/cuid2";
719
- var RunEventEmitter = class {
720
- listeners = [];
721
- subscribe(listener) {
722
- this.listeners.push(listener);
723
- }
724
- async emit(event) {
725
- for (const listener of this.listeners) {
726
- await listener({
727
- ...event,
728
- id: createId2(),
729
- timestamp: Date.now()
730
- });
731
- }
732
- }
733
- };
734
-
735
- // src/schemas/api-registry.ts
736
- import { z as z3 } from "zod";
737
- var RegistryV1ExpertSchema = z3.object({
738
- name: z3.string(),
739
- version: z3.string(),
740
- minRuntimeVersion: z3.string(),
741
- description: z3.string(),
742
- instruction: z3.string(),
743
- skills: z3.record(
744
- z3.string(),
745
- z3.discriminatedUnion("type", [
746
- McpStdioSkillSchema.omit({ name: true }),
747
- McpSseSkillSchema.omit({ name: true }),
748
- InteractiveSkillSchema.omit({ name: true })
749
- ])
750
- ),
751
- delegates: z3.array(z3.string()),
752
- tags: z3.array(z3.string()),
753
- status: z3.string(),
754
- owner: z3.object({ name: z3.string() }),
755
- createdAt: z3.iso.datetime(),
756
- updatedAt: z3.iso.datetime()
757
- });
758
- var RegistryV1ExpertsGetResponseSchema = z3.object({
759
- data: z3.object({
760
- expert: RegistryV1ExpertSchema
761
- })
762
- });
763
-
764
- // src/api-clinent.ts
765
- var Perstack = class {
766
- baseUrl;
767
- registry;
768
- apiKey;
769
- constructor(params) {
770
- this.baseUrl = params?.baseUrl ?? process.env.PERSTACK_API_BASE_URL ?? "https://api.perstack.ai";
771
- this.apiKey = params?.apiKey ?? process.env.PERSTACK_API_KEY;
772
- this.registry = new RegistryClientV1(this);
773
- }
774
- };
775
- var RegistryClientV1 = class {
776
- client;
777
- endpoint;
778
- constructor(client) {
779
- this.client = client;
780
- this.endpoint = "/api/registry/v1/experts";
781
- }
782
- async get(expertKey) {
783
- const safeExpertKey = encodeURIComponent(expertKey);
784
- const url = new URL(`${this.endpoint}/${safeExpertKey}`, this.client.baseUrl);
785
- const headers = {
786
- "Content-Type": "application/json",
787
- Authorization: `Bearer ${this.client.apiKey}`
788
- };
789
- const result = await fetch(url.toString(), { headers });
790
- if (!result.ok) {
791
- throw new Error(
792
- `Registry returned non-200 status code: ${result.status}, reason: ${result.statusText}`
793
- );
794
- }
795
- const json = await result.json();
796
- return RegistryV1ExpertsGetResponseSchema.parse(json);
797
- }
798
- };
799
-
800
- // src/resolve-expert-to-run.ts
801
- async function resolveExpertToRun(expertKey, experts) {
802
- if (experts[expertKey]) {
803
- return experts[expertKey];
804
- }
805
- const client = new Perstack();
806
- const { data } = await client.registry.get(expertKey);
807
- const expert = ExpertSchema.parse({
808
- ...data.expert,
809
- key: expertKey
810
- });
811
- experts[expertKey] = expert;
812
- return expert;
76
+ function calculateContextWindowUsage(usage, contextWindow) {
77
+ return (usage.inputTokens + usage.cachedInputTokens + usage.outputTokens) / contextWindow;
813
78
  }
814
-
815
- // src/runtime-state-machine.ts
816
- import { assign, setup } from "xstate";
817
-
818
- // src/skill-manager.ts
819
- import { Client as McpClient } from "@modelcontextprotocol/sdk/client/index.js";
820
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
821
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
822
- import { McpError } from "@modelcontextprotocol/sdk/types.js";
823
- import { createId as createId3 } from "@paralleldrive/cuid2";
824
- import { jsonSchema, tool } from "ai";
825
- import { ZodError } from "zod";
826
79
  var SkillManager = class {
827
80
  _toolDefinitions = [];
828
81
  _initialized = false;
@@ -833,6 +86,7 @@ var SkillManager = class {
833
86
  expert;
834
87
  _mcpClient;
835
88
  _params;
89
+ _env;
836
90
  constructor(params) {
837
91
  this._params = params;
838
92
  this.type = params.type;
@@ -840,14 +94,17 @@ var SkillManager = class {
840
94
  case "mcp":
841
95
  this.name = params.skill.name;
842
96
  this.skill = params.skill;
97
+ this._env = params.env;
843
98
  break;
844
99
  case "interactive":
845
100
  this.name = params.interactiveSkill.name;
846
101
  this.interactiveSkill = params.interactiveSkill;
102
+ this._env = {};
847
103
  break;
848
104
  case "delegate":
849
105
  this.name = params.expert.name;
850
106
  this.expert = params.expert;
107
+ this._env = {};
851
108
  break;
852
109
  }
853
110
  }
@@ -868,7 +125,7 @@ var SkillManager = class {
868
125
  }
869
126
  }
870
127
  async _initMcpSkill(params) {
871
- this._mcpClient = new McpClient({
128
+ this._mcpClient = new Client({
872
129
  name: `${params.skill.name}-mcp-client`,
873
130
  version: "1.0.0"
874
131
  });
@@ -877,14 +134,16 @@ var SkillManager = class {
877
134
  if (!params.skill.command) {
878
135
  throw new Error(`Skill ${params.skill.name} has no command`);
879
136
  }
137
+ const env = {};
138
+ const { requiredEnv } = params.skill;
139
+ for (const envName of requiredEnv) {
140
+ if (!this._env[envName]) {
141
+ throw new Error(`Skill ${params.skill.name} requires environment variable ${envName}`);
142
+ }
143
+ env[envName] = this._env[envName];
144
+ }
880
145
  const { command, args } = this._getCommandArgs(params.skill);
881
- const transport = new StdioClientTransport({
882
- command,
883
- args,
884
- env: Object.fromEntries(
885
- Object.entries(process.env).filter(([_, value]) => value !== void 0 && value !== "").map(([key, value]) => [key, value])
886
- )
887
- });
146
+ const transport = new StdioClientTransport({ command, args, env });
888
147
  await this._mcpClient.connect(transport);
889
148
  break;
890
149
  }
@@ -995,13 +254,10 @@ var SkillManager = class {
995
254
  {
996
255
  type: "textPart",
997
256
  text: `Error calling tool ${toolName}: ${error.message}`,
998
- id: createId3()
257
+ id: createId()
999
258
  }
1000
259
  ];
1001
260
  }
1002
- if (error instanceof ZodError) {
1003
- return [{ type: "textPart", text: `Invalid tool call arguments: ${error}`, id: createId3() }];
1004
- }
1005
261
  throw error;
1006
262
  }
1007
263
  _convertToolResult(result, toolName, input) {
@@ -1010,7 +266,7 @@ var SkillManager = class {
1010
266
  {
1011
267
  type: "textPart",
1012
268
  text: `Tool ${toolName} returned nothing with arguments: ${JSON.stringify(input)}`,
1013
- id: createId3()
269
+ id: createId()
1014
270
  }
1015
271
  ];
1016
272
  }
@@ -1020,9 +276,9 @@ var SkillManager = class {
1020
276
  switch (part.type) {
1021
277
  case "text":
1022
278
  if (!part.text || part.text === "") {
1023
- return { type: "textPart", text: "Error: No content", id: createId3() };
279
+ return { type: "textPart", text: "Error: No content", id: createId() };
1024
280
  }
1025
- return { type: "textPart", text: part.text, id: createId3() };
281
+ return { type: "textPart", text: part.text, id: createId() };
1026
282
  case "image":
1027
283
  if (!part.data || !part.mimeType) {
1028
284
  throw new Error("Image part must have both data and mimeType");
@@ -1031,7 +287,7 @@ var SkillManager = class {
1031
287
  type: "imageInlinePart",
1032
288
  encodedData: part.data,
1033
289
  mimeType: part.mimeType,
1034
- id: createId3()
290
+ id: createId()
1035
291
  };
1036
292
  case "resource":
1037
293
  if (!part.resource) {
@@ -1045,39 +301,36 @@ var SkillManager = class {
1045
301
  throw new Error(`Resource ${JSON.stringify(resource)} has no mimeType`);
1046
302
  }
1047
303
  if (resource.text && typeof resource.text === "string") {
1048
- return { type: "textPart", text: resource.text, id: createId3() };
304
+ return { type: "textPart", text: resource.text, id: createId() };
1049
305
  }
1050
306
  if (resource.blob && typeof resource.blob === "string") {
1051
307
  return {
1052
308
  type: "fileInlinePart",
1053
309
  encodedData: resource.blob,
1054
310
  mimeType: resource.mimeType,
1055
- id: createId3()
311
+ id: createId()
1056
312
  };
1057
313
  }
1058
314
  throw new Error(`Unsupported resource type: ${JSON.stringify(resource)}`);
1059
315
  }
1060
316
  };
1061
- async function getSkillManagers(expert, experts) {
317
+ async function getSkillManagers(expert, experts, setting) {
318
+ const { perstackBaseSkillArgs, env } = setting;
1062
319
  const skillManagers = {};
1063
320
  const { skills } = expert;
1064
321
  if (!skills["@perstack/base"]) {
1065
- skills["@perstack/base"] = {
1066
- type: "mcpStdioSkill",
1067
- name: "@perstack/base",
1068
- description: "The base skill for Perstack",
1069
- pick: [],
1070
- omit: [],
1071
- command: "npx",
1072
- args: ["-y", "@perstack/base"],
1073
- requiredEnv: []
1074
- };
322
+ throw new Error("Base skill is not defined");
1075
323
  }
1076
324
  const mcpSkillManagers = await Promise.all(
1077
325
  Object.values(skills).filter((skill) => skill.type === "mcpStdioSkill" || skill.type === "mcpSseSkill").map(async (skill) => {
326
+ if (perstackBaseSkillArgs && skill.type === "mcpStdioSkill" && skill.name === "@perstack/base") {
327
+ skill.packageName = void 0;
328
+ skill.args = ["-y", ...perstackBaseSkillArgs];
329
+ }
1078
330
  const skillManager = new SkillManager({
1079
331
  type: "mcp",
1080
- skill
332
+ skill,
333
+ env
1081
334
  });
1082
335
  await skillManager.init();
1083
336
  return skillManager;
@@ -1152,12 +405,12 @@ async function callingDelegateLogic({
1152
405
  step,
1153
406
  skillManagers
1154
407
  }) {
1155
- if (!step?.toolCall) {
408
+ if (!step.toolCall) {
1156
409
  throw new Error("No tool call found");
1157
410
  }
1158
411
  const { id, toolName, args } = step.toolCall;
1159
412
  const skillManager = await getSkillManagerByToolName(skillManagers, toolName);
1160
- if (!skillManager || !skillManager.expert) {
413
+ if (!skillManager.expert) {
1161
414
  throw new Error(`Delegation error: skill manager "${toolName}" not found`);
1162
415
  }
1163
416
  if (!args || !args.query || typeof args.query !== "string") {
@@ -1184,8 +437,6 @@ async function callingDelegateLogic({
1184
437
  }
1185
438
  });
1186
439
  }
1187
-
1188
- // src/states/calling-interactive-tool.ts
1189
440
  async function callingInteractiveToolLogic({
1190
441
  setting,
1191
442
  checkpoint,
@@ -1202,15 +453,13 @@ async function callingInteractiveToolLogic({
1202
453
  }
1203
454
  });
1204
455
  }
1205
-
1206
- // src/states/calling-tool.ts
1207
456
  async function callingToolLogic({
1208
457
  setting,
1209
458
  checkpoint,
1210
459
  step,
1211
460
  skillManagers
1212
461
  }) {
1213
- if (!step?.toolCall) {
462
+ if (!step.toolCall) {
1214
463
  throw new Error("No tool call found");
1215
464
  }
1216
465
  const { id, skillName, toolName, args } = step.toolCall;
@@ -1236,9 +485,6 @@ async function callingToolLogic({
1236
485
  }
1237
486
  return resolveToolResult(setting, checkpoint, { toolResult });
1238
487
  }
1239
-
1240
- // src/states/finishing-step.ts
1241
- import { createId as createId4 } from "@paralleldrive/cuid2";
1242
488
  async function finishingStepLogic({
1243
489
  setting,
1244
490
  checkpoint,
@@ -1266,26 +512,19 @@ async function finishingStepLogic({
1266
512
  },
1267
513
  nextCheckpoint: {
1268
514
  ...checkpoint,
1269
- id: createId4(),
515
+ id: createId(),
1270
516
  stepNumber: checkpoint.stepNumber + 1
1271
517
  }
1272
518
  });
1273
519
  }
1274
-
1275
- // src/states/generating-run-result.ts
1276
- import { generateText } from "ai";
1277
-
1278
- // src/messages/message.ts
1279
- import { createId as createId5 } from "@paralleldrive/cuid2";
1280
- import { dedent } from "ts-dedent";
1281
520
  function createUserMessage(contents) {
1282
521
  return {
1283
522
  type: "userMessage",
1284
523
  contents: contents.map((part) => ({
1285
524
  ...part,
1286
- id: createId5()
525
+ id: createId()
1287
526
  })),
1288
- id: createId5()
527
+ id: createId()
1289
528
  };
1290
529
  }
1291
530
  function createExpertMessage(contents) {
@@ -1293,9 +532,9 @@ function createExpertMessage(contents) {
1293
532
  type: "expertMessage",
1294
533
  contents: contents.map((part) => ({
1295
534
  ...part,
1296
- id: createId5()
535
+ id: createId()
1297
536
  })),
1298
- id: createId5()
537
+ id: createId()
1299
538
  };
1300
539
  }
1301
540
  function createToolMessage(contents) {
@@ -1305,11 +544,11 @@ function createToolMessage(contents) {
1305
544
  ...part,
1306
545
  contents: part.contents.map((part2) => ({
1307
546
  ...part2,
1308
- id: createId5()
547
+ id: createId()
1309
548
  })),
1310
- id: createId5()
549
+ id: createId()
1311
550
  })),
1312
- id: createId5()
551
+ id: createId()
1313
552
  };
1314
553
  }
1315
554
  function messageToCoreMessage(message) {
@@ -1476,36 +715,29 @@ function toolResultPartToCoreToolResultPart(part) {
1476
715
  // src/usage.ts
1477
716
  function createEmptyUsage() {
1478
717
  return {
1479
- promptTokens: 0,
1480
- completionTokens: 0,
718
+ inputTokens: 0,
719
+ outputTokens: 0,
720
+ reasoningTokens: 0,
1481
721
  totalTokens: 0,
1482
- cacheCreationInputTokens: 0,
1483
- cacheReadInputTokens: 0
722
+ cachedInputTokens: 0
1484
723
  };
1485
724
  }
1486
725
  function usageFromGenerateTextResult(result) {
1487
- let cacheCreationInputTokens = 0;
1488
- let cacheReadInputTokens = 0;
1489
- if (result.providerMetadata?.anthropic) {
1490
- const anthropicMetadata = result.providerMetadata.anthropic;
1491
- cacheCreationInputTokens = anthropicMetadata.cacheCreationInputTokens || 0;
1492
- cacheReadInputTokens = anthropicMetadata.cacheReadInputTokens || 0;
1493
- }
1494
726
  return {
1495
- promptTokens: result.usage.inputTokens || 0,
1496
- completionTokens: result.usage.outputTokens || 0,
727
+ inputTokens: result.usage.inputTokens || 0,
728
+ outputTokens: result.usage.outputTokens || 0,
729
+ reasoningTokens: result.usage.reasoningTokens || 0,
1497
730
  totalTokens: result.usage.totalTokens || 0,
1498
- cacheCreationInputTokens,
1499
- cacheReadInputTokens
731
+ cachedInputTokens: result.usage.cachedInputTokens || 0
1500
732
  };
1501
733
  }
1502
734
  function sumUsage(a, b) {
1503
735
  return {
1504
- promptTokens: a.promptTokens + b.promptTokens,
1505
- completionTokens: a.completionTokens + b.completionTokens,
736
+ inputTokens: a.inputTokens + b.inputTokens,
737
+ outputTokens: a.outputTokens + b.outputTokens,
738
+ reasoningTokens: a.reasoningTokens + b.reasoningTokens,
1506
739
  totalTokens: a.totalTokens + b.totalTokens,
1507
- cacheCreationInputTokens: a.cacheCreationInputTokens + b.cacheCreationInputTokens,
1508
- cacheReadInputTokens: a.cacheReadInputTokens + b.cacheReadInputTokens
740
+ cachedInputTokens: a.cachedInputTokens + b.cachedInputTokens
1509
741
  };
1510
742
  }
1511
743
 
@@ -1515,7 +747,7 @@ async function generatingRunResultLogic({
1515
747
  checkpoint,
1516
748
  step
1517
749
  }) {
1518
- if (!step?.toolCall || !step?.toolResult) {
750
+ if (!step.toolCall || !step.toolResult) {
1519
751
  throw new Error("No tool call or tool result found");
1520
752
  }
1521
753
  const { id, toolName } = step.toolCall;
@@ -1530,7 +762,7 @@ async function generatingRunResultLogic({
1530
762
  )
1531
763
  }
1532
764
  ]);
1533
- const model = getModel(setting.model);
765
+ const model = getModel(setting.model, setting.providerConfig);
1534
766
  const { messages } = checkpoint;
1535
767
  let generationResult;
1536
768
  try {
@@ -1543,17 +775,11 @@ async function generatingRunResultLogic({
1543
775
  });
1544
776
  } catch (error) {
1545
777
  if (error instanceof Error) {
778
+ const reason = JSON.stringify({ error: error.name, message: error.message });
1546
779
  return retry(setting, checkpoint, {
1547
- newMessages: [
1548
- toolMessage,
1549
- createUserMessage([
1550
- {
1551
- type: "textPart",
1552
- text: JSON.stringify({ error: error.name, message: error.message })
1553
- }
1554
- ])
1555
- ],
1556
- usage: checkpoint.usage
780
+ reason,
781
+ newMessages: [toolMessage, createUserMessage([{ type: "textPart", text: reason }])],
782
+ usage: createEmptyUsage()
1557
783
  });
1558
784
  }
1559
785
  throw error;
@@ -1566,6 +792,7 @@ async function generatingRunResultLogic({
1566
792
  ...checkpoint,
1567
793
  messages: [...messages, ...newMessages],
1568
794
  usage: sumUsage(checkpoint.usage, usage),
795
+ contextWindowUsage: checkpoint.contextWindow ? calculateContextWindowUsage(usage, checkpoint.contextWindow) : void 0,
1569
796
  status: "completed"
1570
797
  },
1571
798
  step: {
@@ -1578,20 +805,16 @@ async function generatingRunResultLogic({
1578
805
  usage
1579
806
  });
1580
807
  }
1581
-
1582
- // src/states/generating-tool-call.ts
1583
- import { createId as createId6 } from "@paralleldrive/cuid2";
1584
- import { generateText as generateText2 } from "ai";
1585
808
  async function generatingToolCallLogic({
1586
809
  setting,
1587
810
  checkpoint,
1588
811
  skillManagers
1589
812
  }) {
1590
813
  const { messages } = checkpoint;
1591
- const model = getModel(setting.model);
814
+ const model = getModel(setting.model, setting.providerConfig);
1592
815
  let result;
1593
816
  try {
1594
- result = await generateText2({
817
+ result = await generateText({
1595
818
  model,
1596
819
  messages: messages.map(messageToCoreMessage),
1597
820
  temperature: setting.temperature,
@@ -1602,16 +825,12 @@ async function generatingToolCallLogic({
1602
825
  });
1603
826
  } catch (error) {
1604
827
  if (error instanceof Error) {
828
+ console.error(error);
829
+ const reason = JSON.stringify({ error: error.name, message: error.message });
1605
830
  return retry(setting, checkpoint, {
1606
- newMessages: [
1607
- createUserMessage([
1608
- {
1609
- type: "textPart",
1610
- text: JSON.stringify({ error: error.name, message: error.message })
1611
- }
1612
- ])
1613
- ],
1614
- usage: checkpoint.usage
831
+ reason,
832
+ newMessages: [createUserMessage([{ type: "textPart", text: reason }])],
833
+ usage: createEmptyUsage()
1615
834
  });
1616
835
  }
1617
836
  throw error;
@@ -1620,18 +839,13 @@ async function generatingToolCallLogic({
1620
839
  const { text, toolCalls, finishReason } = result;
1621
840
  const toolCall = toolCalls[0];
1622
841
  if (!toolCall) {
842
+ const reason = JSON.stringify({
843
+ error: "Error: No tool call generated",
844
+ message: "You must generate a tool call. Try again."
845
+ });
1623
846
  return retry(setting, checkpoint, {
1624
- newMessages: [
1625
- createUserMessage([
1626
- {
1627
- type: "textPart",
1628
- text: JSON.stringify({
1629
- error: "Error: No tool call generated",
1630
- message: "You must generate a tool call. Try again."
1631
- })
1632
- }
1633
- ])
1634
- ],
847
+ reason,
848
+ newMessages: [createUserMessage([{ type: "textPart", text: reason }])],
1635
849
  usage
1636
850
  });
1637
851
  }
@@ -1660,7 +874,7 @@ async function generatingToolCallLogic({
1660
874
  },
1661
875
  usage
1662
876
  };
1663
- if (finishReason === "tool-calls") {
877
+ if (finishReason === "tool-calls" || finishReason === "stop") {
1664
878
  switch (skillManager.type) {
1665
879
  case "mcp":
1666
880
  return callTool(setting, checkpoint, eventPayload);
@@ -1671,7 +885,12 @@ async function generatingToolCallLogic({
1671
885
  }
1672
886
  }
1673
887
  if (finishReason === "length") {
888
+ const reason = JSON.stringify({
889
+ error: "Error: Tool call generation failed",
890
+ message: "Generation length exceeded. Try again."
891
+ });
1674
892
  return retry(setting, checkpoint, {
893
+ reason,
1675
894
  newMessages: [
1676
895
  createExpertMessage([
1677
896
  {
@@ -1686,15 +905,7 @@ async function generatingToolCallLogic({
1686
905
  type: "toolResultPart",
1687
906
  toolCallId: toolCall.toolCallId,
1688
907
  toolName: toolCall.toolName,
1689
- contents: [
1690
- {
1691
- type: "textPart",
1692
- text: JSON.stringify({
1693
- error: "Error: Tool call generation failed",
1694
- message: "Generation length exceeded. Try again."
1695
- })
1696
- }
1697
- ]
908
+ contents: [{ type: "textPart", text: reason }]
1698
909
  }
1699
910
  ])
1700
911
  ],
@@ -1703,27 +914,14 @@ async function generatingToolCallLogic({
1703
914
  id: toolCall.toolCallId,
1704
915
  skillName: skillManager.name,
1705
916
  toolName: toolCall.toolName,
1706
- result: [
1707
- {
1708
- type: "textPart",
1709
- id: createId6(),
1710
- text: JSON.stringify({
1711
- error: "Error: Tool call generation failed",
1712
- message: "Generation length exceeded. Try again."
1713
- })
1714
- }
1715
- ]
917
+ result: [{ type: "textPart", id: createId(), text: reason }]
1716
918
  },
1717
919
  usage
1718
920
  });
1719
921
  }
1720
922
  throw new Error(`Unexpected finish reason: ${finishReason}`);
1721
923
  }
1722
-
1723
- // src/messages/instruction-message.ts
1724
- import { createId as createId7 } from "@paralleldrive/cuid2";
1725
- import { dedent as dedent2 } from "ts-dedent";
1726
- var metaInstruction = dedent2`
924
+ var metaInstruction = dedent`
1727
925
  IMPORTANT:
1728
926
  You are NOT an "interactive" AI agent.
1729
927
  From the start of the agent loop until the completion of the task,
@@ -1741,33 +939,32 @@ var metaInstruction = dedent2`
1741
939
  5. Notify Task Completion: Call the attemptCompletion tool to inform the user when the task is complete
1742
940
  6. Generate Final Results: Produce a final result that clearly describes each task you performed, step by step
1743
941
 
1744
- エージェントループの終了条件:
1745
- 以下の条件に該当した場合は、**即座にattemptCompletionツールを呼び出してください**。
1746
- エージェントループを終了しなければならない状況で、attemptCompletion以外のツールを呼び出すことは非常に危険です。
1747
- 絶対に、何があってもこのルールは守るようにしてください。
1748
- - タスクが完了した時
1749
- - ユーザーの依頼があなたの専門外だった時
1750
- - ユーザーが倫理的に不正な要求をした時
1751
- - ユーザーの依頼が理解不能である時
1752
- - ユーザーの依頼によって、セキュリティに危険が生じる恐れがある時
1753
- - ユーザーの依頼によって、他人に迷惑をかける恐れがある時
1754
- - ユーザーの依頼に、不適切な言葉や、性的な内容が含まれている時
942
+ Conditions for ending the agent loop:
943
+ If any of the following apply, **immediately call the attemptCompletion tool**.
944
+ When the agent loop must end, calling any tool other than attemptCompletion is highly dangerous.
945
+ Under all circumstances, strictly follow this rule.
946
+ - When the task is complete
947
+ - When the user's request is outside your expertise
948
+ - When the user makes an unethical request
949
+ - When the user's request is unintelligible
950
+ - When the request may pose security risks
951
+ - When the request may harm or inconvenience others
952
+ - When the request contains inappropriate or sexual content
1755
953
 
1756
954
  Rules for requests outside your area of expertise:
1757
955
  - Tell your area of expertise to the user in final results
1758
- - In the Final Result, you can show the user how to create an expert that they might need; This can be done by running the \`parrot new\` (no arguments required) command.
1759
956
 
1760
- 全般的なタスクの取り組み方や、アウトプット品質に関するルール:
1761
- - ユーザはあなたのことを、その分野の『専門家』であると認識しています
1762
- - 専門家である以上、タスクの実行においては、徹底した考察を行いつつ、確証を持って一つ一つのタスクを実行してください
1763
- - 専門家である以上、ユーザーが期待する以上の品質のアウトプットを行ってください
957
+ General approach and output quality rules:
958
+ - The user recognizes you as an expert in this domain
959
+ - As an expert, execute each step with thorough reasoning and high confidence
960
+ - As an expert, deliver output exceeding the user's expectations
1764
961
 
1765
962
  Environment information:
1766
963
  - Current time is ${(/* @__PURE__ */ new Date()).toISOString()}
1767
964
  - Current working directory is ${process.cwd()}
1768
965
  `;
1769
966
  function createInstructionMessage(expert, experts) {
1770
- const instruction = dedent2`
967
+ const instruction = dedent`
1771
968
  You are Perstack, an AI expert that tackles tasks requested by users by utilizing all available tools.
1772
969
 
1773
970
  (The following information describes your nature and role as an AI, the mechanisms of the AI system, and other meta-cognitive aspects.)
@@ -1795,12 +992,12 @@ function createInstructionMessage(expert, experts) {
1795
992
  type: "instructionMessage",
1796
993
  contents: [
1797
994
  {
1798
- id: createId7(),
995
+ id: createId(),
1799
996
  type: "textPart",
1800
997
  text: instruction
1801
998
  }
1802
999
  ],
1803
- id: createId7(),
1000
+ id: createId(),
1804
1001
  cache: true
1805
1002
  };
1806
1003
  }
@@ -1809,7 +1006,7 @@ function getSkillRules(expert) {
1809
1006
  if (!skill.rule) {
1810
1007
  return acc;
1811
1008
  }
1812
- return dedent2`
1009
+ return dedent`
1813
1010
  ${acc}
1814
1011
 
1815
1012
  "${skill.name}" skill rules:
@@ -1823,7 +1020,7 @@ function getDelegateRules(expert, experts) {
1823
1020
  if (!delegate) {
1824
1021
  return acc;
1825
1022
  }
1826
- return dedent2`
1023
+ return dedent`
1827
1024
  ${acc}
1828
1025
 
1829
1026
  About "${delegate.name}":
@@ -1847,33 +1044,12 @@ async function initLogic({
1847
1044
  return startRun(setting, checkpoint, {
1848
1045
  initialCheckpoint: checkpoint,
1849
1046
  inputMessages: [
1850
- createInstructionMessage(expert, experts),
1851
- createUserMessage([{ type: "textPart", text: setting.input.text }])
1852
- ]
1853
- });
1854
- }
1855
- case "proceeding": {
1856
- if (!setting.input.text) {
1857
- throw new Error("Input message is undefined");
1858
- }
1859
- return startRun(setting, checkpoint, {
1860
- initialCheckpoint: checkpoint,
1861
- inputMessages: [createUserMessage([{ type: "textPart", text: setting.input.text }])]
1862
- });
1863
- }
1864
- case "stoppedByDelegate": {
1865
- if (!setting.input.interactiveToolCallResult) {
1866
- throw new Error("Interactive tool call result is undefined");
1867
- }
1868
- return startRun(setting, checkpoint, {
1869
- initialCheckpoint: checkpoint,
1870
- inputMessages: [
1871
- createUserMessage([
1872
- { type: "textPart", text: setting.input.interactiveToolCallResult.text }
1873
- ])
1047
+ createInstructionMessage(expert, experts),
1048
+ createUserMessage([{ type: "textPart", text: setting.input.text }])
1874
1049
  ]
1875
1050
  });
1876
1051
  }
1052
+ case "stoppedByDelegate":
1877
1053
  case "stoppedByInteractiveTool": {
1878
1054
  if (!setting.input.interactiveToolCallResult) {
1879
1055
  throw new Error("Interactive tool call result is undefined");
@@ -1893,11 +1069,15 @@ async function initLogic({
1893
1069
  });
1894
1070
  }
1895
1071
  default:
1896
- throw new Error(`Unexpected checkpoint status: ${checkpoint.status}`);
1072
+ if (!setting.input.text) {
1073
+ throw new Error("Input message is undefined");
1074
+ }
1075
+ return startRun(setting, checkpoint, {
1076
+ initialCheckpoint: checkpoint,
1077
+ inputMessages: [createUserMessage([{ type: "textPart", text: setting.input.text }])]
1078
+ });
1897
1079
  }
1898
1080
  }
1899
-
1900
- // src/states/preparing-for-step.ts
1901
1081
  async function preparingForStepLogic({
1902
1082
  setting,
1903
1083
  checkpoint
@@ -1906,15 +1086,12 @@ async function preparingForStepLogic({
1906
1086
  messages: checkpoint.messages
1907
1087
  });
1908
1088
  }
1909
-
1910
- // src/states/resolving-image-file.ts
1911
- import { readFile as readFile2 } from "fs/promises";
1912
1089
  async function resolvingImageFileLogic({
1913
1090
  setting,
1914
1091
  checkpoint,
1915
1092
  step
1916
1093
  }) {
1917
- if (!step?.toolCall || !step?.toolResult) {
1094
+ if (!step.toolCall || !step.toolResult) {
1918
1095
  throw new Error("No tool call or tool result found");
1919
1096
  }
1920
1097
  const { id, toolName } = step.toolCall;
@@ -1933,7 +1110,7 @@ async function resolvingImageFileLogic({
1933
1110
  continue;
1934
1111
  }
1935
1112
  const { path: path2, mimeType, size } = imageInfo;
1936
- const file = await readFile2(path2).then((buffer) => ({
1113
+ const file = await readFile(path2).then((buffer) => ({
1937
1114
  encodedData: buffer.toString("base64"),
1938
1115
  mimeType,
1939
1116
  size
@@ -1957,15 +1134,12 @@ async function resolvingImageFileLogic({
1957
1134
  ]
1958
1135
  });
1959
1136
  }
1960
-
1961
- // src/states/resolving-pdf-file.ts
1962
- import { readFile as readFile3 } from "fs/promises";
1963
1137
  async function resolvingPdfFileLogic({
1964
1138
  setting,
1965
1139
  checkpoint,
1966
1140
  step
1967
1141
  }) {
1968
- if (!step?.toolCall || !step?.toolResult) {
1142
+ if (!step.toolCall || !step.toolResult) {
1969
1143
  throw new Error("No tool call or tool result found");
1970
1144
  }
1971
1145
  const { id, toolName } = step.toolCall;
@@ -1984,7 +1158,7 @@ async function resolvingPdfFileLogic({
1984
1158
  continue;
1985
1159
  }
1986
1160
  const { path: path2, mimeType, size } = pdfInfo;
1987
- const file = await readFile3(path2).then((buffer) => ({
1161
+ const file = await readFile(path2).then((buffer) => ({
1988
1162
  encodedData: buffer.toString("base64"),
1989
1163
  mimeType,
1990
1164
  size
@@ -2014,14 +1188,12 @@ async function resolvingPdfFileLogic({
2014
1188
  ]
2015
1189
  });
2016
1190
  }
2017
-
2018
- // src/states/resolving-tool-result.ts
2019
1191
  async function resolvingToolResultLogic({
2020
1192
  setting,
2021
1193
  checkpoint,
2022
1194
  step
2023
1195
  }) {
2024
- if (!step?.toolCall || !step?.toolResult) {
1196
+ if (!step.toolCall || !step.toolResult) {
2025
1197
  throw new Error("No tool call or tool result found");
2026
1198
  }
2027
1199
  const { id, toolName } = step.toolCall;
@@ -2077,17 +1249,14 @@ var runtimeStateMachine = setup({
2077
1249
  startRun: {
2078
1250
  target: "PreparingForStep",
2079
1251
  actions: assign({
2080
- checkpoint: ({ event }) => ({
2081
- ...event.initialCheckpoint,
2082
- messages: [...event.initialCheckpoint.messages, ...event.inputMessages],
2083
- status: "proceeding"
1252
+ checkpoint: ({ context, event }) => ({
1253
+ ...context.checkpoint,
1254
+ status: "proceeding",
1255
+ messages: [...context.checkpoint.messages, ...event.inputMessages]
2084
1256
  }),
2085
- step: ({ event }) => ({
2086
- stepNumber: event.initialCheckpoint.stepNumber,
2087
- inputMessages: event.inputMessages,
2088
- newMessages: [],
2089
- usage: createEmptyUsage(),
2090
- startedAt: event.timestamp
1257
+ step: ({ context, event }) => ({
1258
+ ...context.step,
1259
+ inputMessages: event.inputMessages
2091
1260
  })
2092
1261
  })
2093
1262
  }
@@ -2100,7 +1269,7 @@ var runtimeStateMachine = setup({
2100
1269
  actions: assign({
2101
1270
  step: ({ context, event }) => ({
2102
1271
  stepNumber: context.checkpoint.stepNumber,
2103
- inputMessages: context.step.inputMessages,
1272
+ inputMessages: context.step.inputMessages ?? [],
2104
1273
  newMessages: [],
2105
1274
  usage: createEmptyUsage(),
2106
1275
  startedAt: event.timestamp
@@ -2134,7 +1303,8 @@ var runtimeStateMachine = setup({
2134
1303
  checkpoint: ({ context, event }) => ({
2135
1304
  ...context.checkpoint,
2136
1305
  messages: [...context.checkpoint.messages, event.newMessage],
2137
- usage: sumUsage(context.checkpoint.usage, event.usage)
1306
+ usage: sumUsage(context.checkpoint.usage, event.usage),
1307
+ contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(event.usage, context.checkpoint.contextWindow) : void 0
2138
1308
  }),
2139
1309
  step: ({ context, event }) => ({
2140
1310
  ...context.step,
@@ -2150,7 +1320,8 @@ var runtimeStateMachine = setup({
2150
1320
  checkpoint: ({ context, event }) => ({
2151
1321
  ...context.checkpoint,
2152
1322
  messages: [...context.checkpoint.messages, event.newMessage],
2153
- usage: sumUsage(context.checkpoint.usage, event.usage)
1323
+ usage: sumUsage(context.checkpoint.usage, event.usage),
1324
+ contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(event.usage, context.checkpoint.contextWindow) : void 0
2154
1325
  }),
2155
1326
  step: ({ context, event }) => ({
2156
1327
  ...context.step,
@@ -2166,7 +1337,8 @@ var runtimeStateMachine = setup({
2166
1337
  checkpoint: ({ context, event }) => ({
2167
1338
  ...context.checkpoint,
2168
1339
  messages: [...context.checkpoint.messages, event.newMessage],
2169
- usage: sumUsage(context.checkpoint.usage, event.usage)
1340
+ usage: sumUsage(context.checkpoint.usage, event.usage),
1341
+ contextWindowUsage: context.checkpoint.contextWindow ? calculateContextWindowUsage(event.usage, context.checkpoint.contextWindow) : void 0
2170
1342
  }),
2171
1343
  step: ({ context, event }) => ({
2172
1344
  ...context.step,
@@ -2318,7 +1490,10 @@ var runtimeStateMachine = setup({
2318
1490
  target: "Stopped",
2319
1491
  actions: assign({
2320
1492
  checkpoint: ({ event }) => event.checkpoint,
2321
- step: ({ event }) => event.step
1493
+ step: ({ event }) => ({
1494
+ ...event.step,
1495
+ inputMessages: void 0
1496
+ })
2322
1497
  })
2323
1498
  }
2324
1499
  }
@@ -2329,7 +1504,10 @@ var runtimeStateMachine = setup({
2329
1504
  target: "Stopped",
2330
1505
  actions: assign({
2331
1506
  checkpoint: ({ event }) => event.checkpoint,
2332
- step: ({ event }) => event.step
1507
+ step: ({ event }) => ({
1508
+ ...event.step,
1509
+ inputMessages: void 0
1510
+ })
2333
1511
  })
2334
1512
  }
2335
1513
  }
@@ -2340,7 +1518,10 @@ var runtimeStateMachine = setup({
2340
1518
  target: "Stopped",
2341
1519
  actions: assign({
2342
1520
  checkpoint: ({ event }) => event.checkpoint,
2343
- step: ({ event }) => event.step
1521
+ step: ({ event }) => ({
1522
+ ...event.step,
1523
+ inputMessages: void 0
1524
+ })
2344
1525
  })
2345
1526
  }
2346
1527
  }
@@ -2389,75 +1570,272 @@ var StateMachineLogics = {
2389
1570
  CallingDelegate: callingDelegateLogic,
2390
1571
  FinishingStep: finishingStepLogic
2391
1572
  };
1573
+ async function defaultRetrieveCheckpoint(runId, checkpointId) {
1574
+ const runDir = getRunDir(runId);
1575
+ const checkpointFiles = await readdir(runDir, { withFileTypes: true }).then(
1576
+ (files) => files.filter((file) => file.isFile() && file.name.startsWith("checkpoint-"))
1577
+ );
1578
+ const checkpointFile = checkpointFiles.find((file) => file.name.endsWith(`-${checkpointId}.json`));
1579
+ if (!checkpointFile) {
1580
+ throw new Error(`checkpoint not found: ${runId} ${checkpointId}`);
1581
+ }
1582
+ const checkpointPath = `${runDir}/${checkpointFile.name}`;
1583
+ const checkpoint = await readFile(checkpointPath, "utf8");
1584
+ return checkpointSchema.parse(JSON.parse(checkpoint));
1585
+ }
1586
+ async function defaultStoreCheckpoint(checkpoint, timestamp) {
1587
+ const { id, runId, stepNumber } = checkpoint;
1588
+ const runDir = getRunDir(runId);
1589
+ const checkpointPath = `${runDir}/checkpoint-${timestamp}-${stepNumber}-${id}.json`;
1590
+ await mkdir(runDir, { recursive: true });
1591
+ await writeFile(checkpointPath, JSON.stringify(checkpoint, null, 2));
1592
+ }
1593
+ async function defaultStoreEvent(event) {
1594
+ const { timestamp, runId, stepNumber, type } = event;
1595
+ const runDir = getRunDir(runId);
1596
+ const eventPath = `${runDir}/event-${timestamp}-${stepNumber}-${type}.json`;
1597
+ await mkdir(runDir, { recursive: true });
1598
+ await writeFile(eventPath, JSON.stringify(event, null, 2));
1599
+ }
2392
1600
 
2393
- // src/schemas/perstack-toml.ts
2394
- import { z as z4 } from "zod";
2395
- var PerstackConfigSchema = z4.object({
2396
- model: z4.string().optional(),
2397
- temperature: z4.number().optional(),
2398
- maxSteps: z4.number().optional(),
2399
- maxRetries: z4.number().optional(),
2400
- timeout: z4.number().optional(),
2401
- experts: z4.record(
2402
- z4.string(),
2403
- z4.object({
2404
- version: z4.string().optional(),
2405
- minRuntimeVersion: z4.string().optional(),
2406
- description: z4.string().optional(),
2407
- instruction: z4.string(),
2408
- skills: z4.record(
2409
- z4.string(),
2410
- z4.discriminatedUnion("type", [
2411
- z4.object({
2412
- type: z4.literal("mcpStdioSkill"),
2413
- description: z4.string().optional(),
2414
- rule: z4.string().optional(),
2415
- pick: z4.array(z4.string()).optional(),
2416
- omit: z4.array(z4.string()).optional(),
2417
- command: z4.string(),
2418
- packageName: z4.string().optional(),
2419
- args: z4.array(z4.string()).optional(),
2420
- requiredEnv: z4.array(z4.string()).optional()
2421
- }),
2422
- z4.object({
2423
- type: z4.literal("mcpSseSkill"),
2424
- description: z4.string().optional(),
2425
- rule: z4.string().optional(),
2426
- pick: z4.array(z4.string()).optional(),
2427
- omit: z4.array(z4.string()).optional(),
2428
- endpoint: z4.string()
2429
- }),
2430
- z4.object({
2431
- type: z4.literal("interactiveSkill"),
2432
- description: z4.string().optional(),
2433
- rule: z4.string().optional(),
2434
- tools: z4.record(
2435
- z4.string(),
2436
- z4.object({
2437
- description: z4.string().optional(),
2438
- inputJsonSchema: z4.string()
2439
- })
2440
- )
2441
- })
2442
- ])
2443
- ).optional(),
2444
- delegates: z4.array(z4.string()).optional()
1601
+ // package.json
1602
+ var package_default = {
1603
+ version: "0.0.25"};
1604
+
1605
+ // src/events/default-event-listener.ts
1606
+ var log = console.info;
1607
+ var debug = console.debug;
1608
+ var header = (e) => {
1609
+ const t = (/* @__PURE__ */ new Date()).toISOString();
1610
+ const stepNumber = e.stepNumber;
1611
+ const key = e.expertKey;
1612
+ return `${t} ${stepNumber} ${key}`;
1613
+ };
1614
+ async function defaultEventListener(e) {
1615
+ await defaultStoreEvent(e);
1616
+ switch (e.type) {
1617
+ case "startRun": {
1618
+ log(`${header(e)} Perstack@${package_default.version} started`);
1619
+ break;
1620
+ }
1621
+ case "startGeneration": {
1622
+ log(`${header(e)} Generating tool call`);
1623
+ break;
1624
+ }
1625
+ case "retry": {
1626
+ log(`${header(e)} Retrying tool call generation`);
1627
+ debug(e.reason);
1628
+ break;
1629
+ }
1630
+ case "callTool": {
1631
+ log(`${header(e)} Calling tool`);
1632
+ if (e.toolCall.skillName === "@perstack/base") {
1633
+ switch (e.toolCall.toolName) {
1634
+ case "think": {
1635
+ const thought = e.toolCall.args.thought;
1636
+ log(`${header(e)} Thought Updated:`);
1637
+ debug(thought);
1638
+ break;
1639
+ }
1640
+ case "readPdfFile": {
1641
+ const path2 = e.toolCall.args.path;
1642
+ log(`${header(e)} Reading PDF: ${path2}`);
1643
+ break;
1644
+ }
1645
+ case "readImageFile": {
1646
+ const path2 = e.toolCall.args.path;
1647
+ log(`${header(e)} Reading Image: ${path2}`);
1648
+ break;
1649
+ }
1650
+ default: {
1651
+ log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
1652
+ debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
1653
+ break;
1654
+ }
1655
+ }
1656
+ } else {
1657
+ log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
1658
+ debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
1659
+ }
1660
+ break;
1661
+ }
1662
+ case "callInteractiveTool": {
1663
+ log(`${header(e)} Calling interactive tool`);
1664
+ log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
1665
+ debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
1666
+ break;
1667
+ }
1668
+ case "callDelegate": {
1669
+ log(`${header(e)} Calling delegate`);
1670
+ log(`${header(e)} Tool: ${e.toolCall.toolName}`);
1671
+ debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
1672
+ break;
1673
+ }
1674
+ case "resolveToolResult": {
1675
+ log(`${header(e)} Resolved Tool Result`);
1676
+ if (e.toolResult.skillName === "@perstack/base") {
1677
+ switch (e.toolResult.toolName) {
1678
+ case "todo": {
1679
+ const text = e.toolResult.result.find((r) => r.type === "textPart")?.text;
1680
+ const { todos } = JSON.parse(text ?? "{}");
1681
+ log(`${header(e)} Todo:`);
1682
+ for (const todo of todos) {
1683
+ debug(`${todo.completed ? "[x]" : "[ ]"} ${todo.id}: ${todo.title}`);
1684
+ }
1685
+ break;
1686
+ }
1687
+ default: {
1688
+ log(`${header(e)} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
1689
+ debug(`${header(e)} Result: ${JSON.stringify(e.toolResult.result, null, 2)}`);
1690
+ break;
1691
+ }
1692
+ }
1693
+ } else {
1694
+ log(`${header(e)} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
1695
+ debug(`${header(e)} Result: ${JSON.stringify(e.toolResult.result, null, 2)}`);
1696
+ }
1697
+ break;
1698
+ }
1699
+ case "resolveThought": {
1700
+ log(`${header(e)} Resolved Thought:`, e.toolResult);
1701
+ break;
1702
+ }
1703
+ case "resolvePdfFile": {
1704
+ log(`${header(e)} Resolved PDF:`, e.toolResult);
1705
+ break;
1706
+ }
1707
+ case "resolveImageFile": {
1708
+ log(`${header(e)} Resolved Image:`, e.toolResult);
1709
+ break;
1710
+ }
1711
+ case "attemptCompletion": {
1712
+ log(`${header(e)} Attempting completion`);
1713
+ break;
1714
+ }
1715
+ case "completeRun": {
1716
+ logUsage(e);
1717
+ log(`${header(e)} Completing run`);
1718
+ debug(`${header(e)} Result:`, e.text);
1719
+ break;
1720
+ }
1721
+ case "stopRunByInteractiveTool": {
1722
+ logUsage(e);
1723
+ log(`${header(e)} Stopping run by interactive tool`);
1724
+ break;
1725
+ }
1726
+ case "stopRunByDelegate": {
1727
+ logUsage(e);
1728
+ log(`${header(e)} Stopping run by delegate`);
1729
+ break;
1730
+ }
1731
+ case "stopRunByExceededMaxSteps": {
1732
+ logUsage(e);
1733
+ log(`${header(e)} Stopping run by exceeded max steps`);
1734
+ break;
1735
+ }
1736
+ case "continueToNextStep": {
1737
+ logUsage(e);
1738
+ log(`${header(e)} Continuing to next step`);
1739
+ if (e.checkpoint.contextWindowUsage) {
1740
+ log(`${header(e)} Context window usage: ${e.checkpoint.contextWindowUsage.toFixed(2)}%`);
1741
+ }
1742
+ break;
1743
+ }
1744
+ }
1745
+ }
1746
+ function logUsage(e) {
1747
+ const usageByStep = [
1748
+ `In: ${e.step.usage.inputTokens.toLocaleString()}`,
1749
+ `Reasoning: ${e.step.usage.reasoningTokens.toLocaleString()}`,
1750
+ `Out: ${e.step.usage.outputTokens.toLocaleString()}`,
1751
+ `Total: ${e.step.usage.totalTokens.toLocaleString()}`,
1752
+ `Cache-read: ${e.step.usage.cachedInputTokens.toLocaleString()}`
1753
+ ].join(", ");
1754
+ const usageByRun = [
1755
+ `In: ${e.checkpoint.usage.inputTokens.toLocaleString()}`,
1756
+ `Reasoning: ${e.checkpoint.usage.reasoningTokens.toLocaleString()}`,
1757
+ `Out: ${e.checkpoint.usage.outputTokens.toLocaleString()}`,
1758
+ `Total: ${e.checkpoint.usage.totalTokens.toLocaleString()}`,
1759
+ `Cache-read: ${e.checkpoint.usage.cachedInputTokens.toLocaleString()}`
1760
+ ].join(", ");
1761
+ log(`${header(e)} Tokens usage by step: ${usageByStep}`);
1762
+ log(`${header(e)} Tokens usage by run: ${usageByRun}`);
1763
+ }
1764
+ var RunEventEmitter = class {
1765
+ listeners = [];
1766
+ subscribe(listener) {
1767
+ this.listeners.push(listener);
1768
+ }
1769
+ async emit(event) {
1770
+ for (const listener of this.listeners) {
1771
+ await listener({
1772
+ ...event,
1773
+ id: createId(),
1774
+ timestamp: Date.now()
1775
+ });
1776
+ }
1777
+ }
1778
+ };
1779
+ async function resolveExpertToRun(expertKey, experts, clientOptions) {
1780
+ console.log(experts);
1781
+ if (experts[expertKey]) {
1782
+ return experts[expertKey];
1783
+ }
1784
+ const client = new ApiV1Client({
1785
+ baseUrl: clientOptions.perstackApiBaseUrl,
1786
+ apiKey: clientOptions.perstackApiKey
1787
+ });
1788
+ const { expert } = await client.registry.experts.get({ expertKey });
1789
+ experts[expertKey] = toRuntimeExpert(expert);
1790
+ return experts[expertKey];
1791
+ }
1792
+ function toRuntimeExpert(expert) {
1793
+ const skills = Object.fromEntries(
1794
+ Object.entries(expert.skills).map(([name, skill]) => {
1795
+ switch (skill.type) {
1796
+ case "mcpStdioSkill":
1797
+ return [
1798
+ name,
1799
+ {
1800
+ ...skill,
1801
+ name
1802
+ }
1803
+ ];
1804
+ case "mcpSseSkill":
1805
+ return [
1806
+ name,
1807
+ {
1808
+ ...skill,
1809
+ name
1810
+ }
1811
+ ];
1812
+ case "interactiveSkill":
1813
+ return [
1814
+ name,
1815
+ {
1816
+ ...skill,
1817
+ name
1818
+ }
1819
+ ];
1820
+ }
2445
1821
  })
2446
- ).optional()
2447
- });
1822
+ );
1823
+ return {
1824
+ ...expert,
1825
+ skills
1826
+ };
1827
+ }
2448
1828
 
2449
1829
  // src/runtime.ts
2450
1830
  async function run(runInput, options) {
2451
- const runParams = RunParamsSchema.parse(runInput);
1831
+ const runParams = runParamsSchema.parse(runInput);
2452
1832
  const eventListener = options?.eventListener ?? defaultEventListener;
2453
1833
  const retrieveCheckpoint = options?.retrieveCheckpoint ?? defaultRetrieveCheckpoint;
2454
1834
  const storeCheckpoint = options?.storeCheckpoint ?? defaultStoreCheckpoint;
2455
1835
  const eventEmitter = new RunEventEmitter();
2456
1836
  eventEmitter.subscribe(eventListener);
2457
1837
  let { setting, checkpoint } = runParams;
2458
- if (checkpoint) {
2459
- checkpoint.status = "proceeding";
2460
- }
1838
+ const contextWindow = getContextWindow(setting.providerConfig.name, setting.model);
2461
1839
  if (setting.workspace) {
2462
1840
  if (!path.isAbsolute(setting.workspace)) {
2463
1841
  throw new Error(`Workspace path must be absolute: ${setting.workspace}`);
@@ -2468,7 +1846,7 @@ async function run(runInput, options) {
2468
1846
  while (true) {
2469
1847
  const { expertToRun, experts } = await setupExperts(setting);
2470
1848
  printRunSetting(expertToRun.name, experts, setting);
2471
- const skillManagers = await getSkillManagers(expertToRun, experts);
1849
+ const skillManagers = await getSkillManagers(expertToRun, experts, setting);
2472
1850
  const runActor = createActor(runtimeStateMachine, {
2473
1851
  input: {
2474
1852
  setting: {
@@ -2477,10 +1855,10 @@ async function run(runInput, options) {
2477
1855
  },
2478
1856
  initialCheckpoint: checkpoint ? {
2479
1857
  ...checkpoint,
2480
- id: createId8(),
1858
+ id: createId(),
2481
1859
  stepNumber: checkpoint.stepNumber + 1
2482
1860
  } : {
2483
- id: createId8(),
1861
+ id: createId(),
2484
1862
  runId: setting.runId,
2485
1863
  expert: {
2486
1864
  key: setting.expertKey,
@@ -2490,7 +1868,9 @@ async function run(runInput, options) {
2490
1868
  stepNumber: 1,
2491
1869
  status: "init",
2492
1870
  messages: [],
2493
- usage: createEmptyUsage()
1871
+ usage: createEmptyUsage(),
1872
+ contextWindow,
1873
+ contextWindowUsage: contextWindow ? 0 : void 0
2494
1874
  },
2495
1875
  eventListener,
2496
1876
  skillManagers
@@ -2619,9 +1999,13 @@ async function run(runInput, options) {
2619
1999
  async function setupExperts(setting) {
2620
2000
  const { expertKey } = setting;
2621
2001
  const experts = { ...setting.experts };
2622
- const expertToRun = await resolveExpertToRun(expertKey, experts);
2002
+ const clientOptions = {
2003
+ perstackApiBaseUrl: setting.perstackApiBaseUrl,
2004
+ perstackApiKey: setting.perstackApiKey
2005
+ };
2006
+ const expertToRun = await resolveExpertToRun(expertKey, experts, clientOptions);
2623
2007
  for (const delegateName of expertToRun.delegates) {
2624
- const delegate = await resolveExpertToRun(delegateName, experts);
2008
+ const delegate = await resolveExpertToRun(delegateName, experts, clientOptions);
2625
2009
  if (!delegate) {
2626
2010
  throw new Error(`Delegate ${delegateName} not found`);
2627
2011
  }
@@ -2650,12 +2034,12 @@ async function storeRunSetting(setting) {
2650
2034
  const runDir = getRunDir(setting.runId);
2651
2035
  if (existsSync(runDir)) {
2652
2036
  const runSettingPath = path.resolve(runDir, "run-setting.json");
2653
- const runSetting = JSON.parse(await readFile4(runSettingPath, "utf-8"));
2037
+ const runSetting = JSON.parse(await readFile(runSettingPath, "utf-8"));
2654
2038
  runSetting.updatedAt = Date.now();
2655
- await writeFile2(runSettingPath, JSON.stringify(runSetting, null, 2), "utf-8");
2039
+ await writeFile(runSettingPath, JSON.stringify(runSetting, null, 2), "utf-8");
2656
2040
  } else {
2657
- await mkdir2(runDir, { recursive: true });
2658
- await writeFile2(
2041
+ await mkdir(runDir, { recursive: true });
2042
+ await writeFile(
2659
2043
  path.resolve(runDir, "run-setting.json"),
2660
2044
  JSON.stringify(setting, null, 2),
2661
2045
  "utf-8"
@@ -2665,119 +2049,7 @@ async function storeRunSetting(setting) {
2665
2049
  function getRunDir(runId) {
2666
2050
  return `${process.cwd()}/perstack/runs/${runId}`;
2667
2051
  }
2668
- async function parseConfig(config) {
2669
- const toml = TOML.parse(config ?? "");
2670
- return PerstackConfigSchema.parse(toml);
2671
- }
2672
2052
 
2673
- // src/schemas/command-run.ts
2674
- import { z as z5 } from "zod";
2675
- var RunInputSchema = z5.object({
2676
- expertKey: z5.string(),
2677
- query: z5.string(),
2678
- options: z5.object({
2679
- config: z5.string().optional(),
2680
- model: z5.string().optional(),
2681
- temperature: z5.string().optional().transform((value) => {
2682
- if (value === void 0) {
2683
- return void 0;
2684
- }
2685
- const parsedValue = Number.parseFloat(value);
2686
- if (Number.isNaN(parsedValue)) {
2687
- return void 0;
2688
- }
2689
- return parsedValue;
2690
- }),
2691
- maxSteps: z5.string().optional().transform((value) => {
2692
- if (value === void 0) {
2693
- return void 0;
2694
- }
2695
- const parsedValue = Number.parseInt(value);
2696
- if (Number.isNaN(parsedValue)) {
2697
- return void 0;
2698
- }
2699
- return parsedValue;
2700
- }),
2701
- maxRetries: z5.string().optional().transform((value) => {
2702
- if (value === void 0) {
2703
- return void 0;
2704
- }
2705
- const parsedValue = Number.parseInt(value);
2706
- if (Number.isNaN(parsedValue)) {
2707
- return void 0;
2708
- }
2709
- return parsedValue;
2710
- }),
2711
- timeout: z5.string().optional().transform((value) => {
2712
- if (value === void 0) {
2713
- return void 0;
2714
- }
2715
- const parsedValue = Number.parseInt(value);
2716
- if (Number.isNaN(parsedValue)) {
2717
- return void 0;
2718
- }
2719
- return parsedValue;
2720
- }),
2721
- runId: z5.string().optional()
2722
- })
2723
- });
2724
- export {
2725
- CheckpointSchema,
2726
- CheckpointStatusSchema,
2727
- ExpertMessageSchema,
2728
- ExpertSchema,
2729
- FileBinaryPartSchema,
2730
- FileInlinePartSchema,
2731
- FileUrlPartSchema,
2732
- ImageBinaryPartSchema,
2733
- ImageInlinePartSchema,
2734
- ImageUrlPartSchema,
2735
- InstructionMessageSchema,
2736
- InteractiveSkillSchema,
2737
- InteractiveToolSchema,
2738
- McpSseSkillSchema,
2739
- McpStdioSkillSchema,
2740
- MessageSchema,
2741
- PerstackConfigSchema,
2742
- RegistryV1ExpertsGetResponseSchema,
2743
- RunInputSchema,
2744
- RunParamsSchema,
2745
- StateMachineLogics,
2746
- TextPartSchema,
2747
- ToolCallPartSchema,
2748
- ToolMessageSchema,
2749
- ToolResultPartSchema,
2750
- UsageSchema,
2751
- UserMessageSchema,
2752
- attemptCompletion,
2753
- callDelegate,
2754
- callInteractiveTool,
2755
- callTool,
2756
- completeRun,
2757
- continueToNextStep,
2758
- createEvent,
2759
- defaultEventListener,
2760
- expertKeyRegex,
2761
- expertNameRegex,
2762
- finishToolCall,
2763
- getRunDir,
2764
- maxNameLength,
2765
- parseConfig,
2766
- parseExpertKey,
2767
- resolveImageFile,
2768
- resolvePdfFile,
2769
- resolveThought,
2770
- resolveToolResult,
2771
- retry,
2772
- run,
2773
- runtimeStateMachine,
2774
- skillNameRegex,
2775
- startGeneration,
2776
- startRun,
2777
- stopRunByDelegate,
2778
- stopRunByExceededMaxSteps,
2779
- stopRunByInteractiveTool,
2780
- tagNameRegex,
2781
- versionRegex
2782
- };
2053
+ export { StateMachineLogics, calculateContextWindowUsage, defaultEventListener, getContextWindow, getModel, getRunDir, run, runtimeStateMachine };
2054
+ //# sourceMappingURL=index.js.map
2783
2055
  //# sourceMappingURL=index.js.map