@perstack/runtime 0.0.20 → 0.0.22
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.d.ts +605 -3820
- package/dist/index.js +277 -194
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
|
|
4
4
|
import path from "path";
|
|
5
|
-
import { createId as
|
|
5
|
+
import { createId as createId8 } from "@paralleldrive/cuid2";
|
|
6
6
|
import TOML from "smol-toml";
|
|
7
7
|
import { createActor } from "xstate";
|
|
8
8
|
|
|
@@ -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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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(
|
|
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.
|
|
469
|
+
version: "0.0.22",
|
|
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": "^
|
|
491
|
-
"@ai-sdk/google": "^
|
|
492
|
-
"@ai-sdk/openai": "^
|
|
493
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
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: "^
|
|
496
|
-
"smol-toml": "^1.
|
|
498
|
+
ai: "^5.0.4",
|
|
499
|
+
"smol-toml": "^1.4.1",
|
|
497
500
|
"ts-dedent": "^2.2.0",
|
|
498
|
-
xstate: "^5.
|
|
499
|
-
zod: "^
|
|
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
|
|
506
|
+
"@types/node": "^24.2.0",
|
|
504
507
|
tsup: "^8.5.0",
|
|
505
|
-
typescript: "^5.
|
|
506
|
-
vitest: "^3.2.
|
|
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)}
|
|
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)}
|
|
541
|
+
log(`${header(e)} Generating tool call`);
|
|
539
542
|
break;
|
|
540
543
|
}
|
|
541
544
|
case "retry": {
|
|
542
545
|
logUsage(e);
|
|
543
|
-
log(`${header(e)}
|
|
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)}
|
|
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)}
|
|
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)}
|
|
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)}
|
|
567
|
+
log(`${header(e)} Reading Image: ${path2}`);
|
|
565
568
|
break;
|
|
566
569
|
}
|
|
567
570
|
default: {
|
|
568
|
-
log(`${header(e)}
|
|
569
|
-
|
|
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)}
|
|
575
|
-
|
|
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)}
|
|
582
|
-
log(`${header(e)}
|
|
583
|
-
|
|
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)}
|
|
589
|
-
log(`${header(e)}
|
|
590
|
-
|
|
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)}
|
|
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)}
|
|
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)}
|
|
608
|
-
|
|
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)}
|
|
614
|
-
|
|
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)}
|
|
622
|
+
log(`${header(e)} Resolved Thought:`, e.toolResult);
|
|
620
623
|
break;
|
|
621
624
|
}
|
|
622
625
|
case "resolvePdfFile": {
|
|
623
|
-
log(`${header(e)}
|
|
626
|
+
log(`${header(e)} Resolved PDF:`, e.toolResult);
|
|
624
627
|
break;
|
|
625
628
|
}
|
|
626
629
|
case "resolveImageFile": {
|
|
627
|
-
log(`${header(e)}
|
|
630
|
+
log(`${header(e)} Resolved Image:`, e.toolResult);
|
|
628
631
|
break;
|
|
629
632
|
}
|
|
630
633
|
case "attemptCompletion": {
|
|
631
|
-
log(`${header(e)}
|
|
634
|
+
log(`${header(e)} Attempting completion`);
|
|
632
635
|
break;
|
|
633
636
|
}
|
|
634
637
|
case "completeRun": {
|
|
635
638
|
logUsage(e);
|
|
636
|
-
log(`${header(e)}
|
|
637
|
-
|
|
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)}
|
|
644
|
+
log(`${header(e)} Stopping run by interactive tool`);
|
|
642
645
|
break;
|
|
643
646
|
}
|
|
644
647
|
case "stopRunByDelegate": {
|
|
645
|
-
log(`${header(e)}
|
|
648
|
+
log(`${header(e)} Stopping run by delegate`);
|
|
646
649
|
break;
|
|
647
650
|
}
|
|
648
651
|
case "stopRunByExceededMaxSteps": {
|
|
649
|
-
log(`${header(e)}
|
|
652
|
+
log(`${header(e)} Stopping run by exceeded max steps`);
|
|
650
653
|
break;
|
|
651
654
|
}
|
|
652
655
|
case "continueToNextStep": {
|
|
653
|
-
log(`${header(e)}
|
|
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}
|
|
666
|
+
log(`${t} User: ${content.text}`);
|
|
664
667
|
} else if (content.type === "imageUrlPart") {
|
|
665
|
-
log(`${t}
|
|
668
|
+
log(`${t} User: ${content.url}`);
|
|
666
669
|
} else if (content.type === "imageInlinePart") {
|
|
667
|
-
log(`${t}
|
|
670
|
+
log(`${t} User: Inline image`);
|
|
668
671
|
} else if (content.type === "imageBinaryPart") {
|
|
669
|
-
log(`${t}
|
|
672
|
+
log(`${t} User: Binary image`);
|
|
670
673
|
} else if (content.type === "fileUrlPart") {
|
|
671
|
-
log(`${t}
|
|
674
|
+
log(`${t} User: ${content.url}`);
|
|
672
675
|
} else if (content.type === "fileInlinePart") {
|
|
673
|
-
log(`${t}
|
|
676
|
+
log(`${t} User: Inline file`);
|
|
674
677
|
} else if (content.type === "fileBinaryPart") {
|
|
675
|
-
log(`${t}
|
|
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}
|
|
690
|
+
log(`${t} Tool Result: ${content2.text}`);
|
|
688
691
|
} else if (content2.type === "imageInlinePart") {
|
|
689
|
-
log(`${t}
|
|
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)}
|
|
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)}
|
|
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.
|
|
753
|
-
updatedAt: z3.
|
|
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((
|
|
901
|
+
this._toolDefinitions = tools.map((tool2) => ({
|
|
899
902
|
skillName: params.skill.name,
|
|
900
|
-
name:
|
|
901
|
-
description:
|
|
902
|
-
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((
|
|
927
|
+
this._toolDefinitions = Object.values(params.interactiveSkill.tools).map((tool2) => ({
|
|
925
928
|
skillName: params.interactiveSkill.name,
|
|
926
|
-
name:
|
|
927
|
-
description:
|
|
928
|
-
inputSchema: JSON.parse(
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
1495
|
-
completionTokens: result.usage.
|
|
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
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
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, message: 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 }] : [])];
|
|
@@ -1559,6 +1580,7 @@ async function generatingRunResultLogic({
|
|
|
1559
1580
|
}
|
|
1560
1581
|
|
|
1561
1582
|
// src/states/generating-tool-call.ts
|
|
1583
|
+
import { createId as createId6 } from "@paralleldrive/cuid2";
|
|
1562
1584
|
import { generateText as generateText2 } from "ai";
|
|
1563
1585
|
async function generatingToolCallLogic({
|
|
1564
1586
|
setting,
|
|
@@ -1567,66 +1589,58 @@ async function generatingToolCallLogic({
|
|
|
1567
1589
|
}) {
|
|
1568
1590
|
const { messages } = checkpoint;
|
|
1569
1591
|
const model = getModel(setting.model);
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1592
|
+
let result;
|
|
1593
|
+
try {
|
|
1594
|
+
result = await generateText2({
|
|
1595
|
+
model,
|
|
1596
|
+
messages: messages.map(messageToCoreMessage),
|
|
1597
|
+
temperature: setting.temperature,
|
|
1598
|
+
maxRetries: setting.maxRetries,
|
|
1599
|
+
tools: await getToolSet(skillManagers),
|
|
1600
|
+
toolChoice: "required",
|
|
1601
|
+
abortSignal: AbortSignal.timeout(setting.timeout)
|
|
1602
|
+
});
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
if (error instanceof Error) {
|
|
1605
|
+
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
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
throw error;
|
|
1618
|
+
}
|
|
1578
1619
|
const usage = usageFromGenerateTextResult(result);
|
|
1579
1620
|
const { text, toolCalls, finishReason } = result;
|
|
1580
1621
|
const toolCall = toolCalls[0];
|
|
1581
1622
|
if (!toolCall) {
|
|
1582
1623
|
return retry(setting, checkpoint, {
|
|
1583
1624
|
newMessages: [
|
|
1584
|
-
createExpertMessage(text ? [{ type: "textPart", text }] : []),
|
|
1585
1625
|
createUserMessage([
|
|
1586
1626
|
{
|
|
1587
1627
|
type: "textPart",
|
|
1588
|
-
text:
|
|
1628
|
+
text: JSON.stringify({
|
|
1629
|
+
error: "No tool call generated",
|
|
1630
|
+
message: "You must generate a tool call. Try again."
|
|
1631
|
+
})
|
|
1589
1632
|
}
|
|
1590
1633
|
])
|
|
1591
1634
|
],
|
|
1592
1635
|
usage
|
|
1593
1636
|
});
|
|
1594
1637
|
}
|
|
1595
|
-
if (finishReason !== "tool-calls") {
|
|
1596
|
-
switch (finishReason) {
|
|
1597
|
-
case "length": {
|
|
1598
|
-
return retry(setting, checkpoint, {
|
|
1599
|
-
newMessages: [
|
|
1600
|
-
createExpertMessage([
|
|
1601
|
-
{
|
|
1602
|
-
type: "toolCallPart",
|
|
1603
|
-
toolCallId: toolCall.toolCallId,
|
|
1604
|
-
toolName: toolCall.toolName,
|
|
1605
|
-
args: toolCall.args
|
|
1606
|
-
}
|
|
1607
|
-
]),
|
|
1608
|
-
createToolMessage([
|
|
1609
|
-
{
|
|
1610
|
-
type: "toolResultPart",
|
|
1611
|
-
toolCallId: toolCall.toolCallId,
|
|
1612
|
-
toolName: toolCall.toolName,
|
|
1613
|
-
contents: [{ type: "textPart", text: "Error: Generation length exceeded" }]
|
|
1614
|
-
}
|
|
1615
|
-
])
|
|
1616
|
-
],
|
|
1617
|
-
usage
|
|
1618
|
-
});
|
|
1619
|
-
}
|
|
1620
|
-
default:
|
|
1621
|
-
throw new Error(`Unexpected finish reason: ${finishReason}`);
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
1638
|
const contents = [
|
|
1625
1639
|
{
|
|
1626
1640
|
type: "toolCallPart",
|
|
1627
1641
|
toolCallId: toolCall.toolCallId,
|
|
1628
1642
|
toolName: toolCall.toolName,
|
|
1629
|
-
args: toolCall.
|
|
1643
|
+
args: toolCall.input
|
|
1630
1644
|
}
|
|
1631
1645
|
];
|
|
1632
1646
|
if (text) {
|
|
@@ -1642,22 +1656,55 @@ async function generatingToolCallLogic({
|
|
|
1642
1656
|
id: toolCall.toolCallId,
|
|
1643
1657
|
skillName: skillManager.name,
|
|
1644
1658
|
toolName: toolCall.toolName,
|
|
1645
|
-
args: toolCall.
|
|
1659
|
+
args: toolCall.input
|
|
1646
1660
|
},
|
|
1647
1661
|
usage
|
|
1648
1662
|
};
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1663
|
+
if (finishReason === "tool-calls") {
|
|
1664
|
+
switch (skillManager.type) {
|
|
1665
|
+
case "mcp":
|
|
1666
|
+
return callTool(setting, checkpoint, eventPayload);
|
|
1667
|
+
case "interactive":
|
|
1668
|
+
return callInteractiveTool(setting, checkpoint, eventPayload);
|
|
1669
|
+
case "delegate":
|
|
1670
|
+
return callDelegate(setting, checkpoint, eventPayload);
|
|
1671
|
+
}
|
|
1656
1672
|
}
|
|
1673
|
+
if (finishReason === "length") {
|
|
1674
|
+
return retry(setting, checkpoint, {
|
|
1675
|
+
newMessages: [
|
|
1676
|
+
createExpertMessage([
|
|
1677
|
+
{
|
|
1678
|
+
type: "toolCallPart",
|
|
1679
|
+
toolCallId: toolCall.toolCallId,
|
|
1680
|
+
toolName: toolCall.toolName,
|
|
1681
|
+
args: toolCall.input
|
|
1682
|
+
}
|
|
1683
|
+
]),
|
|
1684
|
+
createToolMessage([
|
|
1685
|
+
{
|
|
1686
|
+
type: "toolResultPart",
|
|
1687
|
+
toolCallId: toolCall.toolCallId,
|
|
1688
|
+
toolName: toolCall.toolName,
|
|
1689
|
+
contents: [{ type: "textPart", text: "Error: Generation length exceeded" }]
|
|
1690
|
+
}
|
|
1691
|
+
])
|
|
1692
|
+
],
|
|
1693
|
+
toolCall: eventPayload.toolCall,
|
|
1694
|
+
toolResult: {
|
|
1695
|
+
id: toolCall.toolCallId,
|
|
1696
|
+
skillName: skillManager.name,
|
|
1697
|
+
toolName: toolCall.toolName,
|
|
1698
|
+
result: [{ type: "textPart", id: createId6(), text: "Error: Generation length exceeded" }]
|
|
1699
|
+
},
|
|
1700
|
+
usage
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
throw new Error(`Unexpected finish reason: ${finishReason}`);
|
|
1657
1704
|
}
|
|
1658
1705
|
|
|
1659
1706
|
// src/messages/instruction-message.ts
|
|
1660
|
-
import { createId as
|
|
1707
|
+
import { createId as createId7 } from "@paralleldrive/cuid2";
|
|
1661
1708
|
import { dedent as dedent2 } from "ts-dedent";
|
|
1662
1709
|
var metaInstruction = dedent2`
|
|
1663
1710
|
IMPORTANT:
|
|
@@ -1731,12 +1778,12 @@ function createInstructionMessage(expert, experts) {
|
|
|
1731
1778
|
type: "instructionMessage",
|
|
1732
1779
|
contents: [
|
|
1733
1780
|
{
|
|
1734
|
-
id:
|
|
1781
|
+
id: createId7(),
|
|
1735
1782
|
type: "textPart",
|
|
1736
1783
|
text: instruction
|
|
1737
1784
|
}
|
|
1738
1785
|
],
|
|
1739
|
-
id:
|
|
1786
|
+
id: createId7(),
|
|
1740
1787
|
cache: true
|
|
1741
1788
|
};
|
|
1742
1789
|
}
|
|
@@ -1797,6 +1844,19 @@ async function initLogic({
|
|
|
1797
1844
|
inputMessages: [createUserMessage([{ type: "textPart", text: setting.input.text }])]
|
|
1798
1845
|
});
|
|
1799
1846
|
}
|
|
1847
|
+
case "stoppedByDelegate": {
|
|
1848
|
+
if (!setting.input.interactiveToolCallResult) {
|
|
1849
|
+
throw new Error("Interactive tool call result is undefined");
|
|
1850
|
+
}
|
|
1851
|
+
return startRun(setting, checkpoint, {
|
|
1852
|
+
initialCheckpoint: checkpoint,
|
|
1853
|
+
inputMessages: [
|
|
1854
|
+
createUserMessage([
|
|
1855
|
+
{ type: "textPart", text: setting.input.interactiveToolCallResult.text }
|
|
1856
|
+
])
|
|
1857
|
+
]
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1800
1860
|
case "stoppedByInteractiveTool": {
|
|
1801
1861
|
if (!setting.input.interactiveToolCallResult) {
|
|
1802
1862
|
throw new Error("Interactive tool call result is undefined");
|
|
@@ -2045,6 +2105,8 @@ var runtimeStateMachine = setup({
|
|
|
2045
2105
|
step: ({ context, event }) => ({
|
|
2046
2106
|
...context.step,
|
|
2047
2107
|
newMessages: event.newMessages,
|
|
2108
|
+
toolCall: event.toolCall,
|
|
2109
|
+
toolResult: event.toolResult,
|
|
2048
2110
|
usage: sumUsage(context.step.usage, event.usage)
|
|
2049
2111
|
})
|
|
2050
2112
|
})
|
|
@@ -2218,6 +2280,23 @@ var runtimeStateMachine = setup({
|
|
|
2218
2280
|
},
|
|
2219
2281
|
GeneratingRunResult: {
|
|
2220
2282
|
on: {
|
|
2283
|
+
retry: {
|
|
2284
|
+
target: "FinishingStep",
|
|
2285
|
+
actions: assign({
|
|
2286
|
+
checkpoint: ({ context, event }) => ({
|
|
2287
|
+
...context.checkpoint,
|
|
2288
|
+
messages: [...context.checkpoint.messages, ...event.newMessages],
|
|
2289
|
+
usage: sumUsage(context.checkpoint.usage, event.usage)
|
|
2290
|
+
}),
|
|
2291
|
+
step: ({ context, event }) => ({
|
|
2292
|
+
...context.step,
|
|
2293
|
+
newMessages: event.newMessages,
|
|
2294
|
+
toolCall: event.toolCall,
|
|
2295
|
+
toolResult: event.toolResult,
|
|
2296
|
+
usage: sumUsage(context.step.usage, event.usage)
|
|
2297
|
+
})
|
|
2298
|
+
})
|
|
2299
|
+
},
|
|
2221
2300
|
completeRun: {
|
|
2222
2301
|
target: "Stopped",
|
|
2223
2302
|
actions: assign({
|
|
@@ -2301,6 +2380,7 @@ var PerstackConfigSchema = z4.object({
|
|
|
2301
2380
|
temperature: z4.number().optional(),
|
|
2302
2381
|
maxSteps: z4.number().optional(),
|
|
2303
2382
|
maxRetries: z4.number().optional(),
|
|
2383
|
+
timeout: z4.number().optional(),
|
|
2304
2384
|
experts: z4.record(
|
|
2305
2385
|
z4.string(),
|
|
2306
2386
|
z4.object({
|
|
@@ -2358,6 +2438,9 @@ async function run(runInput, options) {
|
|
|
2358
2438
|
const eventEmitter = new RunEventEmitter();
|
|
2359
2439
|
eventEmitter.subscribe(eventListener);
|
|
2360
2440
|
let { setting, checkpoint } = runParams;
|
|
2441
|
+
if (checkpoint) {
|
|
2442
|
+
checkpoint.status = "proceeding";
|
|
2443
|
+
}
|
|
2361
2444
|
if (setting.workspace) {
|
|
2362
2445
|
if (!path.isAbsolute(setting.workspace)) {
|
|
2363
2446
|
throw new Error(`Workspace path must be absolute: ${setting.workspace}`);
|
|
@@ -2376,19 +2459,11 @@ async function run(runInput, options) {
|
|
|
2376
2459
|
experts
|
|
2377
2460
|
},
|
|
2378
2461
|
initialCheckpoint: checkpoint ? {
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
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
|
|
2462
|
+
...checkpoint,
|
|
2463
|
+
id: createId8(),
|
|
2464
|
+
stepNumber: checkpoint.stepNumber + 1
|
|
2390
2465
|
} : {
|
|
2391
|
-
id:
|
|
2466
|
+
id: createId8(),
|
|
2392
2467
|
runId: setting.runId,
|
|
2393
2468
|
expert: {
|
|
2394
2469
|
key: setting.expertKey,
|
|
@@ -2468,8 +2543,7 @@ async function run(runInput, options) {
|
|
|
2468
2543
|
};
|
|
2469
2544
|
checkpoint = {
|
|
2470
2545
|
...await retrieveCheckpoint(setting.runId, checkpointId),
|
|
2471
|
-
|
|
2472
|
-
stepNumber: runResultCheckpoint.stepNumber + 1,
|
|
2546
|
+
stepNumber: runResultCheckpoint.stepNumber,
|
|
2473
2547
|
usage: runResultCheckpoint.usage
|
|
2474
2548
|
};
|
|
2475
2549
|
break;
|
|
@@ -2492,10 +2566,8 @@ async function run(runInput, options) {
|
|
|
2492
2566
|
}
|
|
2493
2567
|
};
|
|
2494
2568
|
checkpoint = {
|
|
2495
|
-
|
|
2496
|
-
runId: setting.runId,
|
|
2569
|
+
...runResultCheckpoint,
|
|
2497
2570
|
status: "init",
|
|
2498
|
-
stepNumber: runResultCheckpoint.stepNumber + 1,
|
|
2499
2571
|
messages: [],
|
|
2500
2572
|
expert: {
|
|
2501
2573
|
key: expert.key,
|
|
@@ -2540,13 +2612,14 @@ async function setupExperts(setting) {
|
|
|
2540
2612
|
return { expertToRun, experts };
|
|
2541
2613
|
}
|
|
2542
2614
|
function printRunSetting(expertName, experts, setting) {
|
|
2543
|
-
console.log("
|
|
2615
|
+
console.log("Starting Perstack");
|
|
2544
2616
|
console.log(`Expert To Run: ${expertName}`);
|
|
2545
2617
|
console.log(`Experts: ${Object.keys(experts).join(", ")}`);
|
|
2546
2618
|
console.log(`Model: ${setting.model}`);
|
|
2547
2619
|
console.log(`Temperature: ${setting.temperature}`);
|
|
2548
2620
|
console.log(`Max Steps: ${setting.maxSteps}`);
|
|
2549
2621
|
console.log(`Max Retries: ${setting.maxRetries}`);
|
|
2622
|
+
console.log(`Timeout: ${setting.timeout}`);
|
|
2550
2623
|
if (setting.input.text) {
|
|
2551
2624
|
console.log(`Query: ${setting.input.text}`);
|
|
2552
2625
|
}
|
|
@@ -2618,6 +2691,16 @@ var RunInputSchema = z5.object({
|
|
|
2618
2691
|
}
|
|
2619
2692
|
return parsedValue;
|
|
2620
2693
|
}),
|
|
2694
|
+
timeout: z5.string().optional().transform((value) => {
|
|
2695
|
+
if (value === void 0) {
|
|
2696
|
+
return void 0;
|
|
2697
|
+
}
|
|
2698
|
+
const parsedValue = Number.parseInt(value);
|
|
2699
|
+
if (Number.isNaN(parsedValue)) {
|
|
2700
|
+
return void 0;
|
|
2701
|
+
}
|
|
2702
|
+
return parsedValue;
|
|
2703
|
+
}),
|
|
2621
2704
|
runId: z5.string().optional()
|
|
2622
2705
|
})
|
|
2623
2706
|
});
|