@statelyai/agent 2.0.0-next.1 → 2.0.0-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changeset/grumpy-dolphins-think.md +17 -0
- package/.changeset/old-teachers-tap.md +5 -0
- package/.changeset/pink-eagles-deliver.md +13 -0
- package/.changeset/pre.json +9 -1
- package/.changeset/quiet-turtles-do.md +7 -0
- package/.changeset/smart-yaks-pull.md +23 -0
- package/.changeset/sweet-clouds-mix.md +16 -0
- package/.changeset/swift-mangos-rush.md +5 -0
- package/.changeset/tough-ways-rhyme.md +5 -0
- package/CHANGELOG.md +79 -0
- package/dist/index.d.mts +116 -100
- package/dist/index.d.ts +116 -100
- package/dist/index.js +102 -72
- package/dist/index.mjs +105 -75
- package/examples/chatbot.ts +2 -2
- package/examples/cot.ts +21 -73
- package/examples/customer-service-sim.ts +3 -3
- package/examples/email.ts +3 -5
- package/examples/example.ts +2 -2
- package/examples/goal.ts +2 -2
- package/examples/joke.ts +12 -12
- package/examples/jugs.ts +4 -7
- package/examples/learn-from-feedback.ts +123 -0
- package/examples/number.ts +2 -2
- package/examples/raffle.ts +2 -2
- package/examples/river-crossing.ts +4 -7
- package/examples/simple.ts +13 -10
- package/examples/summary.ts +2 -5
- package/examples/support.ts +38 -38
- package/examples/ticTacToe.ts +46 -4
- package/examples/todo.ts +3 -3
- package/examples/tutor.ts +2 -2
- package/examples/verify.ts +2 -2
- package/examples/weather-agent.ts +139 -0
- package/examples/weather.ts +26 -23
- package/examples/word.ts +8 -6
- package/package.json +2 -1
- package/src/agent.test.ts +37 -52
- package/src/agent.ts +93 -60
- package/src/decide.test.ts +56 -8
- package/src/decide.ts +42 -32
- package/src/strategies/chainOfThought.ts +50 -0
- package/src/{planners → strategies}/shortestPath.test.ts +4 -7
- package/src/strategies/shortestPath.ts +178 -0
- package/src/{planners → strategies}/simple.ts +25 -26
- package/src/templates/defaultText.ts +3 -0
- package/src/text.ts +13 -13
- package/src/types.ts +124 -83
- package/src/utils.ts +13 -1
- package/src/planners/shortestPath.ts +0 -177
- package/src/strategies/chain-of-note.ts +0 -106
package/src/types.ts
CHANGED
|
@@ -27,21 +27,25 @@ export type GenerateTextOptions = Parameters<typeof generateText>[0];
|
|
|
27
27
|
|
|
28
28
|
export type StreamTextOptions = Parameters<typeof streamText>[0];
|
|
29
29
|
|
|
30
|
-
export type CostFunction<
|
|
31
|
-
path: AgentPath<
|
|
30
|
+
export type CostFunction<TAgent extends AnyAgent> = (
|
|
31
|
+
path: AgentPath<TAgent>
|
|
32
32
|
) => number;
|
|
33
33
|
|
|
34
|
-
export type
|
|
35
|
-
AgentGenerateTextOptions
|
|
34
|
+
export type AgentDecideInput<TAgent extends AnyAgent> = Omit<
|
|
35
|
+
AgentGenerateTextOptions<TAgent>,
|
|
36
36
|
'prompt' | 'tools'
|
|
37
37
|
> & {
|
|
38
38
|
/**
|
|
39
39
|
* The currently observed state.
|
|
40
40
|
*/
|
|
41
|
-
state: ObservedState
|
|
41
|
+
state: ObservedState<TAgent>;
|
|
42
|
+
/**
|
|
43
|
+
* The context to provide in the prompt to the agent. This overrides the `state.context`.
|
|
44
|
+
*/
|
|
45
|
+
context?: Record<string, any>;
|
|
42
46
|
/**
|
|
43
47
|
* The goal for the agent to accomplish.
|
|
44
|
-
* The agent will
|
|
48
|
+
* The agent will make a decision based on this goal.
|
|
45
49
|
*/
|
|
46
50
|
goal: string;
|
|
47
51
|
/**
|
|
@@ -54,58 +58,55 @@ export type AgentPlanInput<TEvent extends EventObject> = Omit<
|
|
|
54
58
|
* is interacting with.
|
|
55
59
|
*/
|
|
56
60
|
machine?: AnyStateMachine;
|
|
57
|
-
/**
|
|
58
|
-
* The previous plan.
|
|
59
|
-
*/
|
|
60
|
-
previousPlan?: AgentPlan<TEvent>;
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* The total cost of the path to the goal state.
|
|
64
64
|
*/
|
|
65
|
-
costFunction?: CostFunction<
|
|
65
|
+
costFunction?: CostFunction<TAgent>;
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* The maximum number of attempts to
|
|
68
|
+
* The maximum number of attempts to make a decision.
|
|
69
69
|
* Defaults to 2.
|
|
70
70
|
*/
|
|
71
71
|
maxAttempts?: number;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
export type AgentStep<
|
|
74
|
+
export type AgentStep<TAgent extends AnyAgent> = {
|
|
75
75
|
/** The event to take */
|
|
76
|
-
event:
|
|
76
|
+
event: EventFromAgent<TAgent>;
|
|
77
77
|
/** The next expected state after taking the event */
|
|
78
|
-
state: ObservedState | undefined;
|
|
78
|
+
state: ObservedState<TAgent> | undefined;
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
export type AgentPath<
|
|
81
|
+
export type AgentPath<TAgent extends AnyAgent> = {
|
|
82
82
|
/** The expected ending state of the path */
|
|
83
|
-
state: ObservedState | undefined;
|
|
83
|
+
state: ObservedState<TAgent> | undefined;
|
|
84
84
|
/** The steps to reach the ending state */
|
|
85
|
-
steps: Array<AgentStep<
|
|
85
|
+
steps: Array<AgentStep<TAgent>>;
|
|
86
86
|
weight?: number;
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
-
export type
|
|
89
|
+
export type AgentDecision<TAgent extends AnyAgent> = {
|
|
90
|
+
id: string;
|
|
90
91
|
/**
|
|
91
|
-
* The
|
|
92
|
+
* The strategy used to generate the decision
|
|
92
93
|
*/
|
|
93
|
-
|
|
94
|
+
strategy: string;
|
|
94
95
|
goal: string;
|
|
95
96
|
/**
|
|
96
|
-
* The ending state of the
|
|
97
|
+
* The ending state of the decision.
|
|
97
98
|
*/
|
|
98
|
-
goalState: ObservedState | undefined;
|
|
99
|
+
goalState: ObservedState<TAgent> | undefined;
|
|
99
100
|
/**
|
|
100
101
|
* The next event that the agent decided needs to occur to achieve the `goal`.
|
|
101
102
|
*
|
|
102
103
|
* This next event is chosen from the
|
|
103
104
|
*/
|
|
104
|
-
nextEvent:
|
|
105
|
+
nextEvent: EventFromAgent<TAgent> | undefined;
|
|
105
106
|
/**
|
|
106
107
|
* The paths that the agent can take to achieve the goal.
|
|
107
108
|
*/
|
|
108
|
-
paths: AgentPath<
|
|
109
|
+
paths: AgentPath<TAgent>[];
|
|
109
110
|
episodeId: string;
|
|
110
111
|
timestamp: number;
|
|
111
112
|
// result: GenerateObjectResult<any>;
|
|
@@ -118,17 +119,13 @@ export interface TransitionData {
|
|
|
118
119
|
target?: any;
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
export type PromptTemplate<
|
|
122
|
+
export type PromptTemplate<TAgent extends AnyAgent> = (data: {
|
|
122
123
|
goal: string;
|
|
123
124
|
/**
|
|
124
125
|
* The observed state
|
|
125
126
|
*/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
* The context to provide.
|
|
129
|
-
* This overrides the observed state.context, if provided.
|
|
130
|
-
*/
|
|
131
|
-
context?: any;
|
|
127
|
+
stateValue?: any;
|
|
128
|
+
context?: Record<string, any>;
|
|
132
129
|
/**
|
|
133
130
|
* The state machine model of the observed environment
|
|
134
131
|
*/
|
|
@@ -144,22 +141,34 @@ export type PromptTemplate<TEvents extends EventObject> = (data: {
|
|
|
144
141
|
observations?: AgentObservation<any>[]; // TODO
|
|
145
142
|
feedback?: AgentFeedback[];
|
|
146
143
|
messages?: AgentMessage[];
|
|
147
|
-
|
|
144
|
+
decisions?: AgentDecision<TAgent>[];
|
|
148
145
|
}) => string;
|
|
149
146
|
|
|
150
|
-
export type
|
|
151
|
-
agent:
|
|
152
|
-
input:
|
|
153
|
-
) => Promise<
|
|
147
|
+
export type AgentStrategy<TAgent extends AnyAgent> = (
|
|
148
|
+
agent: TAgent,
|
|
149
|
+
input: AgentDecideInput<EventFromAgent<TAgent>>
|
|
150
|
+
) => Promise<AgentDecision<TAgent> | undefined>;
|
|
151
|
+
|
|
152
|
+
export type AgentInteractInput<T extends AnyAgent> = Omit<
|
|
153
|
+
AgentDecideOptions<T>,
|
|
154
|
+
'state'
|
|
155
|
+
> & {
|
|
156
|
+
state?: never;
|
|
157
|
+
};
|
|
154
158
|
|
|
155
|
-
export type AgentDecideOptions<
|
|
159
|
+
export type AgentDecideOptions<TAgent extends AnyAgent> = {
|
|
156
160
|
goal: string;
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
state: ObservedState<TAgent>;
|
|
162
|
+
/**
|
|
163
|
+
* The context to provide in the prompt to the agent. This overrides the `state.context`.
|
|
164
|
+
*/
|
|
165
|
+
context?: Record<string, any>;
|
|
159
166
|
machine?: AnyStateMachine;
|
|
167
|
+
model?: LanguageModel;
|
|
160
168
|
execute?: (event: AnyEventObject) => Promise<void>;
|
|
161
|
-
|
|
169
|
+
strategy?: AgentStrategy<TAgent>;
|
|
162
170
|
events?: ZodEventMapping;
|
|
171
|
+
allowedEvents?: Array<EventFromAgent<TAgent>['type']>;
|
|
163
172
|
/**
|
|
164
173
|
* The maximum number of times the agent will attempt to make a decision.
|
|
165
174
|
* Defaults to 2.
|
|
@@ -168,23 +177,23 @@ export type AgentDecideOptions<T extends AnyAgent> = {
|
|
|
168
177
|
} & Omit<Parameters<typeof generateText>[0], 'model' | 'tools' | 'prompt'>;
|
|
169
178
|
|
|
170
179
|
export interface AgentFeedback {
|
|
171
|
-
|
|
172
|
-
|
|
180
|
+
observationId: string;
|
|
181
|
+
score: number;
|
|
182
|
+
comment: string | undefined;
|
|
173
183
|
/**
|
|
174
184
|
* The message correlation that the feedback is relevant for
|
|
175
185
|
*/
|
|
176
186
|
attributes: Record<string, any>;
|
|
177
|
-
reward: number;
|
|
178
187
|
timestamp: number;
|
|
179
188
|
episodeId: string;
|
|
180
189
|
}
|
|
181
190
|
|
|
182
191
|
export interface AgentFeedbackInput {
|
|
183
|
-
|
|
184
|
-
|
|
192
|
+
observationId: string;
|
|
193
|
+
score: number;
|
|
194
|
+
comment?: string;
|
|
185
195
|
attributes?: Record<string, any>;
|
|
186
196
|
timestamp?: number;
|
|
187
|
-
reward?: number;
|
|
188
197
|
}
|
|
189
198
|
|
|
190
199
|
export type AgentMessage = CoreMessage & {
|
|
@@ -327,6 +336,7 @@ export type AgentMessageInput = CoreMessage & {
|
|
|
327
336
|
|
|
328
337
|
export interface AgentObservation<TActor extends ActorRefLike> {
|
|
329
338
|
id: string;
|
|
339
|
+
goal?: string;
|
|
330
340
|
prevState: SnapshotFrom<TActor> | undefined;
|
|
331
341
|
event: EventFrom<TActor> | undefined;
|
|
332
342
|
state: SnapshotFrom<TActor>;
|
|
@@ -335,13 +345,14 @@ export interface AgentObservation<TActor extends ActorRefLike> {
|
|
|
335
345
|
timestamp: number;
|
|
336
346
|
}
|
|
337
347
|
|
|
338
|
-
export interface AgentObservationInput {
|
|
348
|
+
export interface AgentObservationInput<TAgent extends AnyAgent> {
|
|
339
349
|
id?: string;
|
|
340
|
-
prevState?: ObservedState
|
|
350
|
+
prevState?: ObservedState<TAgent>;
|
|
341
351
|
event?: AnyEventObject;
|
|
342
|
-
state: ObservedState
|
|
352
|
+
state: ObservedState<TAgent>;
|
|
343
353
|
machine?: AnyStateMachine;
|
|
344
354
|
timestamp?: number;
|
|
355
|
+
goal: string | undefined;
|
|
345
356
|
}
|
|
346
357
|
|
|
347
358
|
export type AgentDecisionInput = {
|
|
@@ -350,12 +361,12 @@ export type AgentDecisionInput = {
|
|
|
350
361
|
context?: Record<string, any>;
|
|
351
362
|
} & Omit<Parameters<typeof generateText>[0], 'model' | 'tools' | 'prompt'>;
|
|
352
363
|
|
|
353
|
-
export type AgentDecisionLogic<
|
|
354
|
-
|
|
364
|
+
export type AgentDecisionLogic<TAgent extends AnyAgent> = PromiseActorLogic<
|
|
365
|
+
AgentDecision<TAgent> | undefined,
|
|
355
366
|
AgentDecisionInput | string
|
|
356
367
|
>;
|
|
357
368
|
|
|
358
|
-
export type AgentEmitted<
|
|
369
|
+
export type AgentEmitted<TAgent extends AnyAgent> =
|
|
359
370
|
| {
|
|
360
371
|
type: 'feedback';
|
|
361
372
|
feedback: AgentFeedback;
|
|
@@ -369,12 +380,12 @@ export type AgentEmitted<TEvents extends EventObject> =
|
|
|
369
380
|
message: AgentMessage;
|
|
370
381
|
}
|
|
371
382
|
| {
|
|
372
|
-
type: '
|
|
373
|
-
|
|
383
|
+
type: 'decision';
|
|
384
|
+
decision: AgentDecision<TAgent>;
|
|
374
385
|
};
|
|
375
386
|
|
|
376
|
-
export type AgentLogic<
|
|
377
|
-
TransitionSnapshot<AgentMemoryContext
|
|
387
|
+
export type AgentLogic<TAgent extends AnyAgent> = ActorLogic<
|
|
388
|
+
TransitionSnapshot<AgentMemoryContext<TAgent>>,
|
|
378
389
|
| {
|
|
379
390
|
type: 'agent.feedback';
|
|
380
391
|
feedback: AgentFeedback;
|
|
@@ -388,20 +399,22 @@ export type AgentLogic<TEvents extends EventObject> = ActorLogic<
|
|
|
388
399
|
message: AgentMessage;
|
|
389
400
|
}
|
|
390
401
|
| {
|
|
391
|
-
type: 'agent.
|
|
392
|
-
|
|
402
|
+
type: 'agent.decision';
|
|
403
|
+
decision: AgentDecision<TAgent>;
|
|
393
404
|
},
|
|
394
405
|
any, // TODO: input
|
|
395
406
|
any,
|
|
396
|
-
AgentEmitted<
|
|
407
|
+
AgentEmitted<TAgent>
|
|
397
408
|
>;
|
|
398
409
|
|
|
399
410
|
export type EventsFromZodEventMapping<TEventSchemas extends ZodEventMapping> =
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
411
|
+
Compute<
|
|
412
|
+
Values<{
|
|
413
|
+
[K in keyof TEventSchemas & string]: {
|
|
414
|
+
type: K;
|
|
415
|
+
} & TypeOf<TEventSchemas[K]>;
|
|
416
|
+
}>
|
|
417
|
+
>;
|
|
405
418
|
|
|
406
419
|
export type ContextFromZodContextMapping<
|
|
407
420
|
TContextSchema extends ZodContextMapping
|
|
@@ -413,27 +426,27 @@ export type AnyAgent = Agent<any, any, any, any>;
|
|
|
413
426
|
|
|
414
427
|
export type FromAgent<T> = T | ((agent: AnyAgent) => T | Promise<T>);
|
|
415
428
|
|
|
416
|
-
export type CommonTextOptions = {
|
|
429
|
+
export type CommonTextOptions<TAgent extends AnyAgent> = {
|
|
417
430
|
prompt: FromAgent<string>;
|
|
418
431
|
model?: LanguageModel;
|
|
419
|
-
context?: Record<string, any>;
|
|
420
432
|
messages?: FromAgent<CoreMessage[]>;
|
|
421
433
|
template?: PromptTemplate<any>;
|
|
434
|
+
context?: Record<string, any>;
|
|
422
435
|
};
|
|
423
436
|
|
|
424
|
-
export type AgentGenerateTextOptions = Omit<
|
|
437
|
+
export type AgentGenerateTextOptions<TAgent extends AnyAgent> = Omit<
|
|
425
438
|
GenerateTextOptions,
|
|
426
439
|
'model' | 'prompt' | 'messages'
|
|
427
440
|
> &
|
|
428
|
-
CommonTextOptions
|
|
441
|
+
CommonTextOptions<TAgent>;
|
|
429
442
|
|
|
430
|
-
export type AgentStreamTextOptions = Omit<
|
|
443
|
+
export type AgentStreamTextOptions<TAgent extends AnyAgent> = Omit<
|
|
431
444
|
StreamTextOptions,
|
|
432
445
|
'model' | 'prompt' | 'messages'
|
|
433
446
|
> &
|
|
434
|
-
CommonTextOptions
|
|
447
|
+
CommonTextOptions<TAgent>;
|
|
435
448
|
|
|
436
|
-
export interface ObservedState {
|
|
449
|
+
export interface ObservedState<TAgent extends AnyAgent> {
|
|
437
450
|
/**
|
|
438
451
|
* The current state value of the state machine, e.g.
|
|
439
452
|
* `"loading"` or `"processing"` or `"ready"`
|
|
@@ -442,7 +455,7 @@ export interface ObservedState {
|
|
|
442
455
|
/**
|
|
443
456
|
* Additional contextual data related to the current state
|
|
444
457
|
*/
|
|
445
|
-
context?:
|
|
458
|
+
context?: ContextFromAgent<TAgent>;
|
|
446
459
|
}
|
|
447
460
|
|
|
448
461
|
export type ObservedStateFrom<TActor extends ActorRefLike> = Pick<
|
|
@@ -450,25 +463,53 @@ export type ObservedStateFrom<TActor extends ActorRefLike> = Pick<
|
|
|
450
463
|
'value' | 'context'
|
|
451
464
|
>;
|
|
452
465
|
|
|
453
|
-
export type AgentMemoryContext = {
|
|
454
|
-
observations: AgentObservation<
|
|
466
|
+
export type AgentMemoryContext<TAgent extends AnyAgent> = {
|
|
467
|
+
observations: AgentObservation<TAgent>[]; // TODO
|
|
455
468
|
messages: AgentMessage[];
|
|
456
|
-
|
|
469
|
+
decisions: AgentDecision<TAgent>[];
|
|
457
470
|
feedback: AgentFeedback[];
|
|
458
471
|
};
|
|
459
472
|
|
|
460
|
-
export interface AgentLongTermMemory {
|
|
461
|
-
get<K extends keyof AgentMemoryContext
|
|
473
|
+
export interface AgentLongTermMemory<TAgent extends AnyAgent> {
|
|
474
|
+
get<K extends keyof AgentMemoryContext<TAgent>>(
|
|
462
475
|
key: K
|
|
463
|
-
): Promise<AgentMemoryContext[K]>;
|
|
464
|
-
append<K extends keyof AgentMemoryContext
|
|
476
|
+
): Promise<AgentMemoryContext<TAgent>[K]>;
|
|
477
|
+
append<K extends keyof AgentMemoryContext<TAgent>>(
|
|
465
478
|
key: K,
|
|
466
|
-
item: AgentMemoryContext[K][0]
|
|
479
|
+
item: AgentMemoryContext<TAgent>[K][0]
|
|
467
480
|
): Promise<void>;
|
|
468
|
-
set<K extends keyof AgentMemoryContext
|
|
481
|
+
set<K extends keyof AgentMemoryContext<TAgent>>(
|
|
469
482
|
key: K,
|
|
470
|
-
items: AgentMemoryContext[K]
|
|
483
|
+
items: AgentMemoryContext<TAgent>[K]
|
|
471
484
|
): Promise<void>;
|
|
472
485
|
}
|
|
473
486
|
|
|
474
487
|
export type Compute<A extends any> = { [K in keyof A]: A[K] } & unknown;
|
|
488
|
+
|
|
489
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
490
|
+
|
|
491
|
+
export type EventFromAgent<T extends AnyAgent> = T extends Agent<
|
|
492
|
+
infer _,
|
|
493
|
+
infer __,
|
|
494
|
+
infer TEvents,
|
|
495
|
+
infer ___
|
|
496
|
+
>
|
|
497
|
+
? TEvents
|
|
498
|
+
: never;
|
|
499
|
+
|
|
500
|
+
export type TypesFromAgent<T extends AnyAgent> = T extends Agent<
|
|
501
|
+
infer TContextSchema,
|
|
502
|
+
infer TEventSchema
|
|
503
|
+
>
|
|
504
|
+
? {
|
|
505
|
+
context: ContextFromZodContextMapping<TContextSchema>;
|
|
506
|
+
events: EventsFromZodEventMapping<TEventSchema>;
|
|
507
|
+
}
|
|
508
|
+
: never;
|
|
509
|
+
|
|
510
|
+
export type ContextFromAgent<T extends AnyAgent> = T extends Agent<
|
|
511
|
+
infer TContextSchema,
|
|
512
|
+
infer _TEventSchema
|
|
513
|
+
>
|
|
514
|
+
? ContextFromZodContextMapping<TContextSchema>
|
|
515
|
+
: never;
|
package/src/utils.ts
CHANGED
|
@@ -59,6 +59,18 @@ export function wrapInXml(tagName: string, content: string): string {
|
|
|
59
59
|
return `<${tagName}>${content}</${tagName}>`;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
export function convertToXml(obj: Record<string, any>): string {
|
|
63
|
+
return Object.entries(obj)
|
|
64
|
+
.map(([key, value]) => {
|
|
65
|
+
if (typeof value === 'object' && value !== null) {
|
|
66
|
+
return wrapInXml(key, convertToXml(value));
|
|
67
|
+
} else {
|
|
68
|
+
return wrapInXml(key, value);
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
.join('');
|
|
72
|
+
}
|
|
73
|
+
|
|
62
74
|
export function randomId(prefix?: string): string {
|
|
63
75
|
const timestamp = Date.now().toString(36);
|
|
64
76
|
const random = Math.random().toString(36).substring(2, 9);
|
|
@@ -89,7 +101,7 @@ export function isActorRef(
|
|
|
89
101
|
}
|
|
90
102
|
|
|
91
103
|
export function getTransitions(
|
|
92
|
-
state: ObservedState
|
|
104
|
+
state: ObservedState<any>,
|
|
93
105
|
machine: AnyStateMachine
|
|
94
106
|
): TransitionData[] {
|
|
95
107
|
if (!machine) {
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { generateObject } from 'ai';
|
|
2
|
-
import {
|
|
3
|
-
AgentPlan,
|
|
4
|
-
AgentPlanInput,
|
|
5
|
-
AgentPlanner,
|
|
6
|
-
AgentStep,
|
|
7
|
-
AnyAgent,
|
|
8
|
-
CostFunction,
|
|
9
|
-
ObservedState,
|
|
10
|
-
} from '../types';
|
|
11
|
-
import { getShortestPaths } from '@xstate/graph';
|
|
12
|
-
import { z } from 'zod';
|
|
13
|
-
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
14
|
-
import Ajv from 'ajv';
|
|
15
|
-
import { AnyMachineSnapshot } from 'xstate';
|
|
16
|
-
|
|
17
|
-
const ajv = new Ajv();
|
|
18
|
-
|
|
19
|
-
function observedStatesEqual(state1: ObservedState, state2: ObservedState) {
|
|
20
|
-
// check state value && state context
|
|
21
|
-
return (
|
|
22
|
-
JSON.stringify(state1.value) === JSON.stringify(state2.value) &&
|
|
23
|
-
JSON.stringify(state1.context) === JSON.stringify(state2.context)
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function trimSteps(steps: AgentStep<any>[], currentState: ObservedState) {
|
|
28
|
-
const index = steps.findIndex(
|
|
29
|
-
(step) => step.state && observedStatesEqual(step.state, currentState)
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
if (index === -1) {
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return steps.slice(index + 1, steps.length);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function experimental_createShortestPathPlanner<
|
|
40
|
-
T extends AnyAgent
|
|
41
|
-
>(): AgentPlanner<T> {
|
|
42
|
-
return async function shortestPathPlanner<T extends AnyAgent>(
|
|
43
|
-
agent: T,
|
|
44
|
-
input: AgentPlanInput<any>
|
|
45
|
-
): Promise<AgentPlan<any> | undefined> {
|
|
46
|
-
const costFunction: CostFunction<any> =
|
|
47
|
-
input.costFunction ?? ((path) => path.weight ?? Infinity);
|
|
48
|
-
const existingPlan = agent
|
|
49
|
-
.getPlans()
|
|
50
|
-
.find((p) => p.planner === 'shortestPath' && p.goal === input.goal);
|
|
51
|
-
|
|
52
|
-
let paths = existingPlan?.paths;
|
|
53
|
-
|
|
54
|
-
if (existingPlan) {
|
|
55
|
-
console.log('Existing plan found');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (!input.machine && !existingPlan) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (input.machine && !existingPlan) {
|
|
63
|
-
const contextSchema = zodToJsonSchema(z.object(agent.context));
|
|
64
|
-
const result = await generateObject({
|
|
65
|
-
model: agent.model,
|
|
66
|
-
system: input.system ?? agent.description,
|
|
67
|
-
prompt: `
|
|
68
|
-
<goal>
|
|
69
|
-
${input.goal}
|
|
70
|
-
</goal>
|
|
71
|
-
<contextSchema>
|
|
72
|
-
${contextSchema}
|
|
73
|
-
</contextSchema>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
Update the context JSON schema so that it validates the context to determine that it reaches the goal. Return the result as a diff.
|
|
77
|
-
|
|
78
|
-
The contextSchema properties must not change. Do not add or remove properties, or modify the name of the properties.
|
|
79
|
-
Use "const" for exact required values and define ranges/types for flexible conditions.
|
|
80
|
-
|
|
81
|
-
Examples:
|
|
82
|
-
1. For "user is logged in with admin role":
|
|
83
|
-
{
|
|
84
|
-
"contextSchema": "{"type": "object", "properties": {"role": {"const": "admin"}, "lastLogin": {"type": "string"}}, "required": ["role"]}"
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
2. For "score is above 100":
|
|
88
|
-
{
|
|
89
|
-
"contextSchema": "{"type": "object", "properties": {"score": {"type": "number", "minimum": 100}}, "required": ["score"]}"
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
3. For "fruits contain apple, orange, banana":
|
|
93
|
-
{
|
|
94
|
-
"type": "array",
|
|
95
|
-
"allOf": [
|
|
96
|
-
{ "contains": { "const": "apple" } },
|
|
97
|
-
{ "contains": { "const": "orange" } },
|
|
98
|
-
{ "contains": { "const": "banana" } }
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
`.trim(),
|
|
102
|
-
schema: z.object({
|
|
103
|
-
// valueSchema: z
|
|
104
|
-
// .string()
|
|
105
|
-
// .describe('The JSON Schema representing the goal state value'),
|
|
106
|
-
contextSchema: z
|
|
107
|
-
.object({
|
|
108
|
-
type: z.literal('object'),
|
|
109
|
-
properties: z.object(
|
|
110
|
-
Object.keys((contextSchema as any).properties).reduce(
|
|
111
|
-
(acc, key) => {
|
|
112
|
-
acc[key] = z.any();
|
|
113
|
-
return acc;
|
|
114
|
-
},
|
|
115
|
-
{} as any
|
|
116
|
-
)
|
|
117
|
-
),
|
|
118
|
-
required: z.array(z.string()).optional(),
|
|
119
|
-
})
|
|
120
|
-
.describe('The JSON Schema representing the goal state context'),
|
|
121
|
-
}),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
console.log(result.object);
|
|
125
|
-
const validateContext = ajv.compile(result.object.contextSchema);
|
|
126
|
-
|
|
127
|
-
const stateFilter = (state: AnyMachineSnapshot) => {
|
|
128
|
-
return validateContext(state.context);
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const resolvedState = input.machine.resolveState({
|
|
132
|
-
...input.state,
|
|
133
|
-
context: input.state.context ?? {},
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
paths = getShortestPaths(input.machine, {
|
|
137
|
-
fromState: resolvedState,
|
|
138
|
-
toState: stateFilter,
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (!paths) {
|
|
143
|
-
return undefined;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const trimmedPaths = paths
|
|
147
|
-
.map((path) => {
|
|
148
|
-
const trimmedSteps = trimSteps(path.steps, input.state);
|
|
149
|
-
if (!trimmedSteps) {
|
|
150
|
-
return undefined;
|
|
151
|
-
}
|
|
152
|
-
return {
|
|
153
|
-
...path,
|
|
154
|
-
steps: trimmedSteps,
|
|
155
|
-
};
|
|
156
|
-
})
|
|
157
|
-
.filter((p): p is NonNullable<typeof p> => p !== undefined);
|
|
158
|
-
|
|
159
|
-
// Sort paths from least weight to most weight
|
|
160
|
-
const sortedPaths = trimmedPaths.sort(
|
|
161
|
-
(a, b) => costFunction(a) - costFunction(b)
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
const leastWeightPath = sortedPaths[0];
|
|
165
|
-
const nextStep = leastWeightPath?.steps[0];
|
|
166
|
-
|
|
167
|
-
return {
|
|
168
|
-
planner: 'shortestPath',
|
|
169
|
-
episodeId: agent.episodeId,
|
|
170
|
-
goal: input.goal,
|
|
171
|
-
goalState: paths[0]?.state,
|
|
172
|
-
nextEvent: nextStep?.event,
|
|
173
|
-
paths,
|
|
174
|
-
timestamp: Date.now(),
|
|
175
|
-
};
|
|
176
|
-
};
|
|
177
|
-
}
|