@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.
- package/.changeset/cyan-carpets-perform.md +5 -0
- package/.changeset/fast-donkeys-argue.md +5 -0
- package/.changeset/grumpy-dolphins-think.md +17 -0
- package/.changeset/old-jobs-check.md +5 -0
- package/.changeset/old-teachers-tap.md +5 -0
- package/.changeset/pre.json +7 -1
- package/.changeset/smart-yaks-pull.md +23 -0
- package/CHANGELOG.md +52 -0
- package/dist/index.d.mts +69 -66
- package/dist/index.d.ts +69 -66
- package/dist/index.js +111 -79
- package/dist/index.mjs +114 -82
- package/examples/chatbot-alt.ts +1 -1
- package/examples/chatbot.ts +3 -3
- package/examples/cot.ts +7 -25
- package/examples/customer-service-sim.ts +7 -7
- package/examples/email.ts +37 -35
- package/examples/example.ts +3 -3
- package/examples/goal.ts +3 -3
- package/examples/joke.ts +3 -3
- package/examples/jugs.ts +5 -8
- package/examples/learn-from-feedback.ts +100 -0
- package/examples/multi.ts +1 -1
- package/examples/number.ts +3 -3
- package/examples/raffle.ts +3 -3
- package/examples/river-crossing.ts +5 -8
- package/examples/simple.ts +14 -11
- package/examples/summary.ts +3 -6
- package/examples/support.ts +43 -39
- package/examples/ticTacToe.ts +48 -6
- package/examples/todo.ts +3 -3
- package/examples/tutor.ts +4 -4
- package/examples/verify.ts +3 -3
- package/examples/weather-agent.ts +141 -0
- package/examples/weather.ts +24 -24
- package/examples/wiki.ts +1 -1
- package/examples/word.ts +9 -7
- package/package.json +6 -3
- package/src/agent.test.ts +161 -19
- package/src/agent.ts +66 -250
- package/src/decide.test.ts +172 -3
- package/src/decide.ts +50 -30
- package/src/middleware.ts +2 -14
- package/src/strategies/chainOfThought.ts +48 -0
- package/src/strategies/shortestPath.test.ts +91 -0
- package/src/{planners/shortestPathPlanner.ts → strategies/shortestPath.ts} +32 -19
- package/src/{planners/simplePlanner.ts → strategies/simple.ts} +28 -24
- package/src/types.ts +75 -34
- package/src/utils.ts +23 -0
- package/vitest.config.ts +9 -3
- package/src/strategies/chain-of-note.ts +0 -106
package/examples/example.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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 {
|
|
5
|
+
import { experimental_shortestPathStrategy } from '../src/strategies/shortestPath';
|
|
6
6
|
|
|
7
7
|
const agent = createAgent({
|
|
8
|
-
|
|
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
|
-
|
|
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
package/examples/number.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
24
|
+
events: {} as EventsFromAgent<typeof agent>,
|
|
25
25
|
},
|
|
26
26
|
actors: {
|
|
27
27
|
agent: fromDecision(agent),
|
package/examples/raffle.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
|
-
|
|
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
|
|
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 {
|
|
5
|
+
import { experimental_shortestPathStrategy } from '../src/strategies/shortestPath';
|
|
6
6
|
|
|
7
7
|
const agent = createAgent({
|
|
8
|
-
|
|
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
|
-
|
|
121
|
+
strategy: experimental_shortestPathStrategy,
|
|
125
122
|
});
|
|
126
123
|
|
|
127
124
|
console.log(decision?.nextEvent);
|
package/examples/simple.ts
CHANGED
|
@@ -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
|
-
|
|
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 =
|
|
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,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
|
-
|
|
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,
|
package/examples/support.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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({
|
|
@@ -39,19 +48,30 @@ const context = {
|
|
|
39
48
|
};
|
|
40
49
|
|
|
41
50
|
const xAgent = createAgent({
|
|
42
|
-
|
|
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
|
-
|
|
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
|
|
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,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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
31
|
+
events: {} as EventsFromAgent<typeof agent>,
|
|
32
32
|
},
|
|
33
33
|
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
|
|
34
34
|
}).createMachine({
|