@botbotgo/agent-harness 0.0.95 → 0.0.97
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 +1 -114
- package/README.zh.md +1 -70
- package/dist/api.d.ts +5 -5
- package/dist/config/workflows/langgraph-workflows.yaml +363 -111
- package/dist/config/workflows/runtime-profiles.yaml +94 -0
- package/dist/contracts/core.d.ts +9 -0
- package/dist/contracts/core.js +1 -0
- package/dist/contracts/runtime.d.ts +421 -0
- package/dist/contracts/runtime.js +1 -0
- package/dist/contracts/types.d.ts +3 -571
- package/dist/contracts/types.js +3 -1
- package/dist/contracts/workspace.d.ts +229 -0
- package/dist/contracts/workspace.js +1 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/compat/deepagent-compat.d.ts +16 -0
- package/dist/runtime/adapter/compat/deepagent-compat.js +45 -0
- package/dist/runtime/adapter/compat/openai-compatible.d.ts +2 -0
- package/dist/runtime/adapter/compat/openai-compatible.js +43 -0
- package/dist/runtime/adapter/index.d.ts +15 -0
- package/dist/runtime/adapter/index.js +15 -0
- package/dist/runtime/adapter/langgraph/presets.js +165 -0
- package/dist/runtime/{langgraph-profiles.d.ts → adapter/langgraph/profiles.d.ts} +1 -1
- package/dist/runtime/adapter/langgraph/profiles.js +206 -0
- package/dist/runtime/adapter/model/invocation-request.d.ts +10 -0
- package/dist/runtime/adapter/model/invocation-request.js +46 -0
- package/dist/runtime/adapter/model/message-assembly.d.ts +6 -0
- package/dist/runtime/adapter/model/message-assembly.js +21 -0
- package/dist/runtime/adapter/model/model-providers.d.ts +2 -0
- package/dist/runtime/adapter/model/model-providers.js +27 -0
- package/dist/runtime/adapter/resilience.d.ts +12 -0
- package/dist/runtime/adapter/resilience.js +60 -0
- package/dist/runtime/{declared-middleware.d.ts → adapter/tool/declared-middleware.d.ts} +1 -1
- package/dist/runtime/adapter/tool/interrupt-policy.d.ts +8 -0
- package/dist/runtime/adapter/tool/interrupt-policy.js +34 -0
- package/dist/runtime/adapter/tool/provider-tool.d.ts +2 -0
- package/dist/runtime/adapter/tool/provider-tool.js +25 -0
- package/dist/runtime/adapter/tool/resolved-tool.d.ts +18 -0
- package/dist/runtime/adapter/tool/resolved-tool.js +62 -0
- package/dist/runtime/adapter/tool/tool-arguments.d.ts +7 -0
- package/dist/runtime/adapter/tool/tool-arguments.js +87 -0
- package/dist/runtime/{tool-hitl.d.ts → adapter/tool/tool-hitl.d.ts} +2 -2
- package/dist/runtime/adapter/tool/tool-name-mapping.d.ts +13 -0
- package/dist/runtime/adapter/tool/tool-name-mapping.js +101 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +5 -20
- package/dist/runtime/agent-runtime-adapter.js +42 -544
- package/dist/runtime/checkpoint-maintenance.d.ts +1 -45
- package/dist/runtime/checkpoint-maintenance.js +1 -259
- package/dist/runtime/file-checkpoint-saver.d.ts +1 -20
- package/dist/runtime/file-checkpoint-saver.js +1 -106
- package/dist/runtime/{event-bus.d.ts → harness/events/event-bus.d.ts} +1 -1
- package/dist/runtime/{event-sink.d.ts → harness/events/event-sink.d.ts} +1 -1
- package/dist/runtime/{event-sink.js → harness/events/event-sink.js} +1 -1
- package/dist/runtime/harness/events/events.d.ts +23 -0
- package/dist/runtime/harness/events/events.js +61 -0
- package/dist/runtime/harness/events/streaming.d.ts +19 -0
- package/dist/runtime/harness/events/streaming.js +96 -0
- package/dist/runtime/harness/index.d.ts +16 -0
- package/dist/runtime/harness/index.js +16 -0
- package/dist/runtime/harness/run/helpers.d.ts +33 -0
- package/dist/runtime/harness/run/helpers.js +74 -0
- package/dist/runtime/harness/run/resources.d.ts +7 -0
- package/dist/runtime/harness/run/resources.js +58 -0
- package/dist/runtime/harness/run/resume.d.ts +6 -0
- package/dist/runtime/harness/run/resume.js +56 -0
- package/dist/runtime/harness/run/routing.d.ts +12 -0
- package/dist/runtime/harness/run/routing.js +47 -0
- package/dist/runtime/harness/run/run-lifecycle.d.ts +37 -0
- package/dist/runtime/harness/run/run-lifecycle.js +109 -0
- package/dist/runtime/harness/run/run-queue.d.ts +17 -0
- package/dist/runtime/harness/run/run-queue.js +43 -0
- package/dist/runtime/{health-monitor.d.ts → harness/system/health-monitor.d.ts} +3 -3
- package/dist/runtime/{health-monitor.js → harness/system/health-monitor.js} +2 -2
- package/dist/runtime/{inventory.d.ts → harness/system/inventory.d.ts} +2 -2
- package/dist/runtime/{inventory.js → harness/system/inventory.js} +4 -4
- package/dist/runtime/{policy-engine.d.ts → harness/system/policy-engine.d.ts} +1 -1
- package/dist/runtime/{policy-engine.js → harness/system/policy-engine.js} +1 -1
- package/dist/runtime/{skill-requirements.d.ts → harness/system/skill-requirements.d.ts} +1 -1
- package/dist/runtime/{skill-requirements.js → harness/system/skill-requirements.js} +1 -1
- package/dist/runtime/{thread-memory-sync.d.ts → harness/system/thread-memory-sync.d.ts} +2 -2
- package/dist/runtime/{thread-memory-sync.js → harness/system/thread-memory-sync.js} +1 -1
- package/dist/runtime/harness.d.ts +2 -7
- package/dist/runtime/harness.js +158 -477
- package/dist/runtime/index.d.ts +7 -7
- package/dist/runtime/index.js +7 -7
- package/dist/runtime/maintenance/checkpoint-maintenance.d.ts +45 -0
- package/dist/runtime/maintenance/checkpoint-maintenance.js +259 -0
- package/dist/runtime/maintenance/file-checkpoint-saver.d.ts +20 -0
- package/dist/runtime/maintenance/file-checkpoint-saver.js +106 -0
- package/dist/runtime/maintenance/index.d.ts +4 -0
- package/dist/runtime/maintenance/index.js +4 -0
- package/dist/runtime/{runtime-record-maintenance.d.ts → maintenance/runtime-record-maintenance.d.ts} +1 -1
- package/dist/runtime/{runtime-record-maintenance.js → maintenance/runtime-record-maintenance.js} +2 -2
- package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.d.ts +9 -0
- package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.js +39 -0
- package/dist/runtime/parsing/stream-event-parsing.d.ts +6 -0
- package/dist/runtime/parsing/stream-event-parsing.js +231 -0
- package/dist/runtime/sqlite-maintained-checkpoint-saver.d.ts +1 -9
- package/dist/runtime/sqlite-maintained-checkpoint-saver.js +1 -39
- package/dist/runtime/support/harness-support.d.ts +4 -4
- package/dist/runtime/support/harness-support.js +14 -3
- package/dist/runtime/support/runtime-factories.d.ts +1 -1
- package/dist/runtime/support/runtime-factories.js +1 -1
- package/dist/workspace/agent-binding-compiler.js +39 -3
- package/dist/workspace/object-loader.js +5 -1
- package/package.json +4 -4
- package/dist/runtime/langgraph-presets.js +0 -165
- package/dist/runtime/langgraph-profiles.js +0 -206
- /package/dist/runtime/{langgraph-presets.d.ts → adapter/langgraph/presets.d.ts} +0 -0
- /package/dist/runtime/{declared-middleware.js → adapter/tool/declared-middleware.js} +0 -0
- /package/dist/runtime/{tool-hitl.js → adapter/tool/tool-hitl.js} +0 -0
- /package/dist/runtime/{event-bus.js → harness/events/event-bus.js} +0 -0
- /package/dist/runtime/{store.d.ts → harness/system/store.d.ts} +0 -0
- /package/dist/runtime/{store.js → harness/system/store.js} +0 -0
|
@@ -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: "step1",
|
|
32
|
+
nodes: [
|
|
33
|
+
{ id: "step1", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
34
|
+
{ id: "step2", kind: "agent", agent: coderAgent },
|
|
35
|
+
{ id: "step3", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
36
|
+
{ id: "step4", kind: "llm", role: "replanner", prompt: DEFAULT_REPLANNER_PROMPT },
|
|
37
|
+
...(needsVerification
|
|
38
|
+
? [{ id: "step5", kind: "approval" }, { id: "step6", kind: "agent", agent: verifierAgent ?? coderAgent }]
|
|
39
|
+
: []),
|
|
40
|
+
{ id: "step7", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
41
|
+
],
|
|
42
|
+
edges: [
|
|
43
|
+
{ from: "step1", to: "step2" },
|
|
44
|
+
{ from: "step2", to: "step3", when: "has_result" },
|
|
45
|
+
{ from: "step3", to: needsVerification ? "step5" : "step7", when: "review_ok" },
|
|
46
|
+
{ from: "step3", to: "step4", when: "review_incomplete" },
|
|
47
|
+
{ from: "step4", to: "step2", when: "has_plan" },
|
|
48
|
+
...(needsVerification
|
|
49
|
+
? [
|
|
50
|
+
{ from: "step5", to: "step6", when: "approval_approved" },
|
|
51
|
+
{ from: "step5", to: "step6", when: "approval_edited" },
|
|
52
|
+
{ from: "step6", to: "step7", 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: "step1",
|
|
65
|
+
nodes: [
|
|
66
|
+
{ id: "step1", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
67
|
+
...(worker ? [{ id: "step2", kind: "agent", agent: worker }] : [{ id: "step2", kind: "tool", tool: "repo_inventory" }]),
|
|
68
|
+
{ id: "step3", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
69
|
+
{ id: "step4", kind: "approval" },
|
|
70
|
+
{ id: "step5", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
71
|
+
],
|
|
72
|
+
edges: [
|
|
73
|
+
{ from: "step1", to: "step2" },
|
|
74
|
+
{ from: "step2", to: "step3", when: "has_result" },
|
|
75
|
+
{ from: "step3", to: "step4", when: "review_incomplete" },
|
|
76
|
+
{ from: "step3", to: "step5", when: "review_ok" },
|
|
77
|
+
{ from: "step4", to: "step5", when: "approval_approved" },
|
|
78
|
+
{ from: "step4", to: "step5", 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: "step1",
|
|
88
|
+
nodes: [
|
|
89
|
+
{ id: "step1", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
90
|
+
{ id: "step2", kind: "agent", agent: gathererAgent },
|
|
91
|
+
{ id: "step3", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
92
|
+
{ id: "step4", kind: "agent", agent: analystAgent },
|
|
93
|
+
...(synthesizerAgent ? [{ id: "step5", kind: "agent", agent: synthesizerAgent }] : []),
|
|
94
|
+
{ id: "step6", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
95
|
+
],
|
|
96
|
+
edges: [
|
|
97
|
+
{ from: "step1", to: "step2" },
|
|
98
|
+
{ from: "step2", to: "step3", when: "has_result" },
|
|
99
|
+
{ from: "step3", to: "step4", when: "review_ok" },
|
|
100
|
+
{ from: "step3", to: "step2", when: "review_incomplete" },
|
|
101
|
+
{ from: "step4", to: synthesizerAgent ? "step5" : "step6", when: "has_result" },
|
|
102
|
+
...(synthesizerAgent ? [{ from: "step5", to: "step6", 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: "step1",
|
|
111
|
+
nodes: [
|
|
112
|
+
{ id: "step1", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
113
|
+
{ id: "step2", kind: "agent", agent: preparerAgent },
|
|
114
|
+
...(reviewerAgent ? [{ id: "step3", kind: "agent", agent: reviewerAgent }] : [{ id: "step3", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT }]),
|
|
115
|
+
{ id: "step4", kind: "approval" },
|
|
116
|
+
{ id: "step5", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
117
|
+
],
|
|
118
|
+
edges: [
|
|
119
|
+
{ from: "step1", to: "step2" },
|
|
120
|
+
{ from: "step2", to: "step3", when: "has_result" },
|
|
121
|
+
{ from: "step3", to: "step4", when: "has_result" },
|
|
122
|
+
{ from: "step4", to: "step5", when: "approval_approved" },
|
|
123
|
+
{ from: "step4", to: "step5", 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: "step1",
|
|
137
|
+
nodes: [
|
|
138
|
+
{ id: "step1", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
139
|
+
{ id: "step2", kind: "agent", agent: routedAgent },
|
|
140
|
+
{ id: "step3", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
141
|
+
],
|
|
142
|
+
edges: [
|
|
143
|
+
{ from: "step1", to: "step2" },
|
|
144
|
+
{ from: "step2", to: "step3", when: "has_result" },
|
|
145
|
+
],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function buildCopilotSidecarWorkflow(options) {
|
|
149
|
+
const coderAgent = requireAgentOption("copilot-sidecar", options, "coderAgent");
|
|
150
|
+
return {
|
|
151
|
+
entryNode: "step1",
|
|
152
|
+
nodes: [
|
|
153
|
+
{ id: "step1", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
154
|
+
{ id: "step2", kind: "agent", agent: coderAgent },
|
|
155
|
+
{ id: "step3", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
156
|
+
],
|
|
157
|
+
edges: [
|
|
158
|
+
{ from: "step1", to: "step2" },
|
|
159
|
+
{ from: "step2", to: "step3", 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: "step1",
|
|
170
|
+
nodes: [
|
|
171
|
+
{ id: "step1", kind: "llm", role: "planner", prompt: DEFAULT_PLANNER_PROMPT },
|
|
172
|
+
{ id: "step2", kind: "agent", agent: workerAgent },
|
|
173
|
+
{ id: "step3", kind: "llm", role: "reviewer", prompt: DEFAULT_REVIEWER_PROMPT },
|
|
174
|
+
{ id: "step4", kind: "llm", role: "finalizer", prompt: DEFAULT_FINALIZER_PROMPT },
|
|
175
|
+
],
|
|
176
|
+
edges: [
|
|
177
|
+
{ from: "step1", to: "step2" },
|
|
178
|
+
{ from: "step2", to: "step3", when: "has_result" },
|
|
179
|
+
{ from: "step3", to: "step4", 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
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CompiledAgentBinding, MessageContent, TranscriptMessage } from "../../../contracts/types.js";
|
|
2
|
+
export declare function buildAgentMessages(history: TranscriptMessage[], input: MessageContent): Array<{
|
|
3
|
+
role: string;
|
|
4
|
+
content: MessageContent;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function buildSlashCommandSkillInstruction(binding: CompiledAgentBinding, input: MessageContent): string | undefined;
|
|
7
|
+
export declare function buildInvocationRequest(binding: CompiledAgentBinding, history: TranscriptMessage[], input: MessageContent, options?: {
|
|
8
|
+
state?: Record<string, unknown>;
|
|
9
|
+
files?: Record<string, unknown>;
|
|
10
|
+
}): Record<string, unknown>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { extractMessageText, normalizeMessageContent } from "../../../utils/message-content.js";
|
|
2
|
+
import { readSkillMetadata } from "../../support/skill-metadata.js";
|
|
3
|
+
export function buildAgentMessages(history, input) {
|
|
4
|
+
return [
|
|
5
|
+
...history.map((item) => ({ role: item.role, content: normalizeMessageContent(item.content) })),
|
|
6
|
+
{ role: "user", content: normalizeMessageContent(input) },
|
|
7
|
+
];
|
|
8
|
+
}
|
|
9
|
+
export function buildSlashCommandSkillInstruction(binding, input) {
|
|
10
|
+
const inputText = extractMessageText(input).trim();
|
|
11
|
+
const match = inputText.match(/^\/([a-z0-9]+(?:-[a-z0-9]+)*)(?:\s+([\s\S]*))?$/i);
|
|
12
|
+
if (!match) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const invokedName = match[1].toLowerCase();
|
|
16
|
+
const argumentText = match[2]?.trim() ?? "";
|
|
17
|
+
const skillPaths = binding.deepAgentParams?.skills ?? binding.langchainAgentParams?.skills ?? [];
|
|
18
|
+
const matchedSkillPath = skillPaths.find((skillPath) => readSkillMetadata(skillPath).name.toLowerCase() === invokedName);
|
|
19
|
+
if (!matchedSkillPath) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const metadata = readSkillMetadata(matchedSkillPath);
|
|
23
|
+
const skillQualifier = metadata.userInvocable === true ? "user-invocable skill" : "skill";
|
|
24
|
+
const dryRunHint = /\s--dry-run(?:\s|$)/.test(` ${argumentText} `)
|
|
25
|
+
? "This invocation includes `--dry-run`. Perform the real fetch or inspection steps needed for dry-run output. Do not return hypothetical or mock results."
|
|
26
|
+
: undefined;
|
|
27
|
+
return [
|
|
28
|
+
`This user message is an explicit command-style invocation of the ${skillQualifier} \`${metadata.name}\`.`,
|
|
29
|
+
`Read the skill file for \`${metadata.name}\` before taking action, then follow its documented phases and constraints exactly.`,
|
|
30
|
+
`You must use the \`${metadata.name}\` skill for this request and follow its documented workflow.`,
|
|
31
|
+
`Treat everything after \`/${metadata.name}\` as the skill argument string: ${argumentText ? JSON.stringify(argumentText) : '""'}.`,
|
|
32
|
+
"Do not answer with a generic explanation of what the skill would do. Execute the skill workflow using the available tools unless the skill instructions explicitly require confirmation before acting.",
|
|
33
|
+
dryRunHint,
|
|
34
|
+
].filter((line) => typeof line === "string" && line.length > 0).join("\n");
|
|
35
|
+
}
|
|
36
|
+
export function buildInvocationRequest(binding, history, input, options = {}) {
|
|
37
|
+
const userInvocableInstruction = buildSlashCommandSkillInstruction(binding, input);
|
|
38
|
+
const messages = buildAgentMessages(history, input);
|
|
39
|
+
return {
|
|
40
|
+
...(options.state ?? {}),
|
|
41
|
+
...(options.files ? { files: options.files } : {}),
|
|
42
|
+
messages: userInvocableInstruction
|
|
43
|
+
? [{ role: "system", content: userInvocableInstruction }, ...messages]
|
|
44
|
+
: messages,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CompiledAgentBinding, MessageContent, TranscriptMessage } from "../../../contracts/types.js";
|
|
2
|
+
export declare function buildStateSnapshot(result: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
3
|
+
export declare function buildRawModelMessages(binding: CompiledAgentBinding, systemPrompt: string | undefined, history: TranscriptMessage[], input: MessageContent): Array<{
|
|
4
|
+
role: string;
|
|
5
|
+
content: MessageContent;
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { buildAgentMessages, buildSlashCommandSkillInstruction } from "./invocation-request.js";
|
|
2
|
+
export function buildStateSnapshot(result) {
|
|
3
|
+
const snapshot = { ...result };
|
|
4
|
+
delete snapshot.messages;
|
|
5
|
+
delete snapshot.__interrupt__;
|
|
6
|
+
delete snapshot.structuredResponse;
|
|
7
|
+
delete snapshot.files;
|
|
8
|
+
return Object.keys(snapshot).length > 0 ? snapshot : undefined;
|
|
9
|
+
}
|
|
10
|
+
export function buildRawModelMessages(binding, systemPrompt, history, input) {
|
|
11
|
+
const messages = [];
|
|
12
|
+
if (systemPrompt) {
|
|
13
|
+
messages.push({ role: "system", content: systemPrompt });
|
|
14
|
+
}
|
|
15
|
+
const userInvocableInstruction = buildSlashCommandSkillInstruction(binding, input);
|
|
16
|
+
if (userInvocableInstruction) {
|
|
17
|
+
messages.push({ role: "system", content: userInvocableInstruction });
|
|
18
|
+
}
|
|
19
|
+
messages.push(...buildAgentMessages(history, input));
|
|
20
|
+
return messages;
|
|
21
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ChatAnthropic } from "@langchain/anthropic";
|
|
2
|
+
import { ChatGoogle } from "@langchain/google";
|
|
3
|
+
import { ChatOllama } from "@langchain/ollama";
|
|
4
|
+
import { ChatOpenAI } from "@langchain/openai";
|
|
5
|
+
import { initChatModel } from "langchain";
|
|
6
|
+
import { normalizeOpenAICompatibleInit } from "../compat/openai-compatible.js";
|
|
7
|
+
export async function createResolvedModel(model, modelResolver) {
|
|
8
|
+
if (modelResolver) {
|
|
9
|
+
return modelResolver(model.id);
|
|
10
|
+
}
|
|
11
|
+
if (model.provider === "ollama") {
|
|
12
|
+
return new ChatOllama({ model: model.model, ...model.init });
|
|
13
|
+
}
|
|
14
|
+
if (model.provider === "openai-compatible") {
|
|
15
|
+
return new ChatOpenAI({ model: model.model, ...normalizeOpenAICompatibleInit(model.init) });
|
|
16
|
+
}
|
|
17
|
+
if (model.provider === "openai") {
|
|
18
|
+
return new ChatOpenAI({ model: model.model, ...model.init });
|
|
19
|
+
}
|
|
20
|
+
if (model.provider === "anthropic") {
|
|
21
|
+
return new ChatAnthropic({ model: model.model, ...model.init });
|
|
22
|
+
}
|
|
23
|
+
if (model.provider === "google" || model.provider === "google-genai" || model.provider === "gemini") {
|
|
24
|
+
return new ChatGoogle({ model: model.model, ...model.init });
|
|
25
|
+
}
|
|
26
|
+
return initChatModel(model.model, { modelProvider: model.provider, ...model.init });
|
|
27
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CompiledAgentBinding } from "../../contracts/types.js";
|
|
2
|
+
export declare function resolveTimeoutMs(value: unknown): number | undefined;
|
|
3
|
+
export declare function computeRemainingTimeoutMs(deadlineAt: number | undefined, fallbackTimeoutMs: number | undefined): number | undefined;
|
|
4
|
+
export declare function resolveBindingTimeout(binding: CompiledAgentBinding): number | undefined;
|
|
5
|
+
export declare function resolveStreamIdleTimeout(binding: CompiledAgentBinding): number | undefined;
|
|
6
|
+
export type ProviderRetryPolicy = {
|
|
7
|
+
maxAttempts: number;
|
|
8
|
+
backoffMs: number;
|
|
9
|
+
retryableMessages: string[];
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveProviderRetryPolicy(binding: CompiledAgentBinding): ProviderRetryPolicy;
|
|
12
|
+
export declare function isRetryableProviderError(binding: CompiledAgentBinding, error: unknown): boolean;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { getBindingModelInit } from "../support/compiled-binding.js";
|
|
2
|
+
export function resolveTimeoutMs(value) {
|
|
3
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
4
|
+
}
|
|
5
|
+
export function computeRemainingTimeoutMs(deadlineAt, fallbackTimeoutMs) {
|
|
6
|
+
if (!deadlineAt) {
|
|
7
|
+
return fallbackTimeoutMs;
|
|
8
|
+
}
|
|
9
|
+
const remaining = deadlineAt - Date.now();
|
|
10
|
+
if (remaining <= 0) {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
return fallbackTimeoutMs ? Math.min(fallbackTimeoutMs, remaining) : remaining;
|
|
14
|
+
}
|
|
15
|
+
export function resolveBindingTimeout(binding) {
|
|
16
|
+
return resolveTimeoutMs(getBindingModelInit(binding)?.timeout);
|
|
17
|
+
}
|
|
18
|
+
export function resolveStreamIdleTimeout(binding) {
|
|
19
|
+
const configuredIdleTimeout = resolveTimeoutMs(getBindingModelInit(binding)?.streamIdleTimeout);
|
|
20
|
+
if (configuredIdleTimeout) {
|
|
21
|
+
return configuredIdleTimeout;
|
|
22
|
+
}
|
|
23
|
+
const invokeTimeout = resolveBindingTimeout(binding);
|
|
24
|
+
if (invokeTimeout) {
|
|
25
|
+
return Math.min(invokeTimeout, 15_000);
|
|
26
|
+
}
|
|
27
|
+
return 15_000;
|
|
28
|
+
}
|
|
29
|
+
export function resolveProviderRetryPolicy(binding) {
|
|
30
|
+
const resilience = typeof binding.harnessRuntime.resilience === "object" && binding.harnessRuntime.resilience
|
|
31
|
+
? binding.harnessRuntime.resilience
|
|
32
|
+
: {};
|
|
33
|
+
const providerRetries = typeof resilience.providerRetries === "object" && resilience.providerRetries
|
|
34
|
+
? resilience.providerRetries
|
|
35
|
+
: {};
|
|
36
|
+
const maxAttempts = typeof providerRetries.maxAttempts === "number" &&
|
|
37
|
+
Number.isFinite(providerRetries.maxAttempts) &&
|
|
38
|
+
providerRetries.maxAttempts > 0
|
|
39
|
+
? Math.floor(providerRetries.maxAttempts)
|
|
40
|
+
: 2;
|
|
41
|
+
const backoffMs = typeof providerRetries.backoffMs === "number" &&
|
|
42
|
+
Number.isFinite(providerRetries.backoffMs) &&
|
|
43
|
+
providerRetries.backoffMs >= 0
|
|
44
|
+
? Math.floor(providerRetries.backoffMs)
|
|
45
|
+
: 1_000;
|
|
46
|
+
const retryableMessages = Array.isArray(providerRetries.retryableMessages)
|
|
47
|
+
? providerRetries.retryableMessages.filter((value) => typeof value === "string" && value.trim().length > 0)
|
|
48
|
+
: [];
|
|
49
|
+
return {
|
|
50
|
+
maxAttempts,
|
|
51
|
+
backoffMs,
|
|
52
|
+
retryableMessages,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function isRetryableProviderError(binding, error) {
|
|
56
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
57
|
+
const normalized = message.toLowerCase();
|
|
58
|
+
const { retryableMessages } = resolveProviderRetryPolicy(binding);
|
|
59
|
+
return retryableMessages.some((candidate) => normalized.includes(candidate.toLowerCase()));
|
|
60
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CompiledAgentBinding, CompiledModel } from "
|
|
1
|
+
import type { CompiledAgentBinding, CompiledModel } from "../../../contracts/types.js";
|
|
2
2
|
type MiddlewareConfig = Record<string, unknown>;
|
|
3
3
|
type MiddlewareFactoryContext = {
|
|
4
4
|
config: MiddlewareConfig;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CompiledTool } from "../../../contracts/types.js";
|
|
2
|
+
export type InterruptDecision = "approve" | "edit" | "reject";
|
|
3
|
+
export declare function normalizeInterruptPolicy(rule: boolean | object | undefined): InterruptDecision[] | null;
|
|
4
|
+
export declare function compileInterruptOn(tools: Array<Pick<CompiledTool, "name">> | Array<{
|
|
5
|
+
name: string;
|
|
6
|
+
}>, compatibilityRules?: Record<string, boolean | object>): Record<string, {
|
|
7
|
+
allowedDecisions: InterruptDecision[];
|
|
8
|
+
}> | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { buildToolNameMapping } from "./tool-name-mapping.js";
|
|
2
|
+
export function normalizeInterruptPolicy(rule) {
|
|
3
|
+
if (!rule)
|
|
4
|
+
return null;
|
|
5
|
+
if (rule === true)
|
|
6
|
+
return ["approve", "edit", "reject"];
|
|
7
|
+
const typed = rule;
|
|
8
|
+
if (Array.isArray(typed.allowedDecisions)) {
|
|
9
|
+
return typed.allowedDecisions.filter((item) => item === "approve" || item === "edit" || item === "reject");
|
|
10
|
+
}
|
|
11
|
+
const decisions = [];
|
|
12
|
+
if (typed.allowAccept !== false)
|
|
13
|
+
decisions.push("approve");
|
|
14
|
+
if (typed.allowEdit !== false)
|
|
15
|
+
decisions.push("edit");
|
|
16
|
+
if (typed.allowReject !== false)
|
|
17
|
+
decisions.push("reject");
|
|
18
|
+
return decisions.length > 0 ? decisions : null;
|
|
19
|
+
}
|
|
20
|
+
export function compileInterruptOn(tools, compatibilityRules) {
|
|
21
|
+
const toolNameMapping = buildToolNameMapping(tools);
|
|
22
|
+
const compiled = new Map();
|
|
23
|
+
for (const [toolName, rule] of Object.entries(compatibilityRules ?? {})) {
|
|
24
|
+
const modelFacingName = toolNameMapping.originalToModelFacing.get(toolName) ?? toolName;
|
|
25
|
+
const allowedDecisions = normalizeInterruptPolicy(rule);
|
|
26
|
+
if (!allowedDecisions) {
|
|
27
|
+
compiled.delete(modelFacingName);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
compiled.set(modelFacingName, { allowedDecisions });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return compiled.size > 0 ? Object.fromEntries(compiled.entries()) : undefined;
|
|
34
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { tools as anthropicProviderTools } from "@langchain/anthropic";
|
|
2
|
+
import { tools as openAIProviderTools } from "@langchain/openai";
|
|
3
|
+
import { asRecord } from "./resolved-tool.js";
|
|
4
|
+
export function instantiateProviderTool(compiledTool) {
|
|
5
|
+
const providerTool = asRecord(compiledTool.config?.providerTool);
|
|
6
|
+
const provider = typeof providerTool?.provider === "string" ? providerTool.provider.trim().toLowerCase() : "";
|
|
7
|
+
const toolName = typeof providerTool?.tool === "string" ? providerTool.tool.trim() : "";
|
|
8
|
+
const args = asRecord(providerTool?.args) ?? {};
|
|
9
|
+
if (!provider || !toolName) {
|
|
10
|
+
throw new Error(`Provider tool ${compiledTool.id} must define providerTool.provider and providerTool.tool`);
|
|
11
|
+
}
|
|
12
|
+
const registry = provider === "openai"
|
|
13
|
+
? openAIProviderTools
|
|
14
|
+
: provider === "anthropic"
|
|
15
|
+
? anthropicProviderTools
|
|
16
|
+
: undefined;
|
|
17
|
+
if (!registry) {
|
|
18
|
+
throw new Error(`Provider tool ${compiledTool.id} uses unsupported provider ${provider}`);
|
|
19
|
+
}
|
|
20
|
+
const factory = registry[toolName];
|
|
21
|
+
if (typeof factory !== "function") {
|
|
22
|
+
throw new Error(`Provider tool ${compiledTool.id} references unknown ${provider} tool ${toolName}`);
|
|
23
|
+
}
|
|
24
|
+
return factory(args);
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export type ResolvedToolLike = {
|
|
3
|
+
name?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
schema?: {
|
|
6
|
+
parse?: (input: unknown) => unknown;
|
|
7
|
+
};
|
|
8
|
+
invoke?: (input: unknown, config?: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
9
|
+
call?: (input: unknown, config?: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
10
|
+
func?: (input: unknown, config?: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
11
|
+
};
|
|
12
|
+
export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
|
|
13
|
+
export declare function wrapResolvedToolWithModelFacingName<T>(resolvedTool: T, modelFacingName: string): T;
|
|
14
|
+
export declare function hasCallableToolHandler(value: unknown): value is ResolvedToolLike;
|
|
15
|
+
export declare function normalizeResolvedToolSchema(resolvedTool: ResolvedToolLike): Record<string, unknown> | {
|
|
16
|
+
parse?: (input: unknown) => unknown;
|
|
17
|
+
} | z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">> | undefined;
|
|
18
|
+
export declare function asStructuredExecutableTool(resolvedTool: unknown, modelFacingName: string, description: string): unknown;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { tool as createLangChainTool } from "@langchain/core/tools";
|
|
3
|
+
export function asRecord(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
5
|
+
? { ...value }
|
|
6
|
+
: undefined;
|
|
7
|
+
}
|
|
8
|
+
export function wrapResolvedToolWithModelFacingName(resolvedTool, modelFacingName) {
|
|
9
|
+
if (typeof resolvedTool !== "object" || resolvedTool === null) {
|
|
10
|
+
return resolvedTool;
|
|
11
|
+
}
|
|
12
|
+
return new Proxy(resolvedTool, {
|
|
13
|
+
get(target, prop, receiver) {
|
|
14
|
+
if (prop === "name") {
|
|
15
|
+
return modelFacingName;
|
|
16
|
+
}
|
|
17
|
+
return Reflect.get(target, prop, receiver);
|
|
18
|
+
},
|
|
19
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
20
|
+
if (prop === "name") {
|
|
21
|
+
return {
|
|
22
|
+
configurable: true,
|
|
23
|
+
enumerable: true,
|
|
24
|
+
writable: false,
|
|
25
|
+
value: modelFacingName,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function hasCallableToolHandler(value) {
|
|
33
|
+
if (typeof value !== "object" || value === null) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const typed = value;
|
|
37
|
+
return typeof typed.invoke === "function" || typeof typed.call === "function" || typeof typed.func === "function";
|
|
38
|
+
}
|
|
39
|
+
export function normalizeResolvedToolSchema(resolvedTool) {
|
|
40
|
+
const schema = resolvedTool.schema;
|
|
41
|
+
if (schema && typeof schema.parse === "function" && "_def" in schema) {
|
|
42
|
+
return resolvedTool.schema;
|
|
43
|
+
}
|
|
44
|
+
if (schema && (schema.type === "object" || typeof schema.properties === "object")) {
|
|
45
|
+
return schema;
|
|
46
|
+
}
|
|
47
|
+
return z.object({}).passthrough();
|
|
48
|
+
}
|
|
49
|
+
export function asStructuredExecutableTool(resolvedTool, modelFacingName, description) {
|
|
50
|
+
if (!hasCallableToolHandler(resolvedTool)) {
|
|
51
|
+
return resolvedTool;
|
|
52
|
+
}
|
|
53
|
+
const handler = resolvedTool.invoke ?? resolvedTool.call ?? resolvedTool.func;
|
|
54
|
+
if (typeof handler !== "function") {
|
|
55
|
+
return resolvedTool;
|
|
56
|
+
}
|
|
57
|
+
return createLangChainTool(async (input, config) => handler(input, config), {
|
|
58
|
+
name: modelFacingName,
|
|
59
|
+
description,
|
|
60
|
+
schema: normalizeResolvedToolSchema(resolvedTool),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function stringifyToolOutput(output: unknown): string;
|
|
2
|
+
export declare function normalizeToolArgsForSchema(args: Record<string, unknown>, schema: unknown): Record<string, unknown>;
|
|
3
|
+
export declare function extractToolCallsFromResult(result: unknown): Array<{
|
|
4
|
+
id?: string;
|
|
5
|
+
name: string;
|
|
6
|
+
args: Record<string, unknown>;
|
|
7
|
+
}>;
|