@statelyai/agent 1.1.6 → 2.0.0-next.1
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/.changeset/cyan-carpets-perform.md +5 -0
- package/.changeset/fast-donkeys-argue.md +5 -0
- package/.changeset/light-hats-drive.md +9 -0
- package/.changeset/old-jobs-check.md +5 -0
- package/.changeset/pre.json +13 -0
- package/.vscode/launch.json +6 -0
- package/CHANGELOG.md +22 -0
- package/dist/index.d.mts +262 -171
- package/dist/index.d.ts +262 -171
- package/dist/index.js +383 -274
- package/dist/index.mjs +386 -272
- package/examples/chatbot-alt.ts +57 -0
- package/examples/chatbot.ts +12 -17
- package/examples/cot.ts +26 -23
- package/examples/customer-service-sim.ts +107 -0
- package/examples/email.ts +37 -41
- package/examples/example.ts +6 -6
- package/examples/executor.ts +66 -0
- package/examples/goal.ts +12 -12
- package/examples/helpers/helpers.ts +26 -14
- package/examples/joke.ts +79 -76
- package/examples/jugs.ts +125 -0
- package/examples/multi.ts +5 -5
- package/examples/newspaper.ts +98 -104
- package/examples/number.ts +6 -5
- package/examples/raffle.ts +11 -12
- package/examples/river-crossing.ts +140 -0
- package/examples/sandbox.ts +1 -1
- package/examples/simple.ts +5 -3
- package/examples/summary.ts +121 -0
- package/examples/support.ts +6 -6
- package/examples/ticTacToe.ts +86 -45
- package/examples/todo.ts +7 -7
- package/examples/tutor.ts +15 -15
- package/examples/verify.ts +3 -3
- package/examples/weather.ts +6 -9
- package/examples/wiki.ts +27 -8
- package/examples/word.ts +16 -11
- package/package.json +16 -11
- package/readme.md +1 -1
- package/src/agent-experimental.ts +1 -1
- package/src/agent.test.ts +243 -214
- package/src/agent.ts +286 -95
- package/src/decide.test.ts +276 -0
- package/src/decide.ts +163 -0
- package/src/index.ts +1 -1
- package/src/middleware.ts +91 -0
- package/src/mockModel.ts +47 -0
- package/src/planners/shortestPath.test.ts +94 -0
- package/src/planners/shortestPath.ts +177 -0
- package/src/planners/simple.ts +105 -0
- package/src/strategies/chain-of-note.ts +6 -55
- package/src/text.ts +51 -144
- package/src/types.ts +187 -212
- package/src/utils.ts +48 -4
- package/vitest.config.ts +9 -3
- package/src/adapters/vercel.ts +0 -7
- package/src/decision.test.ts +0 -179
- package/src/decision.ts +0 -84
- package/src/memory.ts +0 -25
- package/src/planners/shortestPathPlanner.ts +0 -22
- package/src/planners/simplePlanner.ts +0 -139
package/dist/index.js
CHANGED
|
@@ -38,10 +38,10 @@ __export(src_exports, {
|
|
|
38
38
|
module.exports = __toCommonJS(src_exports);
|
|
39
39
|
|
|
40
40
|
// src/agent.ts
|
|
41
|
-
var
|
|
41
|
+
var import_xstate4 = require("xstate");
|
|
42
42
|
|
|
43
|
-
// src/planners/
|
|
44
|
-
var
|
|
43
|
+
// src/planners/simple.ts
|
|
44
|
+
var import_ai3 = require("ai");
|
|
45
45
|
|
|
46
46
|
// src/utils.ts
|
|
47
47
|
var import_object_hash = __toESM(require("object-hash"));
|
|
@@ -79,10 +79,10 @@ function getAllMachineTransitions(stateNode) {
|
|
|
79
79
|
function wrapInXml(tagName, content) {
|
|
80
80
|
return `<${tagName}>${content}</${tagName}>`;
|
|
81
81
|
}
|
|
82
|
-
function randomId() {
|
|
82
|
+
function randomId(prefix) {
|
|
83
83
|
const timestamp = Date.now().toString(36);
|
|
84
84
|
const random = Math.random().toString(36).substring(2, 9);
|
|
85
|
-
return
|
|
85
|
+
return `${prefix || ""}${timestamp}${random}`;
|
|
86
86
|
}
|
|
87
87
|
var machineHashes = /* @__PURE__ */ new WeakMap();
|
|
88
88
|
function getMachineHash(machine) {
|
|
@@ -92,6 +92,26 @@ function getMachineHash(machine) {
|
|
|
92
92
|
machineHashes.set(machine, machineHash);
|
|
93
93
|
return machineHash;
|
|
94
94
|
}
|
|
95
|
+
function isActorRef(actorRefLike) {
|
|
96
|
+
return "src" in actorRefLike && "system" in actorRefLike && "sessionId" in actorRefLike;
|
|
97
|
+
}
|
|
98
|
+
function getTransitions(state, machine) {
|
|
99
|
+
if (!machine) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const resolvedState = machine.resolveState({
|
|
103
|
+
...state,
|
|
104
|
+
// Need this property defined to make TS happy
|
|
105
|
+
context: state.context
|
|
106
|
+
});
|
|
107
|
+
return getAllTransitions(resolvedState);
|
|
108
|
+
}
|
|
109
|
+
function isMachineActor(actor) {
|
|
110
|
+
return "src" in actor && typeof actor.src === "object" && actor.src !== null && "definition" in actor.src;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/planners/simple.ts
|
|
114
|
+
var import_xstate3 = require("xstate");
|
|
95
115
|
|
|
96
116
|
// src/templates/defaultText.ts
|
|
97
117
|
var defaultTextTemplate = (data) => {
|
|
@@ -106,6 +126,7 @@ ${data.goal}
|
|
|
106
126
|
};
|
|
107
127
|
|
|
108
128
|
// src/text.ts
|
|
129
|
+
var import_ai = require("ai");
|
|
109
130
|
var import_xstate = require("xstate");
|
|
110
131
|
async function getMessages(agent, prompt, options) {
|
|
111
132
|
let messages = [];
|
|
@@ -120,120 +141,26 @@ async function getMessages(agent, prompt, options) {
|
|
|
120
141
|
});
|
|
121
142
|
return messages;
|
|
122
143
|
}
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
...agent.defaultOptions,
|
|
126
|
-
...options,
|
|
127
|
-
correlationId: options.correlationId ?? randomId()
|
|
128
|
-
};
|
|
129
|
-
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
130
|
-
const id = randomId();
|
|
131
|
-
const goal = typeof resolvedOptions.prompt === "string" ? resolvedOptions.prompt : await resolvedOptions.prompt(agent);
|
|
132
|
-
const promptWithContext = template({
|
|
133
|
-
goal,
|
|
134
|
-
context: resolvedOptions.context
|
|
135
|
-
});
|
|
136
|
-
const messages = await getMessages(agent, promptWithContext, resolvedOptions);
|
|
137
|
-
agent.addMessage({
|
|
138
|
-
id,
|
|
139
|
-
role: "user",
|
|
140
|
-
content: promptWithContext,
|
|
141
|
-
timestamp: Date.now(),
|
|
142
|
-
correlationId: resolvedOptions.correlationId,
|
|
143
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
144
|
-
});
|
|
145
|
-
const result = await agent.adapter.generateText({
|
|
146
|
-
...resolvedOptions,
|
|
147
|
-
prompt: void 0,
|
|
148
|
-
messages
|
|
149
|
-
});
|
|
150
|
-
agent.addMessage({
|
|
151
|
-
content: result.text,
|
|
152
|
-
id,
|
|
153
|
-
role: "assistant",
|
|
154
|
-
timestamp: Date.now(),
|
|
155
|
-
responseId: id,
|
|
156
|
-
result,
|
|
157
|
-
correlationId: resolvedOptions.correlationId,
|
|
158
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
159
|
-
});
|
|
160
|
-
return {
|
|
161
|
-
...result,
|
|
162
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
163
|
-
correlationId: resolvedOptions.correlationId
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
async function agentStreamText(agent, options) {
|
|
167
|
-
const resolvedOptions = {
|
|
168
|
-
...agent.defaultOptions,
|
|
169
|
-
...options,
|
|
170
|
-
correlationId: options.correlationId ?? randomId()
|
|
171
|
-
};
|
|
172
|
-
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
173
|
-
const id = randomId();
|
|
174
|
-
const goal = typeof resolvedOptions.prompt === "string" ? resolvedOptions.prompt : await resolvedOptions.prompt(agent);
|
|
175
|
-
const promptWithContext = template({
|
|
176
|
-
goal,
|
|
177
|
-
context: resolvedOptions.context
|
|
178
|
-
});
|
|
179
|
-
const messages = await getMessages(agent, promptWithContext, resolvedOptions);
|
|
180
|
-
agent.addMessage({
|
|
181
|
-
role: "user",
|
|
182
|
-
content: promptWithContext,
|
|
183
|
-
id,
|
|
184
|
-
timestamp: Date.now(),
|
|
185
|
-
correlationId: resolvedOptions.correlationId,
|
|
186
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
187
|
-
});
|
|
188
|
-
const result = await agent.adapter.streamText({
|
|
189
|
-
...resolvedOptions,
|
|
190
|
-
prompt: void 0,
|
|
191
|
-
messages,
|
|
192
|
-
onFinish: async (res) => {
|
|
193
|
-
agent.addMessage({
|
|
194
|
-
role: "assistant",
|
|
195
|
-
result: {
|
|
196
|
-
text: res.text,
|
|
197
|
-
finishReason: res.finishReason,
|
|
198
|
-
logprobs: void 0,
|
|
199
|
-
responseMessages: [],
|
|
200
|
-
toolCalls: [],
|
|
201
|
-
toolResults: [],
|
|
202
|
-
usage: res.usage,
|
|
203
|
-
warnings: res.warnings,
|
|
204
|
-
rawResponse: res.rawResponse,
|
|
205
|
-
roundtrips: [],
|
|
206
|
-
// TODO: how do we get this information?,
|
|
207
|
-
steps: res.steps,
|
|
208
|
-
response: res.response,
|
|
209
|
-
experimental_providerMetadata: res.experimental_providerMetadata
|
|
210
|
-
},
|
|
211
|
-
content: res.text,
|
|
212
|
-
id: randomId(),
|
|
213
|
-
timestamp: Date.now(),
|
|
214
|
-
responseId: id,
|
|
215
|
-
correlationId: resolvedOptions.correlationId,
|
|
216
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
return {
|
|
221
|
-
...result,
|
|
222
|
-
textStream: result.textStream,
|
|
223
|
-
fullStream: result.fullStream,
|
|
224
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
225
|
-
correlationId: resolvedOptions.correlationId
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
function fromTextStream(agent, defaultOptions) {
|
|
144
|
+
function fromTextStream(agent, options) {
|
|
145
|
+
const template = options?.template ?? defaultTextTemplate;
|
|
229
146
|
return (0, import_xstate.fromObservable)(({ input }) => {
|
|
230
147
|
const observers = /* @__PURE__ */ new Set();
|
|
231
148
|
(async () => {
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
149
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
150
|
+
const goal = typeof input.prompt === "string" ? input.prompt : await input.prompt(agent);
|
|
151
|
+
const promptWithContext = template({
|
|
152
|
+
goal,
|
|
235
153
|
context: input.context
|
|
236
154
|
});
|
|
155
|
+
const messages = await getMessages(agent, promptWithContext, input);
|
|
156
|
+
const result = await (0, import_ai.streamText)({
|
|
157
|
+
...options,
|
|
158
|
+
...input,
|
|
159
|
+
prompt: void 0,
|
|
160
|
+
// overwritten by messages
|
|
161
|
+
model,
|
|
162
|
+
messages
|
|
163
|
+
});
|
|
237
164
|
for await (const part of result.fullStream) {
|
|
238
165
|
if (part.type === "text-delta") {
|
|
239
166
|
observers.forEach((observer) => {
|
|
@@ -255,32 +182,97 @@ function fromTextStream(agent, defaultOptions) {
|
|
|
255
182
|
};
|
|
256
183
|
});
|
|
257
184
|
}
|
|
258
|
-
function fromText(agent,
|
|
185
|
+
function fromText(agent, options) {
|
|
186
|
+
const resolvedOptions = {
|
|
187
|
+
...agent.defaultOptions,
|
|
188
|
+
...options
|
|
189
|
+
};
|
|
190
|
+
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
259
191
|
return (0, import_xstate.fromPromise)(async ({ input }) => {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
192
|
+
const goal = typeof input.prompt === "string" ? input.prompt : await input.prompt(agent);
|
|
193
|
+
const promptWithContext = template({
|
|
194
|
+
goal,
|
|
263
195
|
context: input.context
|
|
264
196
|
});
|
|
197
|
+
const messages = await getMessages(agent, promptWithContext, input);
|
|
198
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
199
|
+
return await (0, import_ai.generateText)({
|
|
200
|
+
...input,
|
|
201
|
+
...options,
|
|
202
|
+
prompt: void 0,
|
|
203
|
+
messages,
|
|
204
|
+
model
|
|
205
|
+
});
|
|
265
206
|
});
|
|
266
207
|
}
|
|
267
208
|
|
|
268
|
-
// src/
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
209
|
+
// src/decide.ts
|
|
210
|
+
var import_xstate2 = require("xstate");
|
|
211
|
+
var import_ai2 = require("ai");
|
|
212
|
+
async function agentDecide(agent, options) {
|
|
213
|
+
const resolvedOptions = {
|
|
214
|
+
...agent.defaultOptions,
|
|
215
|
+
...options
|
|
216
|
+
};
|
|
217
|
+
const {
|
|
218
|
+
planner = simplePlanner,
|
|
219
|
+
goal,
|
|
220
|
+
events = agent.events,
|
|
221
|
+
state,
|
|
222
|
+
machine,
|
|
223
|
+
model = agent.model,
|
|
224
|
+
messages,
|
|
225
|
+
...otherPlanInput
|
|
226
|
+
} = resolvedOptions;
|
|
227
|
+
let attempts = 0;
|
|
228
|
+
const maxAttempts = resolvedOptions.maxAttempts ?? 2;
|
|
229
|
+
let plan;
|
|
230
|
+
while (attempts++ < maxAttempts) {
|
|
231
|
+
plan = await planner(agent, {
|
|
232
|
+
model,
|
|
233
|
+
goal,
|
|
234
|
+
events,
|
|
235
|
+
state,
|
|
236
|
+
machine,
|
|
237
|
+
messages,
|
|
238
|
+
// TODO: fix UIMessage thing
|
|
239
|
+
...otherPlanInput
|
|
240
|
+
});
|
|
241
|
+
if (plan?.nextEvent) {
|
|
242
|
+
agent.addPlan(plan);
|
|
243
|
+
await resolvedOptions.execute?.(plan.nextEvent);
|
|
244
|
+
}
|
|
272
245
|
}
|
|
273
|
-
|
|
274
|
-
return getAllTransitions(resolvedState);
|
|
246
|
+
return plan;
|
|
275
247
|
}
|
|
276
|
-
|
|
277
|
-
return
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
248
|
+
function fromDecision(agent, defaultInput) {
|
|
249
|
+
return (0, import_xstate2.fromPromise)(async ({ input, self }) => {
|
|
250
|
+
const parentRef = self._parent;
|
|
251
|
+
if (!parentRef) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const snapshot = parentRef.getSnapshot();
|
|
255
|
+
const inputObject = typeof input === "string" ? { goal: input } : input;
|
|
256
|
+
const resolvedInput = {
|
|
257
|
+
...defaultInput,
|
|
258
|
+
...inputObject
|
|
259
|
+
};
|
|
260
|
+
const state = {
|
|
261
|
+
value: snapshot.value,
|
|
262
|
+
context: resolvedInput.context
|
|
263
|
+
};
|
|
264
|
+
const plan = await agentDecide(agent, {
|
|
265
|
+
machine: parentRef.logic,
|
|
266
|
+
state,
|
|
267
|
+
execute: async (event) => {
|
|
268
|
+
parentRef.send(event);
|
|
269
|
+
},
|
|
270
|
+
...resolvedInput
|
|
271
|
+
});
|
|
272
|
+
return plan;
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
function getToolMap(_agent, input) {
|
|
284
276
|
const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
|
|
285
277
|
eventType,
|
|
286
278
|
description
|
|
@@ -305,7 +297,7 @@ async function simplePlanner(agent, input) {
|
|
|
305
297
|
if (!toolZodType) {
|
|
306
298
|
continue;
|
|
307
299
|
}
|
|
308
|
-
toolMap[toolTransitionData.name] = (0,
|
|
300
|
+
toolMap[toolTransitionData.name] = (0, import_ai2.tool)({
|
|
309
301
|
description: toolZodType?.description ?? toolTransitionData.description,
|
|
310
302
|
parameters: toolZodType,
|
|
311
303
|
execute: async (params) => {
|
|
@@ -320,17 +312,56 @@ async function simplePlanner(agent, input) {
|
|
|
320
312
|
if (!Object.keys(toolMap).length) {
|
|
321
313
|
return void 0;
|
|
322
314
|
}
|
|
315
|
+
return toolMap;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/planners/simple.ts
|
|
319
|
+
var simplePlannerPromptTemplate = (data) => {
|
|
320
|
+
return `
|
|
321
|
+
${defaultTextTemplate(data)}
|
|
322
|
+
|
|
323
|
+
Make at most one tool call to achieve the above goal. If the goal cannot be achieved with any tool calls, do not make any tool call.
|
|
324
|
+
`.trim();
|
|
325
|
+
};
|
|
326
|
+
async function simplePlanner(agent, input) {
|
|
327
|
+
const toolMap = getToolMap(agent, input);
|
|
328
|
+
if (!toolMap) {
|
|
329
|
+
return void 0;
|
|
330
|
+
}
|
|
323
331
|
const prompt = simplePlannerPromptTemplate({
|
|
324
332
|
context: input.state.context,
|
|
325
333
|
goal: input.goal
|
|
326
334
|
});
|
|
327
335
|
const messages = await getMessages(agent, prompt, input);
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
336
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
337
|
+
const {
|
|
338
|
+
state,
|
|
339
|
+
machine,
|
|
340
|
+
previousPlan,
|
|
341
|
+
events,
|
|
342
|
+
goal,
|
|
343
|
+
model: _,
|
|
344
|
+
...rest
|
|
345
|
+
} = input;
|
|
346
|
+
const machineState = input.machine ? input.machine.resolveState({
|
|
347
|
+
...input.state,
|
|
348
|
+
context: input.state.context
|
|
349
|
+
}) : void 0;
|
|
350
|
+
const result = await (0, import_ai3.generateText)({
|
|
351
|
+
...rest,
|
|
352
|
+
system: input.system ?? agent.description,
|
|
353
|
+
model,
|
|
332
354
|
messages,
|
|
333
|
-
tools: toolMap
|
|
355
|
+
tools: toolMap,
|
|
356
|
+
toolChoice: input.toolChoice ?? "required"
|
|
357
|
+
});
|
|
358
|
+
result.response.messages.forEach((m) => {
|
|
359
|
+
const message = m;
|
|
360
|
+
agent.addMessage({
|
|
361
|
+
...message,
|
|
362
|
+
id: randomId(),
|
|
363
|
+
timestamp: Date.now()
|
|
364
|
+
});
|
|
334
365
|
});
|
|
335
366
|
const singleResult = result.toolResults[0];
|
|
336
367
|
if (!singleResult) {
|
|
@@ -338,91 +369,94 @@ async function simplePlanner(agent, input) {
|
|
|
338
369
|
return void 0;
|
|
339
370
|
}
|
|
340
371
|
return {
|
|
372
|
+
planner: "simple",
|
|
341
373
|
goal: input.goal,
|
|
342
|
-
|
|
343
|
-
execute: async (state) => {
|
|
344
|
-
if (JSON.stringify(state) === JSON.stringify(input.state)) {
|
|
345
|
-
return singleResult.result;
|
|
346
|
-
}
|
|
347
|
-
return void 0;
|
|
348
|
-
},
|
|
374
|
+
goalState: input.state,
|
|
349
375
|
nextEvent: singleResult.result,
|
|
350
|
-
|
|
351
|
-
timestamp: Date.now()
|
|
376
|
+
episodeId: agent.episodeId,
|
|
377
|
+
timestamp: Date.now(),
|
|
378
|
+
paths: [
|
|
379
|
+
{
|
|
380
|
+
state: void 0,
|
|
381
|
+
steps: [
|
|
382
|
+
{
|
|
383
|
+
event: singleResult.result,
|
|
384
|
+
state: machine && machineState ? (0, import_xstate3.getNextSnapshot)(machine, machineState, singleResult.result) : void 0
|
|
385
|
+
}
|
|
386
|
+
]
|
|
387
|
+
}
|
|
388
|
+
]
|
|
352
389
|
};
|
|
353
390
|
}
|
|
354
391
|
|
|
355
|
-
// src/
|
|
356
|
-
var
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
392
|
+
// src/agent.ts
|
|
393
|
+
var import_ai4 = require("ai");
|
|
394
|
+
|
|
395
|
+
// src/middleware.ts
|
|
396
|
+
function createAgentMiddleware(agent) {
|
|
397
|
+
const middleware = {
|
|
398
|
+
transformParams: async ({ params }) => {
|
|
399
|
+
return params;
|
|
400
|
+
},
|
|
401
|
+
wrapGenerate: async ({ doGenerate, params }) => {
|
|
402
|
+
const id = randomId();
|
|
403
|
+
params.prompt.forEach((message) => {
|
|
404
|
+
agent.addMessage({
|
|
405
|
+
id,
|
|
406
|
+
...message,
|
|
407
|
+
timestamp: Date.now()
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
const result = await doGenerate();
|
|
411
|
+
return result;
|
|
412
|
+
},
|
|
413
|
+
wrapStream: async ({ doStream, params }) => {
|
|
414
|
+
const id = randomId();
|
|
415
|
+
params.prompt.forEach((message) => {
|
|
416
|
+
message.content;
|
|
417
|
+
agent.addMessage({
|
|
418
|
+
id,
|
|
419
|
+
...message,
|
|
420
|
+
timestamp: Date.now()
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
const { stream, ...rest } = await doStream();
|
|
424
|
+
let generatedText = "";
|
|
425
|
+
const transformStream = new TransformStream({
|
|
426
|
+
transform(chunk, controller) {
|
|
427
|
+
if (chunk.type === "text-delta") {
|
|
428
|
+
generatedText += chunk.textDelta;
|
|
429
|
+
}
|
|
430
|
+
controller.enqueue(chunk);
|
|
431
|
+
},
|
|
432
|
+
flush() {
|
|
433
|
+
const content = [];
|
|
434
|
+
if (generatedText) {
|
|
435
|
+
content.push({
|
|
436
|
+
type: "text",
|
|
437
|
+
text: generatedText
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
agent.addMessage({
|
|
441
|
+
id: randomId(),
|
|
442
|
+
timestamp: Date.now(),
|
|
443
|
+
role: "assistant",
|
|
444
|
+
content,
|
|
445
|
+
responseId: id
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
return {
|
|
450
|
+
stream: stream.pipeThrough(transformStream),
|
|
451
|
+
...rest
|
|
452
|
+
};
|
|
390
453
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const resolvedInput = {
|
|
394
|
-
...defaultInput,
|
|
395
|
-
...inputObject
|
|
396
|
-
};
|
|
397
|
-
const contextToInclude = resolvedInput.context === true ? (
|
|
398
|
-
// include entire context
|
|
399
|
-
parentRef.getSnapshot().context
|
|
400
|
-
) : resolvedInput.context;
|
|
401
|
-
const state = {
|
|
402
|
-
value: snapshot.value,
|
|
403
|
-
context: contextToInclude
|
|
404
|
-
};
|
|
405
|
-
const plan = await agentDecide(agent, {
|
|
406
|
-
machine: parentRef.logic,
|
|
407
|
-
state,
|
|
408
|
-
execute: async (event) => {
|
|
409
|
-
parentRef.send(event);
|
|
410
|
-
},
|
|
411
|
-
...resolvedInput
|
|
412
|
-
});
|
|
413
|
-
return plan;
|
|
414
|
-
});
|
|
454
|
+
};
|
|
455
|
+
return middleware;
|
|
415
456
|
}
|
|
416
457
|
|
|
417
|
-
// src/adapters/vercel.ts
|
|
418
|
-
var import_ai2 = require("ai");
|
|
419
|
-
var vercelAdapter = {
|
|
420
|
-
generateText: import_ai2.generateText,
|
|
421
|
-
streamText: import_ai2.streamText
|
|
422
|
-
};
|
|
423
|
-
|
|
424
458
|
// src/agent.ts
|
|
425
|
-
var agentLogic = (0,
|
|
459
|
+
var agentLogic = (0, import_xstate4.fromTransition)(
|
|
426
460
|
(state, event, { emit }) => {
|
|
427
461
|
switch (event.type) {
|
|
428
462
|
case "agent.feedback": {
|
|
@@ -461,8 +495,10 @@ var agentLogic = (0, import_xstate3.fromTransition)(
|
|
|
461
495
|
});
|
|
462
496
|
break;
|
|
463
497
|
}
|
|
464
|
-
default:
|
|
498
|
+
default: {
|
|
499
|
+
console.warn("Unrecognized event", event);
|
|
465
500
|
break;
|
|
501
|
+
}
|
|
466
502
|
}
|
|
467
503
|
return state;
|
|
468
504
|
},
|
|
@@ -474,111 +510,149 @@ var agentLogic = (0, import_xstate3.fromTransition)(
|
|
|
474
510
|
})
|
|
475
511
|
);
|
|
476
512
|
function createAgent({
|
|
477
|
-
|
|
513
|
+
id,
|
|
478
514
|
description,
|
|
479
515
|
model,
|
|
480
516
|
events,
|
|
481
517
|
context,
|
|
482
518
|
planner = simplePlanner,
|
|
483
|
-
|
|
484
|
-
getMemory,
|
|
485
|
-
logic = agentLogic,
|
|
486
|
-
adapter = vercelAdapter,
|
|
487
|
-
...generateTextOptions
|
|
519
|
+
logic = agentLogic
|
|
488
520
|
}) {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
521
|
+
return new Agent({
|
|
522
|
+
id,
|
|
523
|
+
context,
|
|
524
|
+
events,
|
|
525
|
+
description,
|
|
526
|
+
planner,
|
|
527
|
+
model,
|
|
528
|
+
logic
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
var Agent = class extends import_xstate4.Actor {
|
|
532
|
+
// todo
|
|
533
|
+
constructor({
|
|
534
|
+
logic = agentLogic,
|
|
535
|
+
id,
|
|
536
|
+
name,
|
|
537
|
+
description,
|
|
538
|
+
model,
|
|
539
|
+
events,
|
|
540
|
+
context,
|
|
541
|
+
planner = simplePlanner
|
|
542
|
+
}) {
|
|
543
|
+
super(logic);
|
|
544
|
+
this.model = model;
|
|
545
|
+
this.episodeId = id ?? randomId();
|
|
546
|
+
this.name = name;
|
|
547
|
+
this.description = description;
|
|
548
|
+
this.events = events;
|
|
549
|
+
this.context = context;
|
|
550
|
+
this.planner = planner;
|
|
551
|
+
this.types = {};
|
|
552
|
+
this.start();
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Called whenever the agent (LLM assistant) receives or sends a message.
|
|
556
|
+
*/
|
|
557
|
+
onMessage(fn) {
|
|
558
|
+
return this.on("message", (ev) => fn(ev.message));
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Retrieves messages from the agent's short-term (local) memory.
|
|
562
|
+
*/
|
|
563
|
+
addMessage(messageInput) {
|
|
507
564
|
const message = {
|
|
508
565
|
...messageInput,
|
|
509
566
|
id: messageInput.id ?? randomId(),
|
|
510
567
|
timestamp: messageInput.timestamp ?? Date.now(),
|
|
511
|
-
|
|
512
|
-
correlationId: messageInput.correlationId ?? randomId()
|
|
568
|
+
episodeId: this.episodeId
|
|
513
569
|
};
|
|
514
|
-
|
|
570
|
+
this.send({
|
|
515
571
|
type: "agent.message",
|
|
516
572
|
message
|
|
517
573
|
});
|
|
518
574
|
return message;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
575
|
+
}
|
|
576
|
+
getMessages() {
|
|
577
|
+
return this.getSnapshot().context.messages;
|
|
578
|
+
}
|
|
579
|
+
addFeedback(feedbackInput) {
|
|
524
580
|
const feedback = {
|
|
525
581
|
...feedbackInput,
|
|
526
582
|
attributes: { ...feedbackInput.attributes },
|
|
527
583
|
reward: feedbackInput.reward ?? 0,
|
|
528
584
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
529
|
-
|
|
585
|
+
episodeId: this.episodeId
|
|
530
586
|
};
|
|
531
|
-
|
|
587
|
+
this.send({
|
|
532
588
|
type: "agent.feedback",
|
|
533
589
|
feedback
|
|
534
590
|
});
|
|
535
591
|
return feedback;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Retrieves feedback from the agent's short-term (local) memory.
|
|
595
|
+
*/
|
|
596
|
+
getFeedback() {
|
|
597
|
+
return this.getSnapshot().context.feedback;
|
|
598
|
+
}
|
|
599
|
+
addObservation(observationInput) {
|
|
539
600
|
const { prevState, event, state } = observationInput;
|
|
540
601
|
const observation = {
|
|
541
602
|
prevState,
|
|
542
603
|
event,
|
|
543
604
|
state,
|
|
544
605
|
id: observationInput.id ?? randomId(),
|
|
545
|
-
|
|
606
|
+
episodeId: this.episodeId,
|
|
546
607
|
timestamp: observationInput.timestamp ?? Date.now(),
|
|
547
608
|
machineHash: observationInput.machine ? getMachineHash(observationInput.machine) : void 0
|
|
548
609
|
};
|
|
549
|
-
|
|
610
|
+
this.send({
|
|
550
611
|
type: "agent.observe",
|
|
551
612
|
observation
|
|
552
613
|
});
|
|
553
614
|
return observation;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Retrieves observations from the agent's short-term (local) memory.
|
|
618
|
+
*/
|
|
619
|
+
getObservations() {
|
|
620
|
+
return this.getSnapshot().context.observations;
|
|
621
|
+
}
|
|
622
|
+
addPlan(plan) {
|
|
623
|
+
this.send({
|
|
558
624
|
type: "agent.plan",
|
|
559
625
|
plan
|
|
560
626
|
});
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Retrieves strategies from the agent's short-term (local) memory.
|
|
630
|
+
*/
|
|
631
|
+
getPlans() {
|
|
632
|
+
return this.getSnapshot().context.plans;
|
|
633
|
+
}
|
|
634
|
+
interact(actorRef, getInput) {
|
|
635
|
+
const actorRefCheck = isActorRef(actorRef) && actorRef.src;
|
|
636
|
+
const machine = isMachineActor(actorRef) ? actorRef.src : void 0;
|
|
564
637
|
let prevState = void 0;
|
|
565
638
|
let subscribed = true;
|
|
639
|
+
const agent = this;
|
|
566
640
|
async function handleObservation(observationInput) {
|
|
567
641
|
const observation = agent.addObservation(observationInput);
|
|
568
642
|
const input = getInput?.(observation);
|
|
569
643
|
if (input) {
|
|
570
|
-
await agentDecide(agent, {
|
|
571
|
-
machine
|
|
644
|
+
const res = await agentDecide(agent, {
|
|
645
|
+
machine,
|
|
572
646
|
state: observation.state,
|
|
573
|
-
execute: async (event) => {
|
|
574
|
-
actorRef.send(event);
|
|
575
|
-
},
|
|
576
647
|
...input
|
|
577
648
|
});
|
|
649
|
+
if (res?.nextEvent) {
|
|
650
|
+
actorRef.send(res.nextEvent);
|
|
651
|
+
}
|
|
578
652
|
}
|
|
579
653
|
prevState = observationInput.state;
|
|
580
654
|
}
|
|
581
|
-
actorRef.system.inspect({
|
|
655
|
+
const sub = actorRefCheck ? actorRef.system.inspect({
|
|
582
656
|
next: async (inspEvent) => {
|
|
583
657
|
if (!subscribed || inspEvent.actorRef !== actorRef || inspEvent.type !== "@xstate.snapshot") {
|
|
584
658
|
return;
|
|
@@ -591,7 +665,7 @@ function createAgent({
|
|
|
591
665
|
};
|
|
592
666
|
await handleObservation(observationInput);
|
|
593
667
|
}
|
|
594
|
-
});
|
|
668
|
+
}) : void 0;
|
|
595
669
|
if (actorRef._processingStatus === 1) {
|
|
596
670
|
handleObservation({
|
|
597
671
|
prevState: void 0,
|
|
@@ -603,15 +677,50 @@ function createAgent({
|
|
|
603
677
|
}
|
|
604
678
|
return {
|
|
605
679
|
unsubscribe: () => {
|
|
680
|
+
sub?.unsubscribe();
|
|
606
681
|
subscribed = false;
|
|
607
682
|
}
|
|
608
|
-
// TODO: make this actually unsubscribe
|
|
609
683
|
};
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
684
|
+
}
|
|
685
|
+
observe(actorRef) {
|
|
686
|
+
let prevState = actorRef.getSnapshot();
|
|
687
|
+
const actorRefCheck = isActorRef(actorRef);
|
|
688
|
+
const sub = actorRefCheck ? actorRef.system.inspect({
|
|
689
|
+
next: async (inspEvent) => {
|
|
690
|
+
if (inspEvent.actorRef !== actorRef || inspEvent.type !== "@xstate.snapshot") {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const observationInput = {
|
|
694
|
+
event: inspEvent.event,
|
|
695
|
+
prevState,
|
|
696
|
+
state: inspEvent.snapshot,
|
|
697
|
+
machine: actorRef.src
|
|
698
|
+
};
|
|
699
|
+
prevState = observationInput.state;
|
|
700
|
+
this.addObservation(observationInput);
|
|
701
|
+
}
|
|
702
|
+
}) : void 0;
|
|
703
|
+
return sub ?? { unsubscribe: () => {
|
|
704
|
+
} };
|
|
705
|
+
}
|
|
706
|
+
wrap(modelToWrap) {
|
|
707
|
+
return (0, import_ai4.experimental_wrapLanguageModel)({
|
|
708
|
+
model: modelToWrap,
|
|
709
|
+
middleware: createAgentMiddleware(this)
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Resolves with an `AgentPlan` based on the information provided in the `options`, including:
|
|
714
|
+
*
|
|
715
|
+
* - The `goal` for the agent to achieve
|
|
716
|
+
* - The observed current `state`
|
|
717
|
+
* - The `machine` (e.g. a state machine) that specifies what can happen next
|
|
718
|
+
* - Additional `context`
|
|
719
|
+
*/
|
|
720
|
+
decide(opts) {
|
|
721
|
+
return agentDecide(this, opts);
|
|
722
|
+
}
|
|
723
|
+
};
|
|
615
724
|
// Annotate the CommonJS export names for ESM import in node:
|
|
616
725
|
0 && (module.exports = {
|
|
617
726
|
createAgent,
|