@elvatis_com/openclaw-cli-bridge-elvatis 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/SKILL.md +1 -1
- package/index.ts +35 -37
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/cli-runner.ts +11 -13
- package/src/config.ts +217 -0
- package/src/provider-sessions.ts +264 -0
- package/src/proxy-server.ts +57 -15
- package/src/session-manager.ts +9 -8
- package/test/config.test.ts +102 -0
- package/test/provider-sessions.test.ts +294 -0
- package/test/session-manager.test.ts +14 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> OpenClaw plugin that bridges locally installed AI CLIs (Codex, Gemini, Claude Code, OpenCode, Pi) as model providers — with slash commands for instant model switching, restore, health testing, and model listing.
|
|
4
4
|
|
|
5
|
-
**Current version:** `2.
|
|
5
|
+
**Current version:** `2.6.0`
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -378,7 +378,7 @@ Model fallback (v1.9.0):
|
|
|
378
378
|
```bash
|
|
379
379
|
npm run lint # eslint (TypeScript-aware)
|
|
380
380
|
npm run typecheck # tsc --noEmit
|
|
381
|
-
npm test # vitest run (
|
|
381
|
+
npm test # vitest run (252 tests)
|
|
382
382
|
npm run ci # lint + typecheck + test
|
|
383
383
|
```
|
|
384
384
|
|
|
@@ -386,6 +386,15 @@ npm run ci # lint + typecheck + test
|
|
|
386
386
|
|
|
387
387
|
## Changelog
|
|
388
388
|
|
|
389
|
+
### v2.6.0
|
|
390
|
+
- **feat:** Provider session registry (`src/provider-sessions.ts`) — persistent sessions that survive across runs. When a CLI run times out, the session is preserved (not deleted) so follow-up runs can resume in the same context. Sessions are stored in `~/.openclaw/cli-bridge/sessions.json`.
|
|
391
|
+
- **feat:** Centralized config module (`src/config.ts`) — all magic numbers, timeouts, paths, ports, and model defaults extracted into one file. No more scattered hardcoded values.
|
|
392
|
+
- **feat:** Session-aware proxy — every CLI request gets a `provider_session_id` in the response. Pass it back via `providerSessionId` in subsequent requests to reuse the same session.
|
|
393
|
+
- **feat:** New proxy endpoints: `GET /v1/provider-sessions` (list sessions + stats), `DELETE /v1/provider-sessions/:id` (remove a session)
|
|
394
|
+
- **fix:** Version fallback changed from `"0.0.0"` to `"unknown"` with secondary lookup in `openclaw.plugin.json` — prevents Dashboard showing wrong version
|
|
395
|
+
- **refactor:** `index.ts`, `cli-runner.ts`, `session-manager.ts`, `proxy-server.ts` now import all constants from `config.ts` instead of defining them locally
|
|
396
|
+
- **test:** 35 new tests for provider sessions, config exports (252 total)
|
|
397
|
+
|
|
389
398
|
### v2.5.0
|
|
390
399
|
- **feat:** Graceful timeout handling — replaces Node's `spawn({ timeout })` with manual SIGTERM→SIGKILL sequence (5s grace period). Exit 143 is now clearly annotated as "timeout by supervisor" in logs, not a cryptic model error.
|
|
391
400
|
- **feat:** Per-model timeout profiles — new `modelTimeouts` config option sets sensible defaults per model: Opus 5 min, Sonnet 3 min, Haiku 90s, Flash models 90s. Scales dynamically with conversation size (+2s/msg beyond 10, +5s/tool).
|
package/SKILL.md
CHANGED
package/index.ts
CHANGED
|
@@ -41,7 +41,13 @@ const PACKAGE_VERSION: string = (() => {
|
|
|
41
41
|
const pkg = JSON.parse(readFileSync(join(__dirname_local, "package.json"), "utf-8")) as { version: string };
|
|
42
42
|
return pkg.version;
|
|
43
43
|
} catch {
|
|
44
|
-
|
|
44
|
+
// Second attempt: try openclaw.plugin.json (always co-located)
|
|
45
|
+
try {
|
|
46
|
+
const manifest = JSON.parse(readFileSync(join(__dirname_local, "openclaw.plugin.json"), "utf-8")) as { version: string };
|
|
47
|
+
return manifest.version;
|
|
48
|
+
} catch {
|
|
49
|
+
return "unknown"; // should never happen — both files are always present
|
|
50
|
+
}
|
|
45
51
|
}
|
|
46
52
|
})();
|
|
47
53
|
import type {
|
|
@@ -62,6 +68,18 @@ import {
|
|
|
62
68
|
import { importCodexAuth } from "./src/codex-auth-import.js";
|
|
63
69
|
import { startProxyServer } from "./src/proxy-server.js";
|
|
64
70
|
import { patchOpencllawConfig } from "./src/config-patcher.js";
|
|
71
|
+
import {
|
|
72
|
+
DEFAULT_PROXY_PORT,
|
|
73
|
+
DEFAULT_PROXY_API_KEY,
|
|
74
|
+
DEFAULT_PROXY_TIMEOUT_MS,
|
|
75
|
+
DEFAULT_MODEL_TIMEOUTS,
|
|
76
|
+
DEFAULT_MODEL_FALLBACKS,
|
|
77
|
+
STATE_FILE as CONFIG_STATE_FILE,
|
|
78
|
+
PENDING_FILE as CONFIG_PENDING_FILE,
|
|
79
|
+
OPENCLAW_DIR,
|
|
80
|
+
CLI_TEST_DEFAULT_MODEL as CONFIG_CLI_TEST_DEFAULT_MODEL,
|
|
81
|
+
PROFILE_DIRS,
|
|
82
|
+
} from "./src/config.js";
|
|
65
83
|
import {
|
|
66
84
|
loadSession,
|
|
67
85
|
deleteSession,
|
|
@@ -109,11 +127,11 @@ interface CliPluginConfig {
|
|
|
109
127
|
let grokBrowser: Browser | null = null;
|
|
110
128
|
let grokContext: BrowserContext | null = null;
|
|
111
129
|
|
|
112
|
-
// Persistent profile dirs —
|
|
113
|
-
const GROK_PROFILE_DIR =
|
|
114
|
-
const GEMINI_PROFILE_DIR =
|
|
115
|
-
const CLAUDE_PROFILE_DIR =
|
|
116
|
-
const CHATGPT_PROFILE_DIR =
|
|
130
|
+
// Persistent profile dirs — imported from config.ts
|
|
131
|
+
const GROK_PROFILE_DIR = PROFILE_DIRS.grok;
|
|
132
|
+
const GEMINI_PROFILE_DIR = PROFILE_DIRS.gemini;
|
|
133
|
+
const CLAUDE_PROFILE_DIR = PROFILE_DIRS.claude;
|
|
134
|
+
const CHATGPT_PROFILE_DIR = PROFILE_DIRS.chatgpt;
|
|
117
135
|
|
|
118
136
|
// Stealth launch options — prevent Cloudflare/bot detection from flagging the browser
|
|
119
137
|
const STEALTH_ARGS = [
|
|
@@ -685,14 +703,13 @@ async function tryRestoreGrokSession(
|
|
|
685
703
|
}
|
|
686
704
|
}
|
|
687
705
|
|
|
688
|
-
|
|
689
|
-
const DEFAULT_PROXY_API_KEY = "cli-bridge";
|
|
706
|
+
// DEFAULT_PROXY_PORT, DEFAULT_PROXY_API_KEY imported from config.ts
|
|
690
707
|
|
|
691
708
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
692
709
|
// State file — persists the model that was active before the last /cli-* switch
|
|
693
710
|
// Located at ~/.openclaw/cli-bridge-state.json (survives gateway restarts)
|
|
694
711
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
695
|
-
const STATE_FILE =
|
|
712
|
+
const STATE_FILE = CONFIG_STATE_FILE;
|
|
696
713
|
|
|
697
714
|
interface CliBridgeState {
|
|
698
715
|
previousModel: string;
|
|
@@ -708,7 +725,7 @@ function readState(): CliBridgeState | null {
|
|
|
708
725
|
|
|
709
726
|
function writeState(state: CliBridgeState): void {
|
|
710
727
|
try {
|
|
711
|
-
mkdirSync(
|
|
728
|
+
mkdirSync(OPENCLAW_DIR, { recursive: true });
|
|
712
729
|
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
713
730
|
} catch {
|
|
714
731
|
// non-fatal — /cli-back will just report no previous model
|
|
@@ -780,7 +797,7 @@ const CLI_MODEL_COMMANDS = [
|
|
|
780
797
|
] as const;
|
|
781
798
|
|
|
782
799
|
/** Default model used by /cli-test when no arg is given */
|
|
783
|
-
const CLI_TEST_DEFAULT_MODEL =
|
|
800
|
+
const CLI_TEST_DEFAULT_MODEL = CONFIG_CLI_TEST_DEFAULT_MODEL;
|
|
784
801
|
|
|
785
802
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
786
803
|
// Staged-switch state file
|
|
@@ -788,7 +805,7 @@ const CLI_TEST_DEFAULT_MODEL = "cli-claude/claude-sonnet-4-6";
|
|
|
788
805
|
// Written by /cli-* (default), applied by /cli-apply or /cli-* --now.
|
|
789
806
|
// Located at ~/.openclaw/cli-bridge-pending.json
|
|
790
807
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
791
|
-
const PENDING_FILE =
|
|
808
|
+
const PENDING_FILE = CONFIG_PENDING_FILE;
|
|
792
809
|
|
|
793
810
|
interface CliBridgePending {
|
|
794
811
|
model: string;
|
|
@@ -806,7 +823,7 @@ function readPending(): CliBridgePending | null {
|
|
|
806
823
|
|
|
807
824
|
function writePending(pending: CliBridgePending): void {
|
|
808
825
|
try {
|
|
809
|
-
mkdirSync(
|
|
826
|
+
mkdirSync(OPENCLAW_DIR, { recursive: true });
|
|
810
827
|
writeFileSync(PENDING_FILE, JSON.stringify(pending, null, 2) + "\n", "utf8");
|
|
811
828
|
} catch {
|
|
812
829
|
// non-fatal
|
|
@@ -988,22 +1005,9 @@ const plugin = {
|
|
|
988
1005
|
const enableProxy = cfg.enableProxy ?? true;
|
|
989
1006
|
const port = cfg.proxyPort ?? DEFAULT_PROXY_PORT;
|
|
990
1007
|
const apiKey = cfg.proxyApiKey ?? DEFAULT_PROXY_API_KEY;
|
|
991
|
-
const timeoutMs = cfg.proxyTimeoutMs ??
|
|
992
|
-
// Per-model timeout overrides —
|
|
993
|
-
|
|
994
|
-
const defaultModelTimeouts: Record<string, number> = {
|
|
995
|
-
"cli-claude/claude-opus-4-6": 300_000, // 5 min — heavy, agentic tasks
|
|
996
|
-
"cli-claude/claude-sonnet-4-6": 180_000, // 3 min — standard interactive chat
|
|
997
|
-
"cli-claude/claude-haiku-4-5": 90_000, // 90s — fast responses
|
|
998
|
-
"cli-gemini/gemini-2.5-pro": 180_000,
|
|
999
|
-
"cli-gemini/gemini-2.5-flash": 90_000,
|
|
1000
|
-
"cli-gemini/gemini-3-pro-preview": 180_000,
|
|
1001
|
-
"cli-gemini/gemini-3-flash-preview": 90_000,
|
|
1002
|
-
"openai-codex/gpt-5.4": 300_000,
|
|
1003
|
-
"openai-codex/gpt-5.3-codex": 180_000,
|
|
1004
|
-
"openai-codex/gpt-5.1-codex-mini": 90_000,
|
|
1005
|
-
};
|
|
1006
|
-
const modelTimeouts = { ...defaultModelTimeouts, ...cfg.modelTimeouts };
|
|
1008
|
+
const timeoutMs = cfg.proxyTimeoutMs ?? DEFAULT_PROXY_TIMEOUT_MS;
|
|
1009
|
+
// Per-model timeout overrides — defaults from config.ts, can be extended via plugin config.
|
|
1010
|
+
const modelTimeouts = { ...DEFAULT_MODEL_TIMEOUTS, ...cfg.modelTimeouts };
|
|
1007
1011
|
const codexAuthPath = cfg.codexAuthPath ?? DEFAULT_CODEX_AUTH_PATH;
|
|
1008
1012
|
const grokSessionPath = cfg.grokSessionPath ?? DEFAULT_SESSION_PATH;
|
|
1009
1013
|
|
|
@@ -1015,14 +1019,8 @@ const plugin = {
|
|
|
1015
1019
|
modelCommands[modelId] = `/${entry.name}`;
|
|
1016
1020
|
}
|
|
1017
1021
|
|
|
1018
|
-
// ── Default model fallback chain
|
|
1019
|
-
|
|
1020
|
-
const modelFallbacks: Record<string, string> = {
|
|
1021
|
-
"cli-gemini/gemini-2.5-pro": "cli-gemini/gemini-2.5-flash",
|
|
1022
|
-
"cli-gemini/gemini-3-pro-preview": "cli-gemini/gemini-3-flash-preview",
|
|
1023
|
-
"cli-claude/claude-opus-4-6": "cli-claude/claude-sonnet-4-6",
|
|
1024
|
-
"cli-claude/claude-sonnet-4-6": "cli-claude/claude-haiku-4-5",
|
|
1025
|
-
};
|
|
1022
|
+
// ── Default model fallback chain (from config.ts) ──────────────────────────
|
|
1023
|
+
const modelFallbacks = { ...DEFAULT_MODEL_FALLBACKS };
|
|
1026
1024
|
|
|
1027
1025
|
// ── Migrate legacy per-provider cookie expiry files to consolidated store ─
|
|
1028
1026
|
const migration = migrateLegacyFiles();
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "openclaw-cli-bridge-elvatis",
|
|
3
3
|
"slug": "openclaw-cli-bridge-elvatis",
|
|
4
4
|
"name": "OpenClaw CLI Bridge",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.6.0",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"description": "Phase 1: openai-codex auth bridge. Phase 2: local HTTP proxy routing model calls through gemini/claude CLIs (vllm provider).",
|
|
8
8
|
"providers": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elvatis_com/openclaw-cli-bridge-elvatis",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Bridges gemini, claude, and codex CLI tools as OpenClaw model providers. Reads existing CLI auth without re-login.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"openclaw": {
|
package/src/cli-runner.ts
CHANGED
|
@@ -28,11 +28,13 @@ import {
|
|
|
28
28
|
buildToolPromptBlock,
|
|
29
29
|
parseToolCallResponse,
|
|
30
30
|
} from "./tool-protocol.js";
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
import {
|
|
32
|
+
MAX_MESSAGES,
|
|
33
|
+
MAX_MSG_CHARS,
|
|
34
|
+
DEFAULT_CLI_TIMEOUT_MS,
|
|
35
|
+
TIMEOUT_GRACE_MS,
|
|
36
|
+
MEDIA_TMP_DIR,
|
|
37
|
+
} from "./config.js";
|
|
36
38
|
|
|
37
39
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
38
40
|
// Message formatting
|
|
@@ -152,7 +154,7 @@ export interface MediaFile {
|
|
|
152
154
|
mimeType: string;
|
|
153
155
|
}
|
|
154
156
|
|
|
155
|
-
|
|
157
|
+
// MEDIA_TMP_DIR imported from config.ts
|
|
156
158
|
|
|
157
159
|
/**
|
|
158
160
|
* Extract non-text content parts (images, audio) from messages.
|
|
@@ -293,11 +295,7 @@ export interface RunCliOptions {
|
|
|
293
295
|
log?: (msg: string) => void;
|
|
294
296
|
}
|
|
295
297
|
|
|
296
|
-
|
|
297
|
-
* Grace period between SIGTERM and SIGKILL when a timeout fires.
|
|
298
|
-
* Gives the CLI process 5 seconds to flush output and exit cleanly.
|
|
299
|
-
*/
|
|
300
|
-
const TIMEOUT_GRACE_MS = 5_000;
|
|
298
|
+
// TIMEOUT_GRACE_MS imported from config.ts
|
|
301
299
|
|
|
302
300
|
/**
|
|
303
301
|
* Spawn a CLI and deliver the prompt via stdin.
|
|
@@ -315,7 +313,7 @@ export function runCli(
|
|
|
315
313
|
cmd: string,
|
|
316
314
|
args: string[],
|
|
317
315
|
prompt: string,
|
|
318
|
-
timeoutMs =
|
|
316
|
+
timeoutMs = DEFAULT_CLI_TIMEOUT_MS,
|
|
319
317
|
opts: RunCliOptions = {}
|
|
320
318
|
): Promise<CliRunResult> {
|
|
321
319
|
const cwd = opts.cwd ?? homedir();
|
|
@@ -381,7 +379,7 @@ export function runCli(
|
|
|
381
379
|
export function runCliWithArg(
|
|
382
380
|
cmd: string,
|
|
383
381
|
args: string[],
|
|
384
|
-
timeoutMs =
|
|
382
|
+
timeoutMs = DEFAULT_CLI_TIMEOUT_MS,
|
|
385
383
|
opts: RunCliOptions = {}
|
|
386
384
|
): Promise<CliRunResult> {
|
|
387
385
|
const cwd = opts.cwd ?? homedir();
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config.ts
|
|
3
|
+
*
|
|
4
|
+
* Central configuration defaults for the CLI bridge plugin.
|
|
5
|
+
* All magic numbers, timeouts, paths, and constants live here.
|
|
6
|
+
* Import from this module instead of scattering literals across the codebase.
|
|
7
|
+
*
|
|
8
|
+
* Values can be overridden at runtime via openclaw.plugin.json configSchema
|
|
9
|
+
* or via the CliPluginConfig interface in index.ts.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { homedir, tmpdir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
|
|
15
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// Proxy server
|
|
17
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
/** Default port for the local OpenAI-compatible proxy server. */
|
|
20
|
+
export const DEFAULT_PROXY_PORT = 31337;
|
|
21
|
+
|
|
22
|
+
/** Default API key between OpenClaw vllm provider and the proxy. */
|
|
23
|
+
export const DEFAULT_PROXY_API_KEY = "cli-bridge";
|
|
24
|
+
|
|
25
|
+
/** Default base timeout for CLI subprocess responses (ms). Scales dynamically. */
|
|
26
|
+
export const DEFAULT_PROXY_TIMEOUT_MS = 300_000; // 5 min
|
|
27
|
+
|
|
28
|
+
/** Maximum effective timeout after dynamic scaling (ms). */
|
|
29
|
+
export const MAX_EFFECTIVE_TIMEOUT_MS = 600_000; // 10 min
|
|
30
|
+
|
|
31
|
+
/** Extra timeout per message beyond 10 in the conversation (ms). */
|
|
32
|
+
export const TIMEOUT_PER_EXTRA_MSG_MS = 2_000;
|
|
33
|
+
|
|
34
|
+
/** Extra timeout per tool definition in the request (ms). */
|
|
35
|
+
export const TIMEOUT_PER_TOOL_MS = 5_000;
|
|
36
|
+
|
|
37
|
+
/** SSE keepalive interval — prevents OpenClaw read-timeout during long CLI runs (ms). */
|
|
38
|
+
export const SSE_KEEPALIVE_INTERVAL_MS = 15_000;
|
|
39
|
+
|
|
40
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
41
|
+
// CLI subprocess
|
|
42
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
/** Default timeout for individual CLI subprocess invocations (ms). */
|
|
45
|
+
export const DEFAULT_CLI_TIMEOUT_MS = 120_000; // 2 min
|
|
46
|
+
|
|
47
|
+
/** Grace period between SIGTERM and SIGKILL when a timeout fires (ms). */
|
|
48
|
+
export const TIMEOUT_GRACE_MS = 5_000;
|
|
49
|
+
|
|
50
|
+
/** Max messages to include in the prompt sent to CLI subprocesses. */
|
|
51
|
+
export const MAX_MESSAGES = 20;
|
|
52
|
+
|
|
53
|
+
/** Max characters per message content before truncation. */
|
|
54
|
+
export const MAX_MSG_CHARS = 4_000;
|
|
55
|
+
|
|
56
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
57
|
+
// Session manager (long-running sessions)
|
|
58
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
/** Auto-cleanup threshold: sessions older than this are killed and removed (ms). */
|
|
61
|
+
export const SESSION_TTL_MS = 30 * 60 * 1_000; // 30 min
|
|
62
|
+
|
|
63
|
+
/** Interval for the session cleanup sweep (ms). */
|
|
64
|
+
export const CLEANUP_INTERVAL_MS = 5 * 60 * 1_000; // 5 min
|
|
65
|
+
|
|
66
|
+
/** Grace period between SIGTERM and SIGKILL for session termination (ms). */
|
|
67
|
+
export const SESSION_KILL_GRACE_MS = 5_000;
|
|
68
|
+
|
|
69
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
70
|
+
// Provider sessions (persistent session registry)
|
|
71
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
/** Default TTL for provider sessions before they're considered stale (ms). */
|
|
74
|
+
export const PROVIDER_SESSION_TTL_MS = 2 * 60 * 60 * 1_000; // 2 hours
|
|
75
|
+
|
|
76
|
+
/** Sweep interval for stale provider sessions (ms). */
|
|
77
|
+
export const PROVIDER_SESSION_SWEEP_MS = 10 * 60 * 1_000; // 10 min
|
|
78
|
+
|
|
79
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
80
|
+
// Per-model timeout defaults (ms)
|
|
81
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Default per-model timeout overrides.
|
|
85
|
+
* These are applied as the base timeout before dynamic scaling.
|
|
86
|
+
* Override via `modelTimeouts` in plugin config.
|
|
87
|
+
*
|
|
88
|
+
* Strategy:
|
|
89
|
+
* - Heavy/agentic models (Opus, GPT-5.4): 5 min — need time for tool use
|
|
90
|
+
* - Standard interactive (Sonnet, Pro, GPT-5.3): 3 min
|
|
91
|
+
* - Fast/lightweight (Haiku, Flash, Mini): 90s
|
|
92
|
+
*/
|
|
93
|
+
export const DEFAULT_MODEL_TIMEOUTS: Record<string, number> = {
|
|
94
|
+
"cli-claude/claude-opus-4-6": 300_000, // 5 min
|
|
95
|
+
"cli-claude/claude-sonnet-4-6": 180_000, // 3 min
|
|
96
|
+
"cli-claude/claude-haiku-4-5": 90_000, // 90s
|
|
97
|
+
"cli-gemini/gemini-2.5-pro": 180_000,
|
|
98
|
+
"cli-gemini/gemini-2.5-flash": 90_000,
|
|
99
|
+
"cli-gemini/gemini-3-pro-preview": 180_000,
|
|
100
|
+
"cli-gemini/gemini-3-flash-preview": 90_000,
|
|
101
|
+
"openai-codex/gpt-5.4": 300_000,
|
|
102
|
+
"openai-codex/gpt-5.3-codex": 180_000,
|
|
103
|
+
"openai-codex/gpt-5.1-codex-mini": 90_000,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
107
|
+
// Model fallback chain
|
|
108
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Default fallback chain: when a primary model fails (timeout, error),
|
|
112
|
+
* retry once with the lighter variant.
|
|
113
|
+
*/
|
|
114
|
+
export const DEFAULT_MODEL_FALLBACKS: Record<string, string> = {
|
|
115
|
+
"cli-gemini/gemini-2.5-pro": "cli-gemini/gemini-2.5-flash",
|
|
116
|
+
"cli-gemini/gemini-3-pro-preview": "cli-gemini/gemini-3-flash-preview",
|
|
117
|
+
"cli-claude/claude-opus-4-6": "cli-claude/claude-sonnet-4-6",
|
|
118
|
+
"cli-claude/claude-sonnet-4-6": "cli-claude/claude-haiku-4-5",
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
122
|
+
// Paths
|
|
123
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
/** Base directory for all CLI bridge state files. */
|
|
126
|
+
export const OPENCLAW_DIR = join(homedir(), ".openclaw");
|
|
127
|
+
|
|
128
|
+
/** State file — persists the model active before the last /cli-* switch. */
|
|
129
|
+
export const STATE_FILE = join(OPENCLAW_DIR, "cli-bridge-state.json");
|
|
130
|
+
|
|
131
|
+
/** Pending switch file — stores a staged model switch not yet applied. */
|
|
132
|
+
export const PENDING_FILE = join(OPENCLAW_DIR, "cli-bridge-pending.json");
|
|
133
|
+
|
|
134
|
+
/** Provider session registry file. */
|
|
135
|
+
export const PROVIDER_SESSIONS_FILE = join(OPENCLAW_DIR, "cli-bridge", "sessions.json");
|
|
136
|
+
|
|
137
|
+
/** Temporary directory for multimodal media files. */
|
|
138
|
+
export const MEDIA_TMP_DIR = join(tmpdir(), "cli-bridge-media");
|
|
139
|
+
|
|
140
|
+
/** Browser profile directories. */
|
|
141
|
+
export const PROFILE_DIRS = {
|
|
142
|
+
grok: join(OPENCLAW_DIR, "grok-profile"),
|
|
143
|
+
gemini: join(OPENCLAW_DIR, "gemini-profile"),
|
|
144
|
+
claude: join(OPENCLAW_DIR, "claude-profile"),
|
|
145
|
+
chatgpt: join(OPENCLAW_DIR, "chatgpt-profile"),
|
|
146
|
+
} as const;
|
|
147
|
+
|
|
148
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
149
|
+
// Browser automation
|
|
150
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
/** Navigation timeout for Playwright page.goto (ms). */
|
|
153
|
+
export const BROWSER_NAV_TIMEOUT_MS = 15_000;
|
|
154
|
+
|
|
155
|
+
/** Delay after page load before interacting (ms). */
|
|
156
|
+
export const BROWSER_PAGE_LOAD_DELAY_MS = 2_000;
|
|
157
|
+
|
|
158
|
+
/** Delay after typing into input fields (ms). */
|
|
159
|
+
export const BROWSER_INPUT_DELAY_MS = 300;
|
|
160
|
+
|
|
161
|
+
/** Default timeout for browser-based completions (ms). */
|
|
162
|
+
export const BROWSER_COMPLETION_TIMEOUT_MS = 120_000;
|
|
163
|
+
|
|
164
|
+
/** Consecutive stable reads to confirm a streaming response is done. */
|
|
165
|
+
export const BROWSER_STABLE_CHECKS = 3;
|
|
166
|
+
|
|
167
|
+
/** Interval between stability checks (ms). */
|
|
168
|
+
export const BROWSER_STABLE_INTERVAL_MS = 500;
|
|
169
|
+
|
|
170
|
+
/** Gemini uses a longer stability interval due to slower streaming. */
|
|
171
|
+
export const GEMINI_STABLE_INTERVAL_MS = 600;
|
|
172
|
+
|
|
173
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
174
|
+
// Claude auth
|
|
175
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
176
|
+
|
|
177
|
+
/** Refresh OAuth token this many ms before expiry. */
|
|
178
|
+
export const CLAUDE_REFRESH_BEFORE_EXPIRY_MS = 30 * 60 * 1_000; // 30 min
|
|
179
|
+
|
|
180
|
+
/** Sync window for token refresh (ms). */
|
|
181
|
+
export const CLAUDE_REFRESH_SYNC_WINDOW_MS = 5 * 60 * 1_000; // 5 min
|
|
182
|
+
|
|
183
|
+
/** Max wait for a single token refresh attempt (ms). */
|
|
184
|
+
export const CLAUDE_REFRESH_TIMEOUT_MS = 30_000;
|
|
185
|
+
|
|
186
|
+
/** Polling interval for proactive token refresh (ms). */
|
|
187
|
+
export const CLAUDE_REFRESH_POLL_INTERVAL_MS = 10 * 60 * 1_000; // 10 min
|
|
188
|
+
|
|
189
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
190
|
+
// Workdir isolation
|
|
191
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
192
|
+
|
|
193
|
+
/** Prefix for temporary workdir directories. */
|
|
194
|
+
export const WORKDIR_PREFIX = "cli-bridge-";
|
|
195
|
+
|
|
196
|
+
/** Max age for orphaned workdirs before they are swept (ms). */
|
|
197
|
+
export const WORKDIR_ORPHAN_MAX_AGE_MS = 60 * 60 * 1_000; // 1 hour
|
|
198
|
+
|
|
199
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
200
|
+
// BitNet
|
|
201
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
202
|
+
|
|
203
|
+
/** Default URL for the local BitNet llama-server. */
|
|
204
|
+
export const DEFAULT_BITNET_SERVER_URL = "http://127.0.0.1:8082";
|
|
205
|
+
|
|
206
|
+
/** Max messages to send to BitNet (4096 token context limit). */
|
|
207
|
+
export const BITNET_MAX_MESSAGES = 6;
|
|
208
|
+
|
|
209
|
+
/** Minimal system prompt for BitNet to conserve tokens. */
|
|
210
|
+
export const BITNET_SYSTEM_PROMPT =
|
|
211
|
+
"You are Akido, a concise AI assistant. Answer briefly and directly. Current user: Emre. Timezone: Europe/Berlin.";
|
|
212
|
+
|
|
213
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
214
|
+
// Default model for /cli-test
|
|
215
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
export const CLI_TEST_DEFAULT_MODEL = "cli-claude/claude-sonnet-4-6";
|