@statelyai/agent 1.0.0 → 1.1.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/.github/actions/ci-setup/action.yml +11 -11
- package/.github/workflows/release.yml +17 -5
- package/CHANGELOG.md +91 -0
- package/dist/index.d.mts +30 -11
- package/dist/index.d.ts +30 -11
- package/dist/index.js +37 -16
- package/dist/index.mjs +38 -18
- package/package.json +19 -21
- package/readme.md +1 -4
- package/src/agent.test.ts +149 -2
- package/src/agent.ts +14 -11
- package/src/decision.ts +2 -2
- package/src/planners/simplePlanner.ts +1 -2
- package/src/text.ts +27 -10
- package/src/types.ts +32 -10
- package/.changeset/heavy-moons-bake.md +0 -12
- package/.changeset/shaggy-buttons-itch.md +0 -5
- package/.changeset/silly-berries-drop.md +0 -5
- package/.changeset/wild-bobcats-care.md +0 -26
|
@@ -7,18 +7,18 @@ runs:
|
|
|
7
7
|
- uses: actions/setup-node@v4
|
|
8
8
|
with:
|
|
9
9
|
node-version: 20.x
|
|
10
|
+
|
|
11
|
+
- name: install pnpm
|
|
12
|
+
run: npm i pnpm@latest -g
|
|
13
|
+
shell: bash
|
|
10
14
|
|
|
11
|
-
- name:
|
|
15
|
+
- name: Setup npmrc
|
|
16
|
+
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
|
|
12
17
|
shell: bash
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
with:
|
|
19
|
-
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
|
20
|
-
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
21
|
-
restore-keys: |
|
|
22
|
-
${{ runner.os }}-pnpm-store-
|
|
18
|
+
|
|
19
|
+
- name: setup pnpm config
|
|
20
|
+
run: pnpm config set store-dir $PNPM_CACHE_FOLDER
|
|
21
|
+
shell: bash
|
|
22
|
+
|
|
23
23
|
- run: pnpm install
|
|
24
24
|
shell: bash
|
|
@@ -22,14 +22,26 @@ jobs:
|
|
|
22
22
|
runs-on: ubuntu-latest
|
|
23
23
|
|
|
24
24
|
steps:
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
- name: checkout code repository
|
|
26
|
+
uses: actions/checkout@v3
|
|
27
|
+
with:
|
|
28
|
+
fetch-depth: 0
|
|
29
|
+
- name: setup node.js
|
|
30
|
+
uses: actions/setup-node@v3
|
|
31
|
+
with:
|
|
32
|
+
node-version: 20
|
|
33
|
+
- name: install pnpm
|
|
34
|
+
run: npm i pnpm@latest -g
|
|
35
|
+
- name: Setup npmrc
|
|
36
|
+
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
|
|
37
|
+
- name: setup pnpm config
|
|
38
|
+
run: pnpm config set store-dir $PNPM_CACHE_FOLDER
|
|
39
|
+
- name: install dependencies
|
|
40
|
+
run: pnpm install
|
|
41
|
+
- name: create and publish versions
|
|
29
42
|
uses: changesets/action@v1
|
|
30
43
|
with:
|
|
31
44
|
publish: pnpm run release
|
|
32
45
|
version: pnpm run version
|
|
33
46
|
env:
|
|
34
47
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
35
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,96 @@
|
|
|
1
1
|
# @statelyai/agent
|
|
2
2
|
|
|
3
|
+
## 1.1.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#45](https://github.com/statelyai/agent/pull/45) [`3c271f3`](https://github.com/statelyai/agent/commit/3c271f306c4ed9553c155e66cec8aa4284e9c813) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Fix reading the actor logic
|
|
8
|
+
|
|
9
|
+
## 1.1.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#43](https://github.com/statelyai/agent/pull/43) [`8e7629c`](https://github.com/statelyai/agent/commit/8e7629c347b29b704ae9576aa1af97e6cd693bc7) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Update dependencies
|
|
14
|
+
|
|
15
|
+
## 1.1.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [#41](https://github.com/statelyai/agent/pull/41) [`b2f2b73`](https://github.com/statelyai/agent/commit/b2f2b7307e96d7722968769aae9db2572ede8ce7) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Update dependencies
|
|
20
|
+
|
|
21
|
+
## 1.1.0
|
|
22
|
+
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- [#39](https://github.com/statelyai/agent/pull/39) [`3cce30f`](https://github.com/statelyai/agent/commit/3cce30fc77d36dbed0abad805248de9f64bf8086) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Added four new methods for easily retrieving agent messages, observations, feedback, and plans:
|
|
26
|
+
|
|
27
|
+
- `agent.getMessages()`
|
|
28
|
+
- `agent.getObservations()`
|
|
29
|
+
- `agent.getFeedback()`
|
|
30
|
+
- `agent.getPlans()`
|
|
31
|
+
|
|
32
|
+
The `agent.select(…)` method is deprecated in favor of these methods.
|
|
33
|
+
|
|
34
|
+
- [#40](https://github.com/statelyai/agent/pull/40) [`8b7c374`](https://github.com/statelyai/agent/commit/8b7c37482d5c35b2b3addc2f88e198526f203da7) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Correlation IDs are now provided as part of the result from `agent.generateText(…)` and `agent.streamText(…)`:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const result = await agent.generateText({
|
|
38
|
+
prompt: "Write me a song",
|
|
39
|
+
correlationId: "my-correlation-id",
|
|
40
|
+
// ...
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
result.correlationId; // 'my-correlation-id'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
These correlation IDs can be passed to feedback:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// ...
|
|
50
|
+
|
|
51
|
+
agent.addFeedback({
|
|
52
|
+
reward: -1,
|
|
53
|
+
correlationId: result.correlationId,
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- [#40](https://github.com/statelyai/agent/pull/40) [`8b7c374`](https://github.com/statelyai/agent/commit/8b7c37482d5c35b2b3addc2f88e198526f203da7) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Changes to agent feedback (the `AgentFeedback` interface):
|
|
58
|
+
|
|
59
|
+
- `goal` is now optional
|
|
60
|
+
- `observationId` is now optional
|
|
61
|
+
- `correlationId` has been added (optional)
|
|
62
|
+
- `reward` has been added (optional)
|
|
63
|
+
- `attributes` are now optional
|
|
64
|
+
|
|
65
|
+
- [#38](https://github.com/statelyai/agent/pull/38) [`21fb17c`](https://github.com/statelyai/agent/commit/21fb17c65fac1cbb4a8b08a04a58480a6930a0a9) Thanks [@davidkpiano](https://github.com/davidkpiano)! - You can now add `context` Zod schema to your agent. For now, this is meant to be passed directly to the state machine, but in the future, the schema can be shared with the LLM agent to better understand the state machine and its context for decision making.
|
|
66
|
+
|
|
67
|
+
Breaking: The `context` and `events` types are now in `agent.types` instead of ~~`agent.eventTypes`.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const agent = createAgent({
|
|
71
|
+
// ...
|
|
72
|
+
context: {
|
|
73
|
+
score: z.number().describe("The score of the game"),
|
|
74
|
+
// ...
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const machine = setup({
|
|
79
|
+
types: agent.types,
|
|
80
|
+
}).createMachine({
|
|
81
|
+
context: {
|
|
82
|
+
score: 0,
|
|
83
|
+
},
|
|
84
|
+
// ...
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Patch Changes
|
|
89
|
+
|
|
90
|
+
- [`5f863bb`](https://github.com/statelyai/agent/commit/5f863bb0d89d90f30d0a9aa1f0dd2a35f0eeb45b) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Use nanoid
|
|
91
|
+
|
|
92
|
+
- [#37](https://github.com/statelyai/agent/pull/37) [`dafa815`](https://github.com/statelyai/agent/commit/dafa8157cc1b5adbfb222c146dbc84ab2eed8894) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Messages are now properly included in `agent.decide(…)`, when specified.
|
|
93
|
+
|
|
3
94
|
## 0.1.0
|
|
4
95
|
|
|
5
96
|
### Minor Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -97,17 +97,24 @@ type AgentDecideOptions = {
|
|
|
97
97
|
events?: ZodEventMapping;
|
|
98
98
|
} & Omit<Parameters<typeof generateText>[0], 'model' | 'tools' | 'prompt' | 'messages'>;
|
|
99
99
|
interface AgentFeedback {
|
|
100
|
-
goal
|
|
101
|
-
observationId
|
|
100
|
+
goal?: string;
|
|
101
|
+
observationId?: string;
|
|
102
|
+
/**
|
|
103
|
+
* The message correlation that the feedback is relevant for
|
|
104
|
+
*/
|
|
105
|
+
correlationId?: string;
|
|
102
106
|
attributes: Record<string, any>;
|
|
107
|
+
reward: number;
|
|
103
108
|
timestamp: number;
|
|
104
109
|
sessionId: string;
|
|
105
110
|
}
|
|
106
111
|
interface AgentFeedbackInput {
|
|
107
|
-
goal
|
|
108
|
-
observationId
|
|
109
|
-
|
|
112
|
+
goal?: string;
|
|
113
|
+
observationId?: string;
|
|
114
|
+
correlationId?: string;
|
|
115
|
+
attributes?: Record<string, any>;
|
|
110
116
|
timestamp?: number;
|
|
117
|
+
reward?: number;
|
|
111
118
|
}
|
|
112
119
|
type AgentMessage = CoreMessage & {
|
|
113
120
|
timestamp: number;
|
|
@@ -119,6 +126,8 @@ type AgentMessage = CoreMessage & {
|
|
|
119
126
|
responseId?: string;
|
|
120
127
|
result?: GenerateTextResult<any>;
|
|
121
128
|
sessionId: string;
|
|
129
|
+
correlationId: string;
|
|
130
|
+
parentCorrelationId?: string;
|
|
122
131
|
};
|
|
123
132
|
type AgentMessageInput = CoreMessage & {
|
|
124
133
|
timestamp?: number;
|
|
@@ -128,6 +137,8 @@ type AgentMessageInput = CoreMessage & {
|
|
|
128
137
|
* which message this message is responding to, if any.
|
|
129
138
|
*/
|
|
130
139
|
responseId?: string;
|
|
140
|
+
correlationId?: string;
|
|
141
|
+
parentCorrelationId?: string;
|
|
131
142
|
result?: GenerateTextResult<any>;
|
|
132
143
|
};
|
|
133
144
|
interface AgentObservation<TActor extends AnyActorRef> {
|
|
@@ -223,8 +234,8 @@ type Agent<TContext, TEvents extends EventObject> = ActorRefFrom<AgentLogic<TEve
|
|
|
223
234
|
* - Additional `context`
|
|
224
235
|
*/
|
|
225
236
|
decide: (options: AgentDecideOptions) => Promise<AgentPlan<TEvents> | undefined>;
|
|
226
|
-
generateText: (options: AgentGenerateTextOptions) => Promise<
|
|
227
|
-
streamText: (options: AgentStreamTextOptions) => Promise<
|
|
237
|
+
generateText: (options: AgentGenerateTextOptions) => Promise<AgentGenerateTextResult>;
|
|
238
|
+
streamText: (options: AgentStreamTextOptions) => Promise<AgentStreamTextResult>;
|
|
228
239
|
addObservation: (observationInput: AgentObservationInput) => AgentObservation<any>;
|
|
229
240
|
addMessage: (messageInput: AgentMessageInput) => AgentMessage;
|
|
230
241
|
addFeedback: (feedbackInput: AgentFeedbackInput) => AgentFeedback;
|
|
@@ -306,16 +317,24 @@ type Agent<TContext, TEvents extends EventObject> = ActorRefFrom<AgentLogic<TEve
|
|
|
306
317
|
interact<TActor extends AnyActorRef>(actorRef: TActor, getInput: (observation: AgentObservation<TActor>) => AgentDecisionInput | undefined): Subscription;
|
|
307
318
|
};
|
|
308
319
|
type AnyAgent = Agent<any, any>;
|
|
309
|
-
type FromAgent<T> = T | ((
|
|
310
|
-
|
|
320
|
+
type FromAgent<T> = T | ((agent: AnyAgent) => T | Promise<T>);
|
|
321
|
+
type CommonTextOptions = {
|
|
311
322
|
prompt: FromAgent<string>;
|
|
312
323
|
model?: LanguageModel;
|
|
313
324
|
context?: Record<string, any>;
|
|
314
325
|
messages?: FromAgent<CoreMessage[]>;
|
|
315
326
|
template?: PromptTemplate<any>;
|
|
316
|
-
|
|
327
|
+
correlationId?: string;
|
|
328
|
+
parentCorrelationId?: string;
|
|
329
|
+
};
|
|
330
|
+
type TextResultMeta = {
|
|
331
|
+
correlationId: string;
|
|
332
|
+
parentCorrelationId?: string;
|
|
333
|
+
};
|
|
317
334
|
type AgentGenerateTextOptions = Omit<GenerateTextOptions, 'model' | 'prompt' | 'messages'> & CommonTextOptions;
|
|
335
|
+
type AgentGenerateTextResult = GenerateTextResult<any> & TextResultMeta;
|
|
318
336
|
type AgentStreamTextOptions = Omit<StreamTextOptions, 'model' | 'prompt' | 'messages'> & CommonTextOptions;
|
|
337
|
+
type AgentStreamTextResult = StreamTextResult<any> & TextResultMeta;
|
|
319
338
|
interface ObservedState {
|
|
320
339
|
/**
|
|
321
340
|
* The current state value of the state machine, e.g.
|
|
@@ -406,4 +425,4 @@ declare function fromText<T extends AnyAgent>(agent: T, defaultOptions?: AgentGe
|
|
|
406
425
|
|
|
407
426
|
declare function fromDecision(agent: AnyAgent, defaultInput?: AgentDecisionInput): AgentDecisionLogic<any>;
|
|
408
427
|
|
|
409
|
-
export { type AIAdapter, type Agent, type AgentDecideOptions, type AgentDecisionInput, type AgentDecisionLogic, type AgentEmitted, type AgentFeedback, type AgentFeedbackInput, type AgentGenerateTextOptions, type AgentLogic, type AgentLongTermMemory, type AgentMemory, type AgentMemoryContext, type AgentMessage, type AgentMessageInput, type AgentObservation, type AgentObservationInput, type AgentPlan, type AgentPlanInput, type AgentPlanner, type AgentStreamTextOptions, type AnyAgent, type AppendOnlyStorage, type CommonTextOptions, type Compute, type ContextFromZodContextMapping, type EventsFromZodEventMapping, type FromAgent, type GenerateTextOptions, type ObservedState, type ObservedStateFrom, type PromptTemplate, type StreamTextOptions, type TransitionData, createAgent, fromDecision, fromText, fromTextStream };
|
|
428
|
+
export { type AIAdapter, type Agent, type AgentDecideOptions, type AgentDecisionInput, type AgentDecisionLogic, type AgentEmitted, type AgentFeedback, type AgentFeedbackInput, type AgentGenerateTextOptions, type AgentGenerateTextResult, type AgentLogic, type AgentLongTermMemory, type AgentMemory, type AgentMemoryContext, type AgentMessage, type AgentMessageInput, type AgentObservation, type AgentObservationInput, type AgentPlan, type AgentPlanInput, type AgentPlanner, type AgentStreamTextOptions, type AgentStreamTextResult, type AnyAgent, type AppendOnlyStorage, type CommonTextOptions, type Compute, type ContextFromZodContextMapping, type EventsFromZodEventMapping, type FromAgent, type GenerateTextOptions, type ObservedState, type ObservedStateFrom, type PromptTemplate, type StreamTextOptions, type TextResultMeta, type TransitionData, createAgent, fromDecision, fromText, fromTextStream };
|
package/dist/index.d.ts
CHANGED
|
@@ -97,17 +97,24 @@ type AgentDecideOptions = {
|
|
|
97
97
|
events?: ZodEventMapping;
|
|
98
98
|
} & Omit<Parameters<typeof generateText>[0], 'model' | 'tools' | 'prompt' | 'messages'>;
|
|
99
99
|
interface AgentFeedback {
|
|
100
|
-
goal
|
|
101
|
-
observationId
|
|
100
|
+
goal?: string;
|
|
101
|
+
observationId?: string;
|
|
102
|
+
/**
|
|
103
|
+
* The message correlation that the feedback is relevant for
|
|
104
|
+
*/
|
|
105
|
+
correlationId?: string;
|
|
102
106
|
attributes: Record<string, any>;
|
|
107
|
+
reward: number;
|
|
103
108
|
timestamp: number;
|
|
104
109
|
sessionId: string;
|
|
105
110
|
}
|
|
106
111
|
interface AgentFeedbackInput {
|
|
107
|
-
goal
|
|
108
|
-
observationId
|
|
109
|
-
|
|
112
|
+
goal?: string;
|
|
113
|
+
observationId?: string;
|
|
114
|
+
correlationId?: string;
|
|
115
|
+
attributes?: Record<string, any>;
|
|
110
116
|
timestamp?: number;
|
|
117
|
+
reward?: number;
|
|
111
118
|
}
|
|
112
119
|
type AgentMessage = CoreMessage & {
|
|
113
120
|
timestamp: number;
|
|
@@ -119,6 +126,8 @@ type AgentMessage = CoreMessage & {
|
|
|
119
126
|
responseId?: string;
|
|
120
127
|
result?: GenerateTextResult<any>;
|
|
121
128
|
sessionId: string;
|
|
129
|
+
correlationId: string;
|
|
130
|
+
parentCorrelationId?: string;
|
|
122
131
|
};
|
|
123
132
|
type AgentMessageInput = CoreMessage & {
|
|
124
133
|
timestamp?: number;
|
|
@@ -128,6 +137,8 @@ type AgentMessageInput = CoreMessage & {
|
|
|
128
137
|
* which message this message is responding to, if any.
|
|
129
138
|
*/
|
|
130
139
|
responseId?: string;
|
|
140
|
+
correlationId?: string;
|
|
141
|
+
parentCorrelationId?: string;
|
|
131
142
|
result?: GenerateTextResult<any>;
|
|
132
143
|
};
|
|
133
144
|
interface AgentObservation<TActor extends AnyActorRef> {
|
|
@@ -223,8 +234,8 @@ type Agent<TContext, TEvents extends EventObject> = ActorRefFrom<AgentLogic<TEve
|
|
|
223
234
|
* - Additional `context`
|
|
224
235
|
*/
|
|
225
236
|
decide: (options: AgentDecideOptions) => Promise<AgentPlan<TEvents> | undefined>;
|
|
226
|
-
generateText: (options: AgentGenerateTextOptions) => Promise<
|
|
227
|
-
streamText: (options: AgentStreamTextOptions) => Promise<
|
|
237
|
+
generateText: (options: AgentGenerateTextOptions) => Promise<AgentGenerateTextResult>;
|
|
238
|
+
streamText: (options: AgentStreamTextOptions) => Promise<AgentStreamTextResult>;
|
|
228
239
|
addObservation: (observationInput: AgentObservationInput) => AgentObservation<any>;
|
|
229
240
|
addMessage: (messageInput: AgentMessageInput) => AgentMessage;
|
|
230
241
|
addFeedback: (feedbackInput: AgentFeedbackInput) => AgentFeedback;
|
|
@@ -306,16 +317,24 @@ type Agent<TContext, TEvents extends EventObject> = ActorRefFrom<AgentLogic<TEve
|
|
|
306
317
|
interact<TActor extends AnyActorRef>(actorRef: TActor, getInput: (observation: AgentObservation<TActor>) => AgentDecisionInput | undefined): Subscription;
|
|
307
318
|
};
|
|
308
319
|
type AnyAgent = Agent<any, any>;
|
|
309
|
-
type FromAgent<T> = T | ((
|
|
310
|
-
|
|
320
|
+
type FromAgent<T> = T | ((agent: AnyAgent) => T | Promise<T>);
|
|
321
|
+
type CommonTextOptions = {
|
|
311
322
|
prompt: FromAgent<string>;
|
|
312
323
|
model?: LanguageModel;
|
|
313
324
|
context?: Record<string, any>;
|
|
314
325
|
messages?: FromAgent<CoreMessage[]>;
|
|
315
326
|
template?: PromptTemplate<any>;
|
|
316
|
-
|
|
327
|
+
correlationId?: string;
|
|
328
|
+
parentCorrelationId?: string;
|
|
329
|
+
};
|
|
330
|
+
type TextResultMeta = {
|
|
331
|
+
correlationId: string;
|
|
332
|
+
parentCorrelationId?: string;
|
|
333
|
+
};
|
|
317
334
|
type AgentGenerateTextOptions = Omit<GenerateTextOptions, 'model' | 'prompt' | 'messages'> & CommonTextOptions;
|
|
335
|
+
type AgentGenerateTextResult = GenerateTextResult<any> & TextResultMeta;
|
|
318
336
|
type AgentStreamTextOptions = Omit<StreamTextOptions, 'model' | 'prompt' | 'messages'> & CommonTextOptions;
|
|
337
|
+
type AgentStreamTextResult = StreamTextResult<any> & TextResultMeta;
|
|
319
338
|
interface ObservedState {
|
|
320
339
|
/**
|
|
321
340
|
* The current state value of the state machine, e.g.
|
|
@@ -406,4 +425,4 @@ declare function fromText<T extends AnyAgent>(agent: T, defaultOptions?: AgentGe
|
|
|
406
425
|
|
|
407
426
|
declare function fromDecision(agent: AnyAgent, defaultInput?: AgentDecisionInput): AgentDecisionLogic<any>;
|
|
408
427
|
|
|
409
|
-
export { type AIAdapter, type Agent, type AgentDecideOptions, type AgentDecisionInput, type AgentDecisionLogic, type AgentEmitted, type AgentFeedback, type AgentFeedbackInput, type AgentGenerateTextOptions, type AgentLogic, type AgentLongTermMemory, type AgentMemory, type AgentMemoryContext, type AgentMessage, type AgentMessageInput, type AgentObservation, type AgentObservationInput, type AgentPlan, type AgentPlanInput, type AgentPlanner, type AgentStreamTextOptions, type AnyAgent, type AppendOnlyStorage, type CommonTextOptions, type Compute, type ContextFromZodContextMapping, type EventsFromZodEventMapping, type FromAgent, type GenerateTextOptions, type ObservedState, type ObservedStateFrom, type PromptTemplate, type StreamTextOptions, type TransitionData, createAgent, fromDecision, fromText, fromTextStream };
|
|
428
|
+
export { type AIAdapter, type Agent, type AgentDecideOptions, type AgentDecisionInput, type AgentDecisionLogic, type AgentEmitted, type AgentFeedback, type AgentFeedbackInput, type AgentGenerateTextOptions, type AgentGenerateTextResult, type AgentLogic, type AgentLongTermMemory, type AgentMemory, type AgentMemoryContext, type AgentMessage, type AgentMessageInput, type AgentObservation, type AgentObservationInput, type AgentPlan, type AgentPlanInput, type AgentPlanner, type AgentStreamTextOptions, type AgentStreamTextResult, type AnyAgent, type AppendOnlyStorage, type CommonTextOptions, type Compute, type ContextFromZodContextMapping, type EventsFromZodEventMapping, type FromAgent, type GenerateTextOptions, type ObservedState, type ObservedStateFrom, type PromptTemplate, type StreamTextOptions, type TextResultMeta, type TransitionData, createAgent, fromDecision, fromText, fromTextStream };
|
package/dist/index.js
CHANGED
|
@@ -123,7 +123,8 @@ async function getMessages(agent, prompt, options) {
|
|
|
123
123
|
async function agentGenerateText(agent, options) {
|
|
124
124
|
const resolvedOptions = {
|
|
125
125
|
...agent.defaultOptions,
|
|
126
|
-
...options
|
|
126
|
+
...options,
|
|
127
|
+
correlationId: options.correlationId ?? randomId()
|
|
127
128
|
};
|
|
128
129
|
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
129
130
|
const id = randomId();
|
|
@@ -137,7 +138,9 @@ async function agentGenerateText(agent, options) {
|
|
|
137
138
|
id,
|
|
138
139
|
role: "user",
|
|
139
140
|
content: promptWithContext,
|
|
140
|
-
timestamp: Date.now()
|
|
141
|
+
timestamp: Date.now(),
|
|
142
|
+
correlationId: resolvedOptions.correlationId,
|
|
143
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
141
144
|
});
|
|
142
145
|
const result = await agent.adapter.generateText({
|
|
143
146
|
...resolvedOptions,
|
|
@@ -150,14 +153,21 @@ async function agentGenerateText(agent, options) {
|
|
|
150
153
|
role: "assistant",
|
|
151
154
|
timestamp: Date.now(),
|
|
152
155
|
responseId: id,
|
|
153
|
-
result
|
|
156
|
+
result,
|
|
157
|
+
correlationId: resolvedOptions.correlationId,
|
|
158
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
154
159
|
});
|
|
155
|
-
return
|
|
160
|
+
return {
|
|
161
|
+
...result,
|
|
162
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
163
|
+
correlationId: resolvedOptions.correlationId
|
|
164
|
+
};
|
|
156
165
|
}
|
|
157
166
|
async function agentStreamText(agent, options) {
|
|
158
167
|
const resolvedOptions = {
|
|
159
168
|
...agent.defaultOptions,
|
|
160
|
-
...options
|
|
169
|
+
...options,
|
|
170
|
+
correlationId: options.correlationId ?? randomId()
|
|
161
171
|
};
|
|
162
172
|
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
163
173
|
const id = randomId();
|
|
@@ -171,7 +181,9 @@ async function agentStreamText(agent, options) {
|
|
|
171
181
|
role: "user",
|
|
172
182
|
content: promptWithContext,
|
|
173
183
|
id,
|
|
174
|
-
timestamp: Date.now()
|
|
184
|
+
timestamp: Date.now(),
|
|
185
|
+
correlationId: resolvedOptions.correlationId,
|
|
186
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
175
187
|
});
|
|
176
188
|
const result = await agent.adapter.streamText({
|
|
177
189
|
...resolvedOptions,
|
|
@@ -189,16 +201,24 @@ async function agentStreamText(agent, options) {
|
|
|
189
201
|
toolResults: [],
|
|
190
202
|
usage: res.usage,
|
|
191
203
|
warnings: res.warnings,
|
|
192
|
-
rawResponse: res.rawResponse
|
|
204
|
+
rawResponse: res.rawResponse,
|
|
205
|
+
roundtrips: []
|
|
206
|
+
// TODO: how do we get this information?
|
|
193
207
|
},
|
|
194
208
|
content: res.text,
|
|
195
209
|
id: randomId(),
|
|
196
210
|
timestamp: Date.now(),
|
|
197
|
-
responseId: id
|
|
211
|
+
responseId: id,
|
|
212
|
+
correlationId: resolvedOptions.correlationId,
|
|
213
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
198
214
|
});
|
|
199
215
|
}
|
|
200
216
|
});
|
|
201
|
-
return
|
|
217
|
+
return {
|
|
218
|
+
...result,
|
|
219
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
220
|
+
correlationId: resolvedOptions.correlationId
|
|
221
|
+
};
|
|
202
222
|
}
|
|
203
223
|
function fromTextStream(agent, defaultOptions) {
|
|
204
224
|
return (0, import_xstate.fromObservable)(({ input }) => {
|
|
@@ -309,7 +329,6 @@ async function simplePlanner(agent, input) {
|
|
|
309
329
|
});
|
|
310
330
|
const singleResult = result.toolResults[0];
|
|
311
331
|
if (!singleResult) {
|
|
312
|
-
console.log(toolMap);
|
|
313
332
|
console.warn("No tool call results returned");
|
|
314
333
|
return void 0;
|
|
315
334
|
}
|
|
@@ -379,7 +398,7 @@ function fromDecision(agent, defaultInput) {
|
|
|
379
398
|
context: contextToInclude
|
|
380
399
|
};
|
|
381
400
|
const plan = await agentDecide(agent, {
|
|
382
|
-
machine: parentRef.
|
|
401
|
+
machine: parentRef.logic,
|
|
383
402
|
state,
|
|
384
403
|
execute: async (event) => {
|
|
385
404
|
parentRef.send(event);
|
|
@@ -442,12 +461,12 @@ var agentLogic = (0, import_xstate3.fromTransition)(
|
|
|
442
461
|
}
|
|
443
462
|
return state;
|
|
444
463
|
},
|
|
445
|
-
{
|
|
464
|
+
() => ({
|
|
446
465
|
feedback: [],
|
|
447
466
|
messages: [],
|
|
448
467
|
observations: [],
|
|
449
468
|
plans: []
|
|
450
|
-
}
|
|
469
|
+
})
|
|
451
470
|
);
|
|
452
471
|
function createAgent({
|
|
453
472
|
name,
|
|
@@ -462,7 +481,6 @@ function createAgent({
|
|
|
462
481
|
adapter = vercelAdapter,
|
|
463
482
|
...generateTextOptions
|
|
464
483
|
}) {
|
|
465
|
-
const messageHistoryListeners = [];
|
|
466
484
|
const agent = (0, import_xstate3.createActor)(logic);
|
|
467
485
|
agent.events = events;
|
|
468
486
|
agent.model = model;
|
|
@@ -475,7 +493,7 @@ function createAgent({
|
|
|
475
493
|
};
|
|
476
494
|
agent.memory = getMemory ? getMemory(agent) : void 0;
|
|
477
495
|
agent.onMessage = (callback) => {
|
|
478
|
-
|
|
496
|
+
agent.on("message", (ev) => callback(ev.message));
|
|
479
497
|
};
|
|
480
498
|
agent.decide = (opts) => {
|
|
481
499
|
return agentDecide(agent, opts);
|
|
@@ -485,7 +503,8 @@ function createAgent({
|
|
|
485
503
|
...messageInput,
|
|
486
504
|
id: messageInput.id ?? randomId(),
|
|
487
505
|
timestamp: messageInput.timestamp ?? Date.now(),
|
|
488
|
-
sessionId: agent.sessionId
|
|
506
|
+
sessionId: agent.sessionId,
|
|
507
|
+
correlationId: messageInput.correlationId ?? randomId()
|
|
489
508
|
};
|
|
490
509
|
agent.send({
|
|
491
510
|
type: "agent.message",
|
|
@@ -499,6 +518,8 @@ function createAgent({
|
|
|
499
518
|
agent.addFeedback = (feedbackInput) => {
|
|
500
519
|
const feedback = {
|
|
501
520
|
...feedbackInput,
|
|
521
|
+
attributes: { ...feedbackInput.attributes },
|
|
522
|
+
reward: feedbackInput.reward ?? 0,
|
|
502
523
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
503
524
|
sessionId: agent.sessionId
|
|
504
525
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// src/agent.ts
|
|
2
2
|
import {
|
|
3
3
|
createActor,
|
|
4
|
-
fromTransition
|
|
5
|
-
toObserver as toObserver2
|
|
4
|
+
fromTransition
|
|
6
5
|
} from "xstate";
|
|
7
6
|
|
|
8
7
|
// src/planners/simplePlanner.ts
|
|
@@ -92,7 +91,8 @@ async function getMessages(agent, prompt, options) {
|
|
|
92
91
|
async function agentGenerateText(agent, options) {
|
|
93
92
|
const resolvedOptions = {
|
|
94
93
|
...agent.defaultOptions,
|
|
95
|
-
...options
|
|
94
|
+
...options,
|
|
95
|
+
correlationId: options.correlationId ?? randomId()
|
|
96
96
|
};
|
|
97
97
|
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
98
98
|
const id = randomId();
|
|
@@ -106,7 +106,9 @@ async function agentGenerateText(agent, options) {
|
|
|
106
106
|
id,
|
|
107
107
|
role: "user",
|
|
108
108
|
content: promptWithContext,
|
|
109
|
-
timestamp: Date.now()
|
|
109
|
+
timestamp: Date.now(),
|
|
110
|
+
correlationId: resolvedOptions.correlationId,
|
|
111
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
110
112
|
});
|
|
111
113
|
const result = await agent.adapter.generateText({
|
|
112
114
|
...resolvedOptions,
|
|
@@ -119,14 +121,21 @@ async function agentGenerateText(agent, options) {
|
|
|
119
121
|
role: "assistant",
|
|
120
122
|
timestamp: Date.now(),
|
|
121
123
|
responseId: id,
|
|
122
|
-
result
|
|
124
|
+
result,
|
|
125
|
+
correlationId: resolvedOptions.correlationId,
|
|
126
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
123
127
|
});
|
|
124
|
-
return
|
|
128
|
+
return {
|
|
129
|
+
...result,
|
|
130
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
131
|
+
correlationId: resolvedOptions.correlationId
|
|
132
|
+
};
|
|
125
133
|
}
|
|
126
134
|
async function agentStreamText(agent, options) {
|
|
127
135
|
const resolvedOptions = {
|
|
128
136
|
...agent.defaultOptions,
|
|
129
|
-
...options
|
|
137
|
+
...options,
|
|
138
|
+
correlationId: options.correlationId ?? randomId()
|
|
130
139
|
};
|
|
131
140
|
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
132
141
|
const id = randomId();
|
|
@@ -140,7 +149,9 @@ async function agentStreamText(agent, options) {
|
|
|
140
149
|
role: "user",
|
|
141
150
|
content: promptWithContext,
|
|
142
151
|
id,
|
|
143
|
-
timestamp: Date.now()
|
|
152
|
+
timestamp: Date.now(),
|
|
153
|
+
correlationId: resolvedOptions.correlationId,
|
|
154
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
144
155
|
});
|
|
145
156
|
const result = await agent.adapter.streamText({
|
|
146
157
|
...resolvedOptions,
|
|
@@ -158,16 +169,24 @@ async function agentStreamText(agent, options) {
|
|
|
158
169
|
toolResults: [],
|
|
159
170
|
usage: res.usage,
|
|
160
171
|
warnings: res.warnings,
|
|
161
|
-
rawResponse: res.rawResponse
|
|
172
|
+
rawResponse: res.rawResponse,
|
|
173
|
+
roundtrips: []
|
|
174
|
+
// TODO: how do we get this information?
|
|
162
175
|
},
|
|
163
176
|
content: res.text,
|
|
164
177
|
id: randomId(),
|
|
165
178
|
timestamp: Date.now(),
|
|
166
|
-
responseId: id
|
|
179
|
+
responseId: id,
|
|
180
|
+
correlationId: resolvedOptions.correlationId,
|
|
181
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId
|
|
167
182
|
});
|
|
168
183
|
}
|
|
169
184
|
});
|
|
170
|
-
return
|
|
185
|
+
return {
|
|
186
|
+
...result,
|
|
187
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
188
|
+
correlationId: resolvedOptions.correlationId
|
|
189
|
+
};
|
|
171
190
|
}
|
|
172
191
|
function fromTextStream(agent, defaultOptions) {
|
|
173
192
|
return fromObservable(({ input }) => {
|
|
@@ -278,7 +297,6 @@ async function simplePlanner(agent, input) {
|
|
|
278
297
|
});
|
|
279
298
|
const singleResult = result.toolResults[0];
|
|
280
299
|
if (!singleResult) {
|
|
281
|
-
console.log(toolMap);
|
|
282
300
|
console.warn("No tool call results returned");
|
|
283
301
|
return void 0;
|
|
284
302
|
}
|
|
@@ -348,7 +366,7 @@ function fromDecision(agent, defaultInput) {
|
|
|
348
366
|
context: contextToInclude
|
|
349
367
|
};
|
|
350
368
|
const plan = await agentDecide(agent, {
|
|
351
|
-
machine: parentRef.
|
|
369
|
+
machine: parentRef.logic,
|
|
352
370
|
state,
|
|
353
371
|
execute: async (event) => {
|
|
354
372
|
parentRef.send(event);
|
|
@@ -411,12 +429,12 @@ var agentLogic = fromTransition(
|
|
|
411
429
|
}
|
|
412
430
|
return state;
|
|
413
431
|
},
|
|
414
|
-
{
|
|
432
|
+
() => ({
|
|
415
433
|
feedback: [],
|
|
416
434
|
messages: [],
|
|
417
435
|
observations: [],
|
|
418
436
|
plans: []
|
|
419
|
-
}
|
|
437
|
+
})
|
|
420
438
|
);
|
|
421
439
|
function createAgent({
|
|
422
440
|
name,
|
|
@@ -431,7 +449,6 @@ function createAgent({
|
|
|
431
449
|
adapter = vercelAdapter,
|
|
432
450
|
...generateTextOptions
|
|
433
451
|
}) {
|
|
434
|
-
const messageHistoryListeners = [];
|
|
435
452
|
const agent = createActor(logic);
|
|
436
453
|
agent.events = events;
|
|
437
454
|
agent.model = model;
|
|
@@ -444,7 +461,7 @@ function createAgent({
|
|
|
444
461
|
};
|
|
445
462
|
agent.memory = getMemory ? getMemory(agent) : void 0;
|
|
446
463
|
agent.onMessage = (callback) => {
|
|
447
|
-
|
|
464
|
+
agent.on("message", (ev) => callback(ev.message));
|
|
448
465
|
};
|
|
449
466
|
agent.decide = (opts) => {
|
|
450
467
|
return agentDecide(agent, opts);
|
|
@@ -454,7 +471,8 @@ function createAgent({
|
|
|
454
471
|
...messageInput,
|
|
455
472
|
id: messageInput.id ?? randomId(),
|
|
456
473
|
timestamp: messageInput.timestamp ?? Date.now(),
|
|
457
|
-
sessionId: agent.sessionId
|
|
474
|
+
sessionId: agent.sessionId,
|
|
475
|
+
correlationId: messageInput.correlationId ?? randomId()
|
|
458
476
|
};
|
|
459
477
|
agent.send({
|
|
460
478
|
type: "agent.message",
|
|
@@ -468,6 +486,8 @@ function createAgent({
|
|
|
468
486
|
agent.addFeedback = (feedbackInput) => {
|
|
469
487
|
const feedback = {
|
|
470
488
|
...feedbackInput,
|
|
489
|
+
attributes: { ...feedbackInput.attributes },
|
|
490
|
+
reward: feedbackInput.reward ?? 0,
|
|
471
491
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
472
492
|
sessionId: agent.sessionId
|
|
473
493
|
};
|
package/package.json
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statelyai/agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Stateful agents that make decisions based on finite-state machine models",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"scripts": {
|
|
9
|
-
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
10
|
-
"lint": "tsc --noEmit",
|
|
11
|
-
"test": "vitest",
|
|
12
|
-
"test:ci": "vitest --run",
|
|
13
|
-
"example": "ts-node examples/helpers/runner.ts",
|
|
14
|
-
"prepublishOnly": "tsup src/index.ts --format cjs,esm --dts",
|
|
15
|
-
"changeset": "changeset",
|
|
16
|
-
"release": "changeset publish",
|
|
17
|
-
"version": "changeset version"
|
|
18
|
-
},
|
|
19
8
|
"keywords": [
|
|
20
9
|
"ai",
|
|
21
10
|
"state machine",
|
|
@@ -31,14 +20,14 @@
|
|
|
31
20
|
"@langchain/community": "^0.0.53",
|
|
32
21
|
"@langchain/core": "^0.1.63",
|
|
33
22
|
"@langchain/openai": "^0.0.28",
|
|
34
|
-
"@types/node": "^20.14.
|
|
23
|
+
"@types/node": "^20.14.13",
|
|
35
24
|
"@types/object-hash": "^3.0.6",
|
|
36
25
|
"dotenv": "^16.4.5",
|
|
37
26
|
"json-schema-to-ts": "^3.1.0",
|
|
38
27
|
"ts-node": "^10.9.2",
|
|
39
|
-
"tsup": "^8.
|
|
40
|
-
"typescript": "^5.5.
|
|
41
|
-
"vitest": "^
|
|
28
|
+
"tsup": "^8.2.3",
|
|
29
|
+
"typescript": "^5.5.4",
|
|
30
|
+
"vitest": "^2.0.4",
|
|
42
31
|
"wikipedia": "^2.1.2",
|
|
43
32
|
"zod": "^3.23.8"
|
|
44
33
|
},
|
|
@@ -46,11 +35,20 @@
|
|
|
46
35
|
"access": "public"
|
|
47
36
|
},
|
|
48
37
|
"dependencies": {
|
|
49
|
-
"@ai-sdk/openai": "^0.0.
|
|
38
|
+
"@ai-sdk/openai": "^0.0.40",
|
|
50
39
|
"@xstate/graph": "^2.0.0",
|
|
51
|
-
"ai": "^3.2.
|
|
40
|
+
"ai": "^3.2.40",
|
|
52
41
|
"object-hash": "^3.0.0",
|
|
53
|
-
"xstate": "^5.
|
|
42
|
+
"xstate": "^5.16.0"
|
|
54
43
|
},
|
|
55
|
-
"
|
|
56
|
-
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
46
|
+
"lint": "tsc --noEmit",
|
|
47
|
+
"test": "vitest",
|
|
48
|
+
"test:ci": "vitest --run",
|
|
49
|
+
"example": "ts-node examples/helpers/runner.ts",
|
|
50
|
+
"changeset": "changeset",
|
|
51
|
+
"release": "changeset publish",
|
|
52
|
+
"version": "changeset version"
|
|
53
|
+
}
|
|
54
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# Stately Agent
|
|
2
2
|
|
|
3
|
-
> [!WARNING]
|
|
4
|
-
> Alpha software! Not ready for production yet.
|
|
5
|
-
|
|
6
3
|
Stately Agent is a flexible framework for building AI agents using state machines. Stately agents go beyond normal LLM-based AI agents by:
|
|
7
4
|
|
|
8
5
|
- Using state machines to guide the agent's behavior, powered by [XState](https://stately.ai/docs/xstate)
|
|
@@ -10,4 +7,4 @@ Stately Agent is a flexible framework for building AI agents using state machine
|
|
|
10
7
|
- Enabling custom **planning** abilities for agents to achieve specific goals based on state machine logic, observations, and feedback
|
|
11
8
|
- Wrapping the [Vercel AI SDK](https://sdk.vercel.ai/) to easily support multiple model providers, such as OpenAI, Anthropic, Google, Mistral, Groq, Perplexity, and more
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
**Read the documentation: [stately.ai/docs/agents](https://stately.ai/docs/agents)**
|
package/src/agent.test.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { test, expect, vi } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AgentGenerateTextResult,
|
|
4
|
+
AgentMessage,
|
|
5
|
+
createAgent,
|
|
6
|
+
type AIAdapter,
|
|
7
|
+
} from './';
|
|
3
8
|
import { createActor, createMachine } from 'xstate';
|
|
4
9
|
import { GenerateTextResult } from 'ai';
|
|
5
10
|
import { z } from 'zod';
|
|
@@ -297,7 +302,7 @@ test('You can listen for plan events', async () => {
|
|
|
297
302
|
},
|
|
298
303
|
},
|
|
299
304
|
],
|
|
300
|
-
} as any as
|
|
305
|
+
} as any as AgentGenerateTextResult;
|
|
301
306
|
},
|
|
302
307
|
streamText: {} as any,
|
|
303
308
|
},
|
|
@@ -357,3 +362,145 @@ test('agent.types provides context and event types', () => {
|
|
|
357
362
|
// @ts-expect-error
|
|
358
363
|
agent.types.context satisfies { score: string };
|
|
359
364
|
});
|
|
365
|
+
|
|
366
|
+
test.each(['generateText', 'streamText'] as const)(
|
|
367
|
+
'can provide a correlation ID (%s)',
|
|
368
|
+
async (method) => {
|
|
369
|
+
const agent = createAgent({
|
|
370
|
+
model: {} as any,
|
|
371
|
+
events: {},
|
|
372
|
+
adapter: {
|
|
373
|
+
[method]: async (opts: any) => {
|
|
374
|
+
const res = {
|
|
375
|
+
text: 'response',
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
opts.onFinish?.(res);
|
|
379
|
+
|
|
380
|
+
return res as AgentGenerateTextResult;
|
|
381
|
+
},
|
|
382
|
+
} as any as AIAdapter,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
const promise = new Promise<AgentMessage>((res) => {
|
|
386
|
+
agent.onMessage((msg) => {
|
|
387
|
+
if (msg.role === 'assistant') {
|
|
388
|
+
res(msg);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
await agent[method]({
|
|
394
|
+
prompt: 'hi',
|
|
395
|
+
correlationId: 'c-1',
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
const msg = await promise;
|
|
399
|
+
|
|
400
|
+
expect(msg.correlationId).toBe('c-1');
|
|
401
|
+
expect(msg.parentCorrelationId).toBe(undefined);
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
test.each(['generateText', 'streamText'] as const)(
|
|
406
|
+
'correlation IDs are automatically generated if not provided (%s)',
|
|
407
|
+
async (method) => {
|
|
408
|
+
const agent = createAgent({
|
|
409
|
+
model: {} as any,
|
|
410
|
+
events: {},
|
|
411
|
+
adapter: {
|
|
412
|
+
[method]: async (opts: any) => {
|
|
413
|
+
const res = {
|
|
414
|
+
text: 'response',
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
opts.onFinish?.(res);
|
|
418
|
+
|
|
419
|
+
return res as AgentGenerateTextResult;
|
|
420
|
+
},
|
|
421
|
+
} as any as AIAdapter,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
await agent[method]({
|
|
425
|
+
prompt: 'hi',
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
const messages = agent.getMessages();
|
|
429
|
+
|
|
430
|
+
expect(messages[0]?.correlationId).toEqual(expect.stringMatching(/.+/));
|
|
431
|
+
expect(messages[0]?.role).toBe('user');
|
|
432
|
+
expect(messages[1]?.correlationId).toEqual(expect.stringMatching(/.+/));
|
|
433
|
+
expect(messages[1]?.role).toBe('assistant');
|
|
434
|
+
|
|
435
|
+
expect(messages[0]!.correlationId).toEqual(messages[1]!.correlationId);
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
test.each(['generateText', 'streamText'] as const)(
|
|
440
|
+
'can provide a parent correlation ID (%s)',
|
|
441
|
+
async (method) => {
|
|
442
|
+
const agent = createAgent({
|
|
443
|
+
model: {} as any,
|
|
444
|
+
events: {},
|
|
445
|
+
adapter: {
|
|
446
|
+
[method]: async (opts: any) => {
|
|
447
|
+
const res = {
|
|
448
|
+
text: 'response',
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
opts.onFinish?.(res);
|
|
452
|
+
|
|
453
|
+
return res as AgentGenerateTextResult;
|
|
454
|
+
},
|
|
455
|
+
} as any as AIAdapter,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
await agent[method]({
|
|
459
|
+
prompt: 'hi',
|
|
460
|
+
correlationId: 'c-1',
|
|
461
|
+
parentCorrelationId: 'c-0',
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
const msg = agent.getMessages().find((msg) => msg.role === 'assistant')!;
|
|
465
|
+
|
|
466
|
+
expect(msg.correlationId).toBe('c-1');
|
|
467
|
+
expect(msg.parentCorrelationId).toBe('c-0');
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
test.each(['generateText', 'streamText'] as const)(
|
|
472
|
+
'can add feedback to a correlation (%s)',
|
|
473
|
+
async (method) => {
|
|
474
|
+
const agent = createAgent({
|
|
475
|
+
name: 'test',
|
|
476
|
+
model: {} as any,
|
|
477
|
+
events: {},
|
|
478
|
+
adapter: {
|
|
479
|
+
[method]: async (opts: any) => {
|
|
480
|
+
const res = {
|
|
481
|
+
text: 'response',
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
opts.onFinish?.(res);
|
|
485
|
+
|
|
486
|
+
return res as AgentGenerateTextResult;
|
|
487
|
+
},
|
|
488
|
+
} as any as AIAdapter,
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
const res = await agent[method]({
|
|
492
|
+
prompt: 'test',
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
agent.addFeedback({
|
|
496
|
+
correlationId: res.correlationId,
|
|
497
|
+
reward: -1,
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
const message = agent.getMessages()[0]!;
|
|
501
|
+
const feedback = agent.getFeedback()[0]!;
|
|
502
|
+
|
|
503
|
+
expect(message.correlationId).toBeDefined();
|
|
504
|
+
expect(feedback.correlationId).toEqual(message.correlationId);
|
|
505
|
+
}
|
|
506
|
+
);
|
package/src/agent.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
AgentMemoryContext,
|
|
23
23
|
AgentObservation,
|
|
24
24
|
ContextFromZodContextMapping,
|
|
25
|
+
AgentFeedback,
|
|
25
26
|
} from './types';
|
|
26
27
|
import { simplePlanner } from './planners/simplePlanner';
|
|
27
28
|
import { agentGenerateText, agentStreamText } from './text';
|
|
@@ -73,12 +74,13 @@ export const agentLogic: AgentLogic<AnyEventObject> = fromTransition(
|
|
|
73
74
|
}
|
|
74
75
|
return state;
|
|
75
76
|
},
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
() =>
|
|
78
|
+
({
|
|
79
|
+
feedback: [],
|
|
80
|
+
messages: [],
|
|
81
|
+
observations: [],
|
|
82
|
+
plans: [],
|
|
83
|
+
} as AgentMemoryContext)
|
|
82
84
|
);
|
|
83
85
|
|
|
84
86
|
export function createAgent<
|
|
@@ -140,8 +142,6 @@ export function createAgent<
|
|
|
140
142
|
logic?: AgentLogic<TEvents>;
|
|
141
143
|
adapter?: AIAdapter;
|
|
142
144
|
} & GenerateTextOptions): Agent<TContext, TEvents> {
|
|
143
|
-
const messageHistoryListeners: Observer<AgentMessage>[] = [];
|
|
144
|
-
|
|
145
145
|
const agent = createActor(logic) as unknown as Agent<TContext, TEvents>;
|
|
146
146
|
agent.events = events;
|
|
147
147
|
agent.model = model;
|
|
@@ -155,7 +155,7 @@ export function createAgent<
|
|
|
155
155
|
agent.memory = getMemory ? getMemory(agent) : undefined;
|
|
156
156
|
|
|
157
157
|
agent.onMessage = (callback) => {
|
|
158
|
-
|
|
158
|
+
agent.on('message', (ev) => callback(ev.message));
|
|
159
159
|
};
|
|
160
160
|
|
|
161
161
|
agent.decide = (opts) => {
|
|
@@ -168,7 +168,8 @@ export function createAgent<
|
|
|
168
168
|
id: messageInput.id ?? randomId(),
|
|
169
169
|
timestamp: messageInput.timestamp ?? Date.now(),
|
|
170
170
|
sessionId: agent.sessionId,
|
|
171
|
-
|
|
171
|
+
correlationId: messageInput.correlationId ?? randomId(),
|
|
172
|
+
} satisfies AgentMessage;
|
|
172
173
|
agent.send({
|
|
173
174
|
type: 'agent.message',
|
|
174
175
|
message,
|
|
@@ -185,9 +186,11 @@ export function createAgent<
|
|
|
185
186
|
agent.addFeedback = (feedbackInput) => {
|
|
186
187
|
const feedback = {
|
|
187
188
|
...feedbackInput,
|
|
189
|
+
attributes: { ...feedbackInput.attributes },
|
|
190
|
+
reward: feedbackInput.reward ?? 0,
|
|
188
191
|
timestamp: feedbackInput.timestamp ?? Date.now(),
|
|
189
192
|
sessionId: agent.sessionId,
|
|
190
|
-
};
|
|
193
|
+
} satisfies AgentFeedback;
|
|
191
194
|
agent.send({
|
|
192
195
|
type: 'agent.feedback',
|
|
193
196
|
feedback,
|
package/src/decision.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyMachineSnapshot, fromPromise } from 'xstate';
|
|
1
|
+
import { AnyActor, AnyMachineSnapshot, fromPromise } from 'xstate';
|
|
2
2
|
import {
|
|
3
3
|
AnyAgent,
|
|
4
4
|
AgentDecideOptions,
|
|
@@ -71,7 +71,7 @@ export function fromDecision(
|
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
const plan = await agentDecide(agent, {
|
|
74
|
-
machine: parentRef
|
|
74
|
+
machine: (parentRef as AnyActor).logic,
|
|
75
75
|
state,
|
|
76
76
|
execute: async (event) => {
|
|
77
77
|
parentRef.send(event);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CoreTool, tool } from 'ai';
|
|
1
|
+
import { type CoreTool, tool } from 'ai';
|
|
2
2
|
import {
|
|
3
3
|
AgentPlan,
|
|
4
4
|
AgentPlanInput,
|
|
@@ -118,7 +118,6 @@ export async function simplePlanner<T extends AnyAgent>(
|
|
|
118
118
|
const singleResult = result.toolResults[0];
|
|
119
119
|
|
|
120
120
|
if (!singleResult) {
|
|
121
|
-
console.log(toolMap);
|
|
122
121
|
// TODO: retries?
|
|
123
122
|
console.warn('No tool call results returned');
|
|
124
123
|
return undefined;
|
package/src/text.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CoreMessage,
|
|
3
|
-
CoreTool,
|
|
4
|
-
GenerateTextResult,
|
|
5
|
-
StreamTextResult,
|
|
6
|
-
} from 'ai';
|
|
1
|
+
import type { CoreMessage, CoreTool, GenerateTextResult } from 'ai';
|
|
7
2
|
import {
|
|
8
3
|
AgentGenerateTextOptions,
|
|
4
|
+
AgentGenerateTextResult,
|
|
9
5
|
AgentStreamTextOptions,
|
|
6
|
+
AgentStreamTextResult,
|
|
10
7
|
AnyAgent,
|
|
11
8
|
} from './types';
|
|
12
9
|
import { defaultTextTemplate } from './templates/defaultText';
|
|
@@ -51,11 +48,13 @@ export async function getMessages(
|
|
|
51
48
|
export async function agentGenerateText<T extends AnyAgent>(
|
|
52
49
|
agent: T,
|
|
53
50
|
options: AgentGenerateTextOptions
|
|
54
|
-
) {
|
|
51
|
+
): Promise<AgentGenerateTextResult> {
|
|
55
52
|
const resolvedOptions = {
|
|
56
53
|
...agent.defaultOptions,
|
|
57
54
|
...options,
|
|
55
|
+
correlationId: options.correlationId ?? randomId(),
|
|
58
56
|
};
|
|
57
|
+
// Generate a correlation ID if one is not provided
|
|
59
58
|
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
60
59
|
// TODO: check if messages was provided instead
|
|
61
60
|
const id = randomId();
|
|
@@ -76,6 +75,8 @@ export async function agentGenerateText<T extends AnyAgent>(
|
|
|
76
75
|
role: 'user',
|
|
77
76
|
content: promptWithContext,
|
|
78
77
|
timestamp: Date.now(),
|
|
78
|
+
correlationId: resolvedOptions.correlationId,
|
|
79
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
79
80
|
});
|
|
80
81
|
|
|
81
82
|
const result = await agent.adapter.generateText({
|
|
@@ -91,18 +92,25 @@ export async function agentGenerateText<T extends AnyAgent>(
|
|
|
91
92
|
timestamp: Date.now(),
|
|
92
93
|
responseId: id,
|
|
93
94
|
result,
|
|
95
|
+
correlationId: resolvedOptions.correlationId,
|
|
96
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
94
97
|
});
|
|
95
98
|
|
|
96
|
-
return
|
|
99
|
+
return {
|
|
100
|
+
...result,
|
|
101
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
102
|
+
correlationId: resolvedOptions.correlationId,
|
|
103
|
+
};
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
export async function agentStreamText(
|
|
100
107
|
agent: AnyAgent,
|
|
101
108
|
options: AgentStreamTextOptions
|
|
102
|
-
): Promise<
|
|
109
|
+
): Promise<AgentStreamTextResult> {
|
|
103
110
|
const resolvedOptions = {
|
|
104
111
|
...agent.defaultOptions,
|
|
105
112
|
...options,
|
|
113
|
+
correlationId: options.correlationId ?? randomId(),
|
|
106
114
|
};
|
|
107
115
|
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
108
116
|
|
|
@@ -124,6 +132,8 @@ export async function agentStreamText(
|
|
|
124
132
|
content: promptWithContext,
|
|
125
133
|
id,
|
|
126
134
|
timestamp: Date.now(),
|
|
135
|
+
correlationId: resolvedOptions.correlationId,
|
|
136
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
127
137
|
});
|
|
128
138
|
|
|
129
139
|
const result = await agent.adapter.streamText({
|
|
@@ -143,16 +153,23 @@ export async function agentStreamText(
|
|
|
143
153
|
usage: res.usage,
|
|
144
154
|
warnings: res.warnings,
|
|
145
155
|
rawResponse: res.rawResponse,
|
|
156
|
+
roundtrips: [], // TODO: how do we get this information?
|
|
146
157
|
},
|
|
147
158
|
content: res.text,
|
|
148
159
|
id: randomId(),
|
|
149
160
|
timestamp: Date.now(),
|
|
150
161
|
responseId: id,
|
|
162
|
+
correlationId: resolvedOptions.correlationId,
|
|
163
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
151
164
|
});
|
|
152
165
|
},
|
|
153
166
|
});
|
|
154
167
|
|
|
155
|
-
return
|
|
168
|
+
return {
|
|
169
|
+
...result,
|
|
170
|
+
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
171
|
+
correlationId: resolvedOptions.correlationId,
|
|
172
|
+
} as unknown as AgentStreamTextResult; // TODO: fix
|
|
156
173
|
}
|
|
157
174
|
|
|
158
175
|
export function fromTextStream<T extends AnyAgent>(
|
package/src/types.ts
CHANGED
|
@@ -128,18 +128,25 @@ export type AgentDecideOptions = {
|
|
|
128
128
|
>;
|
|
129
129
|
|
|
130
130
|
export interface AgentFeedback {
|
|
131
|
-
goal
|
|
132
|
-
observationId
|
|
131
|
+
goal?: string;
|
|
132
|
+
observationId?: string;
|
|
133
|
+
/**
|
|
134
|
+
* The message correlation that the feedback is relevant for
|
|
135
|
+
*/
|
|
136
|
+
correlationId?: string;
|
|
133
137
|
attributes: Record<string, any>;
|
|
138
|
+
reward: number;
|
|
134
139
|
timestamp: number;
|
|
135
140
|
sessionId: string;
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
export interface AgentFeedbackInput {
|
|
139
|
-
goal
|
|
140
|
-
observationId
|
|
141
|
-
|
|
144
|
+
goal?: string;
|
|
145
|
+
observationId?: string;
|
|
146
|
+
correlationId?: string;
|
|
147
|
+
attributes?: Record<string, any>;
|
|
142
148
|
timestamp?: number;
|
|
149
|
+
reward?: number;
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
export type AgentMessage = CoreMessage & {
|
|
@@ -152,6 +159,8 @@ export type AgentMessage = CoreMessage & {
|
|
|
152
159
|
responseId?: string;
|
|
153
160
|
result?: GenerateTextResult<any>;
|
|
154
161
|
sessionId: string;
|
|
162
|
+
correlationId: string;
|
|
163
|
+
parentCorrelationId?: string;
|
|
155
164
|
};
|
|
156
165
|
|
|
157
166
|
export type AgentMessageInput = CoreMessage & {
|
|
@@ -162,6 +171,8 @@ export type AgentMessageInput = CoreMessage & {
|
|
|
162
171
|
* which message this message is responding to, if any.
|
|
163
172
|
*/
|
|
164
173
|
responseId?: string;
|
|
174
|
+
correlationId?: string;
|
|
175
|
+
parentCorrelationId?: string;
|
|
165
176
|
result?: GenerateTextResult<any>;
|
|
166
177
|
};
|
|
167
178
|
|
|
@@ -293,12 +304,12 @@ export type Agent<TContext, TEvents extends EventObject> = ActorRefFrom<
|
|
|
293
304
|
// Generate text
|
|
294
305
|
generateText: (
|
|
295
306
|
options: AgentGenerateTextOptions
|
|
296
|
-
) => Promise<
|
|
307
|
+
) => Promise<AgentGenerateTextResult>;
|
|
297
308
|
|
|
298
309
|
// Stream text
|
|
299
310
|
streamText: (
|
|
300
311
|
options: AgentStreamTextOptions
|
|
301
|
-
) => Promise<
|
|
312
|
+
) => Promise<AgentStreamTextResult>;
|
|
302
313
|
|
|
303
314
|
addObservation: (
|
|
304
315
|
observationInput: AgentObservationInput
|
|
@@ -395,15 +406,22 @@ export type Agent<TContext, TEvents extends EventObject> = ActorRefFrom<
|
|
|
395
406
|
|
|
396
407
|
export type AnyAgent = Agent<any, any>;
|
|
397
408
|
|
|
398
|
-
export type FromAgent<T> = T | ((
|
|
409
|
+
export type FromAgent<T> = T | ((agent: AnyAgent) => T | Promise<T>);
|
|
399
410
|
|
|
400
|
-
export
|
|
411
|
+
export type CommonTextOptions = {
|
|
401
412
|
prompt: FromAgent<string>;
|
|
402
413
|
model?: LanguageModel;
|
|
403
414
|
context?: Record<string, any>;
|
|
404
415
|
messages?: FromAgent<CoreMessage[]>;
|
|
405
416
|
template?: PromptTemplate<any>;
|
|
406
|
-
|
|
417
|
+
correlationId?: string;
|
|
418
|
+
parentCorrelationId?: string;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
export type TextResultMeta = {
|
|
422
|
+
correlationId: string;
|
|
423
|
+
parentCorrelationId?: string;
|
|
424
|
+
};
|
|
407
425
|
|
|
408
426
|
export type AgentGenerateTextOptions = Omit<
|
|
409
427
|
GenerateTextOptions,
|
|
@@ -411,12 +429,16 @@ export type AgentGenerateTextOptions = Omit<
|
|
|
411
429
|
> &
|
|
412
430
|
CommonTextOptions;
|
|
413
431
|
|
|
432
|
+
export type AgentGenerateTextResult = GenerateTextResult<any> & TextResultMeta;
|
|
433
|
+
|
|
414
434
|
export type AgentStreamTextOptions = Omit<
|
|
415
435
|
StreamTextOptions,
|
|
416
436
|
'model' | 'prompt' | 'messages'
|
|
417
437
|
> &
|
|
418
438
|
CommonTextOptions;
|
|
419
439
|
|
|
440
|
+
export type AgentStreamTextResult = StreamTextResult<any> & TextResultMeta;
|
|
441
|
+
|
|
420
442
|
export interface ObservedState {
|
|
421
443
|
/**
|
|
422
444
|
* The current state value of the state machine, e.g.
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
'@statelyai/agent': minor
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Added four new methods for easily retrieving agent messages, observations, feedback, and plans:
|
|
6
|
-
|
|
7
|
-
- `agent.getMessages()`
|
|
8
|
-
- `agent.getObservations()`
|
|
9
|
-
- `agent.getFeedback()`
|
|
10
|
-
- `agent.getPlans()`
|
|
11
|
-
|
|
12
|
-
The `agent.select(…)` method is deprecated in favor of these methods.
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
'@statelyai/agent': minor
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
You can now add `context` Zod schema to your agent. For now, this is meant to be passed directly to the state machine, but in the future, the schema can be shared with the LLM agent to better understand the state machine and its context for decision making.
|
|
6
|
-
|
|
7
|
-
Breaking: The `context` and `events` types are now in `agent.types` instead of ~~`agent.eventTypes`.
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
const agent = createAgent({
|
|
11
|
-
// ...
|
|
12
|
-
context: {
|
|
13
|
-
score: z.number().describe('The score of the game'),
|
|
14
|
-
// ...
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const machine = setup({
|
|
19
|
-
types: agent.types,
|
|
20
|
-
}).createMachine({
|
|
21
|
-
context: {
|
|
22
|
-
score: 0,
|
|
23
|
-
},
|
|
24
|
-
// ...
|
|
25
|
-
});
|
|
26
|
-
```
|