@rynfar/meridian 1.68.0 → 1.69.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/dist/{cli-0zhb8ss4.js → cli-x1sv3bqf.js} +897 -504
- package/dist/{cli-sh8bzdwe.js → cli-zdbv40d5.js} +26 -7
- package/dist/cli.js +4 -4
- package/dist/meridian/index.js +252 -0
- package/dist/meridian/package.json +6 -0
- package/dist/proxy/adapter.d.ts +16 -0
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/claudecode.d.ts +23 -0
- package/dist/proxy/adapters/claudecode.d.ts.map +1 -1
- package/dist/proxy/adapters/passthrough.d.ts.map +1 -1
- package/dist/proxy/errors.d.ts +2 -0
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/openaiResponses.d.ts +106 -3
- package/dist/proxy/openaiResponses.d.ts.map +1 -1
- package/dist/proxy/passthroughEarlyStop.d.ts +3 -3
- package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
- package/dist/proxy/passthroughTools.d.ts +63 -2
- package/dist/proxy/passthroughTools.d.ts.map +1 -1
- package/dist/proxy/query.d.ts +3 -0
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/session/cache.d.ts +20 -3
- package/dist/proxy/session/cache.d.ts.map +1 -1
- package/dist/proxy/session/lineage.d.ts +56 -0
- package/dist/proxy/session/lineage.d.ts.map +1 -1
- package/dist/proxy/session/processIncarnation.d.ts +55 -0
- package/dist/proxy/session/processIncarnation.d.ts.map +1 -1
- package/dist/proxy/setup.d.ts +12 -2
- package/dist/proxy/setup.d.ts.map +1 -1
- package/dist/proxy/transforms/codex.d.ts +12 -0
- package/dist/proxy/transforms/codex.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/{setup-knvctar4.js → setup-b3ymd9z8.js} +3 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/plugin/meridian/index.js +1 -0
- package/plugin/meridian/package.json +6 -0
- package/plugin/meridian.ts +1 -1
|
@@ -720,6 +720,15 @@ class UnparseableConfigError extends Error {
|
|
|
720
720
|
}
|
|
721
721
|
}
|
|
722
722
|
|
|
723
|
+
class MissingV1PluginError extends Error {
|
|
724
|
+
expectedPath;
|
|
725
|
+
constructor(expectedPath) {
|
|
726
|
+
super(`OpenCode V1 plugin bundle not found at ${expectedPath}`);
|
|
727
|
+
this.expectedPath = expectedPath;
|
|
728
|
+
this.name = "MissingV1PluginError";
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
723
732
|
class MissingV2PluginError extends Error {
|
|
724
733
|
expectedPath;
|
|
725
734
|
constructor(expectedPath) {
|
|
@@ -771,14 +780,24 @@ function siblingOpencodeConfigPath(configPath) {
|
|
|
771
780
|
return;
|
|
772
781
|
}
|
|
773
782
|
function findPluginPath(fromUrl) {
|
|
774
|
-
const
|
|
775
|
-
|
|
783
|
+
const entryPath = fileURLToPath(fromUrl);
|
|
784
|
+
const dir = dirname2(entryPath);
|
|
785
|
+
if (entryPath.endsWith(".ts")) {
|
|
786
|
+
const sourcePlugin = join2(dir, "..", "plugin", "meridian");
|
|
787
|
+
if (hasPluginPackageEntry(sourcePlugin))
|
|
788
|
+
return sourcePlugin;
|
|
789
|
+
throw new MissingV1PluginError(sourcePlugin);
|
|
790
|
+
}
|
|
791
|
+
const bundledPlugin = join2(dir, "meridian");
|
|
792
|
+
if (hasPluginPackageEntry(bundledPlugin))
|
|
793
|
+
return bundledPlugin;
|
|
794
|
+
throw new MissingV1PluginError(bundledPlugin);
|
|
776
795
|
}
|
|
777
796
|
var SUPPORTED_OPENCODE_V2_VERSIONS = new Set([
|
|
778
797
|
"0.0.0-beta-18314",
|
|
779
798
|
"0.0.0-beta-18866"
|
|
780
799
|
]);
|
|
781
|
-
function
|
|
800
|
+
function hasPluginPackageEntry(path) {
|
|
782
801
|
try {
|
|
783
802
|
if (!statSync(join2(path, "index.js"), { throwIfNoEntry: false })?.isFile())
|
|
784
803
|
return false;
|
|
@@ -796,12 +815,12 @@ function findV2PluginPath(fromUrl) {
|
|
|
796
815
|
const dir = dirname2(entryPath);
|
|
797
816
|
if (entryPath.endsWith(".ts")) {
|
|
798
817
|
const sourcePlugin = join2(dir, "..", "plugin", "meridian-v2");
|
|
799
|
-
if (
|
|
818
|
+
if (hasPluginPackageEntry(sourcePlugin))
|
|
800
819
|
return sourcePlugin;
|
|
801
820
|
throw new MissingV2PluginError(sourcePlugin);
|
|
802
821
|
}
|
|
803
822
|
const bundledPlugin = join2(dir, "meridian-v2");
|
|
804
|
-
if (
|
|
823
|
+
if (hasPluginPackageEntry(bundledPlugin))
|
|
805
824
|
return bundledPlugin;
|
|
806
825
|
throw new MissingV2PluginError(bundledPlugin);
|
|
807
826
|
}
|
|
@@ -856,7 +875,7 @@ function isMeridianEntry(entry) {
|
|
|
856
875
|
const packageName = pluginEntryPackage(entry);
|
|
857
876
|
if (!packageName)
|
|
858
877
|
return false;
|
|
859
|
-
return STALE_PATTERNS.some((pattern) => packageName.includes(pattern)) || packageName.includes("meridian.ts") || packageName.includes("meridian-v2.") || packageName.endsWith("/meridian-v2") || packageName.includes("@rynfar/meridian");
|
|
878
|
+
return STALE_PATTERNS.some((pattern) => packageName.includes(pattern)) || packageName.includes("meridian.ts") || packageName.includes("meridian-v2.") || packageName.endsWith("/meridian-v2") || /[\\/]meridian$/.test(packageName) || packageName.includes("@rynfar/meridian");
|
|
860
879
|
}
|
|
861
880
|
function checkPluginConfigured(configPath, expectedPluginPath) {
|
|
862
881
|
const selectedPath = configPath ?? findOpencodeConfigPath();
|
|
@@ -952,4 +971,4 @@ function runSetup(pluginPath, configPath, generation = "v1") {
|
|
|
952
971
|
return { configPath: path, pluginPath, alreadyConfigured, removedStale, created: false };
|
|
953
972
|
}
|
|
954
973
|
|
|
955
|
-
export { LRUMap, PRIORITY_ATTESTATION_HEADER, verifyPriorityAttestation, init_priorityAttestation, UnparseableConfigError, MissingV2PluginError, DuplicateMeridianConfigError, findOpencodeConfigPath, findPluginPath, SUPPORTED_OPENCODE_V2_VERSIONS, findV2PluginPath, classifyOpenCodeVersion, detectOpenCodeGeneration, pluginPathForGeneration, checkPluginConfigured, clearPluginlessWarnings, notePluginlessOpenCodeRequest, runSetup };
|
|
974
|
+
export { LRUMap, PRIORITY_ATTESTATION_HEADER, verifyPriorityAttestation, init_priorityAttestation, UnparseableConfigError, MissingV1PluginError, MissingV2PluginError, DuplicateMeridianConfigError, findOpencodeConfigPath, findPluginPath, SUPPORTED_OPENCODE_V2_VERSIONS, findV2PluginPath, classifyOpenCodeVersion, detectOpenCodeGeneration, pluginPathForGeneration, checkPluginConfigured, clearPluginlessWarnings, notePluginlessOpenCodeRequest, runSetup };
|
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-x1sv3bqf.js";
|
|
5
5
|
import"./cli-5jxyma6z.js";
|
|
6
6
|
import"./cli-sry5aqdj.js";
|
|
7
7
|
import"./cli-8yp89fan.js";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./cli-9e5cxp89.js";
|
|
11
11
|
import"./cli-khhjyk04.js";
|
|
12
12
|
import"./cli-vj9cv18n.js";
|
|
13
|
-
import"./cli-
|
|
13
|
+
import"./cli-zdbv40d5.js";
|
|
14
14
|
import {
|
|
15
15
|
__require
|
|
16
16
|
} from "./cli-p9swy5t3.js";
|
|
@@ -93,7 +93,7 @@ if (args[0] === "setup") {
|
|
|
93
93
|
runSetup,
|
|
94
94
|
SUPPORTED_OPENCODE_V2_VERSIONS,
|
|
95
95
|
UnparseableConfigError
|
|
96
|
-
} = await import("./setup-
|
|
96
|
+
} = await import("./setup-b3ymd9z8.js");
|
|
97
97
|
const forceV1 = args.includes("--v1");
|
|
98
98
|
const forceV2 = args.includes("--v2");
|
|
99
99
|
if (forceV1 && forceV2) {
|
|
@@ -205,7 +205,7 @@ async function runCli(start = startProxyServer, runAuthCheck = async () => {
|
|
|
205
205
|
return execFile(claudePath, ["auth", "status"], { timeout: 5000 });
|
|
206
206
|
}) {
|
|
207
207
|
try {
|
|
208
|
-
const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-
|
|
208
|
+
const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-b3ymd9z8.js");
|
|
209
209
|
const configPath = findOpencodeConfigPath();
|
|
210
210
|
const { existsSync } = await import("fs");
|
|
211
211
|
if (existsSync(configPath) && !checkPluginConfigured(configPath)) {
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// plugin/priority-attestation.ts
|
|
2
|
+
import { createHash, createHmac } from "node:crypto";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
var PRIORITY_ATTESTATION_HEADER = "x-meridian-opencode-turn";
|
|
7
|
+
var PRIORITY_ATTESTATION_KEY_ENV = "MERIDIAN_OPENCODE_ATTESTATION_KEY";
|
|
8
|
+
var PRIORITY_ATTESTATION_KEY_FILE = "opencode-turn.key";
|
|
9
|
+
var TOKEN_PREFIX = "v1";
|
|
10
|
+
var MAC_DOMAIN = "meridian.opencode.turn.v1\x00";
|
|
11
|
+
var TURN_DOMAIN = "meridian.opencode.human.v1\x00";
|
|
12
|
+
var MAX_HEADER_BYTES = 768;
|
|
13
|
+
var MAX_PAYLOAD_BYTES = 384;
|
|
14
|
+
var TURN_DIGEST_PATTERN = /^[A-Za-z0-9_-]{43}$/;
|
|
15
|
+
var SAFE_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
16
|
+
function configDirectory() {
|
|
17
|
+
return process.env.MERIDIAN_CONFIG_DIR ?? join(homedir(), ".config", "meridian");
|
|
18
|
+
}
|
|
19
|
+
function priorityAttestationKeyPath() {
|
|
20
|
+
return join(configDirectory(), PRIORITY_ATTESTATION_KEY_FILE);
|
|
21
|
+
}
|
|
22
|
+
function isSafeAgentId(value) {
|
|
23
|
+
return value.length >= 1 && value.length <= 64 && value.trim() === value && /^[\x20-\x7E]+$/.test(value);
|
|
24
|
+
}
|
|
25
|
+
function decodeCanonicalBase64Url(raw) {
|
|
26
|
+
if (!/^[A-Za-z0-9_-]+$/.test(raw))
|
|
27
|
+
return;
|
|
28
|
+
const decoded = Buffer.from(raw, "base64url");
|
|
29
|
+
return decoded.toString("base64url") === raw ? decoded : undefined;
|
|
30
|
+
}
|
|
31
|
+
function decodePriorityAttestationKey(raw) {
|
|
32
|
+
if (raw === undefined)
|
|
33
|
+
return;
|
|
34
|
+
const normalized = raw.trim();
|
|
35
|
+
const decoded = decodeCanonicalBase64Url(normalized);
|
|
36
|
+
return decoded?.length === 32 ? decoded : undefined;
|
|
37
|
+
}
|
|
38
|
+
function loadPriorityAttestationKey() {
|
|
39
|
+
const fromEnv = process.env[PRIORITY_ATTESTATION_KEY_ENV];
|
|
40
|
+
if (fromEnv !== undefined)
|
|
41
|
+
return decodePriorityAttestationKey(fromEnv);
|
|
42
|
+
try {
|
|
43
|
+
return decodePriorityAttestationKey(readFileSync(priorityAttestationKeyPath(), "utf8"));
|
|
44
|
+
} catch {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function computePriorityTurnDigest(input) {
|
|
49
|
+
if (!SAFE_ID_PATTERN.test(input.sessionId) || !SAFE_ID_PATTERN.test(input.humanMessageId)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
return createHash("sha256").update(TURN_DOMAIN).update(input.generation).update("\x00").update(input.sessionId).update("\x00").update(input.humanMessageId).digest("base64url");
|
|
53
|
+
}
|
|
54
|
+
function createPriorityAttestation(input, key = loadPriorityAttestationKey() ?? Buffer.alloc(0)) {
|
|
55
|
+
if (key.length !== 32)
|
|
56
|
+
return;
|
|
57
|
+
if (!SAFE_ID_PATTERN.test(input.sessionId) || !isSafeAgentId(input.agentId))
|
|
58
|
+
return;
|
|
59
|
+
const turnDigest = computePriorityTurnDigest(input);
|
|
60
|
+
if (!turnDigest || !TURN_DIGEST_PATTERN.test(turnDigest))
|
|
61
|
+
return;
|
|
62
|
+
const issuedAt = input.issuedAt;
|
|
63
|
+
if (!Number.isSafeInteger(issuedAt) || issuedAt < 0)
|
|
64
|
+
return;
|
|
65
|
+
const payload = JSON.stringify({
|
|
66
|
+
v: 1,
|
|
67
|
+
g: input.generation,
|
|
68
|
+
s: input.sessionId,
|
|
69
|
+
a: input.agentId,
|
|
70
|
+
t: turnDigest,
|
|
71
|
+
iat: issuedAt
|
|
72
|
+
});
|
|
73
|
+
if (Buffer.byteLength(payload) > MAX_PAYLOAD_BYTES)
|
|
74
|
+
return;
|
|
75
|
+
const encodedPayload = Buffer.from(payload).toString("base64url");
|
|
76
|
+
const mac = createHmac("sha256", key).update(MAC_DOMAIN).update(payload).digest("base64url");
|
|
77
|
+
const token = `${TOKEN_PREFIX}.${encodedPayload}.${mac}`;
|
|
78
|
+
return Buffer.byteLength(token) <= MAX_HEADER_BYTES ? token : undefined;
|
|
79
|
+
}
|
|
80
|
+
function deleteHeader(headers, name) {
|
|
81
|
+
if (headers instanceof Headers) {
|
|
82
|
+
headers.delete(name);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const lower = name.toLowerCase();
|
|
86
|
+
for (const key of Object.keys(headers)) {
|
|
87
|
+
if (key.toLowerCase() === lower)
|
|
88
|
+
delete headers[key];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function getHeader(headers, name) {
|
|
92
|
+
if (headers instanceof Headers)
|
|
93
|
+
return headers.get(name) ?? undefined;
|
|
94
|
+
const lower = name.toLowerCase();
|
|
95
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
96
|
+
if (key.toLowerCase() === lower)
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
function setHeader(headers, name, value) {
|
|
102
|
+
deleteHeader(headers, name);
|
|
103
|
+
if (headers instanceof Headers)
|
|
104
|
+
headers.set(name, value);
|
|
105
|
+
else
|
|
106
|
+
headers[name] = value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// plugin/meridian.ts
|
|
110
|
+
var BUILTIN_AGENT_MODES = {
|
|
111
|
+
build: "primary",
|
|
112
|
+
plan: "primary",
|
|
113
|
+
general: "subagent",
|
|
114
|
+
explore: "subagent",
|
|
115
|
+
title: "subagent",
|
|
116
|
+
summary: "subagent",
|
|
117
|
+
compaction: "subagent"
|
|
118
|
+
};
|
|
119
|
+
var INTERNAL_AGENT_IDS = new Set(["title", "summary", "compaction"]);
|
|
120
|
+
var ROOT_SESSION_CACHE_MAX = 256;
|
|
121
|
+
var ROOT_SESSION_CACHE_TTL_MS = 5000;
|
|
122
|
+
var LOOKUP_TIMEOUT_MS = 250;
|
|
123
|
+
function isRecord(value) {
|
|
124
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
125
|
+
}
|
|
126
|
+
async function withTimeout(pending, timeoutMs) {
|
|
127
|
+
let timer;
|
|
128
|
+
const timedOut = new Promise((resolve) => {
|
|
129
|
+
timer = setTimeout(() => resolve(undefined), timeoutMs);
|
|
130
|
+
timer.unref?.();
|
|
131
|
+
});
|
|
132
|
+
try {
|
|
133
|
+
return await Promise.race([pending, timedOut]);
|
|
134
|
+
} finally {
|
|
135
|
+
if (timer)
|
|
136
|
+
clearTimeout(timer);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
var MeridianPlugin = async (pluginInput) => {
|
|
140
|
+
let configAgents = {};
|
|
141
|
+
const rootSessionCache = new Map;
|
|
142
|
+
const resolve = (agent) => {
|
|
143
|
+
if (typeof agent === "object" && agent !== null) {
|
|
144
|
+
return { name: agent.name ?? "unknown", mode: agent.mode ?? "primary" };
|
|
145
|
+
}
|
|
146
|
+
const name = String(agent);
|
|
147
|
+
return { name, mode: configAgents[name]?.mode ?? BUILTIN_AGENT_MODES[name] ?? "primary" };
|
|
148
|
+
};
|
|
149
|
+
const isStrictVisiblePrimary = (agent) => {
|
|
150
|
+
const name = typeof agent === "string" ? agent : agent.name;
|
|
151
|
+
if (!name || INTERNAL_AGENT_IDS.has(name))
|
|
152
|
+
return false;
|
|
153
|
+
if (typeof agent === "object") {
|
|
154
|
+
return agent.mode === "primary" && agent.hidden !== true;
|
|
155
|
+
}
|
|
156
|
+
const configured = configAgents[name];
|
|
157
|
+
if (configured)
|
|
158
|
+
return configured.mode === "primary" && configured.hidden !== true;
|
|
159
|
+
return BUILTIN_AGENT_MODES[name] === "primary";
|
|
160
|
+
};
|
|
161
|
+
const isRootSession = async (sessionID) => {
|
|
162
|
+
const cached = rootSessionCache.get(sessionID);
|
|
163
|
+
if (cached && cached.expiresAt > Date.now())
|
|
164
|
+
return cached.pending;
|
|
165
|
+
const pending = (async () => {
|
|
166
|
+
if (!isRecord(pluginInput) || !isRecord(pluginInput.client))
|
|
167
|
+
return false;
|
|
168
|
+
const sessionApi = pluginInput.client.session;
|
|
169
|
+
if (!isRecord(sessionApi) || typeof sessionApi.get !== "function")
|
|
170
|
+
return false;
|
|
171
|
+
const controller = new AbortController;
|
|
172
|
+
try {
|
|
173
|
+
const lookup = Promise.resolve(Reflect.apply(sessionApi.get, sessionApi, [
|
|
174
|
+
{ path: { id: sessionID }, signal: controller.signal }
|
|
175
|
+
]));
|
|
176
|
+
const result = await withTimeout(lookup, LOOKUP_TIMEOUT_MS);
|
|
177
|
+
if (!isRecord(result))
|
|
178
|
+
return false;
|
|
179
|
+
const data = isRecord(result.data) ? result.data : result;
|
|
180
|
+
return data.id === sessionID && data.parentID === undefined && data.fork === undefined;
|
|
181
|
+
} catch {
|
|
182
|
+
return false;
|
|
183
|
+
} finally {
|
|
184
|
+
controller.abort();
|
|
185
|
+
}
|
|
186
|
+
})();
|
|
187
|
+
rootSessionCache.delete(sessionID);
|
|
188
|
+
rootSessionCache.set(sessionID, { expiresAt: Date.now() + ROOT_SESSION_CACHE_TTL_MS, pending });
|
|
189
|
+
while (rootSessionCache.size > ROOT_SESSION_CACHE_MAX) {
|
|
190
|
+
const oldest = rootSessionCache.keys().next().value;
|
|
191
|
+
if (oldest === undefined)
|
|
192
|
+
break;
|
|
193
|
+
rootSessionCache.delete(oldest);
|
|
194
|
+
}
|
|
195
|
+
const eligible = await pending;
|
|
196
|
+
if (!eligible && rootSessionCache.get(sessionID)?.pending === pending)
|
|
197
|
+
rootSessionCache.delete(sessionID);
|
|
198
|
+
return eligible;
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
config: (cfg) => {
|
|
202
|
+
const next = {};
|
|
203
|
+
for (const [name, def] of Object.entries(cfg?.agent ?? {})) {
|
|
204
|
+
if (!def)
|
|
205
|
+
continue;
|
|
206
|
+
next[name] = {
|
|
207
|
+
...typeof def.mode === "string" ? { mode: def.mode } : {},
|
|
208
|
+
...typeof def.hidden === "boolean" ? { hidden: def.hidden } : {}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
configAgents = next;
|
|
212
|
+
},
|
|
213
|
+
"chat.headers": async (incoming, output) => {
|
|
214
|
+
deleteHeader(output.headers, PRIORITY_ATTESTATION_HEADER);
|
|
215
|
+
if (incoming.model.providerID !== "anthropic")
|
|
216
|
+
return;
|
|
217
|
+
setHeader(output.headers, "x-opencode-session", incoming.sessionID);
|
|
218
|
+
setHeader(output.headers, "x-opencode-request", incoming.message.id);
|
|
219
|
+
const { name, mode } = resolve(incoming.agent);
|
|
220
|
+
const safeName = name.replace(/[^\x20-\x7E]/g, "").trim() || "unknown";
|
|
221
|
+
setHeader(output.headers, "x-opencode-agent-mode", mode === "subagent" ? "subagent" : "primary");
|
|
222
|
+
setHeader(output.headers, "x-opencode-agent-name", safeName);
|
|
223
|
+
if (getHeader(output.headers, "x-meridian-profile") !== undefined)
|
|
224
|
+
return;
|
|
225
|
+
if (safeName !== name || !isStrictVisiblePrimary(incoming.agent))
|
|
226
|
+
return;
|
|
227
|
+
const createdAt = incoming.message.time?.created;
|
|
228
|
+
if (typeof createdAt !== "number" || !Number.isSafeInteger(createdAt) || createdAt < 0)
|
|
229
|
+
return;
|
|
230
|
+
const issuedAt = Math.floor(createdAt / 1000);
|
|
231
|
+
if (incoming.message.sessionID !== undefined && incoming.message.sessionID !== incoming.sessionID)
|
|
232
|
+
return;
|
|
233
|
+
if (!await isRootSession(incoming.sessionID))
|
|
234
|
+
return;
|
|
235
|
+
if (!isStrictVisiblePrimary(incoming.agent))
|
|
236
|
+
return;
|
|
237
|
+
const token = createPriorityAttestation({
|
|
238
|
+
generation: "oc1",
|
|
239
|
+
sessionId: incoming.sessionID,
|
|
240
|
+
agentId: safeName,
|
|
241
|
+
humanMessageId: incoming.message.id,
|
|
242
|
+
issuedAt
|
|
243
|
+
});
|
|
244
|
+
if (token)
|
|
245
|
+
setHeader(output.headers, PRIORITY_ATTESTATION_HEADER, token);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
};
|
|
249
|
+
var meridian_default = MeridianPlugin;
|
|
250
|
+
export {
|
|
251
|
+
meridian_default as default
|
|
252
|
+
};
|
package/dist/proxy/adapter.d.ts
CHANGED
|
@@ -127,6 +127,22 @@ export interface AgentIdentity {
|
|
|
127
127
|
* Tools are registered as `mcp__{name}__{tool}`.
|
|
128
128
|
*/
|
|
129
129
|
getMcpServerName(): string;
|
|
130
|
+
/**
|
|
131
|
+
* The namespace the CLIENT'S tools are nested under in passthrough mode,
|
|
132
|
+
* where they appear to the model as `mcp__{name}__{tool}`.
|
|
133
|
+
*
|
|
134
|
+
* Deliberately NOT `getMcpServerName()`, which names the server Meridian
|
|
135
|
+
* registers in INTERNAL mode. Reusing that would rename every OpenCode
|
|
136
|
+
* client tool from `mcp__oc__read` to `mcp__opencode__read`, moving the
|
|
137
|
+
* model-visible prompt — and so the prompt cache — for the entire existing
|
|
138
|
+
* user base, and colliding with the `mcp__opencode__*` names
|
|
139
|
+
* `passthroughEarlyStop` excludes precisely because they are internal.
|
|
140
|
+
*
|
|
141
|
+
* Defaults to `oc` when unset, which is what every adapter used before this
|
|
142
|
+
* existed. Override it only where the default actively misleads: `oc` reads
|
|
143
|
+
* as "opencode" to a model on an adapter that is not OpenCode (#893).
|
|
144
|
+
*/
|
|
145
|
+
getPassthroughMcpName?(): string;
|
|
130
146
|
}
|
|
131
147
|
/**
|
|
132
148
|
* An agent adapter provides agent-specific configuration to the proxy.
|
|
@@ -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,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,aAAa,GAAG,wBAAwB,CAAA;CAC9D,CAAC,CAAA;AAEF;;;;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;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAEnE;;;OAGG;IACH,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE7D;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,gCAAgC,CAAC,EAAE,OAAO,CAAA;IAEnD;;;;;;OAMG;IACH,sBAAsB,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,mBAAmB,GAAG,SAAS,CAAA;IAEpF;;;;;;;;;;;;;;;;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;;;;;OAKG;IACH,QAAQ,CAAC,mCAAmC,CAAC,EAAE,OAAO,CAAA;IAEtD;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAA;IAEtC;;;;;OAKG;IACH,8BAA8B,CAAC,CAC7B,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,GAClD,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAE5C;;;OAGG;IACH,gBAAgB,IAAI,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/proxy/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* - Parses the client's local CWD via extractClientWorkingDirectory for
|
|
17
17
|
* fingerprinting and a system-prompt hint (see server.ts + query.ts).
|
|
18
18
|
*/
|
|
19
|
+
import type { Context } from "hono";
|
|
19
20
|
import type { AgentAdapter } from "../adapter";
|
|
20
21
|
/**
|
|
21
22
|
* Session identity declared in `metadata.user_id`.
|
|
@@ -48,5 +49,27 @@ export declare function extractClaudeCodeSessionIdentity(body: unknown): ClaudeC
|
|
|
48
49
|
export declare function extractClaudeCodeSessionId(body: unknown): string | undefined;
|
|
49
50
|
/** Extract the immediate parent session key, when the client declares lineage. */
|
|
50
51
|
export declare function extractClaudeCodeParentSessionId(body: unknown): string | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Is this request from the Claude Code CLI, whatever adapter is handling it?
|
|
54
|
+
*
|
|
55
|
+
* Claude Code sends `x-claude-code-session-id` on every request — verified
|
|
56
|
+
* against 2.1.266 that it is the CLI session UUID, pinned exactly by
|
|
57
|
+
* `--session-id`. No other client sends it, so it identifies the client even
|
|
58
|
+
* when a gateway has rewritten the User-Agent and the LiteLLM heuristic has
|
|
59
|
+
* already claimed the request.
|
|
60
|
+
*
|
|
61
|
+
* This answers "who owns the tool loop", not "which adapter should run". The
|
|
62
|
+
* header is deliberately NOT used for adapter selection: routing gateway
|
|
63
|
+
* traffic to the claude-code adapter would swap tool handling, MCP naming and
|
|
64
|
+
* prompt shape for every existing LiteLLM user and move their cache prefix.
|
|
65
|
+
*
|
|
66
|
+
* It is also NOT a session key. The CLI reuses one session id across the
|
|
67
|
+
* auxiliary requests it makes alongside a conversation, so keying on it puts
|
|
68
|
+
* two unrelated histories under one key — measured live as
|
|
69
|
+
* `unrelated-history` and an HTTP 400 concurrent conflict, i.e. a hard failure
|
|
70
|
+
* where there had only been a silent inefficiency. See
|
|
71
|
+
* `scripts/e2e-passthrough-claude-code-session.mjs`, which guards that.
|
|
72
|
+
*/
|
|
73
|
+
export declare function isClaudeCodeClient(c: Context): boolean;
|
|
51
74
|
export declare const claudeCodeAdapter: AgentAdapter;
|
|
52
75
|
//# sourceMappingURL=claudecode.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudecode.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/claudecode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"claudecode.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/claudecode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAiC9C;;;;;;;GAOG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAED;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,OAAO,GAAG,yBAAyB,GAAG,SAAS,CA+BrG;AAED,sFAAsF;AACtF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE5E;AAED,kFAAkF;AAClF,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAElF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED,eAAO,MAAM,iBAAiB,EAAE,YAqG/B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passthrough.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/passthrough.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAiD9C,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"passthrough.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/passthrough.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAiD9C,eAAO,MAAM,kBAAkB,EAAE,YAuFhC,CAAA;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
|
package/dist/proxy/errors.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export interface ClassifiedError {
|
|
|
25
25
|
* - The tier is unrecognized, where the global switch is the only safe advice.
|
|
26
26
|
*/
|
|
27
27
|
export declare function extendedContextHint(model?: string): string;
|
|
28
|
+
/** True when a turn failed only because it hit the client's output cap. */
|
|
29
|
+
export declare function isOutputTokenCapExceeded(message: string | undefined | null): boolean;
|
|
28
30
|
/**
|
|
29
31
|
* Detect specific SDK errors and return helpful messages to the client.
|
|
30
32
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/proxy/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAc1D;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/proxy/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAc1D;AAuID,2EAA2E;AAC3E,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAEpF;AAqFD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe,CA2K7E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAM3D;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,aAAa,GAAG,iBAAiB,CAAA;AAEtE;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAahG;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAI3E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGxD;AAuBD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,IAAI,MAAM,CAEhG;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGjE;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,GAAG,cAAc,GAAG,SAAS,GAAG,eAAe,GAAG,kBAAkB,GAAG,SAAS,CAAA;IACnG,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;wCAEoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAuBD;;;;;;GAMG;AACH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;IAChC,WAAW,EAAE,OAAO,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,WAAW,EAAE,OAAO,CAAA;CACrB,GAAG,OAAO,CAYV;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAiEpE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,EAAE,cAAc,EACjB,GAAG,EAAE;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GACA,MAAM,CAYR"}
|
|
@@ -33,25 +33,54 @@ interface ResponsesMessageItem {
|
|
|
33
33
|
interface ResponsesFunctionCallItem {
|
|
34
34
|
type: "function_call";
|
|
35
35
|
name: string;
|
|
36
|
+
/** Set when the tool lives in a `namespace` tool entry (an MCP server). */
|
|
37
|
+
namespace?: string;
|
|
36
38
|
arguments: string;
|
|
37
39
|
call_id: string;
|
|
38
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* `function_call_output.output` is a plain string for shell-style tools and an
|
|
43
|
+
* array of content items for MCP tools (Codex's FunctionCallOutputBody is an
|
|
44
|
+
* untagged Text | ContentItems); custom tool outputs are always strings.
|
|
45
|
+
*/
|
|
46
|
+
interface ResponsesOutputContentItem {
|
|
47
|
+
type: "input_text" | "input_image" | "input_audio" | "encrypted_content" | string;
|
|
48
|
+
text?: string;
|
|
49
|
+
image_url?: string;
|
|
50
|
+
}
|
|
39
51
|
interface ResponsesFunctionCallOutputItem {
|
|
40
52
|
type: "function_call_output";
|
|
41
53
|
call_id: string;
|
|
54
|
+
output: string | ResponsesOutputContentItem[];
|
|
55
|
+
}
|
|
56
|
+
/** A freeform (`type:"custom"`) tool call — Codex's `apply_patch`. */
|
|
57
|
+
interface ResponsesCustomToolCallItem {
|
|
58
|
+
type: "custom_tool_call";
|
|
59
|
+
name: string;
|
|
60
|
+
namespace?: string;
|
|
61
|
+
input: string;
|
|
62
|
+
call_id: string;
|
|
63
|
+
}
|
|
64
|
+
interface ResponsesCustomToolCallOutputItem {
|
|
65
|
+
type: "custom_tool_call_output";
|
|
66
|
+
call_id: string;
|
|
42
67
|
output: string;
|
|
43
68
|
}
|
|
44
69
|
interface ResponsesReasoningItem {
|
|
45
70
|
type: "reasoning";
|
|
46
71
|
[k: string]: unknown;
|
|
47
72
|
}
|
|
48
|
-
type ResponsesInputItem = ResponsesMessageItem | ResponsesFunctionCallItem | ResponsesFunctionCallOutputItem | ResponsesReasoningItem;
|
|
49
|
-
interface ResponsesTool {
|
|
50
|
-
type: "function" | string;
|
|
73
|
+
type ResponsesInputItem = ResponsesMessageItem | ResponsesFunctionCallItem | ResponsesFunctionCallOutputItem | ResponsesCustomToolCallItem | ResponsesCustomToolCallOutputItem | ResponsesReasoningItem;
|
|
74
|
+
export interface ResponsesTool {
|
|
75
|
+
type: "function" | "custom" | "namespace" | string;
|
|
51
76
|
name: string;
|
|
52
77
|
description?: string;
|
|
53
78
|
strict?: boolean;
|
|
54
79
|
parameters?: unknown;
|
|
80
|
+
/** `custom` tools: the freeform grammar Codex expects the input to follow. */
|
|
81
|
+
format?: unknown;
|
|
82
|
+
/** `namespace` tools: the nested function/custom tools of one MCP server. */
|
|
83
|
+
tools?: ResponsesTool[];
|
|
55
84
|
}
|
|
56
85
|
export interface ResponsesRequest {
|
|
57
86
|
model?: string;
|
|
@@ -69,6 +98,75 @@ export interface ResponsesRequest {
|
|
|
69
98
|
stream?: boolean;
|
|
70
99
|
[k: string]: unknown;
|
|
71
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Codex (0.15x) ships every MCP server as one `{type:"namespace", name,
|
|
103
|
+
* tools:[…]}` entry with the tool definitions nested inside, and its freeform
|
|
104
|
+
* `apply_patch` as `{type:"custom"}`. Claude sees one flat list of function
|
|
105
|
+
* tools, so each nested or custom tool is exposed under an alias, and the alias
|
|
106
|
+
* table maps Claude's call back onto the exact `{namespace, name}` pair Codex's
|
|
107
|
+
* router resolves (`ToolName::new(namespace, name)` — a flattened name without
|
|
108
|
+
* `namespace` never matches a namespaced tool).
|
|
109
|
+
*/
|
|
110
|
+
export interface ResponsesToolAlias {
|
|
111
|
+
namespace?: string;
|
|
112
|
+
name: string;
|
|
113
|
+
kind: "function" | "custom";
|
|
114
|
+
}
|
|
115
|
+
export type ResponsesToolAliases = Map<string, ResponsesToolAlias>;
|
|
116
|
+
export declare const RESPONSES_TOOL_ALIAS_MAX: number;
|
|
117
|
+
/**
|
|
118
|
+
* The Claude-visible name of a tool. Deterministic on (namespace, name): the
|
|
119
|
+
* history Codex replays next turn carries the same pair and must land on the
|
|
120
|
+
* same alias, or the replayed `tool_use` names no longer match the tool set.
|
|
121
|
+
*/
|
|
122
|
+
export declare function responsesToolAlias(namespace: string | undefined, name: string): string;
|
|
123
|
+
/**
|
|
124
|
+
* Alias table for a request's tools. Pure and deterministic, so the route can
|
|
125
|
+
* rebuild it for the response side without threading state through the
|
|
126
|
+
* request translator. Top-level function tools keep their own names and are
|
|
127
|
+
* not listed.
|
|
128
|
+
*/
|
|
129
|
+
export declare function buildResponsesToolAliases(tools: ResponsesTool[] | undefined): ResponsesToolAliases;
|
|
130
|
+
/** What one Codex turn says about the conversation it belongs to. */
|
|
131
|
+
export interface CodexThreadIdentity {
|
|
132
|
+
/** Conversation key for session resume — the codex adapter's `x-codex-session`. */
|
|
133
|
+
sessionKey?: string;
|
|
134
|
+
/** Concurrency declaration for a turn that is not the thread the user drives. */
|
|
135
|
+
requestSource?: string;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Reads the conversation identity Codex attaches to a turn.
|
|
139
|
+
*
|
|
140
|
+
* `prompt_cache_key` was the only identity this route had (#655), and for the
|
|
141
|
+
* thread a user drives it is exactly that thread's id. A subagent is the case
|
|
142
|
+
* it cannot describe: Codex Desktop spawns one as its own thread, with its own
|
|
143
|
+
* instructions and its own tools, and hands it the *parent's*
|
|
144
|
+
* `prompt_cache_key`. Keyed on that alone two live conversations become one
|
|
145
|
+
* session — the subagent's first turn rebinds the key to its own SDK session,
|
|
146
|
+
* and the parent's next turn then reads as a rewrite of it: refused as a
|
|
147
|
+
* concurrent conflict when it loses the session-turn race, replayed from
|
|
148
|
+
* scratch when it wins.
|
|
149
|
+
*
|
|
150
|
+
* `x-codex-turn-metadata` names the thread itself, so the thread id is the
|
|
151
|
+
* honest key: identical to `prompt_cache_key` for a user thread — this
|
|
152
|
+
* re-anchors no existing session — and distinct for every spawned one.
|
|
153
|
+
* `thread_source` carries the same fact independently, so a turn from a
|
|
154
|
+
* spawned thread also declares a concurrent flow and is admitted rather than
|
|
155
|
+
* refused should a client ever reuse one id across flows. `fork-` and not
|
|
156
|
+
* `subagent-`: the tier a Codex subagent runs on is the client's choice, and
|
|
157
|
+
* a concurrency declaration must not silently rewrite it.
|
|
158
|
+
*
|
|
159
|
+
* `request_kind` is the third signal. Codex runs side requests against the
|
|
160
|
+
* same thread id — `compact` carries the whole history with no tools to
|
|
161
|
+
* summarise it, and the binary also names `title`, `summary`, `review`,
|
|
162
|
+
* `memory` — and none of them is the conversation: keyed on the thread alone
|
|
163
|
+
* a compaction lands on the conversation's session as a rewrite of it.
|
|
164
|
+
* Observed live: a 379-message `compact` under a live thread's key. Any kind
|
|
165
|
+
* other than `turn` therefore gets its own key beside the thread's and
|
|
166
|
+
* declares its own flow; a kind Codex has not sent yet is handled the same
|
|
167
|
+
* way, since the property that matters — not being the turn — is shared.
|
|
168
|
+
*/
|
|
169
|
+
export declare function resolveCodexThreadIdentity(body: ResponsesRequest, metadataHeader?: string): CodexThreadIdentity;
|
|
72
170
|
/**
|
|
73
171
|
* Translate a Responses request to an Anthropic /v1/messages body.
|
|
74
172
|
* Returns null when `input` is missing (invalid request).
|
|
@@ -86,6 +184,11 @@ export interface ResponsesCtx {
|
|
|
86
184
|
* satisfy its state machine. Set from `reasoningRequested(body)`.
|
|
87
185
|
*/
|
|
88
186
|
reasoningRequested?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Alias table from `buildResponsesToolAliases(request.tools)`: maps Claude's
|
|
189
|
+
* tool_use names back onto Codex's `{namespace, name}` and custom tools.
|
|
190
|
+
*/
|
|
191
|
+
toolAliases?: ResponsesToolAliases;
|
|
89
192
|
}
|
|
90
193
|
/** Did the Responses request ask for reasoning output? */
|
|
91
194
|
export declare function reasoningRequested(body: ResponsesRequest): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openaiResponses.d.ts","sourceRoot":"","sources":["../../src/proxy/openaiResponses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EACV,oBAAoB,EAIpB,cAAc,EACf,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"openaiResponses.d.ts","sourceRoot":"","sources":["../../src/proxy/openaiResponses.ts"],"names":[],"mappings":"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"}
|