@statelyai/agent 1.1.6 → 2.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changeset/cyan-carpets-perform.md +5 -0
- package/.changeset/fast-donkeys-argue.md +5 -0
- package/.changeset/light-hats-drive.md +9 -0
- package/.changeset/old-jobs-check.md +5 -0
- package/.changeset/pre.json +13 -0
- package/.vscode/launch.json +6 -0
- package/CHANGELOG.md +22 -0
- package/dist/index.d.mts +262 -171
- package/dist/index.d.ts +262 -171
- package/dist/index.js +383 -274
- package/dist/index.mjs +386 -272
- package/examples/chatbot-alt.ts +57 -0
- package/examples/chatbot.ts +12 -17
- package/examples/cot.ts +26 -23
- package/examples/customer-service-sim.ts +107 -0
- package/examples/email.ts +37 -41
- package/examples/example.ts +6 -6
- package/examples/executor.ts +66 -0
- package/examples/goal.ts +12 -12
- package/examples/helpers/helpers.ts +26 -14
- package/examples/joke.ts +79 -76
- package/examples/jugs.ts +125 -0
- package/examples/multi.ts +5 -5
- package/examples/newspaper.ts +98 -104
- package/examples/number.ts +6 -5
- package/examples/raffle.ts +11 -12
- package/examples/river-crossing.ts +140 -0
- package/examples/sandbox.ts +1 -1
- package/examples/simple.ts +5 -3
- package/examples/summary.ts +121 -0
- package/examples/support.ts +6 -6
- package/examples/ticTacToe.ts +86 -45
- package/examples/todo.ts +7 -7
- package/examples/tutor.ts +15 -15
- package/examples/verify.ts +3 -3
- package/examples/weather.ts +6 -9
- package/examples/wiki.ts +27 -8
- package/examples/word.ts +16 -11
- package/package.json +16 -11
- package/readme.md +1 -1
- package/src/agent-experimental.ts +1 -1
- package/src/agent.test.ts +243 -214
- package/src/agent.ts +286 -95
- package/src/decide.test.ts +276 -0
- package/src/decide.ts +163 -0
- package/src/index.ts +1 -1
- package/src/middleware.ts +91 -0
- package/src/mockModel.ts +47 -0
- package/src/planners/shortestPath.test.ts +94 -0
- package/src/planners/shortestPath.ts +177 -0
- package/src/planners/simple.ts +105 -0
- package/src/strategies/chain-of-note.ts +6 -55
- package/src/text.ts +51 -144
- package/src/types.ts +187 -212
- package/src/utils.ts +48 -4
- package/vitest.config.ts +9 -3
- package/src/adapters/vercel.ts +0 -7
- package/src/decision.test.ts +0 -179
- package/src/decision.ts +0 -84
- package/src/memory.ts +0 -25
- package/src/planners/shortestPathPlanner.ts +0 -22
- package/src/planners/simplePlanner.ts +0 -139
|
@@ -0,0 +1,177 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { CoreMessage, generateText } from 'ai';
|
|
2
|
+
import { AgentPlan, AgentPlanInput, PromptTemplate, AnyAgent } from '../types';
|
|
3
|
+
import { randomId } from '../utils';
|
|
4
|
+
import { getNextSnapshot } from 'xstate';
|
|
5
|
+
import { defaultTextTemplate } from '../templates/defaultText';
|
|
6
|
+
import { getMessages } from '../text';
|
|
7
|
+
import { getToolMap } from '../decide';
|
|
8
|
+
|
|
9
|
+
const simplePlannerPromptTemplate: PromptTemplate<any> = (data) => {
|
|
10
|
+
return `
|
|
11
|
+
${defaultTextTemplate(data)}
|
|
12
|
+
|
|
13
|
+
Make at most one tool call to achieve the above goal. If the goal cannot be achieved with any tool calls, do not make any tool call.
|
|
14
|
+
`.trim();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export async function simplePlanner<T extends AnyAgent>(
|
|
18
|
+
agent: T,
|
|
19
|
+
input: AgentPlanInput<any>
|
|
20
|
+
): Promise<AgentPlan<any> | undefined> {
|
|
21
|
+
const toolMap = getToolMap(agent, input);
|
|
22
|
+
|
|
23
|
+
if (!toolMap) {
|
|
24
|
+
// No valid transitions for the specified tools
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Create a prompt with the given context and goal.
|
|
29
|
+
// The template is used to ensure that a single tool call at most is made.
|
|
30
|
+
const prompt = simplePlannerPromptTemplate({
|
|
31
|
+
context: input.state.context,
|
|
32
|
+
goal: input.goal,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const messages = await getMessages(agent, prompt, input);
|
|
36
|
+
|
|
37
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
38
|
+
|
|
39
|
+
const {
|
|
40
|
+
state,
|
|
41
|
+
machine,
|
|
42
|
+
previousPlan,
|
|
43
|
+
events,
|
|
44
|
+
goal,
|
|
45
|
+
model: _,
|
|
46
|
+
...rest
|
|
47
|
+
} = input;
|
|
48
|
+
|
|
49
|
+
const machineState = input.machine
|
|
50
|
+
? input.machine.resolveState({
|
|
51
|
+
...input.state,
|
|
52
|
+
context: input.state.context,
|
|
53
|
+
})
|
|
54
|
+
: undefined;
|
|
55
|
+
|
|
56
|
+
const result = await generateText({
|
|
57
|
+
...rest,
|
|
58
|
+
system: input.system ?? agent.description,
|
|
59
|
+
model,
|
|
60
|
+
messages,
|
|
61
|
+
tools: toolMap as any,
|
|
62
|
+
toolChoice: input.toolChoice ?? 'required',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
result.response.messages.forEach((m) => {
|
|
66
|
+
const message: CoreMessage = m;
|
|
67
|
+
|
|
68
|
+
agent.addMessage({
|
|
69
|
+
...message,
|
|
70
|
+
id: randomId(),
|
|
71
|
+
timestamp: Date.now(),
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const singleResult = result.toolResults[0];
|
|
76
|
+
|
|
77
|
+
if (!singleResult) {
|
|
78
|
+
// TODO: retries?
|
|
79
|
+
console.warn('No tool call results returned');
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
planner: 'simple',
|
|
85
|
+
goal: input.goal,
|
|
86
|
+
goalState: input.state,
|
|
87
|
+
nextEvent: singleResult.result,
|
|
88
|
+
episodeId: agent.episodeId,
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
paths: [
|
|
91
|
+
{
|
|
92
|
+
state: undefined,
|
|
93
|
+
steps: [
|
|
94
|
+
{
|
|
95
|
+
event: singleResult.result,
|
|
96
|
+
state:
|
|
97
|
+
machine && machineState
|
|
98
|
+
? getNextSnapshot(machine, machineState, singleResult.result)
|
|
99
|
+
: undefined,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -67,8 +67,8 @@ export const chainOfNote = setup({
|
|
|
67
67
|
},
|
|
68
68
|
}).createMachine({
|
|
69
69
|
initial: 'searching',
|
|
70
|
-
context: (
|
|
71
|
-
...
|
|
70
|
+
context: ({ input }) => ({
|
|
71
|
+
...input,
|
|
72
72
|
searchResults: null,
|
|
73
73
|
summaries: null,
|
|
74
74
|
}),
|
|
@@ -76,8 +76,8 @@ export const chainOfNote = setup({
|
|
|
76
76
|
searching: {
|
|
77
77
|
invoke: {
|
|
78
78
|
src: 'searchWiki',
|
|
79
|
-
input: (
|
|
80
|
-
query:
|
|
79
|
+
input: ({ context }) => ({
|
|
80
|
+
query: context.prompt,
|
|
81
81
|
}),
|
|
82
82
|
onDone: {
|
|
83
83
|
actions: assign({
|
|
@@ -90,8 +90,8 @@ export const chainOfNote = setup({
|
|
|
90
90
|
extracting: {
|
|
91
91
|
invoke: {
|
|
92
92
|
src: 'extractSummaries',
|
|
93
|
-
input: (
|
|
94
|
-
searchResult:
|
|
93
|
+
input: ({ context }) => ({
|
|
94
|
+
searchResult: context.searchResults!,
|
|
95
95
|
}),
|
|
96
96
|
onDone: {
|
|
97
97
|
actions: assign({
|
|
@@ -104,52 +104,3 @@ export const chainOfNote = setup({
|
|
|
104
104
|
generating: {},
|
|
105
105
|
},
|
|
106
106
|
});
|
|
107
|
-
|
|
108
|
-
// export function chainOfNote() {
|
|
109
|
-
// return {
|
|
110
|
-
// generateText: async (x) => {
|
|
111
|
-
// const passages = await wiki.search(x.prompt!, {
|
|
112
|
-
// limit: 5,
|
|
113
|
-
// });
|
|
114
|
-
|
|
115
|
-
// const extracts = await Promise.all(
|
|
116
|
-
// passages.results.map(async (p) => {
|
|
117
|
-
// const summary = await wiki.summary(p.title);
|
|
118
|
-
// return summary.extract;
|
|
119
|
-
// })
|
|
120
|
-
// );
|
|
121
|
-
// x.agent?.addMessage({
|
|
122
|
-
// content: x.prompt!,
|
|
123
|
-
// id: Date.now() + '',
|
|
124
|
-
// role: 'user',
|
|
125
|
-
// timestamp: Date.now(),
|
|
126
|
-
// });
|
|
127
|
-
// const result = await generateText({
|
|
128
|
-
// model: x.model,
|
|
129
|
-
// system: `Task Description:
|
|
130
|
-
|
|
131
|
-
// 1. Read the given question and five Wikipedia passages to gather relevant information.
|
|
132
|
-
|
|
133
|
-
// 2. Write reading notes summarizing the key points from these passages.
|
|
134
|
-
|
|
135
|
-
// 3. Discuss the relevance of the given question and Wikipedia passages.
|
|
136
|
-
|
|
137
|
-
// 4. If some passages are relevant to the given question, provide a brief answer based on the passages.
|
|
138
|
-
|
|
139
|
-
// 5. If no passage is relevant, direcly provide answer without considering the passages.
|
|
140
|
-
|
|
141
|
-
// Passages: \n${extracts.join('\n')}`,
|
|
142
|
-
// prompt: `${x.prompt!}`,
|
|
143
|
-
// });
|
|
144
|
-
|
|
145
|
-
// x.agent?.addMessage({
|
|
146
|
-
// content: result.text,
|
|
147
|
-
// id: Date.now() + '',
|
|
148
|
-
// role: 'user',
|
|
149
|
-
// timestamp: Date.now(),
|
|
150
|
-
// });
|
|
151
|
-
|
|
152
|
-
// return result;
|
|
153
|
-
// },
|
|
154
|
-
// } satisfies AgentStrategy;
|
|
155
|
-
// }
|
package/src/text.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
generateText,
|
|
3
|
+
streamText,
|
|
4
|
+
type CoreMessage,
|
|
5
|
+
type CoreTool,
|
|
6
|
+
type GenerateTextResult,
|
|
7
|
+
} from 'ai';
|
|
2
8
|
import {
|
|
3
9
|
AgentGenerateTextOptions,
|
|
4
|
-
AgentGenerateTextResult,
|
|
5
10
|
AgentStreamTextOptions,
|
|
6
|
-
AgentStreamTextResult,
|
|
7
11
|
AnyAgent,
|
|
8
12
|
} from './types';
|
|
9
13
|
import { defaultTextTemplate } from './templates/defaultText';
|
|
@@ -15,7 +19,6 @@ import {
|
|
|
15
19
|
fromPromise,
|
|
16
20
|
toObserver,
|
|
17
21
|
} from 'xstate';
|
|
18
|
-
import { randomId } from './utils';
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Gets an array of messages from the given prompt, based on the agent and options.
|
|
@@ -45,158 +48,39 @@ export async function getMessages(
|
|
|
45
48
|
return messages;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
export async function agentGenerateText<T extends AnyAgent>(
|
|
49
|
-
agent: T,
|
|
50
|
-
options: AgentGenerateTextOptions
|
|
51
|
-
): Promise<AgentGenerateTextResult> {
|
|
52
|
-
const resolvedOptions = {
|
|
53
|
-
...agent.defaultOptions,
|
|
54
|
-
...options,
|
|
55
|
-
correlationId: options.correlationId ?? randomId(),
|
|
56
|
-
};
|
|
57
|
-
// Generate a correlation ID if one is not provided
|
|
58
|
-
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
59
|
-
// TODO: check if messages was provided instead
|
|
60
|
-
const id = randomId();
|
|
61
|
-
const goal =
|
|
62
|
-
typeof resolvedOptions.prompt === 'string'
|
|
63
|
-
? resolvedOptions.prompt
|
|
64
|
-
: await resolvedOptions.prompt(agent);
|
|
65
|
-
|
|
66
|
-
const promptWithContext = template({
|
|
67
|
-
goal,
|
|
68
|
-
context: resolvedOptions.context,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const messages = await getMessages(agent, promptWithContext, resolvedOptions);
|
|
72
|
-
|
|
73
|
-
agent.addMessage({
|
|
74
|
-
id,
|
|
75
|
-
role: 'user',
|
|
76
|
-
content: promptWithContext,
|
|
77
|
-
timestamp: Date.now(),
|
|
78
|
-
correlationId: resolvedOptions.correlationId,
|
|
79
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const result = await agent.adapter.generateText({
|
|
83
|
-
...resolvedOptions,
|
|
84
|
-
prompt: undefined,
|
|
85
|
-
messages,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
agent.addMessage({
|
|
89
|
-
content: result.text,
|
|
90
|
-
id,
|
|
91
|
-
role: 'assistant',
|
|
92
|
-
timestamp: Date.now(),
|
|
93
|
-
responseId: id,
|
|
94
|
-
result,
|
|
95
|
-
correlationId: resolvedOptions.correlationId,
|
|
96
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
...result,
|
|
101
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
102
|
-
correlationId: resolvedOptions.correlationId,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export async function agentStreamText(
|
|
107
|
-
agent: AnyAgent,
|
|
108
|
-
options: AgentStreamTextOptions
|
|
109
|
-
): Promise<AgentStreamTextResult> {
|
|
110
|
-
const resolvedOptions = {
|
|
111
|
-
...agent.defaultOptions,
|
|
112
|
-
...options,
|
|
113
|
-
correlationId: options.correlationId ?? randomId(),
|
|
114
|
-
};
|
|
115
|
-
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
116
|
-
|
|
117
|
-
const id = randomId();
|
|
118
|
-
const goal =
|
|
119
|
-
typeof resolvedOptions.prompt === 'string'
|
|
120
|
-
? resolvedOptions.prompt
|
|
121
|
-
: await resolvedOptions.prompt(agent);
|
|
122
|
-
|
|
123
|
-
const promptWithContext = template({
|
|
124
|
-
goal,
|
|
125
|
-
context: resolvedOptions.context,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const messages = await getMessages(agent, promptWithContext, resolvedOptions);
|
|
129
|
-
|
|
130
|
-
agent.addMessage({
|
|
131
|
-
role: 'user',
|
|
132
|
-
content: promptWithContext,
|
|
133
|
-
id,
|
|
134
|
-
timestamp: Date.now(),
|
|
135
|
-
correlationId: resolvedOptions.correlationId,
|
|
136
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const result = await agent.adapter.streamText({
|
|
140
|
-
...resolvedOptions,
|
|
141
|
-
prompt: undefined,
|
|
142
|
-
messages,
|
|
143
|
-
onFinish: async (res) => {
|
|
144
|
-
agent.addMessage({
|
|
145
|
-
role: 'assistant',
|
|
146
|
-
result: {
|
|
147
|
-
text: res.text,
|
|
148
|
-
finishReason: res.finishReason,
|
|
149
|
-
logprobs: undefined,
|
|
150
|
-
responseMessages: [],
|
|
151
|
-
toolCalls: [],
|
|
152
|
-
toolResults: [],
|
|
153
|
-
usage: res.usage,
|
|
154
|
-
warnings: res.warnings,
|
|
155
|
-
rawResponse: res.rawResponse,
|
|
156
|
-
roundtrips: [], // TODO: how do we get this information?,
|
|
157
|
-
steps: res.steps,
|
|
158
|
-
response: res.response,
|
|
159
|
-
experimental_providerMetadata: res.experimental_providerMetadata,
|
|
160
|
-
},
|
|
161
|
-
content: res.text,
|
|
162
|
-
id: randomId(),
|
|
163
|
-
timestamp: Date.now(),
|
|
164
|
-
responseId: id,
|
|
165
|
-
correlationId: resolvedOptions.correlationId,
|
|
166
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
167
|
-
});
|
|
168
|
-
},
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
...result,
|
|
173
|
-
textStream: result.textStream,
|
|
174
|
-
fullStream: result.fullStream,
|
|
175
|
-
parentCorrelationId: resolvedOptions.parentCorrelationId,
|
|
176
|
-
correlationId: resolvedOptions.correlationId,
|
|
177
|
-
} as unknown as AgentStreamTextResult; // TODO: fix
|
|
178
|
-
}
|
|
179
|
-
|
|
180
51
|
export function fromTextStream<T extends AnyAgent>(
|
|
181
52
|
agent: T,
|
|
182
|
-
|
|
53
|
+
options?: AgentStreamTextOptions
|
|
183
54
|
): ObservableActorLogic<
|
|
184
55
|
{ textDelta: string },
|
|
185
56
|
Omit<AgentStreamTextOptions, 'context'> & {
|
|
186
57
|
context?: AgentStreamTextOptions['context'];
|
|
187
58
|
}
|
|
188
59
|
> {
|
|
60
|
+
const template = options?.template ?? defaultTextTemplate;
|
|
189
61
|
return fromObservable(({ input }) => {
|
|
190
62
|
const observers = new Set<Observer<{ textDelta: string }>>();
|
|
191
63
|
|
|
192
64
|
// TODO: check if messages was provided instead
|
|
193
65
|
|
|
194
66
|
(async () => {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
67
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
68
|
+
const goal =
|
|
69
|
+
typeof input.prompt === 'string'
|
|
70
|
+
? input.prompt
|
|
71
|
+
: await input.prompt(agent);
|
|
72
|
+
const promptWithContext = template({
|
|
73
|
+
goal,
|
|
198
74
|
context: input.context,
|
|
199
75
|
});
|
|
76
|
+
const messages = await getMessages(agent, promptWithContext, input);
|
|
77
|
+
const result = await streamText({
|
|
78
|
+
...options,
|
|
79
|
+
...input,
|
|
80
|
+
prompt: undefined, // overwritten by messages
|
|
81
|
+
model,
|
|
82
|
+
messages,
|
|
83
|
+
});
|
|
200
84
|
|
|
201
85
|
for await (const part of result.fullStream) {
|
|
202
86
|
if (part.type === 'text-delta') {
|
|
@@ -224,18 +108,41 @@ export function fromTextStream<T extends AnyAgent>(
|
|
|
224
108
|
|
|
225
109
|
export function fromText<T extends AnyAgent>(
|
|
226
110
|
agent: T,
|
|
227
|
-
|
|
111
|
+
options?: AgentGenerateTextOptions
|
|
228
112
|
): PromiseActorLogic<
|
|
229
113
|
GenerateTextResult<Record<string, CoreTool<any, any>>>,
|
|
230
114
|
Omit<AgentGenerateTextOptions, 'context'> & {
|
|
231
115
|
context?: AgentGenerateTextOptions['context'];
|
|
232
116
|
}
|
|
233
117
|
> {
|
|
118
|
+
const resolvedOptions = {
|
|
119
|
+
...agent.defaultOptions,
|
|
120
|
+
...options,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const template = resolvedOptions.template ?? defaultTextTemplate;
|
|
124
|
+
|
|
234
125
|
return fromPromise(async ({ input }) => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
126
|
+
const goal =
|
|
127
|
+
typeof input.prompt === 'string'
|
|
128
|
+
? input.prompt
|
|
129
|
+
: await input.prompt(agent);
|
|
130
|
+
|
|
131
|
+
const promptWithContext = template({
|
|
132
|
+
goal,
|
|
238
133
|
context: input.context,
|
|
239
134
|
});
|
|
135
|
+
|
|
136
|
+
const messages = await getMessages(agent, promptWithContext, input);
|
|
137
|
+
|
|
138
|
+
const model = input.model ? agent.wrap(input.model) : agent.model;
|
|
139
|
+
|
|
140
|
+
return await generateText({
|
|
141
|
+
...input,
|
|
142
|
+
...options,
|
|
143
|
+
prompt: undefined,
|
|
144
|
+
messages,
|
|
145
|
+
model,
|
|
146
|
+
});
|
|
240
147
|
});
|
|
241
148
|
}
|