@rynfar/meridian 1.23.1 → 1.24.0

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
@@ -228,7 +228,8 @@ src/proxy/
228
228
  │ ├── detect.ts ← Agent detection from request headers
229
229
  │ ├── opencode.ts ← OpenCode adapter
230
230
  │ ├── crush.ts ← Crush (Charm) adapter
231
- └── droid.ts ← Droid (Factory AI) adapter
231
+ ├── droid.ts ← Droid (Factory AI) adapter
232
+ │ └── passthrough.ts ← LiteLLM passthrough adapter
232
233
  ├── query.ts ← SDK query options builder
233
234
  ├── errors.ts ← Error classification
234
235
  ├── models.ts ← Model mapping (sonnet/opus/haiku)
@@ -7648,7 +7648,92 @@ var crushAdapter = {
7648
7648
  }
7649
7649
  };
7650
7650
 
7651
+ // src/proxy/adapters/passthrough.ts
7652
+ var MCP_SERVER_NAME2 = "litellm";
7653
+ var ALLOWED_MCP_TOOLS2 = [
7654
+ `mcp__${MCP_SERVER_NAME2}__read`,
7655
+ `mcp__${MCP_SERVER_NAME2}__write`,
7656
+ `mcp__${MCP_SERVER_NAME2}__edit`,
7657
+ `mcp__${MCP_SERVER_NAME2}__bash`,
7658
+ `mcp__${MCP_SERVER_NAME2}__glob`,
7659
+ `mcp__${MCP_SERVER_NAME2}__grep`
7660
+ ];
7661
+ function extractCwdFromBody(body) {
7662
+ if (!body)
7663
+ return;
7664
+ let promptContent = "";
7665
+ if (typeof body.prompt === "string") {
7666
+ promptContent = body.prompt;
7667
+ } else if (Array.isArray(body.messages)) {
7668
+ for (const msg of body.messages) {
7669
+ if (msg.role === "user") {
7670
+ if (typeof msg.content === "string") {
7671
+ promptContent += msg.content;
7672
+ } else if (Array.isArray(msg.content)) {
7673
+ for (const block of msg.content) {
7674
+ if (block.type === "text" && block.text) {
7675
+ promptContent += block.text;
7676
+ }
7677
+ }
7678
+ }
7679
+ }
7680
+ }
7681
+ }
7682
+ const envMatch = promptContent.match(/<env[^>]*cwd=["']([^"']+)["']/s);
7683
+ if (envMatch)
7684
+ return envMatch[1];
7685
+ const cwdMatch = promptContent.match(/cwd=["']([^"']+)["']/);
7686
+ if (cwdMatch)
7687
+ return cwdMatch[1];
7688
+ return;
7689
+ }
7690
+ var passthroughAdapter = {
7691
+ name: "passthrough",
7692
+ getSessionId(c) {
7693
+ return c.req.header("x-litellm-session-id");
7694
+ },
7695
+ extractWorkingDirectory(body) {
7696
+ return extractCwdFromBody(body);
7697
+ },
7698
+ normalizeContent(content) {
7699
+ return normalizeContent(content);
7700
+ },
7701
+ getBlockedBuiltinTools() {
7702
+ return [];
7703
+ },
7704
+ getAgentIncompatibleTools() {
7705
+ return [];
7706
+ },
7707
+ getMcpServerName() {
7708
+ return MCP_SERVER_NAME2;
7709
+ },
7710
+ getAllowedMcpTools() {
7711
+ return ALLOWED_MCP_TOOLS2;
7712
+ },
7713
+ buildSdkAgents(_body, _mcpToolNames) {
7714
+ return {};
7715
+ },
7716
+ buildSdkHooks(_body, _sdkAgents) {
7717
+ return;
7718
+ },
7719
+ buildSystemContextAddendum(_body, _sdkAgents) {
7720
+ return "";
7721
+ },
7722
+ usesPassthrough() {
7723
+ return true;
7724
+ },
7725
+ prefersStreaming(_body) {
7726
+ return false;
7727
+ }
7728
+ };
7729
+
7651
7730
  // src/proxy/adapters/detect.ts
7731
+ function isLiteLLMRequest(c) {
7732
+ if ((c.req.header("user-agent") || "").startsWith("litellm/"))
7733
+ return true;
7734
+ const headers = c.req.header();
7735
+ return Object.keys(headers).some((k) => k.toLowerCase().startsWith("x-litellm-"));
7736
+ }
7652
7737
  function detectAdapter(c) {
7653
7738
  const userAgent = c.req.header("user-agent") || "";
7654
7739
  if (userAgent.startsWith("factory-cli/")) {
@@ -7657,6 +7742,9 @@ function detectAdapter(c) {
7657
7742
  if (userAgent.startsWith("Charm-Crush/")) {
7658
7743
  return crushAdapter;
7659
7744
  }
7745
+ if (isLiteLLMRequest(c)) {
7746
+ return passthroughAdapter;
7747
+ }
7660
7748
  return openCodeAdapter;
7661
7749
  }
7662
7750
 
@@ -14050,8 +14138,9 @@ function createProxyServer(config = {}) {
14050
14138
  const body = await c.req.json();
14051
14139
  const authStatus = await getClaudeAuthStatusAsync();
14052
14140
  let model = mapModelToClaudeModel(body.model || "sonnet", authStatus?.subscriptionType);
14053
- const stream2 = body.stream ?? true;
14054
14141
  const adapter = detectAdapter(c);
14142
+ const adapterStreamPref = adapter.prefersStreaming?.(body);
14143
+ const stream2 = adapterStreamPref !== undefined ? adapterStreamPref : body.stream ?? true;
14055
14144
  const workingDirectory = (process.env.MERIDIAN_WORKDIR ?? process.env.CLAUDE_PROXY_WORKDIR) || adapter.extractWorkingDirectory(body) || process.cwd();
14056
14145
  const {
14057
14146
  CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS,
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  __require,
4
4
  startProxyServer
5
- } from "./cli-nnnww55k.js";
5
+ } from "./cli-adpwqa7a.js";
6
6
 
7
7
  // bin/cli.ts
8
8
  import { createRequire } from "module";
@@ -64,6 +64,14 @@ export interface AgentAdapter {
64
64
  * Return empty string if nothing to add.
65
65
  */
66
66
  buildSystemContextAddendum?(body: any, sdkAgents: Record<string, any>): string;
67
+ /**
68
+ * Whether this agent prefers non-streaming (JSON) responses.
69
+ *
70
+ * When this method is defined and returns false, the proxy forces
71
+ * stream=false regardless of the client's body.stream setting.
72
+ * When undefined or returns true, body.stream is used (defaulting to true).
73
+ */
74
+ prefersStreaming?(body: any): boolean;
67
75
  /**
68
76
  * Whether this agent uses passthrough mode for tool execution.
69
77
  *
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/proxy/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE5C;;;OAGG;IACH,uBAAuB,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAEtD;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAA;IAEtC;;;OAGG;IACH,sBAAsB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE3C;;;;OAIG;IACH,yBAAyB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE9C;;;OAGG;IACH,gBAAgB,IAAI,MAAM,CAAA;IAE1B;;OAEG;IACH,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAAA;IAEvC;;;;OAIG;IACH,cAAc,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAEhF;;;OAGG;IACH,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAA;IAE9D;;;OAGG;IACH,0BAA0B,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAA;IAE9E;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,OAAO,CAAA;IAE3B;;;;;;;;;;;;;;;OAeG;IACH,6BAA6B,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,eAAe,EAAE,UAAU,EAAE,CAAA;CAC3G"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/proxy/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE5C;;;OAGG;IACH,uBAAuB,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAEtD;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAA;IAEtC;;;OAGG;IACH,sBAAsB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE3C;;;;OAIG;IACH,yBAAyB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE9C;;;OAGG;IACH,gBAAgB,IAAI,MAAM,CAAA;IAE1B;;OAEG;IACH,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAAA;IAEvC;;;;OAIG;IACH,cAAc,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAEhF;;;OAGG;IACH,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAA;IAE9D;;;OAGG;IACH,0BAA0B,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAA;IAE9E;;;;;;OAMG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAA;IAErC;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,OAAO,CAAA;IAE3B;;;;;;;;;;;;;;;OAeG;IACH,6BAA6B,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,eAAe,EAAE,UAAU,EAAE,CAAA;CAC3G"}
@@ -12,7 +12,8 @@ import type { AgentAdapter } from "../adapter";
12
12
  * Detection rules (evaluated in order):
13
13
  * 1. User-Agent starts with "factory-cli/" → Droid adapter
14
14
  * 2. User-Agent starts with "Charm-Crush/" → Crush adapter
15
- * 3. Default OpenCode adapter (backward compatible)
15
+ * 3. litellm/* UA or x-litellm-* headers LiteLLM passthrough adapter
16
+ * 4. Default → OpenCode adapter (backward compatible)
16
17
  */
17
18
  export declare function detectAdapter(c: Context): AgentAdapter;
18
19
  //# sourceMappingURL=detect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/detect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAK9C;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,YAAY,CAYtD"}
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/detect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAmB9C;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,YAAY,CAgBtD"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * LiteLLM passthrough adapter.
3
+ *
4
+ * Handles requests from LiteLLM (detected via x-litellm-* headers or
5
+ * litellm/* User-Agent). LiteLLM manages its own tool execution loop,
6
+ * so this adapter forces passthrough mode — the proxy returns tool_use
7
+ * blocks to LiteLLM for execution rather than running them internally.
8
+ *
9
+ * Key characteristics:
10
+ * - Passthrough mode always enabled (overrides MERIDIAN_PASSTHROUGH env var)
11
+ * - Non-streaming: LiteLLM health checks don't send x-litellm-* headers
12
+ * so we can't reliably distinguish them; non-streaming is safe for all requests
13
+ * - Session continuity: uses x-litellm-session-id header when present
14
+ * - CWD: extracts from <env cwd="..."> blocks in the prompt if available
15
+ * - MCP server name: "litellm" (tools appear as mcp__litellm__*)
16
+ */
17
+ import type { AgentAdapter } from "../adapter";
18
+ export declare const passthroughAdapter: AgentAdapter;
19
+ //# sourceMappingURL=passthrough.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passthrough.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/passthrough.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAiD9C,eAAO,MAAM,kBAAkB,EAAE,YA4EhC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AAiBvD,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAgB,MAAM,iBAAiB,CAAA;AAEnH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AAyF7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAksChF;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA0ChG"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AAiBvD,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAgB,MAAM,iBAAiB,CAAA;AAEnH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AAyF7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAosChF;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA0ChG"}
package/dist/server.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  getMaxSessionsLimit,
7
7
  hashMessage,
8
8
  startProxyServer
9
- } from "./cli-nnnww55k.js";
9
+ } from "./cli-adpwqa7a.js";
10
10
  export {
11
11
  startProxyServer,
12
12
  hashMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynfar/meridian",
3
- "version": "1.23.1",
3
+ "version": "1.24.0",
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",