@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/dist/index.d.cts
CHANGED
|
@@ -260,7 +260,7 @@ type RuntimeProfile = BuiltInRuntimeProfile | "custom";
|
|
|
260
260
|
type SummarizationMode = "incremental" | "full_rewrite";
|
|
261
261
|
type ContextPolicy = "raw" | "summary_only" | "hybrid";
|
|
262
262
|
type ToolResponseRetentionPolicy = "keep_full" | "keep_structured" | "summarize_archive" | "drop";
|
|
263
|
-
type ToolResponseClassification = "critical" | "informative" | "verbose" | "redundant";
|
|
263
|
+
type ToolResponseClassification = "critical" | "small" | "informative" | "verbose" | "redundant";
|
|
264
264
|
type PlanningMode = "off" | "todo" | "planner_executor" | "reasoning_then_tools";
|
|
265
265
|
type ReplanPolicy = "never" | "on_failure" | "on_conflict" | "every_n_steps";
|
|
266
266
|
type DelegationMode = "off" | "role_based" | "automatic";
|
|
@@ -366,15 +366,32 @@ type SmartAgentMemoryConfig = {
|
|
|
366
366
|
readPolicy?: MemoryReadPolicy;
|
|
367
367
|
};
|
|
368
368
|
type SmartAgentToolResponseConfig = {
|
|
369
|
+
/** Upper threshold for marking a response as "verbose" (large). */
|
|
369
370
|
maxToolResponseChars?: number;
|
|
371
|
+
/** Upper threshold (in approx. tokens) for marking a response as "verbose". */
|
|
370
372
|
maxToolResponseTokens?: number;
|
|
373
|
+
/** Lower threshold for marking a response as "small". 0 disables the small tier. */
|
|
374
|
+
smallResponseChars?: number;
|
|
375
|
+
/** Policy applied to responses classified as "small". Defaults to keep_full. */
|
|
376
|
+
smallResponsePolicy?: ToolResponseRetentionPolicy;
|
|
377
|
+
/** Policy applied to mid-sized "informative" responses. */
|
|
371
378
|
defaultPolicy?: ToolResponseRetentionPolicy;
|
|
379
|
+
/** Policy applied when a response exceeds the verbose thresholds. */
|
|
372
380
|
largeResponsePolicy?: ToolResponseRetentionPolicy;
|
|
381
|
+
/** Per-tool override map. Wins over size-based classification. */
|
|
373
382
|
toolResponseRetentionByTool?: Record<string, ToolResponseRetentionPolicy>;
|
|
383
|
+
/** Tool names always treated as critical (resolved via fallbackPolicy). */
|
|
374
384
|
criticalTools?: string[];
|
|
375
385
|
schemaValidation?: "strict" | "warn";
|
|
376
386
|
retryOnSchemaError?: boolean;
|
|
387
|
+
/** Policy applied to critical tools. Should default to keep_full so critical payloads are never reduced. */
|
|
377
388
|
fallbackPolicy?: ToolResponseRetentionPolicy;
|
|
389
|
+
/**
|
|
390
|
+
* Number of most-recent successful tool responses to render at full content
|
|
391
|
+
* regardless of their classification. Older responses still follow their
|
|
392
|
+
* resolved policy. 0 disables the recency override. Defaults to 2.
|
|
393
|
+
*/
|
|
394
|
+
keepRecentFullCount?: number;
|
|
378
395
|
};
|
|
379
396
|
type SmartAgentCustomProfileConfig = {
|
|
380
397
|
extends?: BuiltInRuntimeProfile;
|
package/dist/index.d.ts
CHANGED
|
@@ -260,7 +260,7 @@ type RuntimeProfile = BuiltInRuntimeProfile | "custom";
|
|
|
260
260
|
type SummarizationMode = "incremental" | "full_rewrite";
|
|
261
261
|
type ContextPolicy = "raw" | "summary_only" | "hybrid";
|
|
262
262
|
type ToolResponseRetentionPolicy = "keep_full" | "keep_structured" | "summarize_archive" | "drop";
|
|
263
|
-
type ToolResponseClassification = "critical" | "informative" | "verbose" | "redundant";
|
|
263
|
+
type ToolResponseClassification = "critical" | "small" | "informative" | "verbose" | "redundant";
|
|
264
264
|
type PlanningMode = "off" | "todo" | "planner_executor" | "reasoning_then_tools";
|
|
265
265
|
type ReplanPolicy = "never" | "on_failure" | "on_conflict" | "every_n_steps";
|
|
266
266
|
type DelegationMode = "off" | "role_based" | "automatic";
|
|
@@ -366,15 +366,32 @@ type SmartAgentMemoryConfig = {
|
|
|
366
366
|
readPolicy?: MemoryReadPolicy;
|
|
367
367
|
};
|
|
368
368
|
type SmartAgentToolResponseConfig = {
|
|
369
|
+
/** Upper threshold for marking a response as "verbose" (large). */
|
|
369
370
|
maxToolResponseChars?: number;
|
|
371
|
+
/** Upper threshold (in approx. tokens) for marking a response as "verbose". */
|
|
370
372
|
maxToolResponseTokens?: number;
|
|
373
|
+
/** Lower threshold for marking a response as "small". 0 disables the small tier. */
|
|
374
|
+
smallResponseChars?: number;
|
|
375
|
+
/** Policy applied to responses classified as "small". Defaults to keep_full. */
|
|
376
|
+
smallResponsePolicy?: ToolResponseRetentionPolicy;
|
|
377
|
+
/** Policy applied to mid-sized "informative" responses. */
|
|
371
378
|
defaultPolicy?: ToolResponseRetentionPolicy;
|
|
379
|
+
/** Policy applied when a response exceeds the verbose thresholds. */
|
|
372
380
|
largeResponsePolicy?: ToolResponseRetentionPolicy;
|
|
381
|
+
/** Per-tool override map. Wins over size-based classification. */
|
|
373
382
|
toolResponseRetentionByTool?: Record<string, ToolResponseRetentionPolicy>;
|
|
383
|
+
/** Tool names always treated as critical (resolved via fallbackPolicy). */
|
|
374
384
|
criticalTools?: string[];
|
|
375
385
|
schemaValidation?: "strict" | "warn";
|
|
376
386
|
retryOnSchemaError?: boolean;
|
|
387
|
+
/** Policy applied to critical tools. Should default to keep_full so critical payloads are never reduced. */
|
|
377
388
|
fallbackPolicy?: ToolResponseRetentionPolicy;
|
|
389
|
+
/**
|
|
390
|
+
* Number of most-recent successful tool responses to render at full content
|
|
391
|
+
* regardless of their classification. Older responses still follow their
|
|
392
|
+
* resolved policy. 0 disables the recency override. Defaults to 2.
|
|
393
|
+
*/
|
|
394
|
+
keepRecentFullCount?: number;
|
|
378
395
|
};
|
|
379
396
|
type SmartAgentCustomProfileConfig = {
|
|
380
397
|
extends?: BuiltInRuntimeProfile;
|
package/dist/index.mjs
CHANGED
|
@@ -2128,13 +2128,16 @@ var BASE_DEFAULTS = {
|
|
|
2128
2128
|
toolResponses: {
|
|
2129
2129
|
maxToolResponseChars: 3600,
|
|
2130
2130
|
maxToolResponseTokens: 1200,
|
|
2131
|
+
smallResponseChars: 0,
|
|
2132
|
+
smallResponsePolicy: "keep_full",
|
|
2131
2133
|
defaultPolicy: "keep_structured",
|
|
2132
2134
|
largeResponsePolicy: "summarize_archive",
|
|
2133
2135
|
toolResponseRetentionByTool: {},
|
|
2134
2136
|
criticalTools: [...DEFAULT_CRITICAL_TOOLS],
|
|
2135
2137
|
schemaValidation: "strict",
|
|
2136
2138
|
retryOnSchemaError: true,
|
|
2137
|
-
fallbackPolicy: "
|
|
2139
|
+
fallbackPolicy: "keep_full",
|
|
2140
|
+
keepRecentFullCount: 0
|
|
2138
2141
|
}
|
|
2139
2142
|
};
|
|
2140
2143
|
function buildProfile(overrides) {
|
|
@@ -2417,11 +2420,15 @@ function classifyToolResponse(toolName, output, config) {
|
|
|
2417
2420
|
const tokenCount = countApproxTokens(serialized);
|
|
2418
2421
|
const criticalTools = new Set(config.toolResponses.criticalTools);
|
|
2419
2422
|
if (criticalTools.has(toolName)) return "critical";
|
|
2423
|
+
if (serialized === "ok" || serialized === "true" || serialized === "null") {
|
|
2424
|
+
return "redundant";
|
|
2425
|
+
}
|
|
2420
2426
|
if (tokenCount >= config.toolResponses.maxToolResponseTokens || serialized.length >= config.toolResponses.maxToolResponseChars) {
|
|
2421
2427
|
return "verbose";
|
|
2422
2428
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2429
|
+
const smallChars = config.toolResponses.smallResponseChars;
|
|
2430
|
+
if (smallChars > 0 && serialized.length <= smallChars) {
|
|
2431
|
+
return "small";
|
|
2425
2432
|
}
|
|
2426
2433
|
return "informative";
|
|
2427
2434
|
}
|
|
@@ -2431,12 +2438,14 @@ function resolveToolResponsePolicy(toolName, output, config) {
|
|
|
2431
2438
|
const classification = classifyToolResponse(toolName, output, config);
|
|
2432
2439
|
const byTool = config.toolResponses.toolResponseRetentionByTool[toolName];
|
|
2433
2440
|
let retentionPolicy = byTool || config.toolResponses.defaultPolicy;
|
|
2434
|
-
if (classification === "critical") {
|
|
2435
|
-
retentionPolicy =
|
|
2441
|
+
if (byTool) ; else if (classification === "critical") {
|
|
2442
|
+
retentionPolicy = config.toolResponses.fallbackPolicy;
|
|
2436
2443
|
} else if (classification === "verbose") {
|
|
2437
|
-
retentionPolicy =
|
|
2444
|
+
retentionPolicy = config.toolResponses.largeResponsePolicy;
|
|
2445
|
+
} else if (classification === "small") {
|
|
2446
|
+
retentionPolicy = config.toolResponses.smallResponsePolicy;
|
|
2438
2447
|
} else if (classification === "redundant") {
|
|
2439
|
-
retentionPolicy =
|
|
2448
|
+
retentionPolicy = "drop";
|
|
2440
2449
|
}
|
|
2441
2450
|
const summary = summarizeObject(output);
|
|
2442
2451
|
if (retentionPolicy === "keep_full") {
|
|
@@ -2782,10 +2791,10 @@ function createToolsNode(initialTools, opts) {
|
|
|
2782
2791
|
let toolMessageContent = responsePolicy.content;
|
|
2783
2792
|
if (responsePolicy.retentionPolicy === "summarize_archive") {
|
|
2784
2793
|
toolMessageContent = `ARCHIVED_TOOL_RESPONSE [executionId=${executionId}]: ${responsePolicy.summary}
|
|
2785
|
-
|
|
2794
|
+
Only use get_tool_response with executionId "${executionId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
2786
2795
|
} else if (responsePolicy.retentionPolicy === "drop") {
|
|
2787
2796
|
toolMessageContent = `DROPPED_TOOL_RESPONSE [executionId=${executionId}]: ${responsePolicy.summary}
|
|
2788
|
-
|
|
2797
|
+
Only use get_tool_response with executionId "${executionId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
2789
2798
|
}
|
|
2790
2799
|
appended.push({ role: "tool", content: toolMessageContent, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
|
|
2791
2800
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: output, durationMs });
|
|
@@ -3971,6 +3980,40 @@ function createAgentNode(opts) {
|
|
|
3971
3980
|
}
|
|
3972
3981
|
|
|
3973
3982
|
// src/smart/contextPolicy.ts
|
|
3983
|
+
function collectRecentFullToolCallIds(state, keepRecentFullCount) {
|
|
3984
|
+
if (!keepRecentFullCount || keepRecentFullCount <= 0) return /* @__PURE__ */ new Set();
|
|
3985
|
+
const history = state.toolHistory || [];
|
|
3986
|
+
const ids = [];
|
|
3987
|
+
for (let index = history.length - 1; index >= 0 && ids.length < keepRecentFullCount; index -= 1) {
|
|
3988
|
+
const entry = history[index];
|
|
3989
|
+
if (!entry || !entry.tool_call_id) continue;
|
|
3990
|
+
if (entry.status && entry.status !== "success") continue;
|
|
3991
|
+
ids.push(entry.tool_call_id);
|
|
3992
|
+
}
|
|
3993
|
+
return new Set(ids);
|
|
3994
|
+
}
|
|
3995
|
+
function applyRecentFullOverride(messages, state, config) {
|
|
3996
|
+
const keepN = config.toolResponses.keepRecentFullCount;
|
|
3997
|
+
if (!keepN || keepN <= 0) return messages;
|
|
3998
|
+
const recentIds = collectRecentFullToolCallIds(state, keepN);
|
|
3999
|
+
if (recentIds.size === 0) return messages;
|
|
4000
|
+
const history = state.toolHistory || [];
|
|
4001
|
+
const byCallId = /* @__PURE__ */ new Map();
|
|
4002
|
+
for (const entry of history) {
|
|
4003
|
+
if (entry?.tool_call_id) byCallId.set(entry.tool_call_id, entry);
|
|
4004
|
+
}
|
|
4005
|
+
return messages.map((message) => {
|
|
4006
|
+
if (message.role !== "tool" || !message.tool_call_id) return message;
|
|
4007
|
+
if (!recentIds.has(message.tool_call_id)) return message;
|
|
4008
|
+
const entry = byCallId.get(message.tool_call_id);
|
|
4009
|
+
if (!entry) return message;
|
|
4010
|
+
const raw = entry.rawOutput ?? entry.output;
|
|
4011
|
+
if (raw === void 0) return message;
|
|
4012
|
+
const fullContent = typeof raw === "string" ? raw : safeStringify(raw);
|
|
4013
|
+
if (!fullContent || fullContent === message.content) return message;
|
|
4014
|
+
return { ...message, content: fullContent };
|
|
4015
|
+
});
|
|
4016
|
+
}
|
|
3974
4017
|
function collectRecentTurns(messages, lastTurnsToKeep) {
|
|
3975
4018
|
if (lastTurnsToKeep <= 0) return [];
|
|
3976
4019
|
const systemPrefix = messages.filter((message, index) => index === 0 && message.role === "system");
|
|
@@ -4071,7 +4114,7 @@ function clampToBudget(messages, maxContextTokens) {
|
|
|
4071
4114
|
function buildModelMessages(state, config) {
|
|
4072
4115
|
const rawMessages = state.messages || [];
|
|
4073
4116
|
if (config.context.policy === "raw") {
|
|
4074
|
-
return clampToBudget(rawMessages, config.limits.maxContextTokens);
|
|
4117
|
+
return clampToBudget(applyRecentFullOverride(rawMessages, state, config), config.limits.maxContextTokens);
|
|
4075
4118
|
}
|
|
4076
4119
|
const recentMessages = collectRecentTurns(rawMessages, config.context.lastTurnsToKeep);
|
|
4077
4120
|
const latestSummary = state.summaryRecords?.[state.summaryRecords.length - 1];
|
|
@@ -4091,7 +4134,7 @@ function buildModelMessages(state, config) {
|
|
|
4091
4134
|
...syntheticContextMessages,
|
|
4092
4135
|
...config.context.policy === "summary_only" ? body.filter((message) => message.role === "user" || message.role === "assistant").slice(-2) : body
|
|
4093
4136
|
];
|
|
4094
|
-
return clampToBudget(assembled, config.limits.maxContextTokens);
|
|
4137
|
+
return clampToBudget(applyRecentFullOverride(assembled, state, config), config.limits.maxContextTokens);
|
|
4095
4138
|
}
|
|
4096
4139
|
|
|
4097
4140
|
// src/nodes/contextSummarize.ts
|
|
@@ -4247,11 +4290,11 @@ function buildSummarizedToolMessage(message, state) {
|
|
|
4247
4290
|
toolCallId ? `toolCallId=${toolCallId}` : null,
|
|
4248
4291
|
executionId ? `executionId=${executionId}` : null
|
|
4249
4292
|
].filter(Boolean).join("; ");
|
|
4250
|
-
let retrievalHint = "
|
|
4293
|
+
let retrievalHint = "Only use get_tool_response if this summary is missing a specific field, id, snippet, or exact payload you still need.";
|
|
4251
4294
|
if (executionId && toolCallId) {
|
|
4252
|
-
retrievalHint = `
|
|
4295
|
+
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.`;
|
|
4253
4296
|
} else if (executionId || toolCallId) {
|
|
4254
|
-
retrievalHint = `
|
|
4297
|
+
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.`;
|
|
4255
4298
|
}
|
|
4256
4299
|
return [
|
|
4257
4300
|
`SUMMARIZED_TOOL_RESPONSE [${references}]`,
|
|
@@ -4317,11 +4360,13 @@ function createContextSummarizeNode(opts) {
|
|
|
4317
4360
|
const onEvent = state.ctx?.__onEvent;
|
|
4318
4361
|
const traceSession = state.ctx?.__traceSession;
|
|
4319
4362
|
const toolResponsesConfigEarly = resolved.toolResponses;
|
|
4363
|
+
const recentFullToolCallIdsEarly = collectRecentFullToolCallIds(state, toolResponsesConfigEarly.keepRecentFullCount);
|
|
4320
4364
|
const compressableMessages = messages.filter(
|
|
4321
4365
|
(m) => {
|
|
4322
4366
|
if (m.role !== "tool") return false;
|
|
4323
4367
|
if (isSummarizedToolPlaceholder(m.content)) return false;
|
|
4324
4368
|
if (isSyntheticSummaryMessage(m)) return false;
|
|
4369
|
+
if (m.tool_call_id && recentFullToolCallIdsEarly.has(m.tool_call_id)) return false;
|
|
4325
4370
|
const histEntry = findToolHistoryEntry(state, m.tool_call_id, m.name);
|
|
4326
4371
|
if (histEntry?.retentionPolicy === "keep_full") return false;
|
|
4327
4372
|
if (!histEntry?.retentionPolicy) {
|
|
@@ -4508,6 +4553,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4508
4553
|
}
|
|
4509
4554
|
}
|
|
4510
4555
|
const toolResponsesConfig = resolved.toolResponses;
|
|
4556
|
+
const recentFullToolCallIds = collectRecentFullToolCallIds(state, toolResponsesConfig.keepRecentFullCount);
|
|
4511
4557
|
const newMessages = messages.map((m) => {
|
|
4512
4558
|
if (m.role === "tool") {
|
|
4513
4559
|
if (isSyntheticSummaryMessage(m)) {
|
|
@@ -4519,6 +4565,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4519
4565
|
}
|
|
4520
4566
|
if (isSummarizedToolPlaceholder(m.content)) return m;
|
|
4521
4567
|
if (toolCallId && protectedToolCallIds.has(toolCallId)) return m;
|
|
4568
|
+
if (toolCallId && recentFullToolCallIds.has(toolCallId)) return m;
|
|
4522
4569
|
const toolName = m.name || "";
|
|
4523
4570
|
const historyEntry = findToolHistoryEntry(state, toolCallId, toolName);
|
|
4524
4571
|
const entryRetention = historyEntry?.retentionPolicy;
|
|
@@ -4857,8 +4904,9 @@ function createContextTools(stateRef, opts) {
|
|
|
4857
4904
|
}
|
|
4858
4905
|
const getTool = createTool({
|
|
4859
4906
|
name: "get_tool_response",
|
|
4860
|
-
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.",
|
|
4907
|
+
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.",
|
|
4861
4908
|
schema: z.object({ executionId: z.string().describe("Tool execution id or original tool_call_id") }),
|
|
4909
|
+
maxExecutionsPerRun: 8,
|
|
4862
4910
|
func: async ({ executionId }) => {
|
|
4863
4911
|
const matchesExecution = (t) => t?.executionId === executionId || t?.tool_call_id === executionId;
|
|
4864
4912
|
let execution = stateRef.toolHistory?.find((t) => matchesExecution(t));
|
|
@@ -7114,23 +7162,79 @@ function convertContent(content) {
|
|
|
7114
7162
|
function isZodSchema(obj) {
|
|
7115
7163
|
return obj != null && typeof obj === "object" && typeof obj.safeParse === "function" && "_def" in obj;
|
|
7116
7164
|
}
|
|
7165
|
+
function hasStrictUnsafeShape(node, inProperty = false) {
|
|
7166
|
+
if (!node || typeof node !== "object") return false;
|
|
7167
|
+
if (Array.isArray(node)) {
|
|
7168
|
+
return node.some((item) => hasStrictUnsafeShape(item, inProperty));
|
|
7169
|
+
}
|
|
7170
|
+
if (typeof node.$ref === "string") {
|
|
7171
|
+
return true;
|
|
7172
|
+
}
|
|
7173
|
+
const hasType = typeof node.type === "string" || Array.isArray(node.type) && node.type.length > 0;
|
|
7174
|
+
const hasProperties = !!node.properties && typeof node.properties === "object" && !Array.isArray(node.properties);
|
|
7175
|
+
const hasItems = node.items !== void 0;
|
|
7176
|
+
const hasComposite = ["anyOf", "oneOf", "allOf"].some((key) => Array.isArray(node[key]) && node[key].length > 0);
|
|
7177
|
+
if (inProperty && !hasType && !hasProperties && !hasItems) {
|
|
7178
|
+
return true;
|
|
7179
|
+
}
|
|
7180
|
+
if (inProperty && hasComposite && !hasType) {
|
|
7181
|
+
return true;
|
|
7182
|
+
}
|
|
7183
|
+
if (hasProperties) {
|
|
7184
|
+
for (const value of Object.values(node.properties)) {
|
|
7185
|
+
if (hasStrictUnsafeShape(value, true)) {
|
|
7186
|
+
return true;
|
|
7187
|
+
}
|
|
7188
|
+
}
|
|
7189
|
+
}
|
|
7190
|
+
if (node.items && hasStrictUnsafeShape(node.items, false)) {
|
|
7191
|
+
return true;
|
|
7192
|
+
}
|
|
7193
|
+
for (const key of ["anyOf", "oneOf", "allOf"]) {
|
|
7194
|
+
if (Array.isArray(node[key]) && hasStrictUnsafeShape(node[key], false)) {
|
|
7195
|
+
return true;
|
|
7196
|
+
}
|
|
7197
|
+
}
|
|
7198
|
+
for (const key of ["definitions", "$defs"]) {
|
|
7199
|
+
const defs = node[key];
|
|
7200
|
+
if (defs && typeof defs === "object") {
|
|
7201
|
+
for (const value of Object.values(defs)) {
|
|
7202
|
+
if (hasStrictUnsafeShape(value, false)) {
|
|
7203
|
+
return true;
|
|
7204
|
+
}
|
|
7205
|
+
}
|
|
7206
|
+
}
|
|
7207
|
+
}
|
|
7208
|
+
return false;
|
|
7209
|
+
}
|
|
7210
|
+
function canUseStrictToolSchema(schema) {
|
|
7211
|
+
if (!schema || typeof schema !== "object") {
|
|
7212
|
+
return true;
|
|
7213
|
+
}
|
|
7214
|
+
if (isZodSchema(schema)) {
|
|
7215
|
+
return true;
|
|
7216
|
+
}
|
|
7217
|
+
return !hasStrictUnsafeShape(schema);
|
|
7218
|
+
}
|
|
7117
7219
|
function convertToJsonSchema(schema, strict = false) {
|
|
7118
7220
|
if (!schema || typeof schema !== "object") {
|
|
7119
7221
|
return { type: "object", properties: {}, required: [], additionalProperties: false };
|
|
7120
7222
|
}
|
|
7121
7223
|
if (isZodSchema(schema)) {
|
|
7122
|
-
const
|
|
7224
|
+
const converted2 = zodToJsonSchema(schema, {
|
|
7123
7225
|
$refStrategy: "none",
|
|
7124
7226
|
...strict ? { openaiStrictMode: true } : {}
|
|
7125
7227
|
});
|
|
7126
|
-
delete
|
|
7127
|
-
if (!
|
|
7128
|
-
return
|
|
7228
|
+
delete converted2["$schema"];
|
|
7229
|
+
if (!converted2.type) converted2.type = "object";
|
|
7230
|
+
return converted2;
|
|
7129
7231
|
}
|
|
7130
|
-
|
|
7131
|
-
|
|
7232
|
+
const converted = { ...schema };
|
|
7233
|
+
delete converted["$schema"];
|
|
7234
|
+
if (!converted.type && converted.properties) {
|
|
7235
|
+
return { type: "object", ...converted };
|
|
7132
7236
|
}
|
|
7133
|
-
return
|
|
7237
|
+
return converted;
|
|
7134
7238
|
}
|
|
7135
7239
|
function normalizeStrictSchema(schema) {
|
|
7136
7240
|
if (!schema || typeof schema !== "object") return schema;
|
|
@@ -7179,20 +7283,25 @@ function toToolDefinition(tool, strict) {
|
|
|
7179
7283
|
let name;
|
|
7180
7284
|
let description;
|
|
7181
7285
|
let parameters;
|
|
7286
|
+
let rawSchema;
|
|
7287
|
+
let useStrict = strict ?? false;
|
|
7182
7288
|
if (tool.type === "function" && tool.function) {
|
|
7183
7289
|
name = tool.function.name;
|
|
7184
7290
|
description = tool.function.description ?? "";
|
|
7185
|
-
|
|
7291
|
+
rawSchema = tool.function.parameters ?? { type: "object", properties: {}, additionalProperties: false };
|
|
7186
7292
|
} else {
|
|
7187
7293
|
name = tool.name ?? "unknown";
|
|
7188
7294
|
description = tool.description ?? "";
|
|
7189
|
-
|
|
7190
|
-
|
|
7295
|
+
rawSchema = tool.schema ?? tool.parameters;
|
|
7296
|
+
}
|
|
7297
|
+
if (useStrict && !canUseStrictToolSchema(rawSchema)) {
|
|
7298
|
+
useStrict = false;
|
|
7191
7299
|
}
|
|
7192
|
-
|
|
7300
|
+
parameters = convertToJsonSchema(rawSchema, useStrict);
|
|
7301
|
+
if (useStrict) {
|
|
7193
7302
|
parameters = normalizeStrictSchema(parameters);
|
|
7194
7303
|
}
|
|
7195
|
-
return { name, description, parameters, ...
|
|
7304
|
+
return { name, description, parameters, ...useStrict ? { strict: true } : {} };
|
|
7196
7305
|
}
|
|
7197
7306
|
function toBaseChatMessage(response) {
|
|
7198
7307
|
const msg = {
|