@rynfar/meridian 1.69.0 → 1.70.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 +1 -0
- package/dist/{cli-x1sv3bqf.js → cli-198xnjcn.js} +136 -21
- package/dist/cli.js +1 -1
- package/dist/meridian-v2/index.js +20384 -41
- package/dist/meridian-v2.js +20382 -45
- package/dist/proxy/adapters/detect.d.ts.map +1 -1
- package/dist/proxy/adapters/polytoken.d.ts +36 -0
- package/dist/proxy/adapters/polytoken.d.ts.map +1 -0
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/sdkFeatures.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/transforms/polytoken.d.ts +18 -0
- package/dist/proxy/transforms/polytoken.d.ts.map +1 -0
- package/dist/proxy/transforms/registry.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
- package/plugin/meridian-v2.ts +223 -0
package/README.md
CHANGED
|
@@ -108,6 +108,7 @@ The Claude Agent SDK provides programmatic access to Claude. But your favorite c
|
|
|
108
108
|
| [Prime Agent](https://www.npmjs.com/package/prime-agent) | ⚠️ Single-agent verified | Extension config (see [Agent Setup](docs/agents.md)) — reliable with one active agent. Concurrent RLM subagents receive distinct session keys, but are not yet production-safe; see [Prime Agent subagents](#prime-agent-subagents). The extension's `metadata.user_id` stamp is **required**, not optional. |
|
|
109
109
|
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | ✅ Verified | `ANTHROPIC_BASE_URL` — remote clients share a Max subscription over the network; client CWD preserved in system prompt |
|
|
110
110
|
| [Cherry Studio](https://github.com/CherryHQ/cherry-studio) | ✅ Verified | `cherry` adapter (see [Agent Setup](docs/agents.md)) — chat client with Claude's built-in web search via internal mode |
|
|
111
|
+
| [Polytoken](https://polytoken.dev/) | ✅ Verified | Provider config (see [Agent Setup](docs/agents.md#Polytoken)) — `X-Polytoken-Session` identity, mandatory client-owned tools (passthrough cannot be disabled), signed-thinking passthrough |
|
|
111
112
|
| Jcode | ✅ Verified | `/v1/chat/completions` + `x-jcode-session` header — dedicated `jcode` adapter keeps append-only history intact, so retained sessions resume on one SDK session (90.9% cache hit on turn 2 of a two-turn Opus session) |
|
|
112
113
|
| [Codex CLI](https://github.com/openai/codex) | ✅ Verified | `/v1/responses` (see [Agent Setup](docs/agents.md)) — Responses-API provider, passthrough tool execution; verified on 0.144 (plain + tool-driving turns) |
|
|
113
114
|
| [Continue](https://github.com/continuedev/continue) | 🔲 Untested | OpenAI-compatible endpoints should work — set `apiBase` to `http://127.0.0.1:3456` |
|
|
@@ -3338,6 +3338,93 @@ var init_cherry = __esm(() => {
|
|
|
3338
3338
|
};
|
|
3339
3339
|
});
|
|
3340
3340
|
|
|
3341
|
+
// src/proxy/transforms/polytoken.ts
|
|
3342
|
+
var polytokenTransforms;
|
|
3343
|
+
var init_polytoken = __esm(() => {
|
|
3344
|
+
polytokenTransforms = [
|
|
3345
|
+
{
|
|
3346
|
+
name: "polytoken-core",
|
|
3347
|
+
adapters: ["polytoken"],
|
|
3348
|
+
onRequest(ctx) {
|
|
3349
|
+
return {
|
|
3350
|
+
...ctx,
|
|
3351
|
+
blockedTools: [],
|
|
3352
|
+
incompatibleTools: [],
|
|
3353
|
+
allowedMcpTools: [],
|
|
3354
|
+
coreToolNames: [],
|
|
3355
|
+
passthrough: true,
|
|
3356
|
+
sdkAgents: {},
|
|
3357
|
+
sdkHooks: undefined,
|
|
3358
|
+
systemContext: ctx.systemContext,
|
|
3359
|
+
supportsThinking: true,
|
|
3360
|
+
shouldTrackFileChanges: false,
|
|
3361
|
+
extractFileChangesFromToolUse: undefined
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
];
|
|
3366
|
+
});
|
|
3367
|
+
|
|
3368
|
+
// src/proxy/adapters/polytoken.ts
|
|
3369
|
+
function normalizePolytokenSessionId(value) {
|
|
3370
|
+
const trimmed = value?.trim();
|
|
3371
|
+
return trimmed ? trimmed : undefined;
|
|
3372
|
+
}
|
|
3373
|
+
var POLYTOKEN_SESSION_HEADER = "x-polytoken-session", polytokenAdapter;
|
|
3374
|
+
var init_polytoken2 = __esm(() => {
|
|
3375
|
+
init_messages();
|
|
3376
|
+
init_polytoken();
|
|
3377
|
+
polytokenAdapter = {
|
|
3378
|
+
name: "polytoken",
|
|
3379
|
+
clientEnvironmentMayDifferFromProxy: true,
|
|
3380
|
+
getSessionId(c) {
|
|
3381
|
+
return normalizePolytokenSessionId(c.req.header(POLYTOKEN_SESSION_HEADER));
|
|
3382
|
+
},
|
|
3383
|
+
extractWorkingDirectory(_body) {
|
|
3384
|
+
return;
|
|
3385
|
+
},
|
|
3386
|
+
extractClientWorkingDirectory(_body) {
|
|
3387
|
+
return;
|
|
3388
|
+
},
|
|
3389
|
+
normalizeContent(content) {
|
|
3390
|
+
return normalizeContent(content);
|
|
3391
|
+
},
|
|
3392
|
+
getBlockedBuiltinTools() {
|
|
3393
|
+
return [];
|
|
3394
|
+
},
|
|
3395
|
+
getAgentIncompatibleTools() {
|
|
3396
|
+
return [];
|
|
3397
|
+
},
|
|
3398
|
+
getMcpServerName() {
|
|
3399
|
+
return "polytoken";
|
|
3400
|
+
},
|
|
3401
|
+
getAllowedMcpTools() {
|
|
3402
|
+
return [];
|
|
3403
|
+
},
|
|
3404
|
+
getCoreToolNames() {
|
|
3405
|
+
return [];
|
|
3406
|
+
},
|
|
3407
|
+
usesPassthrough() {
|
|
3408
|
+
return true;
|
|
3409
|
+
},
|
|
3410
|
+
supportsThinking() {
|
|
3411
|
+
return true;
|
|
3412
|
+
},
|
|
3413
|
+
shouldTrackFileChanges() {
|
|
3414
|
+
return false;
|
|
3415
|
+
},
|
|
3416
|
+
buildSdkAgents(_body, _mcpToolNames) {
|
|
3417
|
+
return {};
|
|
3418
|
+
},
|
|
3419
|
+
buildSdkHooks(_body, _sdkAgents) {
|
|
3420
|
+
return;
|
|
3421
|
+
},
|
|
3422
|
+
buildSystemContextAddendum(_body, _sdkAgents) {
|
|
3423
|
+
return "";
|
|
3424
|
+
}
|
|
3425
|
+
};
|
|
3426
|
+
});
|
|
3427
|
+
|
|
3341
3428
|
// src/proxy/adapterInstances.ts
|
|
3342
3429
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
3343
3430
|
import { join as join5 } from "node:path";
|
|
@@ -3429,6 +3516,10 @@ __export(exports_detect, {
|
|
|
3429
3516
|
function listAdapterNames() {
|
|
3430
3517
|
return [...new Set(Object.values(ADAPTER_MAP).map((a) => a.name))];
|
|
3431
3518
|
}
|
|
3519
|
+
function resolveDefaultAdapter() {
|
|
3520
|
+
const current = (process.env.MERIDIAN_DEFAULT_AGENT || "").toLowerCase();
|
|
3521
|
+
return ADAPTER_MAP[current] ?? openCodeAdapter;
|
|
3522
|
+
}
|
|
3432
3523
|
function isLiteLLMRequest(c) {
|
|
3433
3524
|
if ((c.req.header("user-agent") || "").startsWith("litellm/"))
|
|
3434
3525
|
return true;
|
|
@@ -3456,19 +3547,20 @@ function detectAdapter(c) {
|
|
|
3456
3547
|
}
|
|
3457
3548
|
const instances = loadAdapterInstances();
|
|
3458
3549
|
const instanceNames = Object.keys(instances);
|
|
3459
|
-
if (instanceNames.length > 0) {
|
|
3460
|
-
|
|
3461
|
-
|
|
3550
|
+
if (instanceNames.length > 0 && agentOverride && instances[agentOverride]) {
|
|
3551
|
+
const inst = makeInstanceAdapter(agentOverride, instances[agentOverride]);
|
|
3552
|
+
if (inst)
|
|
3553
|
+
return inst;
|
|
3554
|
+
}
|
|
3555
|
+
if (normalizePolytokenSessionId(c.req.header("x-polytoken-session"))) {
|
|
3556
|
+
return polytokenAdapter;
|
|
3557
|
+
}
|
|
3558
|
+
for (const name of instanceNames) {
|
|
3559
|
+
if (matchesInstance(instances[name], (h) => c.req.header(h))) {
|
|
3560
|
+
const inst = makeInstanceAdapter(name, instances[name]);
|
|
3462
3561
|
if (inst)
|
|
3463
3562
|
return inst;
|
|
3464
3563
|
}
|
|
3465
|
-
for (const name of instanceNames) {
|
|
3466
|
-
if (matchesInstance(instances[name], (h) => c.req.header(h))) {
|
|
3467
|
-
const inst = makeInstanceAdapter(name, instances[name]);
|
|
3468
|
-
if (inst)
|
|
3469
|
-
return inst;
|
|
3470
|
-
}
|
|
3471
|
-
}
|
|
3472
3564
|
}
|
|
3473
3565
|
if (c.req.header("x-opencode-session")) {
|
|
3474
3566
|
return openCodeAdapter;
|
|
@@ -3486,6 +3578,9 @@ function detectAdapter(c) {
|
|
|
3486
3578
|
if (userAgent.startsWith("Charm-Crush/")) {
|
|
3487
3579
|
return crushAdapter;
|
|
3488
3580
|
}
|
|
3581
|
+
if (/^Polytoken(?:[\s/]|$)/.test(userAgent)) {
|
|
3582
|
+
return polytokenAdapter;
|
|
3583
|
+
}
|
|
3489
3584
|
if (c.req.header("x-session-affinity")) {
|
|
3490
3585
|
return openCodeAdapter;
|
|
3491
3586
|
}
|
|
@@ -3499,9 +3594,9 @@ function detectAdapter(c) {
|
|
|
3499
3594
|
if (isLiteLLMRequest(c)) {
|
|
3500
3595
|
return passthroughAdapter;
|
|
3501
3596
|
}
|
|
3502
|
-
return
|
|
3597
|
+
return resolveDefaultAdapter();
|
|
3503
3598
|
}
|
|
3504
|
-
var ADAPTER_MAP, envDefault
|
|
3599
|
+
var ADAPTER_MAP, envDefault;
|
|
3505
3600
|
var init_detect = __esm(() => {
|
|
3506
3601
|
init_opencode2();
|
|
3507
3602
|
init_droid2();
|
|
@@ -3515,6 +3610,7 @@ var init_detect = __esm(() => {
|
|
|
3515
3610
|
init_jcode();
|
|
3516
3611
|
init_codex();
|
|
3517
3612
|
init_cherry();
|
|
3613
|
+
init_polytoken2();
|
|
3518
3614
|
init_adapterInstances();
|
|
3519
3615
|
ADAPTER_MAP = {
|
|
3520
3616
|
opencode: openCodeAdapter,
|
|
@@ -3529,6 +3625,7 @@ var init_detect = __esm(() => {
|
|
|
3529
3625
|
claudecode: claudeCodeAdapter,
|
|
3530
3626
|
cherry: cherryAdapter,
|
|
3531
3627
|
cherrystudio: cherryAdapter,
|
|
3628
|
+
polytoken: polytokenAdapter,
|
|
3532
3629
|
openai: openAiAdapter,
|
|
3533
3630
|
jcode: jcodeAdapter,
|
|
3534
3631
|
codex: codexAdapter
|
|
@@ -3537,7 +3634,6 @@ var init_detect = __esm(() => {
|
|
|
3537
3634
|
if (envDefault && !ADAPTER_MAP[envDefault]) {
|
|
3538
3635
|
console.warn(`[meridian] Unknown MERIDIAN_DEFAULT_AGENT="${envDefault}". ` + `Valid values: ${Object.keys(ADAPTER_MAP).join(", ")}. Falling back to opencode.`);
|
|
3539
3636
|
}
|
|
3540
|
-
defaultAdapter = ADAPTER_MAP[envDefault] ?? openCodeAdapter;
|
|
3541
3637
|
});
|
|
3542
3638
|
|
|
3543
3639
|
// src/proxy/sdkFeatures.ts
|
|
@@ -3693,6 +3789,14 @@ var init_sdkFeatures = __esm(() => {
|
|
|
3693
3789
|
},
|
|
3694
3790
|
codex: {
|
|
3695
3791
|
codeSystemPrompt: false
|
|
3792
|
+
},
|
|
3793
|
+
polytoken: {
|
|
3794
|
+
codeSystemPrompt: false,
|
|
3795
|
+
clientSystemPrompt: true,
|
|
3796
|
+
claudeMd: "off",
|
|
3797
|
+
memory: false,
|
|
3798
|
+
dreaming: false,
|
|
3799
|
+
sharedMemory: false
|
|
3696
3800
|
}
|
|
3697
3801
|
};
|
|
3698
3802
|
VALID_CLAUDE_MD_VALUES = new Set(["off", "project", "full"]);
|
|
@@ -23563,6 +23667,7 @@ var BILLING_SIGNALS = [
|
|
|
23563
23667
|
/^\s*(?:(?:error|api error|claude code returned an error result):\s*)*credit balance is too low[.!]?\s*$/m,
|
|
23564
23668
|
/^\s*(?:(?:error|api error|claude code returned an error result|subprocess stderr):\s*)*your (?:group|organization|org)(?:'|’)s usage limit is set to \$\d/m
|
|
23565
23669
|
];
|
|
23670
|
+
var SUBSCRIPTION_ACCESS_DISABLED = /^\s*(?:(?:error|api error|claude code returned an error result|subprocess stderr):\s*|failed to authenticate\.\s*)*(?:\d{3} )?your (?:organization|org) has disabled claude subscription access/m;
|
|
23566
23671
|
var HIT_YOUR_LIMIT = /hit your (?:[\w-]+ )?limit/;
|
|
23567
23672
|
var HIT_YOUR_SPEND_LIMIT = /^\s*(?:(?:error|api error|claude code returned an error result|subprocess stderr):\s*)*you(?:'|’)ve hit your (?:[\w'’-]+ ){0,4}(?:spend|usage) limit/m;
|
|
23568
23673
|
var REACHED_YOUR_TIER_LIMIT = /^[ \t]*(?:(?:error|api error|claude code returned an error result|subprocess stderr):[ \t]*)*(?:\d{3}[ \t]+)?you(?:'|’)ve reached your (?:claude )?(?:fable|mythos|opus|sonnet|haiku)(?: \d+(?:\.\d+)*)? limit(?:(?:[.!][ \t]+|[ \t]+)(?:(?:run[ \t]+)?\/usage-credits(?:[ \t]+to[ \t]+continue)?(?:[ \t]+or[ \t]+switch[ \t]+models[ \t]+with[ \t]+\/model)?|\/model[ \t]+to[ \t]+switch[ \t]+models|switch[ \t]+to[ \t]+another[ \t]+model(?:[ \t]+to[ \t]+continue)?)\.?|[.!]?)[ \t\r]*$/m;
|
|
@@ -23591,6 +23696,13 @@ function classifyError(errMsg, model) {
|
|
|
23591
23696
|
message: "Claude OAuth token has expired and could not be refreshed automatically. Run 'claude login' in your terminal to re-authenticate."
|
|
23592
23697
|
};
|
|
23593
23698
|
}
|
|
23699
|
+
if (SUBSCRIPTION_ACCESS_DISABLED.test(lower)) {
|
|
23700
|
+
return {
|
|
23701
|
+
status: 402,
|
|
23702
|
+
type: "billing_error",
|
|
23703
|
+
message: "This account's organization has disabled Claude subscription access for Claude Code. Ask the organization admin to re-enable it, or serve this request from an API-key profile — an identical retry on this account fails the same way."
|
|
23704
|
+
};
|
|
23705
|
+
}
|
|
23594
23706
|
if (HTTP_401.test(lower) || lower.includes("authentication") || lower.includes("invalid auth") || lower.includes("credentials")) {
|
|
23595
23707
|
return {
|
|
23596
23708
|
status: 401,
|
|
@@ -31905,6 +32017,7 @@ var claudeCodeTransforms = [
|
|
|
31905
32017
|
];
|
|
31906
32018
|
|
|
31907
32019
|
// src/proxy/transforms/registry.ts
|
|
32020
|
+
init_polytoken();
|
|
31908
32021
|
var ADAPTER_TRANSFORMS = {
|
|
31909
32022
|
opencode: openCodeTransforms,
|
|
31910
32023
|
crush: crushTransforms,
|
|
@@ -31917,7 +32030,8 @@ var ADAPTER_TRANSFORMS = {
|
|
|
31917
32030
|
"claude-code": claudeCodeTransforms,
|
|
31918
32031
|
openai: openCodeTransforms,
|
|
31919
32032
|
jcode: openCodeTransforms,
|
|
31920
|
-
codex: [...openCodeTransforms, ...codexTransforms]
|
|
32033
|
+
codex: [...openCodeTransforms, ...codexTransforms],
|
|
32034
|
+
polytoken: polytokenTransforms
|
|
31921
32035
|
};
|
|
31922
32036
|
function getAdapterTransforms(adapterName) {
|
|
31923
32037
|
return ADAPTER_TRANSFORMS[adapterName] ?? [];
|
|
@@ -37525,7 +37639,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
37525
37639
|
resolvedProfileId = profile.id;
|
|
37526
37640
|
const authStatus = await getClaudeAuthStatusAsync(profile.id !== "default" ? profile.id : undefined, Object.keys(profile.env).length > 0 ? profile.env : undefined);
|
|
37527
37641
|
const requestSource = c.req.header("x-meridian-source")?.slice(0, 64) || undefined;
|
|
37528
|
-
const declaredAgentMode = adapter.getAgentMode?.(c, body) ?? c.req.header("x-opencode-agent-mode") ?? null;
|
|
37642
|
+
const declaredAgentMode = adapter.getAgentMode?.(c, body) ?? (adapter.baseName === "polytoken" || adapter.name === "polytoken" ? undefined : c.req.header("x-opencode-agent-mode")) ?? null;
|
|
37529
37643
|
const isSubagentRequest = declaredAgentMode === "subagent" || requestSource?.startsWith("subagent-") === true;
|
|
37530
37644
|
const agentMode = isSubagentRequest ? "subagent" : declaredAgentMode;
|
|
37531
37645
|
const requestedModel = typeof body.model === "string" ? body.model : "sonnet";
|
|
@@ -37576,9 +37690,10 @@ data: ${JSON.stringify(lastError)}
|
|
|
37576
37690
|
workingDirectory
|
|
37577
37691
|
}), adapterBase);
|
|
37578
37692
|
const stream3 = pipelineCtx.prefersStreaming !== undefined ? pipelineCtx.prefersStreaming : body.stream ?? false;
|
|
37579
|
-
const
|
|
37580
|
-
const
|
|
37581
|
-
const
|
|
37693
|
+
const isPolytokenBase = adapterBase === "polytoken";
|
|
37694
|
+
const effortHeader = isPolytokenBase ? undefined : c.req.header("x-opencode-effort");
|
|
37695
|
+
const thinkingHeader = isPolytokenBase ? undefined : c.req.header("x-opencode-thinking");
|
|
37696
|
+
const taskBudgetHeader = isPolytokenBase ? undefined : c.req.header("x-opencode-task-budget");
|
|
37582
37697
|
const rawBetaHeader = c.req.header("anthropic-beta");
|
|
37583
37698
|
const betaFilter = filterBetasForProfile(rawBetaHeader, profile.type, getBetaPolicyFromEnv());
|
|
37584
37699
|
if (betaFilter.stripped.length > 0) {
|
|
@@ -37733,7 +37848,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
37733
37848
|
const trailingSystemReminderOptions = adapterBase === "claude-code" ? { allowTrailingSystemReminder: true } : undefined;
|
|
37734
37849
|
const durableCheckpointContinuation = durableCheckpointIds?.length && durableMappingAtTurn.status === "found" && matchesStoredLineagePrefix(durableMappingAtTurn.session, lineageMessages) ? coalesceCompleteToolResultContinuation((body.messages || []).slice(durableMappingAtTurn.session.messageCount), durableCheckpointIds, trailingSystemReminderOptions) : undefined;
|
|
37735
37850
|
const advancesDurableCheckpoint = Boolean(durableCheckpointContinuation);
|
|
37736
|
-
const passthrough = adapter.instancePassthrough !== undefined ? adapter.instancePassthrough : pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
|
|
37851
|
+
const passthrough = adapterBase === "polytoken" ? true : adapter.instancePassthrough !== undefined ? adapter.instancePassthrough : pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
|
|
37737
37852
|
if (advancesDurableCheckpoint && lineageResult.type !== "continuation" && lineageResult.type !== "compaction" && durableMappingAtTurn.status === "found") {
|
|
37738
37853
|
const checkpointSession = getSessionByClaudeId(durableMappingAtTurn.session.claudeSessionId);
|
|
37739
37854
|
if (checkpointSession) {
|
|
@@ -38174,7 +38289,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
38174
38289
|
}
|
|
38175
38290
|
const clientTool = requestTools.find((t) => t.name === toolName);
|
|
38176
38291
|
let toolInput = normalizeToolInput(input.tool_input, clientTool?.input_schema);
|
|
38177
|
-
if (toolName.toLowerCase() === "task" && toolInput?.subagent_type && typeof toolInput.subagent_type === "string") {
|
|
38292
|
+
if (adapterBase !== "polytoken" && toolName.toLowerCase() === "task" && toolInput?.subagent_type && typeof toolInput.subagent_type === "string") {
|
|
38178
38293
|
toolInput = { ...toolInput, subagent_type: resolveAgentAlias(toolInput.subagent_type, validAgentNames) };
|
|
38179
38294
|
}
|
|
38180
38295
|
const signature = toolUseSignature(toolName, toolInput);
|
|
@@ -39086,7 +39201,7 @@ data: ${JSON.stringify({
|
|
|
39086
39201
|
try {
|
|
39087
39202
|
const clientTool = requestTools.find((tool2) => tool2.name === buffered.name);
|
|
39088
39203
|
const parsed = normalizeToolInput(JSON.parse(buffered.json), clientTool?.input_schema);
|
|
39089
|
-
if (buffered.name.toLowerCase() === "task" && typeof parsed?.subagent_type === "string") {
|
|
39204
|
+
if (adapterBase !== "polytoken" && buffered.name.toLowerCase() === "task" && typeof parsed?.subagent_type === "string") {
|
|
39090
39205
|
parsed.subagent_type = resolveAgentAlias(parsed.subagent_type, validAgentNames);
|
|
39091
39206
|
}
|
|
39092
39207
|
fixed = JSON.stringify(parsed);
|