@perstack/runtime 0.0.20 → 0.0.21

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
@@ -33,30 +33,29 @@ var AnthropicModels = [
33
33
  // "claude-3-haiku-20240307", - No pdf support
34
34
  ];
35
35
  var GoogleModels = [
36
- "gemini-2.5-pro-preview-05-06",
37
- "gemini-2.5-pro-exp-03-25",
38
- "gemini-2.5-flash-preview-04-17",
39
- "gemini-2.0-pro-exp-02-05",
40
- "gemini-2.0-flash-thinking-exp-01-21",
41
- "gemini-2.0-flash",
42
- "gemini-2.0-flash-001",
43
- "gemini-2.0-flash-live-001",
44
- "gemini-2.0-flash-lite",
45
- "gemini-2.0-flash-exp",
46
- "gemini-1.5-pro",
47
- "gemini-1.5-pro-latest",
48
- "gemini-1.5-pro-001",
49
- "gemini-1.5-pro-002",
50
36
  "gemini-1.5-flash",
51
37
  "gemini-1.5-flash-latest",
52
38
  "gemini-1.5-flash-001",
53
39
  "gemini-1.5-flash-002",
54
40
  "gemini-1.5-flash-8b",
55
41
  "gemini-1.5-flash-8b-latest",
56
- "gemini-1.5-flash-8b-001"
57
- // "gemini-exp-1206", - Unclear model spec
58
- // "gemma-3-27b-it", - Unclear model spec
59
- // "learnlm-1.5-pro-experimental", - Unclear model spec
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"
60
59
  ];
61
60
  var OpenAIModels = [
62
61
  "o4-mini",
@@ -301,7 +300,10 @@ var ExpertSchema = z2.object({
301
300
  type: "mcpStdioSkill",
302
301
  description: "Base skill",
303
302
  command: "npx",
304
- args: ["-y", "@perstack/base"]
303
+ args: ["-y", "@perstack/base"],
304
+ pick: [],
305
+ omit: [],
306
+ requiredEnv: []
305
307
  }
306
308
  }).transform((skills) => {
307
309
  return Object.fromEntries(
@@ -393,7 +395,8 @@ var RunParamsSchema = z2.object({
393
395
  model: z2.string().optional().default(getDefaultModelName()),
394
396
  temperature: z2.number().min(0).max(1).optional().default(0.3),
395
397
  maxSteps: z2.number().min(1).optional(),
396
- maxRetries: z2.number().min(0).optional().default(10),
398
+ maxRetries: z2.number().min(0).optional().default(5),
399
+ timeout: z2.number().min(0).optional().default(1e3 * 60),
397
400
  workspace: z2.string().optional(),
398
401
  startedAt: z2.number().optional().default(Date.now()),
399
402
  updatedAt: z2.number().optional().default(Date.now())
@@ -463,7 +466,7 @@ async function defaultStoreEvent(event) {
463
466
  // package.json
464
467
  var package_default = {
465
468
  name: "@perstack/runtime",
466
- version: "0.0.20",
469
+ version: "0.0.21",
467
470
  description: "PerStack Runtime",
468
471
  author: "Wintermute Technologies, Inc.",
469
472
  license: "Apache-2.0",
@@ -487,23 +490,23 @@ var package_default = {
487
490
  prepublishOnly: "npm run clean && npm run build"
488
491
  },
489
492
  dependencies: {
490
- "@ai-sdk/anthropic": "^1.2.12",
491
- "@ai-sdk/google": "^1.2.19",
492
- "@ai-sdk/openai": "^1.3.22",
493
- "@modelcontextprotocol/sdk": "^1.12.3",
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",
494
497
  "@paralleldrive/cuid2": "^2.2.2",
495
- ai: "^4.3.16",
496
- "smol-toml": "^1.3.4",
498
+ ai: "^5.0.4",
499
+ "smol-toml": "^1.4.1",
497
500
  "ts-dedent": "^2.2.0",
498
- xstate: "^5.19.4",
499
- zod: "^3.25.67"
501
+ xstate: "^5.20.1",
502
+ zod: "^4.0.14"
500
503
  },
501
504
  devDependencies: {
502
505
  "@tsconfig/node22": "^22.0.2",
503
- "@types/node": "^24.0.3",
506
+ "@types/node": "^24.2.0",
504
507
  tsup: "^8.5.0",
505
- typescript: "^5.8.3",
506
- vitest: "^3.2.3"
508
+ typescript: "^5.9.2",
509
+ vitest: "^3.2.4"
507
510
  },
508
511
  engines: {
509
512
  node: ">=22.0.0"
@@ -523,7 +526,7 @@ async function defaultEventListener(e) {
523
526
  await defaultStoreEvent(e);
524
527
  switch (e.type) {
525
528
  case "startRun": {
526
- log(`${header(e)} \u{1F99C} Perstack@${package_default.version} started`);
529
+ log(`${header(e)} Perstack@${package_default.version} started`);
527
530
  const { inputMessages } = e;
528
531
  for (const message of inputMessages) {
529
532
  if (message.type === "userMessage") {
@@ -535,122 +538,122 @@ async function defaultEventListener(e) {
535
538
  break;
536
539
  }
537
540
  case "startGeneration": {
538
- log(`${header(e)} \u{1F99C} Generating tool call`);
541
+ log(`${header(e)} Generating tool call`);
539
542
  break;
540
543
  }
541
544
  case "retry": {
542
545
  logUsage(e);
543
- log(`${header(e)} \u{1F99C} Retrying tool call generation`);
546
+ log(`${header(e)} Retrying tool call generation`);
544
547
  break;
545
548
  }
546
549
  case "callTool": {
547
550
  logUsage(e);
548
- log(`${header(e)} \u{1F99C} Calling tool`);
551
+ log(`${header(e)} Calling tool`);
549
552
  if (e.toolCall.skillName === "@perstack/base") {
550
553
  switch (e.toolCall.toolName) {
551
554
  case "think": {
552
555
  const thought = e.toolCall.args.thought;
553
- log(`${header(e)} \u{1F4AD} Thought Updated:`);
556
+ log(`${header(e)} Thought Updated:`);
554
557
  debug(thought);
555
558
  break;
556
559
  }
557
560
  case "readPdfFile": {
558
561
  const path2 = e.toolCall.args.path;
559
- log(`${header(e)} \u{1F4C4} Reading PDF: ${path2}`);
562
+ log(`${header(e)} Reading PDF: ${path2}`);
560
563
  break;
561
564
  }
562
565
  case "readImageFile": {
563
566
  const path2 = e.toolCall.args.path;
564
- log(`${header(e)} \u{1F5BC}\uFE0F Reading Image: ${path2}`);
567
+ log(`${header(e)} Reading Image: ${path2}`);
565
568
  break;
566
569
  }
567
570
  default: {
568
- log(`${header(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
569
- log(`${header(e)} \u{1F527} Args: ${e.toolCall.args}`);
571
+ log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
572
+ debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
570
573
  break;
571
574
  }
572
575
  }
573
576
  } else {
574
- log(`${header(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
575
- log(`${header(e)} \u{1F527} Args: ${e.toolCall.args}`);
577
+ log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
578
+ debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
576
579
  }
577
580
  break;
578
581
  }
579
582
  case "callInteractiveTool": {
580
583
  logUsage(e);
581
- log(`${header(e)} \u{1F99C} Calling interactive tool`);
582
- log(`${header(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
583
- log(`${header(e)} \u{1F527} Args: ${e.toolCall.args}`);
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)}`);
584
587
  break;
585
588
  }
586
589
  case "callDelegate": {
587
590
  logUsage(e);
588
- log(`${header(e)} \u{1F99C} Calling delegate`);
589
- log(`${header(e)} \u{1F527} Tool: ${e.toolCall.toolName}`);
590
- log(`${header(e)} \u{1F527} Args: ${e.toolCall.args}`);
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)}`);
591
594
  break;
592
595
  }
593
596
  case "resolveToolResult": {
594
- log(`${header(e)} \u{1F527} Resolved Tool Result`);
597
+ log(`${header(e)} Resolved Tool Result`);
595
598
  if (e.toolResult.skillName === "@perstack/base") {
596
599
  switch (e.toolResult.toolName) {
597
600
  case "todo": {
598
601
  const text = e.toolResult.result.find((r) => r.type === "textPart")?.text;
599
602
  const { todos } = JSON.parse(text ?? "{}");
600
- log(`${header(e)} \u{1F4C4} Todo:`);
603
+ log(`${header(e)} Todo:`);
601
604
  for (const todo of todos) {
602
605
  debug(`${todo.completed ? "[x]" : "[ ]"} ${todo.id}: ${todo.title}`);
603
606
  }
604
607
  break;
605
608
  }
606
609
  default: {
607
- log(`${header(e)} \u{1F527} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
608
- log(`${header(e)} \u{1F527} Result: ${e.toolResult.result}`);
610
+ log(`${header(e)} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
611
+ debug(`${header(e)} Result: ${JSON.stringify(e.toolResult.result, null, 2)}`);
609
612
  break;
610
613
  }
611
614
  }
612
615
  } else {
613
- log(`${header(e)} \u{1F527} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
614
- log(`${header(e)} \u{1F527} Result: ${e.toolResult.result}`);
616
+ log(`${header(e)} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
617
+ debug(`${header(e)} Result: ${JSON.stringify(e.toolResult.result, null, 2)}`);
615
618
  }
616
619
  break;
617
620
  }
618
621
  case "resolveThought": {
619
- log(`${header(e)} \u{1F4AD} Resolved Thought:`, e.toolResult);
622
+ log(`${header(e)} Resolved Thought:`, e.toolResult);
620
623
  break;
621
624
  }
622
625
  case "resolvePdfFile": {
623
- log(`${header(e)} \u{1F4C4} Resolved PDF:`, e.toolResult);
626
+ log(`${header(e)} Resolved PDF:`, e.toolResult);
624
627
  break;
625
628
  }
626
629
  case "resolveImageFile": {
627
- log(`${header(e)} \u{1F5BC}\uFE0F Resolved Image:`, e.toolResult);
630
+ log(`${header(e)} Resolved Image:`, e.toolResult);
628
631
  break;
629
632
  }
630
633
  case "attemptCompletion": {
631
- log(`${header(e)} \u2705 Attempting completion`);
634
+ log(`${header(e)} Attempting completion`);
632
635
  break;
633
636
  }
634
637
  case "completeRun": {
635
638
  logUsage(e);
636
- log(`${header(e)} \u{1F99C} Completing run`);
637
- log(`${header(e)} \u{1F99C} Result:`, e.text);
639
+ log(`${header(e)} Completing run`);
640
+ debug(`${header(e)} Result:`, e.text);
638
641
  break;
639
642
  }
640
643
  case "stopRunByInteractiveTool": {
641
- log(`${header(e)} \u{1F99C} Stopping run by interactive tool`);
644
+ log(`${header(e)} Stopping run by interactive tool`);
642
645
  break;
643
646
  }
644
647
  case "stopRunByDelegate": {
645
- log(`${header(e)} \u{1F99C} Stopping run by delegate`);
648
+ log(`${header(e)} Stopping run by delegate`);
646
649
  break;
647
650
  }
648
651
  case "stopRunByExceededMaxSteps": {
649
- log(`${header(e)} \u{1F99C} Stopping run by exceeded max steps`);
652
+ log(`${header(e)} Stopping run by exceeded max steps`);
650
653
  break;
651
654
  }
652
655
  case "continueToNextStep": {
653
- log(`${header(e)} \u{1F99C} Continuing to next step`);
656
+ log(`${header(e)} Continuing to next step`);
654
657
  break;
655
658
  }
656
659
  }
@@ -660,19 +663,19 @@ function logUserMessage(message) {
660
663
  const contents = message.contents;
661
664
  for (const content of contents) {
662
665
  if (content.type === "textPart") {
663
- log(`${t} \u{1F4AC} User: ${content.text}`);
666
+ log(`${t} User: ${content.text}`);
664
667
  } else if (content.type === "imageUrlPart") {
665
- log(`${t} \u{1F5BC}\uFE0F User: ${content.url}`);
668
+ log(`${t} User: ${content.url}`);
666
669
  } else if (content.type === "imageInlinePart") {
667
- log(`${t} \u{1F5BC}\uFE0F User: Inline image`);
670
+ log(`${t} User: Inline image`);
668
671
  } else if (content.type === "imageBinaryPart") {
669
- log(`${t} \u{1F5BC}\uFE0F User: Binary image`);
672
+ log(`${t} User: Binary image`);
670
673
  } else if (content.type === "fileUrlPart") {
671
- log(`${t} \u{1F4C4} User: ${content.url}`);
674
+ log(`${t} User: ${content.url}`);
672
675
  } else if (content.type === "fileInlinePart") {
673
- log(`${t} \u{1F4C4} User: Inline file`);
676
+ log(`${t} User: Inline file`);
674
677
  } else if (content.type === "fileBinaryPart") {
675
- log(`${t} \u{1F4C4} User: Binary file`);
678
+ log(`${t} User: Binary file`);
676
679
  }
677
680
  }
678
681
  }
@@ -684,9 +687,9 @@ function logToolMessage(message) {
684
687
  const { contents: contents2 } = content;
685
688
  for (const content2 of contents2) {
686
689
  if (content2.type === "textPart") {
687
- log(`${t} \u{1F4AC} Tool Result: ${content2.text}`);
690
+ log(`${t} Tool Result: ${content2.text}`);
688
691
  } else if (content2.type === "imageInlinePart") {
689
- log(`${t} \u{1F5BC}\uFE0F Tool Result: Inline image`);
692
+ log(`${t} Tool Result: Inline image`);
690
693
  }
691
694
  }
692
695
  }
@@ -700,7 +703,7 @@ function logUsage(e) {
700
703
  `Cache-read: ${e.usage.cacheReadInputTokens.toLocaleString()}`,
701
704
  `Cache-write: ${e.usage.cacheCreationInputTokens.toLocaleString()}`
702
705
  ].join(", ");
703
- log(`${header(e)} \u{1F4CA} Tokens usage: ${usageByGeneration}`);
706
+ log(`${header(e)} Tokens usage: ${usageByGeneration}`);
704
707
  const usageByRun = [
705
708
  `In: ${e.usage.promptTokens.toLocaleString()}`,
706
709
  `Out: ${e.usage.completionTokens.toLocaleString()}`,
@@ -708,7 +711,7 @@ function logUsage(e) {
708
711
  `Cache-read: ${e.usage.cacheReadInputTokens.toLocaleString()}`,
709
712
  `Cache-write: ${e.usage.cacheCreationInputTokens.toLocaleString()}`
710
713
  ].join(", ");
711
- log(`${header(e)} \u{1F4CA} Total usage: ${usageByRun}`);
714
+ log(`${header(e)} Total usage: ${usageByRun}`);
712
715
  }
713
716
 
714
717
  // src/events/event-emitter.ts
@@ -749,8 +752,8 @@ var RegistryV1ExpertSchema = z3.object({
749
752
  tags: z3.array(z3.string()),
750
753
  status: z3.string(),
751
754
  owner: z3.object({ name: z3.string() }),
752
- createdAt: z3.string().datetime(),
753
- updatedAt: z3.string().datetime()
755
+ createdAt: z3.iso.datetime(),
756
+ updatedAt: z3.iso.datetime()
754
757
  });
755
758
  var RegistryV1ExpertsGetResponseSchema = z3.object({
756
759
  data: z3.object({
@@ -818,7 +821,7 @@ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
818
821
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
819
822
  import { McpError } from "@modelcontextprotocol/sdk/types.js";
820
823
  import { createId as createId3 } from "@paralleldrive/cuid2";
821
- import { jsonSchema } from "ai";
824
+ import { jsonSchema, tool } from "ai";
822
825
  import { ZodError } from "zod";
823
826
  var SkillManager = class {
824
827
  _toolDefinitions = [];
@@ -895,11 +898,11 @@ var SkillManager = class {
895
898
  }
896
899
  }
897
900
  const { tools } = await this._mcpClient.listTools();
898
- this._toolDefinitions = tools.map((tool) => ({
901
+ this._toolDefinitions = tools.map((tool2) => ({
899
902
  skillName: params.skill.name,
900
- name: tool.name,
901
- description: tool.description,
902
- inputSchema: tool.inputSchema,
903
+ name: tool2.name,
904
+ description: tool2.description,
905
+ inputSchema: tool2.inputSchema,
903
906
  interactive: false
904
907
  }));
905
908
  this._initialized = true;
@@ -921,11 +924,11 @@ var SkillManager = class {
921
924
  return { command, args: newArgs };
922
925
  }
923
926
  async _initInteractiveSkill(params) {
924
- this._toolDefinitions = Object.values(params.interactiveSkill.tools).map((tool) => ({
927
+ this._toolDefinitions = Object.values(params.interactiveSkill.tools).map((tool2) => ({
925
928
  skillName: params.interactiveSkill.name,
926
- name: tool.name,
927
- description: tool.description,
928
- inputSchema: JSON.parse(tool.inputJsonSchema),
929
+ name: tool2.name,
930
+ description: tool2.description,
931
+ inputSchema: JSON.parse(tool2.inputJsonSchema),
929
932
  interactive: true
930
933
  }));
931
934
  this._initialized = true;
@@ -958,7 +961,7 @@ var SkillManager = class {
958
961
  if (this._params.type === "mcp") {
959
962
  const omit = this._params.skill.omit ?? [];
960
963
  const pick = this._params.skill.pick ?? [];
961
- return this._toolDefinitions.filter((tool) => omit.length > 0 ? !omit.includes(tool.name) : true).filter((tool) => pick.length > 0 ? pick.includes(tool.name) : true);
964
+ return this._toolDefinitions.filter((tool2) => omit.length > 0 ? !omit.includes(tool2.name) : true).filter((tool2) => pick.length > 0 ? pick.includes(tool2.name) : true);
962
965
  }
963
966
  return this._toolDefinitions;
964
967
  }
@@ -1133,10 +1136,10 @@ async function getToolSet(skillManagers) {
1133
1136
  for (const skillManager of Object.values(skillManagers)) {
1134
1137
  const toolDefinitions = await skillManager.getToolDefinitions();
1135
1138
  for (const toolDefinition of toolDefinitions) {
1136
- tools[toolDefinition.name] = {
1139
+ tools[toolDefinition.name] = tool({
1137
1140
  description: toolDefinition.description,
1138
- parameters: jsonSchema(toolDefinition.inputSchema)
1139
- };
1141
+ inputSchema: jsonSchema(toolDefinition.inputSchema)
1142
+ });
1140
1143
  }
1141
1144
  }
1142
1145
  return tools;
@@ -1401,42 +1404,42 @@ function imageUrlPartToCoreImagePart(part) {
1401
1404
  return {
1402
1405
  type: "image",
1403
1406
  image: part.url,
1404
- mimeType: part.mimeType
1407
+ mediaType: part.mimeType
1405
1408
  };
1406
1409
  }
1407
1410
  function imageInlinePartToCoreImagePart(part) {
1408
1411
  return {
1409
1412
  type: "image",
1410
1413
  image: part.encodedData,
1411
- mimeType: part.mimeType
1414
+ mediaType: part.mimeType
1412
1415
  };
1413
1416
  }
1414
1417
  function imageBinaryPartToCoreImagePart(part) {
1415
1418
  return {
1416
1419
  type: "image",
1417
1420
  image: part.data,
1418
- mimeType: part.mimeType
1421
+ mediaType: part.mimeType
1419
1422
  };
1420
1423
  }
1421
1424
  function fileUrlPartToCoreFilePart(part) {
1422
1425
  return {
1423
1426
  type: "file",
1424
1427
  data: part.url,
1425
- mimeType: part.mimeType
1428
+ mediaType: part.mimeType
1426
1429
  };
1427
1430
  }
1428
1431
  function fileInlinePartToCoreFilePart(part) {
1429
1432
  return {
1430
1433
  type: "file",
1431
1434
  data: part.encodedData,
1432
- mimeType: part.mimeType
1435
+ mediaType: part.mimeType
1433
1436
  };
1434
1437
  }
1435
1438
  function fileBinaryPartToCoreFilePart(part) {
1436
1439
  return {
1437
1440
  type: "file",
1438
1441
  data: part.data,
1439
- mimeType: part.mimeType
1442
+ mediaType: part.mimeType
1440
1443
  };
1441
1444
  }
1442
1445
  function toolCallPartToCoreToolCallPart(part) {
@@ -1444,31 +1447,29 @@ function toolCallPartToCoreToolCallPart(part) {
1444
1447
  type: "tool-call",
1445
1448
  toolCallId: part.toolCallId,
1446
1449
  toolName: part.toolName,
1447
- args: part.args
1450
+ input: part.args
1448
1451
  };
1449
1452
  }
1450
1453
  function toolResultPartToCoreToolResultPart(part) {
1454
+ const content = part.contents[0];
1455
+ const output = content.type === "textPart" ? {
1456
+ type: "text",
1457
+ value: content.text
1458
+ } : {
1459
+ type: "content",
1460
+ value: [
1461
+ {
1462
+ type: "media",
1463
+ data: content.encodedData,
1464
+ mediaType: content.mimeType
1465
+ }
1466
+ ]
1467
+ };
1451
1468
  return {
1452
1469
  type: "tool-result",
1453
1470
  toolCallId: part.toolCallId,
1454
1471
  toolName: part.toolName,
1455
- result: part.contents,
1456
- experimental_content: part.contents.map((part2) => {
1457
- switch (part2.type) {
1458
- case "textPart":
1459
- return {
1460
- type: "text",
1461
- text: part2.text
1462
- };
1463
- case "imageInlinePart":
1464
- return {
1465
- type: "image",
1466
- data: part2.encodedData,
1467
- mimeType: part2.mimeType
1468
- };
1469
- }
1470
- }),
1471
- isError: part.isError
1472
+ output
1472
1473
  };
1473
1474
  }
1474
1475
 
@@ -1491,9 +1492,9 @@ function usageFromGenerateTextResult(result) {
1491
1492
  cacheReadInputTokens = anthropicMetadata.cacheReadInputTokens || 0;
1492
1493
  }
1493
1494
  return {
1494
- promptTokens: result.usage.promptTokens,
1495
- completionTokens: result.usage.completionTokens,
1496
- totalTokens: result.usage.totalTokens,
1495
+ promptTokens: result.usage.inputTokens || 0,
1496
+ completionTokens: result.usage.outputTokens || 0,
1497
+ totalTokens: result.usage.totalTokens || 0,
1497
1498
  cacheCreationInputTokens,
1498
1499
  cacheReadInputTokens
1499
1500
  };
@@ -1531,12 +1532,32 @@ async function generatingRunResultLogic({
1531
1532
  ]);
1532
1533
  const model = getModel(setting.model);
1533
1534
  const { messages } = checkpoint;
1534
- const generationResult = await generateText({
1535
- model,
1536
- messages: [...messages, toolMessage].map(messageToCoreMessage),
1537
- temperature: setting.temperature,
1538
- maxRetries: setting.maxRetries
1539
- });
1535
+ let generationResult;
1536
+ try {
1537
+ generationResult = await generateText({
1538
+ model,
1539
+ messages: [...messages, toolMessage].map(messageToCoreMessage),
1540
+ temperature: setting.temperature,
1541
+ maxRetries: setting.maxRetries,
1542
+ abortSignal: AbortSignal.timeout(setting.timeout)
1543
+ });
1544
+ } catch (error) {
1545
+ if (error instanceof Error) {
1546
+ return retry(setting, checkpoint, {
1547
+ newMessages: [
1548
+ toolMessage,
1549
+ createUserMessage([
1550
+ {
1551
+ type: "textPart",
1552
+ text: JSON.stringify({ error: error.name, errorMessage: error.message })
1553
+ }
1554
+ ])
1555
+ ],
1556
+ usage: checkpoint.usage
1557
+ });
1558
+ }
1559
+ throw error;
1560
+ }
1540
1561
  const usage = usageFromGenerateTextResult(generationResult);
1541
1562
  const { text } = generationResult;
1542
1563
  const newMessages = [toolMessage, createExpertMessage(text ? [{ type: "textPart", text }] : [])];
@@ -1567,14 +1588,33 @@ async function generatingToolCallLogic({
1567
1588
  }) {
1568
1589
  const { messages } = checkpoint;
1569
1590
  const model = getModel(setting.model);
1570
- const result = await generateText2({
1571
- model,
1572
- messages: messages.map(messageToCoreMessage),
1573
- temperature: setting.temperature,
1574
- maxRetries: setting.maxRetries,
1575
- tools: await getToolSet(skillManagers),
1576
- toolChoice: "required"
1577
- });
1591
+ let result;
1592
+ try {
1593
+ result = await generateText2({
1594
+ model,
1595
+ messages: messages.map(messageToCoreMessage),
1596
+ temperature: setting.temperature,
1597
+ maxRetries: setting.maxRetries,
1598
+ tools: await getToolSet(skillManagers),
1599
+ toolChoice: "required",
1600
+ abortSignal: AbortSignal.timeout(setting.timeout)
1601
+ });
1602
+ } catch (error) {
1603
+ if (error instanceof Error) {
1604
+ return retry(setting, checkpoint, {
1605
+ newMessages: [
1606
+ createUserMessage([
1607
+ {
1608
+ type: "textPart",
1609
+ text: JSON.stringify({ error: error.name, errorMessage: error.message })
1610
+ }
1611
+ ])
1612
+ ],
1613
+ usage: checkpoint.usage
1614
+ });
1615
+ }
1616
+ throw error;
1617
+ }
1578
1618
  const usage = usageFromGenerateTextResult(result);
1579
1619
  const { text, toolCalls, finishReason } = result;
1580
1620
  const toolCall = toolCalls[0];
@@ -1602,7 +1642,7 @@ async function generatingToolCallLogic({
1602
1642
  type: "toolCallPart",
1603
1643
  toolCallId: toolCall.toolCallId,
1604
1644
  toolName: toolCall.toolName,
1605
- args: toolCall.args
1645
+ args: toolCall.input
1606
1646
  }
1607
1647
  ]),
1608
1648
  createToolMessage([
@@ -1626,7 +1666,7 @@ async function generatingToolCallLogic({
1626
1666
  type: "toolCallPart",
1627
1667
  toolCallId: toolCall.toolCallId,
1628
1668
  toolName: toolCall.toolName,
1629
- args: toolCall.args
1669
+ args: toolCall.input
1630
1670
  }
1631
1671
  ];
1632
1672
  if (text) {
@@ -1642,7 +1682,7 @@ async function generatingToolCallLogic({
1642
1682
  id: toolCall.toolCallId,
1643
1683
  skillName: skillManager.name,
1644
1684
  toolName: toolCall.toolName,
1645
- args: toolCall.args
1685
+ args: toolCall.input
1646
1686
  },
1647
1687
  usage
1648
1688
  };
@@ -1797,6 +1837,19 @@ async function initLogic({
1797
1837
  inputMessages: [createUserMessage([{ type: "textPart", text: setting.input.text }])]
1798
1838
  });
1799
1839
  }
1840
+ case "stoppedByDelegate": {
1841
+ if (!setting.input.interactiveToolCallResult) {
1842
+ throw new Error("Interactive tool call result is undefined");
1843
+ }
1844
+ return startRun(setting, checkpoint, {
1845
+ initialCheckpoint: checkpoint,
1846
+ inputMessages: [
1847
+ createUserMessage([
1848
+ { type: "textPart", text: setting.input.interactiveToolCallResult.text }
1849
+ ])
1850
+ ]
1851
+ });
1852
+ }
1800
1853
  case "stoppedByInteractiveTool": {
1801
1854
  if (!setting.input.interactiveToolCallResult) {
1802
1855
  throw new Error("Interactive tool call result is undefined");
@@ -2218,6 +2271,21 @@ var runtimeStateMachine = setup({
2218
2271
  },
2219
2272
  GeneratingRunResult: {
2220
2273
  on: {
2274
+ retry: {
2275
+ target: "FinishingStep",
2276
+ actions: assign({
2277
+ checkpoint: ({ context, event }) => ({
2278
+ ...context.checkpoint,
2279
+ messages: [...context.checkpoint.messages, ...event.newMessages],
2280
+ usage: sumUsage(context.checkpoint.usage, event.usage)
2281
+ }),
2282
+ step: ({ context, event }) => ({
2283
+ ...context.step,
2284
+ newMessages: event.newMessages,
2285
+ usage: sumUsage(context.step.usage, event.usage)
2286
+ })
2287
+ })
2288
+ },
2221
2289
  completeRun: {
2222
2290
  target: "Stopped",
2223
2291
  actions: assign({
@@ -2301,6 +2369,7 @@ var PerstackConfigSchema = z4.object({
2301
2369
  temperature: z4.number().optional(),
2302
2370
  maxSteps: z4.number().optional(),
2303
2371
  maxRetries: z4.number().optional(),
2372
+ timeout: z4.number().optional(),
2304
2373
  experts: z4.record(
2305
2374
  z4.string(),
2306
2375
  z4.object({
@@ -2358,6 +2427,9 @@ async function run(runInput, options) {
2358
2427
  const eventEmitter = new RunEventEmitter();
2359
2428
  eventEmitter.subscribe(eventListener);
2360
2429
  let { setting, checkpoint } = runParams;
2430
+ if (checkpoint) {
2431
+ checkpoint.status = "proceeding";
2432
+ }
2361
2433
  if (setting.workspace) {
2362
2434
  if (!path.isAbsolute(setting.workspace)) {
2363
2435
  throw new Error(`Workspace path must be absolute: ${setting.workspace}`);
@@ -2376,17 +2448,9 @@ async function run(runInput, options) {
2376
2448
  experts
2377
2449
  },
2378
2450
  initialCheckpoint: checkpoint ? {
2451
+ ...checkpoint,
2379
2452
  id: createId7(),
2380
- runId: setting.runId,
2381
- expert: {
2382
- key: setting.expertKey,
2383
- name: expertToRun.name,
2384
- version: expertToRun.version
2385
- },
2386
- stepNumber: checkpoint.stepNumber + 1,
2387
- status: "proceeding",
2388
- messages: checkpoint.messages,
2389
- usage: checkpoint.usage
2453
+ stepNumber: checkpoint.stepNumber + 1
2390
2454
  } : {
2391
2455
  id: createId7(),
2392
2456
  runId: setting.runId,
@@ -2468,8 +2532,7 @@ async function run(runInput, options) {
2468
2532
  };
2469
2533
  checkpoint = {
2470
2534
  ...await retrieveCheckpoint(setting.runId, checkpointId),
2471
- id: createId7(),
2472
- stepNumber: runResultCheckpoint.stepNumber + 1,
2535
+ stepNumber: runResultCheckpoint.stepNumber,
2473
2536
  usage: runResultCheckpoint.usage
2474
2537
  };
2475
2538
  break;
@@ -2492,10 +2555,8 @@ async function run(runInput, options) {
2492
2555
  }
2493
2556
  };
2494
2557
  checkpoint = {
2495
- id: createId7(),
2496
- runId: setting.runId,
2558
+ ...runResultCheckpoint,
2497
2559
  status: "init",
2498
- stepNumber: runResultCheckpoint.stepNumber + 1,
2499
2560
  messages: [],
2500
2561
  expert: {
2501
2562
  key: expert.key,
@@ -2540,13 +2601,14 @@ async function setupExperts(setting) {
2540
2601
  return { expertToRun, experts };
2541
2602
  }
2542
2603
  function printRunSetting(expertName, experts, setting) {
2543
- console.log("\u{1F99C} Starting Perstack \u{1F99C}");
2604
+ console.log("Starting Perstack");
2544
2605
  console.log(`Expert To Run: ${expertName}`);
2545
2606
  console.log(`Experts: ${Object.keys(experts).join(", ")}`);
2546
2607
  console.log(`Model: ${setting.model}`);
2547
2608
  console.log(`Temperature: ${setting.temperature}`);
2548
2609
  console.log(`Max Steps: ${setting.maxSteps}`);
2549
2610
  console.log(`Max Retries: ${setting.maxRetries}`);
2611
+ console.log(`Timeout: ${setting.timeout}`);
2550
2612
  if (setting.input.text) {
2551
2613
  console.log(`Query: ${setting.input.text}`);
2552
2614
  }
@@ -2618,6 +2680,16 @@ var RunInputSchema = z5.object({
2618
2680
  }
2619
2681
  return parsedValue;
2620
2682
  }),
2683
+ timeout: z5.string().optional().transform((value) => {
2684
+ if (value === void 0) {
2685
+ return void 0;
2686
+ }
2687
+ const parsedValue = Number.parseInt(value);
2688
+ if (Number.isNaN(parsedValue)) {
2689
+ return void 0;
2690
+ }
2691
+ return parsedValue;
2692
+ }),
2621
2693
  runId: z5.string().optional()
2622
2694
  })
2623
2695
  });