@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/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
fromTransition
|
|
5
5
|
} from "xstate";
|
|
6
6
|
|
|
7
|
-
// src/
|
|
7
|
+
// src/strategies/simple.ts
|
|
8
8
|
import { generateText as generateText2 } from "ai";
|
|
9
9
|
|
|
10
10
|
// src/utils.ts
|
|
@@ -43,6 +43,15 @@ function getAllMachineTransitions(stateNode) {
|
|
|
43
43
|
function wrapInXml(tagName, content) {
|
|
44
44
|
return `<${tagName}>${content}</${tagName}>`;
|
|
45
45
|
}
|
|
46
|
+
function convertToXml(obj) {
|
|
47
|
+
return Object.entries(obj).map(([key, value]) => {
|
|
48
|
+
if (typeof value === "object" && value !== null) {
|
|
49
|
+
return wrapInXml(key, convertToXml(value));
|
|
50
|
+
} else {
|
|
51
|
+
return wrapInXml(key, value);
|
|
52
|
+
}
|
|
53
|
+
}).join("");
|
|
54
|
+
}
|
|
46
55
|
function randomId(prefix) {
|
|
47
56
|
const timestamp = Date.now().toString(36);
|
|
48
57
|
const random = Math.random().toString(36).substring(2, 9);
|
|
@@ -70,10 +79,19 @@ function getTransitions(state, machine) {
|
|
|
70
79
|
});
|
|
71
80
|
return getAllTransitions(resolvedState);
|
|
72
81
|
}
|
|
82
|
+
function isMachineActor(actor) {
|
|
83
|
+
return "src" in actor && typeof actor.src === "object" && actor.src !== null && "definition" in actor.src;
|
|
84
|
+
}
|
|
73
85
|
|
|
74
|
-
// src/
|
|
86
|
+
// src/strategies/simple.ts
|
|
75
87
|
import { getNextSnapshot } from "xstate";
|
|
76
88
|
|
|
89
|
+
// src/text.ts
|
|
90
|
+
import {
|
|
91
|
+
generateText,
|
|
92
|
+
streamText
|
|
93
|
+
} from "ai";
|
|
94
|
+
|
|
77
95
|
// src/templates/defaultText.ts
|
|
78
96
|
var defaultTextTemplate = (data) => {
|
|
79
97
|
const preamble = [
|
|
@@ -87,10 +105,6 @@ ${data.goal}
|
|
|
87
105
|
};
|
|
88
106
|
|
|
89
107
|
// src/text.ts
|
|
90
|
-
import {
|
|
91
|
-
generateText,
|
|
92
|
-
streamText
|
|
93
|
-
} from "ai";
|
|
94
108
|
import {
|
|
95
109
|
fromObservable,
|
|
96
110
|
fromPromise,
|
|
@@ -183,27 +197,42 @@ async function agentDecide(agent, options) {
|
|
|
183
197
|
...options
|
|
184
198
|
};
|
|
185
199
|
const {
|
|
186
|
-
|
|
200
|
+
strategy = agent.strategy,
|
|
187
201
|
goal,
|
|
202
|
+
allowedEvents,
|
|
188
203
|
events = agent.events,
|
|
189
204
|
state,
|
|
190
205
|
machine,
|
|
191
206
|
model = agent.model,
|
|
192
|
-
|
|
207
|
+
messages,
|
|
208
|
+
...otherDecideInput
|
|
193
209
|
} = resolvedOptions;
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
agent
|
|
204
|
-
|
|
210
|
+
const filteredEventSchemas = allowedEvents ? Object.fromEntries(
|
|
211
|
+
Object.entries(events).filter(([key]) => {
|
|
212
|
+
return allowedEvents.includes(key);
|
|
213
|
+
})
|
|
214
|
+
) : events;
|
|
215
|
+
let attempts = 0;
|
|
216
|
+
const maxAttempts = resolvedOptions.maxAttempts ?? 2;
|
|
217
|
+
let decision;
|
|
218
|
+
while (attempts++ < maxAttempts) {
|
|
219
|
+
decision = await strategy(agent, {
|
|
220
|
+
model,
|
|
221
|
+
goal,
|
|
222
|
+
events: filteredEventSchemas,
|
|
223
|
+
state,
|
|
224
|
+
machine,
|
|
225
|
+
messages,
|
|
226
|
+
// TODO: fix UIMessage thing
|
|
227
|
+
...otherDecideInput
|
|
228
|
+
});
|
|
229
|
+
if (decision?.nextEvent) {
|
|
230
|
+
agent.addDecision(decision);
|
|
231
|
+
await resolvedOptions.execute?.(decision.nextEvent);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
205
234
|
}
|
|
206
|
-
return
|
|
235
|
+
return decision;
|
|
207
236
|
}
|
|
208
237
|
function fromDecision(agent, defaultInput) {
|
|
209
238
|
return fromPromise2(async ({ input, self }) => {
|
|
@@ -221,15 +250,18 @@ function fromDecision(agent, defaultInput) {
|
|
|
221
250
|
value: snapshot.value,
|
|
222
251
|
context: resolvedInput.context
|
|
223
252
|
};
|
|
224
|
-
const
|
|
253
|
+
const decision = await agentDecide(agent, {
|
|
225
254
|
machine: parentRef.logic,
|
|
226
|
-
state,
|
|
255
|
+
state: snapshot,
|
|
256
|
+
context: resolvedInput.context,
|
|
227
257
|
execute: async (event) => {
|
|
228
258
|
parentRef.send(event);
|
|
229
259
|
},
|
|
230
|
-
...resolvedInput
|
|
260
|
+
...resolvedInput,
|
|
261
|
+
// @ts-ignore
|
|
262
|
+
messages: resolvedInput.messages
|
|
231
263
|
});
|
|
232
|
-
return
|
|
264
|
+
return decision;
|
|
233
265
|
});
|
|
234
266
|
}
|
|
235
267
|
function getToolMap(_agent, input) {
|
|
@@ -275,46 +307,48 @@ function getToolMap(_agent, input) {
|
|
|
275
307
|
return toolMap;
|
|
276
308
|
}
|
|
277
309
|
|
|
278
|
-
// src/
|
|
279
|
-
var
|
|
310
|
+
// src/strategies/simple.ts
|
|
311
|
+
var simpleStrategyPromptTemplate = (data) => {
|
|
280
312
|
return `
|
|
281
|
-
${
|
|
313
|
+
${convertToXml(data)}
|
|
282
314
|
|
|
283
315
|
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.
|
|
284
316
|
`.trim();
|
|
285
317
|
};
|
|
286
|
-
async function
|
|
318
|
+
async function simpleStrategy(agent, input) {
|
|
287
319
|
const toolMap = getToolMap(agent, input);
|
|
288
320
|
if (!toolMap) {
|
|
289
321
|
return void 0;
|
|
290
322
|
}
|
|
291
|
-
const prompt =
|
|
292
|
-
context: input.
|
|
323
|
+
const prompt = simpleStrategyPromptTemplate({
|
|
324
|
+
context: input.context,
|
|
293
325
|
goal: input.goal
|
|
294
326
|
});
|
|
295
327
|
const messages = await getMessages(agent, prompt, input);
|
|
296
328
|
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
297
329
|
const {
|
|
298
330
|
state,
|
|
331
|
+
context,
|
|
299
332
|
machine,
|
|
300
|
-
|
|
333
|
+
prevDecision,
|
|
301
334
|
events,
|
|
302
335
|
goal,
|
|
303
336
|
model: _,
|
|
304
337
|
...rest
|
|
305
338
|
} = input;
|
|
306
|
-
const machineState = input.machine ? input.machine.resolveState({
|
|
339
|
+
const machineState = input.machine && input.state ? input.machine.resolveState({
|
|
307
340
|
...input.state,
|
|
308
|
-
context: input.state.context
|
|
341
|
+
context: input.state.context ?? {}
|
|
309
342
|
}) : void 0;
|
|
310
343
|
const result = await generateText2({
|
|
311
344
|
...rest,
|
|
345
|
+
system: input.system ?? agent.description,
|
|
312
346
|
model,
|
|
313
347
|
messages,
|
|
314
348
|
tools: toolMap,
|
|
315
349
|
toolChoice: input.toolChoice ?? "required"
|
|
316
350
|
});
|
|
317
|
-
result.
|
|
351
|
+
result.response.messages.forEach((m) => {
|
|
318
352
|
const message = m;
|
|
319
353
|
agent.addMessage({
|
|
320
354
|
...message,
|
|
@@ -328,7 +362,7 @@ async function simplePlanner(agent, input) {
|
|
|
328
362
|
return void 0;
|
|
329
363
|
}
|
|
330
364
|
return {
|
|
331
|
-
|
|
365
|
+
strategy: "simple",
|
|
332
366
|
goal: input.goal,
|
|
333
367
|
goalState: input.state,
|
|
334
368
|
nextEvent: singleResult.result,
|
|
@@ -361,13 +395,11 @@ function createAgentMiddleware(agent) {
|
|
|
361
395
|
},
|
|
362
396
|
wrapGenerate: async ({ doGenerate, params }) => {
|
|
363
397
|
const id = randomId();
|
|
364
|
-
params.prompt.forEach((
|
|
398
|
+
params.prompt.forEach((message) => {
|
|
365
399
|
agent.addMessage({
|
|
366
400
|
id,
|
|
367
|
-
...
|
|
368
|
-
timestamp: Date.now()
|
|
369
|
-
correlationId: params.providerMetadata?.correlationId,
|
|
370
|
-
parentCorrelationId: params.providerMetadata?.parentCorrelationId
|
|
401
|
+
...message,
|
|
402
|
+
timestamp: Date.now()
|
|
371
403
|
});
|
|
372
404
|
});
|
|
373
405
|
const result = await doGenerate();
|
|
@@ -380,9 +412,7 @@ function createAgentMiddleware(agent) {
|
|
|
380
412
|
agent.addMessage({
|
|
381
413
|
id,
|
|
382
414
|
...message,
|
|
383
|
-
timestamp: Date.now()
|
|
384
|
-
correlationId: params.providerMetadata?.correlationId,
|
|
385
|
-
parentCorrelationId: params.providerMetadata?.parentCorrelationId
|
|
415
|
+
timestamp: Date.now()
|
|
386
416
|
});
|
|
387
417
|
});
|
|
388
418
|
const { stream, ...rest } = await doStream();
|
|
@@ -407,9 +437,7 @@ function createAgentMiddleware(agent) {
|
|
|
407
437
|
timestamp: Date.now(),
|
|
408
438
|
role: "assistant",
|
|
409
439
|
content,
|
|
410
|
-
responseId: id
|
|
411
|
-
correlationId: params.providerMetadata?.correlationId,
|
|
412
|
-
parentCorrelationId: params.providerMetadata?.parentCorrelationId
|
|
440
|
+
responseId: id
|
|
413
441
|
});
|
|
414
442
|
}
|
|
415
443
|
});
|
|
@@ -453,17 +481,18 @@ var agentLogic = fromTransition(
|
|
|
453
481
|
});
|
|
454
482
|
break;
|
|
455
483
|
}
|
|
456
|
-
case "agent.
|
|
457
|
-
state.
|
|
484
|
+
case "agent.decision": {
|
|
485
|
+
state.decisions.push(event.decision);
|
|
458
486
|
emit({
|
|
459
|
-
type: "
|
|
460
|
-
|
|
461
|
-
plan: event.plan
|
|
487
|
+
type: "decision",
|
|
488
|
+
decision: event.decision
|
|
462
489
|
});
|
|
463
490
|
break;
|
|
464
491
|
}
|
|
465
|
-
default:
|
|
492
|
+
default: {
|
|
493
|
+
console.warn("Unrecognized event", event);
|
|
466
494
|
break;
|
|
495
|
+
}
|
|
467
496
|
}
|
|
468
497
|
return state;
|
|
469
498
|
},
|
|
@@ -471,31 +500,28 @@ var agentLogic = fromTransition(
|
|
|
471
500
|
feedback: [],
|
|
472
501
|
messages: [],
|
|
473
502
|
observations: [],
|
|
474
|
-
|
|
503
|
+
decisions: []
|
|
475
504
|
})
|
|
476
505
|
);
|
|
477
506
|
function createAgent({
|
|
478
507
|
id,
|
|
479
|
-
name,
|
|
480
508
|
description,
|
|
481
509
|
model,
|
|
482
510
|
events,
|
|
483
511
|
context,
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
logic = agentLogic,
|
|
488
|
-
...generateTextOptions
|
|
512
|
+
episodeId,
|
|
513
|
+
strategy = simpleStrategy,
|
|
514
|
+
logic = agentLogic
|
|
489
515
|
}) {
|
|
490
516
|
return new Agent({
|
|
491
517
|
id,
|
|
492
518
|
context,
|
|
493
519
|
events,
|
|
494
|
-
name,
|
|
495
520
|
description,
|
|
496
|
-
|
|
521
|
+
strategy,
|
|
497
522
|
model,
|
|
498
|
-
logic
|
|
523
|
+
logic,
|
|
524
|
+
episodeId
|
|
499
525
|
});
|
|
500
526
|
}
|
|
501
527
|
var Agent = class extends Actor {
|
|
@@ -508,17 +534,18 @@ var Agent = class extends Actor {
|
|
|
508
534
|
model,
|
|
509
535
|
events,
|
|
510
536
|
context,
|
|
511
|
-
|
|
537
|
+
episodeId,
|
|
538
|
+
strategy = simpleStrategy
|
|
512
539
|
}) {
|
|
513
540
|
super(logic);
|
|
514
541
|
this.model = model;
|
|
515
|
-
this.episodeId =
|
|
542
|
+
this.episodeId = episodeId ?? randomId("episode-");
|
|
516
543
|
this.name = name;
|
|
517
544
|
this.description = description;
|
|
518
545
|
this.events = events;
|
|
519
546
|
this.context = context;
|
|
520
|
-
this.
|
|
521
|
-
this.
|
|
547
|
+
this.strategy = strategy;
|
|
548
|
+
this.id = id ?? randomId();
|
|
522
549
|
this.start();
|
|
523
550
|
}
|
|
524
551
|
/**
|
|
@@ -527,6 +554,12 @@ var Agent = class extends Actor {
|
|
|
527
554
|
onMessage(fn) {
|
|
528
555
|
return this.on("message", (ev) => fn(ev.message));
|
|
529
556
|
}
|
|
557
|
+
/**
|
|
558
|
+
* Called whenever the agent (LLM assistant) receives some feedback.
|
|
559
|
+
*/
|
|
560
|
+
onFeedback(fn) {
|
|
561
|
+
return this.on("feedback", (ev) => fn(ev.feedback));
|
|
562
|
+
}
|
|
530
563
|
/**
|
|
531
564
|
* Retrieves messages from the agent's short-term (local) memory.
|
|
532
565
|
*/
|
|
@@ -550,7 +583,6 @@ var Agent = class extends Actor {
|
|
|
550
583
|
const feedback = {
|
|
551
584
|
...feedbackInput,
|
|
552
585
|
attributes: { ...feedbackInput.attributes },
|
|
553
|
-
reward: feedbackInput.reward ?? 0,
|
|
554
586
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
555
587
|
episodeId: this.episodeId
|
|
556
588
|
};
|
|
@@ -589,20 +621,21 @@ var Agent = class extends Actor {
|
|
|
589
621
|
getObservations() {
|
|
590
622
|
return this.getSnapshot().context.observations;
|
|
591
623
|
}
|
|
592
|
-
|
|
624
|
+
addDecision(decision) {
|
|
593
625
|
this.send({
|
|
594
|
-
type: "agent.
|
|
595
|
-
|
|
626
|
+
type: "agent.decision",
|
|
627
|
+
decision
|
|
596
628
|
});
|
|
597
629
|
}
|
|
598
630
|
/**
|
|
599
631
|
* Retrieves strategies from the agent's short-term (local) memory.
|
|
600
632
|
*/
|
|
601
|
-
|
|
602
|
-
return this.getSnapshot().context.
|
|
633
|
+
getDecisions() {
|
|
634
|
+
return this.getSnapshot().context.decisions;
|
|
603
635
|
}
|
|
604
636
|
interact(actorRef, getInput) {
|
|
605
|
-
const actorRefCheck = isActorRef(actorRef);
|
|
637
|
+
const actorRefCheck = isActorRef(actorRef) && actorRef.src;
|
|
638
|
+
const machine = isMachineActor(actorRef) ? actorRef.src : void 0;
|
|
606
639
|
let prevState = void 0;
|
|
607
640
|
let subscribed = true;
|
|
608
641
|
const agent = this;
|
|
@@ -610,14 +643,14 @@ var Agent = class extends Actor {
|
|
|
610
643
|
const observation = agent.addObservation(observationInput);
|
|
611
644
|
const input = getInput?.(observation);
|
|
612
645
|
if (input) {
|
|
613
|
-
await agentDecide(agent, {
|
|
614
|
-
machine
|
|
646
|
+
const res = await agentDecide(agent, {
|
|
647
|
+
machine,
|
|
615
648
|
state: observation.state,
|
|
616
|
-
execute: async (event) => {
|
|
617
|
-
actorRef.send(event);
|
|
618
|
-
},
|
|
619
649
|
...input
|
|
620
650
|
});
|
|
651
|
+
if (res?.nextEvent) {
|
|
652
|
+
actorRef.send(res.nextEvent);
|
|
653
|
+
}
|
|
621
654
|
}
|
|
622
655
|
prevState = observationInput.state;
|
|
623
656
|
}
|
|
@@ -638,8 +671,7 @@ var Agent = class extends Actor {
|
|
|
638
671
|
if (actorRef._processingStatus === 1) {
|
|
639
672
|
handleObservation({
|
|
640
673
|
prevState: void 0,
|
|
641
|
-
event:
|
|
642
|
-
// TODO: unknown events?
|
|
674
|
+
event: void 0,
|
|
643
675
|
state: actorRef.getSnapshot(),
|
|
644
676
|
machine: actorRef.src
|
|
645
677
|
});
|
|
@@ -679,14 +711,14 @@ var Agent = class extends Actor {
|
|
|
679
711
|
});
|
|
680
712
|
}
|
|
681
713
|
/**
|
|
682
|
-
* Resolves with an `
|
|
714
|
+
* Resolves with an `AgentDecision` based on the information provided in the `options`, including:
|
|
683
715
|
*
|
|
684
716
|
* - The `goal` for the agent to achieve
|
|
685
717
|
* - The observed current `state`
|
|
686
718
|
* - The `machine` (e.g. a state machine) that specifies what can happen next
|
|
687
719
|
* - Additional `context`
|
|
688
720
|
*/
|
|
689
|
-
decide(opts) {
|
|
721
|
+
async decide(opts) {
|
|
690
722
|
return agentDecide(this, opts);
|
|
691
723
|
}
|
|
692
724
|
};
|
package/examples/chatbot-alt.ts
CHANGED
package/examples/chatbot.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { createAgent, fromDecision } from '../src';
|
|
2
|
+
import { createAgent, fromDecision, TypesFromAgent } 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: 'chatbot',
|
|
9
9
|
model: openai('gpt-4o-mini'),
|
|
10
10
|
events: {
|
|
11
11
|
'agent.respond': z.object({
|
|
@@ -19,7 +19,7 @@ const agent = createAgent({
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
const machine = setup({
|
|
22
|
-
types: agent
|
|
22
|
+
types: {} as TypesFromAgent<typeof agent>,
|
|
23
23
|
actors: { getFromTerminal: fromTerminal },
|
|
24
24
|
}).createMachine({
|
|
25
25
|
initial: 'listening',
|
package/examples/cot.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { createAgent, fromDecision } from '../src';
|
|
2
|
+
import { createAgent, fromDecision, TypesFromAgent } 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
|
+
import { chainOfThoughtStrategy } from '../src/strategies/chainOfThought';
|
|
6
7
|
|
|
7
8
|
const agent = createAgent({
|
|
8
|
-
|
|
9
|
+
id: 'chain-of-thought',
|
|
9
10
|
model: openai('gpt-4o-mini'),
|
|
10
11
|
events: {
|
|
11
12
|
'agent.think': z.object({
|
|
@@ -19,18 +20,17 @@ const agent = createAgent({
|
|
|
19
20
|
},
|
|
20
21
|
context: {
|
|
21
22
|
question: z.string().nullable(),
|
|
22
|
-
thought: z.string().nullable(),
|
|
23
23
|
},
|
|
24
|
+
strategy: chainOfThoughtStrategy,
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
const machine = setup({
|
|
27
|
-
types: agent
|
|
28
|
+
types: {} as TypesFromAgent<typeof agent>,
|
|
28
29
|
actors: { getFromTerminal: fromTerminal },
|
|
29
30
|
}).createMachine({
|
|
30
31
|
initial: 'asking',
|
|
31
32
|
context: {
|
|
32
33
|
question: null,
|
|
33
|
-
thought: null,
|
|
34
34
|
},
|
|
35
35
|
states: {
|
|
36
36
|
asking: {
|
|
@@ -41,19 +41,6 @@ const machine = setup({
|
|
|
41
41
|
actions: assign({
|
|
42
42
|
question: ({ event }) => event.output,
|
|
43
43
|
}),
|
|
44
|
-
target: 'thinking',
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
thinking: {
|
|
49
|
-
on: {
|
|
50
|
-
'agent.think': {
|
|
51
|
-
actions: [
|
|
52
|
-
log(({ event }) => `Thought: ${event.thought}`),
|
|
53
|
-
assign({
|
|
54
|
-
thought: ({ event }) => event.thought,
|
|
55
|
-
}),
|
|
56
|
-
],
|
|
57
44
|
target: 'answering',
|
|
58
45
|
},
|
|
59
46
|
},
|
|
@@ -74,14 +61,9 @@ const machine = setup({
|
|
|
74
61
|
|
|
75
62
|
const actor = createActor(machine).start();
|
|
76
63
|
|
|
64
|
+
agent.onMessage(console.log);
|
|
65
|
+
|
|
77
66
|
agent.interact(actor, (obs) => {
|
|
78
|
-
if (obs.state.matches('thinking')) {
|
|
79
|
-
return {
|
|
80
|
-
goal: 'Think step-by-step about how you would answer the question',
|
|
81
|
-
context: obs.state.context,
|
|
82
|
-
messages: agent.getMessages(),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
67
|
if (obs.state.matches('answering')) {
|
|
86
68
|
return {
|
|
87
69
|
goal: 'Answer the question',
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { createAgent, fromDecision } from '../src';
|
|
1
|
+
import { createAgent, EventsFromAgent, 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';
|
|
5
5
|
|
|
6
6
|
// Create customer service agent
|
|
7
7
|
const customerServiceAgent = createAgent({
|
|
8
|
-
|
|
8
|
+
id: 'customer-service',
|
|
9
9
|
model: openai('gpt-4o'),
|
|
10
10
|
events: {
|
|
11
11
|
'agent.respond': z.object({
|
|
@@ -14,12 +14,12 @@ const customerServiceAgent = createAgent({
|
|
|
14
14
|
.describe('The response from the customer service agent'),
|
|
15
15
|
}),
|
|
16
16
|
},
|
|
17
|
-
|
|
17
|
+
description: 'You are a customer service agent for an airline.',
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
// Create simulated customer agent
|
|
21
21
|
const customerAgent = createAgent({
|
|
22
|
-
|
|
22
|
+
id: 'customer',
|
|
23
23
|
model: openai('gpt-4o-mini'),
|
|
24
24
|
events: {
|
|
25
25
|
'agent.respond': z.object({
|
|
@@ -27,7 +27,7 @@ const customerAgent = createAgent({
|
|
|
27
27
|
}),
|
|
28
28
|
'agent.finish': z.object({}).describe('End the conversation'),
|
|
29
29
|
},
|
|
30
|
-
|
|
30
|
+
description: `You are Harrison, a customer trying to get a refund for a trip to Alaska.
|
|
31
31
|
You want them to give you ALL the money back. Be extremely persistent. This trip happened 5 years ago.
|
|
32
32
|
If you have nothing more to add to the conversation, send agent.finish event.`,
|
|
33
33
|
});
|
|
@@ -38,8 +38,8 @@ const machine = setup({
|
|
|
38
38
|
messages: string[];
|
|
39
39
|
},
|
|
40
40
|
events: {} as
|
|
41
|
-
| typeof customerServiceAgent
|
|
42
|
-
| typeof customerAgent
|
|
41
|
+
| EventsFromAgent<typeof customerServiceAgent>
|
|
42
|
+
| EventsFromAgent<typeof customerAgent>,
|
|
43
43
|
},
|
|
44
44
|
actors: {
|
|
45
45
|
customerService: fromDecision(customerServiceAgent),
|
package/examples/email.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ContextFromAgent,
|
|
4
|
+
createAgent,
|
|
5
|
+
EventsFromAgent,
|
|
6
|
+
fromDecision,
|
|
7
|
+
TypesFromAgent,
|
|
8
|
+
} from '../src';
|
|
3
9
|
import { openai } from '@ai-sdk/openai';
|
|
4
10
|
import { assign, createActor, setup } from 'xstate';
|
|
5
11
|
import { fromTerminal } from './helpers/helpers';
|
|
6
12
|
|
|
7
13
|
const agent = createAgent({
|
|
8
|
-
|
|
9
|
-
model: openai('gpt-4o'),
|
|
14
|
+
id: 'email',
|
|
15
|
+
model: openai('gpt-4o-mini'),
|
|
10
16
|
events: {
|
|
11
17
|
askForClarification: z.object({
|
|
12
18
|
questions: z.array(z.string()).describe('The questions to ask the agent'),
|
|
@@ -15,23 +21,26 @@ const agent = createAgent({
|
|
|
15
21
|
email: z.string().describe('The email to submit'),
|
|
16
22
|
}),
|
|
17
23
|
},
|
|
24
|
+
context: {
|
|
25
|
+
email: z.string().describe('The email to respond to'),
|
|
26
|
+
instructions: z.string().describe('The instructions for the email'),
|
|
27
|
+
clarifications: z
|
|
28
|
+
.array(z.string())
|
|
29
|
+
.describe('The clarifications to the email'),
|
|
30
|
+
replyEmail: z.string().nullable().describe('The email to submit'),
|
|
31
|
+
},
|
|
18
32
|
});
|
|
19
33
|
|
|
20
34
|
const machine = setup({
|
|
21
35
|
types: {
|
|
22
|
-
events: agent
|
|
36
|
+
events: {} as EventsFromAgent<typeof agent>,
|
|
23
37
|
input: {} as {
|
|
24
38
|
email: string;
|
|
25
39
|
instructions: string;
|
|
26
40
|
},
|
|
27
|
-
context: {} as
|
|
28
|
-
email: string;
|
|
29
|
-
instructions: string;
|
|
30
|
-
clarifications: string[];
|
|
31
|
-
replyEmail: string | null;
|
|
32
|
-
},
|
|
41
|
+
context: {} as ContextFromAgent<typeof agent>,
|
|
33
42
|
},
|
|
34
|
-
actors: {
|
|
43
|
+
actors: { getFromTerminal: fromTerminal },
|
|
35
44
|
}).createMachine({
|
|
36
45
|
initial: 'checking',
|
|
37
46
|
context: ({ input }) => ({
|
|
@@ -42,18 +51,6 @@ const machine = setup({
|
|
|
42
51
|
}),
|
|
43
52
|
states: {
|
|
44
53
|
checking: {
|
|
45
|
-
invoke: {
|
|
46
|
-
src: 'agent',
|
|
47
|
-
input: ({ context }) => ({
|
|
48
|
-
context: {
|
|
49
|
-
email: context.email,
|
|
50
|
-
instructions: context.instructions,
|
|
51
|
-
clarifications: context.clarifications,
|
|
52
|
-
},
|
|
53
|
-
messages: agent.getMessages(),
|
|
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
|
-
}),
|
|
56
|
-
},
|
|
57
54
|
on: {
|
|
58
55
|
askForClarification: {
|
|
59
56
|
actions: ({ event }) => console.log(event.questions.join('\n')),
|
|
@@ -78,17 +75,6 @@ const machine = setup({
|
|
|
78
75
|
},
|
|
79
76
|
},
|
|
80
77
|
submitting: {
|
|
81
|
-
invoke: {
|
|
82
|
-
src: 'agent',
|
|
83
|
-
input: ({ context }) => ({
|
|
84
|
-
context: {
|
|
85
|
-
email: context.email,
|
|
86
|
-
instructions: context.instructions,
|
|
87
|
-
clarifications: context.clarifications,
|
|
88
|
-
},
|
|
89
|
-
goal: `Create and submit an email based on the instructions.`,
|
|
90
|
-
}),
|
|
91
|
-
},
|
|
92
78
|
on: {
|
|
93
79
|
submitEmail: {
|
|
94
80
|
actions: assign({
|
|
@@ -109,10 +95,26 @@ const machine = setup({
|
|
|
109
95
|
},
|
|
110
96
|
});
|
|
111
97
|
|
|
112
|
-
createActor(machine, {
|
|
98
|
+
const actor = createActor(machine, {
|
|
113
99
|
input: {
|
|
114
100
|
email: 'That sounds great! When are you available?',
|
|
115
101
|
instructions:
|
|
116
102
|
'Tell them exactly when I am available. Address them by his full (first and last) name.',
|
|
117
103
|
},
|
|
118
104
|
}).start();
|
|
105
|
+
|
|
106
|
+
agent.interact(actor, ({ state }) => {
|
|
107
|
+
if (state.matches('checking')) {
|
|
108
|
+
return {
|
|
109
|
+
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
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (state.matches('submitting')) {
|
|
115
|
+
return {
|
|
116
|
+
goal: 'Create and submit an email based on the instructions.',
|
|
117
|
+
context: state.context,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
});
|