@theokit/sdk 3.2.0 → 3.2.3

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
@@ -4757,7 +4757,14 @@ var init_env_policy = __esm({
4757
4757
  /[_-]PWD/i,
4758
4758
  /CREDENTIAL/i,
4759
4759
  /PRIVATE/i,
4760
- /_AUTH/i
4760
+ /_AUTH/i,
4761
+ // #54-a — value-embedded-secret conventions (no generic `*_URL` — see keep-list test).
4762
+ /DSN/i,
4763
+ /WEBHOOK/i,
4764
+ /COOKIE/i,
4765
+ /CONNECTION[_-]?STRING/i,
4766
+ // Known DB / message-broker connection-string vars (carry `user:pass@`).
4767
+ /(?:^|[_-])(?:DATABASE|DB|REDIS|MONGO(?:DB)?|POSTGRES(?:QL)?|MYSQL|MARIADB|AMQP|RABBITMQ|CLICKHOUSE|ELASTIC(?:SEARCH)?|CASSANDRA|COUCHDB|MEMCACHED|NATS|KAFKA)[_-]?(?:URL|URI|DSN|CONNECTION)/i
4761
4768
  ];
4762
4769
  CORE_VARS = [
4763
4770
  "PATH",
@@ -5166,12 +5173,23 @@ var init_objective_coerce = __esm({
5166
5173
  // src/internal/persistence/pagination.ts
5167
5174
  function paginate(items, opts) {
5168
5175
  if (opts === void 0 || opts.offset === void 0 && opts.limit === void 0) return items;
5169
- const start = Math.max(0, opts.offset ?? 0);
5170
- const end = opts.limit === void 0 ? items.length : start + Math.max(0, opts.limit);
5176
+ const start = opts.offset === void 0 ? 0 : requireNonNegativeInt(opts.offset, "offset");
5177
+ const limit = opts.limit === void 0 ? void 0 : requireNonNegativeInt(opts.limit, "limit");
5178
+ const end = limit === void 0 ? items.length : start + limit;
5171
5179
  return items.slice(start, end);
5172
5180
  }
5181
+ function requireNonNegativeInt(value, field) {
5182
+ if (!Number.isInteger(value) || value < 0) {
5183
+ throw new exports.ConfigurationError(
5184
+ `Invalid pagination ${field}: expected a non-negative integer, got ${value}`,
5185
+ { code: "pagination_invalid" }
5186
+ );
5187
+ }
5188
+ return value;
5189
+ }
5173
5190
  var init_pagination = __esm({
5174
5191
  "src/internal/persistence/pagination.ts"() {
5192
+ init_errors();
5175
5193
  }
5176
5194
  });
5177
5195
 
@@ -7754,15 +7772,19 @@ async function collectChildToolResults(run) {
7754
7772
  ${lines.join("\n")}
7755
7773
  </subagent-tool-results>`;
7756
7774
  }
7757
- async function runChildAgent(spec, input, signal, maxSteps, inherited) {
7758
- const { Agent: Agent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
7775
+ function buildChildCreateOptions(spec, inherited) {
7759
7776
  const model = spec.model ? { id: spec.model } : inherited?.model;
7760
- const agent = await Agent2.create({
7777
+ return {
7761
7778
  ...inherited?.apiKey !== void 0 ? { apiKey: inherited.apiKey } : {},
7762
7779
  ...model !== void 0 ? { model } : {},
7780
+ ...inherited?.plugins !== void 0 ? { plugins: inherited.plugins } : {},
7763
7781
  systemPrompt: spec.instructions,
7764
7782
  tools: spec.tools ?? []
7765
- });
7783
+ };
7784
+ }
7785
+ async function runChildAgent(spec, input, signal, maxSteps, inherited) {
7786
+ const { Agent: Agent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
7787
+ const agent = await Agent2.create(buildChildCreateOptions(spec, inherited));
7766
7788
  try {
7767
7789
  const sendOptions = {
7768
7790
  ...signal !== void 0 ? { signal } : {},
@@ -9665,7 +9687,10 @@ async function runAgentLoop(inputs) {
9665
9687
  }
9666
9688
  budget.consume();
9667
9689
  inputs.budgetTracker?.nextIteration?.();
9668
- if (inputs.signal?.aborted === true) break;
9690
+ if (inputs.signal?.aborted === true) {
9691
+ ctx.finalStatus = "cancelled";
9692
+ break;
9693
+ }
9669
9694
  }
9670
9695
  if (lastTurnDecision === "continue" && budget.shouldContinue() === false) {
9671
9696
  ctx.stoppedAtIterationLimit = true;
@@ -9850,15 +9875,15 @@ async function guardAndTransformToolResults(inputs, raw, ctx) {
9850
9875
  }
9851
9876
  async function continueOrTerminate(inputs, ctx, llmOutput) {
9852
9877
  if (llmOutput.errored) return "error";
9853
- if (llmOutput.text.length > 0) {
9854
- await emitAssistantTextStep(inputs, ctx, llmOutput.text);
9878
+ const tCtx = { agentId: inputs.agentId, runId: inputs.runId };
9879
+ const text = llmOutput.text.length > 0 ? await transformLlmOutputText(inputs, llmOutput.text, tCtx) : llmOutput.text;
9880
+ if (text.length > 0) {
9881
+ await emitAssistantTextStep(inputs, ctx, text);
9855
9882
  }
9856
9883
  if (llmOutput.stopReason !== "tool_use" || llmOutput.toolCalls.length === 0) {
9857
9884
  return finishOrReflect(inputs, ctx, llmOutput);
9858
9885
  }
9859
- const tCtx = { agentId: inputs.agentId, runId: inputs.runId };
9860
- const outText = await transformLlmOutputText(inputs, llmOutput.text, tCtx);
9861
- ctx.messages.push(buildAssistantTurn(outText, llmOutput.toolCalls));
9886
+ ctx.messages.push(buildAssistantTurn(text, llmOutput.toolCalls));
9862
9887
  const rawResults = await dispatchTools(
9863
9888
  // SE12 — forward a read-only text projection of the transcript-so-far to tool
9864
9889
  // handlers via `ctx.messages` (consumed by defineSubAgent's messageFilter).
@@ -10336,6 +10361,8 @@ function parseRetryAfter(headers) {
10336
10361
  if (raw === null) return void 0;
10337
10362
  const n = Number(raw);
10338
10363
  if (Number.isFinite(n) && n >= 0) return Math.ceil(n);
10364
+ const dateMs = Date.parse(raw);
10365
+ if (Number.isFinite(dateMs)) return Math.max(0, Math.ceil((dateMs - Date.now()) / 1e3));
10339
10366
  return void 0;
10340
10367
  }
10341
10368
  function truncateRaw(body) {
@@ -10656,6 +10683,7 @@ function buildAnthropicBody(request) {
10656
10683
  var AnthropicClient, AnthropicStreamAccumulator;
10657
10684
  var init_anthropic3 = __esm({
10658
10685
  "src/internal/llm/anthropic.ts"() {
10686
+ init_errors();
10659
10687
  init_anthropic2();
10660
10688
  init_anthropic_shared();
10661
10689
  init_finish();
@@ -10709,12 +10737,23 @@ var init_anthropic3 = __esm({
10709
10737
  const events = accumulator.consume(parsed);
10710
10738
  for (const event of events) yield event;
10711
10739
  }
10740
+ if (!accumulator.finishReasonSeen) {
10741
+ throw new exports.NetworkError("Anthropic SSE stream truncated (no stop_reason)", {
10742
+ code: "stream_truncated"
10743
+ });
10744
+ }
10712
10745
  return accumulator.finish();
10713
10746
  }
10714
10747
  };
10715
10748
  AnthropicStreamAccumulator = class {
10716
10749
  text = "";
10717
10750
  stopReason = "end_turn";
10751
+ /**
10752
+ * M2 #61 — whether a `message_delta` carrying a real `stop_reason` was seen.
10753
+ * A stream that closes before it is a truncation (server FIN / proxy hiccup),
10754
+ * not a clean `end_turn` — the caller throws `stream_truncated` on `false`.
10755
+ */
10756
+ sawStopReason = false;
10718
10757
  inputTokens;
10719
10758
  outputTokens;
10720
10759
  cacheReadTokens;
@@ -10761,6 +10800,9 @@ var init_anthropic3 = __esm({
10761
10800
  * spinning the SSE parser.
10762
10801
  */
10763
10802
  handleMessageDelta(md) {
10803
+ if (md.delta.stop_reason !== void 0 && md.delta.stop_reason !== null) {
10804
+ this.sawStopReason = true;
10805
+ }
10764
10806
  this.stopReason = mapAnthropicStopReason(md.delta.stop_reason);
10765
10807
  if (md.usage?.input_tokens !== void 0) this.inputTokens = md.usage.input_tokens;
10766
10808
  if (md.usage?.output_tokens !== void 0) this.outputTokens = md.usage.output_tokens;
@@ -10771,6 +10813,10 @@ var init_anthropic3 = __esm({
10771
10813
  this.cacheReadTokens = md.usage.cache_read_input_tokens;
10772
10814
  }
10773
10815
  }
10816
+ /** M2 #61 — whether the terminal `message_delta` (stop_reason) was seen. */
10817
+ get finishReasonSeen() {
10818
+ return this.sawStopReason;
10819
+ }
10774
10820
  finish() {
10775
10821
  const toolCalls = [];
10776
10822
  for (const [index, tool] of this.toolCalls.entries()) {
@@ -13004,7 +13050,6 @@ var init_client = __esm({
13004
13050
  // concurrent request so parallel tool dispatch after a drop awaits one handshake
13005
13051
  // instead of racing (or spuriously failing with mcp_not_init).
13006
13052
  dropped = false;
13007
- reconnectAttempts = 0;
13008
13053
  reconnectPromise;
13009
13054
  get timeoutMs() {
13010
13055
  return this.config.requestTimeoutMs ?? DEFAULT_MCP_TIMEOUT_MS;
@@ -13057,15 +13102,22 @@ var init_client = __esm({
13057
13102
  return this.reconnectPromise;
13058
13103
  }
13059
13104
  async reconnect() {
13060
- if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
13061
- throw new exports.NetworkError(`MCP ${this.name} reconnect exhausted`, { code: "mcp_disconnected" });
13105
+ let lastErr;
13106
+ for (let attempt = 0; attempt < MAX_RECONNECT_ATTEMPTS; attempt += 1) {
13107
+ await reconnectDelay(attempt);
13108
+ this.spawnChild();
13109
+ try {
13110
+ await super.initialize();
13111
+ this.dropped = false;
13112
+ return;
13113
+ } catch (err) {
13114
+ lastErr = err;
13115
+ }
13062
13116
  }
13063
- await reconnectDelay(this.reconnectAttempts);
13064
- this.reconnectAttempts += 1;
13065
- this.spawnChild();
13066
- await super.initialize();
13067
- this.dropped = false;
13068
- this.reconnectAttempts = 0;
13117
+ throw new exports.NetworkError(`MCP ${this.name} reconnect exhausted`, {
13118
+ code: "mcp_disconnected",
13119
+ ...lastErr instanceof Error ? { cause: lastErr } : {}
13120
+ });
13069
13121
  }
13070
13122
  async close() {
13071
13123
  this.rejectAllPending(new exports.NetworkError(`MCP ${this.name} closed`, { code: "mcp_closed" }));
@@ -13196,7 +13248,12 @@ var init_client = __esm({
13196
13248
  code: "mcp_http_error"
13197
13249
  });
13198
13250
  }
13199
- return await response.json();
13251
+ try {
13252
+ return await response.json();
13253
+ } catch (cause) {
13254
+ if (isAbortLike(cause)) throw mcpTimeoutError(this.name, timeoutMs);
13255
+ throw cause;
13256
+ }
13200
13257
  }
13201
13258
  };
13202
13259
  }
@@ -13436,9 +13493,11 @@ function declarativeSubagentTools(agentOptions, parentTools) {
13436
13493
  return subAgentToolsFromDefinitions(agents2, parentTools);
13437
13494
  }
13438
13495
  function bindParentCredentials(tools, agentOptions) {
13496
+ const parentPlugins = Array.isArray(agentOptions.plugins) ? agentOptions.plugins : void 0;
13439
13497
  const credentials = {
13440
13498
  ...agentOptions.apiKey !== void 0 ? { apiKey: agentOptions.apiKey } : {},
13441
- ...typeof agentOptions.model === "object" ? { model: agentOptions.model } : {}
13499
+ ...typeof agentOptions.model === "object" ? { model: agentOptions.model } : {},
13500
+ ...parentPlugins !== void 0 ? { plugins: parentPlugins } : {}
13442
13501
  };
13443
13502
  for (const tool of tools) inheritSubAgentCredentials(tool, credentials);
13444
13503
  }
@@ -15972,10 +16031,11 @@ var init_local_agent_memory = __esm({
15972
16031
  }
15973
16032
  buildTelemetryRecallArgs(telemetry) {
15974
16033
  const userId = typeof this.options.memoryContext?.userId === "string" ? this.options.memoryContext.userId : void 0;
16034
+ const tenantId = typeof this.options.memoryContext?.tenantId === "string" ? this.options.memoryContext.tenantId : void 0;
15975
16035
  return {
15976
16036
  ...telemetry !== void 0 ? { telemetry } : {},
15977
16037
  ...userId !== void 0 ? { userId } : {},
15978
- namespace: "default",
16038
+ namespace: tenantId ?? "default",
15979
16039
  scope: "session"
15980
16040
  };
15981
16041
  }
@@ -22245,8 +22305,10 @@ var JobQueue = class {
22245
22305
  const job = this.jobs.get(id);
22246
22306
  if (!job) return false;
22247
22307
  if (job.status === "pending" || job.status === "running") {
22308
+ const wasRunning = job.status === "running";
22248
22309
  job.status = "cancelled";
22249
22310
  this.controllers.get(id)?.abort();
22311
+ if (wasRunning) this.#release(id);
22250
22312
  return true;
22251
22313
  }
22252
22314
  return false;
@@ -22264,8 +22326,14 @@ var JobQueue = class {
22264
22326
  });
22265
22327
  });
22266
22328
  }
22267
- /** Release a slot + clean up the controller; start the next waiting job. */
22329
+ /**
22330
+ * Release a slot + clean up the controller; start the next waiting job.
22331
+ * Idempotent — keyed on the controller's presence, so a running job that was
22332
+ * cancelled (released early) does not double-decrement when its `.finally`
22333
+ * eventually fires.
22334
+ */
22268
22335
  #release(id) {
22336
+ if (!this.controllers.has(id)) return;
22269
22337
  this.controllers.delete(id);
22270
22338
  this.running -= 1;
22271
22339
  const next = this.waiting.shift();