@statelyai/agent 1.1.6 → 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 +10 -0
- package/dist/index.d.mts +262 -165
- package/dist/index.d.ts +262 -165
- package/dist/index.js +368 -263
- package/dist/index.mjs +371 -261
- 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 +13 -10
- 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 -144
- 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,120 +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
|
-
steps: res.steps,
|
|
176
|
-
response: res.response,
|
|
177
|
-
experimental_providerMetadata: res.experimental_providerMetadata
|
|
178
|
-
},
|
|
179
|
-
content: res.text,
|
|
180
|
-
id: randomId(),
|
|
181
|
-
timestamp: Date.now(),
|
|
182
|
-
responseId: id,
|
|
183
|
-
correlationId: resolvedOptions.correlationId,
|
|
184
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
return {
|
|
189
|
-
...result,
|
|
190
|
-
textStream: result.textStream,
|
|
191
|
-
fullStream: result.fullStream,
|
|
192
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
193
|
-
correlationId: resolvedOptions.correlationId
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
function fromTextStream(agent, defaultOptions) {
|
|
112
|
+
function fromTextStream(agent, options) {
|
|
113
|
+
const template = options?.template ?? defaultTextTemplate;
|
|
197
114
|
return fromObservable(({ input }) => {
|
|
198
115
|
const observers = /* @__PURE__ */ new Set();
|
|
199
116
|
(async () => {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
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,
|
|
203
121
|
context: input.context
|
|
204
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
|
+
});
|
|
205
132
|
for await (const part of result.fullStream) {
|
|
206
133
|
if (part.type === "text-delta") {
|
|
207
134
|
observers.forEach((observer) => {
|
|
@@ -223,32 +150,89 @@ function fromTextStream(agent, defaultOptions) {
|
|
|
223
150
|
};
|
|
224
151
|
});
|
|
225
152
|
}
|
|
226
|
-
function fromText(agent,
|
|
153
|
+
function fromText(agent, options) {
|
|
154
|
+
const resolvedOptions = {
|
|
155
|
+
...agent.defaultOptions,
|
|
156
|
+
...options
|
|
157
|
+
};
|
|
158
|
+
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
227
159
|
return fromPromise(async ({ input }) => {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
160
|
+
const goal = typeof input.prompt === "string" ? input.prompt : await input.prompt(agent);
|
|
161
|
+
const promptWithContext = template({
|
|
162
|
+
goal,
|
|
231
163
|
context: input.context
|
|
232
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
|
+
});
|
|
233
174
|
});
|
|
234
175
|
}
|
|
235
176
|
|
|
236
|
-
// src/
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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);
|
|
240
205
|
}
|
|
241
|
-
|
|
242
|
-
return getAllTransitions(resolvedState);
|
|
206
|
+
return plan;
|
|
243
207
|
}
|
|
244
|
-
|
|
245
|
-
return
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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) {
|
|
252
236
|
const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
|
|
253
237
|
eventType,
|
|
254
238
|
description
|
|
@@ -288,17 +272,55 @@ async function simplePlanner(agent, input) {
|
|
|
288
272
|
if (!Object.keys(toolMap).length) {
|
|
289
273
|
return void 0;
|
|
290
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
|
+
}
|
|
291
291
|
const prompt = simplePlannerPromptTemplate({
|
|
292
292
|
context: input.state.context,
|
|
293
293
|
goal: input.goal
|
|
294
294
|
});
|
|
295
295
|
const messages = await getMessages(agent, prompt, input);
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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,
|
|
300
313
|
messages,
|
|
301
|
-
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
|
+
});
|
|
302
324
|
});
|
|
303
325
|
const singleResult = result.toolResults[0];
|
|
304
326
|
if (!singleResult) {
|
|
@@ -306,89 +328,100 @@ async function simplePlanner(agent, input) {
|
|
|
306
328
|
return void 0;
|
|
307
329
|
}
|
|
308
330
|
return {
|
|
331
|
+
planner: "simple",
|
|
309
332
|
goal: input.goal,
|
|
310
|
-
|
|
311
|
-
execute: async (state) => {
|
|
312
|
-
if (JSON.stringify(state) === JSON.stringify(input.state)) {
|
|
313
|
-
return singleResult.result;
|
|
314
|
-
}
|
|
315
|
-
return void 0;
|
|
316
|
-
},
|
|
333
|
+
goalState: input.state,
|
|
317
334
|
nextEvent: singleResult.result,
|
|
318
|
-
|
|
319
|
-
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
|
+
]
|
|
320
348
|
};
|
|
321
349
|
}
|
|
322
350
|
|
|
323
|
-
// src/
|
|
324
|
-
import {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
+
};
|
|
358
420
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const resolvedInput = {
|
|
362
|
-
...defaultInput,
|
|
363
|
-
...inputObject
|
|
364
|
-
};
|
|
365
|
-
const contextToInclude = resolvedInput.context === true ? (
|
|
366
|
-
// include entire context
|
|
367
|
-
parentRef.getSnapshot().context
|
|
368
|
-
) : resolvedInput.context;
|
|
369
|
-
const state = {
|
|
370
|
-
value: snapshot.value,
|
|
371
|
-
context: contextToInclude
|
|
372
|
-
};
|
|
373
|
-
const plan = await agentDecide(agent, {
|
|
374
|
-
machine: parentRef.logic,
|
|
375
|
-
state,
|
|
376
|
-
execute: async (event) => {
|
|
377
|
-
parentRef.send(event);
|
|
378
|
-
},
|
|
379
|
-
...resolvedInput
|
|
380
|
-
});
|
|
381
|
-
return plan;
|
|
382
|
-
});
|
|
421
|
+
};
|
|
422
|
+
return middleware;
|
|
383
423
|
}
|
|
384
424
|
|
|
385
|
-
// src/adapters/vercel.ts
|
|
386
|
-
import { generateText, streamText } from "ai";
|
|
387
|
-
var vercelAdapter = {
|
|
388
|
-
generateText,
|
|
389
|
-
streamText
|
|
390
|
-
};
|
|
391
|
-
|
|
392
425
|
// src/agent.ts
|
|
393
426
|
var agentLogic = fromTransition(
|
|
394
427
|
(state, event, { emit }) => {
|
|
@@ -442,6 +475,7 @@ var agentLogic = fromTransition(
|
|
|
442
475
|
})
|
|
443
476
|
);
|
|
444
477
|
function createAgent({
|
|
478
|
+
id,
|
|
445
479
|
name,
|
|
446
480
|
description,
|
|
447
481
|
model,
|
|
@@ -451,92 +485,133 @@ function createAgent({
|
|
|
451
485
|
stringify = JSON.stringify,
|
|
452
486
|
getMemory,
|
|
453
487
|
logic = agentLogic,
|
|
454
|
-
adapter = vercelAdapter,
|
|
455
488
|
...generateTextOptions
|
|
456
489
|
}) {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
};
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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) {
|
|
475
534
|
const message = {
|
|
476
535
|
...messageInput,
|
|
477
536
|
id: messageInput.id ?? randomId(),
|
|
478
537
|
timestamp: messageInput.timestamp ?? Date.now(),
|
|
479
|
-
|
|
480
|
-
correlationId: messageInput.correlationId ?? randomId()
|
|
538
|
+
episodeId: this.episodeId
|
|
481
539
|
};
|
|
482
|
-
|
|
540
|
+
this.send({
|
|
483
541
|
type: "agent.message",
|
|
484
542
|
message
|
|
485
543
|
});
|
|
486
544
|
return message;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
545
|
+
}
|
|
546
|
+
getMessages() {
|
|
547
|
+
return this.getSnapshot().context.messages;
|
|
548
|
+
}
|
|
549
|
+
addFeedback(feedbackInput) {
|
|
492
550
|
const feedback = {
|
|
493
551
|
...feedbackInput,
|
|
494
552
|
attributes: { ...feedbackInput.attributes },
|
|
495
553
|
reward: feedbackInput.reward ?? 0,
|
|
496
554
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
497
|
-
|
|
555
|
+
episodeId: this.episodeId
|
|
498
556
|
};
|
|
499
|
-
|
|
557
|
+
this.send({
|
|
500
558
|
type: "agent.feedback",
|
|
501
559
|
feedback
|
|
502
560
|
});
|
|
503
561
|
return feedback;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
|
|
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) {
|
|
507
570
|
const { prevState, event, state } = observationInput;
|
|
508
571
|
const observation = {
|
|
509
572
|
prevState,
|
|
510
573
|
event,
|
|
511
574
|
state,
|
|
512
575
|
id: observationInput.id ?? randomId(),
|
|
513
|
-
|
|
576
|
+
episodeId: this.episodeId,
|
|
514
577
|
timestamp: observationInput.timestamp ?? Date.now(),
|
|
515
578
|
machineHash: observationInput.machine ? getMachineHash(observationInput.machine) : void 0
|
|
516
579
|
};
|
|
517
|
-
|
|
580
|
+
this.send({
|
|
518
581
|
type: "agent.observe",
|
|
519
582
|
observation
|
|
520
583
|
});
|
|
521
584
|
return observation;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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({
|
|
526
594
|
type: "agent.plan",
|
|
527
595
|
plan
|
|
528
596
|
});
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
|
|
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);
|
|
532
606
|
let prevState = void 0;
|
|
533
607
|
let subscribed = true;
|
|
608
|
+
const agent = this;
|
|
534
609
|
async function handleObservation(observationInput) {
|
|
535
610
|
const observation = agent.addObservation(observationInput);
|
|
536
611
|
const input = getInput?.(observation);
|
|
537
612
|
if (input) {
|
|
538
613
|
await agentDecide(agent, {
|
|
539
|
-
machine: actorRef.src,
|
|
614
|
+
machine: actorRefCheck ? actorRef.src : void 0,
|
|
540
615
|
state: observation.state,
|
|
541
616
|
execute: async (event) => {
|
|
542
617
|
actorRef.send(event);
|
|
@@ -546,7 +621,7 @@ function createAgent({
|
|
|
546
621
|
}
|
|
547
622
|
prevState = observationInput.state;
|
|
548
623
|
}
|
|
549
|
-
actorRef.system.inspect({
|
|
624
|
+
const sub = actorRefCheck ? actorRef.system.inspect({
|
|
550
625
|
next: async (inspEvent) => {
|
|
551
626
|
if (!subscribed || inspEvent.actorRef !== actorRef || inspEvent.type !== "@xstate.snapshot") {
|
|
552
627
|
return;
|
|
@@ -559,7 +634,7 @@ function createAgent({
|
|
|
559
634
|
};
|
|
560
635
|
await handleObservation(observationInput);
|
|
561
636
|
}
|
|
562
|
-
});
|
|
637
|
+
}) : void 0;
|
|
563
638
|
if (actorRef._processingStatus === 1) {
|
|
564
639
|
handleObservation({
|
|
565
640
|
prevState: void 0,
|
|
@@ -571,15 +646,50 @@ function createAgent({
|
|
|
571
646
|
}
|
|
572
647
|
return {
|
|
573
648
|
unsubscribe: () => {
|
|
649
|
+
sub?.unsubscribe();
|
|
574
650
|
subscribed = false;
|
|
575
651
|
}
|
|
576
|
-
// TODO: make this actually unsubscribe
|
|
577
652
|
};
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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
|
+
};
|
|
583
693
|
export {
|
|
584
694
|
createAgent,
|
|
585
695
|
fromDecision,
|