@yeaft/webchat-agent 0.1.413 → 0.1.415
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/connection/message-router.js +14 -0
- package/package.json +1 -1
- package/unify/config-api.js +117 -0
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import { sendToServer, flushMessageBuffer } from './buffer.js';
|
|
25
25
|
import { handleRestartAgent, handleUpgradeAgent } from './upgrade.js';
|
|
26
26
|
import { loadMcpServers, updateMcpConfig } from '../mcp.js';
|
|
27
|
+
import { getLlmConfig, updateLlmConfig } from '../unify/config-api.js';
|
|
27
28
|
|
|
28
29
|
export async function handleMessage(msg) {
|
|
29
30
|
switch (msg.type) {
|
|
@@ -304,5 +305,18 @@ export async function handleMessage(msg) {
|
|
|
304
305
|
sendToServer({ type: 'mcp_config_updated', servers: updated });
|
|
305
306
|
break;
|
|
306
307
|
}
|
|
308
|
+
|
|
309
|
+
// LLM configuration (read/write ~/.yeaft/config.json)
|
|
310
|
+
case 'get_llm_config': {
|
|
311
|
+
const config = getLlmConfig(ctx.CONFIG?.yeaftDir);
|
|
312
|
+
sendToServer({ type: 'llm_config', ...config });
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
case 'update_llm_config': {
|
|
317
|
+
const result = updateLlmConfig(msg.config || {}, ctx.CONFIG?.yeaftDir);
|
|
318
|
+
sendToServer({ type: 'llm_config_updated', ...result });
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
307
321
|
}
|
|
308
322
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config-api.js — Read/write Yeaft config.json for remote management
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to get and update the LLM-related portion of
|
|
5
|
+
* ~/.yeaft/config.json via WebSocket messages from the web UI.
|
|
6
|
+
*
|
|
7
|
+
* Only exposes provider/model configuration — not internal fields
|
|
8
|
+
* like maxContinueTurns or debug that don't belong in the UI.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { DEFAULT_YEAFT_DIR } from './init.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Read the LLM-relevant portion of config.json.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} [dir] — Yeaft data directory
|
|
19
|
+
* @returns {{ providers, primaryModel, fastModel, language } | { error: string }}
|
|
20
|
+
*/
|
|
21
|
+
export function getLlmConfig(dir) {
|
|
22
|
+
const root = dir || process.env.YEAFT_DIR || DEFAULT_YEAFT_DIR;
|
|
23
|
+
const configPath = join(root, 'config.json');
|
|
24
|
+
|
|
25
|
+
if (!existsSync(configPath)) {
|
|
26
|
+
return { providers: [], primaryModel: null, fastModel: null, language: 'en', needsSetup: true };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const raw = readFileSync(configPath, 'utf8');
|
|
31
|
+
const json = JSON.parse(raw);
|
|
32
|
+
const providers = Array.isArray(json.providers) ? json.providers : [];
|
|
33
|
+
|
|
34
|
+
// Detect if config still has default/placeholder values (first-time setup needed)
|
|
35
|
+
const needsSetup = providers.length === 0 || providers.every(p =>
|
|
36
|
+
p.apiKey === 'proxy' || p.apiKey === '' || !p.apiKey
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
providers,
|
|
41
|
+
primaryModel: json.primaryModel || null,
|
|
42
|
+
fastModel: json.fastModel || null,
|
|
43
|
+
language: json.language || 'en',
|
|
44
|
+
needsSetup,
|
|
45
|
+
};
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return { error: `Failed to read config.json: ${e.message}` };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Update the LLM-relevant portion of config.json.
|
|
53
|
+
* Merges into existing config — preserves fields like debug, maxContextTokens, etc.
|
|
54
|
+
*
|
|
55
|
+
* @param {object} update — { providers?, primaryModel?, fastModel?, language? }
|
|
56
|
+
* @param {string} [dir] — Yeaft data directory
|
|
57
|
+
* @returns {{ providers, primaryModel, fastModel, language } | { error: string }}
|
|
58
|
+
*/
|
|
59
|
+
export function updateLlmConfig(update, dir) {
|
|
60
|
+
const root = dir || process.env.YEAFT_DIR || DEFAULT_YEAFT_DIR;
|
|
61
|
+
const configPath = join(root, 'config.json');
|
|
62
|
+
|
|
63
|
+
// Read existing config (preserve non-LLM fields)
|
|
64
|
+
let existing = {};
|
|
65
|
+
if (existsSync(configPath)) {
|
|
66
|
+
try {
|
|
67
|
+
existing = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
68
|
+
} catch {
|
|
69
|
+
// Start fresh if corrupt
|
|
70
|
+
existing = {};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Validate providers structure
|
|
75
|
+
if (update.providers !== undefined) {
|
|
76
|
+
if (!Array.isArray(update.providers)) {
|
|
77
|
+
return { error: 'providers must be an array' };
|
|
78
|
+
}
|
|
79
|
+
for (const p of update.providers) {
|
|
80
|
+
if (!p.name || typeof p.name !== 'string') {
|
|
81
|
+
return { error: 'Each provider must have a name' };
|
|
82
|
+
}
|
|
83
|
+
if (!p.baseUrl || typeof p.baseUrl !== 'string') {
|
|
84
|
+
return { error: `Provider "${p.name}" must have a baseUrl` };
|
|
85
|
+
}
|
|
86
|
+
if (!Array.isArray(p.models) || p.models.length === 0) {
|
|
87
|
+
return { error: `Provider "${p.name}" must have at least one model` };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
existing.providers = update.providers;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Update model selections
|
|
94
|
+
if (update.primaryModel !== undefined) {
|
|
95
|
+
existing.primaryModel = update.primaryModel || null;
|
|
96
|
+
}
|
|
97
|
+
if (update.fastModel !== undefined) {
|
|
98
|
+
existing.fastModel = update.fastModel || null;
|
|
99
|
+
}
|
|
100
|
+
if (update.language !== undefined) {
|
|
101
|
+
existing.language = update.language;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Write back
|
|
105
|
+
try {
|
|
106
|
+
writeFileSync(configPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
107
|
+
} catch (e) {
|
|
108
|
+
return { error: `Failed to write config.json: ${e.message}` };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
providers: Array.isArray(existing.providers) ? existing.providers : [],
|
|
113
|
+
primaryModel: existing.primaryModel || null,
|
|
114
|
+
fastModel: existing.fastModel || null,
|
|
115
|
+
language: existing.language || 'en',
|
|
116
|
+
};
|
|
117
|
+
}
|