@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.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// src/agent.ts
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
Actor,
|
|
4
4
|
fromTransition
|
|
5
5
|
} from "xstate";
|
|
6
6
|
|
|
7
7
|
// src/planners/simplePlanner.ts
|
|
8
|
-
import {
|
|
8
|
+
import { generateText as generateText2 } from "ai";
|
|
9
9
|
|
|
10
10
|
// src/utils.ts
|
|
11
11
|
import hash from "object-hash";
|
|
@@ -43,10 +43,10 @@ function getAllMachineTransitions(stateNode) {
|
|
|
43
43
|
function wrapInXml(tagName, content) {
|
|
44
44
|
return `<${tagName}>${content}</${tagName}>`;
|
|
45
45
|
}
|
|
46
|
-
function randomId() {
|
|
46
|
+
function randomId(prefix) {
|
|
47
47
|
const timestamp = Date.now().toString(36);
|
|
48
48
|
const random = Math.random().toString(36).substring(2, 9);
|
|
49
|
-
return
|
|
49
|
+
return `${prefix || ""}${timestamp}${random}`;
|
|
50
50
|
}
|
|
51
51
|
var machineHashes = /* @__PURE__ */ new WeakMap();
|
|
52
52
|
function getMachineHash(machine) {
|
|
@@ -56,6 +56,23 @@ function getMachineHash(machine) {
|
|
|
56
56
|
machineHashes.set(machine, machineHash);
|
|
57
57
|
return machineHash;
|
|
58
58
|
}
|
|
59
|
+
function isActorRef(actorRefLike) {
|
|
60
|
+
return "src" in actorRefLike && "system" in actorRefLike && "sessionId" in actorRefLike;
|
|
61
|
+
}
|
|
62
|
+
function getTransitions(state, machine) {
|
|
63
|
+
if (!machine) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const resolvedState = machine.resolveState({
|
|
67
|
+
...state,
|
|
68
|
+
// Need this property defined to make TS happy
|
|
69
|
+
context: state.context
|
|
70
|
+
});
|
|
71
|
+
return getAllTransitions(resolvedState);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/planners/simplePlanner.ts
|
|
75
|
+
import { getNextSnapshot } from "xstate";
|
|
59
76
|
|
|
60
77
|
// src/templates/defaultText.ts
|
|
61
78
|
var defaultTextTemplate = (data) => {
|
|
@@ -70,6 +87,10 @@ ${data.goal}
|
|
|
70
87
|
};
|
|
71
88
|
|
|
72
89
|
// src/text.ts
|
|
90
|
+
import {
|
|
91
|
+
generateText,
|
|
92
|
+
streamText
|
|
93
|
+
} from "ai";
|
|
73
94
|
import {
|
|
74
95
|
fromObservable,
|
|
75
96
|
fromPromise,
|
|
@@ -88,115 +109,26 @@ async function getMessages(agent, prompt, options) {
|
|
|
88
109
|
});
|
|
89
110
|
return messages;
|
|
90
111
|
}
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
...agent.defaultOptions,
|
|
94
|
-
...options,
|
|
95
|
-
correlationId: options.correlationId ?? randomId()
|
|
96
|
-
};
|
|
97
|
-
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
98
|
-
const id = randomId();
|
|
99
|
-
const goal = typeof resolvedOptions.prompt === "string" ? resolvedOptions.prompt : await resolvedOptions.prompt(agent);
|
|
100
|
-
const promptWithContext = template({
|
|
101
|
-
goal,
|
|
102
|
-
context: resolvedOptions.context
|
|
103
|
-
});
|
|
104
|
-
const messages = await getMessages(agent, promptWithContext, resolvedOptions);
|
|
105
|
-
agent.addMessage({
|
|
106
|
-
id,
|
|
107
|
-
role: "user",
|
|
108
|
-
content: promptWithContext,
|
|
109
|
-
timestamp: Date.now(),
|
|
110
|
-
correlationId: resolvedOptions.correlationId,
|
|
111
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
112
|
-
});
|
|
113
|
-
const result = await agent.adapter.generateText({
|
|
114
|
-
...resolvedOptions,
|
|
115
|
-
prompt: void 0,
|
|
116
|
-
messages
|
|
117
|
-
});
|
|
118
|
-
agent.addMessage({
|
|
119
|
-
content: result.text,
|
|
120
|
-
id,
|
|
121
|
-
role: "assistant",
|
|
122
|
-
timestamp: Date.now(),
|
|
123
|
-
responseId: id,
|
|
124
|
-
result,
|
|
125
|
-
correlationId: resolvedOptions.correlationId,
|
|
126
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
127
|
-
});
|
|
128
|
-
return {
|
|
129
|
-
...result,
|
|
130
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
131
|
-
correlationId: resolvedOptions.correlationId
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
async function agentStreamText(agent, options) {
|
|
135
|
-
const resolvedOptions = {
|
|
136
|
-
...agent.defaultOptions,
|
|
137
|
-
...options,
|
|
138
|
-
correlationId: options.correlationId ?? randomId()
|
|
139
|
-
};
|
|
140
|
-
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
141
|
-
const id = randomId();
|
|
142
|
-
const goal = typeof resolvedOptions.prompt === "string" ? resolvedOptions.prompt : await resolvedOptions.prompt(agent);
|
|
143
|
-
const promptWithContext = template({
|
|
144
|
-
goal,
|
|
145
|
-
context: resolvedOptions.context
|
|
146
|
-
});
|
|
147
|
-
const messages = await getMessages(agent, promptWithContext, resolvedOptions);
|
|
148
|
-
agent.addMessage({
|
|
149
|
-
role: "user",
|
|
150
|
-
content: promptWithContext,
|
|
151
|
-
id,
|
|
152
|
-
timestamp: Date.now(),
|
|
153
|
-
correlationId: resolvedOptions.correlationId,
|
|
154
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
155
|
-
});
|
|
156
|
-
const result = await agent.adapter.streamText({
|
|
157
|
-
...resolvedOptions,
|
|
158
|
-
prompt: void 0,
|
|
159
|
-
messages,
|
|
160
|
-
onFinish: async (res) => {
|
|
161
|
-
agent.addMessage({
|
|
162
|
-
role: "assistant",
|
|
163
|
-
result: {
|
|
164
|
-
text: res.text,
|
|
165
|
-
finishReason: res.finishReason,
|
|
166
|
-
logprobs: void 0,
|
|
167
|
-
responseMessages: [],
|
|
168
|
-
toolCalls: [],
|
|
169
|
-
toolResults: [],
|
|
170
|
-
usage: res.usage,
|
|
171
|
-
warnings: res.warnings,
|
|
172
|
-
rawResponse: res.rawResponse,
|
|
173
|
-
roundtrips: []
|
|
174
|
-
// TODO: how do we get this information?
|
|
175
|
-
},
|
|
176
|
-
content: res.text,
|
|
177
|
-
id: randomId(),
|
|
178
|
-
timestamp: Date.now(),
|
|
179
|
-
responseId: id,
|
|
180
|
-
correlationId: resolvedOptions.correlationId,
|
|
181
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
return {
|
|
186
|
-
...result,
|
|
187
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
188
|
-
correlationId: resolvedOptions.correlationId
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
function fromTextStream(agent, defaultOptions) {
|
|
112
|
+
function fromTextStream(agent, options) {
|
|
113
|
+
const template = options?.template ?? defaultTextTemplate;
|
|
192
114
|
return fromObservable(({ input }) => {
|
|
193
115
|
const observers = /* @__PURE__ */ new Set();
|
|
194
116
|
(async () => {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
117
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
118
|
+
const goal = typeof input.prompt === "string" ? input.prompt : await input.prompt(agent);
|
|
119
|
+
const promptWithContext = template({
|
|
120
|
+
goal,
|
|
198
121
|
context: input.context
|
|
199
122
|
});
|
|
123
|
+
const messages = await getMessages(agent, promptWithContext, input);
|
|
124
|
+
const result = await streamText({
|
|
125
|
+
...options,
|
|
126
|
+
...input,
|
|
127
|
+
prompt: void 0,
|
|
128
|
+
// overwritten by messages
|
|
129
|
+
model,
|
|
130
|
+
messages
|
|
131
|
+
});
|
|
200
132
|
for await (const part of result.fullStream) {
|
|
201
133
|
if (part.type === "text-delta") {
|
|
202
134
|
observers.forEach((observer) => {
|
|
@@ -218,32 +150,89 @@ function fromTextStream(agent, defaultOptions) {
|
|
|
218
150
|
};
|
|
219
151
|
});
|
|
220
152
|
}
|
|
221
|
-
function fromText(agent,
|
|
153
|
+
function fromText(agent, options) {
|
|
154
|
+
const resolvedOptions = {
|
|
155
|
+
...agent.defaultOptions,
|
|
156
|
+
...options
|
|
157
|
+
};
|
|
158
|
+
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
222
159
|
return fromPromise(async ({ input }) => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
160
|
+
const goal = typeof input.prompt === "string" ? input.prompt : await input.prompt(agent);
|
|
161
|
+
const promptWithContext = template({
|
|
162
|
+
goal,
|
|
226
163
|
context: input.context
|
|
227
164
|
});
|
|
165
|
+
const messages = await getMessages(agent, promptWithContext, input);
|
|
166
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
167
|
+
return await generateText({
|
|
168
|
+
...input,
|
|
169
|
+
...options,
|
|
170
|
+
prompt: void 0,
|
|
171
|
+
messages,
|
|
172
|
+
model
|
|
173
|
+
});
|
|
228
174
|
});
|
|
229
175
|
}
|
|
230
176
|
|
|
231
|
-
// src/
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
177
|
+
// src/decide.ts
|
|
178
|
+
import { fromPromise as fromPromise2 } from "xstate";
|
|
179
|
+
import { tool } from "ai";
|
|
180
|
+
async function agentDecide(agent, options) {
|
|
181
|
+
const resolvedOptions = {
|
|
182
|
+
...agent.defaultOptions,
|
|
183
|
+
...options
|
|
184
|
+
};
|
|
185
|
+
const {
|
|
186
|
+
planner = simplePlanner,
|
|
187
|
+
goal,
|
|
188
|
+
events = agent.events,
|
|
189
|
+
state,
|
|
190
|
+
machine,
|
|
191
|
+
model = agent.model,
|
|
192
|
+
...otherPlanInput
|
|
193
|
+
} = resolvedOptions;
|
|
194
|
+
const plan = await planner(agent, {
|
|
195
|
+
model,
|
|
196
|
+
goal,
|
|
197
|
+
events,
|
|
198
|
+
state,
|
|
199
|
+
machine,
|
|
200
|
+
...otherPlanInput
|
|
201
|
+
});
|
|
202
|
+
if (plan?.nextEvent) {
|
|
203
|
+
agent.addPlan(plan);
|
|
204
|
+
await resolvedOptions.execute?.(plan.nextEvent);
|
|
235
205
|
}
|
|
236
|
-
|
|
237
|
-
return getAllTransitions(resolvedState);
|
|
206
|
+
return plan;
|
|
238
207
|
}
|
|
239
|
-
|
|
240
|
-
return
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
208
|
+
function fromDecision(agent, defaultInput) {
|
|
209
|
+
return fromPromise2(async ({ input, self }) => {
|
|
210
|
+
const parentRef = self._parent;
|
|
211
|
+
if (!parentRef) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const snapshot = parentRef.getSnapshot();
|
|
215
|
+
const inputObject = typeof input === "string" ? { goal: input } : input;
|
|
216
|
+
const resolvedInput = {
|
|
217
|
+
...defaultInput,
|
|
218
|
+
...inputObject
|
|
219
|
+
};
|
|
220
|
+
const state = {
|
|
221
|
+
value: snapshot.value,
|
|
222
|
+
context: resolvedInput.context
|
|
223
|
+
};
|
|
224
|
+
const plan = await agentDecide(agent, {
|
|
225
|
+
machine: parentRef.logic,
|
|
226
|
+
state,
|
|
227
|
+
execute: async (event) => {
|
|
228
|
+
parentRef.send(event);
|
|
229
|
+
},
|
|
230
|
+
...resolvedInput
|
|
231
|
+
});
|
|
232
|
+
return plan;
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function getToolMap(_agent, input) {
|
|
247
236
|
const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
|
|
248
237
|
eventType,
|
|
249
238
|
description
|
|
@@ -283,17 +272,55 @@ async function simplePlanner(agent, input) {
|
|
|
283
272
|
if (!Object.keys(toolMap).length) {
|
|
284
273
|
return void 0;
|
|
285
274
|
}
|
|
275
|
+
return toolMap;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/planners/simplePlanner.ts
|
|
279
|
+
var simplePlannerPromptTemplate = (data) => {
|
|
280
|
+
return `
|
|
281
|
+
${defaultTextTemplate(data)}
|
|
282
|
+
|
|
283
|
+
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.
|
|
284
|
+
`.trim();
|
|
285
|
+
};
|
|
286
|
+
async function simplePlanner(agent, input) {
|
|
287
|
+
const toolMap = getToolMap(agent, input);
|
|
288
|
+
if (!toolMap) {
|
|
289
|
+
return void 0;
|
|
290
|
+
}
|
|
286
291
|
const prompt = simplePlannerPromptTemplate({
|
|
287
292
|
context: input.state.context,
|
|
288
293
|
goal: input.goal
|
|
289
294
|
});
|
|
290
295
|
const messages = await getMessages(agent, prompt, input);
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
296
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
297
|
+
const {
|
|
298
|
+
state,
|
|
299
|
+
machine,
|
|
300
|
+
previousPlan,
|
|
301
|
+
events,
|
|
302
|
+
goal,
|
|
303
|
+
model: _,
|
|
304
|
+
...rest
|
|
305
|
+
} = input;
|
|
306
|
+
const machineState = input.machine ? input.machine.resolveState({
|
|
307
|
+
...input.state,
|
|
308
|
+
context: input.state.context
|
|
309
|
+
}) : void 0;
|
|
310
|
+
const result = await generateText2({
|
|
311
|
+
...rest,
|
|
312
|
+
model,
|
|
295
313
|
messages,
|
|
296
|
-
tools: toolMap
|
|
314
|
+
tools: toolMap,
|
|
315
|
+
toolChoice: input.toolChoice ?? "required"
|
|
316
|
+
});
|
|
317
|
+
result.responseMessages.forEach((m) => {
|
|
318
|
+
const message = m;
|
|
319
|
+
agent.addMessage({
|
|
320
|
+
...message,
|
|
321
|
+
id: randomId(),
|
|
322
|
+
timestamp: Date.now()
|
|
323
|
+
});
|
|
297
324
|
});
|
|
298
325
|
const singleResult = result.toolResults[0];
|
|
299
326
|
if (!singleResult) {
|
|
@@ -301,89 +328,100 @@ async function simplePlanner(agent, input) {
|
|
|
301
328
|
return void 0;
|
|
302
329
|
}
|
|
303
330
|
return {
|
|
331
|
+
planner: "simple",
|
|
304
332
|
goal: input.goal,
|
|
305
|
-
|
|
306
|
-
execute: async (state) => {
|
|
307
|
-
if (JSON.stringify(state) === JSON.stringify(input.state)) {
|
|
308
|
-
return singleResult.result;
|
|
309
|
-
}
|
|
310
|
-
return void 0;
|
|
311
|
-
},
|
|
333
|
+
goalState: input.state,
|
|
312
334
|
nextEvent: singleResult.result,
|
|
313
|
-
|
|
314
|
-
timestamp: Date.now()
|
|
335
|
+
episodeId: agent.episodeId,
|
|
336
|
+
timestamp: Date.now(),
|
|
337
|
+
paths: [
|
|
338
|
+
{
|
|
339
|
+
state: void 0,
|
|
340
|
+
steps: [
|
|
341
|
+
{
|
|
342
|
+
event: singleResult.result,
|
|
343
|
+
state: machine && machineState ? getNextSnapshot(machine, machineState, singleResult.result) : void 0
|
|
344
|
+
}
|
|
345
|
+
]
|
|
346
|
+
}
|
|
347
|
+
]
|
|
315
348
|
};
|
|
316
349
|
}
|
|
317
350
|
|
|
318
|
-
// src/
|
|
319
|
-
import {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
351
|
+
// src/agent.ts
|
|
352
|
+
import {
|
|
353
|
+
experimental_wrapLanguageModel
|
|
354
|
+
} from "ai";
|
|
355
|
+
|
|
356
|
+
// src/middleware.ts
|
|
357
|
+
function createAgentMiddleware(agent) {
|
|
358
|
+
const middleware = {
|
|
359
|
+
transformParams: async ({ params }) => {
|
|
360
|
+
return params;
|
|
361
|
+
},
|
|
362
|
+
wrapGenerate: async ({ doGenerate, params }) => {
|
|
363
|
+
const id = randomId();
|
|
364
|
+
params.prompt.forEach((p) => {
|
|
365
|
+
agent.addMessage({
|
|
366
|
+
id,
|
|
367
|
+
...p,
|
|
368
|
+
timestamp: Date.now(),
|
|
369
|
+
correlationId: params.providerMetadata?.correlationId,
|
|
370
|
+
parentCorrelationId: params.providerMetadata?.parentCorrelationId
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
const result = await doGenerate();
|
|
374
|
+
return result;
|
|
375
|
+
},
|
|
376
|
+
wrapStream: async ({ doStream, params }) => {
|
|
377
|
+
const id = randomId();
|
|
378
|
+
params.prompt.forEach((message) => {
|
|
379
|
+
message.content;
|
|
380
|
+
agent.addMessage({
|
|
381
|
+
id,
|
|
382
|
+
...message,
|
|
383
|
+
timestamp: Date.now(),
|
|
384
|
+
correlationId: params.providerMetadata?.correlationId,
|
|
385
|
+
parentCorrelationId: params.providerMetadata?.parentCorrelationId
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
const { stream, ...rest } = await doStream();
|
|
389
|
+
let generatedText = "";
|
|
390
|
+
const transformStream = new TransformStream({
|
|
391
|
+
transform(chunk, controller) {
|
|
392
|
+
if (chunk.type === "text-delta") {
|
|
393
|
+
generatedText += chunk.textDelta;
|
|
394
|
+
}
|
|
395
|
+
controller.enqueue(chunk);
|
|
396
|
+
},
|
|
397
|
+
flush() {
|
|
398
|
+
const content = [];
|
|
399
|
+
if (generatedText) {
|
|
400
|
+
content.push({
|
|
401
|
+
type: "text",
|
|
402
|
+
text: generatedText
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
agent.addMessage({
|
|
406
|
+
id: randomId(),
|
|
407
|
+
timestamp: Date.now(),
|
|
408
|
+
role: "assistant",
|
|
409
|
+
content,
|
|
410
|
+
responseId: id,
|
|
411
|
+
correlationId: params.providerMetadata?.correlationId,
|
|
412
|
+
parentCorrelationId: params.providerMetadata?.parentCorrelationId
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
return {
|
|
417
|
+
stream: stream.pipeThrough(transformStream),
|
|
418
|
+
...rest
|
|
419
|
+
};
|
|
353
420
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const resolvedInput = {
|
|
357
|
-
...defaultInput,
|
|
358
|
-
...inputObject
|
|
359
|
-
};
|
|
360
|
-
const contextToInclude = resolvedInput.context === true ? (
|
|
361
|
-
// include entire context
|
|
362
|
-
parentRef.getSnapshot().context
|
|
363
|
-
) : resolvedInput.context;
|
|
364
|
-
const state = {
|
|
365
|
-
value: snapshot.value,
|
|
366
|
-
context: contextToInclude
|
|
367
|
-
};
|
|
368
|
-
const plan = await agentDecide(agent, {
|
|
369
|
-
machine: parentRef.logic,
|
|
370
|
-
state,
|
|
371
|
-
execute: async (event) => {
|
|
372
|
-
parentRef.send(event);
|
|
373
|
-
},
|
|
374
|
-
...resolvedInput
|
|
375
|
-
});
|
|
376
|
-
return plan;
|
|
377
|
-
});
|
|
421
|
+
};
|
|
422
|
+
return middleware;
|
|
378
423
|
}
|
|
379
424
|
|
|
380
|
-
// src/adapters/vercel.ts
|
|
381
|
-
import { generateText, streamText } from "ai";
|
|
382
|
-
var vercelAdapter = {
|
|
383
|
-
generateText,
|
|
384
|
-
streamText
|
|
385
|
-
};
|
|
386
|
-
|
|
387
425
|
// src/agent.ts
|
|
388
426
|
var agentLogic = fromTransition(
|
|
389
427
|
(state, event, { emit }) => {
|
|
@@ -437,6 +475,7 @@ var agentLogic = fromTransition(
|
|
|
437
475
|
})
|
|
438
476
|
);
|
|
439
477
|
function createAgent({
|
|
478
|
+
id,
|
|
440
479
|
name,
|
|
441
480
|
description,
|
|
442
481
|
model,
|
|
@@ -446,92 +485,133 @@ function createAgent({
|
|
|
446
485
|
stringify = JSON.stringify,
|
|
447
486
|
getMemory,
|
|
448
487
|
logic = agentLogic,
|
|
449
|
-
adapter = vercelAdapter,
|
|
450
488
|
...generateTextOptions
|
|
451
489
|
}) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
490
|
+
return new Agent({
|
|
491
|
+
id,
|
|
492
|
+
context,
|
|
493
|
+
events,
|
|
494
|
+
name,
|
|
495
|
+
description,
|
|
496
|
+
planner,
|
|
497
|
+
model,
|
|
498
|
+
logic
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
var Agent = class extends Actor {
|
|
502
|
+
// todo
|
|
503
|
+
constructor({
|
|
504
|
+
logic = agentLogic,
|
|
505
|
+
id,
|
|
506
|
+
name,
|
|
507
|
+
description,
|
|
508
|
+
model,
|
|
509
|
+
events,
|
|
510
|
+
context,
|
|
511
|
+
planner = simplePlanner
|
|
512
|
+
}) {
|
|
513
|
+
super(logic);
|
|
514
|
+
this.model = model;
|
|
515
|
+
this.episodeId = id ?? randomId();
|
|
516
|
+
this.name = name;
|
|
517
|
+
this.description = description;
|
|
518
|
+
this.events = events;
|
|
519
|
+
this.context = context;
|
|
520
|
+
this.planner = planner;
|
|
521
|
+
this.types = {};
|
|
522
|
+
this.start();
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Called whenever the agent (LLM assistant) receives or sends a message.
|
|
526
|
+
*/
|
|
527
|
+
onMessage(fn) {
|
|
528
|
+
return this.on("message", (ev) => fn(ev.message));
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Retrieves messages from the agent's short-term (local) memory.
|
|
532
|
+
*/
|
|
533
|
+
addMessage(messageInput) {
|
|
470
534
|
const message = {
|
|
471
535
|
...messageInput,
|
|
472
536
|
id: messageInput.id ?? randomId(),
|
|
473
537
|
timestamp: messageInput.timestamp ?? Date.now(),
|
|
474
|
-
|
|
475
|
-
correlationId: messageInput.correlationId ?? randomId()
|
|
538
|
+
episodeId: this.episodeId
|
|
476
539
|
};
|
|
477
|
-
|
|
540
|
+
this.send({
|
|
478
541
|
type: "agent.message",
|
|
479
542
|
message
|
|
480
543
|
});
|
|
481
544
|
return message;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
545
|
+
}
|
|
546
|
+
getMessages() {
|
|
547
|
+
return this.getSnapshot().context.messages;
|
|
548
|
+
}
|
|
549
|
+
addFeedback(feedbackInput) {
|
|
487
550
|
const feedback = {
|
|
488
551
|
...feedbackInput,
|
|
489
552
|
attributes: { ...feedbackInput.attributes },
|
|
490
553
|
reward: feedbackInput.reward ?? 0,
|
|
491
554
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
492
|
-
|
|
555
|
+
episodeId: this.episodeId
|
|
493
556
|
};
|
|
494
|
-
|
|
557
|
+
this.send({
|
|
495
558
|
type: "agent.feedback",
|
|
496
559
|
feedback
|
|
497
560
|
});
|
|
498
561
|
return feedback;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Retrieves feedback from the agent's short-term (local) memory.
|
|
565
|
+
*/
|
|
566
|
+
getFeedback() {
|
|
567
|
+
return this.getSnapshot().context.feedback;
|
|
568
|
+
}
|
|
569
|
+
addObservation(observationInput) {
|
|
502
570
|
const { prevState, event, state } = observationInput;
|
|
503
571
|
const observation = {
|
|
504
572
|
prevState,
|
|
505
573
|
event,
|
|
506
574
|
state,
|
|
507
575
|
id: observationInput.id ?? randomId(),
|
|
508
|
-
|
|
576
|
+
episodeId: this.episodeId,
|
|
509
577
|
timestamp: observationInput.timestamp ?? Date.now(),
|
|
510
578
|
machineHash: observationInput.machine ? getMachineHash(observationInput.machine) : void 0
|
|
511
579
|
};
|
|
512
|
-
|
|
580
|
+
this.send({
|
|
513
581
|
type: "agent.observe",
|
|
514
582
|
observation
|
|
515
583
|
});
|
|
516
584
|
return observation;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Retrieves observations from the agent's short-term (local) memory.
|
|
588
|
+
*/
|
|
589
|
+
getObservations() {
|
|
590
|
+
return this.getSnapshot().context.observations;
|
|
591
|
+
}
|
|
592
|
+
addPlan(plan) {
|
|
593
|
+
this.send({
|
|
521
594
|
type: "agent.plan",
|
|
522
595
|
plan
|
|
523
596
|
});
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Retrieves strategies from the agent's short-term (local) memory.
|
|
600
|
+
*/
|
|
601
|
+
getPlans() {
|
|
602
|
+
return this.getSnapshot().context.plans;
|
|
603
|
+
}
|
|
604
|
+
interact(actorRef, getInput) {
|
|
605
|
+
const actorRefCheck = isActorRef(actorRef);
|
|
527
606
|
let prevState = void 0;
|
|
528
607
|
let subscribed = true;
|
|
608
|
+
const agent = this;
|
|
529
609
|
async function handleObservation(observationInput) {
|
|
530
610
|
const observation = agent.addObservation(observationInput);
|
|
531
611
|
const input = getInput?.(observation);
|
|
532
612
|
if (input) {
|
|
533
613
|
await agentDecide(agent, {
|
|
534
|
-
machine: actorRef.src,
|
|
614
|
+
machine: actorRefCheck ? actorRef.src : void 0,
|
|
535
615
|
state: observation.state,
|
|
536
616
|
execute: async (event) => {
|
|
537
617
|
actorRef.send(event);
|
|
@@ -541,7 +621,7 @@ function createAgent({
|
|
|
541
621
|
}
|
|
542
622
|
prevState = observationInput.state;
|
|
543
623
|
}
|
|
544
|
-
actorRef.system.inspect({
|
|
624
|
+
const sub = actorRefCheck ? actorRef.system.inspect({
|
|
545
625
|
next: async (inspEvent) => {
|
|
546
626
|
if (!subscribed || inspEvent.actorRef !== actorRef || inspEvent.type !== "@xstate.snapshot") {
|
|
547
627
|
return;
|
|
@@ -554,7 +634,7 @@ function createAgent({
|
|
|
554
634
|
};
|
|
555
635
|
await handleObservation(observationInput);
|
|
556
636
|
}
|
|
557
|
-
});
|
|
637
|
+
}) : void 0;
|
|
558
638
|
if (actorRef._processingStatus === 1) {
|
|
559
639
|
handleObservation({
|
|
560
640
|
prevState: void 0,
|
|
@@ -566,15 +646,50 @@ function createAgent({
|
|
|
566
646
|
}
|
|
567
647
|
return {
|
|
568
648
|
unsubscribe: () => {
|
|
649
|
+
sub?.unsubscribe();
|
|
569
650
|
subscribed = false;
|
|
570
651
|
}
|
|
571
|
-
// TODO: make this actually unsubscribe
|
|
572
652
|
};
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
653
|
+
}
|
|
654
|
+
observe(actorRef) {
|
|
655
|
+
let prevState = actorRef.getSnapshot();
|
|
656
|
+
const actorRefCheck = isActorRef(actorRef);
|
|
657
|
+
const sub = actorRefCheck ? actorRef.system.inspect({
|
|
658
|
+
next: async (inspEvent) => {
|
|
659
|
+
if (inspEvent.actorRef !== actorRef || inspEvent.type !== "@xstate.snapshot") {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
const observationInput = {
|
|
663
|
+
event: inspEvent.event,
|
|
664
|
+
prevState,
|
|
665
|
+
state: inspEvent.snapshot,
|
|
666
|
+
machine: actorRef.src
|
|
667
|
+
};
|
|
668
|
+
prevState = observationInput.state;
|
|
669
|
+
this.addObservation(observationInput);
|
|
670
|
+
}
|
|
671
|
+
}) : void 0;
|
|
672
|
+
return sub ?? { unsubscribe: () => {
|
|
673
|
+
} };
|
|
674
|
+
}
|
|
675
|
+
wrap(modelToWrap) {
|
|
676
|
+
return experimental_wrapLanguageModel({
|
|
677
|
+
model: modelToWrap,
|
|
678
|
+
middleware: createAgentMiddleware(this)
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Resolves with an `AgentPlan` based on the information provided in the `options`, including:
|
|
683
|
+
*
|
|
684
|
+
* - The `goal` for the agent to achieve
|
|
685
|
+
* - The observed current `state`
|
|
686
|
+
* - The `machine` (e.g. a state machine) that specifies what can happen next
|
|
687
|
+
* - Additional `context`
|
|
688
|
+
*/
|
|
689
|
+
decide(opts) {
|
|
690
|
+
return agentDecide(this, opts);
|
|
691
|
+
}
|
|
692
|
+
};
|
|
578
693
|
export {
|
|
579
694
|
createAgent,
|
|
580
695
|
fromDecision,
|