@cognipeer/agent-sdk 0.10.3 → 0.10.5
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/index.cjs +516 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -3
- package/dist/index.d.ts +106 -3
- package/dist/index.mjs +512 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -513,7 +513,7 @@ function getModelCapabilities(model) {
|
|
|
513
513
|
return {
|
|
514
514
|
provider,
|
|
515
515
|
structuredOutput: supportsNativeStructuredOutput(provider) ? "native" : "tool_based",
|
|
516
|
-
strictToolCalling: requiresStrictToolCalling(provider),
|
|
516
|
+
strictToolCalling: requiresStrictToolCalling(provider) && isOpenAIHostedEndpoint(model._lc),
|
|
517
517
|
streaming: true
|
|
518
518
|
};
|
|
519
519
|
}
|
|
@@ -556,6 +556,17 @@ function supportsNativeStructuredOutput(provider) {
|
|
|
556
556
|
function requiresStrictToolCalling(provider) {
|
|
557
557
|
return ["openai"].includes(provider);
|
|
558
558
|
}
|
|
559
|
+
function isOpenAIHostedEndpoint(lcModel) {
|
|
560
|
+
if (!lcModel) return true;
|
|
561
|
+
const baseURL = lcModel.clientConfig?.baseURL ?? lcModel.configuration?.baseURL ?? lcModel.baseURL;
|
|
562
|
+
if (typeof baseURL !== "string" || baseURL.trim() === "") return true;
|
|
563
|
+
try {
|
|
564
|
+
const host = new URL(baseURL).hostname.toLowerCase();
|
|
565
|
+
return host === "api.openai.com" || host.endsWith(".openai.azure.com") || host.endsWith(".cognitiveservices.azure.com");
|
|
566
|
+
} catch {
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
559
570
|
|
|
560
571
|
// src/model.ts
|
|
561
572
|
function isSmartModel(m) {
|
|
@@ -2520,13 +2531,19 @@ function resolveCapabilities(provider) {
|
|
|
2520
2531
|
switch (provider) {
|
|
2521
2532
|
case "openai":
|
|
2522
2533
|
case "azure":
|
|
2523
|
-
case "openai-compatible":
|
|
2524
2534
|
return {
|
|
2525
2535
|
structuredOutput: "native",
|
|
2526
2536
|
strictToolCalling: true,
|
|
2527
2537
|
streaming: true,
|
|
2528
2538
|
provider
|
|
2529
2539
|
};
|
|
2540
|
+
case "openai-compatible":
|
|
2541
|
+
return {
|
|
2542
|
+
structuredOutput: "native",
|
|
2543
|
+
strictToolCalling: false,
|
|
2544
|
+
streaming: true,
|
|
2545
|
+
provider
|
|
2546
|
+
};
|
|
2530
2547
|
case "anthropic":
|
|
2531
2548
|
return {
|
|
2532
2549
|
structuredOutput: "tool_based",
|
|
@@ -3855,6 +3872,187 @@ Identical to an earlier ${duplicate.toolName} result. Use get_tool_response with
|
|
|
3855
3872
|
}
|
|
3856
3873
|
return notApplied4(output);
|
|
3857
3874
|
}
|
|
3875
|
+
var identity = (value) => value;
|
|
3876
|
+
function describeLike(schema, source, suffix) {
|
|
3877
|
+
const description = [source.description, suffix].filter(Boolean).join(" ");
|
|
3878
|
+
return description ? schema.describe(description) : schema;
|
|
3879
|
+
}
|
|
3880
|
+
function jsonString(source) {
|
|
3881
|
+
return {
|
|
3882
|
+
schema: describeLike(zod.z.string(), source, "(a JSON value, encoded as a string)"),
|
|
3883
|
+
restore: (value) => {
|
|
3884
|
+
if (typeof value !== "string") return value;
|
|
3885
|
+
try {
|
|
3886
|
+
return JSON.parse(value);
|
|
3887
|
+
} catch {
|
|
3888
|
+
return value;
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
function unwrapOptional(schema) {
|
|
3894
|
+
const def = schema._def;
|
|
3895
|
+
if (def?.typeName === "ZodOptional") return { inner: def.innerType, optional: true };
|
|
3896
|
+
if (def?.typeName === "ZodDefault") return { inner: def.innerType, optional: true };
|
|
3897
|
+
return { inner: schema, optional: false };
|
|
3898
|
+
}
|
|
3899
|
+
function isZodSchema2(schema) {
|
|
3900
|
+
return Boolean(schema) && typeof schema.safeParse === "function" && Boolean(schema._def);
|
|
3901
|
+
}
|
|
3902
|
+
function toStrictCompatible(schema) {
|
|
3903
|
+
const def = schema?._def;
|
|
3904
|
+
switch (def?.typeName) {
|
|
3905
|
+
case "ZodObject": {
|
|
3906
|
+
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
3907
|
+
const keys = Object.keys(shape ?? {});
|
|
3908
|
+
const open = def.unknownKeys === "passthrough" || def.catchall && def.catchall._def?.typeName !== "ZodNever";
|
|
3909
|
+
if (keys.length === 0 && open) return jsonString(schema);
|
|
3910
|
+
const nextShape = {};
|
|
3911
|
+
const restores = {};
|
|
3912
|
+
for (const key of keys) {
|
|
3913
|
+
const field = shape[key];
|
|
3914
|
+
const { inner, optional } = unwrapOptional(field);
|
|
3915
|
+
const child = toStrictCompatible(inner);
|
|
3916
|
+
const childSchema = describeLike(child.schema, field.description ? field : inner);
|
|
3917
|
+
nextShape[key] = optional ? childSchema.nullable() : childSchema;
|
|
3918
|
+
restores[key] = { restore: child.restore, optional };
|
|
3919
|
+
}
|
|
3920
|
+
return {
|
|
3921
|
+
schema: describeLike(zod.z.object(nextShape), schema),
|
|
3922
|
+
restore: (value) => {
|
|
3923
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
3924
|
+
const out = {};
|
|
3925
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
3926
|
+
const entry = restores[key];
|
|
3927
|
+
if (raw === null && entry?.optional) continue;
|
|
3928
|
+
out[key] = entry ? entry.restore(raw) : raw;
|
|
3929
|
+
}
|
|
3930
|
+
return out;
|
|
3931
|
+
}
|
|
3932
|
+
};
|
|
3933
|
+
}
|
|
3934
|
+
case "ZodOptional":
|
|
3935
|
+
case "ZodDefault": {
|
|
3936
|
+
const child = toStrictCompatible(def.innerType);
|
|
3937
|
+
return {
|
|
3938
|
+
schema: describeLike(child.schema.nullable(), schema),
|
|
3939
|
+
restore: (value) => value === null ? void 0 : child.restore(value)
|
|
3940
|
+
};
|
|
3941
|
+
}
|
|
3942
|
+
case "ZodNullable": {
|
|
3943
|
+
const child = toStrictCompatible(def.innerType);
|
|
3944
|
+
return {
|
|
3945
|
+
schema: describeLike(child.schema.nullable(), schema),
|
|
3946
|
+
restore: (value) => value === null ? null : child.restore(value)
|
|
3947
|
+
};
|
|
3948
|
+
}
|
|
3949
|
+
case "ZodArray": {
|
|
3950
|
+
const child = toStrictCompatible(def.type);
|
|
3951
|
+
return {
|
|
3952
|
+
schema: describeLike(zod.z.array(child.schema), schema),
|
|
3953
|
+
restore: (value) => Array.isArray(value) ? value.map(child.restore) : value
|
|
3954
|
+
};
|
|
3955
|
+
}
|
|
3956
|
+
case "ZodUnion":
|
|
3957
|
+
case "ZodDiscriminatedUnion": {
|
|
3958
|
+
const rawOptions = def.options instanceof Map ? [...def.options.values()] : def.options;
|
|
3959
|
+
const options = rawOptions.map(toStrictCompatible);
|
|
3960
|
+
if (options.length === 1) return options[0];
|
|
3961
|
+
if (options.every((option, index) => option.schema === rawOptions[index])) {
|
|
3962
|
+
return { schema, restore: identity };
|
|
3963
|
+
}
|
|
3964
|
+
return {
|
|
3965
|
+
schema: describeLike(zod.z.union(options.map((option) => option.schema)), schema),
|
|
3966
|
+
restore: (value) => {
|
|
3967
|
+
const candidates = options.map((option) => option.restore(value));
|
|
3968
|
+
const index = candidates.findIndex((candidate, i) => rawOptions[i].safeParse(candidate).success);
|
|
3969
|
+
return candidates[index >= 0 ? index : 0];
|
|
3970
|
+
}
|
|
3971
|
+
};
|
|
3972
|
+
}
|
|
3973
|
+
case "ZodEffects":
|
|
3974
|
+
return toStrictCompatible(def.schema);
|
|
3975
|
+
case "ZodRecord":
|
|
3976
|
+
case "ZodAny":
|
|
3977
|
+
case "ZodUnknown":
|
|
3978
|
+
return jsonString(schema);
|
|
3979
|
+
default:
|
|
3980
|
+
return { schema, restore: identity };
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
function topLevelObject(transform) {
|
|
3984
|
+
if (transform.schema._def?.typeName === "ZodObject") return transform;
|
|
3985
|
+
return {
|
|
3986
|
+
schema: zod.z.object({
|
|
3987
|
+
input: transform.schema.describe(
|
|
3988
|
+
transform.schema.description ?? "The tool arguments as a JSON object, encoded as a string"
|
|
3989
|
+
)
|
|
3990
|
+
}),
|
|
3991
|
+
restore: (value) => {
|
|
3992
|
+
const input = value && typeof value === "object" ? value.input : void 0;
|
|
3993
|
+
const restored = transform.restore(input);
|
|
3994
|
+
return restored && typeof restored === "object" ? restored : {};
|
|
3995
|
+
}
|
|
3996
|
+
};
|
|
3997
|
+
}
|
|
3998
|
+
function toStrictToolSchema(schema) {
|
|
3999
|
+
return topLevelObject(toStrictCompatible(schema));
|
|
4000
|
+
}
|
|
4001
|
+
function restoreToolCalls(message, restorers) {
|
|
4002
|
+
if (!message || typeof message !== "object" || restorers.size === 0) return message;
|
|
4003
|
+
const restoreList = (calls) => {
|
|
4004
|
+
if (!Array.isArray(calls) || calls.length === 0) return calls;
|
|
4005
|
+
return calls.map((call) => {
|
|
4006
|
+
const fn = call?.function;
|
|
4007
|
+
const name = call?.name ?? fn?.name;
|
|
4008
|
+
const restore = name ? restorers.get(name) : void 0;
|
|
4009
|
+
if (!restore) return call;
|
|
4010
|
+
let next = call;
|
|
4011
|
+
if (call.args && typeof call.args === "object") next = { ...next, args: restore(call.args) };
|
|
4012
|
+
if (fn && typeof fn.arguments === "string") {
|
|
4013
|
+
try {
|
|
4014
|
+
next = { ...next, function: { ...fn, arguments: JSON.stringify(restore(JSON.parse(fn.arguments))) } };
|
|
4015
|
+
} catch {
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
return next;
|
|
4019
|
+
});
|
|
4020
|
+
};
|
|
4021
|
+
const m = message;
|
|
4022
|
+
const hasDirect = Array.isArray(m.tool_calls) && m.tool_calls.length > 0;
|
|
4023
|
+
const hasKwargs = Array.isArray(m.additional_kwargs?.tool_calls) && m.additional_kwargs.tool_calls.length > 0;
|
|
4024
|
+
if (!hasDirect && !hasKwargs) return message;
|
|
4025
|
+
return {
|
|
4026
|
+
...message,
|
|
4027
|
+
...hasDirect ? { tool_calls: restoreList(m.tool_calls) } : {},
|
|
4028
|
+
...hasKwargs ? { additional_kwargs: { ...m.additional_kwargs, tool_calls: restoreList(m.additional_kwargs.tool_calls) } } : {}
|
|
4029
|
+
};
|
|
4030
|
+
}
|
|
4031
|
+
var strictViews = /* @__PURE__ */ new WeakMap();
|
|
4032
|
+
function prepareStrictToolMenu(tools) {
|
|
4033
|
+
const restorers = /* @__PURE__ */ new Map();
|
|
4034
|
+
const menu = tools.map((tool) => {
|
|
4035
|
+
const t = tool;
|
|
4036
|
+
if (!t || typeof t.name !== "string" || !isZodSchema2(t.schema)) return tool;
|
|
4037
|
+
const cached = strictViews.get(tool);
|
|
4038
|
+
if (cached && cached.schema === t.schema) {
|
|
4039
|
+
restorers.set(t.name, cached.restore);
|
|
4040
|
+
return cached.view;
|
|
4041
|
+
}
|
|
4042
|
+
try {
|
|
4043
|
+
const transform = toStrictToolSchema(t.schema);
|
|
4044
|
+
const view = Object.create(tool);
|
|
4045
|
+
view.schema = transform.schema;
|
|
4046
|
+
view.__lcTool = void 0;
|
|
4047
|
+
strictViews.set(tool, { schema: t.schema, view, restore: transform.restore });
|
|
4048
|
+
restorers.set(t.name, transform.restore);
|
|
4049
|
+
return view;
|
|
4050
|
+
} catch {
|
|
4051
|
+
return tool;
|
|
4052
|
+
}
|
|
4053
|
+
});
|
|
4054
|
+
return { menu, restorers };
|
|
4055
|
+
}
|
|
3858
4056
|
|
|
3859
4057
|
// src/nodes/agentCore.ts
|
|
3860
4058
|
function createAgentCoreNode(opts) {
|
|
@@ -3875,10 +4073,17 @@ function createAgentCoreNode(opts) {
|
|
|
3875
4073
|
};
|
|
3876
4074
|
let tools = runtime.tools ?? [];
|
|
3877
4075
|
const shouldUseStrictToolCalling = Boolean(
|
|
3878
|
-
runtime.
|
|
4076
|
+
runtime.model?.capabilities?.strictToolCalling
|
|
3879
4077
|
);
|
|
4078
|
+
let strictRestorers = /* @__PURE__ */ new Map();
|
|
4079
|
+
const wireMenu = (menu) => {
|
|
4080
|
+
if (!shouldUseStrictToolCalling) return menu;
|
|
4081
|
+
const prepared = prepareStrictToolMenu(menu);
|
|
4082
|
+
strictRestorers = prepared.restorers;
|
|
4083
|
+
return prepared.menu;
|
|
4084
|
+
};
|
|
3880
4085
|
const bindToolMenu = (menu) => runtime.model?.bindTools ? runtime.model.bindTools(
|
|
3881
|
-
menu,
|
|
4086
|
+
wireMenu(menu),
|
|
3882
4087
|
shouldUseStrictToolCalling ? { strict: true } : void 0
|
|
3883
4088
|
) : runtime.model;
|
|
3884
4089
|
const menuMutationReachesProvider = typeof runtime.model?.bindTools === "function";
|
|
@@ -3889,7 +4094,8 @@ function createAgentCoreNode(opts) {
|
|
|
3889
4094
|
const computeTraceToolDefinitions = (menu) => {
|
|
3890
4095
|
if (!traceSession || !traceSession.resolvedConfig.logData || menu.length === 0) return void 0;
|
|
3891
4096
|
try {
|
|
3892
|
-
|
|
4097
|
+
const wire = shouldUseStrictToolCalling ? prepareStrictToolMenu(menu).menu : menu;
|
|
4098
|
+
return wire.map((tool) => {
|
|
3893
4099
|
const def = toToolDefinition(tool, shouldUseStrictToolCalling ? true : void 0);
|
|
3894
4100
|
return { name: def.name, description: def.description || void 0, parameters: def.parameters };
|
|
3895
4101
|
});
|
|
@@ -4195,6 +4401,9 @@ ${append}`;
|
|
|
4195
4401
|
throw err;
|
|
4196
4402
|
}
|
|
4197
4403
|
}
|
|
4404
|
+
if (shortCircuited === void 0 && strictRestorers.size > 0) {
|
|
4405
|
+
response = restoreToolCalls(response, strictRestorers);
|
|
4406
|
+
}
|
|
4198
4407
|
if (!host?.has("postModelCall")) break;
|
|
4199
4408
|
const postGate = await host.runGate("postModelCall", {
|
|
4200
4409
|
message: response,
|
|
@@ -8793,6 +9002,21 @@ var todoUpdateItemSchema = zod.z.object({
|
|
|
8793
9002
|
status: todoStatusSchema.optional(),
|
|
8794
9003
|
evidence: zod.z.string().max(300).optional()
|
|
8795
9004
|
});
|
|
9005
|
+
var todoItemWireSchema = zod.z.object({
|
|
9006
|
+
id: zod.z.number().int().min(1).describe("Sequential id starting from 1 (write) or an existing id (update)"),
|
|
9007
|
+
step: zod.z.string().min(1).optional(),
|
|
9008
|
+
title: zod.z.string().min(1).optional(),
|
|
9009
|
+
description: zod.z.string().min(1).optional(),
|
|
9010
|
+
owner: zod.z.string().min(1).optional(),
|
|
9011
|
+
exitCriteria: zod.z.string().min(1).optional(),
|
|
9012
|
+
status: todoStatusSchema.optional().describe("Required for every item on write"),
|
|
9013
|
+
evidence: zod.z.string().max(300).optional()
|
|
9014
|
+
});
|
|
9015
|
+
function describeTodoIssue(issue) {
|
|
9016
|
+
if (!issue) return void 0;
|
|
9017
|
+
const path2 = issue.path.length > 0 ? `todoList[${issue.path[0]}]${issue.path.slice(1).map((p) => `.${String(p)}`).join("")}` : "todoList";
|
|
9018
|
+
return `${path2}: ${issue.message}`;
|
|
9019
|
+
}
|
|
8796
9020
|
function normalizeTodoItem(item, existing) {
|
|
8797
9021
|
const id = item.id ?? existing?.id;
|
|
8798
9022
|
const step = item.step || item.title || item.description || existing?.step || existing?.title || existing?.description || `Step ${id}`;
|
|
@@ -8909,7 +9133,7 @@ function createPlanTool(stateRef, toolName, description) {
|
|
|
8909
9133
|
schema: zod.z.object({
|
|
8910
9134
|
operation: zod.z.enum(["write", "read", "update"]),
|
|
8911
9135
|
expectedVersion: zod.z.number().int().min(0).optional(),
|
|
8912
|
-
todoList: zod.z.array(
|
|
9136
|
+
todoList: zod.z.array(todoItemWireSchema).optional()
|
|
8913
9137
|
}),
|
|
8914
9138
|
func: async ({ operation, expectedVersion, todoList }) => {
|
|
8915
9139
|
const toolStateRef = manageTodo._stateRef;
|
|
@@ -8975,7 +9199,10 @@ function createPlanTool(stateRef, toolName, description) {
|
|
|
8975
9199
|
return {
|
|
8976
9200
|
status: "error",
|
|
8977
9201
|
operation,
|
|
8978
|
-
|
|
9202
|
+
// The wire schema has `status` optional (one shape for write and
|
|
9203
|
+
// update), so a missing one is caught here — named, so the model
|
|
9204
|
+
// can fix the call.
|
|
9205
|
+
error: describeTodoIssue(parsed.error.issues[0]) || "Invalid todoList for write.",
|
|
8979
9206
|
version: currentVersion,
|
|
8980
9207
|
adherenceScore: stateRef.adherenceScore || 0
|
|
8981
9208
|
};
|
|
@@ -8998,7 +9225,7 @@ function createPlanTool(stateRef, toolName, description) {
|
|
|
8998
9225
|
return {
|
|
8999
9226
|
status: "error",
|
|
9000
9227
|
operation,
|
|
9001
|
-
error: parsed.error.issues[0]
|
|
9228
|
+
error: describeTodoIssue(parsed.error.issues[0]) || "Invalid todoList for update.",
|
|
9002
9229
|
version: currentVersion,
|
|
9003
9230
|
adherenceScore: stateRef.adherenceScore || 0
|
|
9004
9231
|
};
|
|
@@ -14764,8 +14991,127 @@ function sanitizeBedrockDocName(name, fallback = "document") {
|
|
|
14764
14991
|
return cleaned || fallback;
|
|
14765
14992
|
}
|
|
14766
14993
|
|
|
14994
|
+
// src/providers/utils/jsonSchemaRefs.ts
|
|
14995
|
+
var DEFINITION_KEYS = ["definitions", "$defs"];
|
|
14996
|
+
function inlineJsonSchemaRefs(schema) {
|
|
14997
|
+
if (!isObject(schema) || !containsRef(schema)) return schema;
|
|
14998
|
+
const root = structuredClone(schema);
|
|
14999
|
+
const selfReaching = /* @__PURE__ */ new Map();
|
|
15000
|
+
const targetOf = (ref) => {
|
|
15001
|
+
const target = resolvePointer(root, ref);
|
|
15002
|
+
return isObject(target) ? target : void 0;
|
|
15003
|
+
};
|
|
15004
|
+
const reachesItself = (target) => {
|
|
15005
|
+
const known = selfReaching.get(target);
|
|
15006
|
+
if (known !== void 0) return known;
|
|
15007
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15008
|
+
const walk = (node) => {
|
|
15009
|
+
if (Array.isArray(node)) return node.some(walk);
|
|
15010
|
+
if (!isObject(node)) return false;
|
|
15011
|
+
if (typeof node.$ref === "string") {
|
|
15012
|
+
const next = targetOf(node.$ref);
|
|
15013
|
+
if (next === target) return true;
|
|
15014
|
+
if (next && !seen.has(next)) {
|
|
15015
|
+
seen.add(next);
|
|
15016
|
+
if (walk(next)) return true;
|
|
15017
|
+
}
|
|
15018
|
+
}
|
|
15019
|
+
return Object.entries(node).some(([key, value]) => key !== "$ref" && walk(value));
|
|
15020
|
+
};
|
|
15021
|
+
const result2 = walk(target);
|
|
15022
|
+
selfReaching.set(target, result2);
|
|
15023
|
+
return result2;
|
|
15024
|
+
};
|
|
15025
|
+
const keptRefs = /* @__PURE__ */ new Set();
|
|
15026
|
+
const expand = (node) => {
|
|
15027
|
+
if (Array.isArray(node)) return node.map(expand);
|
|
15028
|
+
if (!isObject(node)) return node;
|
|
15029
|
+
if (typeof node.$ref === "string") {
|
|
15030
|
+
const target = targetOf(node.$ref);
|
|
15031
|
+
if (target && !reachesItself(target)) {
|
|
15032
|
+
const { $ref: _inlined, ...siblings } = node;
|
|
15033
|
+
return { ...expand(target), ...expandEntries(siblings) };
|
|
15034
|
+
}
|
|
15035
|
+
keptRefs.add(node.$ref);
|
|
15036
|
+
return expandEntries(node);
|
|
15037
|
+
}
|
|
15038
|
+
return expandEntries(node);
|
|
15039
|
+
};
|
|
15040
|
+
const expandEntries = (node) => {
|
|
15041
|
+
const out = {};
|
|
15042
|
+
for (const [key, value] of Object.entries(node)) out[key] = key === "$ref" ? value : expand(value);
|
|
15043
|
+
return out;
|
|
15044
|
+
};
|
|
15045
|
+
const { definitions: _definitions, $defs: _defs, ...rootBody } = root;
|
|
15046
|
+
const result = typeof root.$ref === "string" ? expand(rootBody) : expandEntries(rootBody);
|
|
15047
|
+
for (const key of DEFINITION_KEYS) delete result[key];
|
|
15048
|
+
for (const key of DEFINITION_KEYS) {
|
|
15049
|
+
const block = root[key];
|
|
15050
|
+
if (!isObject(block)) continue;
|
|
15051
|
+
const needed = neededEntries(key, block, keptRefs);
|
|
15052
|
+
if (needed.length === 0) continue;
|
|
15053
|
+
const kept = {};
|
|
15054
|
+
for (const name of Object.keys(block)) if (needed.includes(name)) kept[name] = block[name];
|
|
15055
|
+
result[key] = kept;
|
|
15056
|
+
}
|
|
15057
|
+
return result;
|
|
15058
|
+
}
|
|
15059
|
+
function neededEntries(key, block, keptRefs) {
|
|
15060
|
+
const needed = [];
|
|
15061
|
+
const queue = [...keptRefs];
|
|
15062
|
+
while (queue.length > 0) {
|
|
15063
|
+
const ref = queue.shift();
|
|
15064
|
+
const segments = pointerSegments(ref);
|
|
15065
|
+
if (!segments || segments[0] !== key || segments.length < 2) continue;
|
|
15066
|
+
const name = segments[1];
|
|
15067
|
+
if (needed.includes(name) || !(name in block)) continue;
|
|
15068
|
+
needed.push(name);
|
|
15069
|
+
collectRefs(block[name], queue);
|
|
15070
|
+
}
|
|
15071
|
+
return needed;
|
|
15072
|
+
}
|
|
15073
|
+
function collectRefs(node, into) {
|
|
15074
|
+
if (Array.isArray(node)) {
|
|
15075
|
+
node.forEach((child) => collectRefs(child, into));
|
|
15076
|
+
return;
|
|
15077
|
+
}
|
|
15078
|
+
if (!isObject(node)) return;
|
|
15079
|
+
if (typeof node.$ref === "string") into.push(node.$ref);
|
|
15080
|
+
for (const [k, value] of Object.entries(node)) if (k !== "$ref") collectRefs(value, into);
|
|
15081
|
+
}
|
|
15082
|
+
function containsRef(node) {
|
|
15083
|
+
if (Array.isArray(node)) return node.some(containsRef);
|
|
15084
|
+
if (!isObject(node)) return false;
|
|
15085
|
+
if (typeof node.$ref === "string") return true;
|
|
15086
|
+
return Object.values(node).some(containsRef);
|
|
15087
|
+
}
|
|
15088
|
+
function pointerSegments(ref) {
|
|
15089
|
+
if (ref === "#") return [];
|
|
15090
|
+
if (!ref.startsWith("#/")) return null;
|
|
15091
|
+
return ref.slice(2).split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
15092
|
+
}
|
|
15093
|
+
function resolvePointer(document, ref) {
|
|
15094
|
+
const segments = pointerSegments(ref);
|
|
15095
|
+
if (!segments) return void 0;
|
|
15096
|
+
let current = document;
|
|
15097
|
+
for (const segment of segments) {
|
|
15098
|
+
if (Array.isArray(current)) {
|
|
15099
|
+
if (!/^\d+$/.test(segment)) return void 0;
|
|
15100
|
+
current = current[Number(segment)];
|
|
15101
|
+
} else if (isObject(current) && Object.prototype.hasOwnProperty.call(current, segment)) {
|
|
15102
|
+
current = current[segment];
|
|
15103
|
+
} else {
|
|
15104
|
+
return void 0;
|
|
15105
|
+
}
|
|
15106
|
+
}
|
|
15107
|
+
return current;
|
|
15108
|
+
}
|
|
15109
|
+
function isObject(value) {
|
|
15110
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15111
|
+
}
|
|
15112
|
+
|
|
14767
15113
|
// src/providers/openai.ts
|
|
14768
|
-
var OpenAIProvider = class extends BaseProvider {
|
|
15114
|
+
var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
14769
15115
|
constructor(config) {
|
|
14770
15116
|
super();
|
|
14771
15117
|
this.providerName = "openai";
|
|
@@ -14777,8 +15123,21 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
14777
15123
|
...config.organization ? { "OpenAI-Organization": config.organization } : {}
|
|
14778
15124
|
};
|
|
14779
15125
|
this.responsesApi = config.responsesApi ?? "auto";
|
|
15126
|
+
const ownInstance = new.target === _OpenAIProvider;
|
|
15127
|
+
this.responsesApiModels = ownInstance ? [...config.responsesApiModels ?? []] : [];
|
|
15128
|
+
this.responsesStreaming = ownInstance && config.responsesStreaming === true;
|
|
14780
15129
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
14781
15130
|
}
|
|
15131
|
+
/** True when the caller listed this request's model in `responsesApiModels`. */
|
|
15132
|
+
isResponsesApiModel(request) {
|
|
15133
|
+
if (this.responsesApiModels.length === 0) return false;
|
|
15134
|
+
const model = request.model || this.defaultModel;
|
|
15135
|
+
return this.responsesApiModels.some((entry) => {
|
|
15136
|
+
if (typeof entry === "string") return entry === model;
|
|
15137
|
+
entry.lastIndex = 0;
|
|
15138
|
+
return entry.test(model);
|
|
15139
|
+
});
|
|
15140
|
+
}
|
|
14782
15141
|
/** True when this request should go to the Responses API rather than Chat
|
|
14783
15142
|
* Completions — which exposes `reasoning.effort` and reasoning summaries that
|
|
14784
15143
|
* Chat Completions silently drops.
|
|
@@ -14787,10 +15146,14 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
14787
15146
|
* carries a reasoning config AND the model name looks like an o-series/gpt-5
|
|
14788
15147
|
* model. `never`/`always` let a caller state the answer instead, because the
|
|
14789
15148
|
* name check is a guess and the two APIs differ in far more than reasoning —
|
|
14790
|
-
* see `responsesApi` in OpenAIProviderConfig.
|
|
15149
|
+
* see `responsesApi` in OpenAIProviderConfig.
|
|
15150
|
+
*
|
|
15151
|
+
* A model listed in `responsesApiModels` is the caller stating the answer
|
|
15152
|
+
* for that model alone; `never` still overrides it. */
|
|
14791
15153
|
useResponsesApi(request) {
|
|
14792
15154
|
if (this.responsesApi === "never") return false;
|
|
14793
15155
|
if (this.responsesApi === "always") return true;
|
|
15156
|
+
if (this.isResponsesApiModel(request)) return true;
|
|
14794
15157
|
if (!request.reasoning) return false;
|
|
14795
15158
|
return isReasoningModel(request.model || this.defaultModel);
|
|
14796
15159
|
}
|
|
@@ -14805,6 +15168,10 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
14805
15168
|
}
|
|
14806
15169
|
async *completeStream(request) {
|
|
14807
15170
|
if (this.useResponsesApi(request)) {
|
|
15171
|
+
if (this.responsesStreaming && this.isResponsesApiModel(request)) {
|
|
15172
|
+
yield* this.streamResponses(request);
|
|
15173
|
+
return;
|
|
15174
|
+
}
|
|
14808
15175
|
const response = await this.completeResponses(request);
|
|
14809
15176
|
yield {
|
|
14810
15177
|
id: response.id,
|
|
@@ -14920,10 +15287,101 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
14920
15287
|
// ─── Responses API (reasoning models) ──────────────────────────────────────
|
|
14921
15288
|
async completeResponses(request) {
|
|
14922
15289
|
const body = this.buildResponsesBody(request);
|
|
15290
|
+
if (this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
|
|
14923
15291
|
const res = await this.responsesFetch(body);
|
|
14924
15292
|
const json = await res.json();
|
|
14925
15293
|
return this.parseResponsesResponse(json, request.model || this.defaultModel);
|
|
14926
15294
|
}
|
|
15295
|
+
/** Real Responses SSE streaming, for models opted in through
|
|
15296
|
+
* `responsesApiModels` with `responsesStreaming` on. Emits the same chunk
|
|
15297
|
+
* shapes as the Chat Completions stream: text deltas as they arrive, a tool
|
|
15298
|
+
* call's id + name when it opens and its argument fragments under that id,
|
|
15299
|
+
* then one final chunk with usage, finish reason and any reasoning summary
|
|
15300
|
+
* (taken from the completed response, exactly as the non-streaming parse
|
|
15301
|
+
* reads it). */
|
|
15302
|
+
async *streamResponses(request) {
|
|
15303
|
+
const modelId = request.model || this.defaultModel;
|
|
15304
|
+
const body = this.buildResponsesBody(request);
|
|
15305
|
+
adaptChatExtrasForResponses(body, request.extra);
|
|
15306
|
+
body.stream = true;
|
|
15307
|
+
const res = await this.responsesFetch(body);
|
|
15308
|
+
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
15309
|
+
let id = "";
|
|
15310
|
+
let model = modelId;
|
|
15311
|
+
const calls = /* @__PURE__ */ new Map();
|
|
15312
|
+
let final;
|
|
15313
|
+
for await (const event of parseSSEStream(res.body)) {
|
|
15314
|
+
if (event.data === "[DONE]") break;
|
|
15315
|
+
let data;
|
|
15316
|
+
try {
|
|
15317
|
+
data = JSON.parse(event.data);
|
|
15318
|
+
} catch {
|
|
15319
|
+
continue;
|
|
15320
|
+
}
|
|
15321
|
+
switch (data.type ?? event.event) {
|
|
15322
|
+
case "response.created":
|
|
15323
|
+
case "response.in_progress":
|
|
15324
|
+
id = data.response?.id ?? id;
|
|
15325
|
+
model = data.response?.model ?? model;
|
|
15326
|
+
break;
|
|
15327
|
+
case "response.output_text.delta":
|
|
15328
|
+
if (data.delta) yield { id, model, delta: { content: data.delta } };
|
|
15329
|
+
break;
|
|
15330
|
+
case "response.output_item.added": {
|
|
15331
|
+
const item = data.item;
|
|
15332
|
+
if (item?.type !== "function_call") break;
|
|
15333
|
+
const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "" };
|
|
15334
|
+
calls.set(item.id ?? call.callId, call);
|
|
15335
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments }] } };
|
|
15336
|
+
break;
|
|
15337
|
+
}
|
|
15338
|
+
case "response.function_call_arguments.delta": {
|
|
15339
|
+
const call = calls.get(data.item_id);
|
|
15340
|
+
if (!call || !data.delta) break;
|
|
15341
|
+
call.arguments += data.delta;
|
|
15342
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta }] } };
|
|
15343
|
+
break;
|
|
15344
|
+
}
|
|
15345
|
+
case "response.output_item.done": {
|
|
15346
|
+
const item = data.item;
|
|
15347
|
+
if (item?.type !== "function_call") break;
|
|
15348
|
+
const full = typeof item.arguments === "string" ? item.arguments : "";
|
|
15349
|
+
const call = calls.get(item.id ?? item.call_id);
|
|
15350
|
+
if (!call) {
|
|
15351
|
+
const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full };
|
|
15352
|
+
calls.set(item.id ?? added.callId, added);
|
|
15353
|
+
yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full }] } };
|
|
15354
|
+
} else if (full.length > call.arguments.length && full.startsWith(call.arguments)) {
|
|
15355
|
+
const rest = full.slice(call.arguments.length);
|
|
15356
|
+
call.arguments = full;
|
|
15357
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest }] } };
|
|
15358
|
+
}
|
|
15359
|
+
break;
|
|
15360
|
+
}
|
|
15361
|
+
case "response.completed":
|
|
15362
|
+
case "response.incomplete":
|
|
15363
|
+
final = this.parseResponsesResponse(data.response ?? {}, modelId);
|
|
15364
|
+
break;
|
|
15365
|
+
case "response.failed":
|
|
15366
|
+
case "error": {
|
|
15367
|
+
const err = data.response?.error ?? data.error ?? data;
|
|
15368
|
+
throw new ProviderError(
|
|
15369
|
+
`OpenAI Responses API stream error: ${err?.message ?? "unknown error"}`,
|
|
15370
|
+
this.providerName,
|
|
15371
|
+
void 0,
|
|
15372
|
+
data
|
|
15373
|
+
);
|
|
15374
|
+
}
|
|
15375
|
+
}
|
|
15376
|
+
}
|
|
15377
|
+
yield {
|
|
15378
|
+
id: final?.id || id,
|
|
15379
|
+
model: final?.model || model,
|
|
15380
|
+
delta: final?.reasoning ? { reasoning: final.reasoning } : {},
|
|
15381
|
+
usage: final?.usage,
|
|
15382
|
+
finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
|
|
15383
|
+
};
|
|
15384
|
+
}
|
|
14927
15385
|
buildResponsesBody(request) {
|
|
14928
15386
|
const body = {
|
|
14929
15387
|
model: request.model || this.defaultModel,
|
|
@@ -14953,7 +15411,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
14953
15411
|
format: {
|
|
14954
15412
|
type: "json_schema",
|
|
14955
15413
|
name: request.responseFormat.name ?? "response",
|
|
14956
|
-
schema: request.responseFormat.schema,
|
|
15414
|
+
schema: inlineJsonSchemaRefs(request.responseFormat.schema),
|
|
14957
15415
|
strict: true
|
|
14958
15416
|
}
|
|
14959
15417
|
};
|
|
@@ -15208,6 +15666,48 @@ function isReasoningModel(model) {
|
|
|
15208
15666
|
const m = model.toLowerCase();
|
|
15209
15667
|
return /(^|[/_-])o[0-9]/.test(m) || m.startsWith("o1") || m.startsWith("o3") || m.startsWith("o4") || m.includes("gpt-5") || m.includes("gpt5");
|
|
15210
15668
|
}
|
|
15669
|
+
function adaptChatExtrasForResponses(body, extra) {
|
|
15670
|
+
const native = extra ?? {};
|
|
15671
|
+
if ("reasoning_effort" in body) {
|
|
15672
|
+
const effort = body.reasoning_effort;
|
|
15673
|
+
delete body.reasoning_effort;
|
|
15674
|
+
if (effort != null) {
|
|
15675
|
+
const reasoning = body.reasoning && typeof body.reasoning === "object" ? body.reasoning : {};
|
|
15676
|
+
if (reasoning.effort == null) body.reasoning = { ...reasoning, effort };
|
|
15677
|
+
}
|
|
15678
|
+
}
|
|
15679
|
+
for (const key of ["max_tokens", "max_completion_tokens"]) {
|
|
15680
|
+
if (!(key in body)) continue;
|
|
15681
|
+
const value = body[key];
|
|
15682
|
+
delete body[key];
|
|
15683
|
+
if (value != null && !("max_output_tokens" in native)) body.max_output_tokens = value;
|
|
15684
|
+
}
|
|
15685
|
+
if ("response_format" in body) {
|
|
15686
|
+
const format = toResponsesTextFormat(body.response_format);
|
|
15687
|
+
delete body.response_format;
|
|
15688
|
+
if (format && !("text" in native)) body.text = { ...body.text, format };
|
|
15689
|
+
}
|
|
15690
|
+
if (body.stream_options && typeof body.stream_options === "object" && "include_usage" in body.stream_options) {
|
|
15691
|
+
const { include_usage: _dropped, ...rest } = body.stream_options;
|
|
15692
|
+
if (Object.keys(rest).length > 0) body.stream_options = rest;
|
|
15693
|
+
else delete body.stream_options;
|
|
15694
|
+
}
|
|
15695
|
+
}
|
|
15696
|
+
function toResponsesTextFormat(rf) {
|
|
15697
|
+
if (!rf || typeof rf !== "object") return void 0;
|
|
15698
|
+
if (rf.type === "json_schema") {
|
|
15699
|
+
const js = rf.json_schema ?? {};
|
|
15700
|
+
return {
|
|
15701
|
+
type: "json_schema",
|
|
15702
|
+
name: js.name ?? "response",
|
|
15703
|
+
schema: inlineJsonSchemaRefs(js.schema),
|
|
15704
|
+
...js.description != null ? { description: js.description } : {},
|
|
15705
|
+
...js.strict != null ? { strict: js.strict } : {}
|
|
15706
|
+
};
|
|
15707
|
+
}
|
|
15708
|
+
if (rf.type === "json_object" || rf.type === "text") return { type: rf.type };
|
|
15709
|
+
return void 0;
|
|
15710
|
+
}
|
|
15211
15711
|
function expandResponsesInput(input) {
|
|
15212
15712
|
const out = [];
|
|
15213
15713
|
for (const item of input) {
|
|
@@ -16658,6 +17158,7 @@ exports.httpSink = httpSink;
|
|
|
16658
17158
|
exports.inMemoryCheckpointStore = inMemoryCheckpointStore;
|
|
16659
17159
|
exports.inMemoryConversationStore = inMemoryConversationStore;
|
|
16660
17160
|
exports.isHookImplemented = isHookImplemented;
|
|
17161
|
+
exports.isOpenAIHostedEndpoint = isOpenAIHostedEndpoint;
|
|
16661
17162
|
exports.isSmartModel = isSmartModel;
|
|
16662
17163
|
exports.isValidIban = isValidIban;
|
|
16663
17164
|
exports.isValidLuhn = isValidLuhn;
|
|
@@ -16686,6 +17187,7 @@ exports.portkeyGateway = portkeyGateway;
|
|
|
16686
17187
|
exports.portkeyGuardrail = portkeyGuardrail;
|
|
16687
17188
|
exports.preopenSkills = preopenSkills;
|
|
16688
17189
|
exports.preopenToolCallId = preopenToolCallId;
|
|
17190
|
+
exports.prepareStrictToolMenu = prepareStrictToolMenu;
|
|
16689
17191
|
exports.promptInjectionGuard = promptInjectionGuard;
|
|
16690
17192
|
exports.rateLimit = rateLimit;
|
|
16691
17193
|
exports.readMemoryFacts = readMemoryFacts;
|
|
@@ -16705,6 +17207,7 @@ exports.resolveToolApprovalState = resolveToolApprovalState;
|
|
|
16705
17207
|
exports.resolveUserQuestionState = resolveUserQuestionState;
|
|
16706
17208
|
exports.responseCache = responseCache;
|
|
16707
17209
|
exports.restoreSnapshot = restoreSnapshot;
|
|
17210
|
+
exports.restoreToolCalls = restoreToolCalls;
|
|
16708
17211
|
exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
|
|
16709
17212
|
exports.scoreItemsByRelevance = scoreItemsByRelevance;
|
|
16710
17213
|
exports.searchSkills = searchSkills;
|
|
@@ -16715,6 +17218,8 @@ exports.setTokenCounter = setTokenCounter;
|
|
|
16715
17218
|
exports.startStreamingSession = startStreamingSession;
|
|
16716
17219
|
exports.summarizeObject = summarizeObject;
|
|
16717
17220
|
exports.textFromContent = textFromContent;
|
|
17221
|
+
exports.toStrictCompatible = toStrictCompatible;
|
|
17222
|
+
exports.toStrictToolSchema = toStrictToolSchema;
|
|
16718
17223
|
exports.tokenize = tokenize;
|
|
16719
17224
|
exports.toolPolicy = toolPolicy;
|
|
16720
17225
|
exports.traceSessionToOtlp = traceSessionToOtlp;
|