@botbotgo/agent-harness 0.0.14 → 0.0.16
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/contracts/types.d.ts +9 -0
- package/dist/resource/resource-impl.js +1 -1
- package/dist/runtime/agent-runtime-adapter.d.ts +2 -1
- package/dist/runtime/agent-runtime-adapter.js +48 -20
- package/dist/runtime/declared-middleware.d.ts +4 -0
- package/dist/runtime/declared-middleware.js +56 -0
- package/dist/workspace/agent-binding-compiler.js +22 -0
- package/dist/workspace/object-loader.js +22 -2
- package/dist/workspace/validate.js +28 -0
- package/package.json +2 -2
|
@@ -73,6 +73,9 @@ export type LangChainAgentParams = {
|
|
|
73
73
|
model: CompiledModel;
|
|
74
74
|
tools: CompiledTool[];
|
|
75
75
|
systemPrompt?: string;
|
|
76
|
+
responseFormat?: unknown;
|
|
77
|
+
contextSchema?: unknown;
|
|
78
|
+
middleware?: Array<Record<string, unknown>>;
|
|
76
79
|
description: string;
|
|
77
80
|
};
|
|
78
81
|
export type CompiledSubAgent = {
|
|
@@ -84,11 +87,17 @@ export type CompiledSubAgent = {
|
|
|
84
87
|
interruptOn?: Record<string, boolean | object>;
|
|
85
88
|
skills?: string[];
|
|
86
89
|
memory?: string[];
|
|
90
|
+
responseFormat?: unknown;
|
|
91
|
+
contextSchema?: unknown;
|
|
92
|
+
middleware?: Array<Record<string, unknown>>;
|
|
87
93
|
};
|
|
88
94
|
export type DeepAgentParams = {
|
|
89
95
|
model: CompiledModel;
|
|
90
96
|
tools: CompiledTool[];
|
|
91
97
|
systemPrompt?: string;
|
|
98
|
+
responseFormat?: unknown;
|
|
99
|
+
contextSchema?: unknown;
|
|
100
|
+
middleware?: Array<Record<string, unknown>>;
|
|
92
101
|
description: string;
|
|
93
102
|
subagents: CompiledSubAgent[];
|
|
94
103
|
interruptOn?: Record<string, boolean | object>;
|
|
@@ -218,7 +218,7 @@ export async function listResourceToolsForSource(source, workspaceRoot = process
|
|
|
218
218
|
}
|
|
219
219
|
export function createResourceBackendResolver(workspace) {
|
|
220
220
|
const localResolver = createProviderBackendResolver(localResource, workspace);
|
|
221
|
-
return (binding) => localResolver?.(binding)
|
|
221
|
+
return (binding) => localResolver?.(binding);
|
|
222
222
|
}
|
|
223
223
|
export function createResourceToolResolver(workspace, options = {}) {
|
|
224
224
|
const functionResolver = createFunctionToolResolver(workspace);
|
|
@@ -15,6 +15,8 @@ export declare class AgentRuntimeAdapter {
|
|
|
15
15
|
private synthesizeDeepAgentAnswer;
|
|
16
16
|
private resolveModel;
|
|
17
17
|
private buildToolNameMapping;
|
|
18
|
+
private buildAgentMessages;
|
|
19
|
+
private buildRawModelMessages;
|
|
18
20
|
private resolveTools;
|
|
19
21
|
private normalizeInterruptPolicy;
|
|
20
22
|
private compileInterruptOn;
|
|
@@ -23,7 +25,6 @@ export declare class AgentRuntimeAdapter {
|
|
|
23
25
|
private resolveCheckpointer;
|
|
24
26
|
private buildRouteSystemPrompt;
|
|
25
27
|
private resolveSubagents;
|
|
26
|
-
private buildConversation;
|
|
27
28
|
create(binding: CompiledAgentBinding): Promise<RunnableLike>;
|
|
28
29
|
route(input: string, primaryBinding: CompiledAgentBinding, secondaryBinding: CompiledAgentBinding, options?: {
|
|
29
30
|
systemPrompt?: string;
|
|
@@ -8,6 +8,7 @@ import { createAgent, humanInTheLoopMiddleware, initChatModel } from "langchain"
|
|
|
8
8
|
import { extractEmptyAssistantMessageFailure, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, sanitizeVisibleText, tryParseJson, wrapResolvedModel, } from "./parsing/output-parsing.js";
|
|
9
9
|
import { extractAgentStep, extractInterruptPayload, extractReasoningStreamOutput, extractTerminalStreamOutput, extractToolResult, normalizeTerminalOutputKey, readStreamDelta, } from "./parsing/stream-event-parsing.js";
|
|
10
10
|
import { wrapToolForExecution } from "./tool-hitl.js";
|
|
11
|
+
import { resolveDeclaredMiddleware } from "./declared-middleware.js";
|
|
11
12
|
const AGENT_INTERRUPT_SENTINEL_PREFIX = "__agent_harness_interrupt__:";
|
|
12
13
|
const MODEL_SAFE_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
13
14
|
function asObject(value) {
|
|
@@ -76,6 +77,9 @@ function wrapResolvedToolWithModelFacingName(resolvedTool, modelFacingName) {
|
|
|
76
77
|
},
|
|
77
78
|
});
|
|
78
79
|
}
|
|
80
|
+
function countConfiguredTools(binding) {
|
|
81
|
+
return binding.langchainAgentParams?.tools.length ?? binding.deepAgentParams?.tools.length ?? 0;
|
|
82
|
+
}
|
|
79
83
|
export class AgentRuntimeAdapter {
|
|
80
84
|
options;
|
|
81
85
|
constructor(options = {}) {
|
|
@@ -197,6 +201,20 @@ export class AgentRuntimeAdapter {
|
|
|
197
201
|
buildToolNameMapping(tools) {
|
|
198
202
|
return buildToolNameMapping(tools);
|
|
199
203
|
}
|
|
204
|
+
buildAgentMessages(history, input) {
|
|
205
|
+
return [
|
|
206
|
+
...history.map((item) => ({ role: item.role, content: item.content })),
|
|
207
|
+
{ role: "user", content: input },
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
buildRawModelMessages(systemPrompt, history, input) {
|
|
211
|
+
const messages = [];
|
|
212
|
+
if (systemPrompt) {
|
|
213
|
+
messages.push({ role: "system", content: systemPrompt });
|
|
214
|
+
}
|
|
215
|
+
messages.push(...this.buildAgentMessages(history, input));
|
|
216
|
+
return messages;
|
|
217
|
+
}
|
|
200
218
|
resolveTools(tools, binding) {
|
|
201
219
|
const resolved = this.options.toolResolver ? this.options.toolResolver(tools.map((tool) => tool.id), binding) : [];
|
|
202
220
|
const toolNameMapping = this.buildToolNameMapping(tools);
|
|
@@ -249,8 +267,15 @@ export class AgentRuntimeAdapter {
|
|
|
249
267
|
}
|
|
250
268
|
return this.compileInterruptOn(binding.langchainAgentParams?.tools ?? [], binding.agent.langchainAgentConfig?.interruptOn);
|
|
251
269
|
}
|
|
252
|
-
resolveMiddleware(binding, interruptOn) {
|
|
253
|
-
const
|
|
270
|
+
async resolveMiddleware(binding, interruptOn) {
|
|
271
|
+
const declarativeMiddleware = await resolveDeclaredMiddleware(binding.langchainAgentParams?.middleware ??
|
|
272
|
+
binding.deepAgentParams?.middleware, {
|
|
273
|
+
resolveModel: (model) => this.resolveModel(model),
|
|
274
|
+
});
|
|
275
|
+
const middleware = [
|
|
276
|
+
...declarativeMiddleware,
|
|
277
|
+
...(this.options.middlewareResolver ? this.options.middlewareResolver(binding) : []),
|
|
278
|
+
];
|
|
254
279
|
if (interruptOn && Object.keys(interruptOn).length > 0) {
|
|
255
280
|
middleware.push(humanInTheLoopMiddleware({ interruptOn }));
|
|
256
281
|
}
|
|
@@ -285,32 +310,28 @@ export class AgentRuntimeAdapter {
|
|
|
285
310
|
model: subagent.model ? (await this.resolveModel(subagent.model)) : undefined,
|
|
286
311
|
tools: subagent.tools ? this.resolveTools(subagent.tools) : undefined,
|
|
287
312
|
interruptOn: this.compileInterruptOn(subagent.tools ?? [], subagent.interruptOn),
|
|
313
|
+
responseFormat: subagent.responseFormat,
|
|
314
|
+
contextSchema: subagent.contextSchema,
|
|
315
|
+
middleware: (await resolveDeclaredMiddleware(subagent.middleware, {
|
|
316
|
+
resolveModel: (model) => this.resolveModel(model),
|
|
317
|
+
})),
|
|
288
318
|
})));
|
|
289
319
|
}
|
|
290
|
-
buildConversation(systemPrompt, history, input) {
|
|
291
|
-
const messages = [];
|
|
292
|
-
if (systemPrompt) {
|
|
293
|
-
messages.push({ role: "system", content: systemPrompt });
|
|
294
|
-
}
|
|
295
|
-
for (const item of history) {
|
|
296
|
-
messages.push({ role: item.role, content: item.content });
|
|
297
|
-
}
|
|
298
|
-
messages.push({ role: "user", content: input });
|
|
299
|
-
return messages;
|
|
300
|
-
}
|
|
301
320
|
async create(binding) {
|
|
302
321
|
if (binding.langchainAgentParams) {
|
|
303
322
|
const interruptOn = this.resolveInterruptOn(binding);
|
|
304
323
|
const model = (await this.resolveModel(binding.langchainAgentParams.model));
|
|
305
324
|
const tools = this.resolveTools(binding.langchainAgentParams.tools, binding);
|
|
306
325
|
if (tools.length > 0 && typeof model.bindTools !== "function") {
|
|
307
|
-
|
|
326
|
+
throw new Error(`Agent ${binding.agent.id} configures ${tools.length} tool(s), but resolved model ${binding.langchainAgentParams.model.id} does not support tool binding.`);
|
|
308
327
|
}
|
|
309
328
|
return createAgent({
|
|
310
329
|
model: model,
|
|
311
330
|
tools: tools,
|
|
312
331
|
systemPrompt: binding.langchainAgentParams.systemPrompt,
|
|
313
|
-
|
|
332
|
+
responseFormat: binding.langchainAgentParams.responseFormat,
|
|
333
|
+
contextSchema: binding.langchainAgentParams.contextSchema,
|
|
334
|
+
middleware: (await this.resolveMiddleware(binding, interruptOn)),
|
|
314
335
|
checkpointer: this.resolveCheckpointer(binding),
|
|
315
336
|
});
|
|
316
337
|
}
|
|
@@ -322,7 +343,9 @@ export class AgentRuntimeAdapter {
|
|
|
322
343
|
model: (await this.resolveModel(params.model)),
|
|
323
344
|
tools: this.resolveTools(params.tools, binding),
|
|
324
345
|
systemPrompt: params.systemPrompt,
|
|
325
|
-
|
|
346
|
+
responseFormat: params.responseFormat,
|
|
347
|
+
contextSchema: params.contextSchema,
|
|
348
|
+
middleware: (await this.resolveMiddleware(binding)),
|
|
326
349
|
subagents: (await this.resolveSubagents(params.subagents)),
|
|
327
350
|
checkpointer: this.resolveCheckpointer(binding),
|
|
328
351
|
store: this.options.storeResolver?.(binding),
|
|
@@ -365,7 +388,7 @@ export class AgentRuntimeAdapter {
|
|
|
365
388
|
}
|
|
366
389
|
async invoke(binding, input, threadId, runId, resumePayload, history = []) {
|
|
367
390
|
const request = resumePayload === undefined
|
|
368
|
-
? { messages: this.
|
|
391
|
+
? { messages: this.buildAgentMessages(history, input) }
|
|
369
392
|
: new Command({ resume: resumePayload });
|
|
370
393
|
let result;
|
|
371
394
|
try {
|
|
@@ -378,7 +401,7 @@ export class AgentRuntimeAdapter {
|
|
|
378
401
|
}
|
|
379
402
|
const retriedBinding = this.applyStrictToolJsonInstruction(binding);
|
|
380
403
|
const runnable = await this.create(retriedBinding);
|
|
381
|
-
result = (await runnable.invoke({ messages: this.
|
|
404
|
+
result = (await runnable.invoke({ messages: this.buildAgentMessages(history, input) }, { configurable: { thread_id: threadId } }));
|
|
382
405
|
}
|
|
383
406
|
const interruptContent = Array.isArray(result.__interrupt__) && result.__interrupt__.length > 0 ? JSON.stringify(result.__interrupt__) : undefined;
|
|
384
407
|
const extractedOutput = extractVisibleOutput(result);
|
|
@@ -414,7 +437,7 @@ export class AgentRuntimeAdapter {
|
|
|
414
437
|
// agent loop and only adds an extra model round-trip before the runnable path.
|
|
415
438
|
if (canUseDirectModelStream && typeof model.stream === "function") {
|
|
416
439
|
let emitted = false;
|
|
417
|
-
const stream = await model.stream(this.
|
|
440
|
+
const stream = await model.stream(this.buildRawModelMessages(binding.langchainAgentParams.systemPrompt, history, input));
|
|
418
441
|
for await (const chunk of stream) {
|
|
419
442
|
const delta = readStreamDelta(chunk);
|
|
420
443
|
if (delta) {
|
|
@@ -433,7 +456,7 @@ export class AgentRuntimeAdapter {
|
|
|
433
456
|
}
|
|
434
457
|
}
|
|
435
458
|
const runnable = await this.create(binding);
|
|
436
|
-
const request = { messages: this.
|
|
459
|
+
const request = { messages: this.buildAgentMessages(history, input) };
|
|
437
460
|
if (typeof runnable.streamEvents === "function") {
|
|
438
461
|
const events = await runnable.streamEvents(request, { configurable: { thread_id: threadId }, version: "v2" });
|
|
439
462
|
let terminalOutput = "";
|
|
@@ -500,6 +523,11 @@ export class AgentRuntimeAdapter {
|
|
|
500
523
|
}
|
|
501
524
|
}
|
|
502
525
|
catch (error) {
|
|
526
|
+
if (countConfiguredTools(binding) > 0 &&
|
|
527
|
+
error instanceof Error &&
|
|
528
|
+
error.message.includes("does not support tool binding")) {
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
503
531
|
if (!isToolCallParseFailure(error)) {
|
|
504
532
|
throw error;
|
|
505
533
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { modelCallLimitMiddleware, modelRetryMiddleware, summarizationMiddleware, todoListMiddleware, toolCallLimitMiddleware, toolRetryMiddleware, } from "langchain";
|
|
2
|
+
function asMiddlewareConfig(value) {
|
|
3
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? { ...value } : null;
|
|
4
|
+
}
|
|
5
|
+
function requireKind(config) {
|
|
6
|
+
const kind = typeof config.kind === "string" ? config.kind.trim() : "";
|
|
7
|
+
if (!kind) {
|
|
8
|
+
throw new Error("Declarative middleware entries must include a non-empty kind");
|
|
9
|
+
}
|
|
10
|
+
return kind;
|
|
11
|
+
}
|
|
12
|
+
function omitKind(config) {
|
|
13
|
+
const { kind: _kind, ...rest } = config;
|
|
14
|
+
return rest;
|
|
15
|
+
}
|
|
16
|
+
export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
|
|
17
|
+
const resolved = [];
|
|
18
|
+
for (const rawConfig of middlewareConfigs ?? []) {
|
|
19
|
+
const config = asMiddlewareConfig(rawConfig);
|
|
20
|
+
if (!config) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const kind = requireKind(config);
|
|
24
|
+
const runtimeConfig = omitKind(config);
|
|
25
|
+
switch (kind) {
|
|
26
|
+
case "summarization": {
|
|
27
|
+
if (runtimeConfig.model && typeof runtimeConfig.model === "object" && runtimeConfig.model !== null && "id" in runtimeConfig.model) {
|
|
28
|
+
runtimeConfig.model = await options.resolveModel(runtimeConfig.model);
|
|
29
|
+
}
|
|
30
|
+
if (runtimeConfig.model === undefined) {
|
|
31
|
+
throw new Error("summarization middleware requires model or modelRef");
|
|
32
|
+
}
|
|
33
|
+
resolved.push(summarizationMiddleware(runtimeConfig));
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
case "modelRetry":
|
|
37
|
+
resolved.push(modelRetryMiddleware(runtimeConfig));
|
|
38
|
+
break;
|
|
39
|
+
case "toolRetry":
|
|
40
|
+
resolved.push(toolRetryMiddleware(runtimeConfig));
|
|
41
|
+
break;
|
|
42
|
+
case "toolCallLimit":
|
|
43
|
+
resolved.push(toolCallLimitMiddleware(runtimeConfig));
|
|
44
|
+
break;
|
|
45
|
+
case "modelCallLimit":
|
|
46
|
+
resolved.push(modelCallLimitMiddleware(runtimeConfig));
|
|
47
|
+
break;
|
|
48
|
+
case "todoList":
|
|
49
|
+
resolved.push(todoListMiddleware(runtimeConfig));
|
|
50
|
+
break;
|
|
51
|
+
default:
|
|
52
|
+
throw new Error(`Unsupported declarative middleware kind ${kind}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return resolved;
|
|
56
|
+
}
|
|
@@ -30,6 +30,19 @@ function requireModel(models, ref, ownerId) {
|
|
|
30
30
|
}
|
|
31
31
|
return compileModel(model);
|
|
32
32
|
}
|
|
33
|
+
function compileMiddlewareConfigs(middleware, models, ownerId) {
|
|
34
|
+
if (!middleware || middleware.length === 0) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
return middleware.map((config) => {
|
|
38
|
+
const compiled = { ...config };
|
|
39
|
+
if (compiled.kind === "summarization" && typeof compiled.modelRef === "string") {
|
|
40
|
+
compiled.model = requireModel(models, compiled.modelRef, ownerId);
|
|
41
|
+
delete compiled.modelRef;
|
|
42
|
+
}
|
|
43
|
+
return compiled;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
33
46
|
function resolveAgentRuntimeName(agent) {
|
|
34
47
|
const baseName = agent.id;
|
|
35
48
|
if (baseName.includes(".")) {
|
|
@@ -72,6 +85,9 @@ function buildSubagent(agent, workspaceRoot, models, tools, parentSkills, parent
|
|
|
72
85
|
interruptOn: agent.deepAgentConfig?.interruptOn,
|
|
73
86
|
skills: compileAgentSkills(workspaceRoot, agent, parentSkills),
|
|
74
87
|
memory: ownMemory.length > 0 ? ownMemory : parentMemory,
|
|
88
|
+
responseFormat: agent.deepAgentConfig?.responseFormat,
|
|
89
|
+
contextSchema: agent.deepAgentConfig?.contextSchema,
|
|
90
|
+
middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
|
|
75
91
|
};
|
|
76
92
|
}
|
|
77
93
|
function resolveDirectPrompt(agent) {
|
|
@@ -148,6 +164,9 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
148
164
|
model: compiledAgentModel,
|
|
149
165
|
tools: requireTools(tools, agent.toolRefs, agent.id),
|
|
150
166
|
systemPrompt: resolveSystemPrompt(agent),
|
|
167
|
+
responseFormat: agent.langchainAgentConfig?.responseFormat,
|
|
168
|
+
contextSchema: agent.langchainAgentConfig?.contextSchema,
|
|
169
|
+
middleware: compileMiddlewareConfigs(agent.langchainAgentConfig?.middleware, models, agent.id),
|
|
151
170
|
description: agent.description,
|
|
152
171
|
};
|
|
153
172
|
return {
|
|
@@ -162,6 +181,9 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
162
181
|
model: compiledAgentModel,
|
|
163
182
|
tools: requireTools(tools, agent.toolRefs, agent.id),
|
|
164
183
|
systemPrompt: resolveSystemPrompt(agent),
|
|
184
|
+
responseFormat: agent.deepAgentConfig?.responseFormat,
|
|
185
|
+
contextSchema: agent.deepAgentConfig?.contextSchema,
|
|
186
|
+
middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
|
|
165
187
|
description: agent.description,
|
|
166
188
|
subagents: agent.subagentRefs.map((ref) => {
|
|
167
189
|
const subagent = agents.get(resolveRefId(ref));
|
|
@@ -174,6 +174,12 @@ function readSingleRef(value) {
|
|
|
174
174
|
}
|
|
175
175
|
return undefined;
|
|
176
176
|
}
|
|
177
|
+
function readMiddlewareArray(items) {
|
|
178
|
+
const middleware = toArray(items)
|
|
179
|
+
.filter((item) => typeof item === "object" && item !== null && !Array.isArray(item))
|
|
180
|
+
.map((item) => ({ ...item }));
|
|
181
|
+
return middleware.length > 0 ? middleware : undefined;
|
|
182
|
+
}
|
|
177
183
|
export function parseAgentItem(item, sourcePath) {
|
|
178
184
|
const subagentRefs = readRefArray(item.subagents);
|
|
179
185
|
const subagentPathRefs = readPathArray(item.subagents);
|
|
@@ -193,11 +199,19 @@ export function parseAgentItem(item, sourcePath) {
|
|
|
193
199
|
subagentRefs,
|
|
194
200
|
subagentPathRefs,
|
|
195
201
|
langchainAgentConfig: {
|
|
196
|
-
...(typeof item.systemPrompt === "string" ||
|
|
202
|
+
...(typeof item.systemPrompt === "string" ||
|
|
203
|
+
typeof item.interruptOn === "object" ||
|
|
204
|
+
typeof item.checkpointer === "object" ||
|
|
205
|
+
item.responseFormat !== undefined ||
|
|
206
|
+
item.contextSchema !== undefined ||
|
|
207
|
+
item.middleware !== undefined
|
|
197
208
|
? {
|
|
198
209
|
...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
|
|
199
210
|
...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
|
|
200
211
|
...(typeof item.checkpointer === "object" && item.checkpointer ? { checkpointer: item.checkpointer } : {}),
|
|
212
|
+
...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
|
|
213
|
+
...(item.contextSchema !== undefined ? { contextSchema: item.contextSchema } : {}),
|
|
214
|
+
...(readMiddlewareArray(item.middleware) ? { middleware: readMiddlewareArray(item.middleware) } : {}),
|
|
201
215
|
}
|
|
202
216
|
: {}),
|
|
203
217
|
},
|
|
@@ -206,13 +220,19 @@ export function parseAgentItem(item, sourcePath) {
|
|
|
206
220
|
typeof item.backend === "object" ||
|
|
207
221
|
typeof item.store === "object" ||
|
|
208
222
|
typeof item.checkpointer === "object" ||
|
|
209
|
-
typeof item.interruptOn === "object"
|
|
223
|
+
typeof item.interruptOn === "object" ||
|
|
224
|
+
item.responseFormat !== undefined ||
|
|
225
|
+
item.contextSchema !== undefined ||
|
|
226
|
+
item.middleware !== undefined
|
|
210
227
|
? {
|
|
211
228
|
...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
|
|
212
229
|
...(typeof item.backend === "object" && item.backend ? { backend: item.backend } : {}),
|
|
213
230
|
...(typeof item.store === "object" && item.store ? { store: item.store } : {}),
|
|
214
231
|
...(typeof item.checkpointer === "object" && item.checkpointer ? { checkpointer: item.checkpointer } : {}),
|
|
215
232
|
...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
|
|
233
|
+
...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
|
|
234
|
+
...(item.contextSchema !== undefined ? { contextSchema: item.contextSchema } : {}),
|
|
235
|
+
...(readMiddlewareArray(item.middleware) ? { middleware: readMiddlewareArray(item.middleware) } : {}),
|
|
216
236
|
}
|
|
217
237
|
: {}),
|
|
218
238
|
},
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
const allowedExecutionModes = new Set(["deepagent", "langchain-v1"]);
|
|
2
|
+
const allowedMiddlewareKinds = new Set([
|
|
3
|
+
"summarization",
|
|
4
|
+
"modelRetry",
|
|
5
|
+
"toolRetry",
|
|
6
|
+
"toolCallLimit",
|
|
7
|
+
"modelCallLimit",
|
|
8
|
+
"todoList",
|
|
9
|
+
]);
|
|
2
10
|
function hasPromptContent(value) {
|
|
3
11
|
return typeof value === "string" && value.trim().length > 0;
|
|
4
12
|
}
|
|
@@ -15,6 +23,25 @@ function validateCheckpointerConfig(agent) {
|
|
|
15
23
|
throw new Error(`Agent ${agent.id} checkpointer.path is not supported for kind MemorySaver`);
|
|
16
24
|
}
|
|
17
25
|
}
|
|
26
|
+
function validateMiddlewareConfig(agent) {
|
|
27
|
+
const middlewareConfigs = [
|
|
28
|
+
...(agent.langchainAgentConfig?.middleware ?? []),
|
|
29
|
+
...(agent.deepAgentConfig?.middleware ?? []),
|
|
30
|
+
];
|
|
31
|
+
for (const config of middlewareConfigs) {
|
|
32
|
+
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
33
|
+
throw new Error(`Agent ${agent.id} middleware entries must be objects`);
|
|
34
|
+
}
|
|
35
|
+
const typed = config;
|
|
36
|
+
const kind = typeof typed.kind === "string" ? typed.kind : "";
|
|
37
|
+
if (!allowedMiddlewareKinds.has(kind)) {
|
|
38
|
+
throw new Error(`Agent ${agent.id} middleware kind ${kind || "(missing)"} is not supported`);
|
|
39
|
+
}
|
|
40
|
+
if (kind === "summarization" && typed.model === undefined && typeof typed.modelRef !== "string") {
|
|
41
|
+
throw new Error(`Agent ${agent.id} summarization middleware requires model or modelRef`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
18
45
|
export function validateAgent(agent) {
|
|
19
46
|
if (!agent.id) {
|
|
20
47
|
throw new Error(`Agent id is required in ${agent.sourcePath}`);
|
|
@@ -35,6 +62,7 @@ export function validateAgent(agent) {
|
|
|
35
62
|
throw new Error(`Agent ${agent.id} must use deepagent execution when subagents are defined`);
|
|
36
63
|
}
|
|
37
64
|
validateCheckpointerConfig(agent);
|
|
65
|
+
validateMiddlewareConfig(agent);
|
|
38
66
|
}
|
|
39
67
|
export function validateTopology(agents) {
|
|
40
68
|
const ids = new Set();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botbotgo/agent-harness",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Agent Harness framework package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@10.9.2",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -p tsconfig.json && cp -R config dist/",
|
|
45
45
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
46
|
-
"test": "vitest run test/public-api.test.ts test/resource-optional-provider.test.ts test/stock-research-app-load-harness.test.ts test/release-workflow.test.ts test/release-version.test.ts test/gitignore.test.ts test/package-lock.test.ts test/readme.test.ts",
|
|
46
|
+
"test": "vitest run test/public-api.test.ts test/resource-optional-provider.test.ts test/stock-research-app-load-harness.test.ts test/release-workflow.test.ts test/release-version.test.ts test/gitignore.test.ts test/package-lock.test.ts test/readme.test.ts test/runtime-adapter-regressions.test.ts",
|
|
47
47
|
"release:prepare": "npm version patch --no-git-tag-version && node ./scripts/sync-example-version.mjs",
|
|
48
48
|
"release:pack": "npm pack --dry-run",
|
|
49
49
|
"release:publish": "npm publish --access public --registry https://registry.npmjs.org/"
|