@rynfar/meridian 1.62.4 → 1.62.6
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 +31 -1
- package/dist/{cli-je60fevk.js → cli-pc0mtjjv.js} +83 -1
- package/dist/{cli-n1jsth00.js → cli-wxk8xvd3.js} +58 -82
- package/dist/cli.js +4 -4
- package/dist/proxy/adapter.d.ts +5 -0
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/opencode.d.ts.map +1 -1
- package/dist/proxy/agentDefs.d.ts +9 -7
- package/dist/proxy/agentDefs.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/setup.d.ts +43 -0
- package/dist/proxy/setup.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/{setup-6c11e8d6.js → setup-0x573t61.js} +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,13 +104,43 @@ The Claude Agent SDK provides programmatic access to Claude. But your favorite c
|
|
|
104
104
|
| [Aider](https://github.com/paul-gauthier/aider) | ✅ Verified | Env vars — file editing, streaming; `--no-stream` broken (litellm bug) |
|
|
105
105
|
| [Open WebUI](https://github.com/open-webui/open-webui) | ✅ Verified | OpenAI-compatible endpoints — set base URL to `http://127.0.0.1:3456` |
|
|
106
106
|
| [Pi](https://github.com/mariozechner/pi-coding-agent) | ✅ Verified | models.json config (see [Agent Setup](docs/agents.md)) — full tool support via passthrough; detected via `x-meridian-agent: pi` header |
|
|
107
|
-
| [Prime Agent](https://www.npmjs.com/package/prime-agent) |
|
|
107
|
+
| [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. |
|
|
108
108
|
| [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 |
|
|
109
109
|
| [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 |
|
|
110
110
|
| 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) |
|
|
111
111
|
| [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) |
|
|
112
112
|
| [Continue](https://github.com/continuedev/continue) | 🔲 Untested | OpenAI-compatible endpoints should work — set `apiBase` to `http://127.0.0.1:3456` |
|
|
113
113
|
|
|
114
|
+
### Prime Agent subagents
|
|
115
|
+
|
|
116
|
+
Prime Agent is reliable through Meridian with one active agent. RLM children have
|
|
117
|
+
separate session identities and can execute successfully, but concurrent subagent
|
|
118
|
+
orchestration is not yet production-safe. Observed failure modes include overload
|
|
119
|
+
amplification, expensive cache churn after fresh-session replay, loss of child-task
|
|
120
|
+
context during recovery, undelivered tool envelopes, and incomplete parent-to-child
|
|
121
|
+
cancellation. Use a single active Prime Agent for unattended or usage-sensitive work
|
|
122
|
+
until coordinated fixes land in Prime Agent and Meridian.
|
|
123
|
+
|
|
124
|
+
Prime Agent can keep Opus on the root session while selecting Sol for an individual
|
|
125
|
+
child. A child inherits its parent's model unless the `rlm` call supplies an exact
|
|
126
|
+
`provider/model` selector returned by `rlm.find_models()`:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
sol_models = await rlm.find_models("sol")
|
|
130
|
+
print(sol_models) # choose an available exact selector for your authenticated providers
|
|
131
|
+
|
|
132
|
+
child = await rlm(
|
|
133
|
+
"Review this change and report your findings to the parent.",
|
|
134
|
+
name="sol-reviewer",
|
|
135
|
+
model="openai-codex/gpt-5.6-sol",
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The selector above requires an authenticated OpenAI Codex provider in Prime Agent;
|
|
140
|
+
Prime Inference may expose a different Sol selector. Explicit child model selection
|
|
141
|
+
reduces Claude Max pressure, but does not by itself fix the orchestration and
|
|
142
|
+
cancellation limitations above.
|
|
143
|
+
|
|
114
144
|
Tested an agent or built a plugin? [Open an issue](https://github.com/rynfar/meridian/issues) and we'll add it.
|
|
115
145
|
|
|
116
146
|
## FAQ
|
|
@@ -5,6 +5,72 @@ import { dirname, join } from "path";
|
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { applyEdits, modify, parse as parseJsonc } from "jsonc-parser";
|
|
7
7
|
|
|
8
|
+
// src/utils/lruMap.ts
|
|
9
|
+
class LRUMap {
|
|
10
|
+
maxSize;
|
|
11
|
+
onEvict;
|
|
12
|
+
map = new Map;
|
|
13
|
+
constructor(maxSize, onEvict) {
|
|
14
|
+
this.maxSize = maxSize;
|
|
15
|
+
this.onEvict = onEvict;
|
|
16
|
+
}
|
|
17
|
+
get size() {
|
|
18
|
+
return this.map.size;
|
|
19
|
+
}
|
|
20
|
+
get(key) {
|
|
21
|
+
const value = this.map.get(key);
|
|
22
|
+
if (value === undefined)
|
|
23
|
+
return;
|
|
24
|
+
this.map.delete(key);
|
|
25
|
+
this.map.set(key, value);
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
set(key, value) {
|
|
29
|
+
if (this.map.has(key)) {
|
|
30
|
+
this.map.delete(key);
|
|
31
|
+
} else if (this.map.size >= this.maxSize) {
|
|
32
|
+
this.evictOldest();
|
|
33
|
+
}
|
|
34
|
+
this.map.set(key, value);
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
has(key) {
|
|
38
|
+
return this.map.has(key);
|
|
39
|
+
}
|
|
40
|
+
delete(key) {
|
|
41
|
+
return this.map.delete(key);
|
|
42
|
+
}
|
|
43
|
+
clear() {
|
|
44
|
+
this.map.clear();
|
|
45
|
+
}
|
|
46
|
+
entries() {
|
|
47
|
+
return this.map.entries();
|
|
48
|
+
}
|
|
49
|
+
keys() {
|
|
50
|
+
return this.map.keys();
|
|
51
|
+
}
|
|
52
|
+
values() {
|
|
53
|
+
return this.map.values();
|
|
54
|
+
}
|
|
55
|
+
forEach(callbackfn) {
|
|
56
|
+
this.map.forEach((value, key) => callbackfn(value, key, this));
|
|
57
|
+
}
|
|
58
|
+
[Symbol.iterator]() {
|
|
59
|
+
return this.map[Symbol.iterator]();
|
|
60
|
+
}
|
|
61
|
+
evictOldest() {
|
|
62
|
+
const oldestKey = this.map.keys().next().value;
|
|
63
|
+
if (oldestKey === undefined)
|
|
64
|
+
return;
|
|
65
|
+
const oldestValue = this.map.get(oldestKey);
|
|
66
|
+
if (oldestValue === undefined)
|
|
67
|
+
return;
|
|
68
|
+
this.map.delete(oldestKey);
|
|
69
|
+
this.onEvict?.(oldestKey, oldestValue);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/proxy/setup.ts
|
|
8
74
|
class UnparseableConfigError extends Error {
|
|
9
75
|
configPath;
|
|
10
76
|
constructor(configPath) {
|
|
@@ -55,6 +121,22 @@ function checkPluginConfigured(configPath) {
|
|
|
55
121
|
const plugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
56
122
|
return plugins.some((p) => typeof p === "string" && isMeridianEntry(p));
|
|
57
123
|
}
|
|
124
|
+
var pluginlessWarned = new LRUMap(256);
|
|
125
|
+
function clearPluginlessWarnings() {
|
|
126
|
+
pluginlessWarned.clear();
|
|
127
|
+
}
|
|
128
|
+
function notePluginlessOpenCodeRequest(input) {
|
|
129
|
+
if (!input.userAgent?.toLowerCase().startsWith("opencode/"))
|
|
130
|
+
return;
|
|
131
|
+
if (input.agentModeHeader)
|
|
132
|
+
return;
|
|
133
|
+
const key = input.sessionId || "(keyless)";
|
|
134
|
+
if (pluginlessWarned.get(key))
|
|
135
|
+
return;
|
|
136
|
+
pluginlessWarned.set(key, true);
|
|
137
|
+
const shortId = input.sessionId ? `${input.sessionId.slice(0, 12)}…` : "(no session header)";
|
|
138
|
+
return `OpenCode request without the Meridian plugin's agent headers (session ${shortId}). ` + `OpenCode runs its internal title/summary agents under your session id, so Meridian ` + `cannot tell them apart from your conversation: the first turn of each session can fail ` + `with a 400 or replay against a cold cache. Fix: meridian setup (or update the plugin).`;
|
|
139
|
+
}
|
|
58
140
|
function runSetup(pluginPath, configPath) {
|
|
59
141
|
const path = configPath ?? findOpencodeConfigPath();
|
|
60
142
|
const dir = dirname(path);
|
|
@@ -82,4 +164,4 @@ function runSetup(pluginPath, configPath) {
|
|
|
82
164
|
return { configPath: path, pluginPath, alreadyConfigured, removedStale, created: false };
|
|
83
165
|
}
|
|
84
166
|
|
|
85
|
-
export { UnparseableConfigError, findOpencodeConfigPath, findPluginPath, checkPluginConfigured, runSetup };
|
|
167
|
+
export { LRUMap, UnparseableConfigError, findOpencodeConfigPath, findPluginPath, checkPluginConfigured, clearPluginlessWarnings, notePluginlessOpenCodeRequest, runSetup };
|
|
@@ -56,8 +56,10 @@ import {
|
|
|
56
56
|
setSetting
|
|
57
57
|
} from "./cli-vj9cv18n.js";
|
|
58
58
|
import {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
LRUMap,
|
|
60
|
+
checkPluginConfigured,
|
|
61
|
+
notePluginlessOpenCodeRequest
|
|
62
|
+
} from "./cli-pc0mtjjv.js";
|
|
61
63
|
import {
|
|
62
64
|
claudeLog,
|
|
63
65
|
createPlatformCredentialStore,
|
|
@@ -153,30 +155,44 @@ function parseAgentDescriptions(taskDescription) {
|
|
|
153
155
|
}
|
|
154
156
|
return agents;
|
|
155
157
|
}
|
|
156
|
-
function
|
|
158
|
+
function mapModelTier(model) {
|
|
159
|
+
if (!model)
|
|
160
|
+
return "inherit";
|
|
161
|
+
const lower = model.toLowerCase();
|
|
162
|
+
if (lower.includes("opus"))
|
|
163
|
+
return "opus";
|
|
164
|
+
if (lower.includes("fable") || lower.includes("mythos"))
|
|
165
|
+
return "fable";
|
|
166
|
+
if (lower.includes("haiku"))
|
|
167
|
+
return "haiku";
|
|
168
|
+
if (lower.includes("sonnet"))
|
|
169
|
+
return "sonnet";
|
|
170
|
+
return "inherit";
|
|
171
|
+
}
|
|
172
|
+
function buildAgentDefinitions(taskDescription, mcpToolNames, modelTier = "inherit") {
|
|
157
173
|
const descriptions = parseAgentDescriptions(taskDescription);
|
|
158
174
|
const agents = {};
|
|
159
175
|
for (const [name, description] of descriptions) {
|
|
160
176
|
agents[name] = {
|
|
161
177
|
description,
|
|
162
178
|
prompt: buildAgentPrompt(name, description),
|
|
163
|
-
model:
|
|
179
|
+
model: modelTier,
|
|
164
180
|
...mcpToolNames?.length ? { tools: [...mcpToolNames] } : {}
|
|
165
181
|
};
|
|
166
182
|
}
|
|
167
183
|
if (descriptions.size > 0) {
|
|
168
|
-
ensureDefaultAgents(agents, mcpToolNames);
|
|
184
|
+
ensureDefaultAgents(agents, mcpToolNames, modelTier);
|
|
169
185
|
addCaseVariants(agents);
|
|
170
186
|
}
|
|
171
187
|
return agents;
|
|
172
188
|
}
|
|
173
|
-
function ensureDefaultAgents(agents, mcpToolNames) {
|
|
189
|
+
function ensureDefaultAgents(agents, mcpToolNames, modelTier) {
|
|
174
190
|
for (const [name, description] of Object.entries(DEFAULT_AGENT_TYPES)) {
|
|
175
191
|
if (!agents[name]) {
|
|
176
192
|
agents[name] = {
|
|
177
193
|
description,
|
|
178
194
|
prompt: buildAgentPrompt(name, description),
|
|
179
|
-
model:
|
|
195
|
+
model: modelTier,
|
|
180
196
|
...mcpToolNames?.length ? { tools: [...mcpToolNames] } : {}
|
|
181
197
|
};
|
|
182
198
|
}
|
|
@@ -223,10 +239,10 @@ function parseAgentNamesFromSchema(taskTool) {
|
|
|
223
239
|
return [];
|
|
224
240
|
return enumNames.filter((n) => typeof n === "string");
|
|
225
241
|
}
|
|
226
|
-
function buildAgentDefinitionsFromTool(taskTool, mcpToolNames) {
|
|
242
|
+
function buildAgentDefinitionsFromTool(taskTool, mcpToolNames, modelTier = "inherit") {
|
|
227
243
|
const rawDescription = getNested(taskTool, "description");
|
|
228
244
|
const description = typeof rawDescription === "string" ? rawDescription : "";
|
|
229
|
-
const fromDescription = buildAgentDefinitions(description, mcpToolNames);
|
|
245
|
+
const fromDescription = buildAgentDefinitions(description, mcpToolNames, modelTier);
|
|
230
246
|
if (Object.keys(fromDescription).length > 0)
|
|
231
247
|
return fromDescription;
|
|
232
248
|
const names = parseAgentNamesFromSchema(taskTool);
|
|
@@ -240,11 +256,11 @@ function buildAgentDefinitionsFromTool(taskTool, mcpToolNames) {
|
|
|
240
256
|
agents[name] = {
|
|
241
257
|
description: desc,
|
|
242
258
|
prompt: buildAgentPrompt(name, desc),
|
|
243
|
-
model:
|
|
259
|
+
model: modelTier,
|
|
244
260
|
...mcpToolNames?.length ? { tools: [...mcpToolNames] } : {}
|
|
245
261
|
};
|
|
246
262
|
}
|
|
247
|
-
ensureDefaultAgents(agents, mcpToolNames);
|
|
263
|
+
ensureDefaultAgents(agents, mcpToolNames, modelTier);
|
|
248
264
|
addCaseVariants(agents);
|
|
249
265
|
return agents;
|
|
250
266
|
}
|
|
@@ -2191,7 +2207,7 @@ var init_opencode = __esm(() => {
|
|
|
2191
2207
|
if (Array.isArray(body.tools)) {
|
|
2192
2208
|
const taskTool = body.tools.find((t) => t.name === "task" || t.name === "Task");
|
|
2193
2209
|
if (taskTool) {
|
|
2194
|
-
sdkAgents = buildAgentDefinitionsFromTool(taskTool, [...allowedMcpTools]);
|
|
2210
|
+
sdkAgents = buildAgentDefinitionsFromTool(taskTool, [...allowedMcpTools], mapModelTier(body.model));
|
|
2195
2211
|
}
|
|
2196
2212
|
}
|
|
2197
2213
|
let sdkHooks = undefined;
|
|
@@ -2268,7 +2284,16 @@ var init_opencode2 = __esm(() => {
|
|
|
2268
2284
|
openCodeAdapter = {
|
|
2269
2285
|
name: "opencode",
|
|
2270
2286
|
getSessionId(c) {
|
|
2271
|
-
|
|
2287
|
+
const base = c.req.header("x-opencode-session") ?? c.req.header("x-session-affinity");
|
|
2288
|
+
if (!base)
|
|
2289
|
+
return;
|
|
2290
|
+
if (c.req.header("x-opencode-agent-mode") !== "subagent")
|
|
2291
|
+
return base;
|
|
2292
|
+
const agent = c.req.header("x-opencode-agent-name")?.trim();
|
|
2293
|
+
return agent ? `${base}#${agent}` : base;
|
|
2294
|
+
},
|
|
2295
|
+
getAgentMode(c) {
|
|
2296
|
+
return c.req.header("x-opencode-agent-mode");
|
|
2272
2297
|
},
|
|
2273
2298
|
extractWorkingDirectory(body) {
|
|
2274
2299
|
return extractClientCwd(body);
|
|
@@ -2306,7 +2331,7 @@ var init_opencode2 = __esm(() => {
|
|
|
2306
2331
|
const taskTool = body.tools.find((t) => t.name === "task" || t.name === "Task");
|
|
2307
2332
|
if (!taskTool)
|
|
2308
2333
|
return {};
|
|
2309
|
-
return buildAgentDefinitionsFromTool(taskTool, [...mcpToolNames]);
|
|
2334
|
+
return buildAgentDefinitionsFromTool(taskTool, [...mcpToolNames], mapModelTier(body.model));
|
|
2310
2335
|
},
|
|
2311
2336
|
buildSdkHooks(body, sdkAgents) {
|
|
2312
2337
|
const validAgentNames = Object.keys(sdkAgents);
|
|
@@ -11292,71 +11317,6 @@ function shouldAttemptRecovery(input) {
|
|
|
11292
11317
|
// src/proxy/server.ts
|
|
11293
11318
|
init_agentMatch();
|
|
11294
11319
|
|
|
11295
|
-
// src/utils/lruMap.ts
|
|
11296
|
-
class LRUMap {
|
|
11297
|
-
maxSize;
|
|
11298
|
-
onEvict;
|
|
11299
|
-
map = new Map;
|
|
11300
|
-
constructor(maxSize, onEvict) {
|
|
11301
|
-
this.maxSize = maxSize;
|
|
11302
|
-
this.onEvict = onEvict;
|
|
11303
|
-
}
|
|
11304
|
-
get size() {
|
|
11305
|
-
return this.map.size;
|
|
11306
|
-
}
|
|
11307
|
-
get(key) {
|
|
11308
|
-
const value = this.map.get(key);
|
|
11309
|
-
if (value === undefined)
|
|
11310
|
-
return;
|
|
11311
|
-
this.map.delete(key);
|
|
11312
|
-
this.map.set(key, value);
|
|
11313
|
-
return value;
|
|
11314
|
-
}
|
|
11315
|
-
set(key, value) {
|
|
11316
|
-
if (this.map.has(key)) {
|
|
11317
|
-
this.map.delete(key);
|
|
11318
|
-
} else if (this.map.size >= this.maxSize) {
|
|
11319
|
-
this.evictOldest();
|
|
11320
|
-
}
|
|
11321
|
-
this.map.set(key, value);
|
|
11322
|
-
return this;
|
|
11323
|
-
}
|
|
11324
|
-
has(key) {
|
|
11325
|
-
return this.map.has(key);
|
|
11326
|
-
}
|
|
11327
|
-
delete(key) {
|
|
11328
|
-
return this.map.delete(key);
|
|
11329
|
-
}
|
|
11330
|
-
clear() {
|
|
11331
|
-
this.map.clear();
|
|
11332
|
-
}
|
|
11333
|
-
entries() {
|
|
11334
|
-
return this.map.entries();
|
|
11335
|
-
}
|
|
11336
|
-
keys() {
|
|
11337
|
-
return this.map.keys();
|
|
11338
|
-
}
|
|
11339
|
-
values() {
|
|
11340
|
-
return this.map.values();
|
|
11341
|
-
}
|
|
11342
|
-
forEach(callbackfn) {
|
|
11343
|
-
this.map.forEach((value, key) => callbackfn(value, key, this));
|
|
11344
|
-
}
|
|
11345
|
-
[Symbol.iterator]() {
|
|
11346
|
-
return this.map[Symbol.iterator]();
|
|
11347
|
-
}
|
|
11348
|
-
evictOldest() {
|
|
11349
|
-
const oldestKey = this.map.keys().next().value;
|
|
11350
|
-
if (oldestKey === undefined)
|
|
11351
|
-
return;
|
|
11352
|
-
const oldestValue = this.map.get(oldestKey);
|
|
11353
|
-
if (oldestValue === undefined)
|
|
11354
|
-
return;
|
|
11355
|
-
this.map.delete(oldestKey);
|
|
11356
|
-
this.onEvict?.(oldestKey, oldestValue);
|
|
11357
|
-
}
|
|
11358
|
-
}
|
|
11359
|
-
|
|
11360
11320
|
// src/telemetry/index.ts
|
|
11361
11321
|
init_env();
|
|
11362
11322
|
import { join as join2 } from "node:path";
|
|
@@ -21340,8 +21300,10 @@ data: ${JSON.stringify(lastError)}
|
|
|
21340
21300
|
}
|
|
21341
21301
|
const profile = resolveProfile(finalConfig.profiles, finalConfig.defaultProfile, options.forcedProfileId || c.req.header("x-meridian-profile") || undefined, routingMode === "sticky" ? { routingMode, stickySessionKey: adapter.getSessionId(c, body) } : undefined);
|
|
21342
21302
|
const authStatus = await getClaudeAuthStatusAsync(profile.id !== "default" ? profile.id : undefined, Object.keys(profile.env).length > 0 ? profile.env : undefined);
|
|
21343
|
-
const agentMode = c.req.header("x-opencode-agent-mode") ?? null;
|
|
21344
21303
|
const requestSource = c.req.header("x-meridian-source")?.slice(0, 64) || undefined;
|
|
21304
|
+
const declaredAgentMode = adapter.getAgentMode?.(c, body) ?? c.req.header("x-opencode-agent-mode") ?? null;
|
|
21305
|
+
const isSubagentRequest = declaredAgentMode === "subagent" || requestSource?.startsWith("subagent-") === true;
|
|
21306
|
+
const agentMode = isSubagentRequest ? "subagent" : declaredAgentMode;
|
|
21345
21307
|
const requestedModel = typeof body.model === "string" ? body.model : "sonnet";
|
|
21346
21308
|
let model = mapModelToClaudeModel(requestedModel, authStatus?.subscriptionType, agentMode);
|
|
21347
21309
|
const envOverrides = explicitModelPin(requestedModel);
|
|
@@ -21426,6 +21388,20 @@ data: ${JSON.stringify(lastError)}
|
|
|
21426
21388
|
const taskBudget = Number.isFinite(parsedBudget) ? { total: parsedBudget } : body.task_budget ? { total: body.task_budget.total ?? body.task_budget } : undefined;
|
|
21427
21389
|
const betas = betaFilter.forwarded;
|
|
21428
21390
|
const agentSessionId = adapter.getSessionId(c, body);
|
|
21391
|
+
const pluginlessWarning = notePluginlessOpenCodeRequest({
|
|
21392
|
+
userAgent: c.req.header("user-agent"),
|
|
21393
|
+
agentModeHeader: c.req.header("x-opencode-agent-mode"),
|
|
21394
|
+
sessionId: agentSessionId
|
|
21395
|
+
});
|
|
21396
|
+
if (pluginlessWarning) {
|
|
21397
|
+
plog(`[PROXY] ${requestMeta.requestId} ${pluginlessWarning}`);
|
|
21398
|
+
diagnosticLog2.log({
|
|
21399
|
+
level: "warn",
|
|
21400
|
+
category: "session",
|
|
21401
|
+
message: `${requestMeta.requestId} ${pluginlessWarning}`,
|
|
21402
|
+
requestId: requestMeta.requestId
|
|
21403
|
+
});
|
|
21404
|
+
}
|
|
21429
21405
|
const profileSessionId = profile.id !== "default" && agentSessionId ? `${profile.id}:${agentSessionId}` : agentSessionId;
|
|
21430
21406
|
const commitSessionTurn = () => {
|
|
21431
21407
|
if (profileSessionId)
|
|
@@ -21435,12 +21411,12 @@ data: ${JSON.stringify(lastError)}
|
|
|
21435
21411
|
const lastMessage = Array.isArray(body.messages) ? body.messages[body.messages.length - 1] : undefined;
|
|
21436
21412
|
const lastIsToolResult = Array.isArray(lastMessage?.content) && lastMessage.content.some((b) => b?.type === "tool_result");
|
|
21437
21413
|
const isClientDrivenLoop = adapterBase !== "claude-code" && !agentSessionId && lastIsToolResult;
|
|
21438
|
-
const isIndependentSession = !agentSessionId && (requestSource?.startsWith("fork-") ||
|
|
21414
|
+
const isIndependentSession = !agentSessionId && (requestSource?.startsWith("fork-") || isSubagentRequest) || isClientDrivenLoop || false;
|
|
21439
21415
|
let lineageResult = isIndependentSession ? { type: "diverged", reason: "independent-request" } : lookupSession(profileSessionId, body.messages || [], profileScopedCwd);
|
|
21440
21416
|
if (lineageResult.type === "undo" && adapterBase === "opencode" && !agentSessionId) {
|
|
21441
21417
|
lineageResult = { type: "diverged", reason: "missing-session-header" };
|
|
21442
21418
|
}
|
|
21443
|
-
const declaresConcurrentFlow = requestSource?.startsWith("fork-") === true ||
|
|
21419
|
+
const declaresConcurrentFlow = requestSource?.startsWith("fork-") === true || isSubagentRequest;
|
|
21444
21420
|
if (profileSessionId && !declaresConcurrentFlow && requestMeta.sessionTurnLease?.advancedWhileWaiting(profileSessionId) && lineageResult.type !== "continuation" && lineageResult.type !== "compaction") {
|
|
21445
21421
|
const reason = lineageResult.type === "diverged" ? lineageResult.reason : lineageResult.type;
|
|
21446
21422
|
const message = "This session advanced while the request was waiting. Retry with the latest conversation history or use a distinct session ID.";
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startProxyServer
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-wxk8xvd3.js";
|
|
5
5
|
import"./cli-m0p2bc8v.js";
|
|
6
6
|
import"./cli-sry5aqdj.js";
|
|
7
7
|
import"./cli-xmweegb1.js";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
resolveClaudeExecutableAsync
|
|
10
10
|
} from "./cli-d45dq9gf.js";
|
|
11
11
|
import"./cli-vj9cv18n.js";
|
|
12
|
-
import"./cli-
|
|
12
|
+
import"./cli-pc0mtjjv.js";
|
|
13
13
|
import"./cli-khhjyk04.js";
|
|
14
14
|
import {
|
|
15
15
|
__require
|
|
@@ -80,7 +80,7 @@ if (args[0] === "profile") {
|
|
|
80
80
|
process.exit(0);
|
|
81
81
|
}
|
|
82
82
|
if (args[0] === "setup") {
|
|
83
|
-
const { findPluginPath, runSetup, UnparseableConfigError } = await import("./setup-
|
|
83
|
+
const { findPluginPath, runSetup, UnparseableConfigError } = await import("./setup-0x573t61.js");
|
|
84
84
|
const pluginPath = findPluginPath(import.meta.url);
|
|
85
85
|
let result;
|
|
86
86
|
try {
|
|
@@ -146,7 +146,7 @@ async function runCli(start = startProxyServer, runAuthCheck = async () => {
|
|
|
146
146
|
return execFile(claudePath, ["auth", "status"], { timeout: 5000 });
|
|
147
147
|
}) {
|
|
148
148
|
try {
|
|
149
|
-
const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-
|
|
149
|
+
const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-0x573t61.js");
|
|
150
150
|
const configPath = findOpencodeConfigPath();
|
|
151
151
|
const { existsSync } = await import("fs");
|
|
152
152
|
if (existsSync(configPath) && !checkPluginConfigured(configPath)) {
|
package/dist/proxy/adapter.d.ts
CHANGED
|
@@ -19,6 +19,11 @@ export interface AgentIdentity {
|
|
|
19
19
|
* Returns undefined if the agent doesn't provide session tracking.
|
|
20
20
|
*/
|
|
21
21
|
getSessionId(c: Context, body?: unknown): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Optional client-declared agent mode. Adapters own their header/protocol
|
|
24
|
+
* details; the proxy uses the normalized value for model-tier selection.
|
|
25
|
+
*/
|
|
26
|
+
getAgentMode?(c: Context, body?: unknown): string | undefined;
|
|
22
27
|
/**
|
|
23
28
|
* Extract the SDK subprocess working directory from the request body.
|
|
24
29
|
*
|
|
@@ -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;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAEnE;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE5D;;;;;;;;;;;;;;;;OAgBG;IACH,uBAAuB,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAEtD;;;;;;;;;;;OAWG;IACH,6BAA6B,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAE7D;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAA;IAEtC;;;OAGG;IACH,gBAAgB,IAAI,MAAM,CAAA;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAa,SAAQ,aAAa;IACjD;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAE1B,6EAA6E;IAC7E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC,OAAO,eAAe,EAAE,eAAe,CAAC,CAAA;IAE5E,6EAA6E;IAC7E,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAEtC;;;OAGG;IACH,sBAAsB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE3C;;;;OAIG;IACH,yBAAyB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE9C;;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;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,SAAS,MAAM,EAAE,CAAA;IAEtC;;;;;;;;;;;;;;OAcG;IACH,iBAAiB,CAAC,IAAI,aAAa,EAAE,CAAA;IAErC;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,OAAO,CAAA;IAE5B;;;;;;OAMG;IACH,sBAAsB,CAAC,IAAI,OAAO,CAAA;IAElC;;;;;;;;OAQG;IACH,yBAAyB,CAAC,IAAI,OAAO,CAAA;IAErC;;;;;;;;;;;;;;;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;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAEnE;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE5D;;;OAGG;IACH,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE7D;;;;;;;;;;;;;;;;OAgBG;IACH,uBAAuB,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAEtD;;;;;;;;;;;OAWG;IACH,6BAA6B,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAE7D;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAA;IAEtC;;;OAGG;IACH,gBAAgB,IAAI,MAAM,CAAA;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAa,SAAQ,aAAa;IACjD;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAE1B,6EAA6E;IAC7E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC,OAAO,eAAe,EAAE,eAAe,CAAC,CAAA;IAE5E,6EAA6E;IAC7E,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAEtC;;;OAGG;IACH,sBAAsB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE3C;;;;OAIG;IACH,yBAAyB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE9C;;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;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,SAAS,MAAM,EAAE,CAAA;IAEtC;;;;;;;;;;;;;;OAcG;IACH,iBAAiB,CAAC,IAAI,aAAa,EAAE,CAAA;IAErC;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,OAAO,CAAA;IAE5B;;;;;;OAMG;IACH,sBAAsB,CAAC,IAAI,OAAO,CAAA;IAElC;;;;;;;;OAQG;IACH,yBAAyB,CAAC,IAAI,OAAO,CAAA;IAErC;;;;;;;;;;;;;;;OAeG;IACH,6BAA6B,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,eAAe,EAAE,UAAU,EAAE,CAAA;CAC3G"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/opencode.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAS9C,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/opencode.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAS9C,eAAO,MAAM,eAAe,EAAE,YAoK7B,CAAA;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
/** Fallback agent name used when no fuzzy match is found */
|
|
14
14
|
export declare const FALLBACK_AGENT_NAME = "general";
|
|
15
15
|
/** SDK-compatible agent definition */
|
|
16
|
+
export type AgentModelTier = "sonnet" | "opus" | "haiku" | "fable" | "inherit";
|
|
16
17
|
export interface AgentDefinition {
|
|
17
18
|
description: string;
|
|
18
19
|
prompt: string;
|
|
19
|
-
model?:
|
|
20
|
+
model?: AgentModelTier;
|
|
20
21
|
tools?: string[];
|
|
21
22
|
disallowedTools?: string[];
|
|
22
23
|
}
|
|
@@ -32,24 +33,25 @@ export declare function parseAgentDescriptions(taskDescription: string): Map<str
|
|
|
32
33
|
/**
|
|
33
34
|
* Map an OpenCode model string to an SDK model tier.
|
|
34
35
|
*
|
|
35
|
-
*
|
|
36
|
-
* We map based on the model name pattern, defaulting to 'inherit'
|
|
36
|
+
* Agent definitions must use base model aliases rather than extended-context
|
|
37
|
+
* variants. We map based on the model name pattern, defaulting to 'inherit'
|
|
37
38
|
* for non-Anthropic models (they'll use the parent session's model).
|
|
38
39
|
*/
|
|
39
|
-
export declare function mapModelTier(model?: string):
|
|
40
|
+
export declare function mapModelTier(model?: string): AgentModelTier;
|
|
40
41
|
/**
|
|
41
42
|
* Build SDK AgentDefinition objects from the Task tool description.
|
|
42
43
|
*
|
|
43
44
|
* Each agent gets:
|
|
44
45
|
* - description: from the Task tool text (user-configured)
|
|
45
46
|
* - prompt: instructional prompt incorporating the description
|
|
46
|
-
* - model:
|
|
47
|
+
* - model: the caller-selected base SDK tier; unknown models inherit the parent
|
|
47
48
|
* - tools: undefined (inherit all tools from parent)
|
|
48
49
|
*
|
|
49
50
|
* @param taskDescription - The full Task tool description text from OpenCode
|
|
50
51
|
* @param mcpToolNames - Optional list of MCP tool names to make available to agents
|
|
52
|
+
* @param modelTier - Base SDK tier for native Task subagents
|
|
51
53
|
*/
|
|
52
|
-
export declare function buildAgentDefinitions(taskDescription: string, mcpToolNames?: string[]): Record<string, AgentDefinition>;
|
|
54
|
+
export declare function buildAgentDefinitions(taskDescription: string, mcpToolNames?: string[], modelTier?: AgentModelTier): Record<string, AgentDefinition>;
|
|
53
55
|
export declare function parseAgentNamesFromSchema(taskTool: unknown): string[];
|
|
54
|
-
export declare function buildAgentDefinitionsFromTool(taskTool: unknown, mcpToolNames?: string[]): Record<string, AgentDefinition>;
|
|
56
|
+
export declare function buildAgentDefinitionsFromTool(taskTool: unknown, mcpToolNames?: string[], modelTier?: AgentModelTier): Record<string, AgentDefinition>;
|
|
55
57
|
//# sourceMappingURL=agentDefs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentDefs.d.ts","sourceRoot":"","sources":["../../src/proxy/agentDefs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,YAAY,CAAA;AAc5C,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"agentDefs.d.ts","sourceRoot":"","sources":["../../src/proxy/agentDefs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,YAAY,CAAA;AAc5C,sCAAsC;AACtC,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;AAE9E,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,cAAc,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,eAAe,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAcnF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,cAAc,CAW3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,eAAe,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,MAAM,EAAE,EACvB,SAAS,GAAE,cAA0B,GACpC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAsBjC;AA6ED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,CAIrE;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,OAAO,EACjB,YAAY,CAAC,EAAE,MAAM,EAAE,EACvB,SAAS,GAAE,cAA0B,GACpC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAuBjC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAkBA,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;AAoDnG,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EAGpB,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAsC,MAAM,iBAAiB,CAAA;AAIzI,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AA0W7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAkBA,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;AAoDnG,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EAGpB,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAsC,MAAM,iBAAiB,CAAA;AAIzI,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AA0W7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CA0+JhF;AAWD,wBAAgB,gCAAgC,IAAI,IAAI,CAavD;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqHhG"}
|
package/dist/proxy/setup.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* - `meridian setup` — writes the plugin entry
|
|
7
7
|
* - `meridian` startup — warns if plugin is missing
|
|
8
8
|
* - `GET /health` — reports plugin status
|
|
9
|
+
* - every request — warns when an OpenCode client sends no plugin
|
|
10
|
+
* headers (see notePluginlessOpenCodeRequest)
|
|
9
11
|
*/
|
|
10
12
|
/**
|
|
11
13
|
* Thrown when an existing OpenCode config can't be parsed (even tolerantly).
|
|
@@ -32,6 +34,47 @@ export declare function findPluginPath(fromUrl: string): string;
|
|
|
32
34
|
* plugin is missing.
|
|
33
35
|
*/
|
|
34
36
|
export declare function checkPluginConfigured(configPath?: string): boolean;
|
|
37
|
+
/** Reset the warned-session memory. Used by tests. */
|
|
38
|
+
export declare function clearPluginlessWarnings(): void;
|
|
39
|
+
/**
|
|
40
|
+
* NOTE: OpenCode-specific. Warn when an OpenCode client reaches the proxy
|
|
41
|
+
* without the plugin's agent headers, once per session.
|
|
42
|
+
*
|
|
43
|
+
* This exists because the exposure it reports cannot be fixed from inside
|
|
44
|
+
* Meridian. OpenCode 1.18.11 sends `x-session-affinity` natively, so a
|
|
45
|
+
* plugin-less client is fully keyed and never reaches the fingerprint fallback
|
|
46
|
+
* — and its internal `title` / `summary` / `compaction` agents run under the
|
|
47
|
+
* SAME session id as the user's chat. One real key, two unrelated
|
|
48
|
+
* conversations. Live, both attempts of a plugin-less run returned HTTP 400
|
|
49
|
+
* `session_turn_conflict` on the user's first turn after an ~8s wait.
|
|
50
|
+
*
|
|
51
|
+
* The fix for that collision scopes the session key by agent, which it reads
|
|
52
|
+
* from the plugin's `x-opencode-agent-mode`. A client that sends none cannot be
|
|
53
|
+
* scoped, and inferring the agent from request shape was tried and reverted:
|
|
54
|
+
* "tool-less, one message" is equally the first turn of an ordinary tool-less
|
|
55
|
+
* chat, and keying that apart broke resume for it.
|
|
56
|
+
*
|
|
57
|
+
* So the remaining job is to stop the exposure being silent. The startup
|
|
58
|
+
* warning in `bin/cli.ts` does not cover it — that one is gated on an OpenCode
|
|
59
|
+
* config FILE existing, deliberately, so Meridian stays quiet for the many
|
|
60
|
+
* clients that are not OpenCode. Run the documented
|
|
61
|
+
* `ANTHROPIC_BASE_URL=… opencode` with no config file and nothing warns.
|
|
62
|
+
*
|
|
63
|
+
* Keyed on the `opencode/` User-Agent rather than the resolved adapter:
|
|
64
|
+
* `MERIDIAN_DEFAULT_AGENT` defaults to opencode, so unrelated clients land on
|
|
65
|
+
* that adapter, and telling a Pi user to configure an OpenCode plugin is worse
|
|
66
|
+
* than saying nothing. The User-Agent has no such ambiguity.
|
|
67
|
+
*
|
|
68
|
+
* Returns the message to log, or undefined when there is nothing to say.
|
|
69
|
+
* Stateful but I/O-free — the caller owns the logging.
|
|
70
|
+
*/
|
|
71
|
+
export declare function notePluginlessOpenCodeRequest(input: {
|
|
72
|
+
userAgent: string | undefined;
|
|
73
|
+
/** The plugin's `x-opencode-agent-mode` header, if it sent one. */
|
|
74
|
+
agentModeHeader: string | undefined;
|
|
75
|
+
/** Client session id — used only to warn once per conversation. */
|
|
76
|
+
sessionId: string | undefined;
|
|
77
|
+
}): string | undefined;
|
|
35
78
|
export interface SetupResult {
|
|
36
79
|
configPath: string;
|
|
37
80
|
pluginPath: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/proxy/setup.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/proxy/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aACnB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAI/C;AAoBD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAW/C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;AAkBD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAOlE;AAaD,sDAAsD;AACtD,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,mEAAmE;IACnE,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,mEAAmE;IACnE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,GAAG,MAAM,GAAG,SAAS,CAkBrB;AAMD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAsC7E"}
|
package/dist/server.js
CHANGED
|
@@ -11,13 +11,13 @@ import {
|
|
|
11
11
|
runObserveHook,
|
|
12
12
|
runTransformHook,
|
|
13
13
|
startProxyServer
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-wxk8xvd3.js";
|
|
15
15
|
import"./cli-m0p2bc8v.js";
|
|
16
16
|
import"./cli-sry5aqdj.js";
|
|
17
17
|
import"./cli-xmweegb1.js";
|
|
18
18
|
import"./cli-d45dq9gf.js";
|
|
19
19
|
import"./cli-vj9cv18n.js";
|
|
20
|
-
import"./cli-
|
|
20
|
+
import"./cli-pc0mtjjv.js";
|
|
21
21
|
import"./cli-khhjyk04.js";
|
|
22
22
|
import"./cli-p9swy5t3.js";
|
|
23
23
|
export {
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
UnparseableConfigError,
|
|
3
3
|
checkPluginConfigured,
|
|
4
|
+
clearPluginlessWarnings,
|
|
4
5
|
findOpencodeConfigPath,
|
|
5
6
|
findPluginPath,
|
|
7
|
+
notePluginlessOpenCodeRequest,
|
|
6
8
|
runSetup
|
|
7
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-pc0mtjjv.js";
|
|
8
10
|
import"./cli-p9swy5t3.js";
|
|
9
11
|
export {
|
|
10
12
|
runSetup,
|
|
13
|
+
notePluginlessOpenCodeRequest,
|
|
11
14
|
findPluginPath,
|
|
12
15
|
findOpencodeConfigPath,
|
|
16
|
+
clearPluginlessWarnings,
|
|
13
17
|
checkPluginConfigured,
|
|
14
18
|
UnparseableConfigError
|
|
15
19
|
};
|
package/package.json
CHANGED