livedesk 0.1.204 → 0.1.206
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/hub/package.json +1 -0
- package/hub/src/agents/agent-device-scope.js +18 -0
- package/hub/src/agents/agent-manager.js +103 -76
- package/hub/src/agents/agent-settings.js +78 -37
- package/hub/src/agents/codex-agent-runtime.js +486 -0
- package/hub/src/agents/codex-mcp-server.js +94 -0
- package/hub/src/agents/provider-errors.js +0 -2
- package/hub/src/agents/secret-store.js +0 -2
- package/hub/src/server.js +222 -2
- package/package.json +2 -1
- package/web/dist/assets/icons-IUb7hANW.js +1 -0
- package/web/dist/assets/index-BZn8XWvN.js +15 -0
- package/web/dist/assets/{react-CbyLy_8G.js → react-iKD0ILd2.js} +1 -1
- package/web/dist/index.html +3 -3
- package/web/dist/assets/icons-Bnj2CBHL.js +0 -1
- package/web/dist/assets/index-D0_InGk0.js +0 -15
package/hub/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function normalizeIds(value) {
|
|
2
|
+
const source = Array.isArray(value) ? value : [];
|
|
3
|
+
return [...new Set(source.map(item => String(item || '').trim()).filter(Boolean))].slice(0, 500);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function createAgentDeviceScope(allowedDeviceIds, fallbackDeviceIds = []) {
|
|
7
|
+
const requested = normalizeIds(allowedDeviceIds);
|
|
8
|
+
const fallback = normalizeIds(fallbackDeviceIds);
|
|
9
|
+
return new Set(requested.length > 0 ? requested : fallback);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function selectAgentDeviceIds({ allowedDeviceIds, requestedDeviceIds, connectedDeviceIds }) {
|
|
13
|
+
const allowed = allowedDeviceIds instanceof Set ? allowedDeviceIds : new Set(normalizeIds(allowedDeviceIds));
|
|
14
|
+
const requested = normalizeIds(requestedDeviceIds);
|
|
15
|
+
const connected = new Set(normalizeIds(connectedDeviceIds));
|
|
16
|
+
const candidates = requested.length > 0 ? requested : [...allowed];
|
|
17
|
+
return candidates.filter(deviceId => allowed.has(deviceId) && connected.has(deviceId));
|
|
18
|
+
}
|
|
@@ -1,44 +1,84 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { AgentSettingsStore } from './agent-settings.js';
|
|
3
|
+
import { AgentSettingsStore, AGENT_PROVIDER_CODEX, AGENT_PROVIDER_OPENCODE_GO } from './agent-settings.js';
|
|
4
4
|
import { createOsSecretStore } from './secret-store.js';
|
|
5
5
|
import { createOpenCodeGoProvider } from './opencode-go-provider.js';
|
|
6
|
+
import { AgentProviderError } from './provider-errors.js';
|
|
7
|
+
import { createCodexAgentRuntime } from './codex-agent-runtime.js';
|
|
6
8
|
|
|
7
9
|
function maskApiKey(value) {
|
|
8
10
|
const key = String(value || '');
|
|
9
11
|
return key.length >= 4 ? `••••${key.slice(-4)}` : '';
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
function publicCodexStatus(status = {}) {
|
|
15
|
+
return {
|
|
16
|
+
installed: status.installed === true,
|
|
17
|
+
authenticated: ['signed-in', 'not-signed-in'].includes(status.authenticated) ? status.authenticated : 'unknown',
|
|
18
|
+
status: String(status.status || 'unknown').slice(0, 40),
|
|
19
|
+
codexPath: String(status.codexPath || '').slice(0, 500),
|
|
20
|
+
detail: String(status.detail || '').slice(0, 300)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createAgentManager({
|
|
25
|
+
dataDir = path.join(os.homedir(), '.livedesk'),
|
|
26
|
+
settingsStore,
|
|
27
|
+
secretStore,
|
|
28
|
+
provider,
|
|
29
|
+
codexRuntime
|
|
30
|
+
} = {}) {
|
|
13
31
|
const settings = settingsStore || new AgentSettingsStore({ dataDir });
|
|
14
32
|
const secrets = secretStore || createOsSecretStore({ dataDir });
|
|
15
|
-
const
|
|
33
|
+
const legacyProvider = provider || createOpenCodeGoProvider();
|
|
34
|
+
const runtime = codexRuntime;
|
|
35
|
+
let statusCache = { expiresAt: 0, value: null };
|
|
36
|
+
|
|
37
|
+
async function getCodexStatus() {
|
|
38
|
+
if (!runtime) return { installed: false, authenticated: 'unknown', status: 'unavailable', codexPath: '' };
|
|
39
|
+
if (statusCache.value && statusCache.expiresAt > Date.now()) return statusCache.value;
|
|
40
|
+
const value = publicCodexStatus(await runtime.getStatus());
|
|
41
|
+
statusCache = { value, expiresAt: Date.now() + 10000 };
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
16
44
|
|
|
17
45
|
async function publicSettings() {
|
|
18
46
|
const current = await settings.get();
|
|
19
47
|
let hasApiKey = false;
|
|
20
48
|
let apiKeyPreview = '';
|
|
21
49
|
let secretStoreAvailable = true;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
50
|
+
if (current.provider === AGENT_PROVIDER_OPENCODE_GO) {
|
|
51
|
+
try {
|
|
52
|
+
const key = await secrets.getApiKey(AGENT_PROVIDER_OPENCODE_GO);
|
|
53
|
+
hasApiKey = Boolean(key);
|
|
54
|
+
apiKeyPreview = maskApiKey(key);
|
|
55
|
+
} catch {
|
|
56
|
+
secretStoreAvailable = false;
|
|
57
|
+
}
|
|
28
58
|
}
|
|
29
|
-
|
|
59
|
+
const codex = await getCodexStatus();
|
|
60
|
+
return {
|
|
61
|
+
...current,
|
|
62
|
+
hasApiKey,
|
|
63
|
+
apiKeyPreview,
|
|
64
|
+
secretStoreAvailable,
|
|
65
|
+
codexInstallation: codex.installed ? 'installed' : 'not-installed',
|
|
66
|
+
codexAuth: codex.authenticated,
|
|
67
|
+
codexStatus: codex.status,
|
|
68
|
+
codexPath: codex.codexPath,
|
|
69
|
+
agentWorkspacePath: current.codexWorkingDirectory
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function legacyApiKey() {
|
|
74
|
+
const key = await secrets.getApiKey(AGENT_PROVIDER_OPENCODE_GO);
|
|
75
|
+
if (!key) throw new AgentProviderError('agent-api-key-missing', 'OpenCode Go API key is not configured.', { status: 401 });
|
|
76
|
+
return key;
|
|
30
77
|
}
|
|
31
78
|
|
|
32
|
-
async function
|
|
79
|
+
async function currentProvider() {
|
|
33
80
|
const current = await settings.get();
|
|
34
|
-
|
|
35
|
-
if (!apiKey) {
|
|
36
|
-
const error = new Error('OpenCode Go API key is not configured.');
|
|
37
|
-
error.code = 'agent-api-key-missing';
|
|
38
|
-
error.status = 401;
|
|
39
|
-
throw error;
|
|
40
|
-
}
|
|
41
|
-
return { current, apiKey };
|
|
81
|
+
return { current, active: current.provider === AGENT_PROVIDER_CODEX ? runtime : legacyProvider };
|
|
42
82
|
}
|
|
43
83
|
|
|
44
84
|
return {
|
|
@@ -48,84 +88,71 @@ export function createAgentManager({ dataDir = path.join(os.homedir(), '.livedes
|
|
|
48
88
|
const apiKey = typeof nextPatch.apiKey === 'string' ? nextPatch.apiKey.trim() : '';
|
|
49
89
|
delete nextPatch.apiKey;
|
|
50
90
|
const current = await settings.get();
|
|
51
|
-
|
|
91
|
+
const requestedProvider = String(nextPatch.provider || current.provider);
|
|
92
|
+
if (apiKey) {
|
|
93
|
+
if (requestedProvider !== AGENT_PROVIDER_OPENCODE_GO) {
|
|
94
|
+
throw new AgentProviderError('agent-codex-does-not-use-api-key', 'Codex authentication is owned by the installed Codex CLI.', { status: 400 });
|
|
95
|
+
}
|
|
96
|
+
await secrets.setApiKey(AGENT_PROVIDER_OPENCODE_GO, apiKey);
|
|
97
|
+
}
|
|
52
98
|
await settings.update(nextPatch);
|
|
99
|
+
statusCache = { expiresAt: 0, value: null };
|
|
53
100
|
return publicSettings();
|
|
54
101
|
},
|
|
55
102
|
async resetSettings() {
|
|
56
103
|
await settings.reset();
|
|
104
|
+
statusCache = { expiresAt: 0, value: null };
|
|
57
105
|
return publicSettings();
|
|
58
106
|
},
|
|
59
107
|
async deleteApiKey() {
|
|
60
|
-
|
|
61
|
-
await secrets.deleteApiKey(current.provider);
|
|
108
|
+
await secrets.deleteApiKey(AGENT_PROVIDER_OPENCODE_GO);
|
|
62
109
|
return publicSettings();
|
|
63
110
|
},
|
|
64
111
|
async getModels() {
|
|
65
|
-
const { current,
|
|
66
|
-
|
|
112
|
+
const { current, active } = await currentProvider();
|
|
113
|
+
if (current.provider === AGENT_PROVIDER_CODEX) {
|
|
114
|
+
return [{ id: '', name: 'Codex default', protocol: 'codex-sdk', available: true, capabilities: { supportsReasoningLevel: true, supportsStreaming: true, supportsTools: true } }];
|
|
115
|
+
}
|
|
116
|
+
return active.getModels(current, await legacyApiKey());
|
|
67
117
|
},
|
|
68
118
|
async testConnection() {
|
|
69
|
-
const { current,
|
|
70
|
-
|
|
119
|
+
const { current, active } = await currentProvider();
|
|
120
|
+
if (current.provider === AGENT_PROVIDER_CODEX) {
|
|
121
|
+
if (!active) throw new AgentProviderError('codex-sdk-not-installed', 'Codex SDK is not installed.', { status: 503 });
|
|
122
|
+
statusCache = { expiresAt: 0, value: null };
|
|
123
|
+
return active.testConnection();
|
|
124
|
+
}
|
|
125
|
+
return active.testConnection(current, await legacyApiKey());
|
|
71
126
|
},
|
|
72
127
|
async createPlan(input) {
|
|
73
|
-
const current = await
|
|
74
|
-
if (!current.enabled) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
error.status = 409;
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
const apiKey = await secrets.getApiKey(current.provider);
|
|
81
|
-
if (!apiKey) {
|
|
82
|
-
const error = new Error('OpenCode Go API key is not configured.');
|
|
83
|
-
error.code = 'agent-api-key-missing';
|
|
84
|
-
error.status = 401;
|
|
85
|
-
throw error;
|
|
128
|
+
const { current, active } = await currentProvider();
|
|
129
|
+
if (!current.enabled) throw new AgentProviderError('agent-ai-disabled', 'Agent AI is disabled in Settings.', { status: 409 });
|
|
130
|
+
if (current.provider === AGENT_PROVIDER_CODEX) {
|
|
131
|
+
throw new AgentProviderError('agent-codex-run-required', 'Codex runs use the LiveDesk tool loop.', { status: 409 });
|
|
86
132
|
}
|
|
87
|
-
return
|
|
133
|
+
return active.createPlan(input, current, await legacyApiKey());
|
|
88
134
|
},
|
|
89
135
|
async createSummary(input) {
|
|
90
|
-
const current = await
|
|
91
|
-
if (!current.enabled || !current.generateSummary) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
const apiKey = await secrets.getApiKey(current.provider);
|
|
98
|
-
if (!apiKey) {
|
|
99
|
-
const error = new Error('OpenCode Go API key is not configured.');
|
|
100
|
-
error.code = 'agent-api-key-missing';
|
|
101
|
-
error.status = 401;
|
|
102
|
-
throw error;
|
|
136
|
+
const { current, active } = await currentProvider();
|
|
137
|
+
if (!current.enabled || !current.generateSummary) throw new AgentProviderError('agent-summary-disabled', 'Agent summaries are disabled in Settings.', { status: 409 });
|
|
138
|
+
if (current.provider === AGENT_PROVIDER_CODEX) {
|
|
139
|
+
const source = input && typeof input === 'object' ? input : {};
|
|
140
|
+
const results = Array.isArray(source.results) ? source.results : [];
|
|
141
|
+
return { summary: String(results.length ? `${source.completed || 0} completed, ${source.failed || 0} failed.` : 'LiveDesk Agent run completed.').slice(0, 1200), modelId: current.codexModelId || 'Codex default' };
|
|
103
142
|
}
|
|
104
143
|
const source = input && typeof input === 'object' ? input : {};
|
|
105
144
|
const results = Array.isArray(source.results) ? source.results : [];
|
|
106
145
|
const safeResults = current.includeRawDeviceDetails
|
|
107
|
-
? results.map(result => ({
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}));
|
|
119
|
-
return agentProvider.createSummary({
|
|
120
|
-
instruction: String(source.instruction || '').slice(0, 500),
|
|
121
|
-
operation: String(source.operation || '').slice(0, 80),
|
|
122
|
-
summary: {
|
|
123
|
-
total: Number(source.total || results.length),
|
|
124
|
-
completed: Number(source.completed || 0),
|
|
125
|
-
failed: Number(source.failed || 0),
|
|
126
|
-
results: safeResults
|
|
127
|
-
}
|
|
128
|
-
}, current, apiKey);
|
|
129
|
-
}
|
|
146
|
+
? results.map(result => ({ deviceName: String(result?.deviceName || '').slice(0, 120), status: String(result?.status || '').slice(0, 40), result: String(result?.result || '').slice(0, 1200), error: String(result?.error || '').slice(0, 500) }))
|
|
147
|
+
: results.map(result => ({ deviceName: String(result?.deviceName || '').slice(0, 120), status: String(result?.status || '').slice(0, 40), hasResult: Boolean(result?.result), hasError: Boolean(result?.error) }));
|
|
148
|
+
return active.createSummary({ instruction: String(source.instruction || '').slice(0, 500), operation: String(source.operation || '').slice(0, 80), summary: { total: Number(source.total || results.length), completed: Number(source.completed || 0), failed: Number(source.failed || 0), results: safeResults } }, current, await legacyApiKey());
|
|
149
|
+
},
|
|
150
|
+
async startRun(input) {
|
|
151
|
+
const current = await settings.get();
|
|
152
|
+
if (current.provider !== AGENT_PROVIDER_CODEX || !runtime) throw new AgentProviderError('agent-codex-not-active', 'Codex SDK is not the active Agent provider.', { status: 409 });
|
|
153
|
+
return runtime.start(input);
|
|
154
|
+
},
|
|
155
|
+
getRun(runId) { return runtime?.get(runId) || null; },
|
|
156
|
+
cancelRun(runId) { return runtime?.cancel(runId) || null; }
|
|
130
157
|
};
|
|
131
158
|
}
|
|
@@ -2,12 +2,33 @@ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
|
-
export const
|
|
5
|
+
export const AGENT_PROVIDER_CODEX = 'codex';
|
|
6
|
+
export const AGENT_PROVIDER_OPENCODE_GO = 'opencode-go';
|
|
7
|
+
export const DEFAULT_AGENT_PROVIDER = AGENT_PROVIDER_CODEX;
|
|
6
8
|
export const DEFAULT_AGENT_BASE_URL = 'https://opencode.ai/zen/go/v1';
|
|
7
|
-
|
|
9
|
+
export const DEFAULT_CODEX_MODEL_ID = '';
|
|
10
|
+
export const DEFAULT_AGENT_WORKSPACE = path.join(os.homedir(), '.livedesk', 'agent-workspace');
|
|
8
11
|
export const DEFAULT_AGENT_SETTINGS = Object.freeze({
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
settingsVersion: 2,
|
|
13
|
+
enabled: true,
|
|
14
|
+
provider: DEFAULT_AGENT_PROVIDER,
|
|
15
|
+
codexModelId: DEFAULT_CODEX_MODEL_ID,
|
|
16
|
+
codexReasoningEffort: 'medium',
|
|
17
|
+
codexSandboxMode: 'read-only',
|
|
18
|
+
codexApprovalPolicy: 'never',
|
|
19
|
+
codexWorkingDirectory: DEFAULT_AGENT_WORKSPACE,
|
|
20
|
+
codexTaskTimeoutMs: 600000,
|
|
21
|
+
codexMaxTurns: 12,
|
|
22
|
+
codexMaxToolCalls: 20,
|
|
23
|
+
codexResumeSessions: true,
|
|
24
|
+
codexShowDetailedEvents: true,
|
|
25
|
+
codexNetworkAccessEnabled: false,
|
|
26
|
+
codexWebSearchMode: 'disabled',
|
|
27
|
+
deterministicParserFirst: true,
|
|
28
|
+
generateSummary: true,
|
|
29
|
+
fallbackSummary: true,
|
|
30
|
+
includeRawDeviceDetails: false,
|
|
31
|
+
maxConcurrentRequests: 2,
|
|
11
32
|
baseUrl: DEFAULT_AGENT_BASE_URL,
|
|
12
33
|
defaultModelId: 'deepseek-v4-flash',
|
|
13
34
|
planModelId: '',
|
|
@@ -22,15 +43,15 @@ export const DEFAULT_AGENT_SETTINGS = Object.freeze({
|
|
|
22
43
|
summaryTimeoutMs: 60000,
|
|
23
44
|
retryCount: 1,
|
|
24
45
|
retryDelayMs: 1000,
|
|
25
|
-
|
|
26
|
-
streamSummary: false,
|
|
27
|
-
deterministicParserFirst: true,
|
|
28
|
-
generateSummary: true,
|
|
29
|
-
fallbackSummary: true,
|
|
30
|
-
includeRawDeviceDetails: false
|
|
46
|
+
streamSummary: false
|
|
31
47
|
});
|
|
32
48
|
|
|
33
|
-
const
|
|
49
|
+
const PROVIDERS = new Set([AGENT_PROVIDER_CODEX, AGENT_PROVIDER_OPENCODE_GO]);
|
|
50
|
+
const REASONING_EFFORTS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh']);
|
|
51
|
+
const SANDBOX_MODES = new Set(['read-only', 'workspace-write', 'danger-full-access']);
|
|
52
|
+
const APPROVAL_POLICIES = new Set(['never', 'on-request', 'on-failure', 'untrusted']);
|
|
53
|
+
const WEB_SEARCH_MODES = new Set(['disabled', 'cached', 'live']);
|
|
54
|
+
const LEGACY_REASONING_LEVELS = new Set(['auto', 'low', 'medium', 'high']);
|
|
34
55
|
|
|
35
56
|
export class AgentSettingsError extends Error {
|
|
36
57
|
constructor(code, message) {
|
|
@@ -57,13 +78,17 @@ function stringValue(value, fallback, maxLength = 240) {
|
|
|
57
78
|
return value.trim().slice(0, maxLength);
|
|
58
79
|
}
|
|
59
80
|
|
|
81
|
+
function enumValue(value, allowed, fallback, code) {
|
|
82
|
+
const normalized = stringValue(value, fallback, 80).toLowerCase();
|
|
83
|
+
if (!allowed.has(normalized)) throw new AgentSettingsError(code, `Invalid agent setting: ${normalized}.`);
|
|
84
|
+
return normalized;
|
|
85
|
+
}
|
|
86
|
+
|
|
60
87
|
function normalizeBaseUrl(value) {
|
|
61
|
-
const candidate = stringValue(value,
|
|
88
|
+
const candidate = stringValue(value, DEFAULT_AGENT_SETTINGS.baseUrl, 500).replace(/\/+$/, '');
|
|
62
89
|
try {
|
|
63
90
|
const parsed = new URL(candidate);
|
|
64
|
-
if (!['http:', 'https:'].includes(parsed.protocol) || !parsed.hostname)
|
|
65
|
-
throw new Error('invalid protocol');
|
|
66
|
-
}
|
|
91
|
+
if (!['http:', 'https:'].includes(parsed.protocol) || !parsed.hostname) throw new Error('invalid protocol');
|
|
67
92
|
parsed.hash = '';
|
|
68
93
|
parsed.search = '';
|
|
69
94
|
return parsed.toString().replace(/\/+$/, '');
|
|
@@ -72,19 +97,45 @@ function normalizeBaseUrl(value) {
|
|
|
72
97
|
}
|
|
73
98
|
}
|
|
74
99
|
|
|
100
|
+
function normalizeWorkingDirectory(value) {
|
|
101
|
+
// The agent runtime owns this directory. Do not allow a browser/API caller
|
|
102
|
+
// to move Codex into a user project or an arbitrary filesystem root.
|
|
103
|
+
return DEFAULT_AGENT_WORKSPACE;
|
|
104
|
+
}
|
|
105
|
+
|
|
75
106
|
export function normalizeAgentSettings(value = {}) {
|
|
76
107
|
const source = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
108
|
+
// The pre-Codex settings file was written by LiveDesk itself and had no
|
|
109
|
+
// migration marker. Keep the legacy values but move that first-run config
|
|
110
|
+
// to the new Codex default.
|
|
111
|
+
const migratingLegacy = Number(source.settingsVersion || 0) < 2 && source.provider === AGENT_PROVIDER_OPENCODE_GO;
|
|
112
|
+
const provider = migratingLegacy
|
|
113
|
+
? DEFAULT_AGENT_PROVIDER
|
|
114
|
+
: enumValue(source.provider, PROVIDERS, DEFAULT_AGENT_PROVIDER, 'agent-unsupported-provider');
|
|
115
|
+
const reasoningLevel = enumValue(source.reasoningLevel, LEGACY_REASONING_LEVELS, DEFAULT_AGENT_SETTINGS.reasoningLevel, 'agent-invalid-reasoning-level');
|
|
85
116
|
return {
|
|
117
|
+
settingsVersion: 2,
|
|
86
118
|
enabled: booleanValue(source.enabled, DEFAULT_AGENT_SETTINGS.enabled),
|
|
87
|
-
provider
|
|
119
|
+
provider,
|
|
120
|
+
codexModelId: stringValue(source.codexModelId, DEFAULT_AGENT_SETTINGS.codexModelId, 160),
|
|
121
|
+
codexReasoningEffort: enumValue(source.codexReasoningEffort, REASONING_EFFORTS, DEFAULT_AGENT_SETTINGS.codexReasoningEffort, 'agent-invalid-reasoning-effort'),
|
|
122
|
+
// These are safety settings, not user-controlled execution toggles. They
|
|
123
|
+
// are accepted for compatibility but always normalized to the safe floor.
|
|
124
|
+
codexSandboxMode: 'read-only',
|
|
125
|
+
codexApprovalPolicy: 'never',
|
|
126
|
+
codexWorkingDirectory: normalizeWorkingDirectory(source.codexWorkingDirectory),
|
|
127
|
+
codexTaskTimeoutMs: numberValue(source.codexTaskTimeoutMs, 30000, 1800000, DEFAULT_AGENT_SETTINGS.codexTaskTimeoutMs, true),
|
|
128
|
+
codexMaxTurns: numberValue(source.codexMaxTurns, 1, 40, DEFAULT_AGENT_SETTINGS.codexMaxTurns, true),
|
|
129
|
+
codexMaxToolCalls: numberValue(source.codexMaxToolCalls, 1, 100, DEFAULT_AGENT_SETTINGS.codexMaxToolCalls, true),
|
|
130
|
+
codexResumeSessions: booleanValue(source.codexResumeSessions, DEFAULT_AGENT_SETTINGS.codexResumeSessions),
|
|
131
|
+
codexShowDetailedEvents: booleanValue(source.codexShowDetailedEvents, DEFAULT_AGENT_SETTINGS.codexShowDetailedEvents),
|
|
132
|
+
codexNetworkAccessEnabled: false,
|
|
133
|
+
codexWebSearchMode: 'disabled',
|
|
134
|
+
deterministicParserFirst: booleanValue(source.deterministicParserFirst, DEFAULT_AGENT_SETTINGS.deterministicParserFirst),
|
|
135
|
+
generateSummary: booleanValue(source.generateSummary, DEFAULT_AGENT_SETTINGS.generateSummary),
|
|
136
|
+
fallbackSummary: booleanValue(source.fallbackSummary, DEFAULT_AGENT_SETTINGS.fallbackSummary),
|
|
137
|
+
includeRawDeviceDetails: booleanValue(source.includeRawDeviceDetails, DEFAULT_AGENT_SETTINGS.includeRawDeviceDetails),
|
|
138
|
+
maxConcurrentRequests: numberValue(source.maxConcurrentRequests, 1, 8, DEFAULT_AGENT_SETTINGS.maxConcurrentRequests, true),
|
|
88
139
|
baseUrl: normalizeBaseUrl(source.baseUrl ?? DEFAULT_AGENT_SETTINGS.baseUrl),
|
|
89
140
|
defaultModelId: stringValue(source.defaultModelId, DEFAULT_AGENT_SETTINGS.defaultModelId, 160),
|
|
90
141
|
planModelId: stringValue(source.planModelId, DEFAULT_AGENT_SETTINGS.planModelId, 160),
|
|
@@ -99,12 +150,7 @@ export function normalizeAgentSettings(value = {}) {
|
|
|
99
150
|
summaryTimeoutMs: numberValue(source.summaryTimeoutMs, 5000, 180000, DEFAULT_AGENT_SETTINGS.summaryTimeoutMs, true),
|
|
100
151
|
retryCount: numberValue(source.retryCount, 0, 4, DEFAULT_AGENT_SETTINGS.retryCount, true),
|
|
101
152
|
retryDelayMs: numberValue(source.retryDelayMs, 100, 10000, DEFAULT_AGENT_SETTINGS.retryDelayMs, true),
|
|
102
|
-
|
|
103
|
-
streamSummary: booleanValue(source.streamSummary, DEFAULT_AGENT_SETTINGS.streamSummary),
|
|
104
|
-
deterministicParserFirst: booleanValue(source.deterministicParserFirst, DEFAULT_AGENT_SETTINGS.deterministicParserFirst),
|
|
105
|
-
generateSummary: booleanValue(source.generateSummary, DEFAULT_AGENT_SETTINGS.generateSummary),
|
|
106
|
-
fallbackSummary: booleanValue(source.fallbackSummary, DEFAULT_AGENT_SETTINGS.fallbackSummary),
|
|
107
|
-
includeRawDeviceDetails: booleanValue(source.includeRawDeviceDetails, DEFAULT_AGENT_SETTINGS.includeRawDeviceDetails)
|
|
153
|
+
streamSummary: booleanValue(source.streamSummary, DEFAULT_AGENT_SETTINGS.streamSummary)
|
|
108
154
|
};
|
|
109
155
|
}
|
|
110
156
|
|
|
@@ -126,12 +172,8 @@ export class AgentSettingsStore {
|
|
|
126
172
|
try {
|
|
127
173
|
const raw = await readFile(this.filePath, 'utf8');
|
|
128
174
|
this.settings = normalizeAgentSettings(JSON.parse(raw));
|
|
129
|
-
} catch
|
|
130
|
-
|
|
131
|
-
this.settings = normalizeAgentSettings(DEFAULT_AGENT_SETTINGS);
|
|
132
|
-
} else {
|
|
133
|
-
this.settings = normalizeAgentSettings(DEFAULT_AGENT_SETTINGS);
|
|
134
|
-
}
|
|
175
|
+
} catch {
|
|
176
|
+
this.settings = normalizeAgentSettings(DEFAULT_AGENT_SETTINGS);
|
|
135
177
|
}
|
|
136
178
|
return { ...this.settings };
|
|
137
179
|
}
|
|
@@ -151,4 +193,3 @@ export class AgentSettingsStore {
|
|
|
151
193
|
return { ...next };
|
|
152
194
|
}
|
|
153
195
|
}
|
|
154
|
-
|