@botbotgo/agent-harness 0.0.92 → 0.0.94
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 +153 -31
- package/README.zh.md +108 -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 +318 -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 +49 -1
- package/dist/runtime/agent-runtime-adapter.js +1103 -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 +25 -0
- package/dist/runtime/langgraph-presets.js +165 -0
- package/dist/runtime/langgraph-profiles.d.ts +6 -0
- package/dist/runtime/langgraph-profiles.js +206 -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 +111 -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,25 @@
|
|
|
1
|
+
type LangGraphPresetNode = {
|
|
2
|
+
id: string;
|
|
3
|
+
kind: string;
|
|
4
|
+
prompt?: string;
|
|
5
|
+
role?: string;
|
|
6
|
+
agent?: string;
|
|
7
|
+
tool?: string;
|
|
8
|
+
};
|
|
9
|
+
type LangGraphPresetEdge = {
|
|
10
|
+
from: string;
|
|
11
|
+
to: string;
|
|
12
|
+
when?: string;
|
|
13
|
+
};
|
|
14
|
+
export type LangGraphPresetWorkflow = {
|
|
15
|
+
entryNode: string;
|
|
16
|
+
nodes: LangGraphPresetNode[];
|
|
17
|
+
edges: LangGraphPresetEdge[];
|
|
18
|
+
};
|
|
19
|
+
export type LangGraphPresetName = "react" | "prompt-chaining" | "routing" | "parallelization" | "plan-execute" | "review-loop" | "evaluator-optimizer" | "approval-gate" | "handoff" | "orchestrator-workers";
|
|
20
|
+
type LangGraphPresetOptions = {
|
|
21
|
+
agent?: string;
|
|
22
|
+
};
|
|
23
|
+
export declare const SUPPORTED_LANGGRAPH_PRESETS: LangGraphPresetName[];
|
|
24
|
+
export declare function resolveLangGraphPresetWorkflow(presetName: string | undefined, options?: LangGraphPresetOptions): LangGraphPresetWorkflow | undefined;
|
|
25
|
+
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 requireAgent(preset, options) {
|
|
18
|
+
if (typeof options.agent === "string" && options.agent.trim()) {
|
|
19
|
+
return options.agent.trim();
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`LangGraph preset ${preset} requires config.agent`);
|
|
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: "agent" },
|
|
33
|
+
],
|
|
34
|
+
edges: [],
|
|
35
|
+
};
|
|
36
|
+
case "prompt-chaining":
|
|
37
|
+
case "plan-execute":
|
|
38
|
+
return {
|
|
39
|
+
entryNode: "planner",
|
|
40
|
+
nodes: [
|
|
41
|
+
{ id: "planner", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
42
|
+
{ id: "executor", kind: "agent" },
|
|
43
|
+
{ id: "finalizer", kind: "llm", role: "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 agent = requireAgent("routing", options);
|
|
52
|
+
return {
|
|
53
|
+
entryNode: "planner",
|
|
54
|
+
nodes: [
|
|
55
|
+
{ id: "planner", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
56
|
+
{ id: "worker", kind: "agent", agent },
|
|
57
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
58
|
+
],
|
|
59
|
+
edges: [
|
|
60
|
+
{ from: "planner", to: "worker" },
|
|
61
|
+
{ from: "worker", to: "finalizer", when: "has_result" },
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
case "parallelization": {
|
|
66
|
+
const agent = requireAgent("parallelization", options);
|
|
67
|
+
return {
|
|
68
|
+
entryNode: "planner",
|
|
69
|
+
nodes: [
|
|
70
|
+
{ id: "planner", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
71
|
+
{ id: "worker", kind: "agent", agent },
|
|
72
|
+
{ id: "reviewer", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
73
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
74
|
+
],
|
|
75
|
+
edges: [
|
|
76
|
+
{ from: "planner", to: "worker" },
|
|
77
|
+
{ from: "worker", 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: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
87
|
+
{ id: "executor", kind: "agent" },
|
|
88
|
+
{ id: "reviewer", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
89
|
+
{ id: "replanner", kind: "llm", role: "replanner", prompt: DEFAULT_REPLANNER_PROMPT },
|
|
90
|
+
{ id: "finalizer", kind: "llm", role: "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: "agent" },
|
|
105
|
+
{ id: "reviewer", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
106
|
+
{ id: "replanner", kind: "llm", role: "replanner", prompt: DEFAULT_REPLANNER_PROMPT },
|
|
107
|
+
{ id: "finalizer", kind: "llm", role: "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: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
121
|
+
{ id: "approval", kind: "approval" },
|
|
122
|
+
{ id: "executor", kind: "agent" },
|
|
123
|
+
{ id: "finalizer", kind: "llm", role: "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 agent = requireAgent("handoff", options);
|
|
134
|
+
return {
|
|
135
|
+
entryNode: "worker",
|
|
136
|
+
nodes: [
|
|
137
|
+
{ id: "worker", kind: "agent", agent },
|
|
138
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
139
|
+
],
|
|
140
|
+
edges: [
|
|
141
|
+
{ from: "worker", to: "finalizer", when: "has_result" },
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
case "orchestrator-workers": {
|
|
146
|
+
const agent = requireAgent("orchestrator-workers", options);
|
|
147
|
+
return {
|
|
148
|
+
entryNode: "planner",
|
|
149
|
+
nodes: [
|
|
150
|
+
{ id: "planner", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
151
|
+
{ id: "worker", kind: "agent", agent },
|
|
152
|
+
{ id: "reviewer", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
153
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
154
|
+
],
|
|
155
|
+
edges: [
|
|
156
|
+
{ from: "planner", to: "worker" },
|
|
157
|
+
{ from: "worker", 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
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LangGraphPresetWorkflow } from "./langgraph-presets.js";
|
|
2
|
+
export type LangGraphProfileName = "coding-runtime" | "personal-assistant" | "research-runtime" | "approval-review-runtime" | "claw-style-assistant" | "chat-operator" | "copilot-sidecar" | "task-delegation-hub";
|
|
3
|
+
type LangGraphProfileOptions = Record<string, unknown>;
|
|
4
|
+
export declare const SUPPORTED_LANGGRAPH_PROFILES: LangGraphProfileName[];
|
|
5
|
+
export declare function resolveLangGraphProfileWorkflow(profileName: string | undefined, options?: LangGraphProfileOptions): LangGraphPresetWorkflow | undefined;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,206 @@
|
|
|
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_FINALIZER_PROMPT = "Rewrite the current result into a concise user-facing final answer. Preserve facts and caveats.";
|
|
4
|
+
const DEFAULT_REPLANNER_PROMPT = "Refine the plan based on the reviewer feedback and current result. Return only the updated plan.";
|
|
5
|
+
export const SUPPORTED_LANGGRAPH_PROFILES = [
|
|
6
|
+
"coding-runtime",
|
|
7
|
+
"personal-assistant",
|
|
8
|
+
"research-runtime",
|
|
9
|
+
"approval-review-runtime",
|
|
10
|
+
"claw-style-assistant",
|
|
11
|
+
"chat-operator",
|
|
12
|
+
"copilot-sidecar",
|
|
13
|
+
"task-delegation-hub",
|
|
14
|
+
];
|
|
15
|
+
function readStringOption(options, key) {
|
|
16
|
+
const value = options[key];
|
|
17
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
18
|
+
}
|
|
19
|
+
function requireAgentOption(profile, options, key) {
|
|
20
|
+
const value = readStringOption(options, key);
|
|
21
|
+
if (value) {
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`LangGraph profile ${profile} requires with.${key}`);
|
|
25
|
+
}
|
|
26
|
+
function buildCodingRuntimeWorkflow(options) {
|
|
27
|
+
const coderAgent = requireAgentOption("coding-runtime", options, "coderAgent");
|
|
28
|
+
const verifierAgent = readStringOption(options, "verifierAgent");
|
|
29
|
+
const needsVerification = Boolean(verifierAgent) || options.runIntegrationVerification === true;
|
|
30
|
+
return {
|
|
31
|
+
entryNode: "planner",
|
|
32
|
+
nodes: [
|
|
33
|
+
{ id: "planner", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
34
|
+
{ id: "coder", kind: "agent", agent: coderAgent },
|
|
35
|
+
{ id: "reviewer", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
36
|
+
{ id: "replanner", kind: "llm", role: "replanner", prompt: DEFAULT_REPLANNER_PROMPT },
|
|
37
|
+
...(needsVerification
|
|
38
|
+
? [{ id: "approval", kind: "approval" }, { id: "verifier", kind: "agent", agent: verifierAgent ?? coderAgent }]
|
|
39
|
+
: []),
|
|
40
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
41
|
+
],
|
|
42
|
+
edges: [
|
|
43
|
+
{ from: "planner", to: "coder" },
|
|
44
|
+
{ from: "coder", to: "reviewer", when: "has_result" },
|
|
45
|
+
{ from: "reviewer", to: needsVerification ? "approval" : "finalizer", when: "review_ok" },
|
|
46
|
+
{ from: "reviewer", to: "replanner", when: "review_incomplete" },
|
|
47
|
+
{ from: "replanner", to: "coder", when: "has_plan" },
|
|
48
|
+
...(needsVerification
|
|
49
|
+
? [
|
|
50
|
+
{ from: "approval", to: "verifier", when: "approval_approved" },
|
|
51
|
+
{ from: "approval", to: "verifier", when: "approval_edited" },
|
|
52
|
+
{ from: "verifier", to: "finalizer", when: "has_result" },
|
|
53
|
+
]
|
|
54
|
+
: []),
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function buildAssistantWorkflow(options) {
|
|
59
|
+
const worker = readStringOption(options, "defaultWorkerAgent") ??
|
|
60
|
+
readStringOption(options, "defaultResearchAgent") ??
|
|
61
|
+
readStringOption(options, "defaultWritingAgent") ??
|
|
62
|
+
readStringOption(options, "defaultSchedulingAgent");
|
|
63
|
+
return {
|
|
64
|
+
entryNode: "intake",
|
|
65
|
+
nodes: [
|
|
66
|
+
{ id: "intake", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
67
|
+
...(worker ? [{ id: "worker", kind: "agent", agent: worker }] : [{ id: "lookup", kind: "tool", tool: "repo_inventory" }]),
|
|
68
|
+
{ id: "reviewer", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
69
|
+
{ id: "approval", kind: "approval" },
|
|
70
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
71
|
+
],
|
|
72
|
+
edges: [
|
|
73
|
+
{ from: "intake", to: worker ? "worker" : "lookup" },
|
|
74
|
+
{ from: worker ? "worker" : "lookup", to: "reviewer", when: "has_result" },
|
|
75
|
+
{ from: "reviewer", to: "approval", when: "review_incomplete" },
|
|
76
|
+
{ from: "reviewer", to: "finalizer", when: "review_ok" },
|
|
77
|
+
{ from: "approval", to: "finalizer", when: "approval_approved" },
|
|
78
|
+
{ from: "approval", to: "finalizer", when: "approval_edited" },
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function buildResearchWorkflow(options) {
|
|
83
|
+
const gathererAgent = requireAgentOption("research-runtime", options, "gathererAgent");
|
|
84
|
+
const analystAgent = requireAgentOption("research-runtime", options, "analystAgent");
|
|
85
|
+
const synthesizerAgent = readStringOption(options, "synthesizerAgent");
|
|
86
|
+
return {
|
|
87
|
+
entryNode: "planner",
|
|
88
|
+
nodes: [
|
|
89
|
+
{ id: "planner", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
90
|
+
{ id: "gatherer", kind: "agent", agent: gathererAgent },
|
|
91
|
+
{ id: "coverage-review", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
92
|
+
{ id: "analyst", kind: "agent", agent: analystAgent },
|
|
93
|
+
...(synthesizerAgent ? [{ id: "synthesizer", kind: "agent", agent: synthesizerAgent }] : []),
|
|
94
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
95
|
+
],
|
|
96
|
+
edges: [
|
|
97
|
+
{ from: "planner", to: "gatherer" },
|
|
98
|
+
{ from: "gatherer", to: "coverage-review", when: "has_result" },
|
|
99
|
+
{ from: "coverage-review", to: "analyst", when: "review_ok" },
|
|
100
|
+
{ from: "coverage-review", to: "gatherer", when: "review_incomplete" },
|
|
101
|
+
{ from: "analyst", to: synthesizerAgent ? "synthesizer" : "finalizer", when: "has_result" },
|
|
102
|
+
...(synthesizerAgent ? [{ from: "synthesizer", to: "finalizer", when: "has_result" }] : []),
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function buildApprovalReviewWorkflow(options) {
|
|
107
|
+
const preparerAgent = requireAgentOption("approval-review-runtime", options, "preparerAgent");
|
|
108
|
+
const reviewerAgent = readStringOption(options, "reviewerAgent");
|
|
109
|
+
return {
|
|
110
|
+
entryNode: "scope",
|
|
111
|
+
nodes: [
|
|
112
|
+
{ id: "scope", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
113
|
+
{ id: "preparer", kind: "agent", agent: preparerAgent },
|
|
114
|
+
...(reviewerAgent ? [{ id: "reviewer-agent", kind: "agent", agent: reviewerAgent }] : [{ id: "risk-review", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT }]),
|
|
115
|
+
{ id: "approval", kind: "approval" },
|
|
116
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
117
|
+
],
|
|
118
|
+
edges: [
|
|
119
|
+
{ from: "scope", to: "preparer" },
|
|
120
|
+
{ from: "preparer", to: reviewerAgent ? "reviewer-agent" : "risk-review", when: "has_result" },
|
|
121
|
+
{ from: reviewerAgent ? "reviewer-agent" : "risk-review", to: "approval", when: "has_result" },
|
|
122
|
+
{ from: "approval", to: "finalizer", when: "approval_approved" },
|
|
123
|
+
{ from: "approval", to: "finalizer", when: "approval_edited" },
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function buildChatOperatorWorkflow(options) {
|
|
128
|
+
const routedAgent = readStringOption(options, "assistantAgent") ??
|
|
129
|
+
readStringOption(options, "researchAgent") ??
|
|
130
|
+
readStringOption(options, "codingAgent") ??
|
|
131
|
+
readStringOption(options, "approvalAgent");
|
|
132
|
+
if (!routedAgent) {
|
|
133
|
+
throw new Error("LangGraph profile chat-operator requires at least one target agent in with.assistantAgent, with.researchAgent, with.codingAgent, or with.approvalAgent");
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
entryNode: "router",
|
|
137
|
+
nodes: [
|
|
138
|
+
{ id: "router", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
139
|
+
{ id: "worker", kind: "agent", agent: routedAgent },
|
|
140
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
141
|
+
],
|
|
142
|
+
edges: [
|
|
143
|
+
{ from: "router", to: "worker" },
|
|
144
|
+
{ from: "worker", to: "finalizer", when: "has_result" },
|
|
145
|
+
],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function buildCopilotSidecarWorkflow(options) {
|
|
149
|
+
const coderAgent = requireAgentOption("copilot-sidecar", options, "coderAgent");
|
|
150
|
+
return {
|
|
151
|
+
entryNode: "intake",
|
|
152
|
+
nodes: [
|
|
153
|
+
{ id: "intake", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
154
|
+
{ id: "coder", kind: "agent", agent: coderAgent },
|
|
155
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
156
|
+
],
|
|
157
|
+
edges: [
|
|
158
|
+
{ from: "intake", to: "coder" },
|
|
159
|
+
{ from: "coder", to: "finalizer", when: "has_result" },
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function buildDelegationHubWorkflow(options) {
|
|
164
|
+
const workerAgent = readStringOption(options, "defaultWorkerFallback");
|
|
165
|
+
if (!workerAgent) {
|
|
166
|
+
throw new Error("LangGraph profile task-delegation-hub requires with.defaultWorkerFallback");
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
entryNode: "router",
|
|
170
|
+
nodes: [
|
|
171
|
+
{ id: "router", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
172
|
+
{ id: "worker", kind: "agent", agent: workerAgent },
|
|
173
|
+
{ id: "reviewer", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
174
|
+
{ id: "finalizer", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
175
|
+
],
|
|
176
|
+
edges: [
|
|
177
|
+
{ from: "router", to: "worker" },
|
|
178
|
+
{ from: "worker", to: "reviewer", when: "has_result" },
|
|
179
|
+
{ from: "reviewer", to: "finalizer", when: "review_ok" },
|
|
180
|
+
],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
export function resolveLangGraphProfileWorkflow(profileName, options = {}) {
|
|
184
|
+
switch (profileName) {
|
|
185
|
+
case undefined:
|
|
186
|
+
case "":
|
|
187
|
+
return undefined;
|
|
188
|
+
case "coding-runtime":
|
|
189
|
+
return buildCodingRuntimeWorkflow(options);
|
|
190
|
+
case "personal-assistant":
|
|
191
|
+
case "claw-style-assistant":
|
|
192
|
+
return buildAssistantWorkflow(options);
|
|
193
|
+
case "research-runtime":
|
|
194
|
+
return buildResearchWorkflow(options);
|
|
195
|
+
case "approval-review-runtime":
|
|
196
|
+
return buildApprovalReviewWorkflow(options);
|
|
197
|
+
case "chat-operator":
|
|
198
|
+
return buildChatOperatorWorkflow(options);
|
|
199
|
+
case "copilot-sidecar":
|
|
200
|
+
return buildCopilotSidecarWorkflow(options);
|
|
201
|
+
case "task-delegation-hub":
|
|
202
|
+
return buildDelegationHubWorkflow(options);
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(`Unsupported LangGraph profile ${String(profileName)}. Supported profiles: ${SUPPORTED_LANGGRAPH_PROFILES.join(", ")}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -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
|
}
|