@statelyai/agent 2.0.0-next.2 → 2.0.0-next.3

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/examples/cot.ts CHANGED
@@ -1,19 +1,13 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, fromDecision, TypesFromAgent } from '../src';
2
+ import { createAgent } from '../src';
3
3
  import { openai } from '@ai-sdk/openai';
4
- import { assign, createActor, log, setup } from 'xstate';
5
- import { fromTerminal } from './helpers/helpers';
4
+ import { getFromTerminal } from './helpers/helpers';
6
5
  import { chainOfThoughtStrategy } from '../src/strategies/chainOfThought';
7
6
 
8
7
  const agent = createAgent({
9
8
  id: 'chain-of-thought',
10
- model: openai('gpt-4o-mini'),
9
+ model: openai('gpt-4o'),
11
10
  events: {
12
- 'agent.think': z.object({
13
- thought: z
14
- .string()
15
- .describe('The thought process to answering the question'),
16
- }),
17
11
  'agent.answer': z.object({
18
12
  answer: z.string().describe('The answer to the question'),
19
13
  }),
@@ -24,51 +18,23 @@ const agent = createAgent({
24
18
  strategy: chainOfThoughtStrategy,
25
19
  });
26
20
 
27
- const machine = setup({
28
- types: {} as TypesFromAgent<typeof agent>,
29
- actors: { getFromTerminal: fromTerminal },
30
- }).createMachine({
31
- initial: 'asking',
32
- context: {
33
- question: null,
34
- },
35
- states: {
36
- asking: {
37
- invoke: {
38
- src: 'getFromTerminal',
39
- input: 'What would you like to ask?',
40
- onDone: {
41
- actions: assign({
42
- question: ({ event }) => event.output,
43
- }),
44
- target: 'answering',
45
- },
46
- },
47
- },
48
- answering: {
49
- on: {
50
- 'agent.answer': {
51
- actions: log(({ event }) => `Answer: ${event.answer}`),
52
- target: 'answered',
53
- },
21
+ // agent.onMessage((msg) => console.log(msg.content));
22
+
23
+ async function main() {
24
+ const msg = await getFromTerminal('what?');
25
+
26
+ const decision = await agent.decide({
27
+ messages: agent.getMessages(),
28
+ goal: 'Answer the question.',
29
+ state: {
30
+ value: 'thinking',
31
+ context: {
32
+ question: msg,
54
33
  },
55
34
  },
56
- answered: {
57
- type: 'final',
58
- },
59
- },
60
- });
61
-
62
- const actor = createActor(machine).start();
35
+ });
63
36
 
64
- agent.onMessage(console.log);
37
+ console.log(decision?.nextEvent?.answer);
38
+ }
65
39
 
66
- agent.interact(actor, (obs) => {
67
- if (obs.state.matches('answering')) {
68
- return {
69
- goal: 'Answer the question',
70
- context: obs.state.context,
71
- messages: agent.getMessages(),
72
- };
73
- }
74
- });
40
+ main();
@@ -1,4 +1,4 @@
1
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
1
+ import { createAgent, EventFromAgent, fromDecision } from '../src';
2
2
  import { assign, createActor, setup } from 'xstate';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { z } from 'zod';
@@ -38,8 +38,8 @@ const machine = setup({
38
38
  messages: string[];
39
39
  },
40
40
  events: {} as
41
- | EventsFromAgent<typeof customerServiceAgent>
42
- | EventsFromAgent<typeof customerAgent>,
41
+ | EventFromAgent<typeof customerServiceAgent>
42
+ | EventFromAgent<typeof customerAgent>,
43
43
  },
44
44
  actors: {
45
45
  customerService: fromDecision(customerServiceAgent),
package/examples/email.ts CHANGED
@@ -1,11 +1,5 @@
1
1
  import { z } from 'zod';
2
- import {
3
- ContextFromAgent,
4
- createAgent,
5
- EventsFromAgent,
6
- fromDecision,
7
- TypesFromAgent,
8
- } from '../src';
2
+ import { ContextFromAgent, createAgent, EventFromAgent } from '../src';
9
3
  import { openai } from '@ai-sdk/openai';
10
4
  import { assign, createActor, setup } from 'xstate';
11
5
  import { fromTerminal } from './helpers/helpers';
@@ -33,7 +27,7 @@ const agent = createAgent({
33
27
 
34
28
  const machine = setup({
35
29
  types: {
36
- events: {} as EventsFromAgent<typeof agent>,
30
+ events: {} as EventFromAgent<typeof agent>,
37
31
  input: {} as {
38
32
  email: string;
39
33
  instructions: string;
@@ -107,14 +101,12 @@ agent.interact(actor, ({ state }) => {
107
101
  if (state.matches('checking')) {
108
102
  return {
109
103
  goal: 'Respond to the email given the instructions and the provided clarifications. If not enough information is provided, ask for clarification. Otherwise, if you are absolutely sure that there is no ambiguous or missing information, create and submit a response email.',
110
- context: state.context,
111
104
  };
112
105
  }
113
106
 
114
107
  if (state.matches('submitting')) {
115
108
  return {
116
109
  goal: 'Create and submit an email based on the instructions.',
117
- context: state.context,
118
110
  };
119
111
  }
120
112
  });
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, EventsFromAgent, fromDecision, fromText } from '../src';
2
+ import { createAgent, EventFromAgent, fromDecision, fromText } from '../src';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { assign, createActor, setup } from 'xstate';
5
5
 
@@ -18,7 +18,7 @@ const agent = createAgent({
18
18
 
19
19
  const machine = setup({
20
20
  types: {
21
- events: {} as EventsFromAgent<typeof agent>,
21
+ events: {} as EventFromAgent<typeof agent>,
22
22
  },
23
23
  actors: { agent: fromDecision(agent), summarizer: fromText(agent) },
24
24
  }).createMachine({
package/examples/goal.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
2
+ import { createAgent, EventFromAgent, 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';
@@ -25,7 +25,7 @@ const machine = setup({
25
25
  question: string | null;
26
26
  goal: string | null;
27
27
  },
28
- events: {} as EventsFromAgent<typeof agent>,
28
+ events: {} as EventFromAgent<typeof agent>,
29
29
  },
30
30
  actors: { decider, getFromTerminal: fromTerminal },
31
31
  }).createMachine({
package/examples/joke.ts CHANGED
@@ -186,40 +186,40 @@ const jokeMachine = setup({
186
186
 
187
187
  const actor = createActor(jokeMachine);
188
188
 
189
- agent.interact(actor, (observed) => {
190
- if (observed.state.matches('tellingJoke')) {
189
+ agent.interact(actor, ({ state }) => {
190
+ if (state.matches('tellingJoke')) {
191
191
  return {
192
192
  goal: 'Tell me a joke about the topic. Do not make any joke that is not relevant to the topic.',
193
193
  context: {
194
- topic: observed.state.context.topic,
194
+ topic: state.context.topic,
195
195
  },
196
196
  };
197
197
  }
198
198
 
199
- if (observed.state.matches('relevance')) {
199
+ if (state.matches('relevance')) {
200
200
  return {
201
201
  goal: 'An irrelevant joke has no reference to the topic. If the last joke is completely irrelevant to the topic, ask for a new joke topic. Otherwise, continue.',
202
202
  context: {
203
- topic: observed.state.context.topic,
204
- lastJoke: observed.state.context.jokes.at(-1),
203
+ topic: state.context.topic,
204
+ lastJoke: state.context.jokes.at(-1),
205
205
  },
206
206
  };
207
207
  }
208
208
 
209
- if (observed.state.matches('rateJoke')) {
209
+ if (state.matches('rateJoke')) {
210
210
  return {
211
211
  goal: 'Rate the last joke on a scale of 1 to 10.',
212
212
  context: {
213
- lastJoke: observed.state.context.jokes.at(-1),
213
+ lastJoke: state.context.jokes.at(-1),
214
214
  },
215
215
  };
216
216
  }
217
217
 
218
- if (observed.state.matches('decide')) {
218
+ if (state.matches('decide')) {
219
219
  return {
220
220
  goal: 'Choose what to do next, given the previous rating of the joke.',
221
221
  context: {
222
- lastRating: observed.state.context.lastRating,
222
+ lastRating: state.context.lastRating,
223
223
  },
224
224
  };
225
225
  }
@@ -14,10 +14,6 @@ const agent = createAgent({
14
14
  },
15
15
  });
16
16
 
17
- agent.onMessage((msg) => {
18
- console.log(`Message`, msg.content);
19
- });
20
-
21
17
  agent.on('decision', ({ decision }) => {
22
18
  console.log(`Decision: ${decision.nextEvent?.type ?? '??'}`);
23
19
  });
@@ -27,7 +23,7 @@ async function main() {
27
23
  let count = 0;
28
24
 
29
25
  while (status !== 'submitted') {
30
- console.log(`Attempt ${count} - ${status}`);
26
+ console.log(`\nState: ${status} (attempt ${count + 1})`);
31
27
  if (count++ > 5) {
32
28
  break;
33
29
  }
@@ -43,27 +39,48 @@ async function main() {
43
39
  );
44
40
 
45
41
  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.',
42
+ goal: `
43
+ <currentState>editing</currentState>
44
+
45
+ <actions>
46
+ <action id="pressEnter">
47
+ <exploration_value>0.2</exploration_value>
48
+ <known_outcomes></known_outcomes>
49
+ </action>
50
+ <action id="submit">
51
+ <exploration_value>0.8</exploration_value>
52
+ <known_outcomes>
53
+ <outcome probability="0.1">editing</outcome>
54
+ <outcome probability="0.9">submitted</outcome>
55
+ </known_outcomes>
56
+ </action>
57
+ </actions>
58
+
59
+ <goal>Submit the form.</goal>
60
+
61
+ Achieve the goal. Consider both exploring unknown actions (high exploration_value) and using actions with known outcomes. Prefer exploration when an action has no known outcomes.
62
+ `.trim(),
47
63
  state: {
48
64
  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
- },
65
+ // context: {
66
+ // feedback: relevantFeedback.map((f) => {
67
+ // const observation = relevantObservations.find(
68
+ // (o) => o.id === f.observationId
69
+ // );
70
+ // return {
71
+ // prevState: observation?.prevState,
72
+ // event: observation?.event,
73
+ // state: observation?.state,
74
+ // comment: f.comment,
75
+ // };
76
+ // }),
77
+ // },
62
78
  },
63
79
  });
64
80
 
65
81
  if (decision?.nextEvent?.type === 'submit') {
66
82
  const observation = await agent.addObservation({
83
+ goal: decision.goal,
67
84
  prevState: { value: 'editing' },
68
85
  event: { type: 'submit' },
69
86
  state: { value: 'editing' },
@@ -72,15 +89,14 @@ async function main() {
72
89
  // don't change the status; pretend submit button is broken
73
90
  await agent.addFeedback({
74
91
  observationId: observation.id,
75
- goal: 'Submit the form',
76
- attributes: {
77
- text: 'Form not submitted',
78
- },
92
+ score: 0,
93
+ comment: 'Form not submitted',
79
94
  });
80
95
  } else if (decision?.nextEvent?.type === 'pressEnter') {
81
96
  status = 'submitted';
82
97
 
83
98
  await agent.addObservation({
99
+ goal: decision.goal,
84
100
  prevState: { value: 'editing' },
85
101
  event: { type: 'pressEnter' },
86
102
  state: { value: 'submitted' },
@@ -93,8 +109,15 @@ async function main() {
93
109
  }
94
110
  }
95
111
 
96
- console.log('End of conversation.');
112
+ if (status === 'submitted') {
113
+ console.log('Success!');
114
+ } else {
115
+ console.log('Failure!');
116
+ }
97
117
  process.exit();
98
118
  }
99
119
 
120
+ agent.onMessage((msg) => {
121
+ // console.log(msg.content);
122
+ });
100
123
  main().catch(console.error);
@@ -1,4 +1,4 @@
1
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
1
+ import { createAgent, EventFromAgent, 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';
@@ -21,7 +21,7 @@ const machine = setup({
21
21
  previousGuesses: number[];
22
22
  answer: number | null;
23
23
  },
24
- events: {} as EventsFromAgent<typeof agent>,
24
+ events: {} as EventFromAgent<typeof agent>,
25
25
  },
26
26
  actors: {
27
27
  agent: fromDecision(agent),
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
2
+ import { createAgent, EventFromAgent, 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';
@@ -27,7 +27,7 @@ const machine = setup({
27
27
  lastInput: string | null;
28
28
  entries: string[];
29
29
  },
30
- events: {} as EventsFromAgent<typeof agent>,
30
+ events: {} as EventFromAgent<typeof agent>,
31
31
  },
32
32
  actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
33
33
  }).createMachine({
@@ -1,5 +1,5 @@
1
1
  import { openai } from '@ai-sdk/openai';
2
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
2
+ import { createAgent, EventFromAgent, fromDecision } from '../src';
3
3
  import { z } from 'zod';
4
4
  import { createActor, log, setup } from 'xstate';
5
5
 
@@ -35,7 +35,7 @@ const agent = createAgent({
35
35
 
36
36
  const machine = setup({
37
37
  types: {
38
- events: {} as EventsFromAgent<typeof agent>,
38
+ events: {} as EventFromAgent<typeof agent>,
39
39
  input: {} as string,
40
40
  context: {} as {
41
41
  customerIssue: string;
@@ -110,8 +110,8 @@ const actor = createActor(machine, {
110
110
 
111
111
  actor.start();
112
112
 
113
- agent.interact(actor, (observation) => {
114
- if (observation.state.matches('frontline')) {
113
+ agent.interact(actor, ({ state }) => {
114
+ if (state.matches('frontline')) {
115
115
  return {
116
116
  goal: `The previous conversation is an interaction between a customer support representative and a user.
117
117
  Classify whether the representative is routing the user to a billing or technical team, or whether they are just responding conversationally.`,
@@ -121,31 +121,27 @@ agent.interact(actor, (observation) => {
121
121
  do not try to answer the question directly or gather information.
122
122
  Instead, immediately transfer them to the billing or technical team by asking the user to hold for a moment.
123
123
  Otherwise, just respond conversationally.`,
124
- context: observation.state.context,
125
124
  };
126
125
  }
127
126
 
128
- if (observation.state.matches('billing')) {
127
+ if (state.matches('billing')) {
129
128
  return {
130
129
  goal: `The following text is a response from a customer support representative. Extract whether they want to refund the user or not.`,
131
130
  system: `Your job is to detect whether a billing support representative wants to refund the user.`,
132
- context: observation.state.context,
133
131
  };
134
132
  }
135
133
 
136
- if (observation.state.matches('technical')) {
134
+ if (state.matches('technical')) {
137
135
  return {
138
136
  goal: 'Solve the customer issue.',
139
137
  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
138
  };
142
139
  }
143
140
 
144
- if (observation.state.matches('conversational')) {
141
+ if (state.matches('conversational')) {
145
142
  return {
146
143
  goal: 'You are a customer support agent that is ending the conversation with the customer. Respond politely and thank them for their time.',
147
144
  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
145
  };
150
146
  }
151
147
  });
@@ -3,7 +3,7 @@ import { z } from 'zod';
3
3
  import {
4
4
  ContextFromAgent,
5
5
  createAgent,
6
- EventsFromAgent,
6
+ EventFromAgent,
7
7
  fromDecision,
8
8
  fromTextStream,
9
9
  TypesFromAgent,
@@ -105,7 +105,7 @@ export const ticTacToeMachine = setup({
105
105
  types: {
106
106
  context: {} as ContextFromAgent<typeof xAgent>,
107
107
  events: {} as
108
- | EventsFromAgent<typeof xAgent>
108
+ | EventFromAgent<typeof xAgent>
109
109
  | {
110
110
  type: 'reset';
111
111
  },
package/examples/todo.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { assign, setup, assertEvent, createActor, createMachine } from 'xstate';
1
+ import { assign, setup, createActor } from 'xstate';
2
2
  import { z } from 'zod';
3
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
3
+ import { createAgent, EventFromAgent, fromDecision } from '../src';
4
4
  import { openai } from '@ai-sdk/openai';
5
5
  import { fromTerminal } from './helpers/helpers';
6
6
 
@@ -37,7 +37,7 @@ const machine = setup({
37
37
  command: string | null;
38
38
  },
39
39
  events: {} as
40
- | EventsFromAgent<typeof agent>
40
+ | EventFromAgent<typeof agent>
41
41
  | { type: 'assist'; command: string },
42
42
  },
43
43
  actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
package/examples/tutor.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { assign, createActor, log, setup } from 'xstate';
2
2
  import { fromTerminal } from './helpers/helpers';
3
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
3
+ import { createAgent, EventFromAgent, fromDecision } from '../src';
4
4
  import { z } from 'zod';
5
5
  import { openai } from '@ai-sdk/openai';
6
6
 
@@ -28,7 +28,7 @@ const machine = setup({
28
28
  context: {} as {
29
29
  conversation: string[];
30
30
  },
31
- events: {} as EventsFromAgent<typeof agent>,
31
+ events: {} as EventFromAgent<typeof agent>,
32
32
  },
33
33
  actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
34
34
  }).createMachine({
@@ -1,6 +1,6 @@
1
1
  import { assign, createActor, setup, log } from 'xstate';
2
2
  import { fromTerminal } from './helpers/helpers';
3
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
3
+ import { createAgent, EventFromAgent, fromDecision } from '../src';
4
4
  import { z } from 'zod';
5
5
  import { openai } from '@ai-sdk/openai';
6
6
 
@@ -35,7 +35,7 @@ const machine = setup({
35
35
  answer: string | null;
36
36
  validation: string | null;
37
37
  },
38
- events: {} as EventsFromAgent<typeof agent>,
38
+ events: {} as EventFromAgent<typeof agent>,
39
39
  },
40
40
  actors: {
41
41
  getFromTerminal: fromTerminal,
@@ -122,19 +122,17 @@ const machine = setup({
122
122
  // Create and start the actor
123
123
  const actor = createActor(machine).start();
124
124
 
125
- agent.interact(actor, (obs) => {
126
- if (obs.state.matches('processing')) {
125
+ agent.interact(actor, ({ state }) => {
126
+ if (state.matches('processing')) {
127
127
  return {
128
128
  goal: 'Determine if user is asking about weather and for which location. If so, get the weather. Otherwise, respond to the user.',
129
- context: obs.state.context,
130
129
  messages: agent.getMessages(),
131
130
  };
132
131
  }
133
132
 
134
- if (obs.state.matches('responding')) {
133
+ if (state.matches('responding')) {
135
134
  return {
136
135
  goal: 'Provide a natural response about the weather in ${context.location}',
137
- context: obs.state.context,
138
136
  messages: agent.getMessages(),
139
137
  };
140
138
  }
@@ -1,4 +1,4 @@
1
- import { createAgent, EventsFromAgent, fromDecision } from '../src';
1
+ import { createAgent, EventFromAgent, fromDecision } from '../src';
2
2
  import { assign, createActor, fromPromise, log, setup } from 'xstate';
3
3
  import { fromTerminal } from './helpers/helpers';
4
4
  import { z } from 'zod';
@@ -78,7 +78,7 @@ const machine = setup({
78
78
  count: number;
79
79
  result: string | null;
80
80
  },
81
- events: {} as EventsFromAgent<typeof agent>,
81
+ events: {} as EventFromAgent<typeof agent>,
82
82
  },
83
83
  actors: {
84
84
  agent: fromDecision(agent),
@@ -156,20 +156,23 @@ const machine = setup({
156
156
  const actor = createActor(machine);
157
157
  actor.start();
158
158
 
159
- agent.interact(actor, (obs) => {
160
- if (obs.state.matches('decide')) {
159
+ agent.interact(actor, ({ state }) => {
160
+ if (state.matches('decide')) {
161
161
  return {
162
162
  goal: `Decide what to do based on the given location, which may or may not be a location`,
163
163
  context: {
164
- location: obs.state.context.location,
164
+ location: state.context.location,
165
165
  },
166
166
  };
167
167
  }
168
168
 
169
- if (obs.state.matches('reportWeather')) {
169
+ if (state.matches('reportWeather')) {
170
170
  return {
171
171
  goal: `Report the weather for the given location`,
172
- context: obs.state.context,
172
+ context: {
173
+ location: state.context.location,
174
+ result: state.context.result,
175
+ },
173
176
  };
174
177
  }
175
178
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statelyai/agent",
3
- "version": "2.0.0-next.2",
3
+ "version": "2.0.0-next.3",
4
4
  "description": "Stateful agents that make decisions based on finite-state machine models",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",