@statelyai/agent 1.0.0-beta.1 → 1.0.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.
@@ -0,0 +1,12 @@
1
+ ---
2
+ '@statelyai/agent': minor
3
+ ---
4
+
5
+ Added four new methods for easily retrieving agent messages, observations, feedback, and plans:
6
+
7
+ - `agent.getMessages()`
8
+ - `agent.getObservations()`
9
+ - `agent.getFeedback()`
10
+ - `agent.getPlans()`
11
+
12
+ The `agent.select(…)` method is deprecated in favor of these methods.
@@ -0,0 +1,5 @@
1
+ ---
2
+ '@statelyai/agent': patch
3
+ ---
4
+
5
+ Messages are now properly included in `agent.decide(…)`, when specified.
@@ -0,0 +1,26 @@
1
+ ---
2
+ '@statelyai/agent': minor
3
+ ---
4
+
5
+ You can now add `context` Zod schema to your agent. For now, this is meant to be passed directly to the state machine, but in the future, the schema can be shared with the LLM agent to better understand the state machine and its context for decision making.
6
+
7
+ Breaking: The `context` and `events` types are now in `agent.types` instead of ~~`agent.eventTypes`.
8
+
9
+ ```ts
10
+ const agent = createAgent({
11
+ // ...
12
+ context: {
13
+ score: z.number().describe('The score of the game'),
14
+ // ...
15
+ },
16
+ });
17
+
18
+ const machine = setup({
19
+ types: agent.types,
20
+ }).createMachine({
21
+ context: {
22
+ score: 0,
23
+ },
24
+ // ...
25
+ });
26
+ ```
package/.env.template CHANGED
@@ -1,6 +1,3 @@
1
1
 
2
2
  # Get your OpenAI API key from: https://platform.openai.com/signup/
3
3
  OPENAI_API_KEY="sk-..."
4
-
5
- # Get your Tavily API key from: https://app.tavily.com/
6
- TAVILY_API_KEY="tvly-..."
@@ -11,9 +11,9 @@ permissions: {}
11
11
  jobs:
12
12
  release:
13
13
  permissions:
14
- contents: write # to create release (changesets/action)
14
+ contents: write # to create release (changesets/action)
15
15
  issues: write # to post issue comments (changesets/action)
16
- pull-requests: write # to create pull request (changesets/action)
16
+ pull-requests: write # to create pull request (changesets/action)
17
17
 
18
18
  if: github.repository == 'statelyai/agent'
19
19
 
@@ -22,7 +22,7 @@ jobs:
22
22
  runs-on: ubuntu-latest
23
23
 
24
24
  steps:
25
- - uses: actions/checkout@v3
25
+ - uses: actions/checkout@v4
26
26
  - uses: ./.github/actions/ci-setup
27
27
 
28
28
  - name: Create Release Pull Request or Publish to npm
package/dist/index.d.mts CHANGED
@@ -1,7 +1,14 @@
1
1
  import { EventObject, AnyStateMachine, AnyEventObject, AnyActorRef, SnapshotFrom, EventFrom, PromiseActorLogic, ActorLogic, TransitionSnapshot, Values, ActorRefFrom, Subscription, StateValue, ObservableActorLogic } from 'xstate';
2
- import { TypeOf, SomeZodObject } from 'zod';
2
+ import { SomeZodObject, ZodType, TypeOf } from 'zod';
3
3
  import { generateText, streamText, LanguageModel, CoreMessage, GenerateTextResult, StreamTextResult, CoreTool } from 'ai';
4
4
 
5
+ type ZodEventMapping = {
6
+ [eventType: string]: SomeZodObject;
7
+ };
8
+ type ZodContextMapping = {
9
+ [contextKey: string]: ZodType;
10
+ };
11
+
5
12
  type GenerateTextOptions = Parameters<typeof generateText>[0];
6
13
  type StreamTextOptions = Parameters<typeof streamText>[0];
7
14
  type AgentPlanInput<TEvent extends EventObject> = Omit<GenerateTextOptions, 'prompt' | 'messages' | 'tools'> & {
@@ -33,10 +40,11 @@ type AgentPlan<TEvent extends EventObject> = {
33
40
  goal: string;
34
41
  state: ObservedState;
35
42
  content?: string;
36
- steps?: Array<{
37
- event: TEvent;
38
- state?: ObservedState;
39
- }>;
43
+ /**
44
+ * Executes the plan based on the given `state` and resolves with
45
+ * a potential next `event` to trigger to achieve the `goal`.
46
+ */
47
+ execute: (state: ObservedState) => Promise<TEvent | undefined>;
40
48
  nextEvent: TEvent | undefined;
41
49
  sessionId: string;
42
50
  timestamp: number;
@@ -74,10 +82,10 @@ type PromptTemplate<TEvents extends EventObject> = (data: {
74
82
  */
75
83
  observations?: AgentObservation<any>[];
76
84
  feedback?: AgentFeedback[];
77
- messages?: AgentMessageHistory[];
85
+ messages?: AgentMessage[];
78
86
  plans?: AgentPlan<TEvents>[];
79
87
  }) => string;
80
- type AgentPlanner<T extends Agent<any>> = (agent: T['eventTypes'], options: AgentPlanInput<T['eventTypes']>) => Promise<AgentPlan<T['eventTypes']> | undefined>;
88
+ type AgentPlanner<T extends AnyAgent> = (agent: T, input: AgentPlanInput<T['types']['events']>) => Promise<AgentPlan<T['types']['events']> | undefined>;
81
89
  type AgentDecideOptions = {
82
90
  goal: string;
83
91
  model?: LanguageModel;
@@ -101,7 +109,7 @@ interface AgentFeedbackInput {
101
109
  attributes: Record<string, any>;
102
110
  timestamp?: number;
103
111
  }
104
- type AgentMessageHistory = CoreMessage & {
112
+ type AgentMessage = CoreMessage & {
105
113
  timestamp: number;
106
114
  id: string;
107
115
  /**
@@ -112,7 +120,7 @@ type AgentMessageHistory = CoreMessage & {
112
120
  result?: GenerateTextResult<any>;
113
121
  sessionId: string;
114
122
  };
115
- type AgentMessageHistoryInput = CoreMessage & {
123
+ type AgentMessageInput = CoreMessage & {
116
124
  timestamp?: number;
117
125
  id?: string;
118
126
  /**
@@ -127,6 +135,7 @@ interface AgentObservation<TActor extends AnyActorRef> {
127
135
  prevState: SnapshotFrom<TActor> | undefined;
128
136
  event: EventFrom<TActor>;
129
137
  state: SnapshotFrom<TActor>;
138
+ machineHash: string | undefined;
130
139
  sessionId: string;
131
140
  timestamp: number;
132
141
  }
@@ -135,6 +144,7 @@ interface AgentObservationInput {
135
144
  prevState: ObservedState | undefined;
136
145
  event: AnyEventObject;
137
146
  state: ObservedState;
147
+ machine?: AnyStateMachine;
138
148
  timestamp?: number;
139
149
  }
140
150
  type AgentDecisionInput = {
@@ -151,7 +161,7 @@ type AgentEmitted<TEvents extends EventObject> = {
151
161
  observation: AgentObservation<any>;
152
162
  } | {
153
163
  type: 'message';
154
- message: AgentMessageHistory;
164
+ message: AgentMessage;
155
165
  } | {
156
166
  type: 'plan';
157
167
  plan: AgentPlan<TEvents>;
@@ -164,7 +174,7 @@ type AgentLogic<TEvents extends EventObject> = ActorLogic<TransitionSnapshot<Age
164
174
  observation: AgentObservation<any>;
165
175
  } | {
166
176
  type: 'agent.message';
167
- message: AgentMessageHistory;
177
+ message: AgentMessage;
168
178
  } | {
169
179
  type: 'agent.plan';
170
180
  plan: AgentPlan<TEvents>;
@@ -175,19 +185,25 @@ type EventsFromZodEventMapping<TEventSchemas extends ZodEventMapping> = Values<{
175
185
  type: K;
176
186
  } & TypeOf<TEventSchemas[K]>;
177
187
  }>;
178
- type Agent<TEvents extends EventObject> = ActorRefFrom<AgentLogic<TEvents>> & {
188
+ type ContextFromZodContextMapping<TContextSchema extends ZodContextMapping> = {
189
+ [K in keyof TContextSchema & string]: TypeOf<TContextSchema[K]>;
190
+ };
191
+ type Agent<TContext, TEvents extends EventObject> = ActorRefFrom<AgentLogic<TEvents>> & {
179
192
  /**
180
- * The general name of the agent. All agents with the same name are related and
193
+ * The name of the agent. All agents with the same name are related and
181
194
  * able to share experiences (observations, feedback) with each other.
182
195
  */
183
- name: string;
196
+ name?: string;
184
197
  /**
185
- * The unique id of the agent. This is used to partition message history.
198
+ * The unique identifier for the agent.
186
199
  */
187
200
  id?: string;
188
201
  description?: string;
189
202
  events: ZodEventMapping;
190
- eventTypes: TEvents;
203
+ types: {
204
+ events: TEvents;
205
+ context: Compute<TContext>;
206
+ };
191
207
  model: LanguageModel;
192
208
  defaultOptions: GenerateTextOptions;
193
209
  memory: AgentLongTermMemory | undefined;
@@ -203,37 +219,99 @@ type Agent<TEvents extends EventObject> = ActorRefFrom<AgentLogic<TEvents>> & {
203
219
  *
204
220
  * - The `goal` for the agent to achieve
205
221
  * - The observed current `state`
206
- * - The `logic` (e.g. a state machine) that specifies what can happen next
222
+ * - The `machine` (e.g. a state machine) that specifies what can happen next
207
223
  * - Additional `context`
208
224
  */
209
225
  decide: (options: AgentDecideOptions) => Promise<AgentPlan<TEvents> | undefined>;
210
226
  generateText: (options: AgentGenerateTextOptions) => Promise<GenerateTextResult<Record<string, any>>>;
211
227
  streamText: (options: AgentStreamTextOptions) => Promise<StreamTextResult<Record<string, CoreTool<any, any>>>>;
212
- addObservation: (observation: AgentObservationInput) => AgentObservation<any>;
213
- addMessage: (history: AgentMessageHistoryInput) => AgentMessageHistory;
214
- addFeedback: (feedbackItem: AgentFeedbackInput) => AgentFeedback;
228
+ addObservation: (observationInput: AgentObservationInput) => AgentObservation<any>;
229
+ addMessage: (messageInput: AgentMessageInput) => AgentMessage;
230
+ addFeedback: (feedbackInput: AgentFeedbackInput) => AgentFeedback;
215
231
  addPlan: (plan: AgentPlan<TEvents>) => void;
216
232
  /**
217
233
  * Called whenever the agent (LLM assistant) receives or sends a message.
218
234
  */
219
- onMessage: (callback: (message: AgentMessageHistory) => void) => void;
235
+ onMessage: (callback: (message: AgentMessage) => void) => void;
220
236
  /**
221
237
  * Selects agent data from its context.
238
+ *
239
+ * @deprecated Select from `agent.getSnapshot().context` directly or:
240
+ * - `agent.getMessages()`
241
+ * - `agent.getObservations()`
242
+ * - `agent.getFeedback()`
243
+ * - `agent.getPlans()`
222
244
  */
223
245
  select: <T>(selector: (context: AgentMemoryContext) => T) => T;
224
246
  /**
225
- * Inspects state machine actor transitions and automatically observes
226
- * (prevState, event, state) tuples.
247
+ * Retrieves messages from the agent's short-term (local) memory.
248
+ */
249
+ getMessages: () => AgentMessage[];
250
+ /**
251
+ * Retrieves observations from the agent's short-term (local) memory.
252
+ */
253
+ getObservations: () => AgentObservation<Agent<TContext, TEvents>>[];
254
+ /**
255
+ * Retrieves feedback from the agent's short-term (local) memory.
256
+ */
257
+ getFeedback: () => AgentFeedback[];
258
+ /**
259
+ * Retrieves strategies from the agent's short-term (local) memory.
260
+ */
261
+ getPlans: () => AgentPlan<TEvents>[];
262
+ /**
263
+ * Interacts with this state machine actor by inspecting state transitions and storing them as observations.
264
+ *
265
+ * Observations contain the `prevState`, `event`, and current `state` of this
266
+ * actor, as well as other properties that are useful when recalled.
267
+ * These observations are stored in the `agent`'s short-term (local) memory
268
+ * and can be retrieved via `agent.getObservations()`.
269
+ *
270
+ * @example
271
+ * ```ts
272
+ * // Only observes the actor's state transitions
273
+ * agent.interact(actor);
274
+ *
275
+ * actor.start();
276
+ * ```
277
+ */
278
+ interact<TActor extends AnyActorRef>(actorRef: TActor): Subscription;
279
+ /**
280
+ * Interacts with this state machine actor by:
281
+ * 1. Inspecting state transitions and storing them as observations
282
+ * 2. Deciding what to do next (which event to send the actor) based on
283
+ * the agent input returned from `getInput(observation)`, if `getInput(…)` is provided as the 2nd argument.
284
+ *
285
+ * Observations contain the `prevState`, `event`, and current `state` of this
286
+ * actor, as well as other properties that are useful when recalled.
287
+ * These observations are stored in the `agent`'s short-term (local) memory
288
+ * and can be retrieved via `agent.getObservations()`.
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * // Observes the actor's state transitions and
293
+ * // makes a decision if on the "summarize" state
294
+ * agent.interact(actor, observed => {
295
+ * if (observed.state.matches('summarize')) {
296
+ * return {
297
+ * context: observed.state.context,
298
+ * goal: 'Summarize the message'
299
+ * }
300
+ * }
301
+ * });
302
+ *
303
+ * actor.start();
304
+ * ```
227
305
  */
228
- interact: <TActor extends AnyActorRef>(actorRef: TActor, getInput?: (observation: AgentObservation<TActor>) => AgentDecisionInput | undefined) => Subscription;
306
+ interact<TActor extends AnyActorRef>(actorRef: TActor, getInput: (observation: AgentObservation<TActor>) => AgentDecisionInput | undefined): Subscription;
229
307
  };
230
- type AnyAgent = Agent<any>;
308
+ type AnyAgent = Agent<any, any>;
231
309
  type FromAgent<T> = T | ((self: AnyAgent) => T | Promise<T>);
232
310
  interface CommonTextOptions {
233
311
  prompt: FromAgent<string>;
234
312
  model?: LanguageModel;
235
313
  context?: Record<string, any>;
236
- messages?: FromAgent<CoreMessage[]> | true;
314
+ messages?: FromAgent<CoreMessage[]>;
237
315
  template?: PromptTemplate<any>;
238
316
  }
239
317
  type AgentGenerateTextOptions = Omit<GenerateTextOptions, 'model' | 'prompt' | 'messages'> & CommonTextOptions;
@@ -252,7 +330,7 @@ interface ObservedState {
252
330
  type ObservedStateFrom<TActor extends AnyActorRef> = Pick<SnapshotFrom<TActor>, 'value' | 'context'>;
253
331
  type AgentMemoryContext = {
254
332
  observations: AgentObservation<any>[];
255
- messages: AgentMessageHistory[];
333
+ messages: AgentMessage[];
256
334
  plans: AgentPlan<any>[];
257
335
  feedback: AgentFeedback[];
258
336
  };
@@ -270,16 +348,30 @@ interface AIAdapter {
270
348
  generateText: typeof generateText;
271
349
  streamText: typeof streamText;
272
350
  }
351
+ type Compute<A extends any> = {
352
+ [K in keyof A]: A[K];
353
+ } & unknown;
273
354
 
274
- type ZodEventMapping = {
275
- [eventType: string]: SomeZodObject;
276
- };
277
-
278
- declare function createAgent<const TEventSchemas extends ZodEventMapping, TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>>({ name, description, model, events, planner, stringify, getMemory, logic, adapter, ...generateTextOptions }: {
355
+ declare function createAgent<const TContextSchema extends ZodContextMapping, const TEventSchemas extends ZodEventMapping, TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>, TContext = ContextFromZodContextMapping<TContextSchema>>({ name, description, model, events, context, planner, stringify, getMemory, logic, adapter, ...generateTextOptions }: {
356
+ /**
357
+ * The unique identifier for the agent.
358
+ *
359
+ * This should be the same across all sessions of a specific agent, as it can be
360
+ * used to retrieve memory for this agent.
361
+ *
362
+ * @example
363
+ * ```ts
364
+ * const agent = createAgent({
365
+ * id: 'recipe-assistant',
366
+ * // ...
367
+ * });
368
+ * ```
369
+ */
370
+ id?: string;
279
371
  /**
280
372
  * The name of the agent
281
373
  */
282
- name: string;
374
+ name?: string;
283
375
  /**
284
376
  * A description of the role of the agent
285
377
  */
@@ -289,30 +381,29 @@ declare function createAgent<const TEventSchemas extends ZodEventMapping, TEvent
289
381
  * that the agent knows about.
290
382
  */
291
383
  events: TEventSchemas;
292
- planner?: AgentPlanner<Agent<TEvents>>;
384
+ context?: TContextSchema;
385
+ planner?: AgentPlanner<Agent<TContext, TEvents>>;
293
386
  stringify?: typeof JSON.stringify;
294
387
  /**
295
388
  * A function that retrieves the agent's long term memory
296
389
  */
297
- getMemory?: (agent: Agent<any>) => AgentLongTermMemory;
390
+ getMemory?: (agent: Agent<TContext, TEvents>) => AgentLongTermMemory;
298
391
  /**
299
392
  * Agent logic
300
393
  */
301
394
  logic?: AgentLogic<TEvents>;
302
395
  adapter?: AIAdapter;
303
- } & GenerateTextOptions): Agent<TEvents>;
396
+ } & GenerateTextOptions): Agent<TContext, TEvents>;
304
397
 
305
- declare function agentGenerateText<T extends Agent<any>>(agent: T, options: AgentGenerateTextOptions): Promise<GenerateTextResult<Record<string, CoreTool<any, any>>>>;
306
- declare function fromTextStream<T extends Agent<any>>(agent: T, defaultOptions?: AgentStreamTextOptions): ObservableActorLogic<{
398
+ declare function fromTextStream<T extends AnyAgent>(agent: T, defaultOptions?: AgentStreamTextOptions): ObservableActorLogic<{
307
399
  textDelta: string;
308
400
  }, Omit<AgentStreamTextOptions, 'context'> & {
309
- context?: AgentStreamTextOptions['context'] | boolean;
401
+ context?: AgentStreamTextOptions['context'];
310
402
  }>;
311
- declare function fromText<T extends Agent<any>>(agent: T, defaultOptions?: AgentGenerateTextOptions): PromiseActorLogic<GenerateTextResult<Record<string, CoreTool<any, any>>>, Omit<AgentGenerateTextOptions, 'context'> & {
312
- context?: AgentGenerateTextOptions['context'] | boolean;
403
+ declare function fromText<T extends AnyAgent>(agent: T, defaultOptions?: AgentGenerateTextOptions): PromiseActorLogic<GenerateTextResult<Record<string, CoreTool<any, any>>>, Omit<AgentGenerateTextOptions, 'context'> & {
404
+ context?: AgentGenerateTextOptions['context'];
313
405
  }>;
314
406
 
315
- declare function agentDecide<T extends Agent<any>>(agent: T, options: AgentDecideOptions): Promise<AgentPlan<any> | undefined>;
316
- declare function fromDecision(agent: Agent<any>, defaultInput?: AgentDecisionInput): AgentDecisionLogic<any>;
407
+ declare function fromDecision(agent: AnyAgent, defaultInput?: AgentDecisionInput): AgentDecisionLogic<any>;
317
408
 
318
- export { type AIAdapter, type Agent, type AgentDecideOptions, type AgentDecisionInput, type AgentDecisionLogic, type AgentEmitted, type AgentFeedback, type AgentFeedbackInput, type AgentGenerateTextOptions, type AgentLogic, type AgentLongTermMemory, type AgentMemory, type AgentMemoryContext, type AgentMessageHistory, type AgentMessageHistoryInput, type AgentObservation, type AgentObservationInput, type AgentPlan, type AgentPlanInput, type AgentPlanner, type AgentStreamTextOptions, type AnyAgent, type AppendOnlyStorage, type CommonTextOptions, type EventsFromZodEventMapping, type FromAgent, type GenerateTextOptions, type ObservedState, type ObservedStateFrom, type PromptTemplate, type StreamTextOptions, type TransitionData, agentDecide, agentGenerateText, createAgent, fromDecision, fromText, fromTextStream };
409
+ export { type AIAdapter, type Agent, type AgentDecideOptions, type AgentDecisionInput, type AgentDecisionLogic, type AgentEmitted, type AgentFeedback, type AgentFeedbackInput, type AgentGenerateTextOptions, type AgentLogic, type AgentLongTermMemory, type AgentMemory, type AgentMemoryContext, type AgentMessage, type AgentMessageInput, type AgentObservation, type AgentObservationInput, type AgentPlan, type AgentPlanInput, type AgentPlanner, type AgentStreamTextOptions, type AnyAgent, type AppendOnlyStorage, type CommonTextOptions, type Compute, type ContextFromZodContextMapping, type EventsFromZodEventMapping, type FromAgent, type GenerateTextOptions, type ObservedState, type ObservedStateFrom, type PromptTemplate, type StreamTextOptions, type TransitionData, createAgent, fromDecision, fromText, fromTextStream };