@statelyai/agent 2.0.0-next.0 → 2.0.0-next.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.
Files changed (51) hide show
  1. package/.changeset/cyan-carpets-perform.md +5 -0
  2. package/.changeset/fast-donkeys-argue.md +5 -0
  3. package/.changeset/grumpy-dolphins-think.md +17 -0
  4. package/.changeset/old-jobs-check.md +5 -0
  5. package/.changeset/old-teachers-tap.md +5 -0
  6. package/.changeset/pre.json +7 -1
  7. package/.changeset/smart-yaks-pull.md +23 -0
  8. package/CHANGELOG.md +52 -0
  9. package/dist/index.d.mts +69 -66
  10. package/dist/index.d.ts +69 -66
  11. package/dist/index.js +111 -79
  12. package/dist/index.mjs +114 -82
  13. package/examples/chatbot-alt.ts +1 -1
  14. package/examples/chatbot.ts +3 -3
  15. package/examples/cot.ts +7 -25
  16. package/examples/customer-service-sim.ts +7 -7
  17. package/examples/email.ts +37 -35
  18. package/examples/example.ts +3 -3
  19. package/examples/goal.ts +3 -3
  20. package/examples/joke.ts +3 -3
  21. package/examples/jugs.ts +5 -8
  22. package/examples/learn-from-feedback.ts +100 -0
  23. package/examples/multi.ts +1 -1
  24. package/examples/number.ts +3 -3
  25. package/examples/raffle.ts +3 -3
  26. package/examples/river-crossing.ts +5 -8
  27. package/examples/simple.ts +14 -11
  28. package/examples/summary.ts +3 -6
  29. package/examples/support.ts +43 -39
  30. package/examples/ticTacToe.ts +48 -6
  31. package/examples/todo.ts +3 -3
  32. package/examples/tutor.ts +4 -4
  33. package/examples/verify.ts +3 -3
  34. package/examples/weather-agent.ts +141 -0
  35. package/examples/weather.ts +24 -24
  36. package/examples/wiki.ts +1 -1
  37. package/examples/word.ts +9 -7
  38. package/package.json +6 -3
  39. package/src/agent.test.ts +161 -19
  40. package/src/agent.ts +66 -250
  41. package/src/decide.test.ts +172 -3
  42. package/src/decide.ts +50 -30
  43. package/src/middleware.ts +2 -14
  44. package/src/strategies/chainOfThought.ts +48 -0
  45. package/src/strategies/shortestPath.test.ts +91 -0
  46. package/src/{planners/shortestPathPlanner.ts → strategies/shortestPath.ts} +32 -19
  47. package/src/{planners/simplePlanner.ts → strategies/simple.ts} +28 -24
  48. package/src/types.ts +75 -34
  49. package/src/utils.ts +23 -0
  50. package/vitest.config.ts +9 -3
  51. package/src/strategies/chain-of-note.ts +0 -106
package/src/types.ts CHANGED
@@ -31,8 +31,8 @@ export type CostFunction<TEvent extends EventObject> = (
31
31
  path: AgentPath<TEvent>
32
32
  ) => number;
33
33
 
34
- export type AgentPlanInput<TEvent extends EventObject> = Omit<
35
- GenerateTextOptions,
34
+ export type AgentDecideInput<TEvent extends EventObject> = Omit<
35
+ AgentGenerateTextOptions,
36
36
  'prompt' | 'tools'
37
37
  > & {
38
38
  /**
@@ -41,7 +41,7 @@ export type AgentPlanInput<TEvent extends EventObject> = Omit<
41
41
  state: ObservedState;
42
42
  /**
43
43
  * The goal for the agent to accomplish.
44
- * The agent will create a plan based on this goal.
44
+ * The agent will make a decision based on this goal.
45
45
  */
46
46
  goal: string;
47
47
  /**
@@ -55,14 +55,20 @@ export type AgentPlanInput<TEvent extends EventObject> = Omit<
55
55
  */
56
56
  machine?: AnyStateMachine;
57
57
  /**
58
- * The previous plan.
58
+ * The previous decision made by the agent.
59
59
  */
60
- previousPlan?: AgentPlan<TEvent>;
60
+ prevDecision?: AgentDecision<TEvent>;
61
61
 
62
62
  /**
63
63
  * The total cost of the path to the goal state.
64
64
  */
65
65
  costFunction?: CostFunction<TEvent>;
66
+
67
+ /**
68
+ * The maximum number of attempts to make a decision.
69
+ * Defaults to 2.
70
+ */
71
+ maxAttempts?: number;
66
72
  };
67
73
 
68
74
  export type AgentStep<TEvent extends EventObject> = {
@@ -80,14 +86,14 @@ export type AgentPath<TEvent extends EventObject> = {
80
86
  weight?: number;
81
87
  };
82
88
 
83
- export type AgentPlan<TEvent extends EventObject> = {
89
+ export type AgentDecision<TEvent extends EventObject> = {
84
90
  /**
85
- * The planner used to generate the plan
91
+ * The strategy used to generate the decision
86
92
  */
87
- planner: string;
93
+ strategy: string;
88
94
  goal: string;
89
95
  /**
90
- * The ending state of the plan.
96
+ * The ending state of the decision.
91
97
  */
92
98
  goalState: ObservedState | undefined;
93
99
  /**
@@ -138,44 +144,52 @@ export type PromptTemplate<TEvents extends EventObject> = (data: {
138
144
  observations?: AgentObservation<any>[]; // TODO
139
145
  feedback?: AgentFeedback[];
140
146
  messages?: AgentMessage[];
141
- plans?: AgentPlan<TEvents>[];
147
+ decisions?: AgentDecision<TEvents>[];
142
148
  }) => string;
143
149
 
144
- export type AgentPlanner<T extends AnyAgent> = (
150
+ export type AgentStrategy<T extends AnyAgent> = (
145
151
  agent: T,
146
- input: AgentPlanInput<T['types']['events']>
147
- ) => Promise<AgentPlan<T['types']['events']> | undefined>;
152
+ input: AgentDecideInput<EventsFromAgent<T>>
153
+ ) => Promise<AgentDecision<EventsFromAgent<T>> | undefined>;
148
154
 
149
- export type AgentDecideOptions = {
155
+ export type AgentInteractInput<T extends AnyAgent> = Omit<
156
+ AgentDecideOptions<T>,
157
+ 'state'
158
+ >;
159
+
160
+ export type AgentDecideOptions<T extends AnyAgent> = {
150
161
  goal: string;
151
- model?: LanguageModel;
152
162
  state: ObservedState;
163
+ context?: Record<string, any>;
153
164
  machine?: AnyStateMachine;
165
+ model?: LanguageModel;
154
166
  execute?: (event: AnyEventObject) => Promise<void>;
155
- planner?: AgentPlanner<any>;
167
+ strategy?: AgentStrategy<T>;
156
168
  events?: ZodEventMapping;
169
+ allowedEvents?: Array<EventsFromAgent<T>['type']>;
170
+ /**
171
+ * The maximum number of times the agent will attempt to make a decision.
172
+ * Defaults to 2.
173
+ */
174
+ maxAttempts?: number;
157
175
  } & Omit<Parameters<typeof generateText>[0], 'model' | 'tools' | 'prompt'>;
158
176
 
159
177
  export interface AgentFeedback {
160
- goal?: string;
161
- observationId?: string;
178
+ goal: string;
179
+ observationId: string;
162
180
  /**
163
181
  * The message correlation that the feedback is relevant for
164
182
  */
165
- correlationId?: string;
166
183
  attributes: Record<string, any>;
167
- reward: number;
168
184
  timestamp: number;
169
185
  episodeId: string;
170
186
  }
171
187
 
172
188
  export interface AgentFeedbackInput {
173
- goal?: string;
174
- observationId?: string;
175
- correlationId?: string;
176
- attributes?: Record<string, any>;
189
+ goal: string;
190
+ observationId: string;
191
+ attributes: Record<string, any>;
177
192
  timestamp?: number;
178
- reward?: number;
179
193
  }
180
194
 
181
195
  export type AgentMessage = CoreMessage & {
@@ -313,13 +327,12 @@ export type AgentMessageInput = CoreMessage & {
313
327
  * which message this message is responding to, if any.
314
328
  */
315
329
  responseId?: string;
316
- correlationId?: string;
317
- parentCorrelationId?: string;
318
330
  result?: GenerateTextResult<any>;
319
331
  };
320
332
 
321
333
  export interface AgentObservation<TActor extends ActorRefLike> {
322
334
  id: string;
335
+ // TODO: goal
323
336
  prevState: SnapshotFrom<TActor> | undefined;
324
337
  event: EventFrom<TActor> | undefined;
325
338
  state: SnapshotFrom<TActor>;
@@ -344,7 +357,7 @@ export type AgentDecisionInput = {
344
357
  } & Omit<Parameters<typeof generateText>[0], 'model' | 'tools' | 'prompt'>;
345
358
 
346
359
  export type AgentDecisionLogic<TEvents extends EventObject> = PromiseActorLogic<
347
- AgentPlan<TEvents> | undefined,
360
+ AgentDecision<TEvents> | undefined,
348
361
  AgentDecisionInput | string
349
362
  >;
350
363
 
@@ -362,8 +375,8 @@ export type AgentEmitted<TEvents extends EventObject> =
362
375
  message: AgentMessage;
363
376
  }
364
377
  | {
365
- type: 'plan';
366
- plan: AgentPlan<TEvents>;
378
+ type: 'decision';
379
+ decision: AgentDecision<TEvents>;
367
380
  };
368
381
 
369
382
  export type AgentLogic<TEvents extends EventObject> = ActorLogic<
@@ -381,8 +394,8 @@ export type AgentLogic<TEvents extends EventObject> = ActorLogic<
381
394
  message: AgentMessage;
382
395
  }
383
396
  | {
384
- type: 'agent.plan';
385
- plan: AgentPlan<TEvents>;
397
+ type: 'agent.decision';
398
+ decision: AgentDecision<TEvents>;
386
399
  },
387
400
  any, // TODO: input
388
401
  any,
@@ -402,7 +415,7 @@ export type ContextFromZodContextMapping<
402
415
  [K in keyof TContextSchema & string]: TypeOf<TContextSchema[K]>;
403
416
  };
404
417
 
405
- export type AnyAgent = Agent<any, any>;
418
+ export type AnyAgent = Agent<any, any, any, any>;
406
419
 
407
420
  export type FromAgent<T> = T | ((agent: AnyAgent) => T | Promise<T>);
408
421
 
@@ -446,7 +459,7 @@ export type ObservedStateFrom<TActor extends ActorRefLike> = Pick<
446
459
  export type AgentMemoryContext = {
447
460
  observations: AgentObservation<any>[]; // TODO
448
461
  messages: AgentMessage[];
449
- plans: AgentPlan<any>[];
462
+ decisions: AgentDecision<any>[];
450
463
  feedback: AgentFeedback[];
451
464
  };
452
465
 
@@ -465,3 +478,31 @@ export interface AgentLongTermMemory {
465
478
  }
466
479
 
467
480
  export type Compute<A extends any> = { [K in keyof A]: A[K] } & unknown;
481
+
482
+ export type MaybePromise<T> = T | Promise<T>;
483
+
484
+ export type EventsFromAgent<T extends AnyAgent> = T extends Agent<
485
+ infer _,
486
+ infer __,
487
+ infer TEvents,
488
+ infer ___
489
+ >
490
+ ? TEvents
491
+ : never;
492
+
493
+ export type TypesFromAgent<T extends AnyAgent> = T extends Agent<
494
+ infer TContextSchema,
495
+ infer TEventSchema
496
+ >
497
+ ? {
498
+ context: ContextFromZodContextMapping<TContextSchema>;
499
+ events: EventsFromZodEventMapping<TEventSchema>;
500
+ }
501
+ : never;
502
+
503
+ export type ContextFromAgent<T extends AnyAgent> = T extends Agent<
504
+ infer TContextSchema,
505
+ infer _TEventSchema
506
+ >
507
+ ? ContextFromZodContextMapping<TContextSchema>
508
+ : never;
package/src/utils.ts CHANGED
@@ -59,6 +59,18 @@ export function wrapInXml(tagName: string, content: string): string {
59
59
  return `<${tagName}>${content}</${tagName}>`;
60
60
  }
61
61
 
62
+ export function convertToXml(obj: Record<string, any>): string {
63
+ return Object.entries(obj)
64
+ .map(([key, value]) => {
65
+ if (typeof value === 'object' && value !== null) {
66
+ return wrapInXml(key, convertToXml(value));
67
+ } else {
68
+ return wrapInXml(key, value);
69
+ }
70
+ })
71
+ .join('');
72
+ }
73
+
62
74
  export function randomId(prefix?: string): string {
63
75
  const timestamp = Date.now().toString(36);
64
76
  const random = Math.random().toString(36).substring(2, 9);
@@ -103,3 +115,14 @@ export function getTransitions(
103
115
  });
104
116
  return getAllTransitions(resolvedState);
105
117
  }
118
+
119
+ export function isMachineActor(
120
+ actor: ActorRefLike
121
+ ): actor is typeof actor & { src: AnyStateMachine } {
122
+ return (
123
+ 'src' in actor &&
124
+ typeof actor.src === 'object' &&
125
+ actor.src !== null &&
126
+ 'definition' in actor.src
127
+ );
128
+ }
package/vitest.config.ts CHANGED
@@ -1,9 +1,15 @@
1
- // vitest.config.ts
1
+ import { defineConfig } from 'vitest/config';
2
2
  import dotenv from 'dotenv';
3
3
  dotenv.config();
4
4
 
5
- export default {
5
+ export default defineConfig({
6
6
  test: {
7
7
  testTimeout: 10000, // Global timeout of 10000ms for all tests
8
+ coverage: {
9
+ provider: 'v8',
10
+ reporter: ['text', 'json', 'html'],
11
+ exclude: ['**.test.ts'],
12
+ include: ['src'],
13
+ },
8
14
  },
9
- };
15
+ });
@@ -1,106 +0,0 @@
1
- import { GenerateTextResult, LanguageModel } from 'ai';
2
- import wiki, { wikiSearchResult, wikiSummary } from 'wikipedia';
3
- import { assign, fromPromise, setup } from 'xstate';
4
- import { AnyAgent } from '../types';
5
-
6
- const searchWiki = fromPromise(
7
- async ({
8
- input,
9
- }: {
10
- input: {
11
- query: string;
12
- limit?: number;
13
- };
14
- }) => {
15
- const passages = await wiki.search(input.query, {
16
- limit: input.limit ?? 5,
17
- });
18
- return passages;
19
- }
20
- );
21
-
22
- const extractSummaries = fromPromise(
23
- async ({
24
- input,
25
- }: {
26
- input: {
27
- searchResult: wikiSearchResult;
28
- };
29
- }) => {
30
- const summaries = await Promise.all(
31
- input.searchResult.results.map(async (result) => {
32
- const summary = await wiki.summary(result.title);
33
- return {
34
- title: result.title,
35
- summary,
36
- };
37
- })
38
- );
39
- return summaries;
40
- }
41
- );
42
-
43
- export const chainOfNote = setup({
44
- types: {
45
- input: {} as {
46
- model: LanguageModel;
47
- agent: AnyAgent;
48
- prompt: string;
49
- },
50
- context: {} as {
51
- searchResults: wikiSearchResult | null;
52
- summaries:
53
- | {
54
- title: any;
55
- summary: wikiSummary;
56
- }[]
57
- | null;
58
- model: LanguageModel;
59
- agent: AnyAgent;
60
- prompt: string;
61
- },
62
- output: {} as GenerateTextResult<any>,
63
- },
64
- actors: {
65
- searchWiki,
66
- extractSummaries,
67
- },
68
- }).createMachine({
69
- initial: 'searching',
70
- context: ({ input }) => ({
71
- ...input,
72
- searchResults: null,
73
- summaries: null,
74
- }),
75
- states: {
76
- searching: {
77
- invoke: {
78
- src: 'searchWiki',
79
- input: ({ context }) => ({
80
- query: context.prompt,
81
- }),
82
- onDone: {
83
- actions: assign({
84
- searchResults: ({ event }) => event.output,
85
- }),
86
- target: 'extracting',
87
- },
88
- },
89
- },
90
- extracting: {
91
- invoke: {
92
- src: 'extractSummaries',
93
- input: ({ context }) => ({
94
- searchResult: context.searchResults!,
95
- }),
96
- onDone: {
97
- actions: assign({
98
- summaries: ({ event }) => event.output,
99
- }),
100
- target: 'generating',
101
- },
102
- },
103
- },
104
- generating: {},
105
- },
106
- });