@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 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) {