@providerprotocol/agents 0.0.1 → 0.0.3
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 +333 -6
- package/dist/checkpoint/index.d.ts +43 -0
- package/dist/checkpoint/index.js +64 -0
- package/dist/checkpoint/index.js.map +1 -0
- package/{src/execution/loop.ts → dist/chunk-4ESYN66B.js} +54 -162
- package/dist/chunk-4ESYN66B.js.map +1 -0
- package/dist/chunk-EKRXMSDX.js +8 -0
- package/dist/chunk-EKRXMSDX.js.map +1 -0
- package/dist/chunk-PHI5ULBV.js +427 -0
- package/dist/chunk-PHI5ULBV.js.map +1 -0
- package/dist/execution/index.d.ts +105 -0
- package/dist/execution/index.js +679 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/index-qsPwbY86.d.ts +65 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +218 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/index.d.ts +23 -0
- package/dist/middleware/index.js +82 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/thread-tree/index.d.ts +115 -0
- package/dist/thread-tree/index.js +4 -0
- package/dist/thread-tree/index.js.map +1 -0
- package/dist/types-2Vsthzyu.d.ts +163 -0
- package/dist/types-BhX9uD_d.d.ts +91 -0
- package/dist/types-DR02gtFv.d.ts +270 -0
- package/dist/types-NGQMdnaD.d.ts +65 -0
- package/package.json +40 -8
- package/.claude/settings.local.json +0 -27
- package/AGENTS.md +0 -681
- package/CLAUDE.md +0 -681
- package/bun.lock +0 -472
- package/eslint.config.js +0 -75
- package/index.ts +0 -1
- package/llms.md +0 -796
- package/specs/UAP-1.0.md +0 -2355
- package/src/agent/index.ts +0 -384
- package/src/agent/types.ts +0 -91
- package/src/checkpoint/file.ts +0 -126
- package/src/checkpoint/index.ts +0 -40
- package/src/checkpoint/types.ts +0 -95
- package/src/execution/index.ts +0 -37
- package/src/execution/plan.ts +0 -497
- package/src/execution/react.ts +0 -340
- package/src/execution/tool-ordering.ts +0 -186
- package/src/execution/types.ts +0 -315
- package/src/index.ts +0 -80
- package/src/middleware/index.ts +0 -7
- package/src/middleware/logging.ts +0 -123
- package/src/middleware/types.ts +0 -69
- package/src/state/index.ts +0 -301
- package/src/state/types.ts +0 -173
- package/src/thread-tree/index.ts +0 -249
- package/src/thread-tree/types.ts +0 -29
- package/src/utils/uuid.ts +0 -7
- package/tests/live/agent-anthropic.test.ts +0 -288
- package/tests/live/agent-strategy-hooks.test.ts +0 -268
- package/tests/live/checkpoint.test.ts +0 -243
- package/tests/live/execution-strategies.test.ts +0 -255
- package/tests/live/plan-strategy.test.ts +0 -160
- package/tests/live/subagent-events.live.test.ts +0 -249
- package/tests/live/thread-tree.test.ts +0 -186
- package/tests/unit/agent.test.ts +0 -703
- package/tests/unit/checkpoint.test.ts +0 -232
- package/tests/unit/execution/equivalence.test.ts +0 -402
- package/tests/unit/execution/loop.test.ts +0 -437
- package/tests/unit/execution/plan.test.ts +0 -590
- package/tests/unit/execution/react.test.ts +0 -604
- package/tests/unit/execution/subagent-events.test.ts +0 -235
- package/tests/unit/execution/tool-ordering.test.ts +0 -310
- package/tests/unit/middleware/logging.test.ts +0 -276
- package/tests/unit/state.test.ts +0 -573
- package/tests/unit/thread-tree.test.ts +0 -249
- package/tsconfig.json +0 -29
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
export { loop } from '../chunk-4ESYN66B.js';
|
|
2
|
+
import { generateUUID } from '../chunk-EKRXMSDX.js';
|
|
3
|
+
import { UserMessage } from '@providerprotocol/ai';
|
|
4
|
+
|
|
5
|
+
var DEFAULT_REACT_OPTIONS = {
|
|
6
|
+
maxSteps: Infinity,
|
|
7
|
+
reasoningPrompt: "Think step by step about what you need to do next. Consider the current state, what tools are available, and what action would be most helpful."
|
|
8
|
+
};
|
|
9
|
+
function react(options = {}) {
|
|
10
|
+
const opts = { ...DEFAULT_REACT_OPTIONS, ...options };
|
|
11
|
+
return {
|
|
12
|
+
name: "react",
|
|
13
|
+
async execute(context) {
|
|
14
|
+
const { llm, input, state, strategy, signal } = context;
|
|
15
|
+
let currentState = state.withMessage(input).withMetadata("agentId", context.agent.id);
|
|
16
|
+
let step = 0;
|
|
17
|
+
let finalTurn;
|
|
18
|
+
const messages = [...currentState.messages];
|
|
19
|
+
while (true) {
|
|
20
|
+
step++;
|
|
21
|
+
currentState = currentState.withStep(step);
|
|
22
|
+
if (signal?.aborted) {
|
|
23
|
+
throw new Error("Execution aborted");
|
|
24
|
+
}
|
|
25
|
+
strategy.onStepStart?.(step, currentState);
|
|
26
|
+
const reasoningMessages = [
|
|
27
|
+
...messages,
|
|
28
|
+
new UserMessage(opts.reasoningPrompt)
|
|
29
|
+
];
|
|
30
|
+
const reasoningTurn = await llm.generate(reasoningMessages);
|
|
31
|
+
const reasoning = reasoningTurn.response.text;
|
|
32
|
+
currentState = currentState.withReasoning(reasoning);
|
|
33
|
+
strategy.onReason?.(step, reasoning);
|
|
34
|
+
messages.push(...reasoningTurn.messages);
|
|
35
|
+
const actionPrompt = new UserMessage(
|
|
36
|
+
"Based on your reasoning, take the appropriate action. Use tools if needed, or provide a final answer."
|
|
37
|
+
);
|
|
38
|
+
messages.push(actionPrompt);
|
|
39
|
+
const actionTurn = await llm.generate(messages);
|
|
40
|
+
finalTurn = actionTurn;
|
|
41
|
+
messages.push(...actionTurn.messages);
|
|
42
|
+
currentState = currentState.withMessages(actionTurn.messages);
|
|
43
|
+
if (actionTurn.response.hasToolCalls) {
|
|
44
|
+
strategy.onAct?.(step, actionTurn.response.toolCalls ?? []);
|
|
45
|
+
}
|
|
46
|
+
if (actionTurn.toolExecutions && actionTurn.toolExecutions.length > 0) {
|
|
47
|
+
strategy.onObserve?.(step, actionTurn.toolExecutions);
|
|
48
|
+
}
|
|
49
|
+
strategy.onStepEnd?.(step, { turn: actionTurn, state: currentState });
|
|
50
|
+
const shouldStop = await strategy.stopCondition?.(currentState);
|
|
51
|
+
if (shouldStop) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
if (!actionTurn.response.hasToolCalls) {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
if (opts.maxSteps !== Infinity && step >= opts.maxSteps) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!finalTurn) {
|
|
62
|
+
throw new Error("No turn generated");
|
|
63
|
+
}
|
|
64
|
+
let finalState = currentState;
|
|
65
|
+
if (context.sessionId) {
|
|
66
|
+
finalState = currentState.withMetadata("sessionId", context.sessionId);
|
|
67
|
+
}
|
|
68
|
+
const result = {
|
|
69
|
+
turn: finalTurn,
|
|
70
|
+
state: finalState
|
|
71
|
+
};
|
|
72
|
+
strategy.onComplete?.(result);
|
|
73
|
+
return result;
|
|
74
|
+
},
|
|
75
|
+
stream(context) {
|
|
76
|
+
const { llm, input, state, strategy, signal } = context;
|
|
77
|
+
const agentId = context.agent.id;
|
|
78
|
+
let aborted = false;
|
|
79
|
+
const abortController = new AbortController();
|
|
80
|
+
if (signal) {
|
|
81
|
+
signal.addEventListener("abort", () => abortController.abort());
|
|
82
|
+
}
|
|
83
|
+
let resolveResult;
|
|
84
|
+
let rejectResult;
|
|
85
|
+
const resultPromise = new Promise((resolve, reject) => {
|
|
86
|
+
resolveResult = resolve;
|
|
87
|
+
rejectResult = reject;
|
|
88
|
+
});
|
|
89
|
+
async function* generateEvents() {
|
|
90
|
+
let currentState = state.withMessage(input).withMetadata("agentId", context.agent.id);
|
|
91
|
+
let step = 0;
|
|
92
|
+
let finalTurn;
|
|
93
|
+
const messages = [...currentState.messages];
|
|
94
|
+
try {
|
|
95
|
+
while (!aborted) {
|
|
96
|
+
step++;
|
|
97
|
+
currentState = currentState.withStep(step);
|
|
98
|
+
if (abortController.signal.aborted) {
|
|
99
|
+
throw new Error("Execution aborted");
|
|
100
|
+
}
|
|
101
|
+
strategy.onStepStart?.(step, currentState);
|
|
102
|
+
yield {
|
|
103
|
+
source: "uap",
|
|
104
|
+
uap: {
|
|
105
|
+
type: "step_start",
|
|
106
|
+
step,
|
|
107
|
+
agentId,
|
|
108
|
+
data: { phase: "reasoning" }
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const reasoningMessages = [
|
|
112
|
+
...messages,
|
|
113
|
+
new UserMessage(opts.reasoningPrompt)
|
|
114
|
+
];
|
|
115
|
+
const reasoningStream = llm.stream(reasoningMessages);
|
|
116
|
+
let reasoningText = "";
|
|
117
|
+
for await (const event of reasoningStream) {
|
|
118
|
+
if (abortController.signal.aborted) {
|
|
119
|
+
throw new Error("Execution aborted");
|
|
120
|
+
}
|
|
121
|
+
yield { source: "upp", upp: event };
|
|
122
|
+
if (event.type === "text_delta" && event.delta.text) {
|
|
123
|
+
reasoningText += event.delta.text;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const reasoningTurn = await reasoningStream.turn;
|
|
127
|
+
currentState = currentState.withReasoning(reasoningText || reasoningTurn.response.text);
|
|
128
|
+
strategy.onReason?.(step, reasoningText || reasoningTurn.response.text);
|
|
129
|
+
yield {
|
|
130
|
+
source: "uap",
|
|
131
|
+
uap: {
|
|
132
|
+
type: "reasoning",
|
|
133
|
+
step,
|
|
134
|
+
agentId,
|
|
135
|
+
data: { reasoning: reasoningText || reasoningTurn.response.text }
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
messages.push(...reasoningTurn.messages);
|
|
139
|
+
const actionPrompt = new UserMessage(
|
|
140
|
+
"Based on your reasoning, take the appropriate action. Use tools if needed, or provide a final answer."
|
|
141
|
+
);
|
|
142
|
+
messages.push(actionPrompt);
|
|
143
|
+
const actionStream = llm.stream(messages);
|
|
144
|
+
for await (const event of actionStream) {
|
|
145
|
+
if (abortController.signal.aborted) {
|
|
146
|
+
throw new Error("Execution aborted");
|
|
147
|
+
}
|
|
148
|
+
yield { source: "upp", upp: event };
|
|
149
|
+
}
|
|
150
|
+
const actionTurn = await actionStream.turn;
|
|
151
|
+
finalTurn = actionTurn;
|
|
152
|
+
messages.push(...actionTurn.messages);
|
|
153
|
+
currentState = currentState.withMessages(actionTurn.messages);
|
|
154
|
+
if (actionTurn.response.hasToolCalls) {
|
|
155
|
+
strategy.onAct?.(step, actionTurn.response.toolCalls ?? []);
|
|
156
|
+
yield {
|
|
157
|
+
source: "uap",
|
|
158
|
+
uap: {
|
|
159
|
+
type: "action",
|
|
160
|
+
step,
|
|
161
|
+
agentId,
|
|
162
|
+
data: { toolCalls: actionTurn.response.toolCalls }
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (actionTurn.toolExecutions && actionTurn.toolExecutions.length > 0) {
|
|
167
|
+
strategy.onObserve?.(step, actionTurn.toolExecutions);
|
|
168
|
+
yield {
|
|
169
|
+
source: "uap",
|
|
170
|
+
uap: {
|
|
171
|
+
type: "observation",
|
|
172
|
+
step,
|
|
173
|
+
agentId,
|
|
174
|
+
data: { observations: actionTurn.toolExecutions }
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
strategy.onStepEnd?.(step, { turn: actionTurn, state: currentState });
|
|
179
|
+
yield {
|
|
180
|
+
source: "uap",
|
|
181
|
+
uap: {
|
|
182
|
+
type: "step_end",
|
|
183
|
+
step,
|
|
184
|
+
agentId,
|
|
185
|
+
data: { phase: "complete" }
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const shouldStop = await strategy.stopCondition?.(currentState);
|
|
189
|
+
if (shouldStop) {
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
if (!actionTurn.response.hasToolCalls) {
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
if (opts.maxSteps !== Infinity && step >= opts.maxSteps) {
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (!finalTurn) {
|
|
200
|
+
throw new Error("No turn generated");
|
|
201
|
+
}
|
|
202
|
+
let finalState = currentState;
|
|
203
|
+
if (context.sessionId) {
|
|
204
|
+
finalState = currentState.withMetadata("sessionId", context.sessionId);
|
|
205
|
+
}
|
|
206
|
+
const result = {
|
|
207
|
+
turn: finalTurn,
|
|
208
|
+
state: finalState
|
|
209
|
+
};
|
|
210
|
+
strategy.onComplete?.(result);
|
|
211
|
+
resolveResult(result);
|
|
212
|
+
} catch (error) {
|
|
213
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
214
|
+
strategy.onError?.(err, currentState);
|
|
215
|
+
rejectResult(err);
|
|
216
|
+
throw err;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const iterator = generateEvents();
|
|
220
|
+
return {
|
|
221
|
+
[Symbol.asyncIterator]() {
|
|
222
|
+
return iterator;
|
|
223
|
+
},
|
|
224
|
+
result: resultPromise,
|
|
225
|
+
abort() {
|
|
226
|
+
aborted = true;
|
|
227
|
+
abortController.abort();
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
var DEFAULT_PLAN_OPTIONS = {
|
|
234
|
+
maxPlanSteps: Infinity,
|
|
235
|
+
allowReplan: true,
|
|
236
|
+
planSchema: {
|
|
237
|
+
type: "object",
|
|
238
|
+
properties: {
|
|
239
|
+
steps: {
|
|
240
|
+
type: "array",
|
|
241
|
+
items: {
|
|
242
|
+
type: "object",
|
|
243
|
+
properties: {
|
|
244
|
+
id: { type: "string", description: "Unique step identifier" },
|
|
245
|
+
description: { type: "string", description: "What this step does" },
|
|
246
|
+
tool: { type: "string", description: "Tool to use (if applicable)" },
|
|
247
|
+
dependsOn: {
|
|
248
|
+
type: "array",
|
|
249
|
+
items: { type: "string" },
|
|
250
|
+
description: "IDs of steps this depends on"
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
required: ["id", "description", "dependsOn"]
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
required: ["steps"]
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
var PLAN_PROMPT = `Create a detailed execution plan to accomplish the task.
|
|
261
|
+
Break it down into clear steps, specifying which tool to use for each step if applicable.
|
|
262
|
+
Include dependencies between steps (which steps must complete before others can start).
|
|
263
|
+
Return your plan as a JSON object with a "steps" array.`;
|
|
264
|
+
function plan(options = {}) {
|
|
265
|
+
const opts = { ...DEFAULT_PLAN_OPTIONS, ...options };
|
|
266
|
+
return {
|
|
267
|
+
name: "plan",
|
|
268
|
+
async execute(context) {
|
|
269
|
+
const { llm, input, state, strategy, signal } = context;
|
|
270
|
+
let currentState = state.withMessage(input).withMetadata("agentId", context.agent.id);
|
|
271
|
+
let step = 0;
|
|
272
|
+
let finalTurn;
|
|
273
|
+
const messages = [...currentState.messages];
|
|
274
|
+
step++;
|
|
275
|
+
currentState = currentState.withStep(step);
|
|
276
|
+
if (signal?.aborted) {
|
|
277
|
+
throw new Error("Execution aborted");
|
|
278
|
+
}
|
|
279
|
+
strategy.onStepStart?.(step, currentState);
|
|
280
|
+
const planMessages = [
|
|
281
|
+
...messages,
|
|
282
|
+
new UserMessage(PLAN_PROMPT)
|
|
283
|
+
];
|
|
284
|
+
const planTurn = await llm.generate(planMessages);
|
|
285
|
+
let planData;
|
|
286
|
+
try {
|
|
287
|
+
if (planTurn.data) {
|
|
288
|
+
planData = planTurn.data;
|
|
289
|
+
} else {
|
|
290
|
+
const jsonMatch = planTurn.response.text.match(/\{[\s\S]*\}/);
|
|
291
|
+
if (jsonMatch) {
|
|
292
|
+
planData = JSON.parse(jsonMatch[0]);
|
|
293
|
+
} else {
|
|
294
|
+
throw new Error("Could not parse plan from response");
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
} catch (err) {
|
|
298
|
+
throw new Error(`Failed to parse execution plan: ${err instanceof Error ? err.message : String(err)}`);
|
|
299
|
+
}
|
|
300
|
+
let planSteps = planData.steps.map((s) => ({
|
|
301
|
+
id: s.id || generateUUID(),
|
|
302
|
+
description: s.description,
|
|
303
|
+
tool: s.tool,
|
|
304
|
+
dependsOn: s.dependsOn || [],
|
|
305
|
+
status: "pending"
|
|
306
|
+
}));
|
|
307
|
+
if (opts.maxPlanSteps !== Infinity && planSteps.length > opts.maxPlanSteps) {
|
|
308
|
+
planSteps = planSteps.slice(0, opts.maxPlanSteps);
|
|
309
|
+
}
|
|
310
|
+
currentState = currentState.withPlan(planSteps);
|
|
311
|
+
messages.push(...planTurn.messages);
|
|
312
|
+
strategy.onStepEnd?.(step, { turn: planTurn, state: currentState });
|
|
313
|
+
const completedSteps = /* @__PURE__ */ new Set();
|
|
314
|
+
while (planSteps.some((s) => s.status === "pending")) {
|
|
315
|
+
const nextStep = planSteps.find(
|
|
316
|
+
(s) => s.status === "pending" && s.dependsOn.every((depId) => completedSteps.has(depId))
|
|
317
|
+
);
|
|
318
|
+
if (!nextStep) {
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
step++;
|
|
322
|
+
currentState = currentState.withStep(step);
|
|
323
|
+
if (signal?.aborted) {
|
|
324
|
+
throw new Error("Execution aborted");
|
|
325
|
+
}
|
|
326
|
+
strategy.onStepStart?.(step, currentState);
|
|
327
|
+
nextStep.status = "in_progress";
|
|
328
|
+
currentState = currentState.withPlan([...planSteps]);
|
|
329
|
+
const stepPrompt = new UserMessage(
|
|
330
|
+
`Execute step "${nextStep.id}": ${nextStep.description}${nextStep.tool ? ` using the ${nextStep.tool} tool` : ""}`
|
|
331
|
+
);
|
|
332
|
+
messages.push(stepPrompt);
|
|
333
|
+
try {
|
|
334
|
+
const stepTurn = await llm.generate(messages);
|
|
335
|
+
finalTurn = stepTurn;
|
|
336
|
+
messages.push(...stepTurn.messages);
|
|
337
|
+
currentState = currentState.withMessages(stepTurn.messages);
|
|
338
|
+
if (stepTurn.response.hasToolCalls) {
|
|
339
|
+
strategy.onAct?.(step, stepTurn.response.toolCalls ?? []);
|
|
340
|
+
}
|
|
341
|
+
if (stepTurn.toolExecutions && stepTurn.toolExecutions.length > 0) {
|
|
342
|
+
strategy.onObserve?.(step, stepTurn.toolExecutions);
|
|
343
|
+
}
|
|
344
|
+
nextStep.status = "completed";
|
|
345
|
+
completedSteps.add(nextStep.id);
|
|
346
|
+
currentState = currentState.withPlan([...planSteps]);
|
|
347
|
+
strategy.onStepEnd?.(step, { turn: stepTurn, state: currentState });
|
|
348
|
+
} catch (err) {
|
|
349
|
+
nextStep.status = "failed";
|
|
350
|
+
currentState = currentState.withPlan([...planSteps]);
|
|
351
|
+
throw err;
|
|
352
|
+
}
|
|
353
|
+
const shouldStop = await strategy.stopCondition?.(currentState);
|
|
354
|
+
if (shouldStop) {
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (!finalTurn) {
|
|
359
|
+
finalTurn = planTurn;
|
|
360
|
+
}
|
|
361
|
+
let finalState = currentState;
|
|
362
|
+
if (context.sessionId) {
|
|
363
|
+
finalState = currentState.withMetadata("sessionId", context.sessionId);
|
|
364
|
+
}
|
|
365
|
+
const result = {
|
|
366
|
+
turn: finalTurn,
|
|
367
|
+
state: finalState
|
|
368
|
+
};
|
|
369
|
+
strategy.onComplete?.(result);
|
|
370
|
+
return result;
|
|
371
|
+
},
|
|
372
|
+
stream(context) {
|
|
373
|
+
const { llm, input, state, strategy, signal } = context;
|
|
374
|
+
const agentId = context.agent.id;
|
|
375
|
+
let aborted = false;
|
|
376
|
+
const abortController = new AbortController();
|
|
377
|
+
if (signal) {
|
|
378
|
+
signal.addEventListener("abort", () => abortController.abort());
|
|
379
|
+
}
|
|
380
|
+
let resolveResult;
|
|
381
|
+
let rejectResult;
|
|
382
|
+
const resultPromise = new Promise((resolve, reject) => {
|
|
383
|
+
resolveResult = resolve;
|
|
384
|
+
rejectResult = reject;
|
|
385
|
+
});
|
|
386
|
+
async function* generateEvents() {
|
|
387
|
+
let currentState = state.withMessage(input).withMetadata("agentId", context.agent.id);
|
|
388
|
+
let step = 0;
|
|
389
|
+
let finalTurn;
|
|
390
|
+
const messages = [...currentState.messages];
|
|
391
|
+
try {
|
|
392
|
+
step++;
|
|
393
|
+
currentState = currentState.withStep(step);
|
|
394
|
+
if (abortController.signal.aborted) {
|
|
395
|
+
throw new Error("Execution aborted");
|
|
396
|
+
}
|
|
397
|
+
strategy.onStepStart?.(step, currentState);
|
|
398
|
+
yield {
|
|
399
|
+
source: "uap",
|
|
400
|
+
uap: {
|
|
401
|
+
type: "step_start",
|
|
402
|
+
step,
|
|
403
|
+
agentId,
|
|
404
|
+
data: { phase: "planning" }
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const planMessages = [
|
|
408
|
+
...messages,
|
|
409
|
+
new UserMessage(PLAN_PROMPT)
|
|
410
|
+
];
|
|
411
|
+
const planStream = llm.stream(planMessages);
|
|
412
|
+
for await (const event of planStream) {
|
|
413
|
+
if (abortController.signal.aborted) {
|
|
414
|
+
throw new Error("Execution aborted");
|
|
415
|
+
}
|
|
416
|
+
yield { source: "upp", upp: event };
|
|
417
|
+
}
|
|
418
|
+
const planTurn = await planStream.turn;
|
|
419
|
+
let planData;
|
|
420
|
+
try {
|
|
421
|
+
if (planTurn.data) {
|
|
422
|
+
planData = planTurn.data;
|
|
423
|
+
} else {
|
|
424
|
+
const jsonMatch = planTurn.response.text.match(/\{[\s\S]*\}/);
|
|
425
|
+
if (jsonMatch) {
|
|
426
|
+
planData = JSON.parse(jsonMatch[0]);
|
|
427
|
+
} else {
|
|
428
|
+
throw new Error("Could not parse plan from response");
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
} catch (err) {
|
|
432
|
+
throw new Error(`Failed to parse execution plan: ${err instanceof Error ? err.message : String(err)}`);
|
|
433
|
+
}
|
|
434
|
+
let planSteps = planData.steps.map((s) => ({
|
|
435
|
+
id: s.id || generateUUID(),
|
|
436
|
+
description: s.description,
|
|
437
|
+
tool: s.tool,
|
|
438
|
+
dependsOn: s.dependsOn || [],
|
|
439
|
+
status: "pending"
|
|
440
|
+
}));
|
|
441
|
+
if (opts.maxPlanSteps !== Infinity && planSteps.length > opts.maxPlanSteps) {
|
|
442
|
+
planSteps = planSteps.slice(0, opts.maxPlanSteps);
|
|
443
|
+
}
|
|
444
|
+
currentState = currentState.withPlan(planSteps);
|
|
445
|
+
messages.push(...planTurn.messages);
|
|
446
|
+
yield {
|
|
447
|
+
source: "uap",
|
|
448
|
+
uap: {
|
|
449
|
+
type: "plan_created",
|
|
450
|
+
step,
|
|
451
|
+
agentId,
|
|
452
|
+
data: { plan: planSteps }
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
strategy.onStepEnd?.(step, { turn: planTurn, state: currentState });
|
|
456
|
+
yield {
|
|
457
|
+
source: "uap",
|
|
458
|
+
uap: {
|
|
459
|
+
type: "step_end",
|
|
460
|
+
step,
|
|
461
|
+
agentId,
|
|
462
|
+
data: { phase: "planning" }
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
const completedSteps = /* @__PURE__ */ new Set();
|
|
466
|
+
while (planSteps.some((s) => s.status === "pending") && !aborted) {
|
|
467
|
+
const nextStep = planSteps.find(
|
|
468
|
+
(s) => s.status === "pending" && s.dependsOn.every((depId) => completedSteps.has(depId))
|
|
469
|
+
);
|
|
470
|
+
if (!nextStep) {
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
step++;
|
|
474
|
+
currentState = currentState.withStep(step);
|
|
475
|
+
if (abortController.signal.aborted) {
|
|
476
|
+
throw new Error("Execution aborted");
|
|
477
|
+
}
|
|
478
|
+
strategy.onStepStart?.(step, currentState);
|
|
479
|
+
yield {
|
|
480
|
+
source: "uap",
|
|
481
|
+
uap: {
|
|
482
|
+
type: "plan_step_start",
|
|
483
|
+
step,
|
|
484
|
+
agentId,
|
|
485
|
+
data: { planStep: nextStep }
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
nextStep.status = "in_progress";
|
|
489
|
+
currentState = currentState.withPlan([...planSteps]);
|
|
490
|
+
const stepPrompt = new UserMessage(
|
|
491
|
+
`Execute step "${nextStep.id}": ${nextStep.description}${nextStep.tool ? ` using the ${nextStep.tool} tool` : ""}`
|
|
492
|
+
);
|
|
493
|
+
messages.push(stepPrompt);
|
|
494
|
+
const stepStream = llm.stream(messages);
|
|
495
|
+
for await (const event of stepStream) {
|
|
496
|
+
if (abortController.signal.aborted) {
|
|
497
|
+
throw new Error("Execution aborted");
|
|
498
|
+
}
|
|
499
|
+
yield { source: "upp", upp: event };
|
|
500
|
+
}
|
|
501
|
+
const stepTurn = await stepStream.turn;
|
|
502
|
+
finalTurn = stepTurn;
|
|
503
|
+
messages.push(...stepTurn.messages);
|
|
504
|
+
currentState = currentState.withMessages(stepTurn.messages);
|
|
505
|
+
if (stepTurn.response.hasToolCalls) {
|
|
506
|
+
strategy.onAct?.(step, stepTurn.response.toolCalls ?? []);
|
|
507
|
+
yield {
|
|
508
|
+
source: "uap",
|
|
509
|
+
uap: {
|
|
510
|
+
type: "action",
|
|
511
|
+
step,
|
|
512
|
+
agentId,
|
|
513
|
+
data: { toolCalls: stepTurn.response.toolCalls }
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
if (stepTurn.toolExecutions && stepTurn.toolExecutions.length > 0) {
|
|
518
|
+
strategy.onObserve?.(step, stepTurn.toolExecutions);
|
|
519
|
+
yield {
|
|
520
|
+
source: "uap",
|
|
521
|
+
uap: {
|
|
522
|
+
type: "observation",
|
|
523
|
+
step,
|
|
524
|
+
agentId,
|
|
525
|
+
data: { observations: stepTurn.toolExecutions }
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
nextStep.status = "completed";
|
|
530
|
+
completedSteps.add(nextStep.id);
|
|
531
|
+
currentState = currentState.withPlan([...planSteps]);
|
|
532
|
+
strategy.onStepEnd?.(step, { turn: stepTurn, state: currentState });
|
|
533
|
+
yield {
|
|
534
|
+
source: "uap",
|
|
535
|
+
uap: {
|
|
536
|
+
type: "plan_step_end",
|
|
537
|
+
step,
|
|
538
|
+
agentId,
|
|
539
|
+
data: { planStep: nextStep }
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
const shouldStop = await strategy.stopCondition?.(currentState);
|
|
543
|
+
if (shouldStop) {
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (!finalTurn) {
|
|
548
|
+
finalTurn = planTurn;
|
|
549
|
+
}
|
|
550
|
+
let finalState = currentState;
|
|
551
|
+
if (context.sessionId) {
|
|
552
|
+
finalState = currentState.withMetadata("sessionId", context.sessionId);
|
|
553
|
+
}
|
|
554
|
+
const result = {
|
|
555
|
+
turn: finalTurn,
|
|
556
|
+
state: finalState
|
|
557
|
+
};
|
|
558
|
+
strategy.onComplete?.(result);
|
|
559
|
+
resolveResult(result);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
562
|
+
strategy.onError?.(err, currentState);
|
|
563
|
+
rejectResult(err);
|
|
564
|
+
throw err;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const iterator = generateEvents();
|
|
568
|
+
return {
|
|
569
|
+
[Symbol.asyncIterator]() {
|
|
570
|
+
return iterator;
|
|
571
|
+
},
|
|
572
|
+
result: resultPromise,
|
|
573
|
+
abort() {
|
|
574
|
+
aborted = true;
|
|
575
|
+
abortController.abort();
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// src/execution/tool-ordering.ts
|
|
583
|
+
function buildToolMap(tools) {
|
|
584
|
+
const map = /* @__PURE__ */ new Map();
|
|
585
|
+
for (const tool of tools) {
|
|
586
|
+
map.set(tool.name, tool);
|
|
587
|
+
}
|
|
588
|
+
return map;
|
|
589
|
+
}
|
|
590
|
+
function getModelDependencies(call) {
|
|
591
|
+
const orderedCall = call;
|
|
592
|
+
return orderedCall.after ?? [];
|
|
593
|
+
}
|
|
594
|
+
function orderToolCalls(toolCalls, tools) {
|
|
595
|
+
if (toolCalls.length === 0) {
|
|
596
|
+
return [];
|
|
597
|
+
}
|
|
598
|
+
const toolMap = buildToolMap(tools);
|
|
599
|
+
const groups = [];
|
|
600
|
+
const completedCallIds = /* @__PURE__ */ new Set();
|
|
601
|
+
const completedToolNames = /* @__PURE__ */ new Set();
|
|
602
|
+
const pending = [...toolCalls];
|
|
603
|
+
while (pending.length > 0) {
|
|
604
|
+
const readyForExecution = [];
|
|
605
|
+
let hasSequential = false;
|
|
606
|
+
const stillPending = [];
|
|
607
|
+
for (const call of pending) {
|
|
608
|
+
const tool = toolMap.get(call.toolName);
|
|
609
|
+
const toolDependsOn = tool?.dependsOn ?? [];
|
|
610
|
+
const modelDependsOn = getModelDependencies(call);
|
|
611
|
+
const toolDepsOk = toolDependsOn.every(
|
|
612
|
+
(depName) => completedToolNames.has(depName)
|
|
613
|
+
);
|
|
614
|
+
const modelDepsOk = modelDependsOn.every(
|
|
615
|
+
(depId) => completedCallIds.has(depId)
|
|
616
|
+
);
|
|
617
|
+
if (toolDepsOk && modelDepsOk) {
|
|
618
|
+
readyForExecution.push(call);
|
|
619
|
+
if (tool?.sequential) {
|
|
620
|
+
hasSequential = true;
|
|
621
|
+
}
|
|
622
|
+
} else {
|
|
623
|
+
stillPending.push(call);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (readyForExecution.length === 0 && stillPending.length > 0) {
|
|
627
|
+
groups.push({
|
|
628
|
+
calls: stillPending,
|
|
629
|
+
isBarrier: false
|
|
630
|
+
});
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
633
|
+
if (hasSequential) {
|
|
634
|
+
for (const call of readyForExecution) {
|
|
635
|
+
const tool = toolMap.get(call.toolName);
|
|
636
|
+
groups.push({
|
|
637
|
+
calls: [call],
|
|
638
|
+
isBarrier: tool?.sequential ?? false
|
|
639
|
+
});
|
|
640
|
+
completedCallIds.add(call.toolCallId);
|
|
641
|
+
completedToolNames.add(call.toolName);
|
|
642
|
+
}
|
|
643
|
+
} else {
|
|
644
|
+
groups.push({
|
|
645
|
+
calls: readyForExecution,
|
|
646
|
+
isBarrier: false
|
|
647
|
+
});
|
|
648
|
+
for (const call of readyForExecution) {
|
|
649
|
+
completedCallIds.add(call.toolCallId);
|
|
650
|
+
completedToolNames.add(call.toolName);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
pending.length = 0;
|
|
654
|
+
pending.push(...stillPending);
|
|
655
|
+
}
|
|
656
|
+
return groups;
|
|
657
|
+
}
|
|
658
|
+
function hasToolDependencies(tools) {
|
|
659
|
+
for (const tool of tools) {
|
|
660
|
+
const t = tool;
|
|
661
|
+
if (t.sequential || t.dependsOn && t.dependsOn.length > 0) {
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
function hasCallDependencies(toolCalls) {
|
|
668
|
+
for (const call of toolCalls) {
|
|
669
|
+
const ordered = call;
|
|
670
|
+
if (ordered.after && ordered.after.length > 0) {
|
|
671
|
+
return true;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return false;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
export { hasCallDependencies, hasToolDependencies, orderToolCalls, plan, react };
|
|
678
|
+
//# sourceMappingURL=index.js.map
|
|
679
|
+
//# sourceMappingURL=index.js.map
|