@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.js CHANGED
@@ -4754,7 +4754,14 @@ var init_env_policy = __esm({
4754
4754
  /[_-]PWD/i,
4755
4755
  /CREDENTIAL/i,
4756
4756
  /PRIVATE/i,
4757
- /_AUTH/i
4757
+ /_AUTH/i,
4758
+ // #54-a — value-embedded-secret conventions (no generic `*_URL` — see keep-list test).
4759
+ /DSN/i,
4760
+ /WEBHOOK/i,
4761
+ /COOKIE/i,
4762
+ /CONNECTION[_-]?STRING/i,
4763
+ // Known DB / message-broker connection-string vars (carry `user:pass@`).
4764
+ /(?:^|[_-])(?:DATABASE|DB|REDIS|MONGO(?:DB)?|POSTGRES(?:QL)?|MYSQL|MARIADB|AMQP|RABBITMQ|CLICKHOUSE|ELASTIC(?:SEARCH)?|CASSANDRA|COUCHDB|MEMCACHED|NATS|KAFKA)[_-]?(?:URL|URI|DSN|CONNECTION)/i
4758
4765
  ];
4759
4766
  CORE_VARS = [
4760
4767
  "PATH",
@@ -5163,12 +5170,23 @@ var init_objective_coerce = __esm({
5163
5170
  // src/internal/persistence/pagination.ts
5164
5171
  function paginate(items, opts) {
5165
5172
  if (opts === void 0 || opts.offset === void 0 && opts.limit === void 0) return items;
5166
- const start = Math.max(0, opts.offset ?? 0);
5167
- const end = opts.limit === void 0 ? items.length : start + Math.max(0, opts.limit);
5173
+ const start = opts.offset === void 0 ? 0 : requireNonNegativeInt(opts.offset, "offset");
5174
+ const limit = opts.limit === void 0 ? void 0 : requireNonNegativeInt(opts.limit, "limit");
5175
+ const end = limit === void 0 ? items.length : start + limit;
5168
5176
  return items.slice(start, end);
5169
5177
  }
5178
+ function requireNonNegativeInt(value, field) {
5179
+ if (!Number.isInteger(value) || value < 0) {
5180
+ throw new ConfigurationError(
5181
+ `Invalid pagination ${field}: expected a non-negative integer, got ${value}`,
5182
+ { code: "pagination_invalid" }
5183
+ );
5184
+ }
5185
+ return value;
5186
+ }
5170
5187
  var init_pagination = __esm({
5171
5188
  "src/internal/persistence/pagination.ts"() {
5189
+ init_errors();
5172
5190
  }
5173
5191
  });
5174
5192
 
@@ -7751,15 +7769,19 @@ async function collectChildToolResults(run) {
7751
7769
  ${lines.join("\n")}
7752
7770
  </subagent-tool-results>`;
7753
7771
  }
7754
- async function runChildAgent(spec, input, signal, maxSteps, inherited) {
7755
- const { Agent: Agent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
7772
+ function buildChildCreateOptions(spec, inherited) {
7756
7773
  const model = spec.model ? { id: spec.model } : inherited?.model;
7757
- const agent = await Agent2.create({
7774
+ return {
7758
7775
  ...inherited?.apiKey !== void 0 ? { apiKey: inherited.apiKey } : {},
7759
7776
  ...model !== void 0 ? { model } : {},
7777
+ ...inherited?.plugins !== void 0 ? { plugins: inherited.plugins } : {},
7760
7778
  systemPrompt: spec.instructions,
7761
7779
  tools: spec.tools ?? []
7762
- });
7780
+ };
7781
+ }
7782
+ async function runChildAgent(spec, input, signal, maxSteps, inherited) {
7783
+ const { Agent: Agent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
7784
+ const agent = await Agent2.create(buildChildCreateOptions(spec, inherited));
7763
7785
  try {
7764
7786
  const sendOptions = {
7765
7787
  ...signal !== void 0 ? { signal } : {},
@@ -9662,7 +9684,10 @@ async function runAgentLoop(inputs) {
9662
9684
  }
9663
9685
  budget.consume();
9664
9686
  inputs.budgetTracker?.nextIteration?.();
9665
- if (inputs.signal?.aborted === true) break;
9687
+ if (inputs.signal?.aborted === true) {
9688
+ ctx.finalStatus = "cancelled";
9689
+ break;
9690
+ }
9666
9691
  }
9667
9692
  if (lastTurnDecision === "continue" && budget.shouldContinue() === false) {
9668
9693
  ctx.stoppedAtIterationLimit = true;
@@ -9847,15 +9872,15 @@ async function guardAndTransformToolResults(inputs, raw, ctx) {
9847
9872
  }
9848
9873
  async function continueOrTerminate(inputs, ctx, llmOutput) {
9849
9874
  if (llmOutput.errored) return "error";
9850
- if (llmOutput.text.length > 0) {
9851
- await emitAssistantTextStep(inputs, ctx, llmOutput.text);
9875
+ const tCtx = { agentId: inputs.agentId, runId: inputs.runId };
9876
+ const text = llmOutput.text.length > 0 ? await transformLlmOutputText(inputs, llmOutput.text, tCtx) : llmOutput.text;
9877
+ if (text.length > 0) {
9878
+ await emitAssistantTextStep(inputs, ctx, text);
9852
9879
  }
9853
9880
  if (llmOutput.stopReason !== "tool_use" || llmOutput.toolCalls.length === 0) {
9854
9881
  return finishOrReflect(inputs, ctx, llmOutput);
9855
9882
  }
9856
- const tCtx = { agentId: inputs.agentId, runId: inputs.runId };
9857
- const outText = await transformLlmOutputText(inputs, llmOutput.text, tCtx);
9858
- ctx.messages.push(buildAssistantTurn(outText, llmOutput.toolCalls));
9883
+ ctx.messages.push(buildAssistantTurn(text, llmOutput.toolCalls));
9859
9884
  const rawResults = await dispatchTools(
9860
9885
  // SE12 — forward a read-only text projection of the transcript-so-far to tool
9861
9886
  // handlers via `ctx.messages` (consumed by defineSubAgent's messageFilter).
@@ -10333,6 +10358,8 @@ function parseRetryAfter(headers) {
10333
10358
  if (raw === null) return void 0;
10334
10359
  const n = Number(raw);
10335
10360
  if (Number.isFinite(n) && n >= 0) return Math.ceil(n);
10361
+ const dateMs = Date.parse(raw);
10362
+ if (Number.isFinite(dateMs)) return Math.max(0, Math.ceil((dateMs - Date.now()) / 1e3));
10336
10363
  return void 0;
10337
10364
  }
10338
10365
  function truncateRaw(body) {
@@ -10653,6 +10680,7 @@ function buildAnthropicBody(request) {
10653
10680
  var AnthropicClient, AnthropicStreamAccumulator;
10654
10681
  var init_anthropic3 = __esm({
10655
10682
  "src/internal/llm/anthropic.ts"() {
10683
+ init_errors();
10656
10684
  init_anthropic2();
10657
10685
  init_anthropic_shared();
10658
10686
  init_finish();
@@ -10706,12 +10734,23 @@ var init_anthropic3 = __esm({
10706
10734
  const events = accumulator.consume(parsed);
10707
10735
  for (const event of events) yield event;
10708
10736
  }
10737
+ if (!accumulator.finishReasonSeen) {
10738
+ throw new NetworkError("Anthropic SSE stream truncated (no stop_reason)", {
10739
+ code: "stream_truncated"
10740
+ });
10741
+ }
10709
10742
  return accumulator.finish();
10710
10743
  }
10711
10744
  };
10712
10745
  AnthropicStreamAccumulator = class {
10713
10746
  text = "";
10714
10747
  stopReason = "end_turn";
10748
+ /**
10749
+ * M2 #61 — whether a `message_delta` carrying a real `stop_reason` was seen.
10750
+ * A stream that closes before it is a truncation (server FIN / proxy hiccup),
10751
+ * not a clean `end_turn` — the caller throws `stream_truncated` on `false`.
10752
+ */
10753
+ sawStopReason = false;
10715
10754
  inputTokens;
10716
10755
  outputTokens;
10717
10756
  cacheReadTokens;
@@ -10758,6 +10797,9 @@ var init_anthropic3 = __esm({
10758
10797
  * spinning the SSE parser.
10759
10798
  */
10760
10799
  handleMessageDelta(md) {
10800
+ if (md.delta.stop_reason !== void 0 && md.delta.stop_reason !== null) {
10801
+ this.sawStopReason = true;
10802
+ }
10761
10803
  this.stopReason = mapAnthropicStopReason(md.delta.stop_reason);
10762
10804
  if (md.usage?.input_tokens !== void 0) this.inputTokens = md.usage.input_tokens;
10763
10805
  if (md.usage?.output_tokens !== void 0) this.outputTokens = md.usage.output_tokens;
@@ -10768,6 +10810,10 @@ var init_anthropic3 = __esm({
10768
10810
  this.cacheReadTokens = md.usage.cache_read_input_tokens;
10769
10811
  }
10770
10812
  }
10813
+ /** M2 #61 — whether the terminal `message_delta` (stop_reason) was seen. */
10814
+ get finishReasonSeen() {
10815
+ return this.sawStopReason;
10816
+ }
10771
10817
  finish() {
10772
10818
  const toolCalls = [];
10773
10819
  for (const [index, tool] of this.toolCalls.entries()) {
@@ -13001,7 +13047,6 @@ var init_client = __esm({
13001
13047
  // concurrent request so parallel tool dispatch after a drop awaits one handshake
13002
13048
  // instead of racing (or spuriously failing with mcp_not_init).
13003
13049
  dropped = false;
13004
- reconnectAttempts = 0;
13005
13050
  reconnectPromise;
13006
13051
  get timeoutMs() {
13007
13052
  return this.config.requestTimeoutMs ?? DEFAULT_MCP_TIMEOUT_MS;
@@ -13054,15 +13099,22 @@ var init_client = __esm({
13054
13099
  return this.reconnectPromise;
13055
13100
  }
13056
13101
  async reconnect() {
13057
- if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
13058
- throw new NetworkError(`MCP ${this.name} reconnect exhausted`, { code: "mcp_disconnected" });
13102
+ let lastErr;
13103
+ for (let attempt = 0; attempt < MAX_RECONNECT_ATTEMPTS; attempt += 1) {
13104
+ await reconnectDelay(attempt);
13105
+ this.spawnChild();
13106
+ try {
13107
+ await super.initialize();
13108
+ this.dropped = false;
13109
+ return;
13110
+ } catch (err) {
13111
+ lastErr = err;
13112
+ }
13059
13113
  }
13060
- await reconnectDelay(this.reconnectAttempts);
13061
- this.reconnectAttempts += 1;
13062
- this.spawnChild();
13063
- await super.initialize();
13064
- this.dropped = false;
13065
- this.reconnectAttempts = 0;
13114
+ throw new NetworkError(`MCP ${this.name} reconnect exhausted`, {
13115
+ code: "mcp_disconnected",
13116
+ ...lastErr instanceof Error ? { cause: lastErr } : {}
13117
+ });
13066
13118
  }
13067
13119
  async close() {
13068
13120
  this.rejectAllPending(new NetworkError(`MCP ${this.name} closed`, { code: "mcp_closed" }));
@@ -13193,7 +13245,12 @@ var init_client = __esm({
13193
13245
  code: "mcp_http_error"
13194
13246
  });
13195
13247
  }
13196
- return await response.json();
13248
+ try {
13249
+ return await response.json();
13250
+ } catch (cause) {
13251
+ if (isAbortLike(cause)) throw mcpTimeoutError(this.name, timeoutMs);
13252
+ throw cause;
13253
+ }
13197
13254
  }
13198
13255
  };
13199
13256
  }
@@ -13433,9 +13490,11 @@ function declarativeSubagentTools(agentOptions, parentTools) {
13433
13490
  return subAgentToolsFromDefinitions(agents2, parentTools);
13434
13491
  }
13435
13492
  function bindParentCredentials(tools, agentOptions) {
13493
+ const parentPlugins = Array.isArray(agentOptions.plugins) ? agentOptions.plugins : void 0;
13436
13494
  const credentials = {
13437
13495
  ...agentOptions.apiKey !== void 0 ? { apiKey: agentOptions.apiKey } : {},
13438
- ...typeof agentOptions.model === "object" ? { model: agentOptions.model } : {}
13496
+ ...typeof agentOptions.model === "object" ? { model: agentOptions.model } : {},
13497
+ ...parentPlugins !== void 0 ? { plugins: parentPlugins } : {}
13439
13498
  };
13440
13499
  for (const tool of tools) inheritSubAgentCredentials(tool, credentials);
13441
13500
  }
@@ -15969,10 +16028,11 @@ var init_local_agent_memory = __esm({
15969
16028
  }
15970
16029
  buildTelemetryRecallArgs(telemetry) {
15971
16030
  const userId = typeof this.options.memoryContext?.userId === "string" ? this.options.memoryContext.userId : void 0;
16031
+ const tenantId = typeof this.options.memoryContext?.tenantId === "string" ? this.options.memoryContext.tenantId : void 0;
15972
16032
  return {
15973
16033
  ...telemetry !== void 0 ? { telemetry } : {},
15974
16034
  ...userId !== void 0 ? { userId } : {},
15975
- namespace: "default",
16035
+ namespace: tenantId ?? "default",
15976
16036
  scope: "session"
15977
16037
  };
15978
16038
  }
@@ -22242,8 +22302,10 @@ var JobQueue = class {
22242
22302
  const job = this.jobs.get(id);
22243
22303
  if (!job) return false;
22244
22304
  if (job.status === "pending" || job.status === "running") {
22305
+ const wasRunning = job.status === "running";
22245
22306
  job.status = "cancelled";
22246
22307
  this.controllers.get(id)?.abort();
22308
+ if (wasRunning) this.#release(id);
22247
22309
  return true;
22248
22310
  }
22249
22311
  return false;
@@ -22261,8 +22323,14 @@ var JobQueue = class {
22261
22323
  });
22262
22324
  });
22263
22325
  }
22264
- /** Release a slot + clean up the controller; start the next waiting job. */
22326
+ /**
22327
+ * Release a slot + clean up the controller; start the next waiting job.
22328
+ * Idempotent — keyed on the controller's presence, so a running job that was
22329
+ * cancelled (released early) does not double-decrement when its `.finally`
22330
+ * eventually fires.
22331
+ */
22265
22332
  #release(id) {
22333
+ if (!this.controllers.has(id)) return;
22266
22334
  this.controllers.delete(id);
22267
22335
  this.running -= 1;
22268
22336
  const next = this.waiting.shift();