@statelyai/agent 2.0.0-next.4 → 2.0.0-next.5
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/calm-beans-talk.md +5 -0
- package/.changeset/long-guests-explode.md +5 -0
- package/.changeset/odd-kiwis-compare.md +5 -0
- package/.changeset/pre.json +3 -0
- package/CHANGELOG.md +12 -0
- package/architecture.tldr +652 -30
- package/dist/index.d.mts +187 -136
- package/dist/index.d.ts +187 -136
- package/dist/index.js +4377 -103
- package/dist/index.mjs +4377 -104
- package/examples/chatbot.ts +9 -5
- package/examples/cot.ts +2 -4
- package/examples/jugs.ts +2 -2
- package/examples/learn-from-feedback.ts +5 -5
- package/examples/newspaper.ts +1 -1
- package/examples/rewoo.ts +62 -0
- package/examples/river-crossing.ts +2 -2
- package/examples/serverless.ts +71 -0
- package/examples/simple.ts +1 -1
- package/examples/ticTacToe.ts +6 -2
- package/examples/wiki.ts +2 -2
- package/package.json +14 -12
- package/readme.md +57 -0
- package/src/agent.test.ts +286 -27
- package/src/agent.ts +165 -51
- package/src/decide.test.ts +2 -2
- package/src/decide.ts +24 -66
- package/src/index.ts +1 -0
- package/src/{strategies/chainOfThought.ts → policies/chainOfThoughtPolicy.ts} +7 -9
- package/src/policies/index.ts +3 -0
- package/src/{strategies/shortestPath.test.ts → policies/shortestPathPolicy.test.ts} +2 -2
- package/src/{strategies/shortestPath.ts → policies/shortestPathPolicy.ts} +8 -8
- package/src/{strategies/simpleStrategy.ts → policies/toolPolicy.ts} +26 -25
- package/src/text.ts +17 -21
- package/src/types.ts +154 -150
- package/src/agent-experimental.ts +0 -221
package/src/agent.ts
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Actor,
|
|
3
3
|
ActorRefLike,
|
|
4
|
-
EventObject,
|
|
5
4
|
fromTransition,
|
|
5
|
+
SnapshotFrom,
|
|
6
6
|
Subscription,
|
|
7
7
|
} from 'xstate';
|
|
8
8
|
import { ZodContextMapping, ZodEventMapping } from './schemas';
|
|
9
9
|
import {
|
|
10
10
|
AgentLogic,
|
|
11
11
|
AgentMessage,
|
|
12
|
-
|
|
13
|
-
EventsFromZodEventMapping,
|
|
12
|
+
AgentPolicy,
|
|
14
13
|
GenerateTextOptions,
|
|
15
14
|
AgentLongTermMemory,
|
|
16
15
|
ObservedState,
|
|
17
16
|
AgentObservationInput,
|
|
18
17
|
AgentMemoryContext,
|
|
19
18
|
AgentObservation,
|
|
20
|
-
ContextFromZodContextMapping,
|
|
21
19
|
AgentFeedback,
|
|
22
20
|
AgentMessageInput,
|
|
23
21
|
AgentFeedbackInput,
|
|
@@ -25,12 +23,16 @@ import {
|
|
|
25
23
|
AnyAgent,
|
|
26
24
|
AgentInteractInput,
|
|
27
25
|
AgentDecideInput,
|
|
26
|
+
EventFromAgent,
|
|
27
|
+
AgentInsightInput,
|
|
28
|
+
AgentInsight,
|
|
29
|
+
AgentDecisionInput,
|
|
28
30
|
} from './types';
|
|
29
|
-
import {
|
|
30
|
-
import { agentDecide } from './decide';
|
|
31
|
+
import { toolPolicy } from './policies/toolPolicy';
|
|
31
32
|
import { isActorRef, isMachineActor, randomId } from './utils';
|
|
32
33
|
import {
|
|
33
|
-
|
|
34
|
+
CoreMessage,
|
|
35
|
+
wrapLanguageModel,
|
|
34
36
|
LanguageModel,
|
|
35
37
|
LanguageModelV1,
|
|
36
38
|
} from 'ai';
|
|
@@ -43,7 +45,6 @@ export const agentLogic: AgentLogic<any> = fromTransition(
|
|
|
43
45
|
state.feedback.push(event.feedback);
|
|
44
46
|
emit({
|
|
45
47
|
type: 'feedback',
|
|
46
|
-
// @ts-ignore TODO: fix types in XState
|
|
47
48
|
feedback: event.feedback,
|
|
48
49
|
});
|
|
49
50
|
break;
|
|
@@ -52,7 +53,6 @@ export const agentLogic: AgentLogic<any> = fromTransition(
|
|
|
52
53
|
state.observations.push(event.observation);
|
|
53
54
|
emit({
|
|
54
55
|
type: 'observation',
|
|
55
|
-
// @ts-ignore TODO: fix types in XState
|
|
56
56
|
observation: event.observation,
|
|
57
57
|
});
|
|
58
58
|
break;
|
|
@@ -61,7 +61,6 @@ export const agentLogic: AgentLogic<any> = fromTransition(
|
|
|
61
61
|
state.messages.push(event.message);
|
|
62
62
|
emit({
|
|
63
63
|
type: 'message',
|
|
64
|
-
// @ts-ignore TODO: fix types in XState
|
|
65
64
|
message: event.message,
|
|
66
65
|
});
|
|
67
66
|
break;
|
|
@@ -74,8 +73,15 @@ export const agentLogic: AgentLogic<any> = fromTransition(
|
|
|
74
73
|
});
|
|
75
74
|
break;
|
|
76
75
|
}
|
|
76
|
+
case 'agent.insight': {
|
|
77
|
+
state.insights.push(event.insight);
|
|
78
|
+
emit({
|
|
79
|
+
type: 'insight',
|
|
80
|
+
insight: event.insight,
|
|
81
|
+
});
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
77
84
|
default: {
|
|
78
|
-
// unrecognized
|
|
79
85
|
console.warn('Unrecognized event', event);
|
|
80
86
|
break;
|
|
81
87
|
}
|
|
@@ -88,29 +94,28 @@ export const agentLogic: AgentLogic<any> = fromTransition(
|
|
|
88
94
|
messages: [],
|
|
89
95
|
observations: [],
|
|
90
96
|
decisions: [],
|
|
97
|
+
insights: [],
|
|
91
98
|
} as AgentMemoryContext<any>)
|
|
92
99
|
);
|
|
93
100
|
|
|
94
101
|
export function createAgent<
|
|
95
102
|
const TContextSchema extends ZodContextMapping,
|
|
96
103
|
const TEventSchemas extends ZodEventMapping,
|
|
97
|
-
TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>,
|
|
98
|
-
TContext = ContextFromZodContextMapping<TContextSchema>,
|
|
99
104
|
TAgent extends AnyAgent = Agent<TContextSchema, TEventSchemas>
|
|
100
105
|
>({
|
|
101
106
|
id,
|
|
102
|
-
description
|
|
107
|
+
description,
|
|
103
108
|
model,
|
|
104
109
|
events,
|
|
105
110
|
context,
|
|
106
111
|
episodeId,
|
|
107
|
-
|
|
108
|
-
logic = agentLogic
|
|
112
|
+
policy = toolPolicy,
|
|
113
|
+
logic = agentLogic,
|
|
109
114
|
}: {
|
|
110
115
|
/**
|
|
111
116
|
* The unique identifier for the agent.
|
|
112
117
|
*
|
|
113
|
-
* This should be the same across all
|
|
118
|
+
* This should be the same across all episodes of a specific agent, as it can be
|
|
114
119
|
* used to retrieve memory for previous episodes of this agent.
|
|
115
120
|
*
|
|
116
121
|
* @example
|
|
@@ -123,17 +128,23 @@ export function createAgent<
|
|
|
123
128
|
*/
|
|
124
129
|
id?: string;
|
|
125
130
|
/**
|
|
126
|
-
* A description of the role of the agent
|
|
131
|
+
* A description of the role of the agent.
|
|
127
132
|
*/
|
|
128
133
|
description?: string;
|
|
129
134
|
/**
|
|
130
|
-
*
|
|
131
|
-
* that the agent knows about.
|
|
135
|
+
* Event schemas for events that the agent can trigger in an environment.
|
|
132
136
|
*/
|
|
133
137
|
events: TEventSchemas;
|
|
138
|
+
/**
|
|
139
|
+
* The state context schema for the states that the agent can observe.
|
|
140
|
+
*/
|
|
134
141
|
context?: TContextSchema;
|
|
135
|
-
|
|
136
|
-
|
|
142
|
+
/**
|
|
143
|
+
* The default policy to use for `agent.decide(…)`.
|
|
144
|
+
*
|
|
145
|
+
* A policy is a strategy that the agent uses to decide which event to trigger next.
|
|
146
|
+
*/
|
|
147
|
+
policy?: AgentPolicy<Agent<TContextSchema, TEventSchemas>>;
|
|
137
148
|
/**
|
|
138
149
|
* A function that retrieves the agent's long term memory
|
|
139
150
|
*/
|
|
@@ -141,10 +152,19 @@ export function createAgent<
|
|
|
141
152
|
agent: Agent<TContextSchema, TEventSchemas>
|
|
142
153
|
) => AgentLongTermMemory<TAgent>;
|
|
143
154
|
/**
|
|
144
|
-
*
|
|
155
|
+
* Custom agent logic, which receives events for handling feedback,
|
|
156
|
+
* observations, messages, decisions, and insights.
|
|
145
157
|
*/
|
|
146
158
|
logic?: AgentLogic<TAgent>;
|
|
159
|
+
/**
|
|
160
|
+
* The default language model for the agent to use in `agent.decide(…)`.
|
|
161
|
+
*/
|
|
147
162
|
model: LanguageModel;
|
|
163
|
+
/**
|
|
164
|
+
* The unique episode ID that this agent will run on.
|
|
165
|
+
*
|
|
166
|
+
* An episode is an instance of an agent interacting with an environment.
|
|
167
|
+
*/
|
|
148
168
|
episodeId?: string;
|
|
149
169
|
}): Agent<TContextSchema, TEventSchemas> {
|
|
150
170
|
return new Agent({
|
|
@@ -152,7 +172,7 @@ export function createAgent<
|
|
|
152
172
|
context,
|
|
153
173
|
events,
|
|
154
174
|
description,
|
|
155
|
-
|
|
175
|
+
policy: policy,
|
|
156
176
|
model,
|
|
157
177
|
logic,
|
|
158
178
|
episodeId,
|
|
@@ -161,9 +181,7 @@ export function createAgent<
|
|
|
161
181
|
|
|
162
182
|
export class Agent<
|
|
163
183
|
const TContextSchema extends ZodContextMapping,
|
|
164
|
-
const TEventSchemas extends ZodEventMapping
|
|
165
|
-
TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>,
|
|
166
|
-
TContext = ContextFromZodContextMapping<TContextSchema>
|
|
184
|
+
const TEventSchemas extends ZodEventMapping
|
|
167
185
|
> extends Actor<AgentLogic<any>> {
|
|
168
186
|
/**
|
|
169
187
|
* The name of the agent. All agents with the same name are related and
|
|
@@ -177,11 +195,7 @@ export class Agent<
|
|
|
177
195
|
public description?: string;
|
|
178
196
|
public events: TEventSchemas;
|
|
179
197
|
public context?: TContextSchema;
|
|
180
|
-
public
|
|
181
|
-
// public types: {
|
|
182
|
-
// events: TEvents;
|
|
183
|
-
// context: Compute<TContext>;
|
|
184
|
-
// };
|
|
198
|
+
public policy: AgentPolicy<Agent<TContextSchema, TEventSchemas>>;
|
|
185
199
|
public model: LanguageModel;
|
|
186
200
|
public memory: AgentLongTermMemory<this> | undefined;
|
|
187
201
|
|
|
@@ -194,7 +208,7 @@ export class Agent<
|
|
|
194
208
|
events,
|
|
195
209
|
context,
|
|
196
210
|
episodeId,
|
|
197
|
-
|
|
211
|
+
policy = toolPolicy,
|
|
198
212
|
}: {
|
|
199
213
|
logic: AgentLogic<any>;
|
|
200
214
|
id?: string;
|
|
@@ -203,7 +217,7 @@ export class Agent<
|
|
|
203
217
|
model: GenerateTextOptions['model'];
|
|
204
218
|
events: TEventSchemas;
|
|
205
219
|
context?: TContextSchema;
|
|
206
|
-
|
|
220
|
+
policy?: AgentPolicy<Agent<TContextSchema, TEventSchemas>>;
|
|
207
221
|
episodeId?: string;
|
|
208
222
|
}) {
|
|
209
223
|
super(logic);
|
|
@@ -213,30 +227,44 @@ export class Agent<
|
|
|
213
227
|
this.description = description;
|
|
214
228
|
this.events = events;
|
|
215
229
|
this.context = context;
|
|
216
|
-
this.
|
|
230
|
+
this.policy = policy;
|
|
217
231
|
this.id = id ?? randomId();
|
|
218
232
|
|
|
219
233
|
this.start();
|
|
220
234
|
}
|
|
221
235
|
|
|
222
236
|
/**
|
|
223
|
-
* Called whenever the agent
|
|
237
|
+
* Called whenever the agent detects that a message was sent from the human, assistant, or system.
|
|
224
238
|
*/
|
|
225
239
|
public onMessage(fn: (message: AgentMessage) => void) {
|
|
226
240
|
return this.on('message', (ev) => fn(ev.message));
|
|
227
241
|
}
|
|
228
242
|
|
|
229
243
|
/**
|
|
230
|
-
* Called whenever the agent
|
|
244
|
+
* Called whenever the agent receives some feedback.
|
|
231
245
|
*/
|
|
232
246
|
public onFeedback(fn: (feedback: AgentFeedback) => void) {
|
|
233
247
|
return this.on('feedback', (ev) => fn(ev.feedback));
|
|
234
248
|
}
|
|
235
249
|
|
|
236
250
|
/**
|
|
237
|
-
*
|
|
251
|
+
* Called whenever the agent receives an observation.
|
|
252
|
+
*/
|
|
253
|
+
public onObservation(fn: (observation: AgentObservation<this>) => void) {
|
|
254
|
+
return this.on('observation', (ev) => fn(ev.observation));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Called whenever the agent makes a decision.
|
|
259
|
+
*/
|
|
260
|
+
public onDecision(fn: (decision: AgentDecision<this>) => void) {
|
|
261
|
+
return this.on('decision', (ev) => fn(ev.decision));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Adds a message to the agent's short-term (local) memory.
|
|
238
266
|
*/
|
|
239
|
-
public addMessage(messageInput: AgentMessageInput) {
|
|
267
|
+
public addMessage(messageInput: AgentMessageInput): AgentMessage {
|
|
240
268
|
const message = {
|
|
241
269
|
...messageInput,
|
|
242
270
|
id: messageInput.id ?? randomId(),
|
|
@@ -258,6 +286,7 @@ export class Agent<
|
|
|
258
286
|
public addFeedback(feedbackInput: AgentFeedbackInput) {
|
|
259
287
|
const feedback = {
|
|
260
288
|
...feedbackInput,
|
|
289
|
+
id: feedbackInput.id ?? randomId(),
|
|
261
290
|
comment: feedbackInput.comment ?? undefined,
|
|
262
291
|
attributes: { ...feedbackInput.attributes },
|
|
263
292
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
@@ -309,10 +338,40 @@ export class Agent<
|
|
|
309
338
|
return this.getSnapshot().context.observations;
|
|
310
339
|
}
|
|
311
340
|
|
|
312
|
-
public
|
|
341
|
+
public addInsight(insightInput: AgentInsightInput): AgentInsight {
|
|
342
|
+
const insight = {
|
|
343
|
+
...insightInput,
|
|
344
|
+
episodeId: insightInput.episodeId ?? this.episodeId,
|
|
345
|
+
id: insightInput.id ?? randomId(),
|
|
346
|
+
timestamp: insightInput.timestamp ?? Date.now(),
|
|
347
|
+
} satisfies AgentInsight;
|
|
348
|
+
|
|
349
|
+
this.send({
|
|
350
|
+
type: 'agent.insight',
|
|
351
|
+
insight,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
return insight;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
public getInsights() {
|
|
358
|
+
return this.getSnapshot().context.insights;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
public addDecision(input: AgentDecisionInput<this>) {
|
|
313
362
|
this.send({
|
|
314
363
|
type: 'agent.decision',
|
|
315
|
-
decision
|
|
364
|
+
decision: {
|
|
365
|
+
id: input.id ?? randomId(),
|
|
366
|
+
episodeId: input.episodeId ?? this.episodeId,
|
|
367
|
+
timestamp: input.timestamp ?? Date.now(),
|
|
368
|
+
decisionId: input.decisionId ?? null,
|
|
369
|
+
policy: input.policy ?? null,
|
|
370
|
+
goalState: input.goalState ?? null,
|
|
371
|
+
nextEvent: input.nextEvent ?? null,
|
|
372
|
+
paths: input.paths ?? [],
|
|
373
|
+
...input,
|
|
374
|
+
},
|
|
316
375
|
});
|
|
317
376
|
}
|
|
318
377
|
/**
|
|
@@ -386,15 +445,15 @@ export class Agent<
|
|
|
386
445
|
|
|
387
446
|
const agent = this;
|
|
388
447
|
|
|
389
|
-
async
|
|
448
|
+
const handleObservation = async (
|
|
390
449
|
observationInput: AgentObservationInput<any>
|
|
391
|
-
) {
|
|
450
|
+
) => {
|
|
392
451
|
const observation = agent.addObservation(observationInput);
|
|
393
452
|
|
|
394
453
|
const interactInput = getInput?.(observation);
|
|
395
454
|
|
|
396
455
|
if (interactInput) {
|
|
397
|
-
const decision = await
|
|
456
|
+
const decision = await this.decide({
|
|
398
457
|
machine,
|
|
399
458
|
state: observation.state,
|
|
400
459
|
...interactInput,
|
|
@@ -408,7 +467,7 @@ export class Agent<
|
|
|
408
467
|
}
|
|
409
468
|
|
|
410
469
|
prevState = observationInput.state;
|
|
411
|
-
}
|
|
470
|
+
};
|
|
412
471
|
|
|
413
472
|
// Inspect system, but only observe specified actor
|
|
414
473
|
const sub = actorRefCheck
|
|
@@ -426,14 +485,16 @@ export class Agent<
|
|
|
426
485
|
| string
|
|
427
486
|
| undefined;
|
|
428
487
|
|
|
488
|
+
const decisions = agent.getDecisions();
|
|
489
|
+
|
|
429
490
|
const decision = decisionId
|
|
430
|
-
?
|
|
491
|
+
? decisions.find((d) => d.id === decisionId)
|
|
431
492
|
: undefined;
|
|
432
493
|
|
|
433
494
|
const observationInput = {
|
|
434
495
|
event: inspEvent.event,
|
|
435
496
|
prevState,
|
|
436
|
-
state: inspEvent.snapshot as
|
|
497
|
+
state: inspEvent.snapshot as SnapshotFrom<TActor>,
|
|
437
498
|
goal: decision?.goal,
|
|
438
499
|
decisionId,
|
|
439
500
|
} satisfies AgentObservationInput<any>;
|
|
@@ -478,15 +539,18 @@ export class Agent<
|
|
|
478
539
|
const decisionId = inspEvent.event['_decision'] as
|
|
479
540
|
| string
|
|
480
541
|
| undefined;
|
|
542
|
+
|
|
543
|
+
const decisions = this.getDecisions();
|
|
544
|
+
|
|
481
545
|
const decision = decisionId
|
|
482
|
-
?
|
|
546
|
+
? decisions.find((d) => d.id === decisionId)
|
|
483
547
|
: undefined;
|
|
484
548
|
|
|
485
549
|
const observationInput = {
|
|
486
550
|
decisionId,
|
|
487
551
|
event: inspEvent.event,
|
|
488
552
|
prevState,
|
|
489
|
-
state: inspEvent.snapshot as
|
|
553
|
+
state: inspEvent.snapshot as SnapshotFrom<TActor>,
|
|
490
554
|
goal: decision?.goal,
|
|
491
555
|
} satisfies AgentObservationInput<this>;
|
|
492
556
|
|
|
@@ -501,7 +565,7 @@ export class Agent<
|
|
|
501
565
|
}
|
|
502
566
|
|
|
503
567
|
public wrap(modelToWrap: LanguageModelV1) {
|
|
504
|
-
return
|
|
568
|
+
return wrapLanguageModel({
|
|
505
569
|
model: modelToWrap,
|
|
506
570
|
middleware: createAgentMiddleware(this),
|
|
507
571
|
});
|
|
@@ -518,6 +582,56 @@ export class Agent<
|
|
|
518
582
|
public async decide(
|
|
519
583
|
input: AgentDecideInput<this>
|
|
520
584
|
): Promise<AgentDecision<this> | undefined> {
|
|
521
|
-
|
|
585
|
+
const resolvedOptions = input;
|
|
586
|
+
const {
|
|
587
|
+
policy = this.policy,
|
|
588
|
+
goal,
|
|
589
|
+
allowedEvents,
|
|
590
|
+
events = this.events,
|
|
591
|
+
state,
|
|
592
|
+
machine,
|
|
593
|
+
model = this.model,
|
|
594
|
+
messages,
|
|
595
|
+
episodeId = this.episodeId,
|
|
596
|
+
maxAttempts = 2,
|
|
597
|
+
...otherDecideInput
|
|
598
|
+
} = resolvedOptions;
|
|
599
|
+
|
|
600
|
+
const filteredEventSchemas = allowedEvents
|
|
601
|
+
? Object.fromEntries(
|
|
602
|
+
Object.entries(events).filter(([key]) => {
|
|
603
|
+
return allowedEvents.includes(key as EventFromAgent<this>['type']);
|
|
604
|
+
})
|
|
605
|
+
)
|
|
606
|
+
: events;
|
|
607
|
+
|
|
608
|
+
let attempts = 0;
|
|
609
|
+
|
|
610
|
+
let decision: AgentDecision<this> | undefined;
|
|
611
|
+
|
|
612
|
+
const minimalState = {
|
|
613
|
+
value: state.value,
|
|
614
|
+
context: state.context,
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
while (attempts++ < maxAttempts) {
|
|
618
|
+
decision = await policy(this, {
|
|
619
|
+
episodeId,
|
|
620
|
+
model,
|
|
621
|
+
goal,
|
|
622
|
+
events: filteredEventSchemas,
|
|
623
|
+
state: minimalState,
|
|
624
|
+
machine,
|
|
625
|
+
messages: messages as CoreMessage[], // TODO: fix UIMessage thing
|
|
626
|
+
...otherDecideInput,
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
if (decision?.nextEvent) {
|
|
630
|
+
this.addDecision(decision);
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return decision;
|
|
522
636
|
}
|
|
523
637
|
}
|
package/src/decide.test.ts
CHANGED
|
@@ -154,7 +154,7 @@ test('interacts with an actor (late interaction)', async () => {
|
|
|
154
154
|
expect(actor.getSnapshot().value).toBe('third');
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
test('agent.decide() makes a decision based on goal and state (
|
|
157
|
+
test('agent.decide() makes a decision based on goal and state (tool policy)', async () => {
|
|
158
158
|
const model = new MockLanguageModelV1({
|
|
159
159
|
doGenerate,
|
|
160
160
|
});
|
|
@@ -211,7 +211,7 @@ test.each([
|
|
|
211
211
|
? params.mode.tools?.map((t) => t.name)
|
|
212
212
|
: [];
|
|
213
213
|
|
|
214
|
-
console.log('try', attempts, 'max', maxAttempts);
|
|
214
|
+
// console.log('try', attempts, 'max', maxAttempts);
|
|
215
215
|
|
|
216
216
|
const toolCalls =
|
|
217
217
|
succeed && attempts++ === (maxAttempts ?? 2) - 1
|
package/src/decide.ts
CHANGED
|
@@ -1,77 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AnyActor,
|
|
3
|
+
AnyMachineSnapshot,
|
|
4
|
+
fromPromise,
|
|
5
|
+
PromiseActorLogic,
|
|
6
|
+
} from 'xstate';
|
|
2
7
|
import {
|
|
3
8
|
AnyAgent,
|
|
4
|
-
AgentDecisionLogic,
|
|
5
|
-
AgentDecision,
|
|
6
9
|
AgentDecideInput,
|
|
7
10
|
TransitionData,
|
|
8
|
-
|
|
11
|
+
AgentDecision,
|
|
9
12
|
} from './types';
|
|
10
13
|
import { getTransitions } from './utils';
|
|
11
|
-
import {
|
|
14
|
+
import { CoreTool, generateText, LanguageModel, tool } from 'ai';
|
|
12
15
|
import { ZodEventMapping } from './schemas';
|
|
13
16
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const {
|
|
20
|
-
strategy = agent.strategy,
|
|
21
|
-
goal,
|
|
22
|
-
allowedEvents,
|
|
23
|
-
events = agent.events,
|
|
24
|
-
state,
|
|
25
|
-
machine,
|
|
26
|
-
model = agent.model,
|
|
27
|
-
messages,
|
|
28
|
-
episodeId = agent.episodeId,
|
|
29
|
-
maxAttempts = 2,
|
|
30
|
-
...otherDecideInput
|
|
31
|
-
} = resolvedOptions;
|
|
32
|
-
|
|
33
|
-
const filteredEventSchemas = allowedEvents
|
|
34
|
-
? Object.fromEntries(
|
|
35
|
-
Object.entries(events).filter(([key]) => {
|
|
36
|
-
return allowedEvents.includes(key);
|
|
37
|
-
})
|
|
38
|
-
)
|
|
39
|
-
: events;
|
|
40
|
-
|
|
41
|
-
let attempts = 0;
|
|
42
|
-
|
|
43
|
-
let decision: AgentDecision<any> | undefined;
|
|
44
|
-
|
|
45
|
-
const minimalState = {
|
|
46
|
-
value: state.value,
|
|
47
|
-
context: state.context,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
while (attempts++ < maxAttempts) {
|
|
51
|
-
decision = await strategy(agent, {
|
|
52
|
-
episodeId,
|
|
53
|
-
model,
|
|
54
|
-
goal,
|
|
55
|
-
events: filteredEventSchemas,
|
|
56
|
-
state: minimalState,
|
|
57
|
-
machine,
|
|
58
|
-
messages: messages as CoreMessage[], // TODO: fix UIMessage thing
|
|
59
|
-
...otherDecideInput,
|
|
60
|
-
});
|
|
17
|
+
export type AgentDecideLogicInput = {
|
|
18
|
+
goal: string;
|
|
19
|
+
model?: LanguageModel;
|
|
20
|
+
context?: Record<string, any>;
|
|
21
|
+
} & Omit<Parameters<typeof generateText>[0], 'model' | 'tools' | 'prompt'>;
|
|
61
22
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
23
|
+
export type MachineDecisionLogic<TAgent extends AnyAgent> = PromiseActorLogic<
|
|
24
|
+
AgentDecision<TAgent> | undefined,
|
|
25
|
+
AgentDecideLogicInput | string
|
|
26
|
+
>;
|
|
67
27
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
agent: T,
|
|
73
|
-
defaultInput?: AgentDecideInput<EventFromAgent<T>>
|
|
74
|
-
): AgentDecisionLogic<any> {
|
|
28
|
+
export function fromDecision<TAgent extends AnyAgent>(
|
|
29
|
+
agent: TAgent,
|
|
30
|
+
defaultInput?: AgentDecideInput<TAgent>
|
|
31
|
+
): MachineDecisionLogic<any> {
|
|
75
32
|
return fromPromise(async ({ input, self }) => {
|
|
76
33
|
const parentRef = self._parent;
|
|
77
34
|
if (!parentRef) {
|
|
@@ -85,9 +42,10 @@ export function fromDecision<T extends AnyAgent>(
|
|
|
85
42
|
...inputObject,
|
|
86
43
|
};
|
|
87
44
|
|
|
88
|
-
const decision = await
|
|
45
|
+
const decision = await agent.decide({
|
|
89
46
|
machine: (parentRef as AnyActor).logic,
|
|
90
47
|
state: snapshot,
|
|
48
|
+
allowedEvents: resolvedInput.allowedEvents as any[],
|
|
91
49
|
...resolvedInput,
|
|
92
50
|
// @ts-ignore
|
|
93
51
|
messages: resolvedInput.messages,
|
|
@@ -98,7 +56,7 @@ export function fromDecision<T extends AnyAgent>(
|
|
|
98
56
|
}
|
|
99
57
|
|
|
100
58
|
return decision;
|
|
101
|
-
}) as
|
|
59
|
+
}) as MachineDecisionLogic<any>;
|
|
102
60
|
}
|
|
103
61
|
|
|
104
62
|
export function getToolMap<TAgent extends AnyAgent>(
|
package/src/index.ts
CHANGED
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
AgentDecision,
|
|
6
6
|
PromptTemplate,
|
|
7
7
|
} from '../types';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { combinePromptAndMessages } from '../text';
|
|
9
|
+
import { toolPolicy } from './toolPolicy';
|
|
10
10
|
import { convertToXml } from '../utils';
|
|
11
11
|
|
|
12
12
|
const chainOfThoughtPromptTemplate: PromptTemplate<any> = ({
|
|
@@ -14,14 +14,12 @@ const chainOfThoughtPromptTemplate: PromptTemplate<any> = ({
|
|
|
14
14
|
context,
|
|
15
15
|
goal,
|
|
16
16
|
}) => {
|
|
17
|
-
return
|
|
18
|
-
${convertToXml({ stateValue, context, goal })}
|
|
17
|
+
return `${convertToXml({ stateValue, context, goal })}
|
|
19
18
|
|
|
20
|
-
How would you achieve the goal? Think step-by-step
|
|
21
|
-
`.trim();
|
|
19
|
+
How would you achieve the goal? Think step-by-step.`;
|
|
22
20
|
};
|
|
23
21
|
|
|
24
|
-
export async function
|
|
22
|
+
export async function chainOfThoughtPolicy<T extends AnyAgent>(
|
|
25
23
|
agent: T,
|
|
26
24
|
input: AgentDecideInput<any>
|
|
27
25
|
): Promise<AgentDecision<any> | undefined> {
|
|
@@ -31,7 +29,7 @@ export async function chainOfThoughtStrategy<T extends AnyAgent>(
|
|
|
31
29
|
goal: input.goal,
|
|
32
30
|
});
|
|
33
31
|
|
|
34
|
-
const messages =
|
|
32
|
+
const messages = combinePromptAndMessages(prompt, input.messages);
|
|
35
33
|
|
|
36
34
|
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
37
35
|
|
|
@@ -41,7 +39,7 @@ export async function chainOfThoughtStrategy<T extends AnyAgent>(
|
|
|
41
39
|
messages,
|
|
42
40
|
});
|
|
43
41
|
|
|
44
|
-
const decision = await
|
|
42
|
+
const decision = await toolPolicy(agent, {
|
|
45
43
|
...input,
|
|
46
44
|
messages: messages.concat(result.response.messages),
|
|
47
45
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createAgent, TypesFromAgent } from '..';
|
|
2
2
|
import { assign, createActor, setup } from 'xstate';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import {
|
|
4
|
+
import { experimental_shortestPathPolicy } from './shortestPathPolicy';
|
|
5
5
|
import { test, expect } from 'vitest';
|
|
6
6
|
import { dummyResponseValues, MockLanguageModelV1 } from '../mockModel';
|
|
7
7
|
|
|
@@ -84,7 +84,7 @@ test.skip('should find shortest path to goal', async () => {
|
|
|
84
84
|
}),
|
|
85
85
|
goal: 'Get the counter to exactly 3',
|
|
86
86
|
state: counterActor.getSnapshot(),
|
|
87
|
-
|
|
87
|
+
policy: experimental_shortestPathPolicy,
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
expect(decision?.nextEvent?.type).toBe('increment');
|