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