@bitkyc08/opencodex 2.1.5 → 2.1.7
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.ko.md +1 -0
- package/README.md +23 -0
- package/README.zh-CN.md +1 -0
- package/gui/dist/assets/{index-DB2i6w5f.js → index-BVahEsvB.js} +1 -1
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic.ts +27 -9
- package/src/cli.ts +82 -0
- package/src/codex-catalog.ts +32 -9
- package/src/codex-history-provider.ts +228 -21
- package/src/codex-inject.ts +28 -6
- package/src/oauth/index.ts +3 -0
- package/src/oauth/key-providers.ts +32 -3
- package/src/oauth/login-cli.ts +37 -9
- package/src/providers/derive.ts +12 -0
- package/src/providers/registry.ts +68 -1
- package/src/types.ts +15 -0
package/src/oauth/index.ts
CHANGED
|
@@ -129,6 +129,9 @@ function cloneProviderField(value: unknown): unknown {
|
|
|
129
129
|
|
|
130
130
|
const OAUTH_RECONCILE_FIELDS: (keyof OcxProviderConfig)[] = [
|
|
131
131
|
"models",
|
|
132
|
+
"contextWindow",
|
|
133
|
+
"modelContextWindows",
|
|
134
|
+
"modelInputModalities",
|
|
132
135
|
"noReasoningModels",
|
|
133
136
|
"noVisionModels",
|
|
134
137
|
"reasoningEfforts",
|
|
@@ -15,6 +15,9 @@ export interface KeyLoginProvider {
|
|
|
15
15
|
dashboardUrl: string;
|
|
16
16
|
models?: string[];
|
|
17
17
|
defaultModel?: string;
|
|
18
|
+
contextWindow?: number;
|
|
19
|
+
modelContextWindows?: Record<string, number>;
|
|
20
|
+
modelInputModalities?: Record<string, string[]>;
|
|
18
21
|
/**
|
|
19
22
|
* Model ids that do NOT accept image input (the vision sidecar describes images for them) / do NOT
|
|
20
23
|
* accept a reasoning param. Copied into the created provider config by `enrichProviderFromCatalog`,
|
|
@@ -31,6 +34,7 @@ export interface KeyLoginProvider {
|
|
|
31
34
|
noPenaltyModels?: string[];
|
|
32
35
|
autoToolChoiceOnlyModels?: string[];
|
|
33
36
|
preserveReasoningContentModels?: string[];
|
|
37
|
+
escapeBuiltinToolNames?: boolean;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
export const KEY_LOGIN_PROVIDERS: Record<string, KeyLoginProvider> = deriveKeyLoginMap();
|
|
@@ -46,6 +50,9 @@ export function enrichProviderFromCatalog(name: string, prov: OcxProviderConfig)
|
|
|
46
50
|
if (!e) return;
|
|
47
51
|
if (!prov.models && e.models) prov.models = [...e.models];
|
|
48
52
|
if (!prov.defaultModel && e.defaultModel) prov.defaultModel = e.defaultModel;
|
|
53
|
+
if (prov.contextWindow === undefined && e.contextWindow !== undefined) prov.contextWindow = e.contextWindow;
|
|
54
|
+
if (!prov.modelContextWindows && e.modelContextWindows) prov.modelContextWindows = { ...e.modelContextWindows };
|
|
55
|
+
if (!prov.modelInputModalities && e.modelInputModalities) prov.modelInputModalities = cloneRecordOfArrays(e.modelInputModalities);
|
|
49
56
|
if (!prov.reasoningEfforts && e.reasoningEfforts) prov.reasoningEfforts = [...e.reasoningEfforts];
|
|
50
57
|
if (!prov.modelReasoningEfforts && e.modelReasoningEfforts) prov.modelReasoningEfforts = cloneRecordOfArrays(e.modelReasoningEfforts);
|
|
51
58
|
if (!prov.reasoningEffortMap && e.reasoningEffortMap) prov.reasoningEffortMap = { ...e.reasoningEffortMap };
|
|
@@ -57,6 +64,7 @@ export function enrichProviderFromCatalog(name: string, prov: OcxProviderConfig)
|
|
|
57
64
|
if (!prov.noPenaltyModels && e.noPenaltyModels) prov.noPenaltyModels = [...e.noPenaltyModels];
|
|
58
65
|
if (!prov.autoToolChoiceOnlyModels && e.autoToolChoiceOnlyModels) prov.autoToolChoiceOnlyModels = [...e.autoToolChoiceOnlyModels];
|
|
59
66
|
if (!prov.preserveReasoningContentModels && e.preserveReasoningContentModels) prov.preserveReasoningContentModels = [...e.preserveReasoningContentModels];
|
|
67
|
+
if (prov.escapeBuiltinToolNames === undefined && e.escapeBuiltinToolNames !== undefined) prov.escapeBuiltinToolNames = e.escapeBuiltinToolNames;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
|
|
@@ -76,10 +84,31 @@ export function listKeyLoginProviders(): Array<{ id: string } & KeyLoginProvider
|
|
|
76
84
|
return Object.entries(KEY_LOGIN_PROVIDERS).map(([id, p]) => ({ id, ...p }));
|
|
77
85
|
}
|
|
78
86
|
|
|
79
|
-
/** Best-effort key validation
|
|
80
|
-
export async function validateApiKey(
|
|
87
|
+
/** Best-effort key validation. Returns true/false/unknown; never persists the key itself. */
|
|
88
|
+
export async function validateApiKey(provider: KeyLoginProvider, key: string): Promise<boolean | "unknown"> {
|
|
81
89
|
try {
|
|
82
|
-
|
|
90
|
+
if (provider.adapter === "anthropic") {
|
|
91
|
+
const base = provider.baseUrl.replace(/\/v1\/?$/, "");
|
|
92
|
+
const res = await fetch(`${base}/v1/messages`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: {
|
|
95
|
+
"Content-Type": "application/json",
|
|
96
|
+
"anthropic-version": "2023-06-01",
|
|
97
|
+
"x-api-key": key,
|
|
98
|
+
},
|
|
99
|
+
body: JSON.stringify({
|
|
100
|
+
model: provider.defaultModel ?? "claude-sonnet-4-6",
|
|
101
|
+
max_tokens: 1,
|
|
102
|
+
messages: [{ role: "user", content: "ping" }],
|
|
103
|
+
}),
|
|
104
|
+
signal: AbortSignal.timeout(8000),
|
|
105
|
+
});
|
|
106
|
+
if (res.ok) return true;
|
|
107
|
+
if (res.status === 401 || res.status === 403) return false;
|
|
108
|
+
return "unknown";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const res = await fetch(`${provider.baseUrl}/models`, {
|
|
83
112
|
headers: { Authorization: `Bearer ${key}` },
|
|
84
113
|
signal: AbortSignal.timeout(8000),
|
|
85
114
|
});
|
package/src/oauth/login-cli.ts
CHANGED
|
@@ -2,7 +2,8 @@ import * as readline from "node:readline";
|
|
|
2
2
|
import { openUrl } from "../open-url";
|
|
3
3
|
import { loadConfig, readPid, saveConfig } from "../config";
|
|
4
4
|
import { OAUTH_PROVIDERS, runLogin } from "./index";
|
|
5
|
-
import { KEY_LOGIN_PROVIDERS, isKeyLoginProvider, validateApiKey } from "./key-providers";
|
|
5
|
+
import { KEY_LOGIN_PROVIDERS, isKeyLoginProvider, validateApiKey, type KeyLoginProvider } from "./key-providers";
|
|
6
|
+
import type { OcxProviderConfig } from "../types";
|
|
6
7
|
|
|
7
8
|
/** Push the new provider into a running proxy's live config so it routes without a restart. */
|
|
8
9
|
async function notifyRunningProxy(name: string, provider: unknown): Promise<void> {
|
|
@@ -51,6 +52,31 @@ async function handleOAuthLogin(name: string): Promise<void> {
|
|
|
51
52
|
console.log(`\n✅ Logged in to ${name}. Try: ocx sync`);
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
export function providerConfigFromKeyLoginProvider(def: KeyLoginProvider, key: string): OcxProviderConfig {
|
|
56
|
+
return {
|
|
57
|
+
adapter: def.adapter,
|
|
58
|
+
baseUrl: def.baseUrl,
|
|
59
|
+
apiKey: key,
|
|
60
|
+
...(def.defaultModel ? { defaultModel: def.defaultModel } : {}),
|
|
61
|
+
...(def.models ? { models: [...def.models] } : {}),
|
|
62
|
+
...(def.contextWindow !== undefined ? { contextWindow: def.contextWindow } : {}),
|
|
63
|
+
...(def.modelContextWindows ? { modelContextWindows: { ...def.modelContextWindows } } : {}),
|
|
64
|
+
...(def.modelInputModalities ? { modelInputModalities: cloneRecordOfArrays(def.modelInputModalities) } : {}),
|
|
65
|
+
...(def.reasoningEfforts ? { reasoningEfforts: [...def.reasoningEfforts] } : {}),
|
|
66
|
+
...(def.modelReasoningEfforts ? { modelReasoningEfforts: cloneRecordOfArrays(def.modelReasoningEfforts) } : {}),
|
|
67
|
+
...(def.reasoningEffortMap ? { reasoningEffortMap: { ...def.reasoningEffortMap } } : {}),
|
|
68
|
+
...(def.modelReasoningEffortMap ? { modelReasoningEffortMap: cloneNestedRecord(def.modelReasoningEffortMap) } : {}),
|
|
69
|
+
...(def.noVisionModels ? { noVisionModels: [...def.noVisionModels] } : {}),
|
|
70
|
+
...(def.noReasoningModels ? { noReasoningModels: [...def.noReasoningModels] } : {}),
|
|
71
|
+
...(def.noTemperatureModels ? { noTemperatureModels: [...def.noTemperatureModels] } : {}),
|
|
72
|
+
...(def.noTopPModels ? { noTopPModels: [...def.noTopPModels] } : {}),
|
|
73
|
+
...(def.noPenaltyModels ? { noPenaltyModels: [...def.noPenaltyModels] } : {}),
|
|
74
|
+
...(def.autoToolChoiceOnlyModels ? { autoToolChoiceOnlyModels: [...def.autoToolChoiceOnlyModels] } : {}),
|
|
75
|
+
...(def.preserveReasoningContentModels ? { preserveReasoningContentModels: [...def.preserveReasoningContentModels] } : {}),
|
|
76
|
+
...(def.escapeBuiltinToolNames !== undefined ? { escapeBuiltinToolNames: def.escapeBuiltinToolNames } : {}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
54
80
|
async function handleKeyLogin(name: string): Promise<void> {
|
|
55
81
|
const def = KEY_LOGIN_PROVIDERS[name];
|
|
56
82
|
console.log(`\n🔑 ${def.label} — opening ${def.dashboardUrl} so you can create/copy an API key...`);
|
|
@@ -63,22 +89,24 @@ async function handleKeyLogin(name: string): Promise<void> {
|
|
|
63
89
|
process.exit(1);
|
|
64
90
|
}
|
|
65
91
|
process.stdout.write(" validating… ");
|
|
66
|
-
const valid = await validateApiKey(def
|
|
92
|
+
const valid = await validateApiKey(def, key);
|
|
67
93
|
console.log(valid === true ? "valid ✅" : valid === false ? "INVALID ❌" : "couldn't validate (may still work)");
|
|
68
94
|
if (valid === false) {
|
|
69
95
|
console.error("Provider rejected the key. Not saved.");
|
|
70
96
|
process.exit(1);
|
|
71
97
|
}
|
|
72
|
-
const provider =
|
|
73
|
-
adapter: def.adapter,
|
|
74
|
-
baseUrl: def.baseUrl,
|
|
75
|
-
apiKey: key,
|
|
76
|
-
...(def.defaultModel ? { defaultModel: def.defaultModel } : {}),
|
|
77
|
-
...(def.models ? { models: def.models } : {}),
|
|
78
|
-
};
|
|
98
|
+
const provider = providerConfigFromKeyLoginProvider(def, key);
|
|
79
99
|
const config = loadConfig();
|
|
80
100
|
config.providers[name] = provider;
|
|
81
101
|
saveConfig(config);
|
|
82
102
|
await notifyRunningProxy(name, provider);
|
|
83
103
|
console.log(`✅ ${def.label} added. Try: ocx sync`);
|
|
84
104
|
}
|
|
105
|
+
|
|
106
|
+
function cloneRecordOfArrays(input: Record<string, string[]>): Record<string, string[]> {
|
|
107
|
+
return Object.fromEntries(Object.entries(input).map(([key, value]) => [key, [...value]]));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function cloneNestedRecord(input: Record<string, Record<string, string>>): Record<string, Record<string, string>> {
|
|
111
|
+
return Object.fromEntries(Object.entries(input).map(([key, value]) => [key, { ...value }]));
|
|
112
|
+
}
|
package/src/providers/derive.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface DerivedKeyLoginProvider {
|
|
|
8
8
|
dashboardUrl: string;
|
|
9
9
|
models?: string[];
|
|
10
10
|
defaultModel?: string;
|
|
11
|
+
contextWindow?: number;
|
|
12
|
+
modelContextWindows?: Record<string, number>;
|
|
13
|
+
modelInputModalities?: Record<string, string[]>;
|
|
11
14
|
reasoningEfforts?: string[];
|
|
12
15
|
modelReasoningEfforts?: Record<string, string[]>;
|
|
13
16
|
reasoningEffortMap?: Record<string, string>;
|
|
@@ -19,6 +22,7 @@ export interface DerivedKeyLoginProvider {
|
|
|
19
22
|
noPenaltyModels?: string[];
|
|
20
23
|
autoToolChoiceOnlyModels?: string[];
|
|
21
24
|
preserveReasoningContentModels?: string[];
|
|
25
|
+
escapeBuiltinToolNames?: boolean;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
export interface DerivedInitProvider {
|
|
@@ -62,6 +66,9 @@ export function providerConfigSeed(entry: ProviderRegistryEntry): OcxProviderCon
|
|
|
62
66
|
authMode: entry.authKind === "local" ? undefined : entry.authKind,
|
|
63
67
|
...(entry.defaultModel ? { defaultModel: entry.defaultModel } : {}),
|
|
64
68
|
...(entry.models ? { models: [...entry.models] } : {}),
|
|
69
|
+
...(entry.contextWindow !== undefined ? { contextWindow: entry.contextWindow } : {}),
|
|
70
|
+
...(entry.modelContextWindows ? { modelContextWindows: { ...entry.modelContextWindows } } : {}),
|
|
71
|
+
...(entry.modelInputModalities ? { modelInputModalities: cloneRecordOfArrays(entry.modelInputModalities) } : {}),
|
|
65
72
|
...(entry.reasoningEfforts ? { reasoningEfforts: [...entry.reasoningEfforts] } : {}),
|
|
66
73
|
...(entry.modelReasoningEfforts ? { modelReasoningEfforts: cloneRecordOfArrays(entry.modelReasoningEfforts) } : {}),
|
|
67
74
|
...(entry.reasoningEffortMap ? { reasoningEffortMap: { ...entry.reasoningEffortMap } } : {}),
|
|
@@ -73,6 +80,7 @@ export function providerConfigSeed(entry: ProviderRegistryEntry): OcxProviderCon
|
|
|
73
80
|
...(entry.noPenaltyModels ? { noPenaltyModels: [...entry.noPenaltyModels] } : {}),
|
|
74
81
|
...(entry.autoToolChoiceOnlyModels ? { autoToolChoiceOnlyModels: [...entry.autoToolChoiceOnlyModels] } : {}),
|
|
75
82
|
...(entry.preserveReasoningContentModels ? { preserveReasoningContentModels: [...entry.preserveReasoningContentModels] } : {}),
|
|
83
|
+
...(entry.escapeBuiltinToolNames !== undefined ? { escapeBuiltinToolNames: entry.escapeBuiltinToolNames } : {}),
|
|
76
84
|
};
|
|
77
85
|
}
|
|
78
86
|
|
|
@@ -88,6 +96,9 @@ export function deriveKeyLoginMap(): Record<string, DerivedKeyLoginProvider> {
|
|
|
88
96
|
dashboardUrl: entry.dashboardUrl,
|
|
89
97
|
...(entry.models ? { models: [...entry.models] } : {}),
|
|
90
98
|
...(entry.defaultModel ? { defaultModel: entry.defaultModel } : {}),
|
|
99
|
+
...(entry.contextWindow !== undefined ? { contextWindow: entry.contextWindow } : {}),
|
|
100
|
+
...(entry.modelContextWindows ? { modelContextWindows: { ...entry.modelContextWindows } } : {}),
|
|
101
|
+
...(entry.modelInputModalities ? { modelInputModalities: cloneRecordOfArrays(entry.modelInputModalities) } : {}),
|
|
91
102
|
...(entry.reasoningEfforts ? { reasoningEfforts: [...entry.reasoningEfforts] } : {}),
|
|
92
103
|
...(entry.modelReasoningEfforts ? { modelReasoningEfforts: cloneRecordOfArrays(entry.modelReasoningEfforts) } : {}),
|
|
93
104
|
...(entry.reasoningEffortMap ? { reasoningEffortMap: { ...entry.reasoningEffortMap } } : {}),
|
|
@@ -99,6 +110,7 @@ export function deriveKeyLoginMap(): Record<string, DerivedKeyLoginProvider> {
|
|
|
99
110
|
...(entry.noPenaltyModels ? { noPenaltyModels: [...entry.noPenaltyModels] } : {}),
|
|
100
111
|
...(entry.autoToolChoiceOnlyModels ? { autoToolChoiceOnlyModels: [...entry.autoToolChoiceOnlyModels] } : {}),
|
|
101
112
|
...(entry.preserveReasoningContentModels ? { preserveReasoningContentModels: [...entry.preserveReasoningContentModels] } : {}),
|
|
113
|
+
...(entry.escapeBuiltinToolNames !== undefined ? { escapeBuiltinToolNames: entry.escapeBuiltinToolNames } : {}),
|
|
102
114
|
};
|
|
103
115
|
}
|
|
104
116
|
return out;
|
|
@@ -14,6 +14,9 @@ export interface ProviderRegistryEntry {
|
|
|
14
14
|
dashboardUrl?: string;
|
|
15
15
|
defaultModel?: string;
|
|
16
16
|
models?: string[];
|
|
17
|
+
contextWindow?: number;
|
|
18
|
+
modelContextWindows?: Record<string, number>;
|
|
19
|
+
modelInputModalities?: Record<string, string[]>;
|
|
17
20
|
reasoningEfforts?: string[];
|
|
18
21
|
modelReasoningEfforts?: Record<string, string[]>;
|
|
19
22
|
reasoningEffortMap?: Record<string, string>;
|
|
@@ -25,6 +28,7 @@ export interface ProviderRegistryEntry {
|
|
|
25
28
|
noPenaltyModels?: string[];
|
|
26
29
|
autoToolChoiceOnlyModels?: string[];
|
|
27
30
|
preserveReasoningContentModels?: string[];
|
|
31
|
+
escapeBuiltinToolNames?: boolean;
|
|
28
32
|
oauthId?: string;
|
|
29
33
|
jawcodeBundle?: string;
|
|
30
34
|
extraMetadataAliases?: string[];
|
|
@@ -34,9 +38,10 @@ export interface ProviderRegistryEntry {
|
|
|
34
38
|
export type ProviderConfigSeed = Pick<
|
|
35
39
|
OcxProviderConfig,
|
|
36
40
|
"adapter" | "baseUrl" | "authMode" | "defaultModel" | "models"
|
|
41
|
+
| "contextWindow" | "modelContextWindows" | "modelInputModalities"
|
|
37
42
|
| "reasoningEfforts" | "modelReasoningEfforts" | "reasoningEffortMap" | "modelReasoningEffortMap"
|
|
38
43
|
| "noVisionModels" | "noReasoningModels" | "noTemperatureModels" | "noTopPModels" | "noPenaltyModels"
|
|
39
|
-
| "autoToolChoiceOnlyModels" | "preserveReasoningContentModels"
|
|
44
|
+
| "autoToolChoiceOnlyModels" | "preserveReasoningContentModels" | "escapeBuiltinToolNames"
|
|
40
45
|
>;
|
|
41
46
|
|
|
42
47
|
|
|
@@ -58,6 +63,39 @@ const NEURALWATT_REASONING_HISTORY_MODELS = [
|
|
|
58
63
|
"moonshotai/Kimi-K2.5", "kimi-k2.6", "kimi-k2.7-code",
|
|
59
64
|
"qwen3.5-397b", "qwen3.6-35b",
|
|
60
65
|
];
|
|
66
|
+
const UMANS_MODELS = [
|
|
67
|
+
"umans-coder",
|
|
68
|
+
"umans-kimi-k2.7",
|
|
69
|
+
"umans-kimi-k2.6",
|
|
70
|
+
"umans-flash",
|
|
71
|
+
"umans-glm-5.2",
|
|
72
|
+
"umans-glm-5.1",
|
|
73
|
+
"umans-qwen3.6-35b-a3b",
|
|
74
|
+
];
|
|
75
|
+
const UMANS_REASONING_EFFORTS = ["low", "medium", "high", "xhigh"];
|
|
76
|
+
const UMANS_GLM_REASONING_EFFORTS = ["high", "xhigh"];
|
|
77
|
+
const UMANS_GLM_REASONING_MAP: Record<string, string> = {
|
|
78
|
+
none: "high",
|
|
79
|
+
minimal: "high",
|
|
80
|
+
low: "high",
|
|
81
|
+
medium: "high",
|
|
82
|
+
high: "high",
|
|
83
|
+
xhigh: "max",
|
|
84
|
+
max: "max",
|
|
85
|
+
};
|
|
86
|
+
const UMANS_TEXT_ONLY_MODELS = ["umans-glm-5.2", "umans-glm-5.1"];
|
|
87
|
+
const UMANS_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
88
|
+
"umans-coder": 262_144,
|
|
89
|
+
"umans-kimi-k2.7": 262_144,
|
|
90
|
+
"umans-kimi-k2.6": 262_144,
|
|
91
|
+
"umans-flash": 262_144,
|
|
92
|
+
"umans-glm-5.2": 405_504,
|
|
93
|
+
"umans-glm-5.1": 202_752,
|
|
94
|
+
"umans-qwen3.6-35b-a3b": 262_144,
|
|
95
|
+
};
|
|
96
|
+
const UMANS_MODEL_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
|
|
97
|
+
UMANS_MODELS.map(id => [id, UMANS_TEXT_ONLY_MODELS.includes(id) ? ["text"] : ["text", "image"]]),
|
|
98
|
+
);
|
|
61
99
|
|
|
62
100
|
export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
63
101
|
{
|
|
@@ -119,6 +157,35 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
119
157
|
preserveReasoningContentModels: KIMI_THINKING_MODELS,
|
|
120
158
|
},
|
|
121
159
|
{ id: "openai-apikey", label: "OpenAI (API key)", adapter: "openai-responses", baseUrl: "https://api.openai.com/v1", authKind: "key", featured: true, dashboardUrl: "https://platform.openai.com/api-keys", defaultModel: "gpt-5.5" },
|
|
160
|
+
{
|
|
161
|
+
id: "umans",
|
|
162
|
+
label: "Umans AI Coding Plan",
|
|
163
|
+
adapter: "anthropic",
|
|
164
|
+
baseUrl: "https://api.code.umans.ai",
|
|
165
|
+
authKind: "key",
|
|
166
|
+
featured: true,
|
|
167
|
+
dashboardUrl: "https://app.umans.ai/billing",
|
|
168
|
+
defaultModel: "umans-coder",
|
|
169
|
+
models: UMANS_MODELS,
|
|
170
|
+
modelContextWindows: UMANS_MODEL_CONTEXT_WINDOWS,
|
|
171
|
+
modelInputModalities: UMANS_MODEL_INPUT_MODALITIES,
|
|
172
|
+
note: "Coding plan via Anthropic Messages",
|
|
173
|
+
modelReasoningEfforts: {
|
|
174
|
+
"umans-coder": UMANS_REASONING_EFFORTS,
|
|
175
|
+
"umans-kimi-k2.7": UMANS_REASONING_EFFORTS,
|
|
176
|
+
"umans-kimi-k2.6": UMANS_REASONING_EFFORTS,
|
|
177
|
+
"umans-flash": ["low", "medium", "high"],
|
|
178
|
+
"umans-glm-5.2": UMANS_GLM_REASONING_EFFORTS,
|
|
179
|
+
"umans-glm-5.1": UMANS_GLM_REASONING_EFFORTS,
|
|
180
|
+
"umans-qwen3.6-35b-a3b": ["low", "medium", "high"],
|
|
181
|
+
},
|
|
182
|
+
modelReasoningEffortMap: {
|
|
183
|
+
"umans-glm-5.2": UMANS_GLM_REASONING_MAP,
|
|
184
|
+
"umans-glm-5.1": UMANS_GLM_REASONING_MAP,
|
|
185
|
+
},
|
|
186
|
+
noVisionModels: UMANS_TEXT_ONLY_MODELS,
|
|
187
|
+
escapeBuiltinToolNames: true,
|
|
188
|
+
},
|
|
122
189
|
{
|
|
123
190
|
id: "opencode-go", label: "opencode go", adapter: "openai-chat", baseUrl: "https://opencode.ai/zen/go/v1",
|
|
124
191
|
authKind: "key", featured: true, dashboardUrl: "https://opencode.ai/auth", defaultModel: "kimi-k2.7-code",
|
package/src/types.ts
CHANGED
|
@@ -187,6 +187,13 @@ export interface OcxConfig {
|
|
|
187
187
|
websockets?: boolean;
|
|
188
188
|
/** Auto-start/sync the proxy from the Codex shim before launching Codex. Default true. */
|
|
189
189
|
codexAutoStart?: boolean;
|
|
190
|
+
/**
|
|
191
|
+
* Compatibility mode: temporarily rewrite Codex resume-history metadata while the proxy is active
|
|
192
|
+
* so Codex App can show old OpenAI chats and opencodex-created exec chats under its default
|
|
193
|
+
* interactive-source/provider filters. Disabled by default because it mutates Codex's local
|
|
194
|
+
* thread index; originals are backed up and restored by `ocx stop` / `ocx restore`.
|
|
195
|
+
*/
|
|
196
|
+
syncResumeHistory?: boolean;
|
|
190
197
|
/** Freshness window (ms) for the per-provider live `/models` cache. Defaults to 5 min. */
|
|
191
198
|
modelCacheTtlMs?: number;
|
|
192
199
|
/** Web-search sidecar: route web_search for non-OpenAI models through a gpt-mini via ChatGPT passthrough. */
|
|
@@ -223,6 +230,12 @@ export interface OcxProviderConfig {
|
|
|
223
230
|
apiKey?: string;
|
|
224
231
|
defaultModel?: string;
|
|
225
232
|
models?: string[];
|
|
233
|
+
/** Provider-wide Codex-visible context-window cap for routed catalog entries. */
|
|
234
|
+
contextWindow?: number;
|
|
235
|
+
/** Model-specific Codex-visible context-window caps. Values cap live metadata, never raise it. */
|
|
236
|
+
modelContextWindows?: Record<string, number>;
|
|
237
|
+
/** Model-specific Codex catalog input modalities, e.g. ["text"] or ["text", "image"]. */
|
|
238
|
+
modelInputModalities?: Record<string, string[]>;
|
|
226
239
|
headers?: Record<string, string>;
|
|
227
240
|
/**
|
|
228
241
|
* "key" (default): authenticate upstream with `apiKey`.
|
|
@@ -258,6 +271,8 @@ export interface OcxProviderConfig {
|
|
|
258
271
|
autoToolChoiceOnlyModels?: string[];
|
|
259
272
|
/** Model ids that expect prior assistant `reasoning_content` to be preserved in chat history. */
|
|
260
273
|
preserveReasoningContentModels?: string[];
|
|
274
|
+
/** Anthropic-compatible gateways that need custom tool names escaped on the wire. */
|
|
275
|
+
escapeBuiltinToolNames?: boolean;
|
|
261
276
|
/**
|
|
262
277
|
* Model ids that do NOT accept image inputs. The proxy gives them "eyes" via the vision sidecar:
|
|
263
278
|
* attached images are described by a gpt vision model and replaced with text before the call.
|