openbot 0.3.1 → 0.3.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/dist/app/cli.js +1 -1
- package/dist/app/server.js +1 -4
- package/dist/bus/services.js +106 -10
- package/dist/harness/context.js +66 -6
- package/dist/harness/queue-processor.js +44 -110
- package/dist/harness/runtime-factory.js +11 -7
- package/dist/harness/todo-advance.js +93 -0
- package/dist/plugins/ai-sdk/index.js +0 -3
- package/dist/plugins/ai-sdk/runtime.js +4 -11
- package/dist/plugins/ai-sdk/system-prompt.js +18 -3
- package/dist/plugins/delegation/index.js +7 -46
- package/dist/plugins/storage-tools/index.js +2 -11
- package/dist/plugins/todo/index.js +54 -0
- package/dist/plugins/workflow/index.js +65 -0
- package/dist/registry/plugins.js +2 -2
- package/dist/services/storage.js +3 -31
- package/dist/workflow/service.js +106 -0
- package/dist/workflow/types.js +3 -0
- package/docs/plugins.md +0 -1
- package/package.json +1 -1
- package/src/app/cli.ts +1 -1
- package/src/app/server.ts +3 -4
- package/src/app/types.ts +80 -45
- package/src/bus/plugin.ts +0 -2
- package/src/bus/services.ts +133 -12
- package/src/bus/types.ts +0 -4
- package/src/harness/context.ts +73 -10
- package/src/harness/queue-processor.ts +54 -143
- package/src/harness/runtime-factory.ts +11 -7
- package/src/harness/todo-advance.ts +128 -0
- package/src/plugins/ai-sdk/index.ts +0 -3
- package/src/plugins/ai-sdk/runtime.ts +284 -300
- package/src/plugins/ai-sdk/system-prompt.ts +18 -4
- package/src/plugins/delegation/index.ts +7 -50
- package/src/plugins/storage-tools/index.ts +8 -19
- package/src/plugins/todo/index.ts +64 -0
- package/src/registry/plugins.ts +2 -3
- package/src/services/storage.ts +2 -49
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentInvokeEvent,
|
|
3
|
-
DelegateResultEvent,
|
|
4
|
-
DelegationRequestEvent,
|
|
5
3
|
HandoffRequestEvent,
|
|
6
4
|
OpenBotEvent,
|
|
7
5
|
OpenBotState,
|
|
8
6
|
} from '../app/types.js';
|
|
9
7
|
import { ensureEventId } from '../app/utils.js';
|
|
10
8
|
import { storageService } from '../services/storage.js';
|
|
9
|
+
import { advanceAfterRun } from './todo-advance.js';
|
|
11
10
|
|
|
12
11
|
export interface QueueItem {
|
|
13
12
|
agentId: string;
|
|
14
13
|
event: OpenBotEvent;
|
|
15
|
-
delegationContext?: {
|
|
16
|
-
parentAgentId: string;
|
|
17
|
-
toolCallId: string;
|
|
18
|
-
delegationWidgetId?: string;
|
|
19
|
-
};
|
|
20
14
|
}
|
|
21
15
|
|
|
22
16
|
export interface QueueProcessorOptions {
|
|
@@ -68,12 +62,12 @@ export class QueueProcessor {
|
|
|
68
62
|
Array.from(groups.entries()).map(async ([agentId, items]) => {
|
|
69
63
|
// Run items for the SAME agent sequentially to preserve event order and state consistency.
|
|
70
64
|
for (const item of items) {
|
|
71
|
-
const { event: currentEvent
|
|
65
|
+
const { event: currentEvent } = item;
|
|
72
66
|
|
|
73
|
-
// Track
|
|
67
|
+
// Track handoff requests queued in this step to avoid accidental duplicates.
|
|
74
68
|
const queuedRequestKeys = new Set<string>();
|
|
75
69
|
const queuedItems: QueueItem[] = [];
|
|
76
|
-
|
|
70
|
+
let lastAgentOutput: string | undefined;
|
|
77
71
|
|
|
78
72
|
const runOnEvent = async (chunk: OpenBotEvent, state: OpenBotState) => {
|
|
79
73
|
// 0. Filter out echoed input events to prevent duplication in the UI/storage
|
|
@@ -81,26 +75,27 @@ export class QueueProcessor {
|
|
|
81
75
|
return false;
|
|
82
76
|
}
|
|
83
77
|
|
|
78
|
+
if (chunk.type === 'agent:output') {
|
|
79
|
+
const outMeta = chunk.meta as { agentId?: string } | undefined;
|
|
80
|
+
if (outMeta?.agentId === agentId) {
|
|
81
|
+
const content = chunk.data?.content;
|
|
82
|
+
if (typeof content === 'string' && content.trim()) {
|
|
83
|
+
lastAgentOutput = content.trim();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
84
88
|
// 1. Detect if a new thread was created and update the context for the rest of the loop
|
|
85
89
|
if (chunk.type === 'action:create_thread:result' && chunk.data.success) {
|
|
86
90
|
this.currentThreadId = chunk.data.threadId || this.currentThreadId;
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
// 2. Internal routing (handoff
|
|
90
|
-
if (chunk.type === 'handoff:request'
|
|
91
|
-
const
|
|
92
|
-
const request = isHandoff
|
|
93
|
-
? (chunk as HandoffRequestEvent)
|
|
94
|
-
: (chunk as DelegationRequestEvent);
|
|
93
|
+
// 2. Internal routing (handoff requests are internal — not forwarded)
|
|
94
|
+
if (chunk.type === 'handoff:request') {
|
|
95
|
+
const request = chunk as HandoffRequestEvent;
|
|
95
96
|
const targetAgentId = request.data?.agentId;
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
? request.meta.toolCallId
|
|
99
|
-
: undefined;
|
|
100
|
-
const requestKey = isHandoff
|
|
101
|
-
? `handoff:${targetAgentId}:${request.data?.content ?? ''}`
|
|
102
|
-
: `delegate:${toolCallId ?? 'missing'}:${targetAgentId}:${request.data?.content ?? ''}`;
|
|
103
|
-
|
|
97
|
+
const requestKey = `handoff:${targetAgentId}`;
|
|
98
|
+
|
|
104
99
|
if (
|
|
105
100
|
targetAgentId &&
|
|
106
101
|
targetAgentId !== agentId &&
|
|
@@ -119,62 +114,11 @@ export class QueueProcessor {
|
|
|
119
114
|
},
|
|
120
115
|
} satisfies AgentInvokeEvent) as AgentInvokeEvent;
|
|
121
116
|
|
|
122
|
-
|
|
123
|
-
queuedItems.push({ agentId: targetAgentId, event: targetEvent });
|
|
124
|
-
} else {
|
|
125
|
-
if (!toolCallId) {
|
|
126
|
-
// Emit error output (this triggers run start if not already started)
|
|
127
|
-
await runOnEvent(
|
|
128
|
-
ensureEventId({
|
|
129
|
-
type: 'agent:output',
|
|
130
|
-
data: {
|
|
131
|
-
content:
|
|
132
|
-
'Delegation request ignored: missing toolCallId. Please retry delegation.',
|
|
133
|
-
},
|
|
134
|
-
meta: {
|
|
135
|
-
agentId,
|
|
136
|
-
threadId: this.currentThreadId,
|
|
137
|
-
},
|
|
138
|
-
} as OpenBotEvent),
|
|
139
|
-
state,
|
|
140
|
-
);
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
const parentAgentId =
|
|
144
|
-
typeof request.meta?.parentAgentId === 'string'
|
|
145
|
-
? request.meta.parentAgentId
|
|
146
|
-
: agentId;
|
|
147
|
-
const delegationWidgetId =
|
|
148
|
-
typeof request.meta?.delegationWidgetId === 'string'
|
|
149
|
-
? request.meta.delegationWidgetId
|
|
150
|
-
: undefined;
|
|
151
|
-
queuedItems.push({
|
|
152
|
-
agentId: targetAgentId,
|
|
153
|
-
event: targetEvent,
|
|
154
|
-
delegationContext: {
|
|
155
|
-
parentAgentId,
|
|
156
|
-
toolCallId,
|
|
157
|
-
delegationWidgetId,
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
}
|
|
117
|
+
queuedItems.push({ agentId: targetAgentId, event: targetEvent });
|
|
161
118
|
}
|
|
162
119
|
return false;
|
|
163
120
|
}
|
|
164
121
|
|
|
165
|
-
if (chunk.type === 'agent:output') {
|
|
166
|
-
const content = chunk.data?.content;
|
|
167
|
-
if (typeof content === 'string' && content.trim().length > 0) {
|
|
168
|
-
runOutputs.push(content.trim());
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// For delegate mode, child agent execution is internal:
|
|
173
|
-
// capture outputs for parent tool result, but don't stream child events to clients/storage.
|
|
174
|
-
if (delegationContext) {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
122
|
// If we get here, the event is accepted and should be emitted.
|
|
179
123
|
await this.options.onEvent(chunk, state);
|
|
180
124
|
return true;
|
|
@@ -191,11 +135,11 @@ export class QueueProcessor {
|
|
|
191
135
|
await this.options.onEvent(
|
|
192
136
|
{
|
|
193
137
|
type: 'agent:run:start',
|
|
194
|
-
data: {
|
|
195
|
-
runId: this.options.runId,
|
|
196
|
-
agentId,
|
|
197
|
-
channelId: this.options.channelId,
|
|
198
|
-
threadId: this.currentThreadId
|
|
138
|
+
data: {
|
|
139
|
+
runId: this.options.runId,
|
|
140
|
+
agentId,
|
|
141
|
+
channelId: this.options.channelId,
|
|
142
|
+
threadId: this.currentThreadId,
|
|
199
143
|
},
|
|
200
144
|
},
|
|
201
145
|
startState,
|
|
@@ -221,75 +165,42 @@ export class QueueProcessor {
|
|
|
221
165
|
await this.options.onEvent(
|
|
222
166
|
{
|
|
223
167
|
type: 'agent:run:end',
|
|
224
|
-
data: {
|
|
225
|
-
runId: this.options.runId,
|
|
226
|
-
agentId,
|
|
227
|
-
channelId: this.options.channelId,
|
|
228
|
-
threadId: this.currentThreadId
|
|
168
|
+
data: {
|
|
169
|
+
runId: this.options.runId,
|
|
170
|
+
agentId,
|
|
171
|
+
channelId: this.options.channelId,
|
|
172
|
+
threadId: this.currentThreadId,
|
|
229
173
|
},
|
|
230
174
|
},
|
|
231
175
|
endState,
|
|
232
176
|
);
|
|
233
|
-
}
|
|
234
177
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
type: 'action:delegate:result',
|
|
243
|
-
data: {
|
|
244
|
-
success: true,
|
|
245
|
-
agentId,
|
|
246
|
-
summary,
|
|
247
|
-
},
|
|
248
|
-
meta: {
|
|
249
|
-
toolCallId: delegationContext.toolCallId,
|
|
250
|
-
agentId: delegationContext.parentAgentId,
|
|
178
|
+
// Autonomous todo advance: mark this agent's in_progress todo done
|
|
179
|
+
// and dispatch the next assignee, if any. Single trigger point,
|
|
180
|
+
// no reliance on the LLM remembering to call `todo_update`.
|
|
181
|
+
try {
|
|
182
|
+
const handoff = await advanceAfterRun({
|
|
183
|
+
storage: storageService,
|
|
184
|
+
channelId: this.options.channelId,
|
|
251
185
|
threadId: this.currentThreadId,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
type: 'delegation:status',
|
|
270
|
-
phase: 'completed',
|
|
271
|
-
delegatedAgentId: agentId,
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
meta: {
|
|
275
|
-
agentId: delegationContext.parentAgentId,
|
|
276
|
-
threadId: this.currentThreadId,
|
|
277
|
-
},
|
|
278
|
-
} as OpenBotEvent),
|
|
279
|
-
await storageService.getOpenBotState({
|
|
280
|
-
runId: this.options.runId,
|
|
281
|
-
agentId: delegationContext.parentAgentId,
|
|
282
|
-
channelId: this.options.channelId,
|
|
283
|
-
threadId: this.currentThreadId,
|
|
284
|
-
event: delegateResultEvent,
|
|
285
|
-
}),
|
|
286
|
-
);
|
|
186
|
+
endedAgentId: agentId,
|
|
187
|
+
lastAgentOutput,
|
|
188
|
+
});
|
|
189
|
+
if (handoff) {
|
|
190
|
+
const requestKey = `handoff:${handoff.agentId}`;
|
|
191
|
+
if (!queuedRequestKeys.has(requestKey)) {
|
|
192
|
+
queuedRequestKeys.add(requestKey);
|
|
193
|
+
const targetEvent = ensureEventId({
|
|
194
|
+
type: 'agent:invoke',
|
|
195
|
+
data: { role: 'user', content: handoff.content },
|
|
196
|
+
meta: { threadId: this.currentThreadId },
|
|
197
|
+
} satisfies AgentInvokeEvent) as AgentInvokeEvent;
|
|
198
|
+
queuedItems.push({ agentId: handoff.agentId, event: targetEvent });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.warn('[queue] todo advance failed', error);
|
|
287
203
|
}
|
|
288
|
-
|
|
289
|
-
nextQueue.push({
|
|
290
|
-
agentId: delegationContext.parentAgentId,
|
|
291
|
-
event: delegateResultEvent,
|
|
292
|
-
});
|
|
293
204
|
}
|
|
294
205
|
|
|
295
206
|
nextQueue.push(...queuedItems);
|
|
@@ -7,8 +7,8 @@ import { busServicesPlugin } from '../bus/services.js';
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Enhances the agent's instructions with a list of other available agents the
|
|
10
|
-
* orchestrator can hand off
|
|
11
|
-
*
|
|
10
|
+
* orchestrator can hand off to. Agents that include the `delegation` plugin
|
|
11
|
+
* will surface peers; agents without it can ignore this.
|
|
12
12
|
*/
|
|
13
13
|
export async function enhanceInstructions(state: OpenBotState) {
|
|
14
14
|
const { agentId, agentDetails } = state;
|
|
@@ -23,12 +23,16 @@ export async function enhanceInstructions(state: OpenBotState) {
|
|
|
23
23
|
.map((a) => `- **${a.id}**${a.description ? `: ${a.description}` : ''}`)
|
|
24
24
|
.join('\n');
|
|
25
25
|
|
|
26
|
-
const header = '### Available Agents
|
|
26
|
+
const header = '### Available Agents:';
|
|
27
27
|
if (!agentDetails.instructions.includes(header)) {
|
|
28
|
-
agentDetails.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
'Use `
|
|
28
|
+
const hasHandoff = (agentDetails.pluginRefs || []).some((r) => r.id === 'delegation');
|
|
29
|
+
const hasTodo = (agentDetails.pluginRefs || []).some((r) => r.id === 'todo');
|
|
30
|
+
const usage = hasTodo
|
|
31
|
+
? 'Use these ids as `assignee` when calling `todo_write` to plan multi-agent work.'
|
|
32
|
+
: hasHandoff
|
|
33
|
+
? 'Use `handoff` to transfer control to another agent in this thread.'
|
|
34
|
+
: '';
|
|
35
|
+
agentDetails.instructions += `\n\n${header}\n${agentsList}${usage ? `\n\n${usage}` : ''}`;
|
|
32
36
|
}
|
|
33
37
|
} catch (error) {
|
|
34
38
|
console.warn('[agent] Failed to enhance instructions', error);
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { TodoItem, TodoStatus } from '../app/types.js';
|
|
2
|
+
import type { Storage } from '../bus/types.js';
|
|
3
|
+
|
|
4
|
+
/** Stored on each todo and inlined into the next assignee's invoke payload. */
|
|
5
|
+
const RESULT_MAX_CHARS = 12000;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shared helpers that drive the autonomous todo loop. The queue processor
|
|
9
|
+
* calls `advanceAfterRun` once per `agent:run:end`; that is the only place
|
|
10
|
+
* todos are completed and dispatched, which keeps the autonomous flow
|
|
11
|
+
* single-threaded and easy to reason about.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const readTodosFromState = (state: unknown): TodoItem[] => {
|
|
15
|
+
const raw = (state as Record<string, unknown> | undefined)?.todos;
|
|
16
|
+
return Array.isArray(raw) ? (raw as TodoItem[]) : [];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function truncateTodoResult(text: string, maxChars = RESULT_MAX_CHARS): string | undefined {
|
|
20
|
+
const trimmed = text.trim();
|
|
21
|
+
if (!trimmed) return undefined;
|
|
22
|
+
if (trimmed.length <= maxChars) return trimmed;
|
|
23
|
+
return `${trimmed.slice(0, maxChars)}\n…[truncated]`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AdvanceResult {
|
|
27
|
+
/** Updated todo list (after marking finished + flipping next to in_progress). */
|
|
28
|
+
todos: TodoItem[];
|
|
29
|
+
/** Next agent to invoke, if any. */
|
|
30
|
+
handoff: { agentId: string; content: string; todoId: string } | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Apply a single advance step:
|
|
35
|
+
* 1. If a todo is `in_progress` and `assignee` matches the agent whose run
|
|
36
|
+
* just ended, mark it `done` and attach `result` from `lastOutput` when present.
|
|
37
|
+
* 2. Pick the next `pending` todo with an `assignee` and flip it to
|
|
38
|
+
* `in_progress`. That assignee gets handed off to; `invoke content` includes
|
|
39
|
+
* the previous step output when available so agents without short-term
|
|
40
|
+
* history still see prior work.
|
|
41
|
+
*
|
|
42
|
+
* If a todo is already `in_progress` and the just-ended agent wasn't its
|
|
43
|
+
* assignee, leave it alone — someone else is working.
|
|
44
|
+
*/
|
|
45
|
+
export function advanceTodos(
|
|
46
|
+
todos: TodoItem[],
|
|
47
|
+
endedAgentId: string,
|
|
48
|
+
lastOutput?: string,
|
|
49
|
+
): AdvanceResult {
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
const truncated = truncateTodoResult(lastOutput ?? '');
|
|
52
|
+
|
|
53
|
+
let completedOutput: string | undefined;
|
|
54
|
+
|
|
55
|
+
let working = todos.map((t) => {
|
|
56
|
+
if (t.status === 'in_progress' && t.assignee === endedAgentId) {
|
|
57
|
+
completedOutput = truncated;
|
|
58
|
+
return {
|
|
59
|
+
...t,
|
|
60
|
+
status: 'done' as TodoStatus,
|
|
61
|
+
updatedAt: now,
|
|
62
|
+
...(truncated !== undefined ? { result: truncated } : {}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return t;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (working.some((t) => t.status === 'in_progress')) {
|
|
69
|
+
return { todos: working, handoff: null };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const idx = working.findIndex((t) => t.status === 'pending' && t.assignee);
|
|
73
|
+
if (idx === -1) return { todos: working, handoff: null };
|
|
74
|
+
|
|
75
|
+
const picked = working[idx];
|
|
76
|
+
working = working.map((t, i) =>
|
|
77
|
+
i === idx ? { ...t, status: 'in_progress' as TodoStatus, updatedAt: now } : t,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const invokeContent =
|
|
81
|
+
completedOutput !== undefined && completedOutput !== ''
|
|
82
|
+
? `${picked.content}\n\n--- Output from previous step ---\n${completedOutput}`
|
|
83
|
+
: picked.content;
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
todos: working,
|
|
87
|
+
handoff: {
|
|
88
|
+
agentId: picked.assignee!,
|
|
89
|
+
content: invokeContent,
|
|
90
|
+
todoId: picked.id,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function advanceAfterRun(options: {
|
|
96
|
+
storage: Storage;
|
|
97
|
+
channelId: string;
|
|
98
|
+
threadId?: string;
|
|
99
|
+
endedAgentId: string;
|
|
100
|
+
lastAgentOutput?: string;
|
|
101
|
+
}): Promise<AdvanceResult['handoff']> {
|
|
102
|
+
const { storage, channelId, threadId, endedAgentId, lastAgentOutput } = options;
|
|
103
|
+
if (!threadId) return null;
|
|
104
|
+
|
|
105
|
+
const details = await storage.getThreadDetails({ channelId, threadId });
|
|
106
|
+
const todos = readTodosFromState(details?.state);
|
|
107
|
+
if (todos.length === 0) return null;
|
|
108
|
+
|
|
109
|
+
const { todos: nextList, handoff } = advanceTodos(todos, endedAgentId, lastAgentOutput);
|
|
110
|
+
|
|
111
|
+
const changed =
|
|
112
|
+
nextList.length !== todos.length ||
|
|
113
|
+
nextList.some((t, i) => {
|
|
114
|
+
const u = todos[i];
|
|
115
|
+
if (!u) return true;
|
|
116
|
+
return (
|
|
117
|
+
t.status !== u.status ||
|
|
118
|
+
t.updatedAt !== u.updatedAt ||
|
|
119
|
+
t.result !== u.result ||
|
|
120
|
+
t.assignee !== u.assignee ||
|
|
121
|
+
t.content !== u.content
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
if (changed) {
|
|
125
|
+
await storage.patchThreadState({ channelId, threadId, state: { todos: nextList } });
|
|
126
|
+
}
|
|
127
|
+
return handoff;
|
|
128
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from '../../bus/plugin.js';
|
|
2
2
|
import { aiSdkRuntime } from './runtime.js';
|
|
3
|
-
import { AI_SDK_SYSTEM_PROMPT } from './system-prompt.js';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* `ai-sdk` — generic LLM runtime plugin built on the Vercel AI SDK.
|
|
@@ -14,7 +13,6 @@ export const aiSdkPlugin: Plugin = {
|
|
|
14
13
|
name: 'AI SDK Runtime',
|
|
15
14
|
description:
|
|
16
15
|
'Generic LLM runtime built on the Vercel AI SDK. Consumes tools contributed by other plugins.',
|
|
17
|
-
defaultInstructions: AI_SDK_SYSTEM_PROMPT,
|
|
18
16
|
configSchema: {
|
|
19
17
|
type: 'object',
|
|
20
18
|
properties: {
|
|
@@ -34,7 +32,6 @@ export const aiSdkPlugin: Plugin = {
|
|
|
34
32
|
|
|
35
33
|
return aiSdkRuntime({
|
|
36
34
|
model,
|
|
37
|
-
system: agentDetails.instructions || AI_SDK_SYSTEM_PROMPT,
|
|
38
35
|
storage,
|
|
39
36
|
toolDefinitions: tools,
|
|
40
37
|
});
|