@rynfar/meridian 1.45.0 → 1.45.2

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/README.md CHANGED
@@ -748,6 +748,36 @@ export default {
748
748
  - **Reload without restart:** `POST /plugins/reload`
749
749
  - **Full guide:** See [PLUGINS.md](PLUGINS.md)
750
750
 
751
+ ### Official plugins
752
+
753
+ Content-scoped scrubbers maintained alongside Meridian. Core stays a clean
754
+ proxy — anything that rewrites client prompt content ships as one of these
755
+ opt-in plugins instead:
756
+
757
+ | Plugin | What it does |
758
+ |--------|--------------|
759
+ | [`@rynfar/meridian-plugin-hermes-scrub`](https://github.com/rynfar/meridian-plugin-hermes-scrub) | Strips Hermes Agent's `# Finishing the job` harness block from the system prompt. Fixes empty-stream responses when proxying Hermes, and avoids its coding-harness fingerprint. |
760
+ | [`@rynfar/meridian-plugin-pi-scrub`](https://github.com/rynfar/meridian-plugin-pi-scrub) | Strips Pi's coding-agent-harness prompt line that Anthropic meters as Extra Usage. |
761
+ | [`@rynfar/meridian-plugin-opencode-scrub`](https://github.com/rynfar/meridian-plugin-opencode-scrub) | Strips OpenCode harness boilerplate from the system prompt before it reaches Claude. |
762
+
763
+ Install into Meridian's config dir and register the built file in
764
+ `~/.config/meridian/plugins.json`:
765
+
766
+ ```bash
767
+ cd ~/.config/meridian
768
+ npm install @rynfar/meridian-plugin-hermes-scrub
769
+ ```
770
+
771
+ ```json
772
+ {
773
+ "plugins": [
774
+ { "path": "/Users/you/.config/meridian/node_modules/@rynfar/meridian-plugin-hermes-scrub/dist/index.js", "enabled": true }
775
+ ]
776
+ }
777
+ ```
778
+
779
+ Paths must be absolute — the loader does not expand `~`.
780
+
751
781
  ## CLI Commands
752
782
 
753
783
  | Command | Description |
@@ -3818,6 +3818,33 @@ async function* guardUpstreamIdle(source, idleMs, onStall, clock = realClock) {
3818
3818
  }
3819
3819
  }
3820
3820
 
3821
+ // src/proxy/requestAbort.ts
3822
+ function linkRequestAbort(signal) {
3823
+ const controller = new AbortController;
3824
+ let attached = false;
3825
+ const abort = (reason) => {
3826
+ if (!controller.signal.aborted)
3827
+ controller.abort(reason);
3828
+ };
3829
+ const forwardAbort = () => abort(signal.reason);
3830
+ if (signal.aborted) {
3831
+ forwardAbort();
3832
+ } else {
3833
+ signal.addEventListener("abort", forwardAbort, { once: true });
3834
+ attached = true;
3835
+ }
3836
+ return {
3837
+ controller,
3838
+ abort,
3839
+ detach: () => {
3840
+ if (!attached)
3841
+ return;
3842
+ signal.removeEventListener("abort", forwardAbort);
3843
+ attached = false;
3844
+ }
3845
+ };
3846
+ }
3847
+
3821
3848
  // src/proxy/oauthUsage.ts
3822
3849
  var OAUTH_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
3823
3850
  var OAUTH_BETA_HEADER = "oauth-2025-04-20";
@@ -8111,6 +8138,9 @@ function stableStringify(value) {
8111
8138
  const parts = keys.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`);
8112
8139
  return `{${parts.join(",")}}`;
8113
8140
  }
8141
+ function toolUseSignature(name, input) {
8142
+ return `${name}::${stableStringify(input ?? null)}`;
8143
+ }
8114
8144
  function stripMcpPrefix(toolName) {
8115
8145
  if (toolName.startsWith(PASSTHROUGH_MCP_PREFIX)) {
8116
8146
  return toolName.slice(PASSTHROUGH_MCP_PREFIX.length);
@@ -9583,12 +9613,35 @@ function translateAnthropicToOpenAi(response, completionId, model, created, opti
9583
9613
  }
9584
9614
  function createSseTranslator(ctx) {
9585
9615
  let toolCallIndex = -1;
9586
- return (event) => {
9616
+ let lastUsage;
9617
+ const translate = (event) => {
9587
9618
  if (event.type === "content_block_start" && event.content_block?.type === "tool_use" && typeof event.content_block.name === "string") {
9588
9619
  toolCallIndex++;
9589
9620
  }
9621
+ if (event.type === "message_delta" && event.usage) {
9622
+ lastUsage = event.usage;
9623
+ }
9590
9624
  return translateAnthropicSseEvent(event, ctx.completionId, ctx.model, ctx.created, toolCallIndex, ctx.thinkingPassthrough);
9591
9625
  };
9626
+ translate.buildUsageChunk = () => {
9627
+ if (!ctx.includeUsage || !lastUsage)
9628
+ return null;
9629
+ const promptTokens = lastUsage.input_tokens ?? 0;
9630
+ const completionTokens = lastUsage.output_tokens ?? 0;
9631
+ return {
9632
+ id: ctx.completionId,
9633
+ object: "chat.completion.chunk",
9634
+ created: ctx.created,
9635
+ model: ctx.model,
9636
+ choices: [],
9637
+ usage: {
9638
+ prompt_tokens: promptTokens,
9639
+ completion_tokens: completionTokens,
9640
+ total_tokens: promptTokens + completionTokens
9641
+ }
9642
+ };
9643
+ };
9644
+ return translate;
9592
9645
  }
9593
9646
  function translateAnthropicSseEvent(event, completionId, model, created, toolCallNum, thinkingPassthrough) {
9594
9647
  if (event.type === "message_start") {
@@ -9987,7 +10040,6 @@ var BLOCKED_BUILTIN_TOOLS = [
9987
10040
  "Read",
9988
10041
  "Write",
9989
10042
  "Edit",
9990
- "MultiEdit",
9991
10043
  "Bash",
9992
10044
  "Glob",
9993
10045
  "Grep",
@@ -16563,7 +16615,9 @@ function stripConfigDir(env2) {
16563
16615
  }
16564
16616
  function computePassthroughMaxTurns(resumeSessionId, hasDeferredTools, advisorModel) {
16565
16617
  const hasResume = !!resumeSessionId;
16566
- const base = hasResume && hasDeferredTools ? 4 : 3;
16618
+ const defaultBase = hasResume && hasDeferredTools ? 4 : 3;
16619
+ const configured = envInt("PASSTHROUGH_MAX_TURNS", defaultBase);
16620
+ const base = configured > 0 ? configured : defaultBase;
16567
16621
  const advisorBump = advisorModel ? 3 : 0;
16568
16622
  return base + advisorBump;
16569
16623
  }
@@ -16594,7 +16648,7 @@ function resolveSystemPrompt(systemContext, passthrough, settingSources, codeSys
16594
16648
  return { systemPrompt: "" };
16595
16649
  return {};
16596
16650
  }
16597
- function buildQueryOptions(ctx) {
16651
+ function buildQueryOptions(ctx, abortController) {
16598
16652
  const {
16599
16653
  prompt,
16600
16654
  model,
@@ -16620,6 +16674,7 @@ function buildQueryOptions(ctx) {
16620
16674
  effort,
16621
16675
  thinking,
16622
16676
  taskBudget,
16677
+ outputFormat,
16623
16678
  betas,
16624
16679
  settingSources,
16625
16680
  codeSystemPrompt,
@@ -16642,6 +16697,7 @@ function buildQueryOptions(ctx) {
16642
16697
  cwd: workingDirectory,
16643
16698
  model,
16644
16699
  pathToClaudeCodeExecutable: claudeExecutable,
16700
+ ...abortController ? { abortController } : {},
16645
16701
  ...stream2 ? { includePartialMessages: true } : {},
16646
16702
  permissionMode: "bypassPermissions",
16647
16703
  allowDangerouslySkipPermissions: true,
@@ -16682,6 +16738,7 @@ function buildQueryOptions(ctx) {
16682
16738
  ...effort ? { effort } : {},
16683
16739
  ...thinking ? { thinking } : {},
16684
16740
  ...taskBudget ? { taskBudget } : {},
16741
+ ...outputFormat ? { outputFormat } : {},
16685
16742
  ...betas && betas.length > 0 ? { betas } : {},
16686
16743
  ...maxBudgetUsd && maxBudgetUsd > 0 ? { maxBudgetUsd } : {},
16687
16744
  ...fallbackModel ? { fallbackModel } : {},
@@ -16698,6 +16755,40 @@ function normalizeEffort(value) {
16698
16755
  return typeof value === "string" && VALID_EFFORTS.includes(value) ? value : undefined;
16699
16756
  }
16700
16757
 
16758
+ // src/proxy/structuredOutput.ts
16759
+ function isRecord(value) {
16760
+ return value !== null && typeof value === "object" && !Array.isArray(value);
16761
+ }
16762
+ function parseOutputFormat(outputConfig, tools) {
16763
+ if (outputConfig === undefined)
16764
+ return { ok: true, value: undefined };
16765
+ if (!isRecord(outputConfig)) {
16766
+ return { ok: false, message: "output_config: Expected an object" };
16767
+ }
16768
+ const format = outputConfig.format;
16769
+ if (format === undefined)
16770
+ return { ok: true, value: undefined };
16771
+ if (!isRecord(format)) {
16772
+ return { ok: false, message: "output_config.format: Expected an object" };
16773
+ }
16774
+ if (format.type !== "json_schema") {
16775
+ return { ok: false, message: "output_config.format.type: Only 'json_schema' is supported" };
16776
+ }
16777
+ if (!isRecord(format.schema)) {
16778
+ return { ok: false, message: "output_config.format.schema: Expected a JSON Schema object" };
16779
+ }
16780
+ if (Array.isArray(tools) && tools.length > 0) {
16781
+ return { ok: false, message: "output_config.format: Cannot be combined with tools" };
16782
+ }
16783
+ return {
16784
+ ok: true,
16785
+ value: { type: "json_schema", schema: format.schema }
16786
+ };
16787
+ }
16788
+ function structuredOutputText(value) {
16789
+ return JSON.stringify(value);
16790
+ }
16791
+
16701
16792
  // src/proxy/transforms/registry.ts
16702
16793
  var ADAPTER_TRANSFORMS = {
16703
16794
  opencode: openCodeTransforms,
@@ -17829,6 +17920,8 @@ function createProxyServer(config = {}) {
17829
17920
  }
17830
17921
  const handleMessages = async (c, requestMeta) => {
17831
17922
  const requestStartAt = Date.now();
17923
+ const requestAbort = linkRequestAbort(c.req.raw.signal);
17924
+ let streamOwnsAbortLink = false;
17832
17925
  return withClaudeLogContext({ requestId: requestMeta.requestId, endpoint: requestMeta.endpoint }, async () => {
17833
17926
  const adapter = detectAdapter(c);
17834
17927
  try {
@@ -17849,13 +17942,18 @@ function createProxyServer(config = {}) {
17849
17942
  if (body.messages.length === 0) {
17850
17943
  return c.json({ type: "error", error: { type: "invalid_request_error", message: "messages: Cannot be empty — at least one message is required" } }, 400);
17851
17944
  }
17945
+ const parsedOutputFormat = parseOutputFormat(body.output_config, body.tools);
17946
+ if (!parsedOutputFormat.ok) {
17947
+ return c.json({ type: "error", error: { type: "invalid_request_error", message: parsedOutputFormat.message } }, 400);
17948
+ }
17949
+ const outputFormat = parsedOutputFormat.value;
17852
17950
  const profile = resolveProfile(finalConfig.profiles, finalConfig.defaultProfile, c.req.header("x-meridian-profile") || undefined);
17853
17951
  const authStatus = await getClaudeAuthStatusAsync(profile.id !== "default" ? profile.id : undefined, Object.keys(profile.env).length > 0 ? profile.env : undefined);
17854
17952
  const agentMode = c.req.header("x-opencode-agent-mode") ?? null;
17855
17953
  const requestSource = c.req.header("x-meridian-source")?.slice(0, 64) || undefined;
17856
17954
  const requestedModel = typeof body.model === "string" ? body.model : "sonnet";
17857
17955
  let model = mapModelToClaudeModel(requestedModel, authStatus?.subscriptionType, agentMode);
17858
- const envOverrides = requestedModel.startsWith("claude-opus-") ? { ANTHROPIC_DEFAULT_OPUS_MODEL: requestedModel } : requestedModel.startsWith("claude-fable-") ? { ANTHROPIC_DEFAULT_FABLE_MODEL: requestedModel } : undefined;
17956
+ const envOverrides = requestedModel.startsWith("claude-opus-") ? { ANTHROPIC_DEFAULT_OPUS_MODEL: requestedModel } : requestedModel.startsWith("claude-fable-") ? { ANTHROPIC_DEFAULT_FABLE_MODEL: requestedModel } : requestedModel.startsWith("claude-sonnet-") ? { ANTHROPIC_DEFAULT_SONNET_MODEL: requestedModel } : requestedModel.startsWith("claude-haiku-") ? { ANTHROPIC_DEFAULT_HAIKU_MODEL: requestedModel } : undefined;
17859
17957
  const cwdResolution = resolveSdkWorkingDirectory({
17860
17958
  envOverride: process.env.MERIDIAN_WORKDIR ?? process.env.CLAUDE_PROXY_WORKDIR,
17861
17959
  adapterCwd: adapter.extractWorkingDirectory(body),
@@ -17946,7 +18044,10 @@ function createProxyServer(config = {}) {
17946
18044
  const agentSessionId = adapter.getSessionId(c);
17947
18045
  const profileSessionId = profile.id !== "default" && agentSessionId ? `${profile.id}:${agentSessionId}` : agentSessionId;
17948
18046
  const profileScopedCwd = profile.id !== "default" ? `${clientWorkingDirectory}::profile=${profile.id}` : clientWorkingDirectory;
17949
- const isIndependentSession = requestSource?.startsWith("fork-") || requestSource?.startsWith("subagent-") || false;
18047
+ const lastMessage = Array.isArray(body.messages) ? body.messages[body.messages.length - 1] : undefined;
18048
+ const lastIsToolResult = Array.isArray(lastMessage?.content) && lastMessage.content.some((b) => b?.type === "tool_result");
18049
+ const isClientDrivenLoop = !agentSessionId && lastIsToolResult;
18050
+ const isIndependentSession = requestSource?.startsWith("fork-") || requestSource?.startsWith("subagent-") || isClientDrivenLoop || false;
17950
18051
  let lineageResult = isIndependentSession ? { type: "diverged" } : lookupSession(profileSessionId, body.messages || [], profileScopedCwd);
17951
18052
  if (lineageResult.type === "undo" && adapter.name === "opencode" && !agentSessionId) {
17952
18053
  lineageResult = { type: "diverged" };
@@ -18056,6 +18157,11 @@ function createProxyServer(config = {}) {
18056
18157
  const passthrough = pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
18057
18158
  const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : pipelineCtx.settingSources ?? [];
18058
18159
  const capturedToolUses = [];
18160
+ const capturedSignatures = new Set;
18161
+ const capturedToolNames = new Set;
18162
+ let sawDuplicateToolUse = false;
18163
+ const toolChoice = body.tool_choice;
18164
+ const forceSingleToolUse = !!toolChoice && (toolChoice.type === "tool" || toolChoice.disable_parallel_tool_use === true);
18059
18165
  const fileChanges = [];
18060
18166
  let passthroughMcp;
18061
18167
  let requestTools = Array.isArray(body.tools) ? body.tools : [];
@@ -18104,6 +18210,8 @@ function createProxyServer(config = {}) {
18104
18210
  hooks: [async (input) => {
18105
18211
  if (input.tool_name === "ToolSearch")
18106
18212
  return {};
18213
+ if (input.tool_name === "StructuredOutput")
18214
+ return {};
18107
18215
  const toolName = stripMcpPrefix(input.tool_name);
18108
18216
  if (hasDeferredTools && coreSet && !coreSet.has(toolName.toLowerCase())) {
18109
18217
  discoveredTools.add(toolName);
@@ -18113,11 +18221,40 @@ function createProxyServer(config = {}) {
18113
18221
  if (toolName.toLowerCase() === "task" && toolInput?.subagent_type && typeof toolInput.subagent_type === "string") {
18114
18222
  toolInput = { ...toolInput, subagent_type: resolveAgentAlias(toolInput.subagent_type) };
18115
18223
  }
18116
- capturedToolUses.push({
18117
- id: input.tool_use_id,
18118
- name: toolName,
18119
- input: toolInput
18120
- });
18224
+ const signature = toolUseSignature(toolName, toolInput);
18225
+ const isExactDuplicate = capturedSignatures.has(signature);
18226
+ const isSameToolRepeat = !isExactDuplicate && capturedToolNames.has(toolName);
18227
+ const exceedsForcedSingle = forceSingleToolUse && capturedToolUses.length >= 1;
18228
+ if (isExactDuplicate) {
18229
+ claudeLog("passthrough.duplicate_tool_use_dropped", { name: toolName });
18230
+ } else if (isSameToolRepeat || exceedsForcedSingle) {
18231
+ sawDuplicateToolUse = true;
18232
+ claudeLog("passthrough.extra_tool_use_dropped", {
18233
+ name: toolName,
18234
+ reason: exceedsForcedSingle ? "forced_single" : "same_tool_repeat"
18235
+ });
18236
+ requestAbort.abort("passthrough single-step complete");
18237
+ } else {
18238
+ capturedSignatures.add(signature);
18239
+ capturedToolNames.add(toolName);
18240
+ capturedToolUses.push({
18241
+ id: input.tool_use_id,
18242
+ name: toolName,
18243
+ input: toolInput
18244
+ });
18245
+ }
18246
+ if (isExactDuplicate) {
18247
+ return {
18248
+ decision: "block",
18249
+ reason: "This exact tool call has already been forwarded to the client — do not repeat it. " + "Do not call additional tools and do not generate further text — end your turn now."
18250
+ };
18251
+ }
18252
+ if (isSameToolRepeat || exceedsForcedSingle) {
18253
+ return {
18254
+ decision: "block",
18255
+ reason: "This tool call was NOT executed and was not forwarded. Your earlier tool call(s) " + "are being returned to the client now; their results arrive next turn. Re-issue this " + "call after that if it is still needed. Do not call additional tools and do not " + "generate further text — end your turn now."
18256
+ };
18257
+ }
18121
18258
  return {
18122
18259
  decision: "block",
18123
18260
  reason: "This tool call has been forwarded to the client for execution. " + "The result will be delivered in a future turn. " + "Do not retry, do not call additional tools, and do not generate further text — end your turn now."
@@ -18136,6 +18273,8 @@ function createProxyServer(config = {}) {
18136
18273
  if (!stream2) {
18137
18274
  const contentBlocks = [];
18138
18275
  let assistantMessages = 0;
18276
+ let hasStructuredOutput = false;
18277
+ let structuredOutput;
18139
18278
  const upstreamStartAt = Date.now();
18140
18279
  let firstChunkAt;
18141
18280
  let currentSessionId;
@@ -18187,6 +18326,7 @@ function createProxyServer(config = {}) {
18187
18326
  effort,
18188
18327
  thinking,
18189
18328
  taskBudget,
18329
+ outputFormat,
18190
18330
  betas,
18191
18331
  settingSources,
18192
18332
  codeSystemPrompt: sdkFeatures.codeSystemPrompt,
@@ -18199,7 +18339,7 @@ function createProxyServer(config = {}) {
18199
18339
  sdkDebug: sdkFeatures.sdkDebug,
18200
18340
  additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
18201
18341
  advisorModel
18202
- }))) {
18342
+ }, requestAbort.controller))) {
18203
18343
  if (event.type === "rate_limit_event") {
18204
18344
  rateLimitStore.record(event.rate_limit_info);
18205
18345
  }
@@ -18250,6 +18390,7 @@ function createProxyServer(config = {}) {
18250
18390
  effort,
18251
18391
  thinking,
18252
18392
  taskBudget,
18393
+ outputFormat,
18253
18394
  betas,
18254
18395
  settingSources,
18255
18396
  codeSystemPrompt: sdkFeatures.codeSystemPrompt,
@@ -18262,7 +18403,7 @@ function createProxyServer(config = {}) {
18262
18403
  sdkDebug: sdkFeatures.sdkDebug,
18263
18404
  additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
18264
18405
  advisorModel
18265
- }));
18406
+ }, requestAbort.controller));
18266
18407
  return;
18267
18408
  }
18268
18409
  if (isExtraUsageRequiredError(errMsg) && hasExtendedContext(model)) {
@@ -18316,6 +18457,7 @@ function createProxyServer(config = {}) {
18316
18457
  effort,
18317
18458
  thinking,
18318
18459
  taskBudget,
18460
+ outputFormat,
18319
18461
  betas,
18320
18462
  settingSources,
18321
18463
  codeSystemPrompt: sdkFeatures.codeSystemPrompt,
@@ -18328,7 +18470,7 @@ function createProxyServer(config = {}) {
18328
18470
  sdkDebug: sdkFeatures.sdkDebug,
18329
18471
  additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
18330
18472
  advisorModel
18331
- }));
18473
+ }, requestAbort.controller));
18332
18474
  return;
18333
18475
  }
18334
18476
  if (isExpiredTokenError(errMsg) && !tokenRefreshed) {
@@ -18376,6 +18518,10 @@ function createProxyServer(config = {}) {
18376
18518
  if (message.session_id) {
18377
18519
  currentSessionId = message.session_id;
18378
18520
  }
18521
+ if (passthrough && sawDuplicateToolUse) {
18522
+ claudeLog("passthrough.loop_break", { mode: "non_stream", assistantMessages, captured: capturedToolUses.length });
18523
+ break;
18524
+ }
18379
18525
  if (message.type === "assistant") {
18380
18526
  assistantMessages += 1;
18381
18527
  if (message.uuid) {
@@ -18421,6 +18567,10 @@ function createProxyServer(config = {}) {
18421
18567
  if (resultUsage) {
18422
18568
  lastUsage = { ...lastUsage, ...resultUsage };
18423
18569
  }
18570
+ if (outputFormat && "structured_output" in message) {
18571
+ hasStructuredOutput = true;
18572
+ structuredOutput = message.structured_output;
18573
+ }
18424
18574
  }
18425
18575
  }
18426
18576
  claudeLog("upstream.completed", {
@@ -18448,14 +18598,40 @@ function createProxyServer(config = {}) {
18448
18598
  error.message = `${error.message}
18449
18599
  Subprocess stderr: ${stderrOutput}`;
18450
18600
  }
18451
- claudeLog("upstream.failed", {
18452
- mode: "non_stream",
18453
- model,
18454
- durationMs: Date.now() - upstreamStartAt,
18455
- error: error instanceof Error ? error.message : String(error),
18456
- ...stderrOutput ? { stderr: stderrOutput } : {}
18601
+ const sdkTerm = extractSdkTermination(error instanceof Error ? error.message : String(error));
18602
+ const canRecoverAsToolUse = passthrough && capturedToolUses.length > 0 && (sdkTerm.reason === "max_turns" || sdkTerm.reason === "aborted");
18603
+ if (canRecoverAsToolUse) {
18604
+ diagnosticLog2.session(`${requestMeta.requestId} sdk_termination_recovered ${formatSdkTermination(sdkTerm, {
18605
+ model,
18606
+ requestSource,
18607
+ isResume,
18608
+ hasDeferredTools,
18609
+ sdkSessionId: resumeSessionId
18610
+ })} captured=${capturedToolUses.length}`, requestMeta.requestId);
18611
+ claudeLog("passthrough.max_turns_recovered", {
18612
+ mode: "non_stream",
18613
+ reason: sdkTerm.reason,
18614
+ captured: capturedToolUses.length
18615
+ });
18616
+ } else {
18617
+ claudeLog("upstream.failed", {
18618
+ mode: "non_stream",
18619
+ model,
18620
+ durationMs: Date.now() - upstreamStartAt,
18621
+ error: error instanceof Error ? error.message : String(error),
18622
+ ...stderrOutput ? { stderr: stderrOutput } : {}
18623
+ });
18624
+ throw error;
18625
+ }
18626
+ }
18627
+ if (outputFormat) {
18628
+ if (!hasStructuredOutput) {
18629
+ throw new Error("Structured output was requested but the SDK returned no structured_output result");
18630
+ }
18631
+ contentBlocks.splice(0, contentBlocks.length, {
18632
+ type: "text",
18633
+ text: structuredOutputText(structuredOutput)
18457
18634
  });
18458
- throw error;
18459
18635
  }
18460
18636
  if (passthrough && capturedToolUses.length > 0) {
18461
18637
  const capturedById = new Map(capturedToolUses.map((tu) => [tu.id, tu]));
@@ -18545,7 +18721,7 @@ Subprocess stderr: ${stderrOutput}`;
18545
18721
  cacheCreationInputTokens: lastUsage?.cache_creation_input_tokens,
18546
18722
  cacheHitRate: computeCacheHitRate(lastUsage)
18547
18723
  });
18548
- if (currentSessionId && !isIndependentSession) {
18724
+ if (currentSessionId && !isIndependentSession && !sawDuplicateToolUse) {
18549
18725
  storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
18550
18726
  }
18551
18727
  const responseSessionId = currentSessionId || resumeSessionId || `session_${Date.now()}`;
@@ -18606,6 +18782,8 @@ Subprocess stderr: ${stderrOutput}`;
18606
18782
  sdkUuidMap.push(null);
18607
18783
  let messageStartEmitted = false;
18608
18784
  let lastUsage;
18785
+ let hasStructuredOutput = false;
18786
+ let structuredOutput;
18609
18787
  const streamedToolUseIds = new Set;
18610
18788
  try {
18611
18789
  let currentSessionId;
@@ -18647,6 +18825,7 @@ Subprocess stderr: ${stderrOutput}`;
18647
18825
  effort,
18648
18826
  thinking,
18649
18827
  taskBudget,
18828
+ outputFormat,
18650
18829
  betas,
18651
18830
  settingSources,
18652
18831
  codeSystemPrompt: sdkFeatures.codeSystemPrompt,
@@ -18659,7 +18838,7 @@ Subprocess stderr: ${stderrOutput}`;
18659
18838
  sdkDebug: sdkFeatures.sdkDebug,
18660
18839
  additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
18661
18840
  advisorModel
18662
- }))) {
18841
+ }, requestAbort.controller))) {
18663
18842
  if (event.type === "rate_limit_event") {
18664
18843
  rateLimitStore.record(event.rate_limit_info);
18665
18844
  }
@@ -18710,6 +18889,7 @@ Subprocess stderr: ${stderrOutput}`;
18710
18889
  effort,
18711
18890
  thinking,
18712
18891
  taskBudget,
18892
+ outputFormat,
18713
18893
  betas,
18714
18894
  settingSources,
18715
18895
  codeSystemPrompt: sdkFeatures.codeSystemPrompt,
@@ -18722,7 +18902,7 @@ Subprocess stderr: ${stderrOutput}`;
18722
18902
  sdkDebug: sdkFeatures.sdkDebug,
18723
18903
  additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
18724
18904
  advisorModel
18725
- }));
18905
+ }, requestAbort.controller));
18726
18906
  return;
18727
18907
  }
18728
18908
  if (isExtraUsageRequiredError(errMsg) && hasExtendedContext(model)) {
@@ -18776,6 +18956,7 @@ Subprocess stderr: ${stderrOutput}`;
18776
18956
  effort,
18777
18957
  thinking,
18778
18958
  taskBudget,
18959
+ outputFormat,
18779
18960
  betas,
18780
18961
  settingSources,
18781
18962
  codeSystemPrompt: sdkFeatures.codeSystemPrompt,
@@ -18788,7 +18969,7 @@ Subprocess stderr: ${stderrOutput}`;
18788
18969
  sdkDebug: sdkFeatures.sdkDebug,
18789
18970
  additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
18790
18971
  advisorModel
18791
- }));
18972
+ }, requestAbort.controller));
18792
18973
  return;
18793
18974
  }
18794
18975
  if (isExpiredTokenError(errMsg) && !tokenRefreshed) {
@@ -18876,6 +19057,15 @@ Subprocess stderr: ${stderrOutput}`;
18876
19057
  if (message.type === "assistant" && message.uuid) {
18877
19058
  sdkUuidMap.push(message.uuid);
18878
19059
  }
19060
+ if (message.type === "result") {
19061
+ const resultUsage = message.usage;
19062
+ if (resultUsage)
19063
+ lastUsage = { ...lastUsage, ...resultUsage };
19064
+ if (outputFormat && "structured_output" in message) {
19065
+ hasStructuredOutput = true;
19066
+ structuredOutput = message.structured_output;
19067
+ }
19068
+ }
18879
19069
  if (message.type === "stream_event") {
18880
19070
  streamEventsSeen += 1;
18881
19071
  if (!firstChunkAt) {
@@ -18889,6 +19079,18 @@ Subprocess stderr: ${stderrOutput}`;
18889
19079
  const event = message.event;
18890
19080
  const eventType = event.type;
18891
19081
  const eventIndex = event.index;
19082
+ if (outputFormat) {
19083
+ if (eventType === "message_start") {
19084
+ const startUsage = event.message?.usage;
19085
+ if (startUsage)
19086
+ lastUsage = { ...lastUsage, ...startUsage };
19087
+ } else if (eventType === "message_delta") {
19088
+ const deltaUsage = event.usage;
19089
+ if (deltaUsage)
19090
+ lastUsage = { ...lastUsage, ...deltaUsage };
19091
+ }
19092
+ continue;
19093
+ }
18892
19094
  if (eventType === "message_start") {
18893
19095
  skipBlockIndices.clear();
18894
19096
  sdkToClientIndex.clear();
@@ -19026,6 +19228,60 @@ data: ${JSON.stringify({ type: "message_stop" })}
19026
19228
  } finally {
19027
19229
  clearInterval(heartbeat);
19028
19230
  }
19231
+ if (outputFormat) {
19232
+ if (!hasStructuredOutput) {
19233
+ throw new Error("Structured output was requested but the SDK returned no structured_output result");
19234
+ }
19235
+ const text = structuredOutputText(structuredOutput);
19236
+ const messageId = `msg_${Date.now()}`;
19237
+ safeEnqueue(encoder.encode(`event: message_start
19238
+ data: ${JSON.stringify({
19239
+ type: "message_start",
19240
+ message: {
19241
+ id: messageId,
19242
+ type: "message",
19243
+ role: "assistant",
19244
+ content: [],
19245
+ model: body.model,
19246
+ stop_reason: null,
19247
+ stop_sequence: null,
19248
+ usage: { input_tokens: lastUsage?.input_tokens ?? 0, output_tokens: 0 }
19249
+ }
19250
+ })}
19251
+
19252
+ `), "structured_message_start");
19253
+ safeEnqueue(encoder.encode(`event: content_block_start
19254
+ data: ${JSON.stringify({
19255
+ type: "content_block_start",
19256
+ index: 0,
19257
+ content_block: { type: "text", text: "" }
19258
+ })}
19259
+
19260
+ `), "structured_block_start");
19261
+ safeEnqueue(encoder.encode(`event: content_block_delta
19262
+ data: ${JSON.stringify({
19263
+ type: "content_block_delta",
19264
+ index: 0,
19265
+ delta: { type: "text_delta", text }
19266
+ })}
19267
+
19268
+ `), "structured_text_delta");
19269
+ safeEnqueue(encoder.encode(`event: content_block_stop
19270
+ data: ${JSON.stringify({ type: "content_block_stop", index: 0 })}
19271
+
19272
+ `), "structured_block_stop");
19273
+ safeEnqueue(encoder.encode(`event: message_delta
19274
+ data: ${JSON.stringify({
19275
+ type: "message_delta",
19276
+ delta: { stop_reason: "end_turn", stop_sequence: null },
19277
+ usage: { output_tokens: lastUsage?.output_tokens ?? 0 }
19278
+ })}
19279
+
19280
+ `), "structured_message_delta");
19281
+ messageStartEmitted = true;
19282
+ eventsForwarded += 5;
19283
+ textEventsForwarded += 1;
19284
+ }
19029
19285
  claudeLog("upstream.completed", {
19030
19286
  mode: "stream",
19031
19287
  model,
@@ -19046,7 +19302,7 @@ data: ${JSON.stringify({ type: "message_stop" })}
19046
19302
  const allNames = [...sessionDiscoveredTools.get(sessId)];
19047
19303
  plog(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
19048
19304
  }
19049
- if (currentSessionId && !isIndependentSession) {
19305
+ if (currentSessionId && !isIndependentSession && !sawDuplicateToolUse) {
19050
19306
  storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
19051
19307
  }
19052
19308
  if (!streamClosed) {
@@ -19230,7 +19486,7 @@ Subprocess stderr: ${stderrOutput}`;
19230
19486
  } : classifyError(errMsg);
19231
19487
  claudeLog("proxy.anthropic.error", { error: errMsg, classified: streamErr.type });
19232
19488
  const sdkTerm = extractSdkTermination(errMsg);
19233
- const canRecoverAsToolUse = sdkTerm.reason === "max_turns" && passthrough && capturedToolUses.length > 0 && messageStartEmitted;
19489
+ const canRecoverAsToolUse = (sdkTerm.reason === "max_turns" || sdkTerm.reason === "aborted" && sawDuplicateToolUse) && passthrough && capturedToolUses.length > 0 && messageStartEmitted;
19234
19490
  if (canRecoverAsToolUse) {
19235
19491
  diagnosticLog2.session(`${requestMeta.requestId} sdk_termination_recovered ${formatSdkTermination(sdkTerm, {
19236
19492
  model,
@@ -19377,10 +19633,17 @@ data: ${JSON.stringify({
19377
19633
  } catch {}
19378
19634
  streamClosed = true;
19379
19635
  }
19636
+ } finally {
19637
+ requestAbort.detach();
19380
19638
  }
19639
+ },
19640
+ cancel(reason) {
19641
+ requestAbort.abort(reason);
19642
+ requestAbort.detach();
19381
19643
  }
19382
19644
  });
19383
19645
  const streamSessionId = resumeSessionId || `session_${Date.now()}`;
19646
+ streamOwnsAbortLink = true;
19384
19647
  return new Response(readable, {
19385
19648
  headers: {
19386
19649
  "Content-Type": "text/event-stream",
@@ -19428,6 +19691,9 @@ data: ${JSON.stringify({
19428
19691
  error: classified.type
19429
19692
  });
19430
19693
  return new Response(JSON.stringify({ type: "error", error: { type: classified.type, message: classified.message } }), { status: classified.status, headers: { "Content-Type": "application/json" } });
19694
+ } finally {
19695
+ if (!streamOwnsAbortLink)
19696
+ requestAbort.detach();
19431
19697
  }
19432
19698
  });
19433
19699
  };
@@ -19667,7 +19933,9 @@ data: ${JSON.stringify({
19667
19933
  const decoder = new TextDecoder;
19668
19934
  let buffer = "";
19669
19935
  let streamError = null;
19670
- const translate = createSseTranslator({ completionId, model, created, thinkingPassthrough: sdkFeatures.thinkingPassthrough });
19936
+ const streamOptions = rawBody.stream_options;
19937
+ const includeUsage = streamOptions?.include_usage === true;
19938
+ const translate = createSseTranslator({ completionId, model, created, thinkingPassthrough: sdkFeatures.thinkingPassthrough, includeUsage });
19671
19939
  try {
19672
19940
  while (true) {
19673
19941
  const { done, value } = await reader.read();
@@ -19701,10 +19969,17 @@ data: ${JSON.stringify({
19701
19969
  } catch (err) {
19702
19970
  streamError = err instanceof Error ? err : new Error(String(err));
19703
19971
  } finally {
19704
- if (!streamError)
19972
+ if (!streamError) {
19973
+ const usageChunk = translate.buildUsageChunk();
19974
+ if (usageChunk) {
19975
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(usageChunk)}
19976
+
19977
+ `));
19978
+ }
19705
19979
  controller.enqueue(encoder.encode(`data: [DONE]
19706
19980
 
19707
19981
  `));
19982
+ }
19708
19983
  controller.close();
19709
19984
  }
19710
19985
  }
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startProxyServer
4
- } from "./cli-rakysex2.js";
4
+ } from "./cli-kgrg9sq3.js";
5
5
  import"./cli-cx463q74.js";
6
6
  import"./cli-sry5aqdj.js";
7
7
  import"./cli-4rqtm83g.js";
@@ -67,6 +67,9 @@ export interface OpenAiChatRequest {
67
67
  output_config?: {
68
68
  effort?: string;
69
69
  };
70
+ stream_options?: {
71
+ include_usage?: boolean;
72
+ };
70
73
  }
71
74
  export interface AnthropicTextBlock {
72
75
  type: "text";
@@ -169,6 +172,11 @@ export interface OpenAiStreamChunk {
169
172
  };
170
173
  finish_reason: "stop" | "length" | "tool_calls" | null;
171
174
  }>;
175
+ usage?: {
176
+ prompt_tokens: number;
177
+ completion_tokens: number;
178
+ total_tokens: number;
179
+ };
172
180
  }
173
181
  export interface OpenAiCompletionFunctionToolCall {
174
182
  type: "function";
@@ -262,9 +270,11 @@ export interface AnthropicSseEvent {
262
270
  message?: {
263
271
  id?: string;
264
272
  };
273
+ usage?: AnthropicUsage;
265
274
  }
266
275
  export interface SseTranslator {
267
276
  (event: AnthropicSseEvent): OpenAiStreamChunk | null;
277
+ buildUsageChunk(): OpenAiStreamChunk | null;
268
278
  }
269
279
  export interface SseTranslatorContext {
270
280
  completionId: string;
@@ -272,6 +282,7 @@ export interface SseTranslatorContext {
272
282
  created: number;
273
283
  /** When false, thinking blocks are stripped from the response */
274
284
  thinkingPassthrough?: boolean;
285
+ includeUsage?: boolean;
275
286
  }
276
287
  /**
277
288
  * A stateful translator for one OpenAI streaming response.
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/proxy/openai.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/proxy/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAA;AAEjE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,CAAA;IACjB,SAAS,CAAC,EAAE;QACV,GAAG,CAAC,EAAE,MAAM,CAAA;KACb,CAAA;CACF;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE;QACV,GAAG,CAAC,EAAE,MAAM,CAAA;KACb,CAAA;CACF;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAAA;IACrC,UAAU,CAAC,EAAE,wBAAwB,EAAE,CAAA;CACxC;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,UAAU,EAAE,OAAO,CAAA;QACnB,MAAM,CAAC,EAAE,OAAO,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,QAAQ,CAAA;CACf;AAED,MAAM,MAAM,cAAc,GAAG,sBAAsB,GAAG,oBAAoB,CAAA;AAE1E,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAA;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,cAAc,EAAE,CAAA;IACxB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gDAAgD;IAChD,aAAa,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACnC,cAAc,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAC7C;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;QAClB,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;CACF;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,OAAO,EAAE,MAAM,GAAG,qBAAqB,EAAE,CAAA;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,gBAAgB,EAAE,CAAA;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,aAAa,EAAE,CAAA;IACvB;oFACgF;IAChF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,UAAU,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,aAAa,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,qBAAqB,EAAE,CAAA;CAC1C;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,qBAAqB,GAC/B,kBAAkB,GAClB,mBAAmB,GACnB,sBAAsB,GACtB,wBAAwB,GACxB,qBAAqB,CAAA;AAEvB,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,CAAA;CACF;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,uBAAuB,CAAA;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,CAAC,CAAA;QACR,KAAK,EAAE;YACL,IAAI,CAAC,EAAE,WAAW,CAAA;YAClB,OAAO,CAAC,EAAE,MAAM,CAAA;YAChB,UAAU,CAAC,EAAE,4BAA4B,EAAE,CAAA;YAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAC3B,CAAA;QACD,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,IAAI,CAAA;KACvD,CAAC,CAAA;IACF,KAAK,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;CACnF;AAED,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAA;QACZ,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;CACF;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,QAAQ,CAAA;CACf;AAED,MAAM,MAAM,wBAAwB,GAClC,gCAAgC,GAChC,8BAA8B,CAAA;AAEhC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,iBAAiB,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,CAAC,CAAA;QACR,OAAO,EAAE;YACP,IAAI,EAAE,WAAW,CAAA;YACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;YACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;YAC1B,UAAU,CAAC,EAAE,wBAAwB,EAAE,CAAA;SACxC,CAAA;QACD,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAA;KAChD,CAAC,CAAA;IACF,KAAK,EAAE;QACL,aAAa,EAAE,MAAM,CAAA;QACrB,iBAAiB,EAAE,MAAM,CAAA;QACzB,YAAY,EAAE,MAAM,CAAA;KACrB,CAAA;CACF;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;CACvB;AAMD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE,GAAG,MAAM,CAUlF;AAwED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,iBAAiB,GAAG,oBAAoB,GAAG,IAAI,CAqJ/F;AAeD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1C,gBAAgB,CAmDlB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,aAAa,CAAC,EACV;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/B;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GACvC,qBAAqB,CAAA;IACzB,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACzB,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,IAAI,CAAA;IACpD,eAAe,IAAI,iBAAiB,GAAG,IAAI,CAAA;CAC5C;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,oBAAoB,GAAG,aAAa,CAiD5E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,iBAAiB,EACxB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,iBAAiB,GAAG,IAAI,CA2H1B;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,iBAAiB,EAAE,OAAO,EAAE,GAAG,SAAgC,GAAG,WAAW,EAAE,CAmD7G"}
@@ -40,6 +40,18 @@ export declare function computeToolSetKey(tools: Array<{
40
40
  input_schema?: unknown;
41
41
  defer_loading?: boolean;
42
42
  }>): string;
43
+ /**
44
+ * Stable semantic signature for a forwarded tool_use: tool name + a
45
+ * key-order-independent serialization of its input. Two tool calls with the
46
+ * same name and the same arguments share a signature even if the SDK assigns
47
+ * them different tool_use ids.
48
+ *
49
+ * Used by the passthrough capture path to tell apart genuine parallel calls
50
+ * (distinct signatures — e.g. get_weather vs get_time) from an SDK internal
51
+ * continuation turn re-emitting a blocked call (identical signature, new id).
52
+ * The former are all forwarded; the latter is a duplicate and dropped.
53
+ */
54
+ export declare function toolUseSignature(name: string, input: unknown): string;
43
55
  /**
44
56
  * Strip the MCP prefix from a tool name to get the OpenCode tool name.
45
57
  * e.g., "mcp__oc__todowrite" → "todowrite"
@@ -1 +1 @@
1
- {"version":3,"file":"passthroughTools.d.ts","sourceRoot":"","sources":["../../src/proxy/passthroughTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AACxC,eAAO,MAAM,sBAAsB,cAAmC,CAAA;AA0CtE,wBAAgB,qBAAqB,IAAI,MAAM,CAM9C;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,EACjG,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE;;;;EA4DlC;AAqBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAC9E,MAAM,CASR;AAUD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKvD;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC1C,YAAY,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,GACtF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgCrC"}
1
+ {"version":3,"file":"passthroughTools.d.ts","sourceRoot":"","sources":["../../src/proxy/passthroughTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AACxC,eAAO,MAAM,sBAAsB,cAAmC,CAAA;AA0CtE,wBAAgB,qBAAqB,IAAI,MAAM,CAM9C;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,EACjG,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE;;;;EA4DlC;AAqBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAC9E,MAAM,CASR;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAErE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKvD;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC1C,YAAY,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,GACtF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgCrC"}
@@ -4,7 +4,7 @@
4
4
  * Centralizes the construction of query() options, eliminating duplication
5
5
  * between the streaming and non-streaming paths in server.ts.
6
6
  */
7
- import type { Options, SettingSource } from "@anthropic-ai/claude-agent-sdk";
7
+ import type { Options, OutputFormat, SettingSource } from "@anthropic-ai/claude-agent-sdk";
8
8
  import { createPassthroughMcpServer } from "./passthroughTools";
9
9
  import type { Effort } from "./effort";
10
10
  export interface QueryContext {
@@ -72,6 +72,8 @@ export interface QueryContext {
72
72
  taskBudget?: {
73
73
  total: number;
74
74
  };
75
+ /** Native JSON-schema output contract for the Claude Agent SDK */
76
+ outputFormat?: OutputFormat;
75
77
  /** Beta features to enable */
76
78
  betas?: string[];
77
79
  /** SDK setting sources — controls CLAUDE.md and user settings loading */
@@ -115,5 +117,5 @@ export interface BuildQueryResult {
115
117
  * reports that as its working directory.
116
118
  */
117
119
  export declare function buildCwdNote(sdkCwd: string, clientCwd?: string): string;
118
- export declare function buildQueryOptions(ctx: QueryContext): BuildQueryResult;
120
+ export declare function buildQueryOptions(ctx: QueryContext, abortController?: AbortController): BuildQueryResult;
119
121
  //# sourceMappingURL=query.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/proxy/query.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/proxy/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface RequestAbortLink {
2
+ controller: AbortController;
3
+ abort: (reason?: unknown) => void;
4
+ detach: () => void;
5
+ }
6
+ /** Forward an HTTP request abort into the SDK query lifecycle. */
7
+ export declare function linkRequestAbort(signal: AbortSignal): RequestAbortLink;
8
+ //# sourceMappingURL=requestAbort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestAbort.d.ts","sourceRoot":"","sources":["../../src/proxy/requestAbort.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,eAAe,CAAA;IAC3B,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACjC,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,gBAAgB,CAyBtE"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AAGvD,YAAY,EACV,SAAS,EACT,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,GACZ,MAAM,aAAa,CAAA;AAKpB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAiCnG,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EAEpB,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAsC,MAAM,iBAAiB,CAAA;AAGzI,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AAiQ7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAgsFhF;AAWD,wBAAgB,gCAAgC,IAAI,IAAI,CAavD;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmGhG"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AAGvD,YAAY,EACV,SAAS,EACT,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,GACZ,MAAM,aAAa,CAAA;AAKpB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAkCnG,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EAEpB,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAsC,MAAM,iBAAiB,CAAA;AAGzI,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AAiQ7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CA8+FhF;AAWD,wBAAgB,gCAAgC,IAAI,IAAI,CAavD;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmGhG"}
@@ -0,0 +1,21 @@
1
+ import type { OutputFormat } from "@anthropic-ai/claude-agent-sdk";
2
+ export type OutputFormatParseResult = {
3
+ ok: true;
4
+ value: OutputFormat | undefined;
5
+ } | {
6
+ ok: false;
7
+ message: string;
8
+ };
9
+ /**
10
+ * Parse Anthropic's `output_config.format` into the Claude Agent SDK's native
11
+ * structured-output option. Absence is a no-op; malformed or unsupported
12
+ * values are rejected at the HTTP boundary instead of failing in the SDK.
13
+ *
14
+ * Combining `tools` with `output_config.format` is rejected: structured-output
15
+ * mode buffers the SDK's wire events and replaces the response content with the
16
+ * validated result, so a tool_use turn would be swallowed and the client-driven
17
+ * tool loop would never see it.
18
+ */
19
+ export declare function parseOutputFormat(outputConfig: unknown, tools?: unknown): OutputFormatParseResult;
20
+ export declare function structuredOutputText(value: unknown): string;
21
+ //# sourceMappingURL=structuredOutput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuredOutput.d.ts","sourceRoot":"","sources":["../../src/proxy/structuredOutput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAElE,MAAM,MAAM,uBAAuB,GAC/B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,YAAY,GAAG,SAAS,CAAA;CAAE,GAC7C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAMlC;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,uBAAuB,CAyBjG;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE3D"}
package/dist/server.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  runObserveHook,
12
12
  runTransformHook,
13
13
  startProxyServer
14
- } from "./cli-rakysex2.js";
14
+ } from "./cli-kgrg9sq3.js";
15
15
  import"./cli-cx463q74.js";
16
16
  import"./cli-sry5aqdj.js";
17
17
  import"./cli-4rqtm83g.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynfar/meridian",
3
- "version": "1.45.0",
3
+ "version": "1.45.2",
4
4
  "description": "Local Anthropic API powered by your Claude Max subscription. One subscription, every agent.",
5
5
  "type": "module",
6
6
  "main": "./dist/server.js",