@statelyai/agent 1.0.0-beta.1 → 1.0.0
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/heavy-moons-bake.md +12 -0
- package/.changeset/silly-berries-drop.md +5 -0
- package/.changeset/wild-bobcats-care.md +26 -0
- package/.env.template +0 -3
- package/.github/workflows/release.yml +3 -3
- package/dist/index.d.mts +135 -44
- package/dist/index.d.ts +135 -44
- package/dist/index.js +155 -103
- package/dist/index.mjs +145 -101
- package/examples/chatbot.ts +9 -17
- package/examples/cot.ts +5 -7
- package/examples/email.ts +2 -2
- package/examples/example.ts +7 -7
- package/examples/goal.ts +1 -1
- package/examples/joke.ts +8 -10
- package/examples/number.ts +1 -1
- package/examples/raffle.ts +1 -1
- package/examples/sandbox.ts +28 -0
- package/examples/support.ts +1 -1
- package/examples/ticTacToe.ts +18 -21
- package/examples/todo.ts +3 -1
- package/examples/tutor.ts +1 -1
- package/examples/verify.ts +1 -1
- package/examples/weather.ts +1 -1
- package/examples/wiki.ts +1 -1
- package/examples/word.ts +1 -1
- package/package.json +8 -6
- package/src/agent.test.ts +176 -4
- package/src/agent.ts +51 -16
- package/src/decision.ts +6 -5
- package/src/index.ts +2 -2
- package/src/planners/shortestPathPlanner.ts +2 -2
- package/src/planners/simplePlanner.ts +22 -11
- package/src/schemas.ts +4 -8
- package/src/strategies/chain-of-note.ts +3 -3
- package/src/text.ts +15 -27
- package/src/types.ts +114 -32
- package/src/utils.ts +53 -9
- package/src/templates/defaultToolCall.ts +0 -10
package/dist/index.mjs
CHANGED
|
@@ -9,13 +9,36 @@ import {
|
|
|
9
9
|
import { tool } from "ai";
|
|
10
10
|
|
|
11
11
|
// src/utils.ts
|
|
12
|
+
import hash from "object-hash";
|
|
12
13
|
function getAllTransitions(state) {
|
|
13
14
|
const nodes = state._nodes;
|
|
14
|
-
const transitions = nodes.map((node) => [...node.transitions.values()]).
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const transitions = nodes.map((node) => [...node.transitions.values()]).map((nodeTransitions) => {
|
|
16
|
+
return nodeTransitions.map((nodeEventTransitions) => {
|
|
17
|
+
return nodeEventTransitions.map((transition) => {
|
|
18
|
+
return {
|
|
19
|
+
...transition,
|
|
20
|
+
guard: typeof transition.guard === "string" ? { type: transition.guard } : transition.guard
|
|
21
|
+
// TODO: fix
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}).flat(2);
|
|
26
|
+
return transitions;
|
|
27
|
+
}
|
|
28
|
+
function getAllMachineTransitions(stateNode) {
|
|
29
|
+
const transitions = [...stateNode.transitions.values()].map((nodeTransitions) => {
|
|
30
|
+
return nodeTransitions.map((transition) => {
|
|
31
|
+
return {
|
|
32
|
+
...transition,
|
|
33
|
+
guard: typeof transition.guard === "string" ? { type: transition.guard } : transition.guard
|
|
34
|
+
// TODO: fix
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}).flat(2);
|
|
38
|
+
for (const s of Object.values(stateNode.states)) {
|
|
39
|
+
const stateTransitions = getAllMachineTransitions(s);
|
|
40
|
+
transitions.push(...stateTransitions);
|
|
41
|
+
}
|
|
19
42
|
return transitions;
|
|
20
43
|
}
|
|
21
44
|
function wrapInXml(tagName, content) {
|
|
@@ -26,6 +49,14 @@ function randomId() {
|
|
|
26
49
|
const random = Math.random().toString(36).substring(2, 9);
|
|
27
50
|
return timestamp + random;
|
|
28
51
|
}
|
|
52
|
+
var machineHashes = /* @__PURE__ */ new WeakMap();
|
|
53
|
+
function getMachineHash(machine) {
|
|
54
|
+
if (machineHashes.has(machine)) return machineHashes.get(machine);
|
|
55
|
+
const transitions = getAllMachineTransitions(machine.root);
|
|
56
|
+
const machineHash = hash(transitions);
|
|
57
|
+
machineHashes.set(machine, machineHash);
|
|
58
|
+
return machineHash;
|
|
59
|
+
}
|
|
29
60
|
|
|
30
61
|
// src/templates/defaultText.ts
|
|
31
62
|
var defaultTextTemplate = (data) => {
|
|
@@ -39,87 +70,6 @@ ${data.goal}
|
|
|
39
70
|
`.trim();
|
|
40
71
|
};
|
|
41
72
|
|
|
42
|
-
// src/planners/simplePlanner.ts
|
|
43
|
-
function getTransitions(state, machine) {
|
|
44
|
-
if (!machine) {
|
|
45
|
-
return [];
|
|
46
|
-
}
|
|
47
|
-
const resolvedState = machine.resolveState(state);
|
|
48
|
-
return getAllTransitions(resolvedState);
|
|
49
|
-
}
|
|
50
|
-
var simplePlannerPromptTemplate = (data) => {
|
|
51
|
-
return `
|
|
52
|
-
${defaultTextTemplate(data)}
|
|
53
|
-
|
|
54
|
-
Only make a single tool call to achieve the above goal.
|
|
55
|
-
`.trim();
|
|
56
|
-
};
|
|
57
|
-
async function simplePlanner(agent, input) {
|
|
58
|
-
const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
|
|
59
|
-
eventType,
|
|
60
|
-
description
|
|
61
|
-
}));
|
|
62
|
-
const filter = (eventType) => Object.keys(input.events).includes(eventType);
|
|
63
|
-
const functionNameMapping = {};
|
|
64
|
-
const toolTransitions = transitions.filter((t) => {
|
|
65
|
-
return filter(t.eventType);
|
|
66
|
-
}).map((t) => {
|
|
67
|
-
const name = t.eventType.replace(/\./g, "_");
|
|
68
|
-
functionNameMapping[name] = t.eventType;
|
|
69
|
-
return {
|
|
70
|
-
type: "function",
|
|
71
|
-
eventType: t.eventType,
|
|
72
|
-
description: t.description,
|
|
73
|
-
name
|
|
74
|
-
};
|
|
75
|
-
});
|
|
76
|
-
const toolMap = {};
|
|
77
|
-
for (const toolTransitionData of toolTransitions) {
|
|
78
|
-
const toolZodType = input.events?.[toolTransitionData.eventType];
|
|
79
|
-
if (!toolZodType) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
toolMap[toolTransitionData.name] = tool({
|
|
83
|
-
description: toolZodType?.description ?? toolTransitionData.description,
|
|
84
|
-
parameters: toolZodType,
|
|
85
|
-
execute: async (params) => {
|
|
86
|
-
const event = {
|
|
87
|
-
type: toolTransitionData.eventType,
|
|
88
|
-
...params
|
|
89
|
-
};
|
|
90
|
-
return event;
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
const prompt = simplePlannerPromptTemplate({
|
|
95
|
-
context: input.state.context,
|
|
96
|
-
goal: input.goal
|
|
97
|
-
});
|
|
98
|
-
const result = await agent.generateText({
|
|
99
|
-
...input,
|
|
100
|
-
prompt,
|
|
101
|
-
tools: toolMap,
|
|
102
|
-
toolChoice: "required"
|
|
103
|
-
});
|
|
104
|
-
const singleResult = result.toolResults[0];
|
|
105
|
-
if (!singleResult) {
|
|
106
|
-
console.warn("No tool call results returned");
|
|
107
|
-
return void 0;
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
goal: input.goal,
|
|
111
|
-
state: input.state,
|
|
112
|
-
steps: [
|
|
113
|
-
{
|
|
114
|
-
event: singleResult.result
|
|
115
|
-
}
|
|
116
|
-
],
|
|
117
|
-
nextEvent: singleResult.result,
|
|
118
|
-
sessionId: agent.sessionId,
|
|
119
|
-
timestamp: Date.now()
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
73
|
// src/text.ts
|
|
124
74
|
import {
|
|
125
75
|
fromObservable,
|
|
@@ -128,9 +78,7 @@ import {
|
|
|
128
78
|
} from "xstate";
|
|
129
79
|
async function getMessages(agent, prompt, options) {
|
|
130
80
|
let messages = [];
|
|
131
|
-
if (options.messages ===
|
|
132
|
-
messages = agent.select((s) => s.messages);
|
|
133
|
-
} else if (typeof options.messages === "function") {
|
|
81
|
+
if (typeof options.messages === "function") {
|
|
134
82
|
messages = await options.messages(agent);
|
|
135
83
|
} else if (options.messages) {
|
|
136
84
|
messages = options.messages;
|
|
@@ -222,14 +170,13 @@ async function agentStreamText(agent, options) {
|
|
|
222
170
|
return result;
|
|
223
171
|
}
|
|
224
172
|
function fromTextStream(agent, defaultOptions) {
|
|
225
|
-
return fromObservable(({ input
|
|
226
|
-
const context = input.context === true ? (self._parent?.getSnapshot()).context : input.context;
|
|
173
|
+
return fromObservable(({ input }) => {
|
|
227
174
|
const observers = /* @__PURE__ */ new Set();
|
|
228
175
|
(async () => {
|
|
229
176
|
const result = await agentStreamText(agent, {
|
|
230
177
|
...defaultOptions,
|
|
231
178
|
...input,
|
|
232
|
-
context
|
|
179
|
+
context: input.context
|
|
233
180
|
});
|
|
234
181
|
for await (const part of result.fullStream) {
|
|
235
182
|
if (part.type === "text-delta") {
|
|
@@ -253,16 +200,103 @@ function fromTextStream(agent, defaultOptions) {
|
|
|
253
200
|
});
|
|
254
201
|
}
|
|
255
202
|
function fromText(agent, defaultOptions) {
|
|
256
|
-
return fromPromise(async ({ input
|
|
257
|
-
const context = input.context === true ? (self._parent?.getSnapshot()).context : input.context;
|
|
203
|
+
return fromPromise(async ({ input }) => {
|
|
258
204
|
return await agentGenerateText(agent, {
|
|
259
205
|
...input,
|
|
260
206
|
...defaultOptions,
|
|
261
|
-
context
|
|
207
|
+
context: input.context
|
|
262
208
|
});
|
|
263
209
|
});
|
|
264
210
|
}
|
|
265
211
|
|
|
212
|
+
// src/planners/simplePlanner.ts
|
|
213
|
+
function getTransitions(state, machine) {
|
|
214
|
+
if (!machine) {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
const resolvedState = machine.resolveState(state);
|
|
218
|
+
return getAllTransitions(resolvedState);
|
|
219
|
+
}
|
|
220
|
+
var simplePlannerPromptTemplate = (data) => {
|
|
221
|
+
return `
|
|
222
|
+
${defaultTextTemplate(data)}
|
|
223
|
+
|
|
224
|
+
Make at most one tool call to achieve the above goal. If the goal cannot be achieved with any tool calls, do not make any tool call.
|
|
225
|
+
`.trim();
|
|
226
|
+
};
|
|
227
|
+
async function simplePlanner(agent, input) {
|
|
228
|
+
const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
|
|
229
|
+
eventType,
|
|
230
|
+
description
|
|
231
|
+
}));
|
|
232
|
+
const filter = (eventType) => Object.keys(input.events).includes(eventType);
|
|
233
|
+
const functionNameMapping = {};
|
|
234
|
+
const toolTransitions = transitions.filter((t) => {
|
|
235
|
+
return filter(t.eventType);
|
|
236
|
+
}).map((t) => {
|
|
237
|
+
const name = t.eventType.replace(/\./g, "_");
|
|
238
|
+
functionNameMapping[name] = t.eventType;
|
|
239
|
+
return {
|
|
240
|
+
type: "function",
|
|
241
|
+
eventType: t.eventType,
|
|
242
|
+
description: t.description,
|
|
243
|
+
name
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
const toolMap = {};
|
|
247
|
+
for (const toolTransitionData of toolTransitions) {
|
|
248
|
+
const toolZodType = input.events?.[toolTransitionData.eventType];
|
|
249
|
+
if (!toolZodType) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
toolMap[toolTransitionData.name] = tool({
|
|
253
|
+
description: toolZodType?.description ?? toolTransitionData.description,
|
|
254
|
+
parameters: toolZodType,
|
|
255
|
+
execute: async (params) => {
|
|
256
|
+
const event = {
|
|
257
|
+
type: toolTransitionData.eventType,
|
|
258
|
+
...params
|
|
259
|
+
};
|
|
260
|
+
return event;
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
if (!Object.keys(toolMap).length) {
|
|
265
|
+
return void 0;
|
|
266
|
+
}
|
|
267
|
+
const prompt = simplePlannerPromptTemplate({
|
|
268
|
+
context: input.state.context,
|
|
269
|
+
goal: input.goal
|
|
270
|
+
});
|
|
271
|
+
const messages = await getMessages(agent, prompt, input);
|
|
272
|
+
const result = await agent.generateText({
|
|
273
|
+
toolChoice: "required",
|
|
274
|
+
...input,
|
|
275
|
+
prompt,
|
|
276
|
+
messages,
|
|
277
|
+
tools: toolMap
|
|
278
|
+
});
|
|
279
|
+
const singleResult = result.toolResults[0];
|
|
280
|
+
if (!singleResult) {
|
|
281
|
+
console.log(toolMap);
|
|
282
|
+
console.warn("No tool call results returned");
|
|
283
|
+
return void 0;
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
goal: input.goal,
|
|
287
|
+
state: input.state,
|
|
288
|
+
execute: async (state) => {
|
|
289
|
+
if (JSON.stringify(state) === JSON.stringify(input.state)) {
|
|
290
|
+
return singleResult.result;
|
|
291
|
+
}
|
|
292
|
+
return void 0;
|
|
293
|
+
},
|
|
294
|
+
nextEvent: singleResult.result,
|
|
295
|
+
sessionId: agent.sessionId,
|
|
296
|
+
timestamp: Date.now()
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
266
300
|
// src/decision.ts
|
|
267
301
|
import { fromPromise as fromPromise2 } from "xstate";
|
|
268
302
|
async function agentDecide(agent, options) {
|
|
@@ -389,6 +423,7 @@ function createAgent({
|
|
|
389
423
|
description,
|
|
390
424
|
model,
|
|
391
425
|
events,
|
|
426
|
+
context,
|
|
392
427
|
planner = simplePlanner,
|
|
393
428
|
stringify = JSON.stringify,
|
|
394
429
|
getMemory,
|
|
@@ -427,6 +462,7 @@ function createAgent({
|
|
|
427
462
|
});
|
|
428
463
|
return message;
|
|
429
464
|
};
|
|
465
|
+
agent.getMessages = () => agent.getSnapshot().context.messages;
|
|
430
466
|
agent.generateText = (opts) => agentGenerateText(agent, opts);
|
|
431
467
|
agent.streamText = (opts) => agentStreamText(agent, opts);
|
|
432
468
|
agent.addFeedback = (feedbackInput) => {
|
|
@@ -441,12 +477,17 @@ function createAgent({
|
|
|
441
477
|
});
|
|
442
478
|
return feedback;
|
|
443
479
|
};
|
|
480
|
+
agent.getFeedback = () => agent.getSnapshot().context.feedback;
|
|
444
481
|
agent.addObservation = (observationInput) => {
|
|
482
|
+
const { prevState, event, state } = observationInput;
|
|
445
483
|
const observation = {
|
|
446
|
-
|
|
484
|
+
prevState,
|
|
485
|
+
event,
|
|
486
|
+
state,
|
|
447
487
|
id: observationInput.id ?? randomId(),
|
|
448
488
|
sessionId: agent.sessionId,
|
|
449
|
-
timestamp: observationInput.timestamp ?? Date.now()
|
|
489
|
+
timestamp: observationInput.timestamp ?? Date.now(),
|
|
490
|
+
machineHash: observationInput.machine ? getMachineHash(observationInput.machine) : void 0
|
|
450
491
|
};
|
|
451
492
|
agent.send({
|
|
452
493
|
type: "agent.observe",
|
|
@@ -454,12 +495,14 @@ function createAgent({
|
|
|
454
495
|
});
|
|
455
496
|
return observation;
|
|
456
497
|
};
|
|
498
|
+
agent.getObservations = () => agent.getSnapshot().context.observations;
|
|
457
499
|
agent.addPlan = (plan) => {
|
|
458
500
|
agent.send({
|
|
459
501
|
type: "agent.plan",
|
|
460
502
|
plan
|
|
461
503
|
});
|
|
462
504
|
};
|
|
505
|
+
agent.getPlans = () => agent.getSnapshot().context.plans;
|
|
463
506
|
agent.interact = (actorRef, getInput) => {
|
|
464
507
|
let prevState = void 0;
|
|
465
508
|
let subscribed = true;
|
|
@@ -486,7 +529,8 @@ function createAgent({
|
|
|
486
529
|
const observationInput = {
|
|
487
530
|
event: inspEvent.event,
|
|
488
531
|
prevState,
|
|
489
|
-
state: inspEvent.snapshot
|
|
532
|
+
state: inspEvent.snapshot,
|
|
533
|
+
machine: actorRef.src
|
|
490
534
|
};
|
|
491
535
|
await handleObservation(observationInput);
|
|
492
536
|
}
|
|
@@ -496,7 +540,8 @@ function createAgent({
|
|
|
496
540
|
prevState: void 0,
|
|
497
541
|
event: { type: "" },
|
|
498
542
|
// TODO: unknown events?
|
|
499
|
-
state: actorRef.getSnapshot()
|
|
543
|
+
state: actorRef.getSnapshot(),
|
|
544
|
+
machine: actorRef.src
|
|
500
545
|
});
|
|
501
546
|
}
|
|
502
547
|
return {
|
|
@@ -506,12 +551,11 @@ function createAgent({
|
|
|
506
551
|
// TODO: make this actually unsubscribe
|
|
507
552
|
};
|
|
508
553
|
};
|
|
554
|
+
agent.types = {};
|
|
509
555
|
agent.start();
|
|
510
556
|
return agent;
|
|
511
557
|
}
|
|
512
558
|
export {
|
|
513
|
-
agentDecide,
|
|
514
|
-
agentGenerateText,
|
|
515
559
|
createAgent,
|
|
516
560
|
fromDecision,
|
|
517
561
|
fromText,
|
package/examples/chatbot.ts
CHANGED
|
@@ -13,20 +13,18 @@ const agent = createAgent({
|
|
|
13
13
|
}),
|
|
14
14
|
'agent.endConversation': z.object({}).describe('Stop the conversation'),
|
|
15
15
|
},
|
|
16
|
+
context: {
|
|
17
|
+
userMessage: z.string(),
|
|
18
|
+
},
|
|
16
19
|
});
|
|
17
20
|
|
|
18
21
|
const machine = setup({
|
|
19
|
-
types:
|
|
20
|
-
context: {} as {
|
|
21
|
-
conversation: string[];
|
|
22
|
-
},
|
|
23
|
-
events: agent.eventTypes,
|
|
24
|
-
},
|
|
22
|
+
types: agent.types,
|
|
25
23
|
actors: { agent: fromDecision(agent), getFromTerminal },
|
|
26
24
|
}).createMachine({
|
|
27
25
|
initial: 'listening',
|
|
28
26
|
context: {
|
|
29
|
-
|
|
27
|
+
userMessage: '',
|
|
30
28
|
},
|
|
31
29
|
states: {
|
|
32
30
|
listening: {
|
|
@@ -35,8 +33,7 @@ const machine = setup({
|
|
|
35
33
|
input: 'User:',
|
|
36
34
|
onDone: {
|
|
37
35
|
actions: assign({
|
|
38
|
-
|
|
39
|
-
x.context.conversation.concat('User: ' + x.event.output),
|
|
36
|
+
userMessage: (x) => x.event.output,
|
|
40
37
|
}),
|
|
41
38
|
target: 'responding',
|
|
42
39
|
},
|
|
@@ -47,20 +44,15 @@ const machine = setup({
|
|
|
47
44
|
src: 'agent',
|
|
48
45
|
input: (x) => ({
|
|
49
46
|
context: {
|
|
50
|
-
|
|
47
|
+
userMessage: 'User says: ' + x.context.userMessage,
|
|
51
48
|
},
|
|
49
|
+
messages: agent.getMessages(),
|
|
52
50
|
goal: 'Respond to the user, unless they want to end the conversation.',
|
|
53
51
|
}),
|
|
54
52
|
},
|
|
55
53
|
on: {
|
|
56
54
|
'agent.respond': {
|
|
57
|
-
actions: [
|
|
58
|
-
assign({
|
|
59
|
-
conversation: (x) =>
|
|
60
|
-
x.context.conversation.concat('Assistant: ' + x.event.response),
|
|
61
|
-
}),
|
|
62
|
-
log((x) => `Agent: ${x.event.response}`),
|
|
63
|
-
],
|
|
55
|
+
actions: [log((x) => `Agent: ${x.event.response}`)],
|
|
64
56
|
target: 'listening',
|
|
65
57
|
},
|
|
66
58
|
'agent.endConversation': 'finished',
|
package/examples/cot.ts
CHANGED
|
@@ -17,16 +17,14 @@ const agent = createAgent({
|
|
|
17
17
|
answer: z.string().describe('The answer to the question'),
|
|
18
18
|
}),
|
|
19
19
|
},
|
|
20
|
+
context: {
|
|
21
|
+
question: z.string().nullable(),
|
|
22
|
+
thought: z.string().nullable(),
|
|
23
|
+
},
|
|
20
24
|
});
|
|
21
25
|
|
|
22
26
|
const machine = setup({
|
|
23
|
-
types:
|
|
24
|
-
context: {} as {
|
|
25
|
-
question: string | null;
|
|
26
|
-
thought: string | null;
|
|
27
|
-
},
|
|
28
|
-
events: agent.eventTypes,
|
|
29
|
-
},
|
|
27
|
+
types: agent.types,
|
|
30
28
|
actors: { agent: fromDecision(agent), getFromTerminal },
|
|
31
29
|
}).createMachine({
|
|
32
30
|
initial: 'asking',
|
package/examples/email.ts
CHANGED
|
@@ -19,7 +19,7 @@ const agent = createAgent({
|
|
|
19
19
|
|
|
20
20
|
const machine = setup({
|
|
21
21
|
types: {
|
|
22
|
-
events: agent.
|
|
22
|
+
events: agent.types.events,
|
|
23
23
|
input: {} as {
|
|
24
24
|
email: string;
|
|
25
25
|
instructions: string;
|
|
@@ -50,7 +50,7 @@ const machine = setup({
|
|
|
50
50
|
instructions: x.context.instructions,
|
|
51
51
|
clarifications: x.context.clarifications,
|
|
52
52
|
},
|
|
53
|
-
messages: agent.
|
|
53
|
+
messages: agent.getMessages(),
|
|
54
54
|
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.',
|
|
55
55
|
}),
|
|
56
56
|
},
|
package/examples/example.ts
CHANGED
|
@@ -18,7 +18,7 @@ const agent = createAgent({
|
|
|
18
18
|
|
|
19
19
|
const machine = setup({
|
|
20
20
|
types: {
|
|
21
|
-
events: agent.
|
|
21
|
+
events: agent.types.events,
|
|
22
22
|
},
|
|
23
23
|
actors: { agent: fromDecision(agent), summarizer: fromText(agent) },
|
|
24
24
|
}).createMachine({
|
|
@@ -32,11 +32,11 @@ const machine = setup({
|
|
|
32
32
|
invoke: [
|
|
33
33
|
{
|
|
34
34
|
src: 'summarizer',
|
|
35
|
-
input: {
|
|
36
|
-
context:
|
|
35
|
+
input: (x) => ({
|
|
36
|
+
context: x.context,
|
|
37
37
|
prompt:
|
|
38
38
|
'Summarize the patient visit in a single sentence. The summary should be in English.',
|
|
39
|
-
},
|
|
39
|
+
}),
|
|
40
40
|
onDone: {
|
|
41
41
|
actions: assign({
|
|
42
42
|
englishSummary: ({ event }) => event.output.text,
|
|
@@ -45,11 +45,11 @@ const machine = setup({
|
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
src: 'summarizer',
|
|
48
|
-
input: {
|
|
49
|
-
context:
|
|
48
|
+
input: (x) => ({
|
|
49
|
+
context: x.context,
|
|
50
50
|
prompt:
|
|
51
51
|
'Summarize the patient visit in a single sentence. The summary should be in Spanish.',
|
|
52
|
-
},
|
|
52
|
+
}),
|
|
53
53
|
onDone: {
|
|
54
54
|
actions: assign({
|
|
55
55
|
spanishSummary: ({ event }) => event.output.text,
|
package/examples/goal.ts
CHANGED
package/examples/joke.ts
CHANGED
|
@@ -67,19 +67,17 @@ const agent = createAgent({
|
|
|
67
67
|
.describe('Explains why the joke was irrelevant'),
|
|
68
68
|
'agent.markAsRelevant': z.object({}).describe('The joke was relevant'),
|
|
69
69
|
},
|
|
70
|
+
context: {
|
|
71
|
+
topic: z.string().describe('The topic for the joke'),
|
|
72
|
+
jokes: z.array(z.string()).describe('The jokes told so far'),
|
|
73
|
+
desire: z.string().nullable().describe('The user desire'),
|
|
74
|
+
lastRating: z.number().nullable().describe('The last joke rating'),
|
|
75
|
+
loader: z.string().nullable().describe('The loader text'),
|
|
76
|
+
},
|
|
70
77
|
});
|
|
71
78
|
|
|
72
79
|
const jokeMachine = setup({
|
|
73
|
-
types:
|
|
74
|
-
context: {} as {
|
|
75
|
-
topic: string;
|
|
76
|
-
jokes: string[];
|
|
77
|
-
desire: string | null;
|
|
78
|
-
lastRating: number | null;
|
|
79
|
-
loader: string | null;
|
|
80
|
-
},
|
|
81
|
-
events: agent.eventTypes,
|
|
82
|
-
},
|
|
80
|
+
types: agent.types,
|
|
83
81
|
actors: {
|
|
84
82
|
agent: fromDecision(agent),
|
|
85
83
|
loader,
|
package/examples/number.ts
CHANGED
package/examples/raffle.ts
CHANGED
|
@@ -27,7 +27,7 @@ const machine = setup({
|
|
|
27
27
|
lastInput: string | null;
|
|
28
28
|
entries: string[];
|
|
29
29
|
},
|
|
30
|
-
events: {} as typeof agent.
|
|
30
|
+
events: {} as typeof agent.types.events | { type: 'draw' },
|
|
31
31
|
},
|
|
32
32
|
actors: { agent: fromDecision(agent), getFromTerminal },
|
|
33
33
|
}).createMachine({
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createAgent } from '../src';
|
|
3
|
+
import { openai } from '@ai-sdk/openai';
|
|
4
|
+
import { createMachine } from 'xstate';
|
|
5
|
+
|
|
6
|
+
const agent = createAgent({
|
|
7
|
+
model: openai('gpt-4o'),
|
|
8
|
+
events: {
|
|
9
|
+
doSomething: z.object({}).describe('Do something'),
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
const machine = createMachine({
|
|
15
|
+
on: {
|
|
16
|
+
doSomething: {},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
const result = await agent.decide({
|
|
20
|
+
goal: 'Do not do anything',
|
|
21
|
+
state: { value: {}, context: {} },
|
|
22
|
+
machine,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
console.log(result);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
main();
|
package/examples/support.ts
CHANGED
package/examples/ticTacToe.ts
CHANGED
|
@@ -23,25 +23,30 @@ const agent = createAgent({
|
|
|
23
23
|
}),
|
|
24
24
|
reset: z.object({}).describe('Reset the game to the initial state'),
|
|
25
25
|
},
|
|
26
|
+
context: {
|
|
27
|
+
board: z
|
|
28
|
+
.array(z.union([z.literal(null), z.literal('x'), z.literal('o')]))
|
|
29
|
+
.describe('The 3x3 board represented as a 9-element array.'),
|
|
30
|
+
moves: z
|
|
31
|
+
.number()
|
|
32
|
+
.min(0)
|
|
33
|
+
.max(9)
|
|
34
|
+
.describe('The number of moves made in the game.'),
|
|
35
|
+
player: z
|
|
36
|
+
.union([z.literal('x'), z.literal('o')])
|
|
37
|
+
.describe('The current player (x or o)'),
|
|
38
|
+
gameReport: z.string(),
|
|
39
|
+
},
|
|
26
40
|
});
|
|
27
41
|
|
|
28
42
|
type Player = 'x' | 'o';
|
|
29
43
|
|
|
30
|
-
interface GameContext {
|
|
31
|
-
board: (Player | null)[];
|
|
32
|
-
moves: number;
|
|
33
|
-
player: Player;
|
|
34
|
-
gameReport: string;
|
|
35
|
-
events: string[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
44
|
const initialContext = {
|
|
39
45
|
board: Array(9).fill(null) as Array<Player | null>,
|
|
40
46
|
moves: 0,
|
|
41
47
|
player: 'x' as Player,
|
|
42
48
|
gameReport: '',
|
|
43
|
-
|
|
44
|
-
} satisfies GameContext;
|
|
49
|
+
} satisfies typeof agent.types.context;
|
|
45
50
|
|
|
46
51
|
function getWinner(board: typeof initialContext.board): Player | null {
|
|
47
52
|
const lines = [
|
|
@@ -64,8 +69,8 @@ function getWinner(board: typeof initialContext.board): Player | null {
|
|
|
64
69
|
|
|
65
70
|
export const ticTacToeMachine = setup({
|
|
66
71
|
types: {
|
|
67
|
-
context:
|
|
68
|
-
events: agent.
|
|
72
|
+
context: agent.types.context,
|
|
73
|
+
events: agent.types.events,
|
|
69
74
|
},
|
|
70
75
|
actors: {
|
|
71
76
|
agent: fromDecision(agent),
|
|
@@ -81,16 +86,8 @@ export const ticTacToeMachine = setup({
|
|
|
81
86
|
},
|
|
82
87
|
moves: ({ context }) => context.moves + 1,
|
|
83
88
|
player: ({ context }) => (context.player === 'x' ? 'o' : 'x'),
|
|
84
|
-
events: ({ context, event }) => {
|
|
85
|
-
return [...context.events, JSON.stringify(event)];
|
|
86
|
-
},
|
|
87
89
|
}),
|
|
88
90
|
resetGame: assign(initialContext),
|
|
89
|
-
recordEvent: assign({
|
|
90
|
-
events: ({ context, event }) => {
|
|
91
|
-
return [...context.events, JSON.stringify(event)];
|
|
92
|
-
},
|
|
93
|
-
}),
|
|
94
91
|
printBoard: ({ context }) => {
|
|
95
92
|
// Print the context.board in a 3 x 3 grid format
|
|
96
93
|
let boardString = '';
|
|
@@ -172,7 +169,7 @@ export const ticTacToeMachine = setup({
|
|
|
172
169
|
src: 'gameReporter',
|
|
173
170
|
input: ({ context }) => ({
|
|
174
171
|
context: {
|
|
175
|
-
events:
|
|
172
|
+
events: agent.getObservations().map((o) => o.event),
|
|
176
173
|
board: context.board,
|
|
177
174
|
},
|
|
178
175
|
prompt: 'Provide a short game report analyzing the game.',
|
package/examples/todo.ts
CHANGED
|
@@ -36,7 +36,9 @@ const machine = setup({
|
|
|
36
36
|
todos: Todo[];
|
|
37
37
|
command: string | null;
|
|
38
38
|
},
|
|
39
|
-
events: {} as
|
|
39
|
+
events: {} as
|
|
40
|
+
| typeof agent.types.events
|
|
41
|
+
| { type: 'assist'; command: string },
|
|
40
42
|
},
|
|
41
43
|
actors: { agent: fromDecision(agent), getFromTerminal },
|
|
42
44
|
}).createMachine({
|