@cognipeer/agent-sdk 0.10.4 → 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 +276 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -1
- package/dist/index.d.ts +47 -1
- package/dist/index.mjs +276 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -14991,8 +14991,127 @@ function sanitizeBedrockDocName(name, fallback = "document") {
|
|
|
14991
14991
|
return cleaned || fallback;
|
|
14992
14992
|
}
|
|
14993
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
|
+
|
|
14994
15113
|
// src/providers/openai.ts
|
|
14995
|
-
var OpenAIProvider = class extends BaseProvider {
|
|
15114
|
+
var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
14996
15115
|
constructor(config) {
|
|
14997
15116
|
super();
|
|
14998
15117
|
this.providerName = "openai";
|
|
@@ -15004,8 +15123,21 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15004
15123
|
...config.organization ? { "OpenAI-Organization": config.organization } : {}
|
|
15005
15124
|
};
|
|
15006
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;
|
|
15007
15129
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
15008
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
|
+
}
|
|
15009
15141
|
/** True when this request should go to the Responses API rather than Chat
|
|
15010
15142
|
* Completions — which exposes `reasoning.effort` and reasoning summaries that
|
|
15011
15143
|
* Chat Completions silently drops.
|
|
@@ -15014,10 +15146,14 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15014
15146
|
* carries a reasoning config AND the model name looks like an o-series/gpt-5
|
|
15015
15147
|
* model. `never`/`always` let a caller state the answer instead, because the
|
|
15016
15148
|
* name check is a guess and the two APIs differ in far more than reasoning —
|
|
15017
|
-
* 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. */
|
|
15018
15153
|
useResponsesApi(request) {
|
|
15019
15154
|
if (this.responsesApi === "never") return false;
|
|
15020
15155
|
if (this.responsesApi === "always") return true;
|
|
15156
|
+
if (this.isResponsesApiModel(request)) return true;
|
|
15021
15157
|
if (!request.reasoning) return false;
|
|
15022
15158
|
return isReasoningModel(request.model || this.defaultModel);
|
|
15023
15159
|
}
|
|
@@ -15032,6 +15168,10 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15032
15168
|
}
|
|
15033
15169
|
async *completeStream(request) {
|
|
15034
15170
|
if (this.useResponsesApi(request)) {
|
|
15171
|
+
if (this.responsesStreaming && this.isResponsesApiModel(request)) {
|
|
15172
|
+
yield* this.streamResponses(request);
|
|
15173
|
+
return;
|
|
15174
|
+
}
|
|
15035
15175
|
const response = await this.completeResponses(request);
|
|
15036
15176
|
yield {
|
|
15037
15177
|
id: response.id,
|
|
@@ -15147,10 +15287,101 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15147
15287
|
// ─── Responses API (reasoning models) ──────────────────────────────────────
|
|
15148
15288
|
async completeResponses(request) {
|
|
15149
15289
|
const body = this.buildResponsesBody(request);
|
|
15290
|
+
if (this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
|
|
15150
15291
|
const res = await this.responsesFetch(body);
|
|
15151
15292
|
const json = await res.json();
|
|
15152
15293
|
return this.parseResponsesResponse(json, request.model || this.defaultModel);
|
|
15153
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
|
+
}
|
|
15154
15385
|
buildResponsesBody(request) {
|
|
15155
15386
|
const body = {
|
|
15156
15387
|
model: request.model || this.defaultModel,
|
|
@@ -15180,7 +15411,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15180
15411
|
format: {
|
|
15181
15412
|
type: "json_schema",
|
|
15182
15413
|
name: request.responseFormat.name ?? "response",
|
|
15183
|
-
schema: request.responseFormat.schema,
|
|
15414
|
+
schema: inlineJsonSchemaRefs(request.responseFormat.schema),
|
|
15184
15415
|
strict: true
|
|
15185
15416
|
}
|
|
15186
15417
|
};
|
|
@@ -15435,6 +15666,48 @@ function isReasoningModel(model) {
|
|
|
15435
15666
|
const m = model.toLowerCase();
|
|
15436
15667
|
return /(^|[/_-])o[0-9]/.test(m) || m.startsWith("o1") || m.startsWith("o3") || m.startsWith("o4") || m.includes("gpt-5") || m.includes("gpt5");
|
|
15437
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
|
+
}
|
|
15438
15711
|
function expandResponsesInput(input) {
|
|
15439
15712
|
const out = [];
|
|
15440
15713
|
for (const item of input) {
|