@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/src/agent.ts
CHANGED
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Actor,
|
|
3
|
+
ActorRefLike,
|
|
2
4
|
AnyEventObject,
|
|
3
5
|
AnyStateMachine,
|
|
4
|
-
createActor,
|
|
5
6
|
EventObject,
|
|
6
7
|
fromTransition,
|
|
7
|
-
|
|
8
|
-
toObserver,
|
|
8
|
+
Subscription,
|
|
9
9
|
} from 'xstate';
|
|
10
10
|
import { ZodContextMapping, ZodEventMapping } from './schemas';
|
|
11
11
|
import {
|
|
12
|
-
Agent,
|
|
13
12
|
AgentLogic,
|
|
14
13
|
AgentMessage,
|
|
15
14
|
AgentPlanner,
|
|
16
15
|
EventsFromZodEventMapping,
|
|
17
16
|
GenerateTextOptions,
|
|
18
17
|
AgentLongTermMemory,
|
|
19
|
-
AIAdapter,
|
|
20
18
|
ObservedState,
|
|
21
19
|
AgentObservationInput,
|
|
22
20
|
AgentMemoryContext,
|
|
23
21
|
AgentObservation,
|
|
24
22
|
ContextFromZodContextMapping,
|
|
25
23
|
AgentFeedback,
|
|
24
|
+
AgentMessageInput,
|
|
25
|
+
AgentFeedbackInput,
|
|
26
|
+
AgentPlan,
|
|
27
|
+
Compute,
|
|
28
|
+
AgentDecisionInput,
|
|
29
|
+
AgentDecideOptions,
|
|
26
30
|
} from './types';
|
|
27
31
|
import { simplePlanner } from './planners/simplePlanner';
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
+
import { agentDecide } from './decide';
|
|
33
|
+
import { getMachineHash, isActorRef, randomId } from './utils';
|
|
34
|
+
import {
|
|
35
|
+
experimental_wrapLanguageModel,
|
|
36
|
+
LanguageModel,
|
|
37
|
+
LanguageModelV1,
|
|
38
|
+
} from 'ai';
|
|
39
|
+
import { createAgentMiddleware } from './middleware';
|
|
32
40
|
|
|
33
41
|
export const agentLogic: AgentLogic<AnyEventObject> = fromTransition(
|
|
34
42
|
(state, event, { emit }) => {
|
|
@@ -89,16 +97,16 @@ export function createAgent<
|
|
|
89
97
|
TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>,
|
|
90
98
|
TContext = ContextFromZodContextMapping<TContextSchema>
|
|
91
99
|
>({
|
|
100
|
+
id,
|
|
92
101
|
name,
|
|
93
102
|
description,
|
|
94
103
|
model,
|
|
95
104
|
events,
|
|
96
105
|
context,
|
|
97
|
-
planner = simplePlanner as AgentPlanner<Agent<
|
|
106
|
+
planner = simplePlanner as AgentPlanner<Agent<TContextSchema, TEventSchemas>>,
|
|
98
107
|
stringify = JSON.stringify,
|
|
99
108
|
getMemory,
|
|
100
109
|
logic = agentLogic as AgentLogic<TEvents>,
|
|
101
|
-
adapter = vercelAdapter,
|
|
102
110
|
...generateTextOptions
|
|
103
111
|
}: {
|
|
104
112
|
/**
|
|
@@ -130,110 +138,441 @@ export function createAgent<
|
|
|
130
138
|
*/
|
|
131
139
|
events: TEventSchemas;
|
|
132
140
|
context?: TContextSchema;
|
|
133
|
-
planner?: AgentPlanner<Agent<
|
|
141
|
+
planner?: AgentPlanner<Agent<TContextSchema, TEventSchemas>>;
|
|
134
142
|
stringify?: typeof JSON.stringify;
|
|
135
143
|
/**
|
|
136
144
|
* A function that retrieves the agent's long term memory
|
|
137
145
|
*/
|
|
138
|
-
getMemory?: (
|
|
146
|
+
getMemory?: (
|
|
147
|
+
agent: Agent<TContextSchema, TEventSchemas>
|
|
148
|
+
) => AgentLongTermMemory;
|
|
139
149
|
/**
|
|
140
150
|
* Agent logic
|
|
141
151
|
*/
|
|
142
152
|
logic?: AgentLogic<TEvents>;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
agent.
|
|
153
|
+
} & GenerateTextOptions): Agent<TContextSchema, TEventSchemas> {
|
|
154
|
+
return new Agent({
|
|
155
|
+
id,
|
|
156
|
+
context,
|
|
157
|
+
events,
|
|
158
|
+
name,
|
|
159
|
+
description,
|
|
160
|
+
planner,
|
|
161
|
+
model,
|
|
162
|
+
logic,
|
|
163
|
+
}) as any;
|
|
164
|
+
// const agent = createActor(logic) as unknown as Agent<TContext, TEvents>;
|
|
165
|
+
// agent.events = events;
|
|
166
|
+
// agent.model = model;
|
|
167
|
+
// agent.name = name;
|
|
168
|
+
// agent.description = description;
|
|
169
|
+
// agent.defaultOptions = { ...generateTextOptions, model };
|
|
170
|
+
// agent.memory = getMemory ? getMemory(agent) : undefined;
|
|
156
171
|
|
|
157
|
-
agent.onMessage = (callback) => {
|
|
158
|
-
|
|
159
|
-
};
|
|
172
|
+
// agent.onMessage = (callback) => {
|
|
173
|
+
// agent.on('message', (ev) => callback(ev.message));
|
|
174
|
+
// };
|
|
175
|
+
|
|
176
|
+
// agent.decide = (opts) => {
|
|
177
|
+
// return agentDecide(agent, opts);
|
|
178
|
+
// };
|
|
179
|
+
|
|
180
|
+
// agent.addMessage = (messageInput) => {
|
|
181
|
+
// const message = {
|
|
182
|
+
// ...messageInput,
|
|
183
|
+
// id: messageInput.id ?? randomId(),
|
|
184
|
+
// timestamp: messageInput.timestamp ?? Date.now(),
|
|
185
|
+
// sessionId: agent.sessionId,
|
|
186
|
+
// } satisfies AgentMessage;
|
|
187
|
+
// agent.send({
|
|
188
|
+
// type: 'agent.message',
|
|
189
|
+
// message,
|
|
190
|
+
// });
|
|
191
|
+
|
|
192
|
+
// return message;
|
|
193
|
+
// };
|
|
194
|
+
// agent.getMessages = () => agent.getSnapshot().context.messages;
|
|
195
|
+
|
|
196
|
+
// agent.addFeedback = (feedbackInput) => {
|
|
197
|
+
// const feedback = {
|
|
198
|
+
// ...feedbackInput,
|
|
199
|
+
// attributes: { ...feedbackInput.attributes },
|
|
200
|
+
// reward: feedbackInput.reward ?? 0,
|
|
201
|
+
// timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
202
|
+
// sessionId: agent.sessionId,
|
|
203
|
+
// } satisfies AgentFeedback;
|
|
204
|
+
// agent.send({
|
|
205
|
+
// type: 'agent.feedback',
|
|
206
|
+
// feedback,
|
|
207
|
+
// });
|
|
208
|
+
// return feedback;
|
|
209
|
+
// };
|
|
210
|
+
// agent.getFeedback = () => agent.getSnapshot().context.feedback;
|
|
211
|
+
|
|
212
|
+
// agent.addObservation = (observationInput) => {
|
|
213
|
+
// const { prevState, event, state } = observationInput;
|
|
214
|
+
// const observedState = { context: state.context, value: state.value };
|
|
215
|
+
// const observedPrevState = prevState
|
|
216
|
+
// ? {
|
|
217
|
+
// context: prevState.context,
|
|
218
|
+
// value: prevState.value,
|
|
219
|
+
// }
|
|
220
|
+
// : undefined;
|
|
221
|
+
// const observation = {
|
|
222
|
+
// prevState: observedPrevState,
|
|
223
|
+
// event,
|
|
224
|
+
// state: observedState,
|
|
225
|
+
// id: observationInput.id ?? randomId(),
|
|
226
|
+
// sessionId: agent.sessionId,
|
|
227
|
+
// timestamp: observationInput.timestamp ?? Date.now(),
|
|
228
|
+
// machineHash: observationInput.machine
|
|
229
|
+
// ? getMachineHash(observationInput.machine)
|
|
230
|
+
// : undefined,
|
|
231
|
+
// } satisfies AgentObservation<any>;
|
|
232
|
+
|
|
233
|
+
// agent.send({
|
|
234
|
+
// type: 'agent.observe',
|
|
235
|
+
// observation,
|
|
236
|
+
// });
|
|
237
|
+
|
|
238
|
+
// return observation;
|
|
239
|
+
// };
|
|
240
|
+
// agent.getObservations = () => agent.getSnapshot().context.observations;
|
|
241
|
+
|
|
242
|
+
// agent.addPlan = (plan) => {
|
|
243
|
+
// agent.send({
|
|
244
|
+
// type: 'agent.plan',
|
|
245
|
+
// plan,
|
|
246
|
+
// });
|
|
247
|
+
// };
|
|
248
|
+
// agent.getPlans = () => agent.getSnapshot().context.plans;
|
|
249
|
+
|
|
250
|
+
// agent.interact = ((actorRef, getInput) => {
|
|
251
|
+
// let prevState: ObservedState | undefined = undefined;
|
|
252
|
+
// let subscribed = true;
|
|
253
|
+
|
|
254
|
+
// async function handleObservation(observationInput: AgentObservationInput) {
|
|
255
|
+
// const observation = agent.addObservation(observationInput);
|
|
256
|
+
|
|
257
|
+
// const input = getInput?.(observation);
|
|
258
|
+
|
|
259
|
+
// if (input) {
|
|
260
|
+
// await agentDecide(agent, {
|
|
261
|
+
// machine: actorRef.src as AnyStateMachine,
|
|
262
|
+
// state: observation.state,
|
|
263
|
+
// execute: async (event) => {
|
|
264
|
+
// actorRef.send(event);
|
|
265
|
+
// },
|
|
266
|
+
// ...input,
|
|
267
|
+
// });
|
|
268
|
+
// }
|
|
269
|
+
|
|
270
|
+
// prevState = observationInput.state;
|
|
271
|
+
// }
|
|
272
|
+
|
|
273
|
+
// // Inspect system, but only observe specified actor
|
|
274
|
+
// const sub = actorRef.system.inspect({
|
|
275
|
+
// next: async (inspEvent) => {
|
|
276
|
+
// if (
|
|
277
|
+
// !subscribed ||
|
|
278
|
+
// inspEvent.actorRef !== actorRef ||
|
|
279
|
+
// inspEvent.type !== '@xstate.snapshot'
|
|
280
|
+
// ) {
|
|
281
|
+
// return;
|
|
282
|
+
// }
|
|
283
|
+
|
|
284
|
+
// const observationInput = {
|
|
285
|
+
// event: inspEvent.event,
|
|
286
|
+
// prevState,
|
|
287
|
+
// state: inspEvent.snapshot as any,
|
|
288
|
+
// machine: (actorRef as any).src,
|
|
289
|
+
// } satisfies AgentObservationInput;
|
|
290
|
+
|
|
291
|
+
// await handleObservation(observationInput);
|
|
292
|
+
// },
|
|
293
|
+
// });
|
|
294
|
+
|
|
295
|
+
// // If actor already started, interact with current state
|
|
296
|
+
// if ((actorRef as any)._processingStatus === 1) {
|
|
297
|
+
// handleObservation({
|
|
298
|
+
// prevState: undefined,
|
|
299
|
+
// event: { type: '' }, // TODO: unknown events?
|
|
300
|
+
// state: actorRef.getSnapshot(),
|
|
301
|
+
// machine: (actorRef as any).src,
|
|
302
|
+
// });
|
|
303
|
+
// }
|
|
304
|
+
|
|
305
|
+
// return {
|
|
306
|
+
// unsubscribe: () => {
|
|
307
|
+
// sub.unsubscribe();
|
|
308
|
+
// subscribed = false;
|
|
309
|
+
// },
|
|
310
|
+
// };
|
|
311
|
+
// }) as typeof agent.interact;
|
|
312
|
+
|
|
313
|
+
// agent.observe = (actorRef) => {
|
|
314
|
+
// let prevState: ObservedState = actorRef.getSnapshot();
|
|
315
|
+
|
|
316
|
+
// const sub = actorRef.system.inspect({
|
|
317
|
+
// next: async (inspEvent) => {
|
|
318
|
+
// if (
|
|
319
|
+
// inspEvent.actorRef !== actorRef ||
|
|
320
|
+
// inspEvent.type !== '@xstate.snapshot'
|
|
321
|
+
// ) {
|
|
322
|
+
// return;
|
|
323
|
+
// }
|
|
324
|
+
|
|
325
|
+
// const observationInput = {
|
|
326
|
+
// event: inspEvent.event,
|
|
327
|
+
// prevState,
|
|
328
|
+
// state: inspEvent.snapshot as any,
|
|
329
|
+
// machine: (actorRef as any).src,
|
|
330
|
+
// } satisfies AgentObservationInput;
|
|
331
|
+
|
|
332
|
+
// prevState = observationInput.state;
|
|
160
333
|
|
|
161
|
-
agent.
|
|
162
|
-
|
|
334
|
+
// agent.addObservation(observationInput);
|
|
335
|
+
// },
|
|
336
|
+
// });
|
|
337
|
+
|
|
338
|
+
// return sub;
|
|
339
|
+
// };
|
|
340
|
+
|
|
341
|
+
// agent.types = {} as any;
|
|
342
|
+
|
|
343
|
+
// agent.wrap = (modelToWrap) =>
|
|
344
|
+
// experimental_wrapLanguageModel({
|
|
345
|
+
// model: modelToWrap,
|
|
346
|
+
// middleware: createAgentMiddleware(agent),
|
|
347
|
+
// });
|
|
348
|
+
|
|
349
|
+
// agent.model = experimental_wrapLanguageModel({
|
|
350
|
+
// model,
|
|
351
|
+
// middleware: createAgentMiddleware(agent),
|
|
352
|
+
// });
|
|
353
|
+
|
|
354
|
+
// agent.start();
|
|
355
|
+
|
|
356
|
+
// return agent;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export class Agent<
|
|
360
|
+
const TContextSchema extends ZodContextMapping,
|
|
361
|
+
const TEventSchemas extends ZodEventMapping,
|
|
362
|
+
TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>,
|
|
363
|
+
TContext = ContextFromZodContextMapping<TContextSchema>
|
|
364
|
+
> extends Actor<AgentLogic<TEvents>> {
|
|
365
|
+
/**
|
|
366
|
+
* The name of the agent. All agents with the same name are related and
|
|
367
|
+
* able to share experiences (observations, feedback) with each other.
|
|
368
|
+
*/
|
|
369
|
+
public name?: string;
|
|
370
|
+
/**
|
|
371
|
+
* The unique identifier for the agent.
|
|
372
|
+
*/
|
|
373
|
+
public episodeId: string;
|
|
374
|
+
public description?: string;
|
|
375
|
+
public events: TEventSchemas;
|
|
376
|
+
public context?: TContextSchema;
|
|
377
|
+
public planner?: AgentPlanner<Agent<TContextSchema, TEventSchemas>>;
|
|
378
|
+
public types: {
|
|
379
|
+
events: TEvents;
|
|
380
|
+
context: Compute<TContext>;
|
|
163
381
|
};
|
|
382
|
+
public model: LanguageModel;
|
|
383
|
+
public memory: AgentLongTermMemory | undefined;
|
|
384
|
+
public defaultOptions: any; // todo
|
|
385
|
+
|
|
386
|
+
constructor({
|
|
387
|
+
logic = agentLogic as AgentLogic<TEvents>,
|
|
388
|
+
id,
|
|
389
|
+
name,
|
|
390
|
+
description,
|
|
391
|
+
model,
|
|
392
|
+
events,
|
|
393
|
+
context,
|
|
394
|
+
planner = simplePlanner,
|
|
395
|
+
}: {
|
|
396
|
+
logic: AgentLogic<TEvents>;
|
|
397
|
+
id?: string;
|
|
398
|
+
name?: string;
|
|
399
|
+
description?: string;
|
|
400
|
+
model: GenerateTextOptions['model'];
|
|
401
|
+
events: TEventSchemas;
|
|
402
|
+
context?: TContextSchema;
|
|
403
|
+
planner?: AgentPlanner<Agent<TContextSchema, TEventSchemas>>;
|
|
404
|
+
}) {
|
|
405
|
+
super(logic);
|
|
406
|
+
this.model = model;
|
|
407
|
+
this.episodeId = id ?? randomId();
|
|
408
|
+
this.name = name;
|
|
409
|
+
this.description = description;
|
|
410
|
+
this.events = events;
|
|
411
|
+
this.context = context;
|
|
412
|
+
this.planner = planner;
|
|
413
|
+
this.types = {} as any;
|
|
164
414
|
|
|
165
|
-
|
|
415
|
+
this.start();
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Called whenever the agent (LLM assistant) receives or sends a message.
|
|
420
|
+
*/
|
|
421
|
+
public onMessage(fn: (message: AgentMessage) => void) {
|
|
422
|
+
return this.on('message', (ev) => fn(ev.message));
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Retrieves messages from the agent's short-term (local) memory.
|
|
427
|
+
*/
|
|
428
|
+
public addMessage(messageInput: AgentMessageInput) {
|
|
166
429
|
const message = {
|
|
167
430
|
...messageInput,
|
|
168
431
|
id: messageInput.id ?? randomId(),
|
|
169
432
|
timestamp: messageInput.timestamp ?? Date.now(),
|
|
170
|
-
|
|
171
|
-
correlationId: messageInput.correlationId ?? randomId(),
|
|
433
|
+
episodeId: this.episodeId,
|
|
172
434
|
} satisfies AgentMessage;
|
|
173
|
-
|
|
435
|
+
this.send({
|
|
174
436
|
type: 'agent.message',
|
|
175
437
|
message,
|
|
176
438
|
});
|
|
177
439
|
|
|
178
440
|
return message;
|
|
179
|
-
}
|
|
180
|
-
agent.getMessages = () => agent.getSnapshot().context.messages;
|
|
181
|
-
|
|
182
|
-
agent.generateText = (opts) => agentGenerateText(agent, opts);
|
|
441
|
+
}
|
|
183
442
|
|
|
184
|
-
|
|
443
|
+
public getMessages() {
|
|
444
|
+
return this.getSnapshot().context.messages;
|
|
445
|
+
}
|
|
185
446
|
|
|
186
|
-
|
|
447
|
+
public addFeedback(feedbackInput: AgentFeedbackInput) {
|
|
187
448
|
const feedback = {
|
|
188
449
|
...feedbackInput,
|
|
189
450
|
attributes: { ...feedbackInput.attributes },
|
|
190
451
|
reward: feedbackInput.reward ?? 0,
|
|
191
452
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
192
|
-
|
|
453
|
+
episodeId: this.episodeId,
|
|
193
454
|
} satisfies AgentFeedback;
|
|
194
|
-
|
|
455
|
+
this.send({
|
|
195
456
|
type: 'agent.feedback',
|
|
196
457
|
feedback,
|
|
197
458
|
});
|
|
198
459
|
return feedback;
|
|
199
|
-
}
|
|
200
|
-
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Retrieves feedback from the agent's short-term (local) memory.
|
|
464
|
+
*/
|
|
465
|
+
public getFeedback() {
|
|
466
|
+
return this.getSnapshot().context.feedback;
|
|
467
|
+
}
|
|
201
468
|
|
|
202
|
-
|
|
469
|
+
public addObservation(
|
|
470
|
+
observationInput: AgentObservationInput
|
|
471
|
+
): AgentObservation<any> {
|
|
203
472
|
const { prevState, event, state } = observationInput;
|
|
204
473
|
const observation = {
|
|
205
474
|
prevState,
|
|
206
475
|
event,
|
|
207
476
|
state,
|
|
208
477
|
id: observationInput.id ?? randomId(),
|
|
209
|
-
|
|
478
|
+
episodeId: this.episodeId,
|
|
210
479
|
timestamp: observationInput.timestamp ?? Date.now(),
|
|
211
480
|
machineHash: observationInput.machine
|
|
212
481
|
? getMachineHash(observationInput.machine)
|
|
213
482
|
: undefined,
|
|
214
483
|
} satisfies AgentObservation<any>;
|
|
215
484
|
|
|
216
|
-
|
|
485
|
+
this.send({
|
|
217
486
|
type: 'agent.observe',
|
|
218
487
|
observation,
|
|
219
488
|
});
|
|
220
489
|
|
|
221
490
|
return observation;
|
|
222
|
-
}
|
|
223
|
-
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Retrieves observations from the agent's short-term (local) memory.
|
|
495
|
+
*/
|
|
496
|
+
public getObservations() {
|
|
497
|
+
return this.getSnapshot().context.observations;
|
|
498
|
+
}
|
|
224
499
|
|
|
225
|
-
|
|
226
|
-
|
|
500
|
+
public addPlan(plan: AgentPlan<TEvents>) {
|
|
501
|
+
this.send({
|
|
227
502
|
type: 'agent.plan',
|
|
228
503
|
plan,
|
|
229
504
|
});
|
|
230
|
-
}
|
|
231
|
-
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Retrieves strategies from the agent's short-term (local) memory.
|
|
508
|
+
*/
|
|
509
|
+
public getPlans() {
|
|
510
|
+
return this.getSnapshot().context.plans;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Interacts with this state machine actor by inspecting state transitions and storing them as observations.
|
|
515
|
+
*
|
|
516
|
+
* Observations contain the `prevState`, `event`, and current `state` of this
|
|
517
|
+
* actor, as well as other properties that are useful when recalled.
|
|
518
|
+
* These observations are stored in the `agent`'s short-term (local) memory
|
|
519
|
+
* and can be retrieved via `agent.getObservations()`.
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* ```ts
|
|
523
|
+
* // Only observes the actor's state transitions
|
|
524
|
+
* agent.interact(actor);
|
|
525
|
+
*
|
|
526
|
+
* actor.start();
|
|
527
|
+
* ```
|
|
528
|
+
*/
|
|
529
|
+
public interact<TActor extends ActorRefLike>(actorRef: TActor): Subscription;
|
|
530
|
+
/**
|
|
531
|
+
* Interacts with this state machine actor by:
|
|
532
|
+
* 1. Inspecting state transitions and storing them as observations
|
|
533
|
+
* 2. Deciding what to do next (which event to send the actor) based on
|
|
534
|
+
* the agent input returned from `getInput(observation)`, if `getInput(…)` is provided as the 2nd argument.
|
|
535
|
+
*
|
|
536
|
+
* Observations contain the `prevState`, `event`, and current `state` of this
|
|
537
|
+
* actor, as well as other properties that are useful when recalled.
|
|
538
|
+
* These observations are stored in the `agent`'s short-term (local) memory
|
|
539
|
+
* and can be retrieved via `agent.getObservations()`.
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```ts
|
|
543
|
+
* // Observes the actor's state transitions and
|
|
544
|
+
* // makes a decision if on the "summarize" state
|
|
545
|
+
* agent.interact(actor, observed => {
|
|
546
|
+
* if (observed.state.matches('summarize')) {
|
|
547
|
+
* return {
|
|
548
|
+
* context: observed.state.context,
|
|
549
|
+
* goal: 'Summarize the message'
|
|
550
|
+
* }
|
|
551
|
+
* }
|
|
552
|
+
* });
|
|
553
|
+
*
|
|
554
|
+
* actor.start();
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
public interact<TActor extends ActorRefLike>(
|
|
558
|
+
actorRef: TActor,
|
|
559
|
+
getInput: (
|
|
560
|
+
observation: AgentObservation<TActor>
|
|
561
|
+
) => AgentDecisionInput | undefined
|
|
562
|
+
): Subscription;
|
|
563
|
+
public interact<TActor extends ActorRefLike>(
|
|
564
|
+
actorRef: TActor,
|
|
565
|
+
getInput?: (
|
|
566
|
+
observation: AgentObservation<TActor>
|
|
567
|
+
) => AgentDecisionInput | undefined
|
|
568
|
+
): Subscription {
|
|
569
|
+
const actorRefCheck = isActorRef(actorRef);
|
|
232
570
|
|
|
233
|
-
agent.interact = ((actorRef, getInput) => {
|
|
234
571
|
let prevState: ObservedState | undefined = undefined;
|
|
235
572
|
let subscribed = true;
|
|
236
573
|
|
|
574
|
+
const agent = this;
|
|
575
|
+
|
|
237
576
|
async function handleObservation(observationInput: AgentObservationInput) {
|
|
238
577
|
const observation = agent.addObservation(observationInput);
|
|
239
578
|
|
|
@@ -241,7 +580,9 @@ export function createAgent<
|
|
|
241
580
|
|
|
242
581
|
if (input) {
|
|
243
582
|
await agentDecide(agent, {
|
|
244
|
-
machine:
|
|
583
|
+
machine: actorRefCheck
|
|
584
|
+
? (actorRef.src as AnyStateMachine)
|
|
585
|
+
: undefined,
|
|
245
586
|
state: observation.state,
|
|
246
587
|
execute: async (event) => {
|
|
247
588
|
actorRef.send(event);
|
|
@@ -254,26 +595,28 @@ export function createAgent<
|
|
|
254
595
|
}
|
|
255
596
|
|
|
256
597
|
// Inspect system, but only observe specified actor
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
598
|
+
const sub = actorRefCheck
|
|
599
|
+
? actorRef.system.inspect({
|
|
600
|
+
next: async (inspEvent) => {
|
|
601
|
+
if (
|
|
602
|
+
!subscribed ||
|
|
603
|
+
inspEvent.actorRef !== actorRef ||
|
|
604
|
+
inspEvent.type !== '@xstate.snapshot'
|
|
605
|
+
) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const observationInput = {
|
|
610
|
+
event: inspEvent.event,
|
|
611
|
+
prevState,
|
|
612
|
+
state: inspEvent.snapshot as any,
|
|
613
|
+
machine: (actorRef as any).src,
|
|
614
|
+
} satisfies AgentObservationInput;
|
|
615
|
+
|
|
616
|
+
await handleObservation(observationInput);
|
|
617
|
+
},
|
|
618
|
+
})
|
|
619
|
+
: undefined;
|
|
277
620
|
|
|
278
621
|
// If actor already started, interact with current state
|
|
279
622
|
if ((actorRef as any)._processingStatus === 1) {
|
|
@@ -287,14 +630,59 @@ export function createAgent<
|
|
|
287
630
|
|
|
288
631
|
return {
|
|
289
632
|
unsubscribe: () => {
|
|
633
|
+
sub?.unsubscribe();
|
|
290
634
|
subscribed = false;
|
|
291
|
-
},
|
|
635
|
+
},
|
|
292
636
|
};
|
|
293
|
-
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
public observe<TActor extends ActorRefLike>(actorRef: TActor): Subscription {
|
|
640
|
+
let prevState: ObservedState = actorRef.getSnapshot();
|
|
641
|
+
const actorRefCheck = isActorRef(actorRef);
|
|
642
|
+
|
|
643
|
+
const sub = actorRefCheck
|
|
644
|
+
? actorRef.system.inspect({
|
|
645
|
+
next: async (inspEvent) => {
|
|
646
|
+
if (
|
|
647
|
+
inspEvent.actorRef !== actorRef ||
|
|
648
|
+
inspEvent.type !== '@xstate.snapshot'
|
|
649
|
+
) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
const observationInput = {
|
|
654
|
+
event: inspEvent.event,
|
|
655
|
+
prevState,
|
|
656
|
+
state: inspEvent.snapshot as any,
|
|
657
|
+
machine: (actorRef as any).src,
|
|
658
|
+
} satisfies AgentObservationInput;
|
|
659
|
+
|
|
660
|
+
prevState = observationInput.state;
|
|
294
661
|
|
|
295
|
-
|
|
662
|
+
this.addObservation(observationInput);
|
|
663
|
+
},
|
|
664
|
+
})
|
|
665
|
+
: undefined;
|
|
666
|
+
|
|
667
|
+
return sub ?? { unsubscribe: () => {} };
|
|
668
|
+
}
|
|
296
669
|
|
|
297
|
-
|
|
670
|
+
public wrap(modelToWrap: LanguageModelV1) {
|
|
671
|
+
return experimental_wrapLanguageModel({
|
|
672
|
+
model: modelToWrap,
|
|
673
|
+
middleware: createAgentMiddleware(this),
|
|
674
|
+
});
|
|
675
|
+
}
|
|
298
676
|
|
|
299
|
-
|
|
677
|
+
/**
|
|
678
|
+
* Resolves with an `AgentPlan` based on the information provided in the `options`, including:
|
|
679
|
+
*
|
|
680
|
+
* - The `goal` for the agent to achieve
|
|
681
|
+
* - The observed current `state`
|
|
682
|
+
* - The `machine` (e.g. a state machine) that specifies what can happen next
|
|
683
|
+
* - Additional `context`
|
|
684
|
+
*/
|
|
685
|
+
public decide(opts: AgentDecideOptions) {
|
|
686
|
+
return agentDecide(this, opts);
|
|
687
|
+
}
|
|
300
688
|
}
|