@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
@@ -1,10 +1,10 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, fromDecision, fromText } from '../src';
2
+ import { createAgent, EventsFromAgent, fromDecision, fromText } from '../src';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { assign, createActor, setup } from 'xstate';
5
5
 
6
6
  const agent = createAgent({
7
- name: 'example',
7
+ id: 'example',
8
8
  model: openai('gpt-4o-mini'),
9
9
  events: {
10
10
  'agent.englishSummary': z.object({
@@ -18,7 +18,7 @@ const agent = createAgent({
18
18
 
19
19
  const machine = setup({
20
20
  types: {
21
- events: agent.types.events,
21
+ events: {} as EventsFromAgent<typeof agent>,
22
22
  },
23
23
  actors: { agent: fromDecision(agent), summarizer: fromText(agent) },
24
24
  }).createMachine({
package/examples/goal.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, fromDecision } from '../src';
2
+ import { createAgent, EventsFromAgent, fromDecision } from '../src';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { assign, createActor, log, setup } from 'xstate';
5
5
  import { fromTerminal } from './helpers/helpers';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'goal',
8
+ id: 'goal',
9
9
  model: openai('gpt-4o-mini'),
10
10
  events: {
11
11
  'agent.createGoal': z.object({
@@ -25,7 +25,7 @@ const machine = setup({
25
25
  question: string | null;
26
26
  goal: string | null;
27
27
  },
28
- events: agent.types.events,
28
+ events: {} as EventsFromAgent<typeof agent>,
29
29
  },
30
30
  actors: { decider, getFromTerminal: fromTerminal },
31
31
  }).createMachine({
package/examples/joke.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { assign, createActor, fromCallback, log, setup } from 'xstate';
2
- import { createAgent, fromDecision } from '../src';
2
+ import { createAgent, fromDecision, TypesFromAgent } from '../src';
3
3
  import { loadingAnimation } from './helpers/loader';
4
4
  import { z } from 'zod';
5
5
  import { openai } from '@ai-sdk/openai';
@@ -45,7 +45,7 @@ const loader = fromCallback(({ input }: { input: string }) => {
45
45
  });
46
46
 
47
47
  const agent = createAgent({
48
- name: 'joke-teller',
48
+ id: 'joke-teller',
49
49
  model: openai('gpt-4o-mini'),
50
50
  events: {
51
51
  askForTopic: z
@@ -81,7 +81,7 @@ const agent = createAgent({
81
81
  });
82
82
 
83
83
  const jokeMachine = setup({
84
- types: agent.types,
84
+ types: {} as TypesFromAgent<typeof agent>,
85
85
  actors: {
86
86
  agent: fromDecision(agent),
87
87
  loader,
package/examples/jugs.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { createAgent } from '../src';
1
+ import { createAgent, TypesFromAgent } from '../src';
2
2
  import { assign, createActor, setup } from 'xstate';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { z } from 'zod';
5
- import { shortestPathPlanner } from '../src/planners/shortestPathPlanner';
5
+ import { experimental_shortestPathStrategy } from '../src/strategies/shortestPath';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'die-hard-solver',
8
+ id: 'die-hard-solver',
9
9
  model: openai('gpt-4o'),
10
10
  events: {
11
11
  fill3: z.object({}).describe('Fill the 3-gallon jug'),
@@ -38,10 +38,7 @@ const agent = createAgent({
38
38
  });
39
39
 
40
40
  const waterJugMachine = setup({
41
- types: {
42
- context: agent.types.context,
43
- events: agent.types.events,
44
- },
41
+ types: {} as TypesFromAgent<typeof agent>,
45
42
  }).createMachine({
46
43
  initial: 'solving',
47
44
  context: { jug3: 0, jug5: 0 },
@@ -106,7 +103,7 @@ async function main() {
106
103
  machine: waterJugMachine,
107
104
  goal: 'Get exactly 4 gallons of water in the 5-gallon jug',
108
105
  state: waterJugActor.getSnapshot(),
109
- planner: shortestPathPlanner,
106
+ strategy: experimental_shortestPathStrategy,
110
107
  });
111
108
 
112
109
  console.log(decision?.nextEvent);
@@ -0,0 +1,100 @@
1
+ import { z } from 'zod';
2
+ import { createAgent } from '../src';
3
+ import { openai } from '@ai-sdk/openai';
4
+
5
+ const agent = createAgent({
6
+ id: 'chatbot',
7
+ model: openai('gpt-4o-mini'),
8
+ events: {
9
+ submit: z.object({}).describe('Submit the form'),
10
+ pressEnter: z.object({}).describe('Press the enter key'),
11
+ },
12
+ context: {
13
+ userMessage: z.string(),
14
+ },
15
+ });
16
+
17
+ agent.onMessage((msg) => {
18
+ console.log(`Message`, msg.content);
19
+ });
20
+
21
+ agent.on('decision', ({ decision }) => {
22
+ console.log(`Decision: ${decision.nextEvent?.type ?? '??'}`);
23
+ });
24
+
25
+ async function main() {
26
+ let status = 'editing';
27
+ let count = 0;
28
+
29
+ while (status !== 'submitted') {
30
+ console.log(`Attempt ${count} - ${status}`);
31
+ if (count++ > 5) {
32
+ break;
33
+ }
34
+ switch (status) {
35
+ case 'editing': {
36
+ const relevantObservations = await agent
37
+ .getObservations()
38
+ .filter((obs) => obs.prevState.value === 'editing');
39
+ const relevantFeedback = await agent
40
+ .getFeedback()
41
+ .filter((f) =>
42
+ relevantObservations.find((o) => o.id === f.observationId)
43
+ );
44
+
45
+ const decision = await agent.decide({
46
+ goal: 'Submit the form. Take the feedback into consideration, and perform the action that will lead to the form being submitted.',
47
+ state: {
48
+ value: 'editing',
49
+ context: {
50
+ feedback: relevantFeedback.map((f) => {
51
+ const observation = relevantObservations.find(
52
+ (o) => o.id === f.observationId
53
+ );
54
+ return {
55
+ prevState: observation?.prevState,
56
+ event: observation?.event,
57
+ state: observation?.state,
58
+ feedback: f.attributes.text,
59
+ };
60
+ }),
61
+ },
62
+ },
63
+ });
64
+
65
+ if (decision?.nextEvent?.type === 'submit') {
66
+ const observation = await agent.addObservation({
67
+ prevState: { value: 'editing' },
68
+ event: { type: 'submit' },
69
+ state: { value: 'editing' },
70
+ });
71
+
72
+ // don't change the status; pretend submit button is broken
73
+ await agent.addFeedback({
74
+ observationId: observation.id,
75
+ goal: 'Submit the form',
76
+ attributes: {
77
+ text: 'Form not submitted',
78
+ },
79
+ });
80
+ } else if (decision?.nextEvent?.type === 'pressEnter') {
81
+ status = 'submitted';
82
+
83
+ await agent.addObservation({
84
+ prevState: { value: 'editing' },
85
+ event: { type: 'pressEnter' },
86
+ state: { value: 'submitted' },
87
+ });
88
+ }
89
+ break;
90
+ }
91
+ case 'submitted':
92
+ break;
93
+ }
94
+ }
95
+
96
+ console.log('End of conversation.');
97
+ process.exit();
98
+ }
99
+
100
+ main().catch(console.error);
package/examples/multi.ts CHANGED
@@ -5,7 +5,7 @@ import { fromTerminal } from './helpers/helpers';
5
5
  import { openai } from '@ai-sdk/openai';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'multi',
8
+ id: 'multi',
9
9
  model: openai('gpt-4o-mini'),
10
10
  events: {
11
11
  'agent.respond': z.object({
@@ -1,11 +1,11 @@
1
- import { createAgent, fromDecision } from '../src';
1
+ import { createAgent, EventsFromAgent, fromDecision } from '../src';
2
2
  import { assign, createActor, log, setup } from 'xstate';
3
3
  import { z } from 'zod';
4
4
  import { openai } from '@ai-sdk/openai';
5
5
  import { fromTerminal } from './helpers/helpers';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'number-guesser',
8
+ id: 'number-guesser',
9
9
  model: openai('gpt-3.5-turbo-1106'),
10
10
  events: {
11
11
  'agent.guess': z.object({
@@ -21,7 +21,7 @@ const machine = setup({
21
21
  previousGuesses: number[];
22
22
  answer: number | null;
23
23
  },
24
- events: agent.types.events,
24
+ events: {} as EventsFromAgent<typeof agent>,
25
25
  },
26
26
  actors: {
27
27
  agent: fromDecision(agent),
@@ -1,11 +1,11 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, fromDecision } from '../src';
2
+ import { createAgent, EventsFromAgent, fromDecision } from '../src';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { assign, createActor, log, setup } from 'xstate';
5
5
  import { fromTerminal } from './helpers/helpers';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'raffle-chooser',
8
+ id: 'raffle-chooser',
9
9
  model: openai('gpt-4o-mini'),
10
10
  events: {
11
11
  'agent.collectEntries': z.object({}).describe('Collect more entries'),
@@ -27,7 +27,7 @@ const machine = setup({
27
27
  lastInput: string | null;
28
28
  entries: string[];
29
29
  },
30
- events: agent.types.events,
30
+ events: {} as EventsFromAgent<typeof agent>,
31
31
  },
32
32
  actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
33
33
  }).createMachine({
@@ -1,11 +1,11 @@
1
- import { createAgent } from '../src';
1
+ import { createAgent, TypesFromAgent } from '../src';
2
2
  import { assign, createActor, setup } from 'xstate';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { z } from 'zod';
5
- import { shortestPathPlanner } from '../src/planners/shortestPathPlanner';
5
+ import { experimental_shortestPathStrategy } from '../src/strategies/shortestPath';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'river-crossing-solver',
8
+ id: 'river-crossing-solver',
9
9
  model: openai('gpt-4'),
10
10
  events: {
11
11
  takeWolf: z
@@ -45,10 +45,7 @@ const agent = createAgent({
45
45
  });
46
46
 
47
47
  const riverCrossingMachine = setup({
48
- types: {
49
- context: agent.types.context,
50
- events: agent.types.events,
51
- },
48
+ types: {} as TypesFromAgent<typeof agent>,
52
49
  }).createMachine({
53
50
  initial: 'solving',
54
51
  context: {
@@ -121,7 +118,7 @@ async function main() {
121
118
  machine: riverCrossingMachine,
122
119
  goal: 'Get all items safely across the river. Remember: Cannot leave wolf with goat or goat with cabbage unattended.',
123
120
  state: riverActor.getSnapshot(),
124
- planner: shortestPathPlanner,
121
+ strategy: experimental_shortestPathStrategy,
125
122
  });
126
123
 
127
124
  console.log(decision?.nextEvent);
@@ -1,10 +1,11 @@
1
1
  import { createAgent, fromDecision } from '../src';
2
2
  import { z } from 'zod';
3
- import { setup, createActor } from 'xstate';
3
+ import { setup, createActor, createMachine } from 'xstate';
4
4
  import { openai } from '@ai-sdk/openai';
5
+ import { chainOfThoughtStrategy } from '../src/strategies/chainOfThought';
5
6
 
6
7
  const agent = createAgent({
7
- name: 'simple',
8
+ id: 'simple',
8
9
  model: openai('gpt-4o-mini'),
9
10
  events: {
10
11
  'agent.thought': z.object({
@@ -13,18 +14,10 @@ const agent = createAgent({
13
14
  },
14
15
  });
15
16
 
16
- const machine = setup({
17
- actors: { agent: fromDecision(agent) },
18
- }).createMachine({
17
+ const machine = createMachine({
19
18
  initial: 'thinking',
20
19
  states: {
21
20
  thinking: {
22
- invoke: {
23
- src: 'agent',
24
- input: {
25
- goal: 'Think about a random topic, and then share that thought.',
26
- },
27
- },
28
21
  on: {
29
22
  'agent.thought': {
30
23
  actions: ({ event }) => console.log(event.text),
@@ -39,3 +32,13 @@ const machine = setup({
39
32
  });
40
33
 
41
34
  const actor = createActor(machine).start();
35
+
36
+ agent.onMessage(console.log);
37
+
38
+ agent.interact(actor, (obs) => {
39
+ if (obs.state.matches('thinking')) {
40
+ return {
41
+ goal: 'Think about a random topic, and then share that thought.',
42
+ };
43
+ }
44
+ });
@@ -1,11 +1,11 @@
1
- import { createAgent, fromDecision } from '../src';
1
+ import { createAgent, fromDecision, TypesFromAgent } from '../src';
2
2
  import { assign, createActor, setup } from 'xstate';
3
3
  import { z } from 'zod';
4
4
  import { openai } from '@ai-sdk/openai';
5
5
  import { fromTerminal } from './helpers/helpers';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'summarizing-chat',
8
+ id: 'summarizing-chat',
9
9
  model: openai('gpt-4o'),
10
10
  events: {
11
11
  'agent.respond': z.object({
@@ -27,10 +27,7 @@ const agent = createAgent({
27
27
  });
28
28
 
29
29
  const machine = setup({
30
- types: {
31
- context: agent.types.context,
32
- events: agent.types.events,
33
- },
30
+ types: {} as TypesFromAgent<typeof agent>,
34
31
  actors: {
35
32
  agent: fromDecision(agent),
36
33
  fromTerminal,
@@ -1,10 +1,10 @@
1
1
  import { openai } from '@ai-sdk/openai';
2
- import { createAgent, fromDecision } from '../src';
2
+ import { createAgent, EventsFromAgent, fromDecision } from '../src';
3
3
  import { z } from 'zod';
4
4
  import { createActor, log, setup } from 'xstate';
5
5
 
6
6
  const agent = createAgent({
7
- name: 'support-agent',
7
+ id: 'support-agent',
8
8
  model: openai('gpt-4o-mini'),
9
9
  events: {
10
10
  'agent.respond': z.object({
@@ -35,7 +35,7 @@ const agent = createAgent({
35
35
 
36
36
  const machine = setup({
37
37
  types: {
38
- events: agent.types.events,
38
+ events: {} as EventsFromAgent<typeof agent>,
39
39
  input: {} as string,
40
40
  context: {} as {
41
41
  customerIssue: string;
@@ -49,20 +49,6 @@ const machine = setup({
49
49
  }),
50
50
  states: {
51
51
  frontline: {
52
- invoke: {
53
- src: 'agent',
54
- input: ({ context }) => ({
55
- context,
56
- system: `You are frontline support staff for LangCorp, a company that sells computers.
57
- Be concise in your responses.
58
- You can chat with customers and help them with basic questions, but if the customer is having a billing or technical problem,
59
- do not try to answer the question directly or gather information.
60
- Instead, immediately transfer them to the billing or technical team by asking the user to hold for a moment.
61
- Otherwise, just respond conversationally.`,
62
- goal: `The previous conversation is an interaction between a customer support representative and a user.
63
- Classify whether the representative is routing the user to a billing or technical team, or whether they are just responding conversationally.`,
64
- }),
65
- },
66
52
  on: {
67
53
  'agent.frontline.classify': [
68
54
  {
@@ -83,14 +69,6 @@ const machine = setup({
83
69
  },
84
70
  },
85
71
  billing: {
86
- invoke: {
87
- src: 'agent',
88
- input: {
89
- system:
90
- 'Your job is to detect whether a billing support representative wants to refund the user.',
91
- goal: `The following text is a response from a customer support representative. Extract whether they want to refund the user or not.`,
92
- },
93
- },
94
72
  on: {
95
73
  'agent.refund': {
96
74
  actions: log(({ event }) => event),
@@ -99,14 +77,6 @@ const machine = setup({
99
77
  },
100
78
  },
101
79
  technical: {
102
- invoke: {
103
- src: 'agent',
104
- input: ({ context }) => ({
105
- context,
106
- system: `You are an expert at diagnosing technical computer issues. You work for a company called LangCorp that sells computers. Help the user to the best of your ability, but be concise in your responses.`,
107
- goal: 'Solve the customer issue.',
108
- }),
109
- },
110
80
  on: {
111
81
  'agent.technical.solve': {
112
82
  actions: log(({ event }) => event),
@@ -115,12 +85,6 @@ const machine = setup({
115
85
  },
116
86
  },
117
87
  conversational: {
118
- invoke: {
119
- src: 'agent',
120
- input: {
121
- goal: 'You are a customer support agent that is ending the conversation with the customer. Respond politely and thank them for their time.',
122
- },
123
- },
124
88
  on: {
125
89
  'agent.endConversation': {
126
90
  actions: log(({ event }) => event),
@@ -145,3 +109,43 @@ const actor = createActor(machine, {
145
109
  });
146
110
 
147
111
  actor.start();
112
+
113
+ agent.interact(actor, (observation) => {
114
+ if (observation.state.matches('frontline')) {
115
+ return {
116
+ goal: `The previous conversation is an interaction between a customer support representative and a user.
117
+ Classify whether the representative is routing the user to a billing or technical team, or whether they are just responding conversationally.`,
118
+ system: `You are frontline support staff for LangCorp, a company that sells computers.
119
+ Be concise in your responses.
120
+ You can chat with customers and help them with basic questions, but if the customer is having a billing or technical problem,
121
+ do not try to answer the question directly or gather information.
122
+ Instead, immediately transfer them to the billing or technical team by asking the user to hold for a moment.
123
+ Otherwise, just respond conversationally.`,
124
+ context: observation.state.context,
125
+ };
126
+ }
127
+
128
+ if (observation.state.matches('billing')) {
129
+ return {
130
+ goal: `The following text is a response from a customer support representative. Extract whether they want to refund the user or not.`,
131
+ system: `Your job is to detect whether a billing support representative wants to refund the user.`,
132
+ context: observation.state.context,
133
+ };
134
+ }
135
+
136
+ if (observation.state.matches('technical')) {
137
+ return {
138
+ goal: 'Solve the customer issue.',
139
+ system: `You are an expert at diagnosing technical computer issues. You work for a company called LangCorp that sells computers. Help the user to the best of your ability, but be concise in your responses.`,
140
+ context: observation.state.context,
141
+ };
142
+ }
143
+
144
+ if (observation.state.matches('conversational')) {
145
+ return {
146
+ goal: 'You are a customer support agent that is ending the conversation with the customer. Respond politely and thank them for their time.',
147
+ system: `You are a customer support agent that is ending the conversation with the customer. Respond politely and thank them for their time.`,
148
+ context: observation.state.context,
149
+ };
150
+ }
151
+ });
@@ -1,7 +1,16 @@
1
1
  import { assign, setup, assertEvent, createActor } from 'xstate';
2
2
  import { z } from 'zod';
3
- import { createAgent, fromDecision, fromTextStream } from '../src';
3
+ import {
4
+ ContextFromAgent,
5
+ createAgent,
6
+ EventsFromAgent,
7
+ fromDecision,
8
+ fromTextStream,
9
+ TypesFromAgent,
10
+ } from '../src';
4
11
  import { openai } from '@ai-sdk/openai';
12
+ import { generateObject, generateText } from 'ai';
13
+ import * as fs from 'fs';
5
14
 
6
15
  const events = {
7
16
  'agent.x.play': z.object({
@@ -39,19 +48,30 @@ const context = {
39
48
  };
40
49
 
41
50
  const xAgent = createAgent({
42
- name: 'tic-tac-toe-learner',
51
+ id: 'tic-tac-toe-learner',
43
52
  model: openai('gpt-4o-mini'),
44
53
  events,
45
54
  context,
46
55
  });
47
56
 
48
57
  const oAgent = createAgent({
49
- name: 'tic-tac-toe-noob',
58
+ id: 'tic-tac-toe-noob',
50
59
  model: openai('gpt-4o-mini'),
51
60
  events,
52
61
  context,
53
62
  });
54
63
 
64
+ const feedbackAgent = createAgent({
65
+ id: 'tic-tac-toe-expert',
66
+ model: openai('gpt-4o-mini'),
67
+ description: 'You are an expert in tic-tac-toe.',
68
+ events: {
69
+ 'agent.feedback': z.object({
70
+ feedback: z.string(),
71
+ }),
72
+ },
73
+ });
74
+
55
75
  type Player = 'x' | 'o';
56
76
 
57
77
  const initialContext = {
@@ -60,7 +80,7 @@ const initialContext = {
60
80
  player: 'x' as Player,
61
81
  gameReport: '',
62
82
  lastReason: '',
63
- } satisfies typeof xAgent.types.context;
83
+ } satisfies ContextFromAgent<typeof xAgent>;
64
84
 
65
85
  function getWinner(board: typeof initialContext.board): Player | null {
66
86
  const lines = [
@@ -83,9 +103,9 @@ function getWinner(board: typeof initialContext.board): Player | null {
83
103
 
84
104
  export const ticTacToeMachine = setup({
85
105
  types: {
86
- context: xAgent.types.context,
106
+ context: {} as ContextFromAgent<typeof xAgent>,
87
107
  events: {} as
88
- | typeof xAgent.types.events
108
+ | EventsFromAgent<typeof xAgent>
89
109
  | {
90
110
  type: 'reset';
91
111
  },
@@ -236,6 +256,23 @@ const actor = createActor(ticTacToeMachine);
236
256
 
237
257
  xAgent.interact(actor, (observed) => {
238
258
  if (observed.state.matches({ playing: 'x' })) {
259
+ // get similar observations
260
+ const similarObservations = xAgent.getObservations().filter((o) => {
261
+ return (
262
+ o.prevState &&
263
+ JSON.stringify(o.prevState.context.board) ===
264
+ JSON.stringify(observed.state.context.board)
265
+ );
266
+ });
267
+
268
+ console.log('Similar:', similarObservations);
269
+
270
+ const similarFeedbacks = similarObservations.map((o) => {
271
+ return xAgent.getFeedback().filter((f) => f.observationId === o.id);
272
+ });
273
+
274
+ console.log('Feedbacks:', similarFeedbacks);
275
+
239
276
  return {
240
277
  goal: `You are playing a game of tic tac toe. This is the current game state. The 3x3 board is represented by a 9-element array. The first element is the top-left cell, the second element is the top-middle cell, the third element is the top-right cell, the fourth element is the middle-left cell, and so on. The value of each cell is either null, x, or o. The value of null means that the cell is empty.
241
278
 
@@ -262,4 +299,9 @@ Execute the single best next move to try to win the game. Do not play on an exis
262
299
  return;
263
300
  });
264
301
 
302
+ xAgent.on('observation', (observation) => {
303
+ // append the observation to a jsonl file
304
+ fs.appendFileSync('observations.jsonl', JSON.stringify(observation) + '\n');
305
+ });
306
+
265
307
  actor.start();
package/examples/todo.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { assign, setup, assertEvent, createActor, createMachine } from 'xstate';
2
2
  import { z } from 'zod';
3
- import { createAgent, fromDecision } from '../src';
3
+ import { createAgent, EventsFromAgent, fromDecision } from '../src';
4
4
  import { openai } from '@ai-sdk/openai';
5
5
  import { fromTerminal } from './helpers/helpers';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'todo',
8
+ id: 'todo',
9
9
  model: openai('gpt-4o-mini'),
10
10
  events: {
11
11
  addTodo: z.object({
@@ -37,7 +37,7 @@ const machine = setup({
37
37
  command: string | null;
38
38
  },
39
39
  events: {} as
40
- | typeof agent.types.events
40
+ | EventsFromAgent<typeof agent>
41
41
  | { type: 'assist'; command: string },
42
42
  },
43
43
  actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
package/examples/tutor.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { assign, createActor, log, setup } from 'xstate';
2
2
  import { fromTerminal } from './helpers/helpers';
3
- import { createAgent, fromDecision } from '../src';
3
+ import { createAgent, EventsFromAgent, fromDecision } from '../src';
4
4
  import { z } from 'zod';
5
5
  import { openai } from '@ai-sdk/openai';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'tutor',
8
+ id: 'tutor',
9
9
  model: openai('gpt-4o-mini'),
10
10
  events: {
11
11
  teach: z.object({
@@ -19,7 +19,7 @@ const agent = createAgent({
19
19
  response: z.string().describe('The response to the human in Spanish'),
20
20
  }),
21
21
  },
22
- system:
22
+ description:
23
23
  'You are an expert Spanish tutor. You will respond to the human in Spanish.',
24
24
  });
25
25
 
@@ -28,7 +28,7 @@ const machine = setup({
28
28
  context: {} as {
29
29
  conversation: string[];
30
30
  },
31
- events: agent.types.events,
31
+ events: {} as EventsFromAgent<typeof agent>,
32
32
  },
33
33
  actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
34
34
  }).createMachine({