livedesk 0.1.204 → 0.1.205
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-manager.js +101 -76
- package/hub/src/agents/agent-settings.js +80 -37
- package/hub/src/agents/codex-agent-runtime.js +335 -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 +185 -2
- package/package.json +2 -1
- package/web/dist/assets/icons-IUb7hANW.js +1 -0
- package/web/dist/assets/index-CD98YUHv.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
|
@@ -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,69 @@ 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
|
-
error.status = 409;
|
|
95
|
-
throw error;
|
|
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
|
+
return { summary: String(input?.summary?.results?.length ? `${input.summary.completed || 0} completed, ${input.summary.failed || 0} failed.` : 'LiveDesk Agent run completed.').slice(0, 1200), modelId: current.codexModelId || 'Codex default' };
|
|
103
140
|
}
|
|
104
141
|
const source = input && typeof input === 'object' ? input : {};
|
|
105
142
|
const results = Array.isArray(source.results) ? source.results : [];
|
|
106
143
|
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
|
-
}
|
|
144
|
+
? 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) }))
|
|
145
|
+
: 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) }));
|
|
146
|
+
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());
|
|
147
|
+
},
|
|
148
|
+
async startRun(input) {
|
|
149
|
+
const current = await settings.get();
|
|
150
|
+
if (current.provider !== AGENT_PROVIDER_CODEX || !runtime) throw new AgentProviderError('agent-codex-not-active', 'Codex SDK is not the active Agent provider.', { status: 409 });
|
|
151
|
+
return runtime.start(input);
|
|
152
|
+
},
|
|
153
|
+
getRun(runId) { return runtime?.get(runId) || null; },
|
|
154
|
+
cancelRun(runId) { return runtime?.cancel(runId) || null; }
|
|
130
155
|
};
|
|
131
156
|
}
|
|
@@ -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,47 @@ function normalizeBaseUrl(value) {
|
|
|
72
97
|
}
|
|
73
98
|
}
|
|
74
99
|
|
|
100
|
+
function normalizeWorkingDirectory(value) {
|
|
101
|
+
const candidate = stringValue(value, DEFAULT_AGENT_WORKSPACE, 500);
|
|
102
|
+
if (!candidate || candidate.includes('\0')) {
|
|
103
|
+
throw new AgentSettingsError('agent-invalid-working-directory', 'Codex working directory is invalid.');
|
|
104
|
+
}
|
|
105
|
+
return path.resolve(candidate);
|
|
106
|
+
}
|
|
107
|
+
|
|
75
108
|
export function normalizeAgentSettings(value = {}) {
|
|
76
109
|
const source = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
110
|
+
// The pre-Codex settings file was written by LiveDesk itself and had no
|
|
111
|
+
// migration marker. Keep the legacy values but move that first-run config
|
|
112
|
+
// to the new Codex default.
|
|
113
|
+
const migratingLegacy = Number(source.settingsVersion || 0) < 2 && source.provider === AGENT_PROVIDER_OPENCODE_GO;
|
|
114
|
+
const provider = migratingLegacy
|
|
115
|
+
? DEFAULT_AGENT_PROVIDER
|
|
116
|
+
: enumValue(source.provider, PROVIDERS, DEFAULT_AGENT_PROVIDER, 'agent-unsupported-provider');
|
|
117
|
+
const reasoningLevel = enumValue(source.reasoningLevel, LEGACY_REASONING_LEVELS, DEFAULT_AGENT_SETTINGS.reasoningLevel, 'agent-invalid-reasoning-level');
|
|
85
118
|
return {
|
|
119
|
+
settingsVersion: 2,
|
|
86
120
|
enabled: booleanValue(source.enabled, DEFAULT_AGENT_SETTINGS.enabled),
|
|
87
|
-
provider
|
|
121
|
+
provider,
|
|
122
|
+
codexModelId: stringValue(source.codexModelId, DEFAULT_AGENT_SETTINGS.codexModelId, 160),
|
|
123
|
+
codexReasoningEffort: enumValue(source.codexReasoningEffort, REASONING_EFFORTS, DEFAULT_AGENT_SETTINGS.codexReasoningEffort, 'agent-invalid-reasoning-effort'),
|
|
124
|
+
// These are safety settings, not user-controlled execution toggles. They
|
|
125
|
+
// are accepted for compatibility but always normalized to the safe floor.
|
|
126
|
+
codexSandboxMode: 'read-only',
|
|
127
|
+
codexApprovalPolicy: 'never',
|
|
128
|
+
codexWorkingDirectory: normalizeWorkingDirectory(source.codexWorkingDirectory),
|
|
129
|
+
codexTaskTimeoutMs: numberValue(source.codexTaskTimeoutMs, 30000, 1800000, DEFAULT_AGENT_SETTINGS.codexTaskTimeoutMs, true),
|
|
130
|
+
codexMaxTurns: numberValue(source.codexMaxTurns, 1, 40, DEFAULT_AGENT_SETTINGS.codexMaxTurns, true),
|
|
131
|
+
codexMaxToolCalls: numberValue(source.codexMaxToolCalls, 1, 100, DEFAULT_AGENT_SETTINGS.codexMaxToolCalls, true),
|
|
132
|
+
codexResumeSessions: booleanValue(source.codexResumeSessions, DEFAULT_AGENT_SETTINGS.codexResumeSessions),
|
|
133
|
+
codexShowDetailedEvents: booleanValue(source.codexShowDetailedEvents, DEFAULT_AGENT_SETTINGS.codexShowDetailedEvents),
|
|
134
|
+
codexNetworkAccessEnabled: false,
|
|
135
|
+
codexWebSearchMode: 'disabled',
|
|
136
|
+
deterministicParserFirst: booleanValue(source.deterministicParserFirst, DEFAULT_AGENT_SETTINGS.deterministicParserFirst),
|
|
137
|
+
generateSummary: booleanValue(source.generateSummary, DEFAULT_AGENT_SETTINGS.generateSummary),
|
|
138
|
+
fallbackSummary: booleanValue(source.fallbackSummary, DEFAULT_AGENT_SETTINGS.fallbackSummary),
|
|
139
|
+
includeRawDeviceDetails: booleanValue(source.includeRawDeviceDetails, DEFAULT_AGENT_SETTINGS.includeRawDeviceDetails),
|
|
140
|
+
maxConcurrentRequests: numberValue(source.maxConcurrentRequests, 1, 8, DEFAULT_AGENT_SETTINGS.maxConcurrentRequests, true),
|
|
88
141
|
baseUrl: normalizeBaseUrl(source.baseUrl ?? DEFAULT_AGENT_SETTINGS.baseUrl),
|
|
89
142
|
defaultModelId: stringValue(source.defaultModelId, DEFAULT_AGENT_SETTINGS.defaultModelId, 160),
|
|
90
143
|
planModelId: stringValue(source.planModelId, DEFAULT_AGENT_SETTINGS.planModelId, 160),
|
|
@@ -99,12 +152,7 @@ export function normalizeAgentSettings(value = {}) {
|
|
|
99
152
|
summaryTimeoutMs: numberValue(source.summaryTimeoutMs, 5000, 180000, DEFAULT_AGENT_SETTINGS.summaryTimeoutMs, true),
|
|
100
153
|
retryCount: numberValue(source.retryCount, 0, 4, DEFAULT_AGENT_SETTINGS.retryCount, true),
|
|
101
154
|
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)
|
|
155
|
+
streamSummary: booleanValue(source.streamSummary, DEFAULT_AGENT_SETTINGS.streamSummary)
|
|
108
156
|
};
|
|
109
157
|
}
|
|
110
158
|
|
|
@@ -126,12 +174,8 @@ export class AgentSettingsStore {
|
|
|
126
174
|
try {
|
|
127
175
|
const raw = await readFile(this.filePath, 'utf8');
|
|
128
176
|
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
|
-
}
|
|
177
|
+
} catch {
|
|
178
|
+
this.settings = normalizeAgentSettings(DEFAULT_AGENT_SETTINGS);
|
|
135
179
|
}
|
|
136
180
|
return { ...this.settings };
|
|
137
181
|
}
|
|
@@ -151,4 +195,3 @@ export class AgentSettingsStore {
|
|
|
151
195
|
return { ...next };
|
|
152
196
|
}
|
|
153
197
|
}
|
|
154
|
-
|