@botbotgo/agent-harness 0.0.92 → 0.0.93
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/README.md +123 -31
- package/README.zh.md +78 -28
- package/dist/benchmark/upstream-runtime-ab-benchmark.d.ts +1 -1
- package/dist/benchmark/upstream-runtime-ab-benchmark.js +2 -1
- package/dist/config/workflows/langgraph-workflows.yaml +292 -0
- package/dist/contracts/types.d.ts +8 -3
- package/dist/init-project.js +7 -7
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/agent-runtime-adapter.d.ts +48 -1
- package/dist/runtime/agent-runtime-adapter.js +1001 -50
- package/dist/runtime/harness.d.ts +2 -0
- package/dist/runtime/harness.js +55 -11
- package/dist/runtime/inventory.d.ts +1 -1
- package/dist/runtime/inventory.js +1 -1
- package/dist/runtime/langgraph-presets.d.ts +23 -0
- package/dist/runtime/langgraph-presets.js +165 -0
- package/dist/runtime/policy-engine.js +0 -5
- package/dist/runtime/support/compiled-binding.d.ts +4 -1
- package/dist/runtime/support/compiled-binding.js +24 -2
- package/dist/runtime/support/harness-support.js +3 -3
- package/dist/runtime/support/runtime-entry.js +1 -1
- package/dist/workspace/agent-binding-compiler.js +82 -8
- package/dist/workspace/compile.js +1 -3
- package/dist/workspace/object-loader.js +46 -5
- package/dist/workspace/support/agent-capabilities.js +2 -2
- package/dist/workspace/support/workspace-ref-utils.d.ts +2 -1
- package/dist/workspace/support/workspace-ref-utils.js +21 -0
- package/dist/workspace/validate.js +1 -1
- package/package.json +2 -2
- /package/dist/config/{backends.yaml → catalogs/backends.yaml} +0 -0
- /package/dist/config/{embedding-models.yaml → catalogs/embedding-models.yaml} +0 -0
- /package/dist/config/{mcp.yaml → catalogs/mcp.yaml} +0 -0
- /package/dist/config/{models.yaml → catalogs/models.yaml} +0 -0
- /package/dist/config/{stores.yaml → catalogs/stores.yaml} +0 -0
- /package/dist/config/{tools.yaml → catalogs/tools.yaml} +0 -0
- /package/dist/config/{vector-stores.yaml → catalogs/vector-stores.yaml} +0 -0
- /package/dist/config/{runtime-memory.yaml → runtime/runtime-memory.yaml} +0 -0
- /package/dist/config/{workspace.yaml → runtime/workspace.yaml} +0 -0
|
@@ -102,6 +102,8 @@ export declare class AgentHarnessRuntime {
|
|
|
102
102
|
private executeQueuedRun;
|
|
103
103
|
private checkpointRefForState;
|
|
104
104
|
private finalizeContinuedRun;
|
|
105
|
+
private synthesizeCompletedRun;
|
|
106
|
+
private reviewCompletedRun;
|
|
105
107
|
private emitOutputDeltaAndCreateItem;
|
|
106
108
|
private createContentBlocksItem;
|
|
107
109
|
private createToolResultKey;
|
package/dist/runtime/harness.js
CHANGED
|
@@ -660,7 +660,7 @@ export class AgentHarnessRuntime {
|
|
|
660
660
|
if (cancelledAfterInvoke.requested) {
|
|
661
661
|
return this.finalizeCancelledRun(threadId, runId, previousState === "queued" ? "running" : previousState, cancelledAfterInvoke.reason);
|
|
662
662
|
}
|
|
663
|
-
const finalized = await this.finalizeContinuedRun(threadId, runId, input, actual, {
|
|
663
|
+
const finalized = await this.finalizeContinuedRun(binding, threadId, runId, input, actual, {
|
|
664
664
|
previousState: previousState === "queued" ? "running" : previousState,
|
|
665
665
|
stateSequence: options.stateSequence ?? 103,
|
|
666
666
|
approvalSequence: options.approvalSequence ?? 104,
|
|
@@ -691,25 +691,68 @@ export class AgentHarnessRuntime {
|
|
|
691
691
|
checkpointRefForState(threadId, runId, state) {
|
|
692
692
|
return state === "waiting_for_approval" ? `checkpoints/${threadId}/${runId}/cp-1` : null;
|
|
693
693
|
}
|
|
694
|
-
async finalizeContinuedRun(threadId, runId, input, actual, options) {
|
|
694
|
+
async finalizeContinuedRun(binding, threadId, runId, input, actual, options) {
|
|
695
695
|
let approval;
|
|
696
|
-
|
|
696
|
+
const finalizedActual = actual.state === "completed"
|
|
697
|
+
? await this.synthesizeCompletedRun(binding, input, actual)
|
|
698
|
+
: actual;
|
|
699
|
+
await this.appendAssistantMessage(threadId, runId, finalizedActual.output);
|
|
697
700
|
const checkpointRef = this.checkpointRefForState(threadId, runId, actual.state);
|
|
698
|
-
await this.setRunStateAndEmit(threadId, runId, options.stateSequence,
|
|
701
|
+
await this.setRunStateAndEmit(threadId, runId, options.stateSequence, finalizedActual.state, {
|
|
699
702
|
previousState: options.previousState,
|
|
700
703
|
checkpointRef,
|
|
701
704
|
});
|
|
702
|
-
if (
|
|
703
|
-
approval = (await this.requestApprovalAndEmit(threadId, runId, input,
|
|
705
|
+
if (finalizedActual.state === "waiting_for_approval" && options.approvalSequence) {
|
|
706
|
+
approval = (await this.requestApprovalAndEmit(threadId, runId, input, finalizedActual.interruptContent, checkpointRef, options.approvalSequence)).approval;
|
|
707
|
+
}
|
|
708
|
+
if (finalizedActual.state === "completed") {
|
|
709
|
+
await this.reviewCompletedRun(binding, threadId, runId, input, finalizedActual);
|
|
704
710
|
}
|
|
705
711
|
return {
|
|
706
|
-
...
|
|
712
|
+
...finalizedActual,
|
|
707
713
|
threadId,
|
|
708
714
|
runId,
|
|
709
|
-
approvalId: approval?.approvalId ??
|
|
710
|
-
pendingActionId: approval?.pendingActionId ??
|
|
715
|
+
approvalId: approval?.approvalId ?? finalizedActual.approvalId,
|
|
716
|
+
pendingActionId: approval?.pendingActionId ?? finalizedActual.pendingActionId,
|
|
711
717
|
};
|
|
712
718
|
}
|
|
719
|
+
async synthesizeCompletedRun(binding, input, actual) {
|
|
720
|
+
try {
|
|
721
|
+
const synthesized = await this.runtimeAdapter.synthesizeFinalResult(binding, input, actual);
|
|
722
|
+
if (!synthesized) {
|
|
723
|
+
return actual;
|
|
724
|
+
}
|
|
725
|
+
return {
|
|
726
|
+
...actual,
|
|
727
|
+
output: synthesized.output,
|
|
728
|
+
finalMessageText: synthesized.finalMessageText,
|
|
729
|
+
metadata: {
|
|
730
|
+
...(typeof actual.metadata === "object" && actual.metadata ? actual.metadata : {}),
|
|
731
|
+
finalSynthesis: {
|
|
732
|
+
modelId: synthesized.modelId,
|
|
733
|
+
},
|
|
734
|
+
},
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
catch {
|
|
738
|
+
return actual;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
async reviewCompletedRun(binding, threadId, runId, input, actual) {
|
|
742
|
+
try {
|
|
743
|
+
const review = await this.runtimeAdapter.reviewRunResult(binding, input, actual);
|
|
744
|
+
if (!review) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
await this.emit(threadId, runId, 7, "run.reviewed", {
|
|
748
|
+
modelId: review.modelId,
|
|
749
|
+
assessment: review.assessment,
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
catch {
|
|
753
|
+
// Review is advisory; do not fail the completed run if the review pass fails.
|
|
754
|
+
}
|
|
755
|
+
}
|
|
713
756
|
async emitOutputDeltaAndCreateItem(threadId, runId, agentId, content) {
|
|
714
757
|
await this.emit(threadId, runId, 3, "output.delta", {
|
|
715
758
|
content,
|
|
@@ -1139,6 +1182,7 @@ export class AgentHarnessRuntime {
|
|
|
1139
1182
|
context: invocation.context,
|
|
1140
1183
|
state: invocation.state,
|
|
1141
1184
|
files: invocation.files,
|
|
1185
|
+
runId,
|
|
1142
1186
|
})) {
|
|
1143
1187
|
if (chunk) {
|
|
1144
1188
|
streamActivityObserved = true;
|
|
@@ -1425,7 +1469,7 @@ export class AgentHarnessRuntime {
|
|
|
1425
1469
|
return this.finalizeCancelledRun(threadId, runId, "resuming", cancelledAfterInvoke.reason);
|
|
1426
1470
|
}
|
|
1427
1471
|
await this.persistence.clearRecoveryIntent(threadId, runId);
|
|
1428
|
-
const finalized = await this.finalizeContinuedRun(threadId, runId, runInput, actual, {
|
|
1472
|
+
const finalized = await this.finalizeContinuedRun(binding, threadId, runId, runInput, actual, {
|
|
1429
1473
|
previousState: "resuming",
|
|
1430
1474
|
stateSequence: 7,
|
|
1431
1475
|
approvalSequence: 8,
|
|
@@ -1668,7 +1712,7 @@ export class AgentHarnessRuntime {
|
|
|
1668
1712
|
const actual = await this.runtimeAdapter.invoke(binding, "", thread.threadId, thread.latestRunId, recoveryIntent.resumePayload, priorHistory);
|
|
1669
1713
|
this.healthMonitor.recordLlmSuccess(Date.now() - startedAt);
|
|
1670
1714
|
await this.persistence.clearRecoveryIntent(thread.threadId, thread.latestRunId);
|
|
1671
|
-
await this.finalizeContinuedRun(thread.threadId, thread.latestRunId, runInput, actual, {
|
|
1715
|
+
await this.finalizeContinuedRun(binding, thread.threadId, thread.latestRunId, runInput, actual, {
|
|
1672
1716
|
previousState: "resuming",
|
|
1673
1717
|
stateSequence: 101,
|
|
1674
1718
|
approvalSequence: 102,
|
|
@@ -20,7 +20,7 @@ export type InventorySkillRecord = {
|
|
|
20
20
|
export type InventoryAgentRecord = {
|
|
21
21
|
id: string;
|
|
22
22
|
description: string;
|
|
23
|
-
role: "
|
|
23
|
+
role: "agent" | "specialist";
|
|
24
24
|
tools: InventoryToolRecord[];
|
|
25
25
|
skills: InventorySkillRecord[];
|
|
26
26
|
};
|
|
@@ -96,7 +96,7 @@ export function listAvailableAgents(workspace, options = {}) {
|
|
|
96
96
|
const topLevel = listHostBindings(workspace).map((binding) => ({
|
|
97
97
|
id: binding.agent.id,
|
|
98
98
|
description: binding.agent.description,
|
|
99
|
-
role: "
|
|
99
|
+
role: "agent",
|
|
100
100
|
tools: listAgentTools(workspace, binding.agent.id),
|
|
101
101
|
skills: listAgentSkills(workspace, binding.agent.id, options),
|
|
102
102
|
}));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type LangGraphPresetNode = {
|
|
2
|
+
id: string;
|
|
3
|
+
kind: string;
|
|
4
|
+
prompt?: string;
|
|
5
|
+
specialist?: string;
|
|
6
|
+
};
|
|
7
|
+
type LangGraphPresetEdge = {
|
|
8
|
+
from: string;
|
|
9
|
+
to: string;
|
|
10
|
+
when?: string;
|
|
11
|
+
};
|
|
12
|
+
export type LangGraphPresetWorkflow = {
|
|
13
|
+
entryNode: string;
|
|
14
|
+
nodes: LangGraphPresetNode[];
|
|
15
|
+
edges: LangGraphPresetEdge[];
|
|
16
|
+
};
|
|
17
|
+
export type LangGraphPresetName = "react" | "prompt-chaining" | "routing" | "parallelization" | "plan-execute" | "review-loop" | "evaluator-optimizer" | "approval-gate" | "handoff" | "orchestrator-workers";
|
|
18
|
+
type LangGraphPresetOptions = {
|
|
19
|
+
specialist?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const SUPPORTED_LANGGRAPH_PRESETS: LangGraphPresetName[];
|
|
22
|
+
export declare function resolveLangGraphPresetWorkflow(presetName: string | undefined, options?: LangGraphPresetOptions): LangGraphPresetWorkflow | undefined;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
const DEFAULT_PLANNER_PROMPT = "You are the workflow planner. Produce a concise execution plan for the user request before execution starts.";
|
|
2
|
+
const DEFAULT_REVIEWER_PROMPT = "Review the current result, call out missing verification or obvious gaps, and state whether the work looks sufficient.";
|
|
3
|
+
const DEFAULT_REPLANNER_PROMPT = "Refine the plan based on the reviewer feedback and current result. Return only the updated plan.";
|
|
4
|
+
const DEFAULT_FINALIZER_PROMPT = "Rewrite the current result into a concise user-facing final answer. Preserve facts and caveats.";
|
|
5
|
+
export const SUPPORTED_LANGGRAPH_PRESETS = [
|
|
6
|
+
"react",
|
|
7
|
+
"prompt-chaining",
|
|
8
|
+
"routing",
|
|
9
|
+
"parallelization",
|
|
10
|
+
"plan-execute",
|
|
11
|
+
"review-loop",
|
|
12
|
+
"evaluator-optimizer",
|
|
13
|
+
"approval-gate",
|
|
14
|
+
"handoff",
|
|
15
|
+
"orchestrator-workers",
|
|
16
|
+
];
|
|
17
|
+
function requireSpecialist(preset, options) {
|
|
18
|
+
if (typeof options.specialist === "string" && options.specialist.trim()) {
|
|
19
|
+
return options.specialist.trim();
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`LangGraph preset ${preset} requires config.specialist`);
|
|
22
|
+
}
|
|
23
|
+
export function resolveLangGraphPresetWorkflow(presetName, options = {}) {
|
|
24
|
+
switch (presetName) {
|
|
25
|
+
case undefined:
|
|
26
|
+
case "":
|
|
27
|
+
return undefined;
|
|
28
|
+
case "react":
|
|
29
|
+
return {
|
|
30
|
+
entryNode: "executor",
|
|
31
|
+
nodes: [
|
|
32
|
+
{ id: "executor", kind: "executor" },
|
|
33
|
+
],
|
|
34
|
+
edges: [],
|
|
35
|
+
};
|
|
36
|
+
case "prompt-chaining":
|
|
37
|
+
case "plan-execute":
|
|
38
|
+
return {
|
|
39
|
+
entryNode: "planner",
|
|
40
|
+
nodes: [
|
|
41
|
+
{ id: "planner", kind: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
42
|
+
{ id: "executor", kind: "executor" },
|
|
43
|
+
{ id: "finalizer", kind: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
44
|
+
],
|
|
45
|
+
edges: [
|
|
46
|
+
{ from: "planner", to: "executor" },
|
|
47
|
+
{ from: "executor", to: "finalizer", when: "has_result" },
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
case "routing": {
|
|
51
|
+
const specialist = requireSpecialist("routing", options);
|
|
52
|
+
return {
|
|
53
|
+
entryNode: "planner",
|
|
54
|
+
nodes: [
|
|
55
|
+
{ id: "planner", kind: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
56
|
+
{ id: "specialist", kind: "specialist", specialist },
|
|
57
|
+
{ id: "finalizer", kind: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
58
|
+
],
|
|
59
|
+
edges: [
|
|
60
|
+
{ from: "planner", to: "specialist" },
|
|
61
|
+
{ from: "specialist", to: "finalizer", when: "has_result" },
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
case "parallelization": {
|
|
66
|
+
const specialist = requireSpecialist("parallelization", options);
|
|
67
|
+
return {
|
|
68
|
+
entryNode: "planner",
|
|
69
|
+
nodes: [
|
|
70
|
+
{ id: "planner", kind: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
71
|
+
{ id: "specialist", kind: "specialist", specialist },
|
|
72
|
+
{ id: "reviewer", kind: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
73
|
+
{ id: "finalizer", kind: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
74
|
+
],
|
|
75
|
+
edges: [
|
|
76
|
+
{ from: "planner", to: "specialist" },
|
|
77
|
+
{ from: "specialist", to: "reviewer", when: "has_result" },
|
|
78
|
+
{ from: "reviewer", to: "finalizer", when: "review_ok" },
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
case "review-loop":
|
|
83
|
+
return {
|
|
84
|
+
entryNode: "planner",
|
|
85
|
+
nodes: [
|
|
86
|
+
{ id: "planner", kind: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
87
|
+
{ id: "executor", kind: "executor" },
|
|
88
|
+
{ id: "reviewer", kind: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
89
|
+
{ id: "replanner", kind: "replanner", prompt: DEFAULT_REPLANNER_PROMPT },
|
|
90
|
+
{ id: "finalizer", kind: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
91
|
+
],
|
|
92
|
+
edges: [
|
|
93
|
+
{ from: "planner", to: "executor" },
|
|
94
|
+
{ from: "executor", to: "reviewer", when: "has_result" },
|
|
95
|
+
{ from: "reviewer", to: "finalizer", when: "review_ok" },
|
|
96
|
+
{ from: "reviewer", to: "replanner", when: "review_incomplete" },
|
|
97
|
+
{ from: "replanner", to: "executor", when: "has_plan" },
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
case "evaluator-optimizer":
|
|
101
|
+
return {
|
|
102
|
+
entryNode: "executor",
|
|
103
|
+
nodes: [
|
|
104
|
+
{ id: "executor", kind: "executor" },
|
|
105
|
+
{ id: "reviewer", kind: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
106
|
+
{ id: "replanner", kind: "replanner", prompt: DEFAULT_REPLANNER_PROMPT },
|
|
107
|
+
{ id: "finalizer", kind: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
108
|
+
],
|
|
109
|
+
edges: [
|
|
110
|
+
{ from: "executor", to: "reviewer", when: "has_result" },
|
|
111
|
+
{ from: "reviewer", to: "finalizer", when: "review_ok" },
|
|
112
|
+
{ from: "reviewer", to: "replanner", when: "review_incomplete" },
|
|
113
|
+
{ from: "replanner", to: "executor", when: "has_plan" },
|
|
114
|
+
],
|
|
115
|
+
};
|
|
116
|
+
case "approval-gate":
|
|
117
|
+
return {
|
|
118
|
+
entryNode: "planner",
|
|
119
|
+
nodes: [
|
|
120
|
+
{ id: "planner", kind: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
121
|
+
{ id: "approval", kind: "approval" },
|
|
122
|
+
{ id: "executor", kind: "executor" },
|
|
123
|
+
{ id: "finalizer", kind: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
124
|
+
],
|
|
125
|
+
edges: [
|
|
126
|
+
{ from: "planner", to: "approval" },
|
|
127
|
+
{ from: "approval", to: "executor", when: "approval_approved" },
|
|
128
|
+
{ from: "approval", to: "executor", when: "approval_edited" },
|
|
129
|
+
{ from: "executor", to: "finalizer", when: "has_result" },
|
|
130
|
+
],
|
|
131
|
+
};
|
|
132
|
+
case "handoff": {
|
|
133
|
+
const specialist = requireSpecialist("handoff", options);
|
|
134
|
+
return {
|
|
135
|
+
entryNode: "specialist",
|
|
136
|
+
nodes: [
|
|
137
|
+
{ id: "specialist", kind: "specialist", specialist },
|
|
138
|
+
{ id: "finalizer", kind: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
139
|
+
],
|
|
140
|
+
edges: [
|
|
141
|
+
{ from: "specialist", to: "finalizer", when: "has_result" },
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
case "orchestrator-workers": {
|
|
146
|
+
const specialist = requireSpecialist("orchestrator-workers", options);
|
|
147
|
+
return {
|
|
148
|
+
entryNode: "planner",
|
|
149
|
+
nodes: [
|
|
150
|
+
{ id: "planner", kind: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
151
|
+
{ id: "specialist", kind: "specialist", specialist },
|
|
152
|
+
{ id: "reviewer", kind: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
153
|
+
{ id: "finalizer", kind: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
154
|
+
],
|
|
155
|
+
edges: [
|
|
156
|
+
{ from: "planner", to: "specialist" },
|
|
157
|
+
{ from: "specialist", to: "reviewer", when: "has_result" },
|
|
158
|
+
{ from: "reviewer", to: "finalizer", when: "review_ok" },
|
|
159
|
+
],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
default:
|
|
163
|
+
throw new Error(`Unsupported LangGraph preset ${String(presetName)}. Supported presets: ${SUPPORTED_LANGGRAPH_PRESETS.join(", ")}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { getPolicyEvaluators } from "../extensions.js";
|
|
2
|
-
import { isRuntimeEntryBinding } from "./support/runtime-entry.js";
|
|
3
2
|
export class PolicyEngine {
|
|
4
3
|
evaluate(binding) {
|
|
5
4
|
const reasons = [];
|
|
6
5
|
let allowed = true;
|
|
7
|
-
if (!isRuntimeEntryBinding(binding)) {
|
|
8
|
-
allowed = false;
|
|
9
|
-
reasons.push("internal subagents cannot be used as runtime entry agents");
|
|
10
|
-
}
|
|
11
6
|
for (const evaluator of getPolicyEvaluators()) {
|
|
12
7
|
const decision = evaluator.evaluate(binding);
|
|
13
8
|
if (!decision) {
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import type { CompiledAgentBinding, CompiledModel, CompiledTool, DeepAgentParams, LangChainAgentParams } from "../../contracts/types.js";
|
|
1
|
+
import type { CompiledAgentBinding, CompiledModel, CompiledTool, DeepAgentParams, LangChainAgentParams, RuntimeModelSlot } from "../../contracts/types.js";
|
|
2
2
|
export declare function getBindingAdapterKind(binding: CompiledAgentBinding): string;
|
|
3
3
|
export declare function getBindingAdapterConfig(binding: CompiledAgentBinding): Record<string, unknown>;
|
|
4
|
+
export declare function getBindingLangGraphWorkflow(binding: CompiledAgentBinding): Record<string, unknown> | undefined;
|
|
5
|
+
export declare function getBindingLangGraphPreset(binding: CompiledAgentBinding): string | undefined;
|
|
4
6
|
export declare function getBindingLangChainParams(binding: CompiledAgentBinding): LangChainAgentParams | undefined;
|
|
5
7
|
export declare function getBindingDeepAgentParams(binding: CompiledAgentBinding): DeepAgentParams | undefined;
|
|
6
8
|
export declare function isLangChainBinding(binding: CompiledAgentBinding): boolean;
|
|
7
9
|
export declare function isDeepAgentBinding(binding: CompiledAgentBinding): boolean;
|
|
8
10
|
export declare function getBindingPrimaryTools(binding: CompiledAgentBinding): CompiledTool[];
|
|
9
11
|
export declare function getBindingPrimaryModel(binding: CompiledAgentBinding): CompiledModel | undefined;
|
|
12
|
+
export declare function getBindingRuntimeModel(binding: CompiledAgentBinding, slot: RuntimeModelSlot): CompiledModel | undefined;
|
|
10
13
|
export declare function getBindingSystemPrompt(binding: CompiledAgentBinding): string | undefined;
|
|
11
14
|
export declare function getBindingMiddlewareConfigs(binding: CompiledAgentBinding): Array<Record<string, unknown>> | undefined;
|
|
12
15
|
export declare function getBindingInterruptCompatibilityRules(binding: CompiledAgentBinding): Record<string, boolean | object> | undefined;
|
|
@@ -9,9 +9,26 @@ export function getBindingAdapterKind(binding) {
|
|
|
9
9
|
export function getBindingAdapterConfig(binding) {
|
|
10
10
|
return binding.adapter?.config ?? {};
|
|
11
11
|
}
|
|
12
|
+
export function getBindingLangGraphWorkflow(binding) {
|
|
13
|
+
const workflow = asRecord(getBindingAdapterConfig(binding).workflow);
|
|
14
|
+
if (workflow) {
|
|
15
|
+
return workflow;
|
|
16
|
+
}
|
|
17
|
+
return asRecord(asRecord(getBindingLangChainParams(binding)?.passthrough)?.workflow);
|
|
18
|
+
}
|
|
19
|
+
export function getBindingLangGraphPreset(binding) {
|
|
20
|
+
const adapterPreset = getBindingAdapterConfig(binding).preset;
|
|
21
|
+
if (typeof adapterPreset === "string" && adapterPreset.trim()) {
|
|
22
|
+
return adapterPreset.trim();
|
|
23
|
+
}
|
|
24
|
+
const passthroughPreset = asRecord(getBindingLangChainParams(binding)?.passthrough)?.preset;
|
|
25
|
+
return typeof passthroughPreset === "string" && passthroughPreset.trim()
|
|
26
|
+
? passthroughPreset.trim()
|
|
27
|
+
: undefined;
|
|
28
|
+
}
|
|
12
29
|
export function getBindingLangChainParams(binding) {
|
|
13
30
|
const adapterParams = asRecord(getBindingAdapterConfig(binding).params);
|
|
14
|
-
if (getBindingAdapterKind(binding) === "langchain-v1" && adapterParams) {
|
|
31
|
+
if ((getBindingAdapterKind(binding) === "langchain-v1" || getBindingAdapterKind(binding) === "langgraph") && adapterParams) {
|
|
15
32
|
return adapterParams;
|
|
16
33
|
}
|
|
17
34
|
return binding.langchainAgentParams;
|
|
@@ -24,7 +41,9 @@ export function getBindingDeepAgentParams(binding) {
|
|
|
24
41
|
return binding.deepAgentParams;
|
|
25
42
|
}
|
|
26
43
|
export function isLangChainBinding(binding) {
|
|
27
|
-
return getBindingAdapterKind(binding) === "langchain-v1" ||
|
|
44
|
+
return getBindingAdapterKind(binding) === "langchain-v1" ||
|
|
45
|
+
getBindingAdapterKind(binding) === "langgraph" ||
|
|
46
|
+
Boolean(binding.langchainAgentParams);
|
|
28
47
|
}
|
|
29
48
|
export function isDeepAgentBinding(binding) {
|
|
30
49
|
return getBindingAdapterKind(binding) === "deepagent" || Boolean(binding.deepAgentParams);
|
|
@@ -35,6 +54,9 @@ export function getBindingPrimaryTools(binding) {
|
|
|
35
54
|
export function getBindingPrimaryModel(binding) {
|
|
36
55
|
return binding.langchainAgentParams?.model ?? binding.deepAgentParams?.model;
|
|
37
56
|
}
|
|
57
|
+
export function getBindingRuntimeModel(binding, slot) {
|
|
58
|
+
return binding.harnessRuntime.models?.[slot];
|
|
59
|
+
}
|
|
38
60
|
export function getBindingSystemPrompt(binding) {
|
|
39
61
|
return binding.langchainAgentParams?.systemPrompt ?? binding.deepAgentParams?.systemPrompt;
|
|
40
62
|
}
|
|
@@ -131,8 +131,8 @@ export function createPendingApproval(threadId, runId, checkpointRef, input, int
|
|
|
131
131
|
}
|
|
132
132
|
export function inferRoutingBindings(workspace) {
|
|
133
133
|
const runtimeEntryBindings = Array.from(workspace.bindings.values()).filter((binding) => isRuntimeEntryBinding(binding));
|
|
134
|
-
const
|
|
135
|
-
const routingHosts =
|
|
134
|
+
const orchestrationHosts = runtimeEntryBindings.filter((binding) => binding.agent.executionMode === "deepagent" || binding.agent.executionMode === "langgraph" || Boolean(binding.deepAgentParams));
|
|
135
|
+
const routingHosts = orchestrationHosts.length > 0 ? orchestrationHosts : runtimeEntryBindings;
|
|
136
136
|
const researchBinding = routingHosts.find((binding) => binding.agent.id === "research-lite" || binding.agent.id === "research");
|
|
137
137
|
const directBinding = routingHosts.find((binding) => binding.agent.id === "direct");
|
|
138
138
|
const delegationHosts = routingHosts.filter((binding) => isDelegationCapableBinding(binding));
|
|
@@ -151,6 +151,6 @@ export function inferRoutingBindings(workspace) {
|
|
|
151
151
|
: delegationPreferredSecondary && delegationPreferredSecondary.agent.id !== primaryBinding?.agent.id
|
|
152
152
|
? delegationPreferredSecondary
|
|
153
153
|
: routingHosts.find((binding) => binding.agent.id !== primaryBinding?.agent.id) ??
|
|
154
|
-
(
|
|
154
|
+
(orchestrationHosts.length > 0 ? undefined : runtimeEntryBindings.find((binding) => binding.agent.id !== primaryBinding?.agent.id));
|
|
155
155
|
return { primaryBinding, secondaryBinding, researchBinding, hostBindings: runtimeEntryBindings };
|
|
156
156
|
}
|
|
@@ -3,7 +3,7 @@ import { getSkillInheritancePolicy, resolveToolTargets } from "../extensions.js"
|
|
|
3
3
|
import { compileModel, compileTool } from "./resource-compilers.js";
|
|
4
4
|
import { inferAgentCapabilities } from "./support/agent-capabilities.js";
|
|
5
5
|
import { discoverSkillPaths } from "./support/discovery.js";
|
|
6
|
-
import { compileAgentMemories, getResilienceConfig, getRuntimeDefaults, getRuntimeMemoryDefaults, getWorkspaceObject, resolvePromptValue, resolveRefId } from "./support/workspace-ref-utils.js";
|
|
6
|
+
import { compileAgentMemories, getResilienceConfig, getRuntimeDefaults, getRuntimeMemoryDefaults, getRuntimeModelDefaults, getWorkspaceObject, resolvePromptValue, resolveRefId } from "./support/workspace-ref-utils.js";
|
|
7
7
|
const WORKSPACE_BOUNDARY_GUIDANCE = "Keep repository and file exploration bounded to the current workspace root unless the user explicitly asks for broader host or filesystem access. " +
|
|
8
8
|
"Do not inspect absolute paths outside the workspace, system directories, or unrelated repos by default. " +
|
|
9
9
|
"Prefer workspace-local tools, relative paths, and the current repository checkout when analyzing code.";
|
|
@@ -150,6 +150,15 @@ function isRefConfig(value) {
|
|
|
150
150
|
}
|
|
151
151
|
return Object.keys(value).every((key) => key === "ref");
|
|
152
152
|
}
|
|
153
|
+
function mergeOpaqueConfig(base, extra) {
|
|
154
|
+
if (!base && !extra) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
...(base ?? {}),
|
|
159
|
+
...(extra ?? {}),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
153
162
|
function materializeWorkspaceObjectConfig(refs, ref, allowedKinds, ownerLabel) {
|
|
154
163
|
const object = getWorkspaceObject(refs, ref);
|
|
155
164
|
if (!object) {
|
|
@@ -232,6 +241,58 @@ function resolveRuntimeMemoryConfig(agent, refs) {
|
|
|
232
241
|
const runtimeMemoryDefaults = getRuntimeMemoryDefaults(refs);
|
|
233
242
|
return runtimeMemoryDefaults ? { config: runtimeMemoryDefaults } : undefined;
|
|
234
243
|
}
|
|
244
|
+
function resolveLangGraphWorkflowConfig(agent, refs) {
|
|
245
|
+
if (agent.executionMode !== "langgraph") {
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
const preset = typeof agent.langchainAgentConfig?.preset === "string" && agent.langchainAgentConfig.preset.trim()
|
|
249
|
+
? agent.langchainAgentConfig.preset.trim()
|
|
250
|
+
: typeof agent.langchainAgentConfig?.passthrough === "object" &&
|
|
251
|
+
agent.langchainAgentConfig.passthrough &&
|
|
252
|
+
typeof agent.langchainAgentConfig.passthrough.preset === "string" &&
|
|
253
|
+
agent.langchainAgentConfig.passthrough.preset.trim()
|
|
254
|
+
? agent.langchainAgentConfig.passthrough.preset.trim()
|
|
255
|
+
: undefined;
|
|
256
|
+
const workflowConfig = typeof agent.langchainAgentConfig?.workflow === "object" && agent.langchainAgentConfig.workflow
|
|
257
|
+
? agent.langchainAgentConfig.workflow
|
|
258
|
+
: typeof agent.langchainAgentConfig?.langgraph === "object" && agent.langchainAgentConfig.langgraph
|
|
259
|
+
? agent.langchainAgentConfig.langgraph
|
|
260
|
+
: typeof agent.langchainAgentConfig?.passthrough === "object" &&
|
|
261
|
+
agent.langchainAgentConfig.passthrough &&
|
|
262
|
+
typeof agent.langchainAgentConfig.passthrough.workflow === "object" &&
|
|
263
|
+
agent.langchainAgentConfig.passthrough.workflow
|
|
264
|
+
? agent.langchainAgentConfig.passthrough.workflow
|
|
265
|
+
: typeof agent.langchainAgentConfig?.passthrough === "object" &&
|
|
266
|
+
agent.langchainAgentConfig.passthrough &&
|
|
267
|
+
typeof agent.langchainAgentConfig.passthrough.langgraph === "object" &&
|
|
268
|
+
agent.langchainAgentConfig.passthrough.langgraph
|
|
269
|
+
? agent.langchainAgentConfig.passthrough.langgraph
|
|
270
|
+
: undefined;
|
|
271
|
+
if (!workflowConfig) {
|
|
272
|
+
return preset ? { preset } : undefined;
|
|
273
|
+
}
|
|
274
|
+
if (isRefConfig(workflowConfig)) {
|
|
275
|
+
return {
|
|
276
|
+
config: materializeWorkspaceObjectConfig(refs, workflowConfig.ref, ["langgraph-workflow"], `Agent ${agent.id} workflow`),
|
|
277
|
+
...(preset ? { preset } : {}),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return { config: workflowConfig, ...(preset ? { preset } : {}) };
|
|
281
|
+
}
|
|
282
|
+
function resolveRuntimeModelRefs(agent, refs) {
|
|
283
|
+
const merged = {
|
|
284
|
+
...(getRuntimeModelDefaults(refs) ?? {}),
|
|
285
|
+
...(agent.runtimeModelRefs ?? {}),
|
|
286
|
+
};
|
|
287
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
288
|
+
}
|
|
289
|
+
function compileRuntimeModels(modelRefs, models, ownerId) {
|
|
290
|
+
if (!modelRefs) {
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
const compiled = Object.fromEntries(Object.entries(modelRefs).map(([slot, modelRef]) => [slot, requireModel(models, modelRef, ownerId)]));
|
|
294
|
+
return Object.keys(compiled).length > 0 ? compiled : undefined;
|
|
295
|
+
}
|
|
235
296
|
export function compileBinding(workspaceRoot, agent, agents, referencedSubagentIds, refs, models, tools) {
|
|
236
297
|
const internalSubagent = referencedSubagentIds.has(agent.id);
|
|
237
298
|
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
@@ -243,6 +304,9 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
243
304
|
const store = resolveStoreConfig(agent, refs);
|
|
244
305
|
const checkpointer = resolveCheckpointerConfig(agent, refs);
|
|
245
306
|
const runtimeMemory = resolveRuntimeMemoryConfig(agent, refs);
|
|
307
|
+
const langGraphWorkflow = resolveLangGraphWorkflowConfig(agent, refs);
|
|
308
|
+
const runtimeModelRefs = resolveRuntimeModelRefs(agent, refs);
|
|
309
|
+
const runtimeModels = compileRuntimeModels(runtimeModelRefs, models, agent.id);
|
|
246
310
|
const runRoot = typeof agent.runRoot === "string" && agent.runRoot.trim().length > 0
|
|
247
311
|
? path.resolve(workspaceRoot, agent.runRoot)
|
|
248
312
|
: typeof runtimeDefaults?.runRoot === "string" && runtimeDefaults.runRoot.trim().length > 0
|
|
@@ -256,14 +320,19 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
256
320
|
? {
|
|
257
321
|
deepAgent: true,
|
|
258
322
|
}
|
|
259
|
-
:
|
|
260
|
-
|
|
261
|
-
|
|
323
|
+
: agent.executionMode === "langgraph"
|
|
324
|
+
? {
|
|
325
|
+
langGraph: true,
|
|
326
|
+
}
|
|
327
|
+
: {
|
|
328
|
+
langchainV1: true,
|
|
329
|
+
},
|
|
262
330
|
},
|
|
263
331
|
harnessRuntime: {
|
|
264
332
|
runRoot,
|
|
265
333
|
workspaceRoot,
|
|
266
|
-
|
|
334
|
+
...(runtimeModelRefs ? { modelRefs: runtimeModelRefs } : {}),
|
|
335
|
+
...(runtimeModels ? { models: runtimeModels } : {}),
|
|
267
336
|
capabilities: inferAgentCapabilities(agent),
|
|
268
337
|
resilience,
|
|
269
338
|
...(checkpointer ? { checkpointer: checkpointer.config } : {}),
|
|
@@ -272,6 +341,9 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
272
341
|
},
|
|
273
342
|
};
|
|
274
343
|
if (agent.executionMode !== "deepagent") {
|
|
344
|
+
const langGraphPassthrough = agent.executionMode === "langgraph" && langGraphWorkflow?.config
|
|
345
|
+
? { workflow: langGraphWorkflow.config }
|
|
346
|
+
: undefined;
|
|
275
347
|
const langchainAgentParams = {
|
|
276
348
|
model: compiledAgentModel,
|
|
277
349
|
tools: requireTools(tools, agent.toolRefs, agent.id),
|
|
@@ -283,9 +355,9 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
283
355
|
? { ...agent.langchainAgentConfig.filesystem }
|
|
284
356
|
: undefined,
|
|
285
357
|
middleware: compileMiddlewareConfigs(agent.langchainAgentConfig?.middleware, models, agent.id),
|
|
286
|
-
passthrough: typeof agent.langchainAgentConfig?.passthrough === "object" && agent.langchainAgentConfig.passthrough
|
|
358
|
+
passthrough: mergeOpaqueConfig(typeof agent.langchainAgentConfig?.passthrough === "object" && agent.langchainAgentConfig.passthrough
|
|
287
359
|
? { ...agent.langchainAgentConfig.passthrough }
|
|
288
|
-
: undefined,
|
|
360
|
+
: undefined, langGraphPassthrough),
|
|
289
361
|
subagents: agent.subagentRefs.map((ref) => {
|
|
290
362
|
const subagent = agents.get(resolveRefId(ref));
|
|
291
363
|
if (!subagent) {
|
|
@@ -309,8 +381,10 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
309
381
|
return {
|
|
310
382
|
...base,
|
|
311
383
|
adapter: {
|
|
312
|
-
kind: "langchain-v1",
|
|
384
|
+
kind: agent.executionMode === "langgraph" ? "langgraph" : "langchain-v1",
|
|
313
385
|
config: {
|
|
386
|
+
...(agent.executionMode === "langgraph" && langGraphWorkflow?.preset ? { preset: langGraphWorkflow.preset } : {}),
|
|
387
|
+
...(agent.executionMode === "langgraph" && langGraphWorkflow?.config ? { workflow: langGraphWorkflow.config } : {}),
|
|
314
388
|
params: langchainAgentParams,
|
|
315
389
|
},
|
|
316
390
|
},
|
|
@@ -71,9 +71,7 @@ function compileBindings(workspaceRoot, refs, agentsList, models, tools) {
|
|
|
71
71
|
return bindings;
|
|
72
72
|
}
|
|
73
73
|
function validateRoutingTargets(refs, agentsList) {
|
|
74
|
-
const runtimeEntryAgentIds = new Set(agentsList
|
|
75
|
-
.filter((agent) => !agentsList.some((owner) => owner.subagentRefs.some((ref) => resolveRefId(ref) === agent.id)))
|
|
76
|
-
.map((agent) => agent.id));
|
|
74
|
+
const runtimeEntryAgentIds = new Set(agentsList.map((agent) => agent.id));
|
|
77
75
|
const defaultAgentId = getRoutingDefaultAgentId(refs);
|
|
78
76
|
if (defaultAgentId && !runtimeEntryAgentIds.has(defaultAgentId)) {
|
|
79
77
|
throw new Error(`Runtime routing.defaultAgentId references unknown runtime entry agent ${defaultAgentId}`);
|