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