@statelyai/agent 2.0.0-next.1 → 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.
- package/.changeset/grumpy-dolphins-think.md +17 -0
- package/.changeset/old-teachers-tap.md +5 -0
- package/.changeset/pre.json +4 -1
- package/.changeset/smart-yaks-pull.md +23 -0
- package/CHANGELOG.md +40 -0
- package/dist/index.d.mts +55 -46
- package/dist/index.d.ts +55 -46
- package/dist/index.js +78 -50
- package/dist/index.mjs +81 -53
- package/examples/chatbot.ts +2 -2
- package/examples/cot.ts +6 -24
- package/examples/customer-service-sim.ts +3 -3
- package/examples/email.ts +9 -3
- package/examples/example.ts +2 -2
- package/examples/goal.ts +2 -2
- package/examples/joke.ts +2 -2
- package/examples/jugs.ts +4 -7
- package/examples/learn-from-feedback.ts +100 -0
- package/examples/number.ts +2 -2
- package/examples/raffle.ts +2 -2
- package/examples/river-crossing.ts +4 -7
- package/examples/simple.ts +13 -10
- package/examples/summary.ts +2 -5
- package/examples/support.ts +42 -38
- package/examples/ticTacToe.ts +46 -4
- package/examples/todo.ts +2 -2
- package/examples/tutor.ts +2 -2
- package/examples/verify.ts +2 -2
- package/examples/weather-agent.ts +141 -0
- package/examples/weather.ts +23 -23
- package/examples/word.ts +8 -6
- package/package.json +2 -1
- package/src/agent.test.ts +17 -15
- package/src/agent.ts +48 -35
- package/src/decide.test.ts +56 -8
- package/src/decide.ts +34 -24
- package/src/strategies/chainOfThought.ts +48 -0
- package/src/{planners → strategies}/shortestPath.test.ts +4 -7
- package/src/strategies/shortestPath.ts +173 -0
- package/src/{planners → strategies}/simple.ts +28 -18
- package/src/types.ts +62 -28
- package/src/utils.ts +12 -0
- package/src/planners/shortestPath.ts +0 -177
- package/src/strategies/chain-of-note.ts +0 -106
|
@@ -1,8 +1,8 @@
|
|
|
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 {
|
|
5
|
+
import { experimental_shortestPathStrategy } from '../src/strategies/shortestPath';
|
|
6
6
|
|
|
7
7
|
const agent = createAgent({
|
|
8
8
|
id: 'river-crossing-solver',
|
|
@@ -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
|
-
|
|
121
|
+
strategy: experimental_shortestPathStrategy,
|
|
125
122
|
});
|
|
126
123
|
|
|
127
124
|
console.log(decision?.nextEvent);
|
package/examples/simple.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
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
8
|
id: 'simple',
|
|
@@ -13,18 +14,10 @@ const agent = createAgent({
|
|
|
13
14
|
},
|
|
14
15
|
});
|
|
15
16
|
|
|
16
|
-
const machine =
|
|
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
|
+
});
|
package/examples/summary.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
@@ -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,
|
package/examples/support.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
|
|
|
@@ -35,7 +35,7 @@ const agent = createAgent({
|
|
|
35
35
|
|
|
36
36
|
const machine = setup({
|
|
37
37
|
types: {
|
|
38
|
-
events: agent
|
|
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
|
+
});
|
package/examples/ticTacToe.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { assign, setup, assertEvent, createActor } from 'xstate';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
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({
|
|
@@ -52,6 +61,17 @@ const oAgent = createAgent({
|
|
|
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
|
|
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
|
|
106
|
+
context: {} as ContextFromAgent<typeof xAgent>,
|
|
87
107
|
events: {} as
|
|
88
|
-
| typeof xAgent
|
|
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,6 +1,6 @@
|
|
|
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
|
|
|
@@ -37,7 +37,7 @@ const machine = setup({
|
|
|
37
37
|
command: string | null;
|
|
38
38
|
},
|
|
39
39
|
events: {} as
|
|
40
|
-
| typeof agent
|
|
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,6 +1,6 @@
|
|
|
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
|
|
|
@@ -28,7 +28,7 @@ const machine = setup({
|
|
|
28
28
|
context: {} as {
|
|
29
29
|
conversation: string[];
|
|
30
30
|
},
|
|
31
|
-
events: agent
|
|
31
|
+
events: {} as EventsFromAgent<typeof agent>,
|
|
32
32
|
},
|
|
33
33
|
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
|
|
34
34
|
}).createMachine({
|
package/examples/verify.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assign, createActor, setup, log } 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
|
|
|
@@ -35,7 +35,7 @@ const machine = setup({
|
|
|
35
35
|
answer: string | null;
|
|
36
36
|
validation: string | null;
|
|
37
37
|
},
|
|
38
|
-
events: agent
|
|
38
|
+
events: {} as EventsFromAgent<typeof agent>,
|
|
39
39
|
},
|
|
40
40
|
actors: {
|
|
41
41
|
getFromTerminal: fromTerminal,
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createAgent } from '../src';
|
|
3
|
+
import { assign, createActor, fromPromise, setup } from 'xstate';
|
|
4
|
+
// import { anthropic } from '@ai-sdk/anthropic';
|
|
5
|
+
import { fromTerminal } from './helpers/helpers';
|
|
6
|
+
import { openai } from '@ai-sdk/openai';
|
|
7
|
+
|
|
8
|
+
// Create the weather agent
|
|
9
|
+
const agent = createAgent({
|
|
10
|
+
id: 'weather-agent',
|
|
11
|
+
model: openai('gpt-4o'),
|
|
12
|
+
events: {
|
|
13
|
+
'weather.check': z.object({
|
|
14
|
+
location: z.string().describe('The location to check weather for'),
|
|
15
|
+
}),
|
|
16
|
+
'weather.report': z.object({
|
|
17
|
+
temperature: z.string(),
|
|
18
|
+
conditions: z.string(),
|
|
19
|
+
}),
|
|
20
|
+
'agent.respond': z.object({
|
|
21
|
+
response: z.string(),
|
|
22
|
+
}),
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Create the weather tool/service
|
|
27
|
+
const getWeather = (location: string) => {
|
|
28
|
+
if (
|
|
29
|
+
location.toLowerCase().includes('sf') ||
|
|
30
|
+
location.toLowerCase().includes('san francisco')
|
|
31
|
+
) {
|
|
32
|
+
return {
|
|
33
|
+
temperature: '60 degrees',
|
|
34
|
+
conditions: 'foggy',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
temperature: '90 degrees',
|
|
39
|
+
conditions: 'sunny',
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Create the state machine
|
|
44
|
+
const machine = setup({
|
|
45
|
+
types: {
|
|
46
|
+
context: {} as {
|
|
47
|
+
input: string | null;
|
|
48
|
+
location: string | null;
|
|
49
|
+
weather: any;
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
actors: {
|
|
53
|
+
getFromTerminal: fromTerminal,
|
|
54
|
+
getWeather: fromPromise(async ({ input }: { input: string }) => {
|
|
55
|
+
return getWeather(input);
|
|
56
|
+
}),
|
|
57
|
+
},
|
|
58
|
+
}).createMachine({
|
|
59
|
+
context: {
|
|
60
|
+
input: null,
|
|
61
|
+
location: null,
|
|
62
|
+
weather: null,
|
|
63
|
+
},
|
|
64
|
+
initial: 'user',
|
|
65
|
+
states: {
|
|
66
|
+
user: {
|
|
67
|
+
invoke: {
|
|
68
|
+
src: 'getFromTerminal',
|
|
69
|
+
input: 'Ask me about the weather!',
|
|
70
|
+
onDone: {
|
|
71
|
+
actions: assign({
|
|
72
|
+
input: ({ event }) => event.output,
|
|
73
|
+
}),
|
|
74
|
+
target: 'processing',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
processing: {
|
|
79
|
+
entry: () => console.log('Processing...'),
|
|
80
|
+
on: {
|
|
81
|
+
'weather.check': {
|
|
82
|
+
actions: assign({
|
|
83
|
+
input: ({ event }) => event.location,
|
|
84
|
+
}),
|
|
85
|
+
target: 'checking',
|
|
86
|
+
},
|
|
87
|
+
'agent.respond': {
|
|
88
|
+
actions: ({ event }) => console.log(event.response),
|
|
89
|
+
target: 'responded',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
checking: {
|
|
94
|
+
entry: ({ event }) => console.log('Checking weather...', event),
|
|
95
|
+
invoke: {
|
|
96
|
+
src: 'getWeather',
|
|
97
|
+
input: ({ context }) => context.input!,
|
|
98
|
+
onDone: {
|
|
99
|
+
actions: assign({
|
|
100
|
+
weather: ({ event }) => event.output,
|
|
101
|
+
}),
|
|
102
|
+
target: 'responding',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
responding: {
|
|
107
|
+
on: {
|
|
108
|
+
'agent.respond': {
|
|
109
|
+
actions: ({ event }) => console.log(event.response),
|
|
110
|
+
target: 'responded',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
responded: {
|
|
115
|
+
after: {
|
|
116
|
+
1000: { target: 'user' },
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Create and start the actor
|
|
123
|
+
const actor = createActor(machine).start();
|
|
124
|
+
|
|
125
|
+
agent.interact(actor, (obs) => {
|
|
126
|
+
if (obs.state.matches('processing')) {
|
|
127
|
+
return {
|
|
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
|
+
messages: agent.getMessages(),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (obs.state.matches('responding')) {
|
|
135
|
+
return {
|
|
136
|
+
goal: 'Provide a natural response about the weather in ${context.location}',
|
|
137
|
+
context: obs.state.context,
|
|
138
|
+
messages: agent.getMessages(),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
});
|
package/examples/weather.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAgent, fromDecision } from '../src';
|
|
1
|
+
import { createAgent, EventsFromAgent, 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';
|
|
@@ -75,10 +75,10 @@ const machine = setup({
|
|
|
75
75
|
types: {
|
|
76
76
|
context: {} as {
|
|
77
77
|
location: string;
|
|
78
|
-
history: string[];
|
|
79
78
|
count: number;
|
|
79
|
+
result: string | null;
|
|
80
80
|
},
|
|
81
|
-
events: agent
|
|
81
|
+
events: {} as EventsFromAgent<typeof agent>,
|
|
82
82
|
},
|
|
83
83
|
actors: {
|
|
84
84
|
agent: fromDecision(agent),
|
|
@@ -90,7 +90,7 @@ const machine = setup({
|
|
|
90
90
|
context: {
|
|
91
91
|
location: '',
|
|
92
92
|
count: 0,
|
|
93
|
-
|
|
93
|
+
result: null,
|
|
94
94
|
},
|
|
95
95
|
states: {
|
|
96
96
|
getLocation: {
|
|
@@ -111,15 +111,6 @@ const machine = setup({
|
|
|
111
111
|
},
|
|
112
112
|
decide: {
|
|
113
113
|
entry: log('Deciding...'),
|
|
114
|
-
invoke: {
|
|
115
|
-
src: 'agent',
|
|
116
|
-
input: ({ context }) => ({
|
|
117
|
-
context: {
|
|
118
|
-
location: context.location,
|
|
119
|
-
},
|
|
120
|
-
goal: `Decide what to do based on the given location, which may or may not be a location`,
|
|
121
|
-
}),
|
|
122
|
-
},
|
|
123
114
|
on: {
|
|
124
115
|
'agent.getWeather': {
|
|
125
116
|
actions: log(({ event }) => event),
|
|
@@ -138,6 +129,7 @@ const machine = setup({
|
|
|
138
129
|
log(({ event }) => event.output),
|
|
139
130
|
assign({
|
|
140
131
|
count: ({ context }) => context.count + 1,
|
|
132
|
+
result: ({ event }) => event.output,
|
|
141
133
|
}),
|
|
142
134
|
],
|
|
143
135
|
target: 'reportWeather',
|
|
@@ -145,13 +137,6 @@ const machine = setup({
|
|
|
145
137
|
},
|
|
146
138
|
},
|
|
147
139
|
reportWeather: {
|
|
148
|
-
invoke: {
|
|
149
|
-
src: 'agent',
|
|
150
|
-
input: ({ context }) => ({
|
|
151
|
-
goal: 'Report the weather', // TODO
|
|
152
|
-
context,
|
|
153
|
-
}),
|
|
154
|
-
},
|
|
155
140
|
on: {
|
|
156
141
|
'agent.reportWeather': {
|
|
157
142
|
actions: log(({ event }) => event),
|
|
@@ -169,7 +154,22 @@ const machine = setup({
|
|
|
169
154
|
});
|
|
170
155
|
|
|
171
156
|
const actor = createActor(machine);
|
|
172
|
-
actor.subscribe((s) => {
|
|
173
|
-
console.log(s.value);
|
|
174
|
-
});
|
|
175
157
|
actor.start();
|
|
158
|
+
|
|
159
|
+
agent.interact(actor, (obs) => {
|
|
160
|
+
if (obs.state.matches('decide')) {
|
|
161
|
+
return {
|
|
162
|
+
goal: `Decide what to do based on the given location, which may or may not be a location`,
|
|
163
|
+
context: {
|
|
164
|
+
location: obs.state.context.location,
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (obs.state.matches('reportWeather')) {
|
|
170
|
+
return {
|
|
171
|
+
goal: `Report the weather for the given location`,
|
|
172
|
+
context: obs.state.context,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
package/examples/word.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { assign, createActor, log, setup } from 'xstate';
|
|
2
2
|
import { fromTerminal } from './helpers/helpers';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ContextFromAgent,
|
|
5
|
+
createAgent,
|
|
6
|
+
fromDecision,
|
|
7
|
+
TypesFromAgent,
|
|
8
|
+
} from '../src';
|
|
4
9
|
import { z } from 'zod';
|
|
5
10
|
import { openai } from '@ai-sdk/openai';
|
|
6
11
|
|
|
@@ -36,13 +41,10 @@ const context = {
|
|
|
36
41
|
word: null,
|
|
37
42
|
guessedWord: null,
|
|
38
43
|
lettersGuessed: [],
|
|
39
|
-
} satisfies typeof agent
|
|
44
|
+
} satisfies ContextFromAgent<typeof agent>;
|
|
40
45
|
|
|
41
46
|
const wordGuesserMachine = setup({
|
|
42
|
-
types: {
|
|
43
|
-
context: agent.types.context,
|
|
44
|
-
events: agent.types.events,
|
|
45
|
-
},
|
|
47
|
+
types: {} as TypesFromAgent<typeof agent>,
|
|
46
48
|
actors: {
|
|
47
49
|
agent: fromDecision(agent),
|
|
48
50
|
getFromTerminal: fromTerminal,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statelyai/agent",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.2",
|
|
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",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"author": "David Khourshid <david@stately.ai>",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"devDependencies": {
|
|
18
|
+
"@ai-sdk/anthropic": "^0.0.54",
|
|
18
19
|
"@ai-sdk/openai": "^0.0.40",
|
|
19
20
|
"@changesets/changelog-github": "^0.5.0",
|
|
20
21
|
"@changesets/cli": "^2.27.9",
|