@botbotgo/agent-harness 0.0.14 → 0.0.15

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.
@@ -73,6 +73,8 @@ export type LangChainAgentParams = {
73
73
  model: CompiledModel;
74
74
  tools: CompiledTool[];
75
75
  systemPrompt?: string;
76
+ responseFormat?: unknown;
77
+ contextSchema?: unknown;
76
78
  description: string;
77
79
  };
78
80
  export type CompiledSubAgent = {
@@ -84,11 +86,15 @@ export type CompiledSubAgent = {
84
86
  interruptOn?: Record<string, boolean | object>;
85
87
  skills?: string[];
86
88
  memory?: string[];
89
+ responseFormat?: unknown;
90
+ contextSchema?: unknown;
87
91
  };
88
92
  export type DeepAgentParams = {
89
93
  model: CompiledModel;
90
94
  tools: CompiledTool[];
91
95
  systemPrompt?: string;
96
+ responseFormat?: unknown;
97
+ contextSchema?: unknown;
92
98
  description: string;
93
99
  subagents: CompiledSubAgent[];
94
100
  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;
@@ -76,6 +76,9 @@ function wrapResolvedToolWithModelFacingName(resolvedTool, modelFacingName) {
76
76
  },
77
77
  });
78
78
  }
79
+ function countConfiguredTools(binding) {
80
+ return binding.langchainAgentParams?.tools.length ?? binding.deepAgentParams?.tools.length ?? 0;
81
+ }
79
82
  export class AgentRuntimeAdapter {
80
83
  options;
81
84
  constructor(options = {}) {
@@ -197,6 +200,20 @@ export class AgentRuntimeAdapter {
197
200
  buildToolNameMapping(tools) {
198
201
  return buildToolNameMapping(tools);
199
202
  }
203
+ buildAgentMessages(history, input) {
204
+ return [
205
+ ...history.map((item) => ({ role: item.role, content: item.content })),
206
+ { role: "user", content: input },
207
+ ];
208
+ }
209
+ buildRawModelMessages(systemPrompt, history, input) {
210
+ const messages = [];
211
+ if (systemPrompt) {
212
+ messages.push({ role: "system", content: systemPrompt });
213
+ }
214
+ messages.push(...this.buildAgentMessages(history, input));
215
+ return messages;
216
+ }
200
217
  resolveTools(tools, binding) {
201
218
  const resolved = this.options.toolResolver ? this.options.toolResolver(tools.map((tool) => tool.id), binding) : [];
202
219
  const toolNameMapping = this.buildToolNameMapping(tools);
@@ -285,31 +302,24 @@ export class AgentRuntimeAdapter {
285
302
  model: subagent.model ? (await this.resolveModel(subagent.model)) : undefined,
286
303
  tools: subagent.tools ? this.resolveTools(subagent.tools) : undefined,
287
304
  interruptOn: this.compileInterruptOn(subagent.tools ?? [], subagent.interruptOn),
305
+ responseFormat: subagent.responseFormat,
306
+ contextSchema: subagent.contextSchema,
288
307
  })));
289
308
  }
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
309
  async create(binding) {
302
310
  if (binding.langchainAgentParams) {
303
311
  const interruptOn = this.resolveInterruptOn(binding);
304
312
  const model = (await this.resolveModel(binding.langchainAgentParams.model));
305
313
  const tools = this.resolveTools(binding.langchainAgentParams.tools, binding);
306
314
  if (tools.length > 0 && typeof model.bindTools !== "function") {
307
- return this.createModelFallbackRunnable(model);
315
+ 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
316
  }
309
317
  return createAgent({
310
318
  model: model,
311
319
  tools: tools,
312
320
  systemPrompt: binding.langchainAgentParams.systemPrompt,
321
+ responseFormat: binding.langchainAgentParams.responseFormat,
322
+ contextSchema: binding.langchainAgentParams.contextSchema,
313
323
  middleware: this.resolveMiddleware(binding, interruptOn),
314
324
  checkpointer: this.resolveCheckpointer(binding),
315
325
  });
@@ -322,6 +332,8 @@ export class AgentRuntimeAdapter {
322
332
  model: (await this.resolveModel(params.model)),
323
333
  tools: this.resolveTools(params.tools, binding),
324
334
  systemPrompt: params.systemPrompt,
335
+ responseFormat: params.responseFormat,
336
+ contextSchema: params.contextSchema,
325
337
  middleware: this.resolveMiddleware(binding),
326
338
  subagents: (await this.resolveSubagents(params.subagents)),
327
339
  checkpointer: this.resolveCheckpointer(binding),
@@ -365,7 +377,7 @@ export class AgentRuntimeAdapter {
365
377
  }
366
378
  async invoke(binding, input, threadId, runId, resumePayload, history = []) {
367
379
  const request = resumePayload === undefined
368
- ? { messages: this.buildConversation(binding.langchainAgentParams?.systemPrompt ?? binding.deepAgentParams?.systemPrompt, history, input) }
380
+ ? { messages: this.buildAgentMessages(history, input) }
369
381
  : new Command({ resume: resumePayload });
370
382
  let result;
371
383
  try {
@@ -378,7 +390,7 @@ export class AgentRuntimeAdapter {
378
390
  }
379
391
  const retriedBinding = this.applyStrictToolJsonInstruction(binding);
380
392
  const runnable = await this.create(retriedBinding);
381
- result = (await runnable.invoke({ messages: this.buildConversation(retriedBinding.langchainAgentParams?.systemPrompt ?? retriedBinding.deepAgentParams?.systemPrompt, history, input) }, { configurable: { thread_id: threadId } }));
393
+ result = (await runnable.invoke({ messages: this.buildAgentMessages(history, input) }, { configurable: { thread_id: threadId } }));
382
394
  }
383
395
  const interruptContent = Array.isArray(result.__interrupt__) && result.__interrupt__.length > 0 ? JSON.stringify(result.__interrupt__) : undefined;
384
396
  const extractedOutput = extractVisibleOutput(result);
@@ -414,7 +426,7 @@ export class AgentRuntimeAdapter {
414
426
  // agent loop and only adds an extra model round-trip before the runnable path.
415
427
  if (canUseDirectModelStream && typeof model.stream === "function") {
416
428
  let emitted = false;
417
- const stream = await model.stream(this.buildConversation(binding.langchainAgentParams.systemPrompt, history, input));
429
+ const stream = await model.stream(this.buildRawModelMessages(binding.langchainAgentParams.systemPrompt, history, input));
418
430
  for await (const chunk of stream) {
419
431
  const delta = readStreamDelta(chunk);
420
432
  if (delta) {
@@ -433,7 +445,7 @@ export class AgentRuntimeAdapter {
433
445
  }
434
446
  }
435
447
  const runnable = await this.create(binding);
436
- const request = { messages: this.buildConversation(binding.deepAgentParams?.systemPrompt, history, input) };
448
+ const request = { messages: this.buildAgentMessages(history, input) };
437
449
  if (typeof runnable.streamEvents === "function") {
438
450
  const events = await runnable.streamEvents(request, { configurable: { thread_id: threadId }, version: "v2" });
439
451
  let terminalOutput = "";
@@ -500,6 +512,11 @@ export class AgentRuntimeAdapter {
500
512
  }
501
513
  }
502
514
  catch (error) {
515
+ if (countConfiguredTools(binding) > 0 &&
516
+ error instanceof Error &&
517
+ error.message.includes("does not support tool binding")) {
518
+ throw error;
519
+ }
503
520
  if (!isToolCallParseFailure(error)) {
504
521
  throw error;
505
522
  }
@@ -72,6 +72,8 @@ function buildSubagent(agent, workspaceRoot, models, tools, parentSkills, parent
72
72
  interruptOn: agent.deepAgentConfig?.interruptOn,
73
73
  skills: compileAgentSkills(workspaceRoot, agent, parentSkills),
74
74
  memory: ownMemory.length > 0 ? ownMemory : parentMemory,
75
+ responseFormat: agent.deepAgentConfig?.responseFormat,
76
+ contextSchema: agent.deepAgentConfig?.contextSchema,
75
77
  };
76
78
  }
77
79
  function resolveDirectPrompt(agent) {
@@ -148,6 +150,8 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
148
150
  model: compiledAgentModel,
149
151
  tools: requireTools(tools, agent.toolRefs, agent.id),
150
152
  systemPrompt: resolveSystemPrompt(agent),
153
+ responseFormat: agent.langchainAgentConfig?.responseFormat,
154
+ contextSchema: agent.langchainAgentConfig?.contextSchema,
151
155
  description: agent.description,
152
156
  };
153
157
  return {
@@ -162,6 +166,8 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
162
166
  model: compiledAgentModel,
163
167
  tools: requireTools(tools, agent.toolRefs, agent.id),
164
168
  systemPrompt: resolveSystemPrompt(agent),
169
+ responseFormat: agent.deepAgentConfig?.responseFormat,
170
+ contextSchema: agent.deepAgentConfig?.contextSchema,
165
171
  description: agent.description,
166
172
  subagents: agent.subagentRefs.map((ref) => {
167
173
  const subagent = agents.get(resolveRefId(ref));
@@ -193,11 +193,17 @@ export function parseAgentItem(item, sourcePath) {
193
193
  subagentRefs,
194
194
  subagentPathRefs,
195
195
  langchainAgentConfig: {
196
- ...(typeof item.systemPrompt === "string" || typeof item.interruptOn === "object" || typeof item.checkpointer === "object"
196
+ ...(typeof item.systemPrompt === "string" ||
197
+ typeof item.interruptOn === "object" ||
198
+ typeof item.checkpointer === "object" ||
199
+ item.responseFormat !== undefined ||
200
+ item.contextSchema !== undefined
197
201
  ? {
198
202
  ...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
199
203
  ...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
200
204
  ...(typeof item.checkpointer === "object" && item.checkpointer ? { checkpointer: item.checkpointer } : {}),
205
+ ...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
206
+ ...(item.contextSchema !== undefined ? { contextSchema: item.contextSchema } : {}),
201
207
  }
202
208
  : {}),
203
209
  },
@@ -206,13 +212,17 @@ export function parseAgentItem(item, sourcePath) {
206
212
  typeof item.backend === "object" ||
207
213
  typeof item.store === "object" ||
208
214
  typeof item.checkpointer === "object" ||
209
- typeof item.interruptOn === "object"
215
+ typeof item.interruptOn === "object" ||
216
+ item.responseFormat !== undefined ||
217
+ item.contextSchema !== undefined
210
218
  ? {
211
219
  ...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
212
220
  ...(typeof item.backend === "object" && item.backend ? { backend: item.backend } : {}),
213
221
  ...(typeof item.store === "object" && item.store ? { store: item.store } : {}),
214
222
  ...(typeof item.checkpointer === "object" && item.checkpointer ? { checkpointer: item.checkpointer } : {}),
215
223
  ...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
224
+ ...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
225
+ ...(item.contextSchema !== undefined ? { contextSchema: item.contextSchema } : {}),
216
226
  }
217
227
  : {}),
218
228
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
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/"