@statelyai/agent 1.0.0-beta.1 → 1.1.2
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/.env.template +0 -3
- package/.github/actions/ci-setup/action.yml +11 -11
- package/.github/workflows/release.yml +19 -7
- package/CHANGELOG.md +85 -0
- package/dist/index.d.mts +164 -54
- package/dist/index.d.ts +164 -54
- package/dist/index.js +190 -117
- package/dist/index.mjs +181 -117
- package/examples/chatbot.ts +9 -17
- package/examples/cot.ts +5 -7
- package/examples/email.ts +2 -2
- package/examples/example.ts +7 -7
- package/examples/goal.ts +1 -1
- package/examples/joke.ts +8 -10
- package/examples/number.ts +1 -1
- package/examples/raffle.ts +1 -1
- package/examples/sandbox.ts +28 -0
- package/examples/support.ts +1 -1
- package/examples/ticTacToe.ts +18 -21
- package/examples/todo.ts +3 -1
- package/examples/tutor.ts +1 -1
- package/examples/verify.ts +1 -1
- package/examples/weather.ts +1 -1
- package/examples/wiki.ts +1 -1
- package/examples/word.ts +1 -1
- package/package.json +22 -22
- package/readme.md +1 -4
- package/src/agent.test.ts +324 -5
- package/src/agent.ts +64 -26
- package/src/decision.ts +6 -5
- package/src/index.ts +2 -2
- package/src/planners/shortestPathPlanner.ts +2 -2
- package/src/planners/simplePlanner.ts +22 -12
- package/src/schemas.ts +4 -8
- package/src/strategies/chain-of-note.ts +3 -3
- package/src/text.ts +42 -37
- package/src/types.ts +146 -42
- package/src/utils.ts +53 -9
- package/.changeset/shaggy-buttons-itch.md +0 -5
- package/src/templates/defaultToolCall.ts +0 -10
package/src/types.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
streamText,
|
|
23
23
|
StreamTextResult,
|
|
24
24
|
} from 'ai';
|
|
25
|
-
import { ZodEventMapping } from './schemas';
|
|
25
|
+
import { ZodContextMapping, ZodEventMapping } from './schemas';
|
|
26
26
|
import { TypeOf } from 'zod';
|
|
27
27
|
|
|
28
28
|
export type GenerateTextOptions = Parameters<typeof generateText>[0];
|
|
@@ -62,10 +62,11 @@ export type AgentPlan<TEvent extends EventObject> = {
|
|
|
62
62
|
goal: string;
|
|
63
63
|
state: ObservedState;
|
|
64
64
|
content?: string;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Executes the plan based on the given `state` and resolves with
|
|
67
|
+
* a potential next `event` to trigger to achieve the `goal`.
|
|
68
|
+
*/
|
|
69
|
+
execute: (state: ObservedState) => Promise<TEvent | undefined>;
|
|
69
70
|
nextEvent: TEvent | undefined;
|
|
70
71
|
sessionId: string;
|
|
71
72
|
timestamp: number;
|
|
@@ -103,14 +104,14 @@ export type PromptTemplate<TEvents extends EventObject> = (data: {
|
|
|
103
104
|
*/
|
|
104
105
|
observations?: AgentObservation<any>[]; // TODO
|
|
105
106
|
feedback?: AgentFeedback[];
|
|
106
|
-
messages?:
|
|
107
|
+
messages?: AgentMessage[];
|
|
107
108
|
plans?: AgentPlan<TEvents>[];
|
|
108
109
|
}) => string;
|
|
109
110
|
|
|
110
|
-
export type AgentPlanner<T extends
|
|
111
|
-
agent: T
|
|
112
|
-
|
|
113
|
-
) => Promise<AgentPlan<T['
|
|
111
|
+
export type AgentPlanner<T extends AnyAgent> = (
|
|
112
|
+
agent: T,
|
|
113
|
+
input: AgentPlanInput<T['types']['events']>
|
|
114
|
+
) => Promise<AgentPlan<T['types']['events']> | undefined>;
|
|
114
115
|
|
|
115
116
|
export type AgentDecideOptions = {
|
|
116
117
|
goal: string;
|
|
@@ -127,21 +128,28 @@ export type AgentDecideOptions = {
|
|
|
127
128
|
>;
|
|
128
129
|
|
|
129
130
|
export interface AgentFeedback {
|
|
130
|
-
goal
|
|
131
|
-
observationId
|
|
131
|
+
goal?: string;
|
|
132
|
+
observationId?: string;
|
|
133
|
+
/**
|
|
134
|
+
* The message correlation that the feedback is relevant for
|
|
135
|
+
*/
|
|
136
|
+
correlationId?: string;
|
|
132
137
|
attributes: Record<string, any>;
|
|
138
|
+
reward: number;
|
|
133
139
|
timestamp: number;
|
|
134
140
|
sessionId: string;
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
export interface AgentFeedbackInput {
|
|
138
|
-
goal
|
|
139
|
-
observationId
|
|
140
|
-
|
|
144
|
+
goal?: string;
|
|
145
|
+
observationId?: string;
|
|
146
|
+
correlationId?: string;
|
|
147
|
+
attributes?: Record<string, any>;
|
|
141
148
|
timestamp?: number;
|
|
149
|
+
reward?: number;
|
|
142
150
|
}
|
|
143
151
|
|
|
144
|
-
export type
|
|
152
|
+
export type AgentMessage = CoreMessage & {
|
|
145
153
|
timestamp: number;
|
|
146
154
|
id: string;
|
|
147
155
|
/**
|
|
@@ -151,9 +159,11 @@ export type AgentMessageHistory = CoreMessage & {
|
|
|
151
159
|
responseId?: string;
|
|
152
160
|
result?: GenerateTextResult<any>;
|
|
153
161
|
sessionId: string;
|
|
162
|
+
correlationId: string;
|
|
163
|
+
parentCorrelationId?: string;
|
|
154
164
|
};
|
|
155
165
|
|
|
156
|
-
export type
|
|
166
|
+
export type AgentMessageInput = CoreMessage & {
|
|
157
167
|
timestamp?: number;
|
|
158
168
|
id?: string;
|
|
159
169
|
/**
|
|
@@ -161,6 +171,8 @@ export type AgentMessageHistoryInput = CoreMessage & {
|
|
|
161
171
|
* which message this message is responding to, if any.
|
|
162
172
|
*/
|
|
163
173
|
responseId?: string;
|
|
174
|
+
correlationId?: string;
|
|
175
|
+
parentCorrelationId?: string;
|
|
164
176
|
result?: GenerateTextResult<any>;
|
|
165
177
|
};
|
|
166
178
|
|
|
@@ -169,6 +181,7 @@ export interface AgentObservation<TActor extends AnyActorRef> {
|
|
|
169
181
|
prevState: SnapshotFrom<TActor> | undefined;
|
|
170
182
|
event: EventFrom<TActor>;
|
|
171
183
|
state: SnapshotFrom<TActor>;
|
|
184
|
+
machineHash: string | undefined;
|
|
172
185
|
sessionId: string;
|
|
173
186
|
timestamp: number;
|
|
174
187
|
}
|
|
@@ -178,6 +191,7 @@ export interface AgentObservationInput {
|
|
|
178
191
|
prevState: ObservedState | undefined;
|
|
179
192
|
event: AnyEventObject;
|
|
180
193
|
state: ObservedState;
|
|
194
|
+
machine?: AnyStateMachine;
|
|
181
195
|
timestamp?: number;
|
|
182
196
|
}
|
|
183
197
|
|
|
@@ -203,7 +217,7 @@ export type AgentEmitted<TEvents extends EventObject> =
|
|
|
203
217
|
}
|
|
204
218
|
| {
|
|
205
219
|
type: 'message';
|
|
206
|
-
message:
|
|
220
|
+
message: AgentMessage;
|
|
207
221
|
}
|
|
208
222
|
| {
|
|
209
223
|
type: 'plan';
|
|
@@ -222,7 +236,7 @@ export type AgentLogic<TEvents extends EventObject> = ActorLogic<
|
|
|
222
236
|
}
|
|
223
237
|
| {
|
|
224
238
|
type: 'agent.message';
|
|
225
|
-
message:
|
|
239
|
+
message: AgentMessage;
|
|
226
240
|
}
|
|
227
241
|
| {
|
|
228
242
|
type: 'agent.plan';
|
|
@@ -240,21 +254,30 @@ export type EventsFromZodEventMapping<TEventSchemas extends ZodEventMapping> =
|
|
|
240
254
|
} & TypeOf<TEventSchemas[K]>;
|
|
241
255
|
}>;
|
|
242
256
|
|
|
243
|
-
export type
|
|
257
|
+
export type ContextFromZodContextMapping<
|
|
258
|
+
TContextSchema extends ZodContextMapping
|
|
259
|
+
> = {
|
|
260
|
+
[K in keyof TContextSchema & string]: TypeOf<TContextSchema[K]>;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
export type Agent<TContext, TEvents extends EventObject> = ActorRefFrom<
|
|
244
264
|
AgentLogic<TEvents>
|
|
245
265
|
> & {
|
|
246
266
|
/**
|
|
247
|
-
* The
|
|
267
|
+
* The name of the agent. All agents with the same name are related and
|
|
248
268
|
* able to share experiences (observations, feedback) with each other.
|
|
249
269
|
*/
|
|
250
|
-
name
|
|
270
|
+
name?: string;
|
|
251
271
|
/**
|
|
252
|
-
* The unique
|
|
272
|
+
* The unique identifier for the agent.
|
|
253
273
|
*/
|
|
254
274
|
id?: string;
|
|
255
275
|
description?: string;
|
|
256
276
|
events: ZodEventMapping;
|
|
257
|
-
|
|
277
|
+
types: {
|
|
278
|
+
events: TEvents;
|
|
279
|
+
context: Compute<TContext>;
|
|
280
|
+
};
|
|
258
281
|
model: LanguageModel;
|
|
259
282
|
defaultOptions: GenerateTextOptions;
|
|
260
283
|
memory: AgentLongTermMemory | undefined;
|
|
@@ -271,7 +294,7 @@ export type Agent<TEvents extends EventObject> = ActorRefFrom<
|
|
|
271
294
|
*
|
|
272
295
|
* - The `goal` for the agent to achieve
|
|
273
296
|
* - The observed current `state`
|
|
274
|
-
* - The `
|
|
297
|
+
* - The `machine` (e.g. a state machine) that specifies what can happen next
|
|
275
298
|
* - Additional `context`
|
|
276
299
|
*/
|
|
277
300
|
decide: (
|
|
@@ -281,49 +304,124 @@ export type Agent<TEvents extends EventObject> = ActorRefFrom<
|
|
|
281
304
|
// Generate text
|
|
282
305
|
generateText: (
|
|
283
306
|
options: AgentGenerateTextOptions
|
|
284
|
-
) => Promise<
|
|
307
|
+
) => Promise<AgentGenerateTextResult>;
|
|
285
308
|
|
|
286
309
|
// Stream text
|
|
287
310
|
streamText: (
|
|
288
311
|
options: AgentStreamTextOptions
|
|
289
|
-
) => Promise<
|
|
312
|
+
) => Promise<AgentStreamTextResult>;
|
|
290
313
|
|
|
291
|
-
addObservation: (
|
|
292
|
-
|
|
293
|
-
|
|
314
|
+
addObservation: (
|
|
315
|
+
observationInput: AgentObservationInput
|
|
316
|
+
) => AgentObservation<any>; // TODO
|
|
317
|
+
addMessage: (messageInput: AgentMessageInput) => AgentMessage;
|
|
318
|
+
addFeedback: (feedbackInput: AgentFeedbackInput) => AgentFeedback;
|
|
294
319
|
addPlan: (plan: AgentPlan<TEvents>) => void;
|
|
295
320
|
/**
|
|
296
321
|
* Called whenever the agent (LLM assistant) receives or sends a message.
|
|
297
322
|
*/
|
|
298
|
-
onMessage: (callback: (message:
|
|
323
|
+
onMessage: (callback: (message: AgentMessage) => void) => void;
|
|
299
324
|
/**
|
|
300
325
|
* Selects agent data from its context.
|
|
326
|
+
*
|
|
327
|
+
* @deprecated Select from `agent.getSnapshot().context` directly or:
|
|
328
|
+
* - `agent.getMessages()`
|
|
329
|
+
* - `agent.getObservations()`
|
|
330
|
+
* - `agent.getFeedback()`
|
|
331
|
+
* - `agent.getPlans()`
|
|
301
332
|
*/
|
|
302
333
|
select: <T>(selector: (context: AgentMemoryContext) => T) => T;
|
|
303
334
|
|
|
304
335
|
/**
|
|
305
|
-
*
|
|
306
|
-
|
|
336
|
+
* Retrieves messages from the agent's short-term (local) memory.
|
|
337
|
+
*/
|
|
338
|
+
getMessages: () => AgentMessage[];
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Retrieves observations from the agent's short-term (local) memory.
|
|
307
342
|
*/
|
|
308
|
-
|
|
343
|
+
getObservations: () => AgentObservation<Agent<TContext, TEvents>>[];
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Retrieves feedback from the agent's short-term (local) memory.
|
|
347
|
+
*/
|
|
348
|
+
getFeedback: () => AgentFeedback[];
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Retrieves strategies from the agent's short-term (local) memory.
|
|
352
|
+
*/
|
|
353
|
+
getPlans: () => AgentPlan<TEvents>[];
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Interacts with this state machine actor by inspecting state transitions and storing them as observations.
|
|
357
|
+
*
|
|
358
|
+
* Observations contain the `prevState`, `event`, and current `state` of this
|
|
359
|
+
* actor, as well as other properties that are useful when recalled.
|
|
360
|
+
* These observations are stored in the `agent`'s short-term (local) memory
|
|
361
|
+
* and can be retrieved via `agent.getObservations()`.
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```ts
|
|
365
|
+
* // Only observes the actor's state transitions
|
|
366
|
+
* agent.interact(actor);
|
|
367
|
+
*
|
|
368
|
+
* actor.start();
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
interact<TActor extends AnyActorRef>(actorRef: TActor): Subscription;
|
|
372
|
+
/**
|
|
373
|
+
* Interacts with this state machine actor by:
|
|
374
|
+
* 1. Inspecting state transitions and storing them as observations
|
|
375
|
+
* 2. Deciding what to do next (which event to send the actor) based on
|
|
376
|
+
* the agent input returned from `getInput(observation)`, if `getInput(…)` is provided as the 2nd argument.
|
|
377
|
+
*
|
|
378
|
+
* Observations contain the `prevState`, `event`, and current `state` of this
|
|
379
|
+
* actor, as well as other properties that are useful when recalled.
|
|
380
|
+
* These observations are stored in the `agent`'s short-term (local) memory
|
|
381
|
+
* and can be retrieved via `agent.getObservations()`.
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* ```ts
|
|
385
|
+
* // Observes the actor's state transitions and
|
|
386
|
+
* // makes a decision if on the "summarize" state
|
|
387
|
+
* agent.interact(actor, observed => {
|
|
388
|
+
* if (observed.state.matches('summarize')) {
|
|
389
|
+
* return {
|
|
390
|
+
* context: observed.state.context,
|
|
391
|
+
* goal: 'Summarize the message'
|
|
392
|
+
* }
|
|
393
|
+
* }
|
|
394
|
+
* });
|
|
395
|
+
*
|
|
396
|
+
* actor.start();
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
interact<TActor extends AnyActorRef>(
|
|
309
400
|
actorRef: TActor,
|
|
310
|
-
getInput
|
|
401
|
+
getInput: (
|
|
311
402
|
observation: AgentObservation<TActor>
|
|
312
403
|
) => AgentDecisionInput | undefined
|
|
313
|
-
)
|
|
404
|
+
): Subscription;
|
|
314
405
|
};
|
|
315
406
|
|
|
316
|
-
export type AnyAgent = Agent<any>;
|
|
407
|
+
export type AnyAgent = Agent<any, any>;
|
|
317
408
|
|
|
318
|
-
export type FromAgent<T> = T | ((
|
|
409
|
+
export type FromAgent<T> = T | ((agent: AnyAgent) => T | Promise<T>);
|
|
319
410
|
|
|
320
|
-
export
|
|
411
|
+
export type CommonTextOptions = {
|
|
321
412
|
prompt: FromAgent<string>;
|
|
322
413
|
model?: LanguageModel;
|
|
323
414
|
context?: Record<string, any>;
|
|
324
|
-
messages?: FromAgent<CoreMessage[]
|
|
415
|
+
messages?: FromAgent<CoreMessage[]>;
|
|
325
416
|
template?: PromptTemplate<any>;
|
|
326
|
-
|
|
417
|
+
correlationId?: string;
|
|
418
|
+
parentCorrelationId?: string;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
export type TextResultMeta = {
|
|
422
|
+
correlationId: string;
|
|
423
|
+
parentCorrelationId?: string;
|
|
424
|
+
};
|
|
327
425
|
|
|
328
426
|
export type AgentGenerateTextOptions = Omit<
|
|
329
427
|
GenerateTextOptions,
|
|
@@ -331,12 +429,16 @@ export type AgentGenerateTextOptions = Omit<
|
|
|
331
429
|
> &
|
|
332
430
|
CommonTextOptions;
|
|
333
431
|
|
|
432
|
+
export type AgentGenerateTextResult = GenerateTextResult<any> & TextResultMeta;
|
|
433
|
+
|
|
334
434
|
export type AgentStreamTextOptions = Omit<
|
|
335
435
|
StreamTextOptions,
|
|
336
436
|
'model' | 'prompt' | 'messages'
|
|
337
437
|
> &
|
|
338
438
|
CommonTextOptions;
|
|
339
439
|
|
|
440
|
+
export type AgentStreamTextResult = StreamTextResult<any> & TextResultMeta;
|
|
441
|
+
|
|
340
442
|
export interface ObservedState {
|
|
341
443
|
/**
|
|
342
444
|
* The current state value of the state machine, e.g.
|
|
@@ -356,7 +458,7 @@ export type ObservedStateFrom<TActor extends AnyActorRef> = Pick<
|
|
|
356
458
|
|
|
357
459
|
export type AgentMemoryContext = {
|
|
358
460
|
observations: AgentObservation<any>[]; // TODO
|
|
359
|
-
messages:
|
|
461
|
+
messages: AgentMessage[];
|
|
360
462
|
plans: AgentPlan<any>[];
|
|
361
463
|
feedback: AgentFeedback[];
|
|
362
464
|
};
|
|
@@ -393,3 +495,5 @@ export interface AIAdapter {
|
|
|
393
495
|
generateText: typeof generateText;
|
|
394
496
|
streamText: typeof streamText;
|
|
395
497
|
}
|
|
498
|
+
|
|
499
|
+
export type Compute<A extends any> = { [K in keyof A]: A[K] } & unknown;
|
package/src/utils.ts
CHANGED
|
@@ -1,18 +1,50 @@
|
|
|
1
|
-
import { AnyMachineSnapshot, AnyStateNode } from 'xstate';
|
|
1
|
+
import { AnyMachineSnapshot, AnyStateMachine, AnyStateNode } from 'xstate';
|
|
2
|
+
import hash from 'object-hash';
|
|
2
3
|
import { TransitionData } from './types';
|
|
3
4
|
|
|
4
5
|
export function getAllTransitions(state: AnyMachineSnapshot): TransitionData[] {
|
|
5
6
|
const nodes = state._nodes;
|
|
6
7
|
const transitions = (nodes as AnyStateNode[])
|
|
7
8
|
.map((node) => [...(node as AnyStateNode).transitions.values()])
|
|
8
|
-
.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
.map((nodeTransitions) => {
|
|
10
|
+
return nodeTransitions.map((nodeEventTransitions) => {
|
|
11
|
+
return nodeEventTransitions.map((transition) => {
|
|
12
|
+
return {
|
|
13
|
+
...transition,
|
|
14
|
+
guard:
|
|
15
|
+
typeof transition.guard === 'string'
|
|
16
|
+
? { type: transition.guard }
|
|
17
|
+
: (transition.guard as any), // TODO: fix
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
})
|
|
22
|
+
.flat(2);
|
|
23
|
+
|
|
24
|
+
return transitions;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getAllMachineTransitions(
|
|
28
|
+
stateNode: AnyStateNode
|
|
29
|
+
): TransitionData[] {
|
|
30
|
+
const transitions: TransitionData[] = [...stateNode.transitions.values()]
|
|
31
|
+
.map((nodeTransitions) => {
|
|
32
|
+
return nodeTransitions.map((transition) => {
|
|
33
|
+
return {
|
|
34
|
+
...transition,
|
|
35
|
+
guard:
|
|
36
|
+
typeof transition.guard === 'string'
|
|
37
|
+
? { type: transition.guard }
|
|
38
|
+
: (transition.guard as any), // TODO: fix
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
})
|
|
42
|
+
.flat(2);
|
|
43
|
+
|
|
44
|
+
for (const s of Object.values(stateNode.states)) {
|
|
45
|
+
const stateTransitions = getAllMachineTransitions(s);
|
|
46
|
+
transitions.push(...stateTransitions);
|
|
47
|
+
}
|
|
16
48
|
|
|
17
49
|
return transitions;
|
|
18
50
|
}
|
|
@@ -26,3 +58,15 @@ export function randomId() {
|
|
|
26
58
|
const random = Math.random().toString(36).substring(2, 9);
|
|
27
59
|
return timestamp + random;
|
|
28
60
|
}
|
|
61
|
+
|
|
62
|
+
const machineHashes: WeakMap<AnyStateMachine, string> = new WeakMap();
|
|
63
|
+
/**
|
|
64
|
+
* Returns a string hash representing only the transitions in the state machine.
|
|
65
|
+
*/
|
|
66
|
+
export function getMachineHash(machine: AnyStateMachine): string {
|
|
67
|
+
if (machineHashes.has(machine)) return machineHashes.get(machine)!;
|
|
68
|
+
const transitions = getAllMachineTransitions(machine.root);
|
|
69
|
+
const machineHash = hash(transitions);
|
|
70
|
+
machineHashes.set(machine, machineHash);
|
|
71
|
+
return machineHash;
|
|
72
|
+
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { PromptTemplate } from '../types';
|
|
2
|
-
import { defaultTextTemplate } from './defaultText';
|
|
3
|
-
|
|
4
|
-
export const defaultToolCallTemplate: PromptTemplate<any> = (data) => {
|
|
5
|
-
return `
|
|
6
|
-
${defaultTextTemplate(data)}
|
|
7
|
-
|
|
8
|
-
Only make a single tool call to achieve the above goal.
|
|
9
|
-
`.trim();
|
|
10
|
-
};
|