@perstack/runtime 0.0.67 → 0.0.68
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.
|
@@ -22,7 +22,7 @@ import { ApiV1Client } from '@perstack/api-client/v1';
|
|
|
22
22
|
// package.json
|
|
23
23
|
var package_default = {
|
|
24
24
|
name: "@perstack/runtime",
|
|
25
|
-
version: "0.0.
|
|
25
|
+
version: "0.0.68",
|
|
26
26
|
description: "Perstack Runtime",
|
|
27
27
|
author: "Wintermute Technologies, Inc.",
|
|
28
28
|
license: "Apache-2.0",
|
|
@@ -353,12 +353,15 @@ var McpSkillManager = class extends BaseSkillManager {
|
|
|
353
353
|
name: `${this.skill.name}-mcp-client`,
|
|
354
354
|
version: "1.0.0"
|
|
355
355
|
});
|
|
356
|
+
let timingInfo;
|
|
356
357
|
if (this.skill.type === "mcpStdioSkill") {
|
|
357
|
-
await this._initStdio(this.skill);
|
|
358
|
+
timingInfo = await this._initStdio(this.skill);
|
|
358
359
|
} else {
|
|
359
360
|
await this._initSse(this.skill);
|
|
360
361
|
}
|
|
362
|
+
const toolDiscoveryStartTime = Date.now();
|
|
361
363
|
const { tools } = await this._mcpClient.listTools();
|
|
364
|
+
const toolDiscoveryDurationMs = Date.now() - toolDiscoveryStartTime;
|
|
362
365
|
this._toolDefinitions = tools.map((tool2) => ({
|
|
363
366
|
skillName: this.skill.name,
|
|
364
367
|
name: tool2.name,
|
|
@@ -366,6 +369,19 @@ var McpSkillManager = class extends BaseSkillManager {
|
|
|
366
369
|
inputSchema: tool2.inputSchema,
|
|
367
370
|
interactive: false
|
|
368
371
|
}));
|
|
372
|
+
if (this._eventListener && timingInfo) {
|
|
373
|
+
const totalDurationMs = Date.now() - timingInfo.startTime;
|
|
374
|
+
const event = createRuntimeEvent("skillConnected", this._jobId, this._runId, {
|
|
375
|
+
skillName: this.skill.name,
|
|
376
|
+
serverInfo: timingInfo.serverInfo,
|
|
377
|
+
spawnDurationMs: timingInfo.spawnDurationMs,
|
|
378
|
+
handshakeDurationMs: timingInfo.handshakeDurationMs,
|
|
379
|
+
toolDiscoveryDurationMs,
|
|
380
|
+
connectDurationMs: timingInfo.spawnDurationMs + timingInfo.handshakeDurationMs,
|
|
381
|
+
totalDurationMs
|
|
382
|
+
});
|
|
383
|
+
this._eventListener(event);
|
|
384
|
+
}
|
|
369
385
|
}
|
|
370
386
|
async _initStdio(skill) {
|
|
371
387
|
if (!skill.command) {
|
|
@@ -390,6 +406,7 @@ var McpSkillManager = class extends BaseSkillManager {
|
|
|
390
406
|
this._eventListener(event);
|
|
391
407
|
}
|
|
392
408
|
const transport = new StdioClientTransport({ command, args, env, stderr: "pipe" });
|
|
409
|
+
const spawnDurationMs = Date.now() - startTime;
|
|
393
410
|
if (transport.stderr) {
|
|
394
411
|
transport.stderr.on("data", (chunk) => {
|
|
395
412
|
if (this._eventListener) {
|
|
@@ -403,17 +420,14 @@ var McpSkillManager = class extends BaseSkillManager {
|
|
|
403
420
|
}
|
|
404
421
|
const connectStartTime = Date.now();
|
|
405
422
|
await this._mcpClient.connect(transport);
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
});
|
|
415
|
-
this._eventListener(event);
|
|
416
|
-
}
|
|
423
|
+
const handshakeDurationMs = Date.now() - connectStartTime;
|
|
424
|
+
const serverVersion = this._mcpClient.getServerVersion();
|
|
425
|
+
return {
|
|
426
|
+
startTime,
|
|
427
|
+
spawnDurationMs,
|
|
428
|
+
handshakeDurationMs,
|
|
429
|
+
serverInfo: serverVersion ? { name: serverVersion.name, version: serverVersion.version } : void 0
|
|
430
|
+
};
|
|
417
431
|
}
|
|
418
432
|
async _initSse(skill) {
|
|
419
433
|
if (!skill.endpoint) {
|
|
@@ -671,12 +685,140 @@ async function getToolSet(skillManagers) {
|
|
|
671
685
|
}
|
|
672
686
|
return tools;
|
|
673
687
|
}
|
|
688
|
+
function isFileInfo(value) {
|
|
689
|
+
return typeof value === "object" && value !== null && "path" in value && "mimeType" in value && "size" in value && typeof value.path === "string" && typeof value.mimeType === "string" && typeof value.size === "number";
|
|
690
|
+
}
|
|
691
|
+
async function processFileToolResult(toolResult, toolName) {
|
|
692
|
+
const processedContents = [];
|
|
693
|
+
for (const part of toolResult.result) {
|
|
694
|
+
if (part.type !== "textPart") {
|
|
695
|
+
processedContents.push(part);
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
let fileInfo;
|
|
699
|
+
try {
|
|
700
|
+
const parsed = JSON.parse(part.text);
|
|
701
|
+
if (isFileInfo(parsed)) {
|
|
702
|
+
fileInfo = parsed;
|
|
703
|
+
}
|
|
704
|
+
} catch {
|
|
705
|
+
processedContents.push(part);
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
if (!fileInfo) {
|
|
709
|
+
processedContents.push(part);
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
const { path, mimeType } = fileInfo;
|
|
713
|
+
try {
|
|
714
|
+
const buffer = await readFile(path);
|
|
715
|
+
if (toolName === "readImageFile") {
|
|
716
|
+
processedContents.push({
|
|
717
|
+
type: "imageInlinePart",
|
|
718
|
+
id: part.id,
|
|
719
|
+
encodedData: buffer.toString("base64"),
|
|
720
|
+
mimeType
|
|
721
|
+
});
|
|
722
|
+
} else {
|
|
723
|
+
processedContents.push({
|
|
724
|
+
type: "fileInlinePart",
|
|
725
|
+
id: part.id,
|
|
726
|
+
encodedData: buffer.toString("base64"),
|
|
727
|
+
mimeType
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
} catch (error) {
|
|
731
|
+
processedContents.push({
|
|
732
|
+
type: "textPart",
|
|
733
|
+
id: part.id,
|
|
734
|
+
text: `Failed to read file "${path}": ${error instanceof Error ? error.message : String(error)}`
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return { ...toolResult, result: processedContents };
|
|
739
|
+
}
|
|
740
|
+
var McpToolExecutor = class {
|
|
741
|
+
type = "mcp";
|
|
742
|
+
async execute(toolCall, skillManagers) {
|
|
743
|
+
const skillManager = await getSkillManagerByToolName(skillManagers, toolCall.toolName);
|
|
744
|
+
if (skillManager.type !== "mcp") {
|
|
745
|
+
throw new Error(`Incorrect SkillType, required MCP, got ${skillManager.type}`);
|
|
746
|
+
}
|
|
747
|
+
const result = await skillManager.callTool(
|
|
748
|
+
toolCall.toolName,
|
|
749
|
+
toolCall.args
|
|
750
|
+
);
|
|
751
|
+
const toolResult = {
|
|
752
|
+
id: toolCall.id,
|
|
753
|
+
skillName: toolCall.skillName,
|
|
754
|
+
toolName: toolCall.toolName,
|
|
755
|
+
result
|
|
756
|
+
};
|
|
757
|
+
if (toolCall.toolName === "readPdfFile" || toolCall.toolName === "readImageFile") {
|
|
758
|
+
return processFileToolResult(toolResult, toolCall.toolName);
|
|
759
|
+
}
|
|
760
|
+
return toolResult;
|
|
761
|
+
}
|
|
762
|
+
};
|
|
674
763
|
|
|
675
|
-
// src/
|
|
676
|
-
|
|
764
|
+
// src/tool-execution/executor-factory.ts
|
|
765
|
+
var ToolExecutorFactory = class {
|
|
766
|
+
executors;
|
|
767
|
+
constructor() {
|
|
768
|
+
this.executors = /* @__PURE__ */ new Map([
|
|
769
|
+
["mcp", new McpToolExecutor()]
|
|
770
|
+
// delegate and interactive are handled specially (not executed here)
|
|
771
|
+
]);
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Get the executor for a given skill type
|
|
775
|
+
*/
|
|
776
|
+
getExecutor(type) {
|
|
777
|
+
return this.executors.get(type);
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Execute a tool call using the appropriate executor
|
|
781
|
+
*/
|
|
782
|
+
async execute(toolCall, type, skillManagers) {
|
|
783
|
+
const executor = this.executors.get(type);
|
|
784
|
+
if (!executor) {
|
|
785
|
+
throw new Error(`No executor registered for skill type: ${type}`);
|
|
786
|
+
}
|
|
787
|
+
return executor.execute(toolCall, skillManagers);
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Check if a skill type can be executed locally (vs requiring delegation)
|
|
791
|
+
*/
|
|
792
|
+
canExecuteLocally(type) {
|
|
793
|
+
return type === "mcp";
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
var toolExecutorFactory = new ToolExecutorFactory();
|
|
797
|
+
|
|
798
|
+
// src/tool-execution/tool-classifier.ts
|
|
799
|
+
async function getToolTypeByName(toolName, skillManagers) {
|
|
677
800
|
const skillManager = await getSkillManagerByToolName(skillManagers, toolName);
|
|
678
801
|
return skillManager.type;
|
|
679
802
|
}
|
|
803
|
+
async function classifyToolCalls(toolCalls, skillManagers) {
|
|
804
|
+
const classified = {
|
|
805
|
+
mcp: [],
|
|
806
|
+
delegate: [],
|
|
807
|
+
interactive: []
|
|
808
|
+
};
|
|
809
|
+
const results = await Promise.all(
|
|
810
|
+
toolCalls.map(async (toolCall) => {
|
|
811
|
+
const skillManager = await getSkillManagerByToolName(skillManagers, toolCall.toolName);
|
|
812
|
+
return { toolCall, type: skillManager.type, skillManager };
|
|
813
|
+
})
|
|
814
|
+
);
|
|
815
|
+
for (const result of results) {
|
|
816
|
+
classified[result.type].push(result);
|
|
817
|
+
}
|
|
818
|
+
return classified;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// src/state-machine/states/calling-delegate.ts
|
|
680
822
|
async function callingDelegateLogic({
|
|
681
823
|
setting,
|
|
682
824
|
checkpoint,
|
|
@@ -689,7 +831,7 @@ async function callingDelegateLogic({
|
|
|
689
831
|
const toolCallTypes = await Promise.all(
|
|
690
832
|
step.pendingToolCalls.map(async (tc) => ({
|
|
691
833
|
toolCall: tc,
|
|
692
|
-
type: await
|
|
834
|
+
type: await getToolTypeByName(tc.toolName, skillManagers)
|
|
693
835
|
}))
|
|
694
836
|
);
|
|
695
837
|
const delegateToolCalls = toolCallTypes.filter((t) => t.type === "delegate").map((t) => t.toolCall);
|
|
@@ -767,79 +909,6 @@ function hasRemainingTodos(toolResult) {
|
|
|
767
909
|
return false;
|
|
768
910
|
}
|
|
769
911
|
}
|
|
770
|
-
function isFileInfo(value) {
|
|
771
|
-
return typeof value === "object" && value !== null && "path" in value && "mimeType" in value && "size" in value && typeof value.path === "string" && typeof value.mimeType === "string" && typeof value.size === "number";
|
|
772
|
-
}
|
|
773
|
-
async function processFileToolResult(toolResult, toolName) {
|
|
774
|
-
const processedContents = [];
|
|
775
|
-
for (const part of toolResult.result) {
|
|
776
|
-
if (part.type !== "textPart") {
|
|
777
|
-
processedContents.push(part);
|
|
778
|
-
continue;
|
|
779
|
-
}
|
|
780
|
-
let fileInfo;
|
|
781
|
-
try {
|
|
782
|
-
const parsed = JSON.parse(part.text);
|
|
783
|
-
if (isFileInfo(parsed)) {
|
|
784
|
-
fileInfo = parsed;
|
|
785
|
-
}
|
|
786
|
-
} catch {
|
|
787
|
-
processedContents.push(part);
|
|
788
|
-
continue;
|
|
789
|
-
}
|
|
790
|
-
if (!fileInfo) {
|
|
791
|
-
processedContents.push(part);
|
|
792
|
-
continue;
|
|
793
|
-
}
|
|
794
|
-
const { path, mimeType } = fileInfo;
|
|
795
|
-
try {
|
|
796
|
-
const buffer = await readFile(path);
|
|
797
|
-
if (toolName === "readImageFile") {
|
|
798
|
-
processedContents.push({
|
|
799
|
-
type: "imageInlinePart",
|
|
800
|
-
id: part.id,
|
|
801
|
-
encodedData: buffer.toString("base64"),
|
|
802
|
-
mimeType
|
|
803
|
-
});
|
|
804
|
-
} else {
|
|
805
|
-
processedContents.push({
|
|
806
|
-
type: "fileInlinePart",
|
|
807
|
-
id: part.id,
|
|
808
|
-
encodedData: buffer.toString("base64"),
|
|
809
|
-
mimeType
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
|
-
} catch (error) {
|
|
813
|
-
processedContents.push({
|
|
814
|
-
type: "textPart",
|
|
815
|
-
id: part.id,
|
|
816
|
-
text: `Failed to read file "${path}": ${error instanceof Error ? error.message : String(error)}`
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
return { ...toolResult, result: processedContents };
|
|
821
|
-
}
|
|
822
|
-
async function executeMcpToolCall(toolCall, skillManagers) {
|
|
823
|
-
const skillManager = await getSkillManagerByToolName(skillManagers, toolCall.toolName);
|
|
824
|
-
if (skillManager.type !== "mcp") {
|
|
825
|
-
throw new Error(`Incorrect SkillType, required MCP, got ${skillManager.type}`);
|
|
826
|
-
}
|
|
827
|
-
const result = await skillManager.callTool(toolCall.toolName, toolCall.args);
|
|
828
|
-
const toolResult = {
|
|
829
|
-
id: toolCall.id,
|
|
830
|
-
skillName: toolCall.skillName,
|
|
831
|
-
toolName: toolCall.toolName,
|
|
832
|
-
result
|
|
833
|
-
};
|
|
834
|
-
if (toolCall.toolName === "readPdfFile" || toolCall.toolName === "readImageFile") {
|
|
835
|
-
return processFileToolResult(toolResult, toolCall.toolName);
|
|
836
|
-
}
|
|
837
|
-
return toolResult;
|
|
838
|
-
}
|
|
839
|
-
async function getToolType2(toolCall, skillManagers) {
|
|
840
|
-
const skillManager = await getSkillManagerByToolName(skillManagers, toolCall.toolName);
|
|
841
|
-
return skillManager.type;
|
|
842
|
-
}
|
|
843
912
|
async function callingToolLogic({
|
|
844
913
|
setting,
|
|
845
914
|
checkpoint,
|
|
@@ -855,28 +924,26 @@ async function callingToolLogic({
|
|
|
855
924
|
(tc) => tc.skillName === "@perstack/base" && tc.toolName === "attemptCompletion"
|
|
856
925
|
);
|
|
857
926
|
if (attemptCompletionTool) {
|
|
858
|
-
const toolResult = await
|
|
927
|
+
const toolResult = await toolExecutorFactory.execute(
|
|
928
|
+
attemptCompletionTool,
|
|
929
|
+
"mcp",
|
|
930
|
+
skillManagers
|
|
931
|
+
);
|
|
859
932
|
if (hasRemainingTodos(toolResult)) {
|
|
860
933
|
return resolveToolResults(setting, checkpoint, { toolResults: [toolResult] });
|
|
861
934
|
}
|
|
862
935
|
return attemptCompletion(setting, checkpoint, { toolResult });
|
|
863
936
|
}
|
|
864
|
-
const
|
|
865
|
-
|
|
866
|
-
toolCall: tc,
|
|
867
|
-
type: await getToolType2(tc, skillManagers)
|
|
868
|
-
}))
|
|
869
|
-
);
|
|
870
|
-
const mcpToolCalls = toolCallTypes.filter((t) => t.type === "mcp").map((t) => t.toolCall);
|
|
871
|
-
const delegateToolCalls = toolCallTypes.filter((t) => t.type === "delegate").map((t) => t.toolCall);
|
|
872
|
-
const interactiveToolCalls = toolCallTypes.filter((t) => t.type === "interactive").map((t) => t.toolCall);
|
|
873
|
-
if (mcpToolCalls.length > 0) {
|
|
937
|
+
const classified = await classifyToolCalls(pendingToolCalls, skillManagers);
|
|
938
|
+
if (classified.mcp.length > 0) {
|
|
874
939
|
const mcpResults = await Promise.all(
|
|
875
|
-
|
|
940
|
+
classified.mcp.map((c) => toolExecutorFactory.execute(c.toolCall, "mcp", skillManagers))
|
|
876
941
|
);
|
|
877
942
|
toolResults.push(...mcpResults);
|
|
878
943
|
}
|
|
879
|
-
if (
|
|
944
|
+
if (classified.delegate.length > 0) {
|
|
945
|
+
const delegateToolCalls = classified.delegate.map((c) => c.toolCall);
|
|
946
|
+
const interactiveToolCalls = classified.interactive.map((c) => c.toolCall);
|
|
880
947
|
step.partialToolResults = toolResults;
|
|
881
948
|
step.pendingToolCalls = [...delegateToolCalls, ...interactiveToolCalls];
|
|
882
949
|
return callDelegate(setting, checkpoint, {
|
|
@@ -885,11 +952,12 @@ async function callingToolLogic({
|
|
|
885
952
|
usage: step.usage
|
|
886
953
|
});
|
|
887
954
|
}
|
|
888
|
-
if (
|
|
889
|
-
const interactiveToolCall =
|
|
955
|
+
if (classified.interactive.length > 0) {
|
|
956
|
+
const interactiveToolCall = classified.interactive[0]?.toolCall;
|
|
890
957
|
if (!interactiveToolCall) {
|
|
891
958
|
throw new Error("No interactive tool call found");
|
|
892
959
|
}
|
|
960
|
+
const interactiveToolCalls = classified.interactive.map((c) => c.toolCall);
|
|
893
961
|
step.partialToolResults = toolResults;
|
|
894
962
|
step.pendingToolCalls = interactiveToolCalls;
|
|
895
963
|
return callInteractiveTool(setting, checkpoint, {
|
|
@@ -1198,7 +1266,7 @@ async function generatingRunResultLogic({
|
|
|
1198
1266
|
usage
|
|
1199
1267
|
});
|
|
1200
1268
|
}
|
|
1201
|
-
async function
|
|
1269
|
+
async function classifyToolCalls2(toolCalls, skillManagers) {
|
|
1202
1270
|
return Promise.all(
|
|
1203
1271
|
toolCalls.map(async (tc) => {
|
|
1204
1272
|
const skillManager = await getSkillManagerByToolName(skillManagers, tc.toolName);
|
|
@@ -1275,7 +1343,7 @@ async function generatingToolCallLogic({
|
|
|
1275
1343
|
usage
|
|
1276
1344
|
});
|
|
1277
1345
|
}
|
|
1278
|
-
const classified = await
|
|
1346
|
+
const classified = await classifyToolCalls2(toolCalls, skillManagers);
|
|
1279
1347
|
const sorted = sortToolCallsByPriority(classified);
|
|
1280
1348
|
if (finishReason === "tool-calls" || finishReason === "stop") {
|
|
1281
1349
|
const toolCallParts = buildToolCallParts(sorted);
|
|
@@ -1963,29 +2031,6 @@ async function executeStateMachine(params) {
|
|
|
1963
2031
|
runActor.start();
|
|
1964
2032
|
});
|
|
1965
2033
|
}
|
|
1966
|
-
var RunEventEmitter = class {
|
|
1967
|
-
listeners = [];
|
|
1968
|
-
subscribe(listener) {
|
|
1969
|
-
this.listeners.push(listener);
|
|
1970
|
-
}
|
|
1971
|
-
async emit(event) {
|
|
1972
|
-
const errors = [];
|
|
1973
|
-
for (const listener of this.listeners) {
|
|
1974
|
-
try {
|
|
1975
|
-
await listener({
|
|
1976
|
-
...event,
|
|
1977
|
-
id: createId(),
|
|
1978
|
-
timestamp: Date.now()
|
|
1979
|
-
});
|
|
1980
|
-
} catch (error) {
|
|
1981
|
-
errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
if (errors.length > 0) {
|
|
1985
|
-
throw new AggregateError(errors, "One or more event listeners failed");
|
|
1986
|
-
}
|
|
1987
|
-
}
|
|
1988
|
-
};
|
|
1989
2034
|
|
|
1990
2035
|
// src/helpers/checkpoint.ts
|
|
1991
2036
|
function createInitialCheckpoint(checkpointId, params) {
|
|
@@ -2049,46 +2094,6 @@ function buildDelegationReturnState(currentSetting, resultCheckpoint, parentChec
|
|
|
2049
2094
|
}
|
|
2050
2095
|
};
|
|
2051
2096
|
}
|
|
2052
|
-
function buildDelegateToState(currentSetting, resultCheckpoint, currentExpert) {
|
|
2053
|
-
const { delegateTo } = resultCheckpoint;
|
|
2054
|
-
if (!delegateTo || delegateTo.length === 0) {
|
|
2055
|
-
throw new Error("delegateTo is required for buildDelegateToState");
|
|
2056
|
-
}
|
|
2057
|
-
const firstDelegation = delegateTo[0];
|
|
2058
|
-
const { expert, toolCallId, toolName, query } = firstDelegation;
|
|
2059
|
-
return {
|
|
2060
|
-
setting: {
|
|
2061
|
-
...currentSetting,
|
|
2062
|
-
expertKey: expert.key,
|
|
2063
|
-
input: {
|
|
2064
|
-
text: query
|
|
2065
|
-
}
|
|
2066
|
-
},
|
|
2067
|
-
checkpoint: {
|
|
2068
|
-
...resultCheckpoint,
|
|
2069
|
-
status: "init",
|
|
2070
|
-
messages: [],
|
|
2071
|
-
expert: {
|
|
2072
|
-
key: expert.key,
|
|
2073
|
-
name: expert.name,
|
|
2074
|
-
version: expert.version
|
|
2075
|
-
},
|
|
2076
|
-
delegatedBy: {
|
|
2077
|
-
expert: {
|
|
2078
|
-
key: currentExpert.key,
|
|
2079
|
-
name: currentExpert.name,
|
|
2080
|
-
version: currentExpert.version
|
|
2081
|
-
},
|
|
2082
|
-
toolCallId,
|
|
2083
|
-
toolName,
|
|
2084
|
-
checkpointId: resultCheckpoint.id
|
|
2085
|
-
},
|
|
2086
|
-
usage: resultCheckpoint.usage,
|
|
2087
|
-
pendingToolCalls: void 0,
|
|
2088
|
-
partialToolResults: void 0
|
|
2089
|
-
}
|
|
2090
|
-
};
|
|
2091
|
-
}
|
|
2092
2097
|
async function resolveExpertToRun(expertKey, experts, clientOptions) {
|
|
2093
2098
|
if (experts[expertKey]) {
|
|
2094
2099
|
return experts[expertKey];
|
|
@@ -2138,68 +2143,245 @@ async function setupExperts(setting, resolveExpertToRun2 = resolveExpertToRun) {
|
|
|
2138
2143
|
}
|
|
2139
2144
|
return { expertToRun, experts };
|
|
2140
2145
|
}
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2146
|
+
var SingleDelegationStrategy = class {
|
|
2147
|
+
async execute(delegations, setting, context, parentExpert, _runFn, _parentOptions) {
|
|
2148
|
+
if (delegations.length !== 1) {
|
|
2149
|
+
throw new Error("SingleDelegationStrategy requires exactly one delegation");
|
|
2150
|
+
}
|
|
2151
|
+
const delegation = delegations[0];
|
|
2152
|
+
const { expert, toolCallId, toolName, query } = delegation;
|
|
2153
|
+
const nextSetting = {
|
|
2154
|
+
...setting,
|
|
2155
|
+
expertKey: expert.key,
|
|
2156
|
+
input: { text: query }
|
|
2157
|
+
};
|
|
2158
|
+
const nextCheckpoint = {
|
|
2159
|
+
id: context.id,
|
|
2160
|
+
jobId: setting.jobId,
|
|
2161
|
+
runId: setting.runId,
|
|
2162
|
+
status: "init",
|
|
2163
|
+
stepNumber: context.stepNumber,
|
|
2164
|
+
messages: [],
|
|
2165
|
+
// Child starts fresh
|
|
2166
|
+
expert: {
|
|
2167
|
+
key: expert.key,
|
|
2168
|
+
name: expert.name,
|
|
2169
|
+
version: expert.version
|
|
2170
|
+
},
|
|
2171
|
+
delegatedBy: {
|
|
2172
|
+
expert: {
|
|
2173
|
+
key: parentExpert.key,
|
|
2174
|
+
name: parentExpert.name,
|
|
2175
|
+
version: parentExpert.version
|
|
2176
|
+
},
|
|
2177
|
+
toolCallId,
|
|
2178
|
+
toolName,
|
|
2179
|
+
checkpointId: context.id
|
|
2180
|
+
},
|
|
2181
|
+
usage: context.usage,
|
|
2182
|
+
contextWindow: context.contextWindow,
|
|
2183
|
+
pendingToolCalls: void 0,
|
|
2184
|
+
partialToolResults: void 0
|
|
2185
|
+
};
|
|
2186
|
+
return { nextSetting, nextCheckpoint };
|
|
2187
|
+
}
|
|
2148
2188
|
};
|
|
2149
|
-
var
|
|
2150
|
-
|
|
2151
|
-
|
|
2189
|
+
var ParallelDelegationStrategy = class {
|
|
2190
|
+
async execute(delegations, setting, context, parentExpert, runFn, parentOptions) {
|
|
2191
|
+
if (delegations.length < 2) {
|
|
2192
|
+
throw new Error("ParallelDelegationStrategy requires at least two delegations");
|
|
2193
|
+
}
|
|
2194
|
+
const [firstDelegation, ...remainingDelegations] = delegations;
|
|
2195
|
+
if (!firstDelegation) {
|
|
2196
|
+
throw new Error("No delegations found");
|
|
2197
|
+
}
|
|
2198
|
+
const allResults = await Promise.all(
|
|
2199
|
+
delegations.map(
|
|
2200
|
+
(delegation) => this.executeSingleDelegation(
|
|
2201
|
+
delegation,
|
|
2202
|
+
setting,
|
|
2203
|
+
context,
|
|
2204
|
+
parentExpert,
|
|
2205
|
+
runFn,
|
|
2206
|
+
parentOptions
|
|
2207
|
+
)
|
|
2208
|
+
)
|
|
2209
|
+
);
|
|
2210
|
+
const [firstResult, ...restResults] = allResults;
|
|
2211
|
+
if (!firstResult) {
|
|
2212
|
+
throw new Error("No delegation results");
|
|
2213
|
+
}
|
|
2214
|
+
const aggregatedUsage = allResults.reduce(
|
|
2215
|
+
(acc, result) => sumUsage(acc, result.deltaUsage),
|
|
2216
|
+
context.usage
|
|
2217
|
+
);
|
|
2218
|
+
const maxStepNumber = Math.max(...allResults.map((r) => r.stepNumber));
|
|
2219
|
+
const restToolResults = restResults.map((result) => ({
|
|
2220
|
+
id: result.toolCallId,
|
|
2221
|
+
skillName: `delegate/${result.expertKey}`,
|
|
2222
|
+
toolName: result.toolName,
|
|
2223
|
+
result: [{ type: "textPart", id: createId(), text: result.text }]
|
|
2224
|
+
}));
|
|
2225
|
+
const processedToolCallIds = new Set(remainingDelegations.map((d) => d.toolCallId));
|
|
2226
|
+
const remainingPendingToolCalls = context.pendingToolCalls?.filter(
|
|
2227
|
+
(tc) => !processedToolCallIds.has(tc.id) && tc.id !== firstDelegation.toolCallId
|
|
2228
|
+
);
|
|
2229
|
+
const nextSetting = {
|
|
2230
|
+
...setting,
|
|
2231
|
+
expertKey: parentExpert.key,
|
|
2232
|
+
input: {
|
|
2233
|
+
interactiveToolCallResult: {
|
|
2234
|
+
toolCallId: firstResult.toolCallId,
|
|
2235
|
+
toolName: firstResult.toolName,
|
|
2236
|
+
skillName: `delegate/${firstResult.expertKey}`,
|
|
2237
|
+
text: firstResult.text
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
};
|
|
2241
|
+
const nextCheckpoint = {
|
|
2242
|
+
id: context.id,
|
|
2243
|
+
jobId: setting.jobId,
|
|
2244
|
+
runId: setting.runId,
|
|
2245
|
+
status: "stoppedByDelegate",
|
|
2246
|
+
stepNumber: maxStepNumber,
|
|
2247
|
+
messages: context.messages,
|
|
2248
|
+
// Restore parent's conversation history
|
|
2249
|
+
expert: {
|
|
2250
|
+
key: parentExpert.key,
|
|
2251
|
+
name: parentExpert.name,
|
|
2252
|
+
version: parentExpert.version
|
|
2253
|
+
},
|
|
2254
|
+
usage: aggregatedUsage,
|
|
2255
|
+
contextWindow: context.contextWindow,
|
|
2256
|
+
delegatedBy: context.delegatedBy,
|
|
2257
|
+
// Preserve parent reference for nested delegations
|
|
2258
|
+
delegateTo: void 0,
|
|
2259
|
+
pendingToolCalls: remainingPendingToolCalls?.length ? remainingPendingToolCalls : void 0,
|
|
2260
|
+
partialToolResults: [...context.partialToolResults ?? [], ...restToolResults]
|
|
2261
|
+
};
|
|
2262
|
+
return { nextSetting, nextCheckpoint };
|
|
2263
|
+
}
|
|
2264
|
+
async executeSingleDelegation(delegation, parentSetting, parentContext, parentExpert, runFn, parentOptions) {
|
|
2265
|
+
const { expert, toolCallId, toolName, query } = delegation;
|
|
2266
|
+
const delegateRunId = createId();
|
|
2267
|
+
const delegateSetting = {
|
|
2268
|
+
...parentSetting,
|
|
2269
|
+
runId: delegateRunId,
|
|
2270
|
+
expertKey: expert.key,
|
|
2271
|
+
input: { text: query }
|
|
2272
|
+
};
|
|
2273
|
+
const delegateCheckpoint = {
|
|
2274
|
+
id: createId(),
|
|
2275
|
+
jobId: parentSetting.jobId,
|
|
2276
|
+
runId: delegateRunId,
|
|
2277
|
+
status: "init",
|
|
2278
|
+
stepNumber: parentContext.stepNumber,
|
|
2279
|
+
messages: [],
|
|
2280
|
+
// Child starts fresh - no parent context inheritance
|
|
2281
|
+
expert: {
|
|
2282
|
+
key: expert.key,
|
|
2283
|
+
name: expert.name,
|
|
2284
|
+
version: expert.version
|
|
2285
|
+
},
|
|
2286
|
+
delegatedBy: {
|
|
2287
|
+
expert: {
|
|
2288
|
+
key: parentExpert.key,
|
|
2289
|
+
name: parentExpert.name,
|
|
2290
|
+
version: parentExpert.version
|
|
2291
|
+
},
|
|
2292
|
+
toolCallId,
|
|
2293
|
+
toolName,
|
|
2294
|
+
checkpointId: parentContext.id
|
|
2295
|
+
},
|
|
2296
|
+
usage: createEmptyUsage(),
|
|
2297
|
+
contextWindow: parentContext.contextWindow
|
|
2298
|
+
};
|
|
2299
|
+
const resultCheckpoint = await runFn(
|
|
2300
|
+
{ setting: delegateSetting, checkpoint: delegateCheckpoint },
|
|
2301
|
+
{ ...parentOptions, returnOnDelegationComplete: true }
|
|
2302
|
+
);
|
|
2303
|
+
return this.extractDelegationResult(resultCheckpoint, toolCallId, toolName, expert.key);
|
|
2304
|
+
}
|
|
2305
|
+
extractDelegationResult(checkpoint, toolCallId, toolName, expertKey) {
|
|
2306
|
+
const lastMessage = checkpoint.messages[checkpoint.messages.length - 1];
|
|
2307
|
+
if (!lastMessage || lastMessage.type !== "expertMessage") {
|
|
2308
|
+
throw new Error("Delegation error: delegation result message is incorrect");
|
|
2309
|
+
}
|
|
2310
|
+
const textPart = lastMessage.contents.find((c) => c.type === "textPart");
|
|
2311
|
+
if (!textPart || textPart.type !== "textPart") {
|
|
2312
|
+
throw new Error("Delegation error: delegation result message does not contain text");
|
|
2313
|
+
}
|
|
2314
|
+
return {
|
|
2315
|
+
toolCallId,
|
|
2316
|
+
toolName,
|
|
2317
|
+
expertKey,
|
|
2318
|
+
text: textPart.text,
|
|
2319
|
+
stepNumber: checkpoint.stepNumber,
|
|
2320
|
+
deltaUsage: checkpoint.usage
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2152
2323
|
};
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
status: "running",
|
|
2157
|
-
totalSteps: 0,
|
|
2158
|
-
startedAt: Date.now(),
|
|
2159
|
-
maxSteps,
|
|
2160
|
-
usage: createEmptyUsage()
|
|
2161
|
-
});
|
|
2162
|
-
async function run(runInput, options) {
|
|
2163
|
-
const runParams = runParamsSchema.parse(runInput);
|
|
2164
|
-
const storeCheckpoint = options?.storeCheckpoint ?? noopStoreCheckpoint;
|
|
2165
|
-
const storeEvent = options?.storeEvent ?? noopStoreEvent;
|
|
2166
|
-
const storeJob = options?.storeJob ?? noopStoreJob;
|
|
2167
|
-
const retrieveJob = options?.retrieveJob ?? noopRetrieveJob;
|
|
2168
|
-
const retrieveCheckpoint = options?.retrieveCheckpoint ?? noopRetrieveCheckpoint;
|
|
2169
|
-
const createJob = options?.createJob ?? defaultCreateJob;
|
|
2170
|
-
const eventListener = createEventListener(options?.eventListener, storeEvent);
|
|
2171
|
-
const eventEmitter = new RunEventEmitter();
|
|
2172
|
-
eventEmitter.subscribe(eventListener);
|
|
2173
|
-
let { setting, checkpoint } = runParams;
|
|
2174
|
-
const contextWindow = getContextWindow(setting.providerConfig.providerName, setting.model);
|
|
2175
|
-
let job = retrieveJob(setting.jobId) ?? createJob(setting.jobId, setting.expertKey, setting.maxSteps);
|
|
2176
|
-
if (job.status !== "running") {
|
|
2177
|
-
job = { ...job, status: "running", finishedAt: void 0 };
|
|
2324
|
+
function selectDelegationStrategy(delegationCount) {
|
|
2325
|
+
if (delegationCount === 1) {
|
|
2326
|
+
return new SingleDelegationStrategy();
|
|
2178
2327
|
}
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2328
|
+
return new ParallelDelegationStrategy();
|
|
2329
|
+
}
|
|
2330
|
+
function buildReturnFromDelegation(currentSetting, resultCheckpoint, parentCheckpoint) {
|
|
2331
|
+
return buildDelegationReturnState(currentSetting, resultCheckpoint, parentCheckpoint);
|
|
2332
|
+
}
|
|
2333
|
+
function extractDelegationContext(checkpoint) {
|
|
2334
|
+
return {
|
|
2335
|
+
id: checkpoint.id,
|
|
2336
|
+
stepNumber: checkpoint.stepNumber,
|
|
2337
|
+
contextWindow: checkpoint.contextWindow,
|
|
2338
|
+
usage: checkpoint.usage,
|
|
2339
|
+
pendingToolCalls: checkpoint.pendingToolCalls,
|
|
2340
|
+
partialToolResults: checkpoint.partialToolResults,
|
|
2341
|
+
delegatedBy: checkpoint.delegatedBy,
|
|
2342
|
+
// Preserve for nested delegations
|
|
2343
|
+
messages: checkpoint.messages
|
|
2344
|
+
// Preserve for parent continuation after delegation
|
|
2345
|
+
};
|
|
2346
|
+
}
|
|
2347
|
+
var RunEventEmitter = class {
|
|
2348
|
+
listeners = [];
|
|
2349
|
+
subscribe(listener) {
|
|
2350
|
+
this.listeners.push(listener);
|
|
2351
|
+
}
|
|
2352
|
+
async emit(event) {
|
|
2353
|
+
const errors = [];
|
|
2354
|
+
for (const listener of this.listeners) {
|
|
2355
|
+
try {
|
|
2356
|
+
await listener({
|
|
2357
|
+
...event,
|
|
2358
|
+
id: createId(),
|
|
2359
|
+
timestamp: Date.now()
|
|
2360
|
+
});
|
|
2361
|
+
} catch (error) {
|
|
2362
|
+
errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
if (errors.length > 0) {
|
|
2366
|
+
throw new AggregateError(errors, "One or more event listeners failed");
|
|
2197
2367
|
}
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
|
|
2371
|
+
// src/orchestration/single-run-executor.ts
|
|
2372
|
+
var SingleRunExecutor = class {
|
|
2373
|
+
constructor(options = {}) {
|
|
2374
|
+
this.options = options;
|
|
2375
|
+
}
|
|
2376
|
+
async execute(setting, checkpoint) {
|
|
2377
|
+
const contextWindow = getContextWindow(setting.providerConfig.providerName, setting.model);
|
|
2378
|
+
const { expertToRun, experts } = await setupExperts(setting, this.options.resolveExpertToRun);
|
|
2379
|
+
this.emitInitEvent(setting, expertToRun, experts);
|
|
2198
2380
|
const skillManagers = await getSkillManagers(
|
|
2199
2381
|
expertToRun,
|
|
2200
2382
|
experts,
|
|
2201
2383
|
setting,
|
|
2202
|
-
options
|
|
2384
|
+
this.options.eventListener,
|
|
2203
2385
|
{ isDelegatedRun: !!checkpoint?.delegatedBy }
|
|
2204
2386
|
);
|
|
2205
2387
|
const initialCheckpoint = checkpoint ? createNextStepCheckpoint(createId(), checkpoint) : createInitialCheckpoint(createId(), {
|
|
@@ -2209,183 +2391,148 @@ async function run(runInput, options) {
|
|
|
2209
2391
|
expert: expertToRun,
|
|
2210
2392
|
contextWindow
|
|
2211
2393
|
});
|
|
2212
|
-
const
|
|
2394
|
+
const eventEmitter = new RunEventEmitter();
|
|
2395
|
+
const eventListener = this.createEventListener();
|
|
2396
|
+
eventEmitter.subscribe(eventListener);
|
|
2397
|
+
const resultCheckpoint = await executeStateMachine({
|
|
2213
2398
|
setting: { ...setting, experts },
|
|
2214
2399
|
initialCheckpoint,
|
|
2215
2400
|
eventListener,
|
|
2216
2401
|
skillManagers,
|
|
2217
2402
|
eventEmitter,
|
|
2218
|
-
storeCheckpoint
|
|
2219
|
-
|
|
2403
|
+
storeCheckpoint: this.options.storeCheckpoint ?? (async () => {
|
|
2404
|
+
}),
|
|
2405
|
+
shouldContinueRun: this.options.shouldContinueRun
|
|
2406
|
+
});
|
|
2407
|
+
return { checkpoint: resultCheckpoint, expertToRun, experts };
|
|
2408
|
+
}
|
|
2409
|
+
createEventListener() {
|
|
2410
|
+
const userListener = this.options.eventListener;
|
|
2411
|
+
const storeEvent = this.options.storeEvent;
|
|
2412
|
+
return async (event) => {
|
|
2413
|
+
if ("stepNumber" in event && storeEvent) {
|
|
2414
|
+
await storeEvent(event);
|
|
2415
|
+
}
|
|
2416
|
+
userListener?.(event);
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2419
|
+
emitInitEvent(setting, expertToRun, experts) {
|
|
2420
|
+
if (!this.options.eventListener) return;
|
|
2421
|
+
const initEvent = createRuntimeEvent("initializeRuntime", setting.jobId, setting.runId, {
|
|
2422
|
+
runtimeVersion: package_default.version,
|
|
2423
|
+
runtime: "local",
|
|
2424
|
+
expertName: expertToRun.name,
|
|
2425
|
+
experts: Object.keys(experts),
|
|
2426
|
+
model: setting.model,
|
|
2427
|
+
temperature: setting.temperature,
|
|
2428
|
+
maxSteps: setting.maxSteps,
|
|
2429
|
+
maxRetries: setting.maxRetries,
|
|
2430
|
+
timeout: setting.timeout,
|
|
2431
|
+
query: setting.input.text,
|
|
2432
|
+
interactiveToolCall: setting.input.interactiveToolCallResult
|
|
2220
2433
|
});
|
|
2434
|
+
this.options.eventListener(initEvent);
|
|
2435
|
+
}
|
|
2436
|
+
};
|
|
2437
|
+
|
|
2438
|
+
// src/run.ts
|
|
2439
|
+
var defaultCreateJob = (jobId, expertKey, maxSteps) => ({
|
|
2440
|
+
id: jobId,
|
|
2441
|
+
coordinatorExpertKey: expertKey,
|
|
2442
|
+
status: "running",
|
|
2443
|
+
totalSteps: 0,
|
|
2444
|
+
startedAt: Date.now(),
|
|
2445
|
+
maxSteps,
|
|
2446
|
+
usage: createEmptyUsage()
|
|
2447
|
+
});
|
|
2448
|
+
async function run(runInput, options) {
|
|
2449
|
+
const runParams = runParamsSchema.parse(runInput);
|
|
2450
|
+
let { setting, checkpoint } = runParams;
|
|
2451
|
+
const storeJob = options?.storeJob ?? (() => {
|
|
2452
|
+
});
|
|
2453
|
+
const retrieveJob = options?.retrieveJob ?? (() => void 0);
|
|
2454
|
+
const retrieveCheckpoint = options?.retrieveCheckpoint ?? (async () => {
|
|
2455
|
+
throw new Error("retrieveCheckpoint not provided");
|
|
2456
|
+
});
|
|
2457
|
+
const createJob = options?.createJob ?? defaultCreateJob;
|
|
2458
|
+
let job = retrieveJob(setting.jobId) ?? createJob(setting.jobId, setting.expertKey, setting.maxSteps);
|
|
2459
|
+
if (job.status !== "running") {
|
|
2460
|
+
job = { ...job, status: "running", finishedAt: void 0 };
|
|
2461
|
+
}
|
|
2462
|
+
storeJob(job);
|
|
2463
|
+
const runExecutor = new SingleRunExecutor({
|
|
2464
|
+
shouldContinueRun: options?.shouldContinueRun,
|
|
2465
|
+
storeCheckpoint: options?.storeCheckpoint,
|
|
2466
|
+
storeEvent: options?.storeEvent,
|
|
2467
|
+
eventListener: options?.eventListener,
|
|
2468
|
+
resolveExpertToRun: options?.resolveExpertToRun
|
|
2469
|
+
});
|
|
2470
|
+
while (true) {
|
|
2471
|
+
const runResult = await runExecutor.execute(setting, checkpoint);
|
|
2472
|
+
const resultCheckpoint = runResult.checkpoint;
|
|
2221
2473
|
job = {
|
|
2222
2474
|
...job,
|
|
2223
|
-
totalSteps:
|
|
2224
|
-
usage:
|
|
2475
|
+
totalSteps: resultCheckpoint.stepNumber,
|
|
2476
|
+
usage: resultCheckpoint.usage
|
|
2225
2477
|
};
|
|
2226
|
-
switch (
|
|
2478
|
+
switch (resultCheckpoint.status) {
|
|
2227
2479
|
case "completed": {
|
|
2228
2480
|
if (options?.returnOnDelegationComplete) {
|
|
2229
2481
|
storeJob(job);
|
|
2230
|
-
return
|
|
2482
|
+
return resultCheckpoint;
|
|
2231
2483
|
}
|
|
2232
|
-
if (
|
|
2484
|
+
if (resultCheckpoint.delegatedBy) {
|
|
2233
2485
|
storeJob(job);
|
|
2234
2486
|
const parentCheckpoint = await retrieveCheckpoint(
|
|
2235
2487
|
setting.jobId,
|
|
2236
|
-
|
|
2488
|
+
resultCheckpoint.delegatedBy.checkpointId
|
|
2237
2489
|
);
|
|
2238
|
-
const result =
|
|
2490
|
+
const result = buildReturnFromDelegation(setting, resultCheckpoint, parentCheckpoint);
|
|
2239
2491
|
setting = result.setting;
|
|
2240
2492
|
checkpoint = result.checkpoint;
|
|
2241
2493
|
break;
|
|
2242
2494
|
}
|
|
2243
2495
|
storeJob({ ...job, status: "completed", finishedAt: Date.now() });
|
|
2244
|
-
return
|
|
2496
|
+
return resultCheckpoint;
|
|
2245
2497
|
}
|
|
2246
2498
|
case "stoppedByInteractiveTool": {
|
|
2247
2499
|
storeJob({ ...job, status: "stoppedByInteractiveTool" });
|
|
2248
|
-
return
|
|
2500
|
+
return resultCheckpoint;
|
|
2249
2501
|
}
|
|
2250
2502
|
case "stoppedByDelegate": {
|
|
2251
2503
|
storeJob(job);
|
|
2252
|
-
const { delegateTo } =
|
|
2504
|
+
const { delegateTo } = resultCheckpoint;
|
|
2253
2505
|
if (!delegateTo || delegateTo.length === 0) {
|
|
2254
2506
|
throw new Error("No delegations found in checkpoint");
|
|
2255
2507
|
}
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
delegateTo.map(
|
|
2266
|
-
(delegation) => runDelegate(delegation, setting, runResultCheckpoint, expertToRun, options)
|
|
2267
|
-
)
|
|
2268
|
-
);
|
|
2269
|
-
const allResults = [firstResult, ...restResults];
|
|
2270
|
-
const aggregatedUsage = allResults.reduce(
|
|
2271
|
-
(acc, result) => sumUsage(acc, result.deltaUsage),
|
|
2272
|
-
runResultCheckpoint.usage
|
|
2273
|
-
);
|
|
2274
|
-
const maxStepNumber = Math.max(...allResults.map((r) => r.stepNumber));
|
|
2275
|
-
const restToolResults = restResults.map((result) => ({
|
|
2276
|
-
id: result.toolCallId,
|
|
2277
|
-
skillName: `delegate/${result.expertKey}`,
|
|
2278
|
-
toolName: result.toolName,
|
|
2279
|
-
result: [{ type: "textPart", id: createId(), text: result.text }]
|
|
2280
|
-
}));
|
|
2281
|
-
const processedToolCallIds = new Set(remainingDelegations.map((d) => d.toolCallId));
|
|
2282
|
-
const remainingToolCalls = runResultCheckpoint.pendingToolCalls?.filter(
|
|
2283
|
-
(tc) => !processedToolCallIds.has(tc.id) && tc.id !== firstDelegation.toolCallId
|
|
2508
|
+
const strategy = selectDelegationStrategy(delegateTo.length);
|
|
2509
|
+
const context = extractDelegationContext(resultCheckpoint);
|
|
2510
|
+
const delegationResult = await strategy.execute(
|
|
2511
|
+
delegateTo,
|
|
2512
|
+
setting,
|
|
2513
|
+
context,
|
|
2514
|
+
runResult.expertToRun,
|
|
2515
|
+
run,
|
|
2516
|
+
options
|
|
2284
2517
|
);
|
|
2285
|
-
setting =
|
|
2286
|
-
|
|
2287
|
-
expertKey: expertToRun.key,
|
|
2288
|
-
input: {
|
|
2289
|
-
interactiveToolCallResult: {
|
|
2290
|
-
toolCallId: firstResult.toolCallId,
|
|
2291
|
-
toolName: firstResult.toolName,
|
|
2292
|
-
skillName: `delegate/${firstResult.expertKey}`,
|
|
2293
|
-
text: firstResult.text
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
};
|
|
2297
|
-
checkpoint = {
|
|
2298
|
-
...runResultCheckpoint,
|
|
2299
|
-
status: "stoppedByDelegate",
|
|
2300
|
-
delegateTo: void 0,
|
|
2301
|
-
stepNumber: maxStepNumber,
|
|
2302
|
-
usage: aggregatedUsage,
|
|
2303
|
-
pendingToolCalls: remainingToolCalls?.length ? remainingToolCalls : void 0,
|
|
2304
|
-
partialToolResults: [
|
|
2305
|
-
...runResultCheckpoint.partialToolResults ?? [],
|
|
2306
|
-
...restToolResults
|
|
2307
|
-
]
|
|
2308
|
-
};
|
|
2518
|
+
setting = delegationResult.nextSetting;
|
|
2519
|
+
checkpoint = delegationResult.nextCheckpoint;
|
|
2309
2520
|
break;
|
|
2310
2521
|
}
|
|
2311
2522
|
case "stoppedByExceededMaxSteps": {
|
|
2312
2523
|
storeJob({ ...job, status: "stoppedByMaxSteps", finishedAt: Date.now() });
|
|
2313
|
-
return
|
|
2524
|
+
return resultCheckpoint;
|
|
2314
2525
|
}
|
|
2315
2526
|
case "stoppedByError": {
|
|
2316
2527
|
storeJob({ ...job, status: "stoppedByError", finishedAt: Date.now() });
|
|
2317
|
-
return
|
|
2528
|
+
return resultCheckpoint;
|
|
2318
2529
|
}
|
|
2319
2530
|
default:
|
|
2320
2531
|
throw new Error("Run stopped by unknown reason");
|
|
2321
2532
|
}
|
|
2322
2533
|
}
|
|
2323
2534
|
}
|
|
2324
|
-
function createEventListener(userListener, storeEvent) {
|
|
2325
|
-
const listener = userListener ?? ((e) => console.log(JSON.stringify(e)));
|
|
2326
|
-
return async (event) => {
|
|
2327
|
-
if ("stepNumber" in event && storeEvent) {
|
|
2328
|
-
await storeEvent(event);
|
|
2329
|
-
}
|
|
2330
|
-
listener(event);
|
|
2331
|
-
};
|
|
2332
|
-
}
|
|
2333
|
-
async function runDelegate(delegation, parentSetting, parentCheckpoint, parentExpert, options) {
|
|
2334
|
-
const { expert, toolCallId, toolName, query } = delegation;
|
|
2335
|
-
const delegateRunId = createId();
|
|
2336
|
-
const delegateSetting = {
|
|
2337
|
-
...parentSetting,
|
|
2338
|
-
runId: delegateRunId,
|
|
2339
|
-
expertKey: expert.key,
|
|
2340
|
-
input: { text: query }
|
|
2341
|
-
};
|
|
2342
|
-
const delegateCheckpoint = {
|
|
2343
|
-
id: createId(),
|
|
2344
|
-
jobId: parentSetting.jobId,
|
|
2345
|
-
runId: delegateRunId,
|
|
2346
|
-
status: "init",
|
|
2347
|
-
stepNumber: parentCheckpoint.stepNumber,
|
|
2348
|
-
messages: [],
|
|
2349
|
-
expert: {
|
|
2350
|
-
key: expert.key,
|
|
2351
|
-
name: expert.name,
|
|
2352
|
-
version: expert.version
|
|
2353
|
-
},
|
|
2354
|
-
delegatedBy: {
|
|
2355
|
-
expert: {
|
|
2356
|
-
key: parentExpert.key,
|
|
2357
|
-
name: parentExpert.name,
|
|
2358
|
-
version: parentExpert.version
|
|
2359
|
-
},
|
|
2360
|
-
toolCallId,
|
|
2361
|
-
toolName,
|
|
2362
|
-
checkpointId: parentCheckpoint.id
|
|
2363
|
-
},
|
|
2364
|
-
usage: createEmptyUsage(),
|
|
2365
|
-
contextWindow: parentCheckpoint.contextWindow
|
|
2366
|
-
};
|
|
2367
|
-
const resultCheckpoint = await run(
|
|
2368
|
-
{ setting: delegateSetting, checkpoint: delegateCheckpoint },
|
|
2369
|
-
{ ...options, returnOnDelegationComplete: true }
|
|
2370
|
-
);
|
|
2371
|
-
const lastMessage = resultCheckpoint.messages[resultCheckpoint.messages.length - 1];
|
|
2372
|
-
if (!lastMessage || lastMessage.type !== "expertMessage") {
|
|
2373
|
-
throw new Error("Delegation error: delegation result message is incorrect");
|
|
2374
|
-
}
|
|
2375
|
-
const textPart = lastMessage.contents.find((c) => c.type === "textPart");
|
|
2376
|
-
if (!textPart || textPart.type !== "textPart") {
|
|
2377
|
-
throw new Error("Delegation error: delegation result message does not contain text");
|
|
2378
|
-
}
|
|
2379
|
-
return {
|
|
2380
|
-
toolCallId,
|
|
2381
|
-
toolName,
|
|
2382
|
-
expertKey: expert.key,
|
|
2383
|
-
text: textPart.text,
|
|
2384
|
-
stepNumber: resultCheckpoint.stepNumber,
|
|
2385
|
-
deltaUsage: resultCheckpoint.usage
|
|
2386
|
-
};
|
|
2387
|
-
}
|
|
2388
2535
|
|
|
2389
2536
|
export { getModel, package_default, run, runtimeStateMachine };
|
|
2390
|
-
//# sourceMappingURL=chunk-
|
|
2391
|
-
//# sourceMappingURL=chunk-
|
|
2537
|
+
//# sourceMappingURL=chunk-7QLRRSNX.js.map
|
|
2538
|
+
//# sourceMappingURL=chunk-7QLRRSNX.js.map
|