@opencow-ai/opencow-agent-sdk 0.4.12 → 0.4.14

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/client.js CHANGED
@@ -34951,7 +34951,7 @@ function parseReasoningEffort(value) {
34951
34951
  if (!value)
34952
34952
  return;
34953
34953
  const normalized = value.trim().toLowerCase();
34954
- if (normalized === "low" || normalized === "medium" || normalized === "high" || normalized === "xhigh") {
34954
+ if (normalized === "none" || normalized === "minimal" || normalized === "low" || normalized === "medium" || normalized === "high" || normalized === "xhigh") {
34955
34955
  return normalized;
34956
34956
  }
34957
34957
  return;
@@ -35041,7 +35041,8 @@ function normalizeGithubModelsApiModel(requestedModel) {
35041
35041
  return segment;
35042
35042
  }
35043
35043
  function resolveProviderTransport(options) {
35044
- const rawBaseUrl = asEnvUrl(options?.baseUrl) ?? asEnvUrl(getQueryEnvVar("OPENAI_BASE_URL")) ?? asEnvUrl(getQueryEnvVar("OPENAI_API_BASE"));
35044
+ const optionBaseUrl = asEnvUrl(options?.baseUrl);
35045
+ const rawBaseUrl = optionBaseUrl ?? asEnvUrl(getQueryEnvVar("OPENAI_BASE_URL")) ?? asEnvUrl(getQueryEnvVar("OPENAI_API_BASE"));
35045
35046
  const envOverride = options?.transportOverride ?? getQueryEnvVar(QUERY_ENV_KEY_TRANSPORT_OVERRIDE);
35046
35047
  if (envOverride && envOverride !== "auto") {
35047
35048
  let normalized;
@@ -35051,7 +35052,8 @@ function resolveProviderTransport(options) {
35051
35052
  } else {
35052
35053
  normalized = envOverride;
35053
35054
  }
35054
- const baseUrl2 = (rawBaseUrl ?? (normalized === "openai_responses" ? DEFAULT_CODEX_BASE_URL : DEFAULT_OPENAI_BASE_URL)).replace(/\/+$/, "");
35055
+ const baseUrlSource = rawBaseUrl ?? (normalized === "openai_responses" ? DEFAULT_CODEX_BASE_URL : DEFAULT_OPENAI_BASE_URL);
35056
+ const baseUrl2 = baseUrlSource.replace(/\/+$/, "");
35055
35057
  return { transport: normalized, baseUrl: baseUrl2 };
35056
35058
  }
35057
35059
  const modelForDetection = options?.model?.trim() ?? "";
@@ -35072,7 +35074,10 @@ function resolveProviderRequest(options) {
35072
35074
  transportOverride: options?.transportOverride
35073
35075
  });
35074
35076
  const resolvedModel = transport === "chat_completions" && isEnvTruthy(getQueryEnvVar("CLAUDE_CODE_USE_GITHUB")) ? normalizeGithubModelsApiModel(requestedModel) : descriptor.baseModel;
35075
- const reasoning = options?.reasoningEffortOverride ? { effort: options.reasoningEffortOverride } : descriptor.reasoning;
35077
+ const hasReasoningEffortOverride = !!options && Object.prototype.hasOwnProperty.call(options, "reasoningEffortOverride");
35078
+ const rawEnvReasoningEffortOverride = getQueryEnvVar(QUERY_ENV_KEY_REASONING_EFFORT_OVERRIDE);
35079
+ const envReasoningEffortOverride = parseReasoningEffort(rawEnvReasoningEffortOverride);
35080
+ const reasoning = hasReasoningEffortOverride ? options?.reasoningEffortOverride ? { effort: options.reasoningEffortOverride } : undefined : rawEnvReasoningEffortOverride === QUERY_ENV_VALUE_REASONING_EFFORT_CLEAR ? undefined : envReasoningEffortOverride ? { effort: envReasoningEffortOverride } : descriptor.reasoning;
35076
35081
  return {
35077
35082
  transport,
35078
35083
  requestedModel,
@@ -35176,7 +35181,7 @@ function resolveCodexApiCredentials(env2 = process.env) {
35176
35181
  originator: "opencow"
35177
35182
  };
35178
35183
  }
35179
- var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1", DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex", DEFAULT_GITHUB_MODELS_API_MODEL = "openai/gpt-4.1", CODEX_ALIAS_MODELS, QUERY_ENV_KEY_TRANSPORT_OVERRIDE = "__OPENCOW_TRANSPORT_OVERRIDE", QUERY_ENV_KEY_PROVIDER_SPECIFIC_OPENAI_RESPONSES = "__OPENCOW_PROVIDER_SPECIFIC_OPENAI_RESPONSES", LOCALHOST_HOSTNAMES, warnedCodexAliasOnce = false, MissingProviderModelError;
35184
+ var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1", DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex", DEFAULT_GITHUB_MODELS_API_MODEL = "openai/gpt-4.1", CODEX_ALIAS_MODELS, QUERY_ENV_KEY_TRANSPORT_OVERRIDE = "__OPENCOW_TRANSPORT_OVERRIDE", QUERY_ENV_KEY_REASONING_EFFORT_OVERRIDE = "__OPENCOW_REASONING_EFFORT_OVERRIDE", QUERY_ENV_VALUE_REASONING_EFFORT_CLEAR = "__OPENCOW_CLEAR_REASONING_EFFORT__", QUERY_ENV_KEY_PROVIDER_SPECIFIC_OPENAI_RESPONSES = "__OPENCOW_PROVIDER_SPECIFIC_OPENAI_RESPONSES", QUERY_ENV_KEY_EXTRA_BODY = "__OPENCOW_EXTRA_BODY", LOCALHOST_HOSTNAMES, warnedCodexAliasOnce = false, MissingProviderModelError;
35180
35185
  var init_config2 = __esm(() => {
35181
35186
  init_envUtils();
35182
35187
  init_state2();
@@ -94701,6 +94706,48 @@ var init_proxy = __esm(() => {
94701
94706
  });
94702
94707
  });
94703
94708
 
94709
+ // src/providers/shared/httpObservability.ts
94710
+ function classifyModelHttpEndpoint(url3) {
94711
+ try {
94712
+ const pathname = new URL(url3).pathname.replace(/\/+$/, "");
94713
+ if (pathname.endsWith("/messages/count_tokens"))
94714
+ return "count_tokens";
94715
+ if (pathname.endsWith("/chat/completions"))
94716
+ return "messages";
94717
+ if (pathname.endsWith("/messages"))
94718
+ return "messages";
94719
+ if (pathname.endsWith("/responses"))
94720
+ return "responses";
94721
+ return pathname || "unknown";
94722
+ } catch {
94723
+ return "unknown";
94724
+ }
94725
+ }
94726
+ function errorToFailureReason(error41) {
94727
+ if (error41 instanceof Error)
94728
+ return error41.message;
94729
+ return String(error41);
94730
+ }
94731
+ function responseBodyToFailureReason(status, body) {
94732
+ let detail = body.trim();
94733
+ try {
94734
+ const parsed = JSON.parse(body);
94735
+ const message = typeof parsed.error?.message === "string" ? parsed.error.message : typeof parsed.message === "string" ? parsed.message : undefined;
94736
+ const code = typeof parsed.error?.code === "string" ? parsed.error.code : typeof parsed.error?.type === "string" ? parsed.error.type : undefined;
94737
+ detail = [code, message].filter(Boolean).join(": ") || detail;
94738
+ } catch {}
94739
+ const compact = detail.replace(/\s+/g, " ").slice(0, 240);
94740
+ return compact ? `HTTP ${status}: ${compact}` : `HTTP ${status}`;
94741
+ }
94742
+ function emitSdkHttp(event) {
94743
+ try {
94744
+ emitHttp(event);
94745
+ } catch {}
94746
+ }
94747
+ var init_httpObservability = __esm(() => {
94748
+ init_observer();
94749
+ });
94750
+
94704
94751
  // src/providers/shared/geminiAuth.ts
94705
94752
  import { homedir as homedir11 } from "node:os";
94706
94753
  import { join as join23 } from "node:path";
@@ -95331,6 +95378,44 @@ var init_capabilities2 = __esm(() => {
95331
95378
  ]);
95332
95379
  });
95333
95380
 
95381
+ // src/providers/shared/requestSideChannels.ts
95382
+ function isRecord(value) {
95383
+ return typeof value === "object" && value !== null && !Array.isArray(value);
95384
+ }
95385
+ function parseJsonObject(raw) {
95386
+ if (!raw)
95387
+ return;
95388
+ try {
95389
+ const parsed = JSON.parse(raw);
95390
+ return isRecord(parsed) ? parsed : undefined;
95391
+ } catch {
95392
+ return;
95393
+ }
95394
+ }
95395
+ function readExplicitExtraBodyParams() {
95396
+ return parseJsonObject(getQueryEnvVar(QUERY_ENV_KEY_EXTRA_BODY)) ?? parseJsonObject(resolveEnvVar("EXTRA_BODY"));
95397
+ }
95398
+ function mergeOpenAICompatibleExtraBodyParams(body, params) {
95399
+ const extra = {};
95400
+ const shouldMerge = (key, value) => value !== undefined && !(key in body);
95401
+ const explicitExtraBody = readExplicitExtraBodyParams();
95402
+ if (explicitExtraBody) {
95403
+ Object.assign(extra, explicitExtraBody);
95404
+ }
95405
+ const nestedExtraBody = params.extra_body;
95406
+ if (isRecord(nestedExtraBody)) {
95407
+ Object.assign(extra, nestedExtraBody);
95408
+ }
95409
+ for (const [key, value] of Object.entries(extra)) {
95410
+ if (shouldMerge(key, value))
95411
+ body[key] = value;
95412
+ }
95413
+ }
95414
+ var init_requestSideChannels = __esm(() => {
95415
+ init_state2();
95416
+ init_config2();
95417
+ });
95418
+
95334
95419
  // src/providers/codex/shim.ts
95335
95420
  function parseSseChunk(chunk) {
95336
95421
  const lines = chunk.split(`
@@ -95679,6 +95764,7 @@ async function performCodexRequest(options) {
95679
95764
  body.top_p = options.params.top_p;
95680
95765
  }
95681
95766
  }
95767
+ mergeOpenAICompatibleExtraBodyParams(body, options.params);
95682
95768
  const headers = {
95683
95769
  "Content-Type": "application/json",
95684
95770
  ...options.defaultHeaders,
@@ -96050,6 +96136,7 @@ var init_shim = __esm(() => {
96050
96136
  init_sdk();
96051
96137
  init_schema();
96052
96138
  init_capabilities2();
96139
+ init_requestSideChannels();
96053
96140
  init_canonical();
96054
96141
  });
96055
96142
 
@@ -96247,7 +96334,7 @@ function convertContentBlocks(content) {
96247
96334
  return parts[0].text ?? "";
96248
96335
  return parts;
96249
96336
  }
96250
- function convertMessages(messages, system) {
96337
+ function convertMessages(messages, system, options = {}) {
96251
96338
  const result = [];
96252
96339
  const sysText = convertSystemPrompt2(system);
96253
96340
  if (sysText) {
@@ -96310,7 +96397,7 @@ function convertMessages(messages, system) {
96310
96397
  return text || null;
96311
96398
  })()
96312
96399
  };
96313
- if (thinkingBlocks.length > 0) {
96400
+ if (options.replayReasoningContent !== false && thinkingBlocks.length > 0) {
96314
96401
  const reasoningText = thinkingBlocks.map((b) => b.thinking ?? "").filter(Boolean).join(`
96315
96402
  `);
96316
96403
  if (reasoningText) {
@@ -96385,7 +96472,7 @@ function convertChunkUsage(usage) {
96385
96472
  return openaiUsageToAnthropicUsage(usage);
96386
96473
  }
96387
96474
  function toOpenAIChatReasoningEffort(effort) {
96388
- return effort === "xhigh" ? "high" : effort;
96475
+ return effort;
96389
96476
  }
96390
96477
  function getOpenAIChatProviderCapabilities(model) {
96391
96478
  return {
@@ -96443,7 +96530,8 @@ function serializeParallelToolCalls(messages, capabilities) {
96443
96530
  }
96444
96531
  function buildOpenAIRequestBody(params, ctx) {
96445
96532
  const capabilities = getOpenAIChatProviderCapabilities(ctx.resolvedModel);
96446
- const openaiMessages = serializeParallelToolCalls(convertMessages(params.messages, params.system), capabilities);
96533
+ const replayReasoningContent = !isGeminiTarget(ctx.resolvedModel);
96534
+ const openaiMessages = serializeParallelToolCalls(convertMessages(params.messages, params.system, { replayReasoningContent }), capabilities);
96447
96535
  const body = {
96448
96536
  model: ctx.resolvedModel,
96449
96537
  messages: openaiMessages,
@@ -96494,6 +96582,7 @@ function buildOpenAIRequestBody(params, ctx) {
96494
96582
  }
96495
96583
  }
96496
96584
  }
96585
+ mergeOpenAICompatibleExtraBodyParams(body, params);
96497
96586
  return body;
96498
96587
  }
96499
96588
  async function* openaiStreamToAnthropic(response, model) {
@@ -96820,17 +96909,26 @@ class OpenAIShimMessages {
96820
96909
  defaultHeaders;
96821
96910
  reasoningEffort;
96822
96911
  providerOverride;
96823
- constructor(defaultHeaders, reasoningEffort, providerOverride) {
96912
+ source;
96913
+ constructor(defaultHeaders, reasoningEffort, providerOverride, source) {
96824
96914
  this.defaultHeaders = defaultHeaders;
96825
96915
  this.reasoningEffort = reasoningEffort;
96826
96916
  this.providerOverride = providerOverride;
96917
+ this.source = source;
96827
96918
  }
96828
96919
  create(params, options) {
96829
96920
  const self2 = this;
96830
96921
  let httpResponse;
96831
96922
  const promise3 = (async () => {
96832
96923
  const overrideTransport = self2.providerOverride?.transport === "anthropic" ? undefined : self2.providerOverride?.transport;
96833
- const request = resolveProviderRequest({ model: self2.providerOverride?.model ?? params.model, baseUrl: self2.providerOverride?.baseURL, reasoningEffortOverride: self2.reasoningEffort, transportOverride: overrideTransport });
96924
+ const hasProviderReasoningEffortOverride = !!self2.providerOverride && Object.prototype.hasOwnProperty.call(self2.providerOverride, "reasoningEffort");
96925
+ const reasoningEffortOverride = hasProviderReasoningEffortOverride ? self2.providerOverride?.reasoningEffort ?? null : self2.reasoningEffort;
96926
+ const request = resolveProviderRequest({
96927
+ model: self2.providerOverride?.model ?? params.model,
96928
+ baseUrl: self2.providerOverride?.baseURL,
96929
+ ...reasoningEffortOverride !== undefined ? { reasoningEffortOverride } : {},
96930
+ transportOverride: overrideTransport
96931
+ });
96834
96932
  const response = await self2._doRequest(request, params, options);
96835
96933
  httpResponse = response;
96836
96934
  if (params.stream) {
@@ -96951,28 +97049,93 @@ class OpenAIShimMessages {
96951
97049
  signal: options?.signal
96952
97050
  };
96953
97051
  const maxAttempts = isGithub ? GITHUB_429_MAX_RETRIES : 1;
97052
+ const endpoint = classifyModelHttpEndpoint(chatCompletionsUrl);
96954
97053
  let response;
96955
97054
  for (let attempt = 0;attempt < maxAttempts; attempt++) {
97055
+ const attemptNumber = attempt + 1;
97056
+ const requestId = `req_${crypto.randomUUID().replace(/-/g, "")}`;
97057
+ const requestStartedAt = Date.now();
97058
+ emitSdkHttp({
97059
+ type: "request_start",
97060
+ requestId,
97061
+ method: fetchInit.method,
97062
+ url: chatCompletionsUrl,
97063
+ source: this.source,
97064
+ endpoint,
97065
+ attempt: attemptNumber,
97066
+ maxAttempts,
97067
+ timestamp: requestStartedAt
97068
+ });
96956
97069
  try {
96957
97070
  response = await fetch(chatCompletionsUrl, fetchInit);
96958
97071
  } catch (fetchErr) {
96959
97072
  const msg = fetchErr instanceof Error ? `${fetchErr.message}${fetchErr.cause ? ` (${fetchErr.cause?.code ?? fetchErr.cause?.message ?? ""})` : ""}` : String(fetchErr);
97073
+ emitSdkHttp({
97074
+ type: "error",
97075
+ requestId,
97076
+ error: fetchErr instanceof Error ? fetchErr : new Error(String(fetchErr)),
97077
+ durationMs: Date.now() - requestStartedAt,
97078
+ source: this.source,
97079
+ endpoint,
97080
+ attempt: attemptNumber,
97081
+ maxAttempts,
97082
+ failureReason: msg,
97083
+ timestamp: Date.now()
97084
+ });
96960
97085
  throw new APIConnectionError({
96961
97086
  message: `OpenAI-compat connection failed: ${msg}`,
96962
97087
  cause: fetchErr
96963
97088
  });
96964
97089
  }
96965
97090
  if (response.ok) {
97091
+ emitSdkHttp({
97092
+ type: "response_start",
97093
+ requestId,
97094
+ status: response.status,
97095
+ durationMs: Date.now() - requestStartedAt,
97096
+ source: this.source,
97097
+ endpoint,
97098
+ attempt: attemptNumber,
97099
+ maxAttempts,
97100
+ timestamp: Date.now()
97101
+ });
96966
97102
  return response;
96967
97103
  }
96968
97104
  if (isGithub && response.status === 429 && attempt < maxAttempts - 1) {
96969
97105
  await response.text().catch(() => {});
96970
97106
  const delaySec = Math.min(GITHUB_429_BASE_DELAY_SEC * 2 ** attempt, GITHUB_429_MAX_DELAY_SEC);
97107
+ emitSdkHttp({
97108
+ type: "response_start",
97109
+ requestId,
97110
+ status: response.status,
97111
+ durationMs: Date.now() - requestStartedAt,
97112
+ source: this.source,
97113
+ endpoint,
97114
+ attempt: attemptNumber,
97115
+ maxAttempts,
97116
+ willRetry: true,
97117
+ retryDelayMs: delaySec * 1000,
97118
+ failureReason: `HTTP ${response.status}${formatRetryAfterHint(response)}`,
97119
+ timestamp: Date.now()
97120
+ });
96971
97121
  await sleepMs(delaySec * 1000);
96972
97122
  continue;
96973
97123
  }
96974
97124
  const errorBody = await response.text().catch(() => "unknown error");
96975
97125
  const rateHint = isGithub && response.status === 429 ? formatRetryAfterHint(response) : "";
97126
+ const failureReason = `${responseBodyToFailureReason(response.status, errorBody)}${rateHint}`;
97127
+ emitSdkHttp({
97128
+ type: "response_start",
97129
+ requestId,
97130
+ status: response.status,
97131
+ durationMs: Date.now() - requestStartedAt,
97132
+ source: this.source,
97133
+ endpoint,
97134
+ attempt: attemptNumber,
97135
+ maxAttempts,
97136
+ failureReason,
97137
+ timestamp: Date.now()
97138
+ });
96976
97139
  let errorResponse;
96977
97140
  try {
96978
97141
  errorResponse = JSON.parse(errorBody);
@@ -97061,8 +97224,8 @@ function convertOpenAIResponseToAnthropic(data, model) {
97061
97224
  class OpenAIShimBeta {
97062
97225
  messages;
97063
97226
  reasoningEffort;
97064
- constructor(defaultHeaders, reasoningEffort, providerOverride) {
97065
- this.messages = new OpenAIShimMessages(defaultHeaders, reasoningEffort, providerOverride);
97227
+ constructor(defaultHeaders, reasoningEffort, providerOverride, source) {
97228
+ this.messages = new OpenAIShimMessages(defaultHeaders, reasoningEffort, providerOverride, source);
97066
97229
  this.reasoningEffort = reasoningEffort;
97067
97230
  }
97068
97231
  }
@@ -97084,7 +97247,7 @@ function createOpenAIShimClient(options) {
97084
97247
  }
97085
97248
  const beta = new OpenAIShimBeta({
97086
97249
  ...options.defaultHeaders ?? {}
97087
- }, options.reasoningEffort, options.providerOverride);
97250
+ }, options.reasoningEffort, options.providerOverride, options.source);
97088
97251
  return {
97089
97252
  beta,
97090
97253
  messages: beta.messages
@@ -97103,7 +97266,9 @@ var init_shim2 = __esm(() => {
97103
97266
  init_schemaSanitizer();
97104
97267
  init_providerProfile();
97105
97268
  init_capabilities2();
97269
+ init_httpObservability();
97106
97270
  init_canonical();
97271
+ init_requestSideChannels();
97107
97272
  OpenAIShimStream = class OpenAIShimStream {
97108
97273
  generator;
97109
97274
  controller = new AbortController;
@@ -97200,7 +97365,8 @@ async function getNormalizedClient({
97200
97365
  defaultHeaders: safeHeaders,
97201
97366
  maxRetries,
97202
97367
  timeout: parseInt(process.env.API_TIMEOUT_MS || String(600000), 10),
97203
- providerOverride
97368
+ providerOverride,
97369
+ source
97204
97370
  });
97205
97371
  }
97206
97372
  const transportOverride = getQueryEnvVar(QUERY_ENV_KEY_TRANSPORT_OVERRIDE);
@@ -97210,7 +97376,8 @@ async function getNormalizedClient({
97210
97376
  return createOpenAIShimClient2({
97211
97377
  defaultHeaders,
97212
97378
  maxRetries,
97213
- timeout: parseInt(process.env.API_TIMEOUT_MS || String(600000), 10)
97379
+ timeout: parseInt(process.env.API_TIMEOUT_MS || String(600000), 10),
97380
+ source
97214
97381
  });
97215
97382
  }
97216
97383
  const stagingOauthBaseUrl = process.env.USER_TYPE === "ant" && isEnvTruthy(process.env.USE_STAGING_OAUTH) ? getOauthConfig().BASE_API_URL : undefined;
@@ -97262,42 +97429,49 @@ function buildFetch(fetchOverride, source) {
97262
97429
  const url3 = input instanceof Request ? input.url : String(input);
97263
97430
  const method = init?.method ?? (input instanceof Request ? input.method : "GET");
97264
97431
  const requestId = headers.get(CLIENT_REQUEST_ID_HEADER) ?? randomUUID();
97432
+ const endpoint = classifyModelHttpEndpoint(url3);
97265
97433
  try {
97266
97434
  logForDebugging(`[API REQUEST] ${new URL(url3).pathname} ${CLIENT_REQUEST_ID_HEADER}=${requestId} source=${source ?? "unknown"}`);
97267
97435
  } catch {}
97268
97436
  const requestStartedAt = Date.now();
97437
+ emitSdkHttp({
97438
+ type: "request_start",
97439
+ requestId,
97440
+ method,
97441
+ url: url3,
97442
+ source,
97443
+ endpoint,
97444
+ attempt: 1,
97445
+ maxAttempts: 1,
97446
+ timestamp: requestStartedAt
97447
+ });
97269
97448
  try {
97270
- emitHttp({
97271
- type: "request_start",
97449
+ const response = await inner(input, { ...init, headers });
97450
+ emitSdkHttp({
97451
+ type: "response_start",
97272
97452
  requestId,
97273
- method,
97274
- url: url3,
97453
+ status: response.status,
97454
+ durationMs: Date.now() - requestStartedAt,
97275
97455
  source,
97276
- timestamp: requestStartedAt
97456
+ endpoint,
97457
+ attempt: 1,
97458
+ maxAttempts: 1,
97459
+ timestamp: Date.now()
97277
97460
  });
97278
- } catch {}
97279
- try {
97280
- const response = await inner(input, { ...init, headers });
97281
- try {
97282
- emitHttp({
97283
- type: "response_start",
97284
- requestId,
97285
- status: response.status,
97286
- durationMs: Date.now() - requestStartedAt,
97287
- timestamp: Date.now()
97288
- });
97289
- } catch {}
97290
97461
  return response;
97291
97462
  } catch (err) {
97292
- try {
97293
- emitHttp({
97294
- type: "error",
97295
- requestId,
97296
- error: err instanceof Error ? err : new Error(String(err)),
97297
- durationMs: Date.now() - requestStartedAt,
97298
- timestamp: Date.now()
97299
- });
97300
- } catch {}
97463
+ emitSdkHttp({
97464
+ type: "error",
97465
+ requestId,
97466
+ error: err instanceof Error ? err : new Error(String(err)),
97467
+ durationMs: Date.now() - requestStartedAt,
97468
+ source,
97469
+ endpoint,
97470
+ attempt: 1,
97471
+ maxAttempts: 1,
97472
+ failureReason: errorToFailureReason(err),
97473
+ timestamp: Date.now()
97474
+ });
97301
97475
  throw err;
97302
97476
  }
97303
97477
  };
@@ -97316,7 +97490,7 @@ var init_clientFactory = __esm(() => {
97316
97490
  init_oauth();
97317
97491
  init_debug();
97318
97492
  init_envUtils();
97319
- init_observer();
97493
+ init_httpObservability();
97320
97494
  });
97321
97495
 
97322
97496
  // src/providers/anthropic/index.ts
@@ -130220,15 +130394,16 @@ function isMaxTokensCapEnabled() {
130220
130394
  }
130221
130395
  function getMaxOutputTokensForModel(model, opts) {
130222
130396
  const maxOutputTokens = getModelMaxOutputTokens(model);
130223
- const defaultTokens = isMaxTokensCapEnabled() ? Math.min(maxOutputTokens.default, CAPPED_DEFAULT_MAX_TOKENS) : maxOutputTokens.default;
130397
+ const upperLimit = opts?.upperLimitOverride !== undefined && Number.isFinite(opts.upperLimitOverride) && opts.upperLimitOverride >= 1 ? Math.floor(opts.upperLimitOverride) : maxOutputTokens.upperLimit;
130398
+ const defaultTokens = isMaxTokensCapEnabled() ? Math.min(maxOutputTokens.default, CAPPED_DEFAULT_MAX_TOKENS, upperLimit) : Math.min(maxOutputTokens.default, upperLimit);
130224
130399
  if (opts?.override !== undefined) {
130225
- if (!Number.isFinite(opts.override) || opts.override < 1 || opts.override > maxOutputTokens.upperLimit) {
130226
- console.warn(`[opencow] Options.maxOutputTokens=${opts.override} out of range ` + `[1, ${maxOutputTokens.upperLimit}] for model ${model}; clamping.`);
130400
+ if (!Number.isFinite(opts.override) || opts.override < 1 || opts.override > upperLimit) {
130401
+ console.warn(`[opencow] Options.maxOutputTokens=${opts.override} out of range ` + `[1, ${upperLimit}] for model ${model}; clamping.`);
130227
130402
  }
130228
- const clamped = Math.min(Math.max(1, Math.floor(opts.override)), maxOutputTokens.upperLimit);
130403
+ const clamped = Math.min(Math.max(1, Math.floor(opts.override)), upperLimit);
130229
130404
  return clamped;
130230
130405
  }
130231
- const result = validateBoundedIntEnvVar("CLAUDE_CODE_MAX_OUTPUT_TOKENS", resolveEnvVar("MAX_OUTPUT_TOKENS"), defaultTokens, maxOutputTokens.upperLimit);
130406
+ const result = validateBoundedIntEnvVar("CLAUDE_CODE_MAX_OUTPUT_TOKENS", resolveEnvVar("MAX_OUTPUT_TOKENS"), defaultTokens, upperLimit);
130232
130407
  return result.effective;
130233
130408
  }
130234
130409
  var init_maxTokens = __esm(() => {
@@ -133203,6 +133378,17 @@ async function* withRetry(getClient, operation, options2) {
133203
133378
  status: error41.status,
133204
133379
  provider: getAPIProviderForStatsig()
133205
133380
  });
133381
+ emitSdkHttp({
133382
+ type: "retry",
133383
+ source: options2.querySource,
133384
+ endpoint: "messages",
133385
+ attempt: reportedAttempt,
133386
+ ...persistent ? {} : { maxAttempts: maxRetries + 1 },
133387
+ retryDelayMs: delayMs,
133388
+ status: error41 instanceof APIError ? error41.status : undefined,
133389
+ failureReason: errorToFailureReason(error41),
133390
+ timestamp: Date.now()
133391
+ });
133206
133392
  if (persistent) {
133207
133393
  if (delayMs > 60000) {
133208
133394
  logEvent("tengu_api_persistent_retry_wait", {
@@ -133456,6 +133642,7 @@ var init_retry = __esm(() => {
133456
133642
  init_mocking();
133457
133643
  init_errors7();
133458
133644
  init_errorUtils();
133645
+ init_httpObservability();
133459
133646
  FOREGROUND_529_RETRY_SOURCES = new Set([
133460
133647
  "repl_main_thread",
133461
133648
  "repl_main_thread:outputStyle:custom",
@@ -235092,6 +235279,11 @@ var FINGERPRINT_SALT = "59cf53e54c78";
235092
235279
  var init_fingerprint = () => {};
235093
235280
 
235094
235281
  // src/session/sideQuery.ts
235282
+ function headersForBetas(betas) {
235283
+ if (!betas || betas.length === 0)
235284
+ return;
235285
+ return { "anthropic-beta": betas.join(",") };
235286
+ }
235095
235287
  function extractFirstUserMessageText(messages) {
235096
235288
  const firstUserMessage = messages.find((m) => m.role === "user");
235097
235289
  if (!firstUserMessage)
@@ -235154,7 +235346,7 @@ async function sideQuery(opts) {
235154
235346
  }
235155
235347
  const normalizedModel = normalizeModelStringForAPI(model);
235156
235348
  const start = Date.now();
235157
- const response = await client.beta.messages.create({
235349
+ const response = await client.messages.create({
235158
235350
  model: normalizedModel,
235159
235351
  max_tokens,
235160
235352
  system: systemBlocks,
@@ -235165,9 +235357,12 @@ async function sideQuery(opts) {
235165
235357
  ...temperature !== undefined && { temperature },
235166
235358
  ...stop_sequences && { stop_sequences },
235167
235359
  ...thinkingConfig && { thinking: thinkingConfig },
235168
- ...betas.length > 0 && { betas },
235169
- metadata: getAPIMetadata()
235170
- }, { signal });
235360
+ metadata: getAPIMetadata(),
235361
+ ...getExtraBodyParams()
235362
+ }, {
235363
+ signal,
235364
+ ...betas.length > 0 ? { headers: headersForBetas(betas) } : {}
235365
+ });
235171
235366
  const requestId = response._request_id ?? undefined;
235172
235367
  const now = Date.now();
235173
235368
  const lastCompletion = getLastApiCompletionTimestamp();
@@ -250637,49 +250832,36 @@ assistant: Still waiting on the audit — that's one of the things it's checking
250637
250832
 
250638
250833
  <example>
250639
250834
  user: "Can you get a second opinion on whether this migration is safe?"
250640
- assistant: <thinking>I'll ask the code-reviewer agent it won't see my analysis, so it can give an independent read.</thinking>
250835
+ assistant: <thinking>Forking this review keeps the detailed audit out of my context while I keep steering the work.</thinking>
250641
250836
  <commentary>
250642
- A subagent_type is specified, so the agent starts fresh. It needs full context in the prompt. The briefing explains what to assess and why.
250837
+ No subagent_type is specified, so this uses the fork path. If you do specify subagent_type, copy an exact type from the available agent list; never invent one from an example.
250643
250838
  </commentary>
250644
250839
  ${AGENT_TOOL_NAME2}({
250645
250840
  name: "migration-review",
250646
250841
  description: "Independent migration review",
250647
- subagent_type: "code-reviewer",
250648
250842
  prompt: "Review migration 0042_user_schema.sql for safety. Context: we're adding a NOT NULL column to a 50M-row table. Existing rows get a backfill default. I want a second opinion on whether the backfill approach is safe under concurrent writes — I've checked locking behavior but want independent verification. Report: is this safe, and if not, what specifically breaks?"
250649
250843
  })
250650
250844
  </example>
250651
250845
  `;
250652
250846
  const currentExamples = `Example usage:
250653
250847
 
250654
- <example_agent_descriptions>
250655
- "test-runner": use this agent after you are done writing code to run tests
250656
- "greeting-responder": use this agent to respond to user greetings with a friendly joke
250657
- </example_agent_descriptions>
250658
-
250659
250848
  <example>
250660
- user: "Please write a function that checks if a number is prime"
250661
- assistant: I'm going to use the ${FILE_WRITE_TOOL_NAME2} tool to write the following code:
250662
- <code>
250663
- function isPrime(n) {
250664
- if (n <= 1) return false
250665
- for (let i = 2; i * i <= n; i++) {
250666
- if (n % i === 0) return false
250667
- }
250668
- return true
250669
- }
250670
- </code>
250849
+ user: "Hello"
250671
250850
  <commentary>
250672
- Since a significant piece of code was written and the task was completed, now use the test-runner agent to run the tests
250851
+ Do not use the ${AGENT_TOOL_NAME2} tool for a simple greeting or a short reply. Answer directly.
250673
250852
  </commentary>
250674
- assistant: Uses the ${AGENT_TOOL_NAME2} tool to launch the test-runner agent
250853
+ assistant: "Hi! Nice to see you. What shall we work on today?"
250675
250854
  </example>
250676
250855
 
250677
250856
  <example>
250678
- user: "Hello"
250857
+ user: "Can you investigate whether this migration is safe?"
250679
250858
  <commentary>
250680
- Since the user is greeting, use the greeting-responder agent to respond with a friendly joke
250859
+ This is a multi-step review, so the ${AGENT_TOOL_NAME2} tool can help. Omit subagent_type to use the default general-purpose agent, or specify a subagent_type only by copying an exact type from the available agent list.
250681
250860
  </commentary>
250682
- assistant: "I'm going to use the ${AGENT_TOOL_NAME2} tool to launch the greeting-responder agent"
250861
+ ${AGENT_TOOL_NAME2}({
250862
+ description: "Review migration safety",
250863
+ prompt: "Review migration 0042_user_schema.sql for safety. Context: we're adding a NOT NULL column to a 50M-row table. Existing rows get a backfill default. Check whether the backfill approach is safe under concurrent writes. Report: is this safe, and if not, what specifically breaks?"
250864
+ })
250683
250865
  </example>
250684
250866
  `;
250685
250867
  const listViaAttachment = shouldInjectAgentListInMessages();
@@ -250692,7 +250874,7 @@ The ${AGENT_TOOL_NAME2} tool launches specialized agents (subprocesses) that aut
250692
250874
 
250693
250875
  ${agentListSection}
250694
250876
 
250695
- ${forkEnabled ? `When using the ${AGENT_TOOL_NAME2} tool, specify a subagent_type to use a specialized agent, or omit it to fork yourself — a fork inherits your full conversation context.` : `When using the ${AGENT_TOOL_NAME2} tool, specify a subagent_type parameter to select which agent type to use. If omitted, the general-purpose agent is used.`}`;
250877
+ ${forkEnabled ? `When using the ${AGENT_TOOL_NAME2} tool, specify a subagent_type to use a specialized agent, or omit it to fork yourself — a fork inherits your full conversation context. Only use subagent_type values that appear in the available agent types; never invent an agent type from an example.` : `When using the ${AGENT_TOOL_NAME2} tool, specify a subagent_type parameter to select which agent type to use. If omitted, the general-purpose agent is used. Only use subagent_type values that appear in the available agent types; never invent an agent type from an example.`}`;
250696
250878
  if (isCoordinator) {
250697
250879
  return shared2;
250698
250880
  }
@@ -250720,7 +250902,7 @@ Usage notes:
250720
250902
  - The agent's outputs should generally be trusted
250721
250903
  - Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.)${forkEnabled ? "" : ", since it is not aware of the user's intent"}
250722
250904
  - If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
250723
- - If the user specifies that they want you to run agents "in parallel", you MUST send a single message with multiple ${AGENT_TOOL_NAME2} tool use content blocks. For example, if you need to launch both a build-validator agent and a test-runner agent in parallel, send a single message with both tool calls.
250905
+ - If the user specifies that they want you to run agents "in parallel", you MUST send a single message with multiple ${AGENT_TOOL_NAME2} tool use content blocks. Each call must either omit subagent_type or use an exact type from the available agent list.
250724
250906
  - You can optionally set \`isolation: "worktree"\` to run the agent in a temporary git worktree, giving it an isolated copy of the repository. The worktree is automatically cleaned up if the agent makes no changes; if changes are made, the worktree path and branch are returned in the result.${process.env.USER_TYPE === "ant" ? `
250725
250907
  - You can set \`isolation: "remote"\` to run the agent in a remote CCR environment. This is always a background task; you'll be notified when it completes. Use for long-running tasks that need a fresh sandbox.` : ""}${isInProcessTeammate() ? `
250726
250908
  - The run_in_background, name, team_name, and mode parameters are not available in this context. Only synchronous subagents are supported.` : isTeammate() ? `
@@ -250735,7 +250917,6 @@ var init_prompt7 = __esm(() => {
250735
250917
  init_teammate();
250736
250918
  init_teammateContext();
250737
250919
  init_prompt2();
250738
- init_prompt3();
250739
250920
  init_constants4();
250740
250921
  init_forkSubagent();
250741
250922
  init_state2();
@@ -255970,6 +256151,13 @@ function getDisableExtglobCommand(shellPath) {
255970
256151
  }
255971
256152
  return null;
255972
256153
  }
256154
+ function getHostProvidedPathCommand() {
256155
+ const path11 = getHostProvidedEnvVar("PATH");
256156
+ if (!path11) {
256157
+ return null;
256158
+ }
256159
+ return `export PATH=${quote([path11])}`;
256160
+ }
255973
256161
  async function createBashShellProvider(shellPath, options2) {
255974
256162
  let currentSandboxTmpDir;
255975
256163
  const snapshotPromise = options2?.skipSnapshot ? Promise.resolve(undefined) : createAndSaveSnapshot(shellPath).catch((error41) => {
@@ -256010,6 +256198,10 @@ async function createBashShellProvider(shellPath, options2) {
256010
256198
  const finalPath = getPlatform() === "windows" ? windowsPathToPosixPath(snapshotFilePath) : snapshotFilePath;
256011
256199
  commandParts.push(`source ${quote([finalPath])} 2>/dev/null || true`);
256012
256200
  }
256201
+ const hostPathCommand = getHostProvidedPathCommand();
256202
+ if (hostPathCommand) {
256203
+ commandParts.push(hostPathCommand);
256204
+ }
256013
256205
  const sessionEnvScript2 = await getSessionEnvironmentScript();
256014
256206
  if (sessionEnvScript2) {
256015
256207
  commandParts.push(sessionEnvScript2);
@@ -269649,7 +269841,7 @@ async function loadPluginSettings(pluginPath, manifest) {
269649
269841
  try {
269650
269842
  const content = await getFsImplementation().readFile(settingsJsonPath, { encoding: "utf-8" });
269651
269843
  const parsed = jsonParse(content);
269652
- if (isRecord(parsed)) {
269844
+ if (isRecord2(parsed)) {
269653
269845
  const filtered = parsePluginSettings(parsed);
269654
269846
  if (filtered) {
269655
269847
  logForDebugging(`Loaded settings from settings.json for plugin ${manifest.name}`);
@@ -270328,7 +270520,7 @@ function cachePluginSettings(plugins) {
270328
270520
  logForDebugging(`Cached plugin settings with keys: ${Object.keys(settings).join(", ")}`);
270329
270521
  }
270330
270522
  }
270331
- function isRecord(value) {
270523
+ function isRecord2(value) {
270332
270524
  return typeof value === "object" && value !== null && !Array.isArray(value);
270333
270525
  }
270334
270526
  var PluginSettingsSchema, loadAllPlugins, loadAllPluginsCacheOnly;
@@ -281957,7 +282149,11 @@ async function* queryLoop(params, consumedCommandUuids) {
281957
282149
  if (false) {}
281958
282150
  const mediaRecoveryEnabled = reactiveCompact?.isReactiveCompactEnabled() ?? false;
281959
282151
  if (!compactionResult && querySource !== "compact" && querySource !== "session_memory" && !(reactiveCompact?.isReactiveCompactEnabled() && isAutoCompactEnabled()) && !collapseOwnsIt) {
281960
- const { isAtBlockingLimit } = calculateTokenWarningState(tokenCountWithEstimation(messagesForQuery) - snipTokensFreed, toolUseContext.options.mainLoopModel);
282152
+ const { isAtBlockingLimit } = calculateTokenWarningState(tokenCountWithEstimation(messagesForQuery) - snipTokensFreed, toolUseContext.options.mainLoopModel, {
282153
+ contextWindow: toolUseContext.options.contextWindow,
282154
+ maxOutputTokens: toolUseContext.options.maxOutputTokens,
282155
+ maxOutputTokensLimit: toolUseContext.options.maxOutputTokensLimit
282156
+ });
281961
282157
  if (isAtBlockingLimit) {
281962
282158
  yield createAssistantAPIErrorMessage({
281963
282159
  content: PROMPT_TOO_LONG_ERROR_MESSAGE,
@@ -282000,6 +282196,7 @@ async function* queryLoop(params, consumedCommandUuids) {
282000
282196
  allowedAgentTypes: toolUseContext.options.agentDefinitions.allowedAgentTypes,
282001
282197
  hasAppendSystemPrompt: !!toolUseContext.options.appendSystemPrompt,
282002
282198
  maxOutputTokensOverride,
282199
+ maxOutputTokensLimitOverride: params.maxOutputTokensLimitOverride,
282003
282200
  fetchOverride: dumpPromptsFetch,
282004
282201
  mcpTools: appState.mcp.tools,
282005
282202
  hasPendingMcpServers: appState.mcp.clients.some((c6) => c6.type === "pending"),
@@ -282675,7 +282872,7 @@ function getAnthropicEnvMetadata() {
282675
282872
  function getBuildAgeMinutes() {
282676
282873
  if (false)
282677
282874
  ;
282678
- const buildTime = new Date("2026-06-24T10:02:32.669Z").getTime();
282875
+ const buildTime = new Date("2026-07-07T07:10:57.155Z").getTime();
282679
282876
  if (isNaN(buildTime))
282680
282877
  return;
282681
282878
  return Math.floor((Date.now() - buildTime) / 60000);
@@ -283257,6 +283454,7 @@ async function runForkedAgent({
283257
283454
  toolUseContext: isolatedToolUseContext,
283258
283455
  querySource,
283259
283456
  maxOutputTokensOverride: maxOutputTokens,
283457
+ maxOutputTokensLimitOverride: isolatedToolUseContext.options.maxOutputTokensLimit,
283260
283458
  maxTurns,
283261
283459
  skipCacheWrite
283262
283460
  })) {
@@ -283495,7 +283693,17 @@ ${formattedSummary}`;
283495
283693
  if (transcriptPath) {
283496
283694
  baseSummary += `
283497
283695
 
283498
- If you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: ${transcriptPath}`;
283696
+ IMPORTANT Transcript recovery protocol:
283697
+ The full pre-compaction conversation is preserved at: ${transcriptPath}
283698
+ When you encounter ANY of these situations, you MUST use the Read tool to search the transcript for the missing context BEFORE responding:
283699
+ - You are unsure about a specific detail (file path, function name, error message, code snippet, user preference)
283700
+ - The user references something you cannot find in the summary above
283701
+ - You need exact code that was previously read or written
283702
+ - You are about to make a decision but feel uncertain whether the user already gave guidance on it
283703
+ - A tool name, skill name, or configuration was discussed but is not in the summary
283704
+
283705
+ The transcript is a JSONL file. Read its tail (last 500–2000 lines) first for the most recent context; if that doesn't resolve the gap, read earlier sections.
283706
+ Do NOT guess or hallucinate details that might have been discussed — read the transcript instead.`;
283499
283707
  }
283500
283708
  if (recentMessagesPreserved) {
283501
283709
  baseSummary += `
@@ -283562,6 +283770,7 @@ Your summary should include the following sections:
283562
283770
  8. Current Work: Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant. Include file names and code snippets where applicable.
283563
283771
  9. Optional Next Step: List the next step that you will take that is related to the most recent work you were doing. IMPORTANT: ensure that this step is DIRECTLY in line with the user's most recent explicit requests, and the task you were working on immediately before this summary request. If your last task was concluded, then only list next steps if they are explicitly in line with the users request. Do not start on tangential requests or really old requests that were already completed without confirming with the user first.
283564
283772
  If there is a next step, include direct quotes from the most recent conversation showing exactly what task you were working on and where you left off. This should be verbatim to ensure there's no drift in task interpretation.
283773
+ 10. Uncertain or Incomplete Context: List any items where you are not fully confident in the details — e.g., a tool/skill name you vaguely recall but cannot confirm, a user preference you think was stated but cannot pinpoint, or a decision whose rationale is unclear. Mark each with [NEEDS_TRANSCRIPT_LOOKUP] so the post-compaction assistant knows to read the transcript file for these specific items before acting on them.
283565
283774
 
283566
283775
  Here's an example of how your output should be structured:
283567
283776
 
@@ -283612,10 +283821,14 @@ Here's an example of how your output should be structured:
283612
283821
  9. Optional Next Step:
283613
283822
  [Optional Next step to take]
283614
283823
 
283824
+ 10. Uncertain or Incomplete Context:
283825
+ - [Item with unclear details] [NEEDS_TRANSCRIPT_LOOKUP]
283826
+ - [...]
283827
+
283615
283828
  </summary>
283616
283829
  </example>
283617
283830
 
283618
- Please provide your summary based on the conversation so far, following this structure and ensuring precision and thoroughness in your response.
283831
+ Please provide your summary based on the conversation so far, following this structure and ensuring precision and thoroughness in your response.
283619
283832
 
283620
283833
  There may be additional summarization instructions provided in the included context. If so, remember to follow these instructions when creating the above summary. Examples of instructions include:
283621
283834
  <example>
@@ -283643,6 +283856,7 @@ Your summary should include the following sections:
283643
283856
  7. Pending Tasks: Outline any pending tasks from the recent messages.
283644
283857
  8. Current Work: Describe precisely what was being worked on immediately before this summary request.
283645
283858
  9. Optional Next Step: List the next step related to the most recent work. Include direct quotes from the most recent conversation.
283859
+ 10. Uncertain or Incomplete Context: List any items where details are unclear or potentially missing from the recent messages. Mark each with [NEEDS_TRANSCRIPT_LOOKUP].
283646
283860
 
283647
283861
  Here's an example of how your output should be structured:
283648
283862
 
@@ -283683,6 +283897,9 @@ Here's an example of how your output should be structured:
283683
283897
  9. Optional Next Step:
283684
283898
  [Optional Next step to take]
283685
283899
 
283900
+ 10. Uncertain or Incomplete Context:
283901
+ - [Item with unclear details] [NEEDS_TRANSCRIPT_LOOKUP]
283902
+
283686
283903
  </summary>
283687
283904
  </example>
283688
283905
 
@@ -283703,6 +283920,7 @@ Your summary should include the following sections:
283703
283920
  7. Pending Tasks: Outline any pending tasks.
283704
283921
  8. Work Completed: Describe what was accomplished by the end of this portion.
283705
283922
  9. Context for Continuing Work: Summarize any context, decisions, or state that would be needed to understand and continue the work in subsequent messages.
283923
+ 10. Uncertain or Incomplete Context: List any items where details are unclear or potentially incomplete. Mark each with [NEEDS_TRANSCRIPT_LOOKUP] so the continuing session knows to look them up in the transcript before acting.
283706
283924
 
283707
283925
  Here's an example of how your output should be structured:
283708
283926
 
@@ -283743,6 +283961,9 @@ Here's an example of how your output should be structured:
283743
283961
  9. Context for Continuing Work:
283744
283962
  [Key context, decisions, or state needed to continue the work]
283745
283963
 
283964
+ 10. Uncertain or Incomplete Context:
283965
+ - [Item with unclear details] [NEEDS_TRANSCRIPT_LOOKUP]
283966
+
283746
283967
  </summary>
283747
283968
  </example>
283748
283969
 
@@ -284194,7 +284415,10 @@ async function streamCompactSummary({
284194
284415
  toolChoice: undefined,
284195
284416
  isNonInteractiveSession: context4.options.isNonInteractiveSession,
284196
284417
  hasAppendSystemPrompt: !!context4.options.appendSystemPrompt,
284197
- maxOutputTokensOverride: Math.min(COMPACT_MAX_OUTPUT_TOKENS, getMaxOutputTokensForModel(context4.options.mainLoopModel)),
284418
+ maxOutputTokensOverride: Math.min(COMPACT_MAX_OUTPUT_TOKENS, getMaxOutputTokensForModel(context4.options.mainLoopModel, {
284419
+ upperLimitOverride: context4.options.maxOutputTokensLimit
284420
+ })),
284421
+ maxOutputTokensLimitOverride: context4.options.maxOutputTokensLimit,
284198
284422
  querySource: "compact",
284199
284423
  agents: context4.options.agentDefinitions.activeAgents,
284200
284424
  mcpTools: [],
@@ -284928,7 +285152,10 @@ var init_sessionMemoryCompact = __esm(() => {
284928
285152
 
284929
285153
  // src/controller/compact/autoCompact.ts
284930
285154
  function getEffectiveContextWindowSize(model, opts) {
284931
- const reservedTokensForSummary = Math.min(getMaxOutputTokensForModel(model, { override: opts?.maxOutputTokens }), MAX_OUTPUT_TOKENS_FOR_SUMMARY);
285155
+ const reservedTokensForSummary = Math.min(getMaxOutputTokensForModel(model, {
285156
+ override: opts?.maxOutputTokens,
285157
+ upperLimitOverride: opts?.maxOutputTokensLimit
285158
+ }), MAX_OUTPUT_TOKENS_FOR_SUMMARY);
284932
285159
  let contextWindow = getContextWindowForModel(model, getSdkBetas(), {
284933
285160
  override: opts?.contextWindow
284934
285161
  });
@@ -285014,7 +285241,8 @@ async function autoCompactIfNeeded(messages, toolUseContext, cacheSafeParams, qu
285014
285241
  const model = toolUseContext.options.mainLoopModel;
285015
285242
  const opts = {
285016
285243
  contextWindow: toolUseContext.options.contextWindow,
285017
- maxOutputTokens: toolUseContext.options.maxOutputTokens
285244
+ maxOutputTokens: toolUseContext.options.maxOutputTokens,
285245
+ maxOutputTokensLimit: toolUseContext.options.maxOutputTokensLimit
285018
285246
  };
285019
285247
  const shouldCompact = await shouldAutoCompact(messages, model, querySource, snipTokensFreed, opts);
285020
285248
  if (!shouldCompact) {
@@ -285495,6 +285723,11 @@ var init_toolSearch = __esm(() => {
285495
285723
  });
285496
285724
 
285497
285725
  // src/providers/shared/tokenCount.ts
285726
+ function headersForBetas2(betas) {
285727
+ if (!betas || betas.length === 0)
285728
+ return;
285729
+ return { "anthropic-beta": betas.join(",") };
285730
+ }
285498
285731
  function hasThinkingBlocks(messages) {
285499
285732
  for (const message of messages) {
285500
285733
  if (message.role === "assistant" && Array.isArray(message.content)) {
@@ -285569,17 +285802,18 @@ async function countMessagesTokensWithAPI(messages, tools) {
285569
285802
  model,
285570
285803
  source: "count_tokens"
285571
285804
  });
285572
- const response = await anthropic.beta.messages.countTokens({
285805
+ const response = await anthropic.messages.countTokens({
285573
285806
  model: normalizeModelStringForAPI(model),
285574
285807
  messages: messages.length > 0 ? messages : [{ role: "user", content: "foo" }],
285575
285808
  tools,
285576
- ...betas.length > 0 && { betas },
285577
285809
  ...containsThinking && {
285578
285810
  thinking: {
285579
285811
  type: "enabled",
285580
285812
  budget_tokens: TOKEN_COUNT_THINKING_BUDGET
285581
285813
  }
285582
285814
  }
285815
+ }, {
285816
+ ...betas.length > 0 ? { headers: headersForBetas2(betas) } : {}
285583
285817
  });
285584
285818
  if (typeof response.input_tokens !== "number") {
285585
285819
  return null;
@@ -285618,12 +285852,11 @@ async function countTokensViaHaikuFallback(messages, tools) {
285618
285852
  const normalizedMessages = stripToolSearchFieldsFromMessages(messages);
285619
285853
  const messagesToSend = normalizedMessages.length > 0 ? normalizedMessages : [{ role: "user", content: "count" }];
285620
285854
  const betas = getModelBetas(model);
285621
- const response = await anthropic.beta.messages.create({
285855
+ const response = await anthropic.messages.create({
285622
285856
  model: normalizeModelStringForAPI(model),
285623
285857
  max_tokens: containsThinking ? TOKEN_COUNT_MAX_TOKENS : 1,
285624
285858
  messages: messagesToSend,
285625
285859
  tools: tools.length > 0 ? tools : undefined,
285626
- ...betas.length > 0 && { betas },
285627
285860
  metadata: getAPIMetadata(),
285628
285861
  ...getExtraBodyParams(),
285629
285862
  ...containsThinking && {
@@ -285632,6 +285865,8 @@ async function countTokensViaHaikuFallback(messages, tools) {
285632
285865
  budget_tokens: TOKEN_COUNT_THINKING_BUDGET
285633
285866
  }
285634
285867
  }
285868
+ }, {
285869
+ ...betas.length > 0 ? { headers: headersForBetas2(betas) } : {}
285635
285870
  });
285636
285871
  const usage = response.usage;
285637
285872
  const inputTokens = usage.input_tokens;
@@ -293362,6 +293597,11 @@ var init_apiMicrocompact = __esm(() => {
293362
293597
 
293363
293598
  // src/controller/loop.ts
293364
293599
  import { randomUUID as randomUUID17 } from "crypto";
293600
+ function headersForBetas3(betas) {
293601
+ if (!betas || betas.length === 0)
293602
+ return;
293603
+ return { "anthropic-beta": betas.join(",") };
293604
+ }
293365
293605
  function adjustParamsForNonStreaming(params, maxTokensCap) {
293366
293606
  const cappedMaxTokens = Math.min(params.max_tokens, maxTokensCap);
293367
293607
  const adjustedParams = { ...params };
@@ -293439,13 +293679,16 @@ async function* executeNonStreamingRequest(clientOptions, retryOptions, paramsFr
293439
293679
  captureRequest(retryParams);
293440
293680
  onAttempt(attempt, start, retryParams.max_tokens);
293441
293681
  const adjustedParams = adjustParamsForNonStreaming(retryParams, MAX_NON_STREAMING_TOKENS);
293682
+ const { betas: requestBetas, ...standardParams } = adjustedParams;
293683
+ const headers = headersForBetas3(requestBetas);
293442
293684
  try {
293443
- return await anthropic.beta.messages.create({
293444
- ...adjustedParams,
293445
- model: normalizeModelStringForAPI(adjustedParams.model)
293685
+ return await anthropic.messages.create({
293686
+ ...standardParams,
293687
+ model: normalizeModelStringForAPI(standardParams.model)
293446
293688
  }, {
293447
293689
  signal: retryOptions.signal,
293448
- timeout: fallbackTimeoutMs
293690
+ timeout: fallbackTimeoutMs,
293691
+ ...headers ? { headers } : {}
293449
293692
  });
293450
293693
  } catch (err2) {
293451
293694
  if (err2 instanceof APIUserAbortError)
@@ -293768,7 +294011,10 @@ ${deferredToolList}
293768
294011
  betasParams.push(STRUCTURED_OUTPUTS_BETA_HEADER);
293769
294012
  }
293770
294013
  }
293771
- const maxOutputTokens2 = retryContext?.maxTokensOverride || options2.maxOutputTokensOverride || getMaxOutputTokensForModel(options2.model);
294014
+ const maxOutputTokens2 = retryContext?.maxTokensOverride || getMaxOutputTokensForModel(options2.model, {
294015
+ override: options2.maxOutputTokensOverride,
294016
+ upperLimitOverride: options2.maxOutputTokensLimitOverride
294017
+ });
293772
294018
  const hasThinking = thinkingConfig.type !== "disabled" && !isEnvTruthy(resolveEnvVar("DISABLE_THINKING"));
293773
294019
  let thinking = undefined;
293774
294020
  if (hasThinking && modelSupportsThinking(options2.model)) {
@@ -293924,11 +294170,19 @@ ${deferredToolList}
293924
294170
  headlessProfilerCheckpoint("api_request_sent");
293925
294171
  }
293926
294172
  clientRequestId = shouldSendClientRequestId() ? randomUUID17() : undefined;
293927
- const result = await anthropic.beta.messages.create({ ...params, stream: true }, {
293928
- signal,
294173
+ const { betas: requestBetas, ...standardParams } = params;
294174
+ const headers = {
294175
+ ...headersForBetas3(requestBetas) ?? {},
293929
294176
  ...clientRequestId && {
293930
- headers: { [CLIENT_REQUEST_ID_HEADER]: clientRequestId }
294177
+ [CLIENT_REQUEST_ID_HEADER]: clientRequestId
293931
294178
  }
294179
+ };
294180
+ const result = await anthropic.messages.create({
294181
+ ...standardParams,
294182
+ stream: true
294183
+ }, {
294184
+ signal,
294185
+ ...Object.keys(headers).length > 0 ? { headers } : {}
293932
294186
  }).withResponse();
293933
294187
  queryCheckpoint("query_response_headers_received");
293934
294188
  streamRequestId = result.request_id;
@@ -296983,6 +297237,11 @@ function stripToolReferenceBlocksFromUserMessage(message) {
296983
297237
  }
296984
297238
  };
296985
297239
  }
297240
+ function omitToolSearchCaller(block2) {
297241
+ const blockWithoutCaller = { ...block2 };
297242
+ delete blockWithoutCaller.caller;
297243
+ return blockWithoutCaller;
297244
+ }
296986
297245
  function stripCallerFieldFromAssistantMessage(message) {
296987
297246
  const hasCallerField = message.message.content.some((block2) => block2.type === "tool_use" && ("caller" in block2) && block2.caller !== null);
296988
297247
  if (!hasCallerField) {
@@ -296996,12 +297255,7 @@ function stripCallerFieldFromAssistantMessage(message) {
296996
297255
  if (block2.type !== "tool_use") {
296997
297256
  return block2;
296998
297257
  }
296999
- return {
297000
- type: "tool_use",
297001
- id: block2.id,
297002
- name: block2.name,
297003
- input: block2.input
297004
- };
297258
+ return omitToolSearchCaller(block2);
297005
297259
  })
297006
297260
  }
297007
297261
  };
@@ -297278,9 +297532,9 @@ function normalizeMessagesForAPI(messages, tools = []) {
297278
297532
  input: normalizedInput
297279
297533
  };
297280
297534
  }
297535
+ const blockWithoutCaller = omitToolSearchCaller(block2);
297281
297536
  return {
297282
- type: "tool_use",
297283
- id: block2.id,
297537
+ ...blockWithoutCaller,
297284
297538
  name: canonicalName,
297285
297539
  input: normalizedInput
297286
297540
  };
@@ -297477,6 +297731,15 @@ function mergeUserContentBlocks(a2, b) {
297477
297731
  }
297478
297732
  return [...a2.slice(0, -1), smooshed, ...toolResults];
297479
297733
  }
297734
+ function normalizeToolUseIdFromAPI(contentBlock) {
297735
+ if (typeof contentBlock.id === "string" && contentBlock.id.trim().length > 0) {
297736
+ return contentBlock.id;
297737
+ }
297738
+ logEvent("tengu_tool_use_missing_id_repaired", {
297739
+ toolName: sanitizeToolNameForAnalytics(contentBlock.name)
297740
+ });
297741
+ return `toolu_${randomUUID18().replace(/-/g, "")}`;
297742
+ }
297480
297743
  function normalizeContentFromAPI(contentBlocks, tools, agentId) {
297481
297744
  if (!contentBlocks) {
297482
297745
  return [];
@@ -297515,6 +297778,7 @@ function normalizeContentFromAPI(contentBlocks, tools, agentId) {
297515
297778
  }
297516
297779
  return {
297517
297780
  ...contentBlock,
297781
+ id: normalizeToolUseIdFromAPI(contentBlock),
297518
297782
  input: normalizedInput
297519
297783
  };
297520
297784
  }
@@ -299730,8 +299994,10 @@ async function processUserInputBase(input, mode, setToolJSX, context4, pastedCon
299730
299994
  }
299731
299995
  }
299732
299996
  }
299997
+ const processSlashCommand = getProcessSlashCommand();
299733
299998
  if (false) {}
299734
- const shouldExtractAttachments = !skipAttachments && inputString !== null && (mode !== "prompt" || effectiveSkipSlash || !inputString.startsWith("/"));
299999
+ const shouldFallbackSlashToPrompt = inputString !== null && mode === "prompt" && !effectiveSkipSlash && inputString.startsWith("/") && !processSlashCommand;
300000
+ const shouldExtractAttachments = !skipAttachments && inputString !== null && (mode !== "prompt" || effectiveSkipSlash || !inputString.startsWith("/") || shouldFallbackSlashToPrompt);
299735
300001
  queryCheckpoint("query_attachment_loading_start");
299736
300002
  const attachmentMessages = shouldExtractAttachments ? await toArray2(getAttachmentMessages(inputString, context4, ideSelection ?? null, [], messages, querySource)) : [];
299737
300003
  queryCheckpoint("query_attachment_loading_end");
@@ -299742,11 +300008,10 @@ async function processUserInputBase(input, mode, setToolJSX, context4, pastedCon
299742
300008
  return addImageMetadataMessage(await processBashCommand(inputString, precedingInputBlocks, attachmentMessages, context4, setToolJSX), imageMetadataTexts);
299743
300009
  }
299744
300010
  if (inputString !== null && !effectiveSkipSlash && inputString.startsWith("/")) {
299745
- const processSlashCommand = getProcessSlashCommand();
299746
- if (!processSlashCommand)
299747
- throw new SlashCommandHandlerNotRegisteredError("slash");
299748
- const slashResult = await processSlashCommand(inputString, precedingInputBlocks, imageContentBlocks, attachmentMessages, context4, setToolJSX, uuid3, isAlreadyProcessing, canUseTool);
299749
- return addImageMetadataMessage(slashResult, imageMetadataTexts);
300011
+ if (processSlashCommand) {
300012
+ const slashResult = await processSlashCommand(inputString, precedingInputBlocks, imageContentBlocks, attachmentMessages, context4, setToolJSX, uuid3, isAlreadyProcessing, canUseTool);
300013
+ return addImageMetadataMessage(slashResult, imageMetadataTexts);
300014
+ }
299750
300015
  }
299751
300016
  if (inputString !== null && mode === "prompt") {
299752
300017
  const trimmedInput = inputString.trim();
@@ -299993,6 +300258,7 @@ class QueryEngine {
299993
300258
  maxTurns,
299994
300259
  maxBudgetUsd,
299995
300260
  maxOutputTokens,
300261
+ maxOutputTokensLimit,
299996
300262
  contextWindow,
299997
300263
  compact,
299998
300264
  taskBudget,
@@ -300082,6 +300348,7 @@ class QueryEngine {
300082
300348
  theme: resolveThemeSetting(getGlobalConfig().theme),
300083
300349
  maxBudgetUsd,
300084
300350
  maxOutputTokens,
300351
+ maxOutputTokensLimit,
300085
300352
  contextWindow,
300086
300353
  modelProviders: this.config.modelProviders,
300087
300354
  subagentDisallowedTools: this.config.subagentDisallowedTools
@@ -300187,6 +300454,7 @@ class QueryEngine {
300187
300454
  agentDefinitions: { activeAgents: agents, allAgents: [] },
300188
300455
  maxBudgetUsd,
300189
300456
  maxOutputTokens,
300457
+ maxOutputTokensLimit,
300190
300458
  contextWindow,
300191
300459
  modelProviders: this.config.modelProviders,
300192
300460
  subagentDisallowedTools: this.config.subagentDisallowedTools
@@ -300307,6 +300575,7 @@ class QueryEngine {
300307
300575
  querySource: "sdk",
300308
300576
  maxTurns,
300309
300577
  maxOutputTokensOverride: maxOutputTokens,
300578
+ maxOutputTokensLimitOverride: maxOutputTokensLimit,
300310
300579
  compactRequest: compact,
300311
300580
  taskBudget
300312
300581
  })) {
@@ -300677,6 +300946,7 @@ async function* ask({
300677
300946
  maxTurns,
300678
300947
  maxBudgetUsd,
300679
300948
  maxOutputTokens,
300949
+ maxOutputTokensLimit,
300680
300950
  contextWindow,
300681
300951
  compact,
300682
300952
  taskBudget,
@@ -300722,6 +300992,7 @@ async function* ask({
300722
300992
  maxTurns,
300723
300993
  maxBudgetUsd,
300724
300994
  maxOutputTokens,
300995
+ maxOutputTokensLimit,
300725
300996
  contextWindow,
300726
300997
  compact,
300727
300998
  taskBudget,
@@ -329493,7 +329764,7 @@ function extractToolUseId2(message) {
329493
329764
  return;
329494
329765
  for (let i3 = content.length - 1;i3 >= 0; i3--) {
329495
329766
  const block2 = content[i3];
329496
- if (block2?.type === "tool_use" && typeof block2.id === "string") {
329767
+ if (block2?.type === "tool_use" && typeof block2.id === "string" && block2.id.trim().length > 0) {
329497
329768
  return block2.id;
329498
329769
  }
329499
329770
  }
@@ -329583,6 +329854,7 @@ function mergeAndFilterTools(initialTools, assembled, mode) {
329583
329854
 
329584
329855
  // src/session/sdkRuntime.ts
329585
329856
  init_config2();
329857
+ init_envVars();
329586
329858
  var getAsk = () => (init_QueryEngine(), __toCommonJS(exports_QueryEngine)).ask;
329587
329859
  var getModelInvocableCommands2 = async (cwd) => {
329588
329860
  const mod = (init_runtime(), __toCommonJS(exports_runtime));
@@ -329741,19 +330013,38 @@ function normalizeInitialMessages(raw) {
329741
330013
  }
329742
330014
  return normalized;
329743
330015
  }
330016
+ function extraBodyFromOptions(options2) {
330017
+ const extraBody = options2.extra_body;
330018
+ if (!extraBody || typeof extraBody !== "object" || Array.isArray(extraBody)) {
330019
+ return;
330020
+ }
330021
+ return extraBody;
330022
+ }
329744
330023
  function optionsWithProviderRoutingEnv(options2) {
329745
330024
  const transport = options2.transport;
330025
+ const reasoningEffort = options2.reasoningEffort;
329746
330026
  const openaiResponses = options2.providerSpecific?.openaiResponses;
329747
- if (transport === undefined && openaiResponses === undefined) {
330027
+ const extraBody = extraBodyFromOptions(options2);
330028
+ if (transport === undefined && reasoningEffort === undefined && openaiResponses === undefined && extraBody === undefined) {
329748
330029
  return options2;
329749
330030
  }
329750
330031
  const mergedEnv = { ...options2.env ?? {} };
329751
330032
  if (typeof transport === "string" && transport.length > 0) {
329752
330033
  mergedEnv[QUERY_ENV_KEY_TRANSPORT_OVERRIDE] = transport;
329753
330034
  }
330035
+ if (reasoningEffort === null) {
330036
+ mergedEnv[QUERY_ENV_KEY_REASONING_EFFORT_OVERRIDE] = QUERY_ENV_VALUE_REASONING_EFFORT_CLEAR;
330037
+ } else if (typeof reasoningEffort === "string" && reasoningEffort.length > 0) {
330038
+ mergedEnv[QUERY_ENV_KEY_REASONING_EFFORT_OVERRIDE] = reasoningEffort;
330039
+ }
329754
330040
  if (openaiResponses && typeof openaiResponses === "object") {
329755
330041
  mergedEnv[QUERY_ENV_KEY_PROVIDER_SPECIFIC_OPENAI_RESPONSES] = JSON.stringify(openaiResponses);
329756
330042
  }
330043
+ if (extraBody) {
330044
+ const rawExtraBody = JSON.stringify(extraBody);
330045
+ mergedEnv[ENV_VARS.EXTRA_BODY.primary] = rawExtraBody;
330046
+ mergedEnv[QUERY_ENV_KEY_EXTRA_BODY] = rawExtraBody;
330047
+ }
329757
330048
  return { ...options2, env: mergedEnv };
329758
330049
  }
329759
330050
  function createQueryLike(generator, runtimeState, onClose) {
@@ -329980,6 +330271,7 @@ function runSdkQueryRuntime(params) {
329980
330271
  maxTurns: options2.maxTurns,
329981
330272
  maxBudgetUsd: options2.maxBudgetUsd,
329982
330273
  maxOutputTokens: options2.maxOutputTokens,
330274
+ maxOutputTokensLimit: options2.maxOutputTokensLimit,
329983
330275
  contextWindow: options2.contextWindow,
329984
330276
  compact: options2.compact,
329985
330277
  taskBudget: options2.taskBudget,
@@ -335637,6 +335929,11 @@ init_generators();
335637
335929
  init_clientFactory();
335638
335930
  init_retry();
335639
335931
  init_requestShaping();
335932
+ function headersForBetas4(betas) {
335933
+ if (!betas || betas.length === 0)
335934
+ return;
335935
+ return { "anthropic-beta": betas.join(",") };
335936
+ }
335640
335937
  async function verifyApiKey(apiKey, isNonInteractiveSession) {
335641
335938
  if (isNonInteractiveSession) {
335642
335939
  return true;
@@ -335651,14 +335948,15 @@ async function verifyApiKey(apiKey, isNonInteractiveSession) {
335651
335948
  source: "verify_api_key"
335652
335949
  }), async (anthropic) => {
335653
335950
  const messages = [{ role: "user", content: "test" }];
335654
- await anthropic.beta.messages.create({
335951
+ await anthropic.messages.create({
335655
335952
  model,
335656
335953
  max_tokens: 1,
335657
335954
  messages,
335658
335955
  temperature: 1,
335659
- ...betas.length > 0 && { betas },
335660
335956
  metadata: getAPIMetadata(),
335661
335957
  ...getExtraBodyParams()
335958
+ }, {
335959
+ ...betas.length > 0 ? { headers: headersForBetas4(betas) } : {}
335662
335960
  });
335663
335961
  return true;
335664
335962
  }, { maxRetries: 2, model, thinkingConfig: { type: "disabled" } }));
@@ -336057,4 +336355,4 @@ export {
336057
336355
  AbortError2 as AbortError
336058
336356
  };
336059
336357
 
336060
- //# debugId=C79EE43EDCAB4CD864756E2164756E21
336358
+ //# debugId=1FEDB4CAC28D153364756E2164756E21