@theokit/sdk 3.2.2 → 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
@@ -5170,12 +5170,23 @@ var init_objective_coerce = __esm({
5170
5170
  // src/internal/persistence/pagination.ts
5171
5171
  function paginate(items, opts) {
5172
5172
  if (opts === void 0 || opts.offset === void 0 && opts.limit === void 0) return items;
5173
- const start = Math.max(0, opts.offset ?? 0);
5174
- 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;
5175
5176
  return items.slice(start, end);
5176
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
+ }
5177
5187
  var init_pagination = __esm({
5178
5188
  "src/internal/persistence/pagination.ts"() {
5189
+ init_errors();
5179
5190
  }
5180
5191
  });
5181
5192
 
@@ -10347,6 +10358,8 @@ function parseRetryAfter(headers) {
10347
10358
  if (raw === null) return void 0;
10348
10359
  const n = Number(raw);
10349
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));
10350
10363
  return void 0;
10351
10364
  }
10352
10365
  function truncateRaw(body) {
@@ -10667,6 +10680,7 @@ function buildAnthropicBody(request) {
10667
10680
  var AnthropicClient, AnthropicStreamAccumulator;
10668
10681
  var init_anthropic3 = __esm({
10669
10682
  "src/internal/llm/anthropic.ts"() {
10683
+ init_errors();
10670
10684
  init_anthropic2();
10671
10685
  init_anthropic_shared();
10672
10686
  init_finish();
@@ -10720,12 +10734,23 @@ var init_anthropic3 = __esm({
10720
10734
  const events = accumulator.consume(parsed);
10721
10735
  for (const event of events) yield event;
10722
10736
  }
10737
+ if (!accumulator.finishReasonSeen) {
10738
+ throw new NetworkError("Anthropic SSE stream truncated (no stop_reason)", {
10739
+ code: "stream_truncated"
10740
+ });
10741
+ }
10723
10742
  return accumulator.finish();
10724
10743
  }
10725
10744
  };
10726
10745
  AnthropicStreamAccumulator = class {
10727
10746
  text = "";
10728
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;
10729
10754
  inputTokens;
10730
10755
  outputTokens;
10731
10756
  cacheReadTokens;
@@ -10772,6 +10797,9 @@ var init_anthropic3 = __esm({
10772
10797
  * spinning the SSE parser.
10773
10798
  */
10774
10799
  handleMessageDelta(md) {
10800
+ if (md.delta.stop_reason !== void 0 && md.delta.stop_reason !== null) {
10801
+ this.sawStopReason = true;
10802
+ }
10775
10803
  this.stopReason = mapAnthropicStopReason(md.delta.stop_reason);
10776
10804
  if (md.usage?.input_tokens !== void 0) this.inputTokens = md.usage.input_tokens;
10777
10805
  if (md.usage?.output_tokens !== void 0) this.outputTokens = md.usage.output_tokens;
@@ -10782,6 +10810,10 @@ var init_anthropic3 = __esm({
10782
10810
  this.cacheReadTokens = md.usage.cache_read_input_tokens;
10783
10811
  }
10784
10812
  }
10813
+ /** M2 #61 — whether the terminal `message_delta` (stop_reason) was seen. */
10814
+ get finishReasonSeen() {
10815
+ return this.sawStopReason;
10816
+ }
10785
10817
  finish() {
10786
10818
  const toolCalls = [];
10787
10819
  for (const [index, tool] of this.toolCalls.entries()) {
@@ -13015,7 +13047,6 @@ var init_client = __esm({
13015
13047
  // concurrent request so parallel tool dispatch after a drop awaits one handshake
13016
13048
  // instead of racing (or spuriously failing with mcp_not_init).
13017
13049
  dropped = false;
13018
- reconnectAttempts = 0;
13019
13050
  reconnectPromise;
13020
13051
  get timeoutMs() {
13021
13052
  return this.config.requestTimeoutMs ?? DEFAULT_MCP_TIMEOUT_MS;
@@ -13068,15 +13099,22 @@ var init_client = __esm({
13068
13099
  return this.reconnectPromise;
13069
13100
  }
13070
13101
  async reconnect() {
13071
- if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
13072
- 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
+ }
13073
13113
  }
13074
- await reconnectDelay(this.reconnectAttempts);
13075
- this.reconnectAttempts += 1;
13076
- this.spawnChild();
13077
- await super.initialize();
13078
- this.dropped = false;
13079
- this.reconnectAttempts = 0;
13114
+ throw new NetworkError(`MCP ${this.name} reconnect exhausted`, {
13115
+ code: "mcp_disconnected",
13116
+ ...lastErr instanceof Error ? { cause: lastErr } : {}
13117
+ });
13080
13118
  }
13081
13119
  async close() {
13082
13120
  this.rejectAllPending(new NetworkError(`MCP ${this.name} closed`, { code: "mcp_closed" }));