@cognipeer/agent-sdk 0.5.2 → 0.5.4
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/README.md +21 -1
- package/dist/index.cjs +136 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.mjs +136 -27
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,7 +136,16 @@ const agent = createSmartAgent({
|
|
|
136
136
|
memory: { provider: "inMemory", scope: "session", writePolicy: "auto_important" },
|
|
137
137
|
summarization: { summaryTriggerTokens: 8000, summaryMode: "incremental" },
|
|
138
138
|
context: { policy: "hybrid", lastTurnsToKeep: 8 },
|
|
139
|
-
toolResponses: {
|
|
139
|
+
toolResponses: {
|
|
140
|
+
smallResponseChars: 1200,
|
|
141
|
+
smallResponsePolicy: "keep_full",
|
|
142
|
+
defaultPolicy: "keep_structured",
|
|
143
|
+
largeResponsePolicy: "summarize_archive",
|
|
144
|
+
fallbackPolicy: "keep_full",
|
|
145
|
+
keepRecentFullCount: 2,
|
|
146
|
+
maxToolResponseChars: 4000,
|
|
147
|
+
maxToolResponseTokens: 1200,
|
|
148
|
+
},
|
|
140
149
|
limits: { maxToolCalls: 5, maxContextTokens: 12000 },
|
|
141
150
|
tracing: { enabled: true },
|
|
142
151
|
});
|
|
@@ -149,6 +158,16 @@ const result = await agent.invoke({
|
|
|
149
158
|
console.log(result.content);
|
|
150
159
|
```
|
|
151
160
|
|
|
161
|
+
Tool-response retention is size-aware and composable:
|
|
162
|
+
|
|
163
|
+
- `smallResponseChars` + `smallResponsePolicy` define how very small payloads are kept.
|
|
164
|
+
- `defaultPolicy` handles normal informative outputs.
|
|
165
|
+
- `largeResponsePolicy` handles verbose outputs that cross the max char/token thresholds.
|
|
166
|
+
- `fallbackPolicy` applies to critical tools and now defaults to `keep_full` so safety-critical payloads are not collapsed accidentally.
|
|
167
|
+
- `keepRecentFullCount` pins the last N successful tool responses at full content during context assembly and excludes them from summarization passes.
|
|
168
|
+
|
|
169
|
+
Resolution order is: per-tool override, then critical fallback, then large/small classification, then the default policy. Redundant payloads like `ok`, `true`, and `null` are dropped automatically.
|
|
170
|
+
|
|
152
171
|
The smart wrapper now supports runtime presets (`fast`, `balanced`, `deep`, `research`), custom profiles layered on top of a base preset, structured summarization, hybrid context compaction, configurable tool-response retention, in-memory fact storage, delegation limits, and an eval harness via `runSmartAgentEvalHarness(...)`.
|
|
153
172
|
|
|
154
173
|
You can also define a custom profile by extending a built-in preset and overriding only the knobs you need:
|
|
@@ -201,6 +220,7 @@ console.log(res.content);
|
|
|
201
220
|
- **Native provider layer** – call OpenAI, Anthropic, Azure, Bedrock, Vertex, and any OpenAI-compatible API directly. No LangChain required. Unified `ChatCompletionRequest` / `ChatCompletionResponse` schema with per-provider wire format conversion.
|
|
202
221
|
- **Full token tracking** – every response surfaces `inputTokens`, `outputTokens`, `cachedInputTokens`, `cachedWriteTokens`, and `reasoningTokens` for all six providers.
|
|
203
222
|
- **Summarization pipeline** – automatic chunking keeps tool call history within `contextTokenLimit` / `summaryTokenLimit`, archiving originals so `get_tool_response` can fetch them later.
|
|
223
|
+
- **Retention controls** – tool outputs can be kept full, reduced to structured previews, archived, or dropped based on size tiers, critical-tool fallback, per-tool overrides, and recent-response pinning.
|
|
204
224
|
- **Planning discipline** – when planning is enabled the system prompt distinguishes full plan writes from incremental plan updates and emits `plan` events as todos change.
|
|
205
225
|
- **Structured output** – supply `outputSchema` and the framework adds a hidden `response` finalize tool; parsed JSON is returned as `result.output`.
|
|
206
226
|
- **Multi-agent orchestration** – reuse agents via `agent.asTool({ toolName })` or perform handoffs that swap runtimes mid-execution.
|
package/dist/index.cjs
CHANGED
|
@@ -2138,13 +2138,16 @@ var BASE_DEFAULTS = {
|
|
|
2138
2138
|
toolResponses: {
|
|
2139
2139
|
maxToolResponseChars: 3600,
|
|
2140
2140
|
maxToolResponseTokens: 1200,
|
|
2141
|
+
smallResponseChars: 0,
|
|
2142
|
+
smallResponsePolicy: "keep_full",
|
|
2141
2143
|
defaultPolicy: "keep_structured",
|
|
2142
2144
|
largeResponsePolicy: "summarize_archive",
|
|
2143
2145
|
toolResponseRetentionByTool: {},
|
|
2144
2146
|
criticalTools: [...DEFAULT_CRITICAL_TOOLS],
|
|
2145
2147
|
schemaValidation: "strict",
|
|
2146
2148
|
retryOnSchemaError: true,
|
|
2147
|
-
fallbackPolicy: "
|
|
2149
|
+
fallbackPolicy: "keep_full",
|
|
2150
|
+
keepRecentFullCount: 0
|
|
2148
2151
|
}
|
|
2149
2152
|
};
|
|
2150
2153
|
function buildProfile(overrides) {
|
|
@@ -2427,11 +2430,15 @@ function classifyToolResponse(toolName, output, config) {
|
|
|
2427
2430
|
const tokenCount = countApproxTokens(serialized);
|
|
2428
2431
|
const criticalTools = new Set(config.toolResponses.criticalTools);
|
|
2429
2432
|
if (criticalTools.has(toolName)) return "critical";
|
|
2433
|
+
if (serialized === "ok" || serialized === "true" || serialized === "null") {
|
|
2434
|
+
return "redundant";
|
|
2435
|
+
}
|
|
2430
2436
|
if (tokenCount >= config.toolResponses.maxToolResponseTokens || serialized.length >= config.toolResponses.maxToolResponseChars) {
|
|
2431
2437
|
return "verbose";
|
|
2432
2438
|
}
|
|
2433
|
-
|
|
2434
|
-
|
|
2439
|
+
const smallChars = config.toolResponses.smallResponseChars;
|
|
2440
|
+
if (smallChars > 0 && serialized.length <= smallChars) {
|
|
2441
|
+
return "small";
|
|
2435
2442
|
}
|
|
2436
2443
|
return "informative";
|
|
2437
2444
|
}
|
|
@@ -2441,12 +2448,14 @@ function resolveToolResponsePolicy(toolName, output, config) {
|
|
|
2441
2448
|
const classification = classifyToolResponse(toolName, output, config);
|
|
2442
2449
|
const byTool = config.toolResponses.toolResponseRetentionByTool[toolName];
|
|
2443
2450
|
let retentionPolicy = byTool || config.toolResponses.defaultPolicy;
|
|
2444
|
-
if (classification === "critical") {
|
|
2445
|
-
retentionPolicy =
|
|
2451
|
+
if (byTool) ; else if (classification === "critical") {
|
|
2452
|
+
retentionPolicy = config.toolResponses.fallbackPolicy;
|
|
2446
2453
|
} else if (classification === "verbose") {
|
|
2447
|
-
retentionPolicy =
|
|
2454
|
+
retentionPolicy = config.toolResponses.largeResponsePolicy;
|
|
2455
|
+
} else if (classification === "small") {
|
|
2456
|
+
retentionPolicy = config.toolResponses.smallResponsePolicy;
|
|
2448
2457
|
} else if (classification === "redundant") {
|
|
2449
|
-
retentionPolicy =
|
|
2458
|
+
retentionPolicy = "drop";
|
|
2450
2459
|
}
|
|
2451
2460
|
const summary = summarizeObject(output);
|
|
2452
2461
|
if (retentionPolicy === "keep_full") {
|
|
@@ -2792,10 +2801,10 @@ function createToolsNode(initialTools, opts) {
|
|
|
2792
2801
|
let toolMessageContent = responsePolicy.content;
|
|
2793
2802
|
if (responsePolicy.retentionPolicy === "summarize_archive") {
|
|
2794
2803
|
toolMessageContent = `ARCHIVED_TOOL_RESPONSE [executionId=${executionId}]: ${responsePolicy.summary}
|
|
2795
|
-
|
|
2804
|
+
Only use get_tool_response with executionId "${executionId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
2796
2805
|
} else if (responsePolicy.retentionPolicy === "drop") {
|
|
2797
2806
|
toolMessageContent = `DROPPED_TOOL_RESPONSE [executionId=${executionId}]: ${responsePolicy.summary}
|
|
2798
|
-
|
|
2807
|
+
Only use get_tool_response with executionId "${executionId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
2799
2808
|
}
|
|
2800
2809
|
appended.push({ role: "tool", content: toolMessageContent, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
|
|
2801
2810
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: output, durationMs });
|
|
@@ -3981,6 +3990,40 @@ function createAgentNode(opts) {
|
|
|
3981
3990
|
}
|
|
3982
3991
|
|
|
3983
3992
|
// src/smart/contextPolicy.ts
|
|
3993
|
+
function collectRecentFullToolCallIds(state, keepRecentFullCount) {
|
|
3994
|
+
if (!keepRecentFullCount || keepRecentFullCount <= 0) return /* @__PURE__ */ new Set();
|
|
3995
|
+
const history = state.toolHistory || [];
|
|
3996
|
+
const ids = [];
|
|
3997
|
+
for (let index = history.length - 1; index >= 0 && ids.length < keepRecentFullCount; index -= 1) {
|
|
3998
|
+
const entry = history[index];
|
|
3999
|
+
if (!entry || !entry.tool_call_id) continue;
|
|
4000
|
+
if (entry.status && entry.status !== "success") continue;
|
|
4001
|
+
ids.push(entry.tool_call_id);
|
|
4002
|
+
}
|
|
4003
|
+
return new Set(ids);
|
|
4004
|
+
}
|
|
4005
|
+
function applyRecentFullOverride(messages, state, config) {
|
|
4006
|
+
const keepN = config.toolResponses.keepRecentFullCount;
|
|
4007
|
+
if (!keepN || keepN <= 0) return messages;
|
|
4008
|
+
const recentIds = collectRecentFullToolCallIds(state, keepN);
|
|
4009
|
+
if (recentIds.size === 0) return messages;
|
|
4010
|
+
const history = state.toolHistory || [];
|
|
4011
|
+
const byCallId = /* @__PURE__ */ new Map();
|
|
4012
|
+
for (const entry of history) {
|
|
4013
|
+
if (entry?.tool_call_id) byCallId.set(entry.tool_call_id, entry);
|
|
4014
|
+
}
|
|
4015
|
+
return messages.map((message) => {
|
|
4016
|
+
if (message.role !== "tool" || !message.tool_call_id) return message;
|
|
4017
|
+
if (!recentIds.has(message.tool_call_id)) return message;
|
|
4018
|
+
const entry = byCallId.get(message.tool_call_id);
|
|
4019
|
+
if (!entry) return message;
|
|
4020
|
+
const raw = entry.rawOutput ?? entry.output;
|
|
4021
|
+
if (raw === void 0) return message;
|
|
4022
|
+
const fullContent = typeof raw === "string" ? raw : safeStringify(raw);
|
|
4023
|
+
if (!fullContent || fullContent === message.content) return message;
|
|
4024
|
+
return { ...message, content: fullContent };
|
|
4025
|
+
});
|
|
4026
|
+
}
|
|
3984
4027
|
function collectRecentTurns(messages, lastTurnsToKeep) {
|
|
3985
4028
|
if (lastTurnsToKeep <= 0) return [];
|
|
3986
4029
|
const systemPrefix = messages.filter((message, index) => index === 0 && message.role === "system");
|
|
@@ -4081,7 +4124,7 @@ function clampToBudget(messages, maxContextTokens) {
|
|
|
4081
4124
|
function buildModelMessages(state, config) {
|
|
4082
4125
|
const rawMessages = state.messages || [];
|
|
4083
4126
|
if (config.context.policy === "raw") {
|
|
4084
|
-
return clampToBudget(rawMessages, config.limits.maxContextTokens);
|
|
4127
|
+
return clampToBudget(applyRecentFullOverride(rawMessages, state, config), config.limits.maxContextTokens);
|
|
4085
4128
|
}
|
|
4086
4129
|
const recentMessages = collectRecentTurns(rawMessages, config.context.lastTurnsToKeep);
|
|
4087
4130
|
const latestSummary = state.summaryRecords?.[state.summaryRecords.length - 1];
|
|
@@ -4101,7 +4144,7 @@ function buildModelMessages(state, config) {
|
|
|
4101
4144
|
...syntheticContextMessages,
|
|
4102
4145
|
...config.context.policy === "summary_only" ? body.filter((message) => message.role === "user" || message.role === "assistant").slice(-2) : body
|
|
4103
4146
|
];
|
|
4104
|
-
return clampToBudget(assembled, config.limits.maxContextTokens);
|
|
4147
|
+
return clampToBudget(applyRecentFullOverride(assembled, state, config), config.limits.maxContextTokens);
|
|
4105
4148
|
}
|
|
4106
4149
|
|
|
4107
4150
|
// src/nodes/contextSummarize.ts
|
|
@@ -4257,11 +4300,11 @@ function buildSummarizedToolMessage(message, state) {
|
|
|
4257
4300
|
toolCallId ? `toolCallId=${toolCallId}` : null,
|
|
4258
4301
|
executionId ? `executionId=${executionId}` : null
|
|
4259
4302
|
].filter(Boolean).join("; ");
|
|
4260
|
-
let retrievalHint = "
|
|
4303
|
+
let retrievalHint = "Only use get_tool_response if this summary is missing a specific field, id, snippet, or exact payload you still need.";
|
|
4261
4304
|
if (executionId && toolCallId) {
|
|
4262
|
-
retrievalHint = `
|
|
4305
|
+
retrievalHint = `Only use get_tool_response with executionId "${executionId}" or tool call id "${toolCallId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
4263
4306
|
} else if (executionId || toolCallId) {
|
|
4264
|
-
retrievalHint = `
|
|
4307
|
+
retrievalHint = `Only use get_tool_response with executionId "${executionId || toolCallId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
4265
4308
|
}
|
|
4266
4309
|
return [
|
|
4267
4310
|
`SUMMARIZED_TOOL_RESPONSE [${references}]`,
|
|
@@ -4327,11 +4370,13 @@ function createContextSummarizeNode(opts) {
|
|
|
4327
4370
|
const onEvent = state.ctx?.__onEvent;
|
|
4328
4371
|
const traceSession = state.ctx?.__traceSession;
|
|
4329
4372
|
const toolResponsesConfigEarly = resolved.toolResponses;
|
|
4373
|
+
const recentFullToolCallIdsEarly = collectRecentFullToolCallIds(state, toolResponsesConfigEarly.keepRecentFullCount);
|
|
4330
4374
|
const compressableMessages = messages.filter(
|
|
4331
4375
|
(m) => {
|
|
4332
4376
|
if (m.role !== "tool") return false;
|
|
4333
4377
|
if (isSummarizedToolPlaceholder(m.content)) return false;
|
|
4334
4378
|
if (isSyntheticSummaryMessage(m)) return false;
|
|
4379
|
+
if (m.tool_call_id && recentFullToolCallIdsEarly.has(m.tool_call_id)) return false;
|
|
4335
4380
|
const histEntry = findToolHistoryEntry(state, m.tool_call_id, m.name);
|
|
4336
4381
|
if (histEntry?.retentionPolicy === "keep_full") return false;
|
|
4337
4382
|
if (!histEntry?.retentionPolicy) {
|
|
@@ -4518,6 +4563,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4518
4563
|
}
|
|
4519
4564
|
}
|
|
4520
4565
|
const toolResponsesConfig = resolved.toolResponses;
|
|
4566
|
+
const recentFullToolCallIds = collectRecentFullToolCallIds(state, toolResponsesConfig.keepRecentFullCount);
|
|
4521
4567
|
const newMessages = messages.map((m) => {
|
|
4522
4568
|
if (m.role === "tool") {
|
|
4523
4569
|
if (isSyntheticSummaryMessage(m)) {
|
|
@@ -4529,6 +4575,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4529
4575
|
}
|
|
4530
4576
|
if (isSummarizedToolPlaceholder(m.content)) return m;
|
|
4531
4577
|
if (toolCallId && protectedToolCallIds.has(toolCallId)) return m;
|
|
4578
|
+
if (toolCallId && recentFullToolCallIds.has(toolCallId)) return m;
|
|
4532
4579
|
const toolName = m.name || "";
|
|
4533
4580
|
const historyEntry = findToolHistoryEntry(state, toolCallId, toolName);
|
|
4534
4581
|
const entryRetention = historyEntry?.retentionPolicy;
|
|
@@ -4867,8 +4914,9 @@ function createContextTools(stateRef, opts) {
|
|
|
4867
4914
|
}
|
|
4868
4915
|
const getTool = createTool({
|
|
4869
4916
|
name: "get_tool_response",
|
|
4870
|
-
description: "RETRIEVE the full output of a tool execution whose response was archived, dropped, or later compacted in conversation history. When a tool response appears as 'ARCHIVED_TOOL_RESPONSE [executionId=xxx]', 'DROPPED_TOOL_RESPONSE [executionId=xxx]', or 'SUMMARIZED_TOOL_RESPONSE [...]', pass the referenced executionId to this tool to get the complete data. You can also pass the original tool_call_id from the tool call.",
|
|
4917
|
+
description: "RETRIEVE the full output of a tool execution whose response was archived, dropped, or later compacted in conversation history. Use this only when the preview or summary is missing a specific field, identifier, snippet, or exact payload you still need to finish the task. Do not call it reflexively for every archived response. When a tool response appears as 'ARCHIVED_TOOL_RESPONSE [executionId=xxx]', 'DROPPED_TOOL_RESPONSE [executionId=xxx]', or 'SUMMARIZED_TOOL_RESPONSE [...]', pass the referenced executionId to this tool to get the complete data. You can also pass the original tool_call_id from the tool call.",
|
|
4871
4918
|
schema: zod.z.object({ executionId: zod.z.string().describe("Tool execution id or original tool_call_id") }),
|
|
4919
|
+
maxExecutionsPerRun: 8,
|
|
4872
4920
|
func: async ({ executionId }) => {
|
|
4873
4921
|
const matchesExecution = (t) => t?.executionId === executionId || t?.tool_call_id === executionId;
|
|
4874
4922
|
let execution = stateRef.toolHistory?.find((t) => matchesExecution(t));
|
|
@@ -7124,23 +7172,79 @@ function convertContent(content) {
|
|
|
7124
7172
|
function isZodSchema(obj) {
|
|
7125
7173
|
return obj != null && typeof obj === "object" && typeof obj.safeParse === "function" && "_def" in obj;
|
|
7126
7174
|
}
|
|
7175
|
+
function hasStrictUnsafeShape(node, inProperty = false) {
|
|
7176
|
+
if (!node || typeof node !== "object") return false;
|
|
7177
|
+
if (Array.isArray(node)) {
|
|
7178
|
+
return node.some((item) => hasStrictUnsafeShape(item, inProperty));
|
|
7179
|
+
}
|
|
7180
|
+
if (typeof node.$ref === "string") {
|
|
7181
|
+
return true;
|
|
7182
|
+
}
|
|
7183
|
+
const hasType = typeof node.type === "string" || Array.isArray(node.type) && node.type.length > 0;
|
|
7184
|
+
const hasProperties = !!node.properties && typeof node.properties === "object" && !Array.isArray(node.properties);
|
|
7185
|
+
const hasItems = node.items !== void 0;
|
|
7186
|
+
const hasComposite = ["anyOf", "oneOf", "allOf"].some((key) => Array.isArray(node[key]) && node[key].length > 0);
|
|
7187
|
+
if (inProperty && !hasType && !hasProperties && !hasItems) {
|
|
7188
|
+
return true;
|
|
7189
|
+
}
|
|
7190
|
+
if (inProperty && hasComposite && !hasType) {
|
|
7191
|
+
return true;
|
|
7192
|
+
}
|
|
7193
|
+
if (hasProperties) {
|
|
7194
|
+
for (const value of Object.values(node.properties)) {
|
|
7195
|
+
if (hasStrictUnsafeShape(value, true)) {
|
|
7196
|
+
return true;
|
|
7197
|
+
}
|
|
7198
|
+
}
|
|
7199
|
+
}
|
|
7200
|
+
if (node.items && hasStrictUnsafeShape(node.items, false)) {
|
|
7201
|
+
return true;
|
|
7202
|
+
}
|
|
7203
|
+
for (const key of ["anyOf", "oneOf", "allOf"]) {
|
|
7204
|
+
if (Array.isArray(node[key]) && hasStrictUnsafeShape(node[key], false)) {
|
|
7205
|
+
return true;
|
|
7206
|
+
}
|
|
7207
|
+
}
|
|
7208
|
+
for (const key of ["definitions", "$defs"]) {
|
|
7209
|
+
const defs = node[key];
|
|
7210
|
+
if (defs && typeof defs === "object") {
|
|
7211
|
+
for (const value of Object.values(defs)) {
|
|
7212
|
+
if (hasStrictUnsafeShape(value, false)) {
|
|
7213
|
+
return true;
|
|
7214
|
+
}
|
|
7215
|
+
}
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
return false;
|
|
7219
|
+
}
|
|
7220
|
+
function canUseStrictToolSchema(schema) {
|
|
7221
|
+
if (!schema || typeof schema !== "object") {
|
|
7222
|
+
return true;
|
|
7223
|
+
}
|
|
7224
|
+
if (isZodSchema(schema)) {
|
|
7225
|
+
return true;
|
|
7226
|
+
}
|
|
7227
|
+
return !hasStrictUnsafeShape(schema);
|
|
7228
|
+
}
|
|
7127
7229
|
function convertToJsonSchema(schema, strict = false) {
|
|
7128
7230
|
if (!schema || typeof schema !== "object") {
|
|
7129
7231
|
return { type: "object", properties: {}, required: [], additionalProperties: false };
|
|
7130
7232
|
}
|
|
7131
7233
|
if (isZodSchema(schema)) {
|
|
7132
|
-
const
|
|
7234
|
+
const converted2 = zodToJsonSchema.zodToJsonSchema(schema, {
|
|
7133
7235
|
$refStrategy: "none",
|
|
7134
7236
|
...strict ? { openaiStrictMode: true } : {}
|
|
7135
7237
|
});
|
|
7136
|
-
delete
|
|
7137
|
-
if (!
|
|
7138
|
-
return
|
|
7238
|
+
delete converted2["$schema"];
|
|
7239
|
+
if (!converted2.type) converted2.type = "object";
|
|
7240
|
+
return converted2;
|
|
7139
7241
|
}
|
|
7140
|
-
|
|
7141
|
-
|
|
7242
|
+
const converted = { ...schema };
|
|
7243
|
+
delete converted["$schema"];
|
|
7244
|
+
if (!converted.type && converted.properties) {
|
|
7245
|
+
return { type: "object", ...converted };
|
|
7142
7246
|
}
|
|
7143
|
-
return
|
|
7247
|
+
return converted;
|
|
7144
7248
|
}
|
|
7145
7249
|
function normalizeStrictSchema(schema) {
|
|
7146
7250
|
if (!schema || typeof schema !== "object") return schema;
|
|
@@ -7189,20 +7293,25 @@ function toToolDefinition(tool, strict) {
|
|
|
7189
7293
|
let name;
|
|
7190
7294
|
let description;
|
|
7191
7295
|
let parameters;
|
|
7296
|
+
let rawSchema;
|
|
7297
|
+
let useStrict = strict ?? false;
|
|
7192
7298
|
if (tool.type === "function" && tool.function) {
|
|
7193
7299
|
name = tool.function.name;
|
|
7194
7300
|
description = tool.function.description ?? "";
|
|
7195
|
-
|
|
7301
|
+
rawSchema = tool.function.parameters ?? { type: "object", properties: {}, additionalProperties: false };
|
|
7196
7302
|
} else {
|
|
7197
7303
|
name = tool.name ?? "unknown";
|
|
7198
7304
|
description = tool.description ?? "";
|
|
7199
|
-
|
|
7200
|
-
|
|
7305
|
+
rawSchema = tool.schema ?? tool.parameters;
|
|
7306
|
+
}
|
|
7307
|
+
if (useStrict && !canUseStrictToolSchema(rawSchema)) {
|
|
7308
|
+
useStrict = false;
|
|
7201
7309
|
}
|
|
7202
|
-
|
|
7310
|
+
parameters = convertToJsonSchema(rawSchema, useStrict);
|
|
7311
|
+
if (useStrict) {
|
|
7203
7312
|
parameters = normalizeStrictSchema(parameters);
|
|
7204
7313
|
}
|
|
7205
|
-
return { name, description, parameters, ...
|
|
7314
|
+
return { name, description, parameters, ...useStrict ? { strict: true } : {} };
|
|
7206
7315
|
}
|
|
7207
7316
|
function toBaseChatMessage(response) {
|
|
7208
7317
|
const msg = {
|