wtt-connect 0.2.17 → 0.2.18
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/package.json +1 -1
- package/src/runner.js +18 -1
- package/src/runtime-info.js +78 -10
- package/src/store.js +12 -1
package/package.json
CHANGED
package/src/runner.js
CHANGED
|
@@ -72,7 +72,7 @@ export class Runner {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
runtimeInfo() {
|
|
75
|
-
return buildRuntimeInfo(this.config);
|
|
75
|
+
return buildRuntimeInfo(this.config, this.store.getRuntime());
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
async onEvent(msg) {
|
|
@@ -167,10 +167,13 @@ export class Runner {
|
|
|
167
167
|
const staged = await this.attachments.stageMessage(m);
|
|
168
168
|
if (!content && !staged.files.length) return;
|
|
169
169
|
await this.wtt.typing(topicId, 'start', { statusText: 'Agent 已接收消息,正在准备执行', statusKind: 'queued', ttlMs: 30000 });
|
|
170
|
+
let runtimeSelection = null;
|
|
170
171
|
try {
|
|
171
172
|
const transcripts = await this.transcribeAttachments(staged.files);
|
|
172
173
|
const modelConfig = modelConfigFromMessage(m);
|
|
173
174
|
const adapter = this.registry.select({ ...m, content, model_config: modelConfig });
|
|
175
|
+
runtimeSelection = { adapter: adapter.name, modelConfig };
|
|
176
|
+
this.recordRuntimeSelection(adapter.name, modelConfig, 'running');
|
|
174
177
|
await this.wtt.typing(topicId, 'start', { statusText: `${adapterDisplayName(adapter.name)} 正在执行${modelConfig.model ? ` · ${modelConfig.model}` : ''}`, statusKind: 'running', adapter: adapter.name, model: modelConfig.model || undefined, ttlMs: 30000 });
|
|
175
178
|
const agentProfile = await this.getAgentProfile();
|
|
176
179
|
const agentSoul = renderAgentSoulContext(m.metadata, agentProfile?.role_template);
|
|
@@ -217,6 +220,7 @@ export class Runner {
|
|
|
217
220
|
await this.wtt.publish(topicId, `执行失败:${err.message}`, 'CHAT_REPLY');
|
|
218
221
|
log('error', 'chat failed', { topicId, error: err.message });
|
|
219
222
|
} finally {
|
|
223
|
+
if (runtimeSelection) this.recordRuntimeSelection(runtimeSelection.adapter, runtimeSelection.modelConfig, 'idle');
|
|
220
224
|
await this.wtt.typing(topicId, 'stop');
|
|
221
225
|
}
|
|
222
226
|
}
|
|
@@ -231,6 +235,7 @@ export class Runner {
|
|
|
231
235
|
const transcripts = await this.transcribeAttachments(staged.files);
|
|
232
236
|
const modelConfig = modelConfigFromMessage(task);
|
|
233
237
|
const adapter = this.registry.select({ ...task, model_config: modelConfig });
|
|
238
|
+
this.recordRuntimeSelection(adapter.name, modelConfig, 'running');
|
|
234
239
|
const agentProfile = await this.getAgentProfile();
|
|
235
240
|
if (topicId) await this.wtt.typing(topicId, 'start', { statusText: `${adapterDisplayName(adapter.name)} 正在执行任务${modelConfig.model ? ` · ${modelConfig.model}` : ''}`, statusKind: 'running', adapter: adapter.name, model: modelConfig.model || undefined, ttlMs: 30000 });
|
|
236
241
|
const prompt = buildTaskPrompt(task, this.config, staged, transcripts, agentProfile);
|
|
@@ -263,6 +268,7 @@ export class Runner {
|
|
|
263
268
|
if (topicId) await this.wtt.publish(topicId, `任务失败:${err.message}`, 'TASK_BLOCKED');
|
|
264
269
|
log('error', 'task failed', { taskId, error: err.message });
|
|
265
270
|
} finally {
|
|
271
|
+
this.recordRuntimeSelection(adapter.name, modelConfig, 'idle');
|
|
266
272
|
if (topicId) await this.wtt.typing(topicId, 'stop');
|
|
267
273
|
}
|
|
268
274
|
}
|
|
@@ -300,6 +306,17 @@ export class Runner {
|
|
|
300
306
|
}
|
|
301
307
|
}
|
|
302
308
|
|
|
309
|
+
recordRuntimeSelection(adapter, modelConfig = {}, status = 'idle') {
|
|
310
|
+
const model = String(modelConfig.model || modelConfig.model_id || modelConfig.modelId || '').trim();
|
|
311
|
+
const reasoning = String(modelConfig.reasoning_effort || modelConfig.reasoningEffort || '').trim().toLowerCase();
|
|
312
|
+
this.store.patchRuntime({
|
|
313
|
+
adapter,
|
|
314
|
+
...(model ? { current_model: model, model, model_source: 'message_metadata' } : { model_source: 'config' }),
|
|
315
|
+
...(reasoning ? { reasoning_effort: reasoning } : {}),
|
|
316
|
+
status,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
303
320
|
async transcribeAttachments(files) {
|
|
304
321
|
try {
|
|
305
322
|
return await this.stt.transcribeAll(files);
|
package/src/runtime-info.js
CHANGED
|
@@ -3,17 +3,20 @@ import path from 'node:path';
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
5
|
|
|
6
|
-
export function buildRuntimeInfo(config) {
|
|
6
|
+
export function buildRuntimeInfo(config, runtimeState = {}) {
|
|
7
7
|
const workdir = resolveWorkDir(config.workDir);
|
|
8
8
|
const git = gitInfo(workdir);
|
|
9
|
-
const
|
|
9
|
+
const adapter = String(runtimeState.adapter || config.adapter || '').trim();
|
|
10
|
+
const model = runtimeModel(config, adapter, runtimeState);
|
|
10
11
|
return {
|
|
11
12
|
kind: 'wtt-connect',
|
|
12
13
|
agent_id: config.agentId,
|
|
13
|
-
adapter: config.adapter,
|
|
14
|
+
adapter: adapter || config.adapter,
|
|
14
15
|
adapters: config.adapters,
|
|
15
16
|
...(model ? { model, current_model: model } : {}),
|
|
16
|
-
...(
|
|
17
|
+
...(runtimeState.model_source ? { model_source: String(runtimeState.model_source) } : {}),
|
|
18
|
+
...(runtimeState.status ? { runtime_status: String(runtimeState.status) } : {}),
|
|
19
|
+
...(runtimeState.reasoning_effort || config.reasoningEffort ? { reasoning_effort: String(runtimeState.reasoning_effort || config.reasoningEffort) } : {}),
|
|
17
20
|
workdir,
|
|
18
21
|
workdir_name: path.basename(workdir || ''),
|
|
19
22
|
cwd: safeRealpath(process.cwd()),
|
|
@@ -28,20 +31,85 @@ export function buildRuntimeInfo(config) {
|
|
|
28
31
|
};
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
function runtimeModel(config) {
|
|
34
|
+
function runtimeModel(config, adapter, runtimeState = {}) {
|
|
35
|
+
const fromRun = String(runtimeState.current_model || runtimeState.model || '').trim();
|
|
36
|
+
if (fromRun) return fromRun;
|
|
37
|
+
|
|
32
38
|
const explicit = String(config.model || '').trim();
|
|
33
39
|
if (explicit) return explicit;
|
|
34
40
|
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
37
|
-
return String(process.env.OPENAI_MODEL || process.env.CODEX_MODEL || '').trim();
|
|
41
|
+
const normalizedAdapter = String(adapter || config.adapter || '').trim().toLowerCase();
|
|
42
|
+
if (normalizedAdapter === 'codex') {
|
|
43
|
+
return String(process.env.OPENAI_MODEL || process.env.CODEX_MODEL || readCodexConfigModel() || '').trim();
|
|
38
44
|
}
|
|
39
|
-
if (
|
|
40
|
-
return String(process.env.ANTHROPIC_MODEL || '').trim();
|
|
45
|
+
if (normalizedAdapter === 'claude-code' || normalizedAdapter === 'claude' || normalizedAdapter === 'claude_code') {
|
|
46
|
+
return String(process.env.ANTHROPIC_MODEL || readClaudeConfigModel() || '').trim();
|
|
41
47
|
}
|
|
42
48
|
return String(process.env.WTT_CONNECT_MODEL || '').trim();
|
|
43
49
|
}
|
|
44
50
|
|
|
51
|
+
function readCodexConfigModel() {
|
|
52
|
+
const home = os.homedir();
|
|
53
|
+
const candidates = [
|
|
54
|
+
path.join(home, '.codex', 'config.toml'),
|
|
55
|
+
path.join(home, '.config', 'codex', 'config.toml'),
|
|
56
|
+
];
|
|
57
|
+
for (const file of candidates) {
|
|
58
|
+
const model = readTomlStringKey(file, 'model');
|
|
59
|
+
if (model) return model;
|
|
60
|
+
}
|
|
61
|
+
return '';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function readClaudeConfigModel() {
|
|
65
|
+
const home = os.homedir();
|
|
66
|
+
const candidates = [
|
|
67
|
+
path.join(home, '.claude.json'),
|
|
68
|
+
path.join(home, '.claude', 'settings.json'),
|
|
69
|
+
path.join(home, '.config', 'claude', 'settings.json'),
|
|
70
|
+
];
|
|
71
|
+
for (const file of candidates) {
|
|
72
|
+
const model = readJsonModelKey(file);
|
|
73
|
+
if (model) return model;
|
|
74
|
+
}
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function readJsonModelKey(file) {
|
|
79
|
+
try {
|
|
80
|
+
if (!fs.existsSync(file)) return '';
|
|
81
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
82
|
+
return findModelValue(parsed);
|
|
83
|
+
} catch {
|
|
84
|
+
return '';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function findModelValue(value, depth = 0) {
|
|
89
|
+
if (!value || typeof value !== 'object' || depth > 4) return '';
|
|
90
|
+
for (const key of ['model', 'model_id', 'modelId', 'defaultModel', 'default_model']) {
|
|
91
|
+
const raw = value[key];
|
|
92
|
+
if (typeof raw === 'string' && raw.trim()) return raw.trim();
|
|
93
|
+
}
|
|
94
|
+
for (const child of Object.values(value)) {
|
|
95
|
+
const found = findModelValue(child, depth + 1);
|
|
96
|
+
if (found) return found;
|
|
97
|
+
}
|
|
98
|
+
return '';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function readTomlStringKey(file, key) {
|
|
102
|
+
try {
|
|
103
|
+
if (!fs.existsSync(file)) return '';
|
|
104
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
105
|
+
const re = new RegExp(`^\\s*${key}\\s*=\\s*["']([^"']+)["']\\s*$`, 'm');
|
|
106
|
+
const match = text.match(re);
|
|
107
|
+
return match ? String(match[1] || '').trim() : '';
|
|
108
|
+
} catch {
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
45
113
|
function resolveWorkDir(workDir) {
|
|
46
114
|
const raw = String(workDir || process.cwd()).trim() || process.cwd();
|
|
47
115
|
return safeRealpath(path.resolve(raw));
|
package/src/store.js
CHANGED
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
export class DurableStore {
|
|
5
5
|
constructor(file) {
|
|
6
6
|
this.file = file;
|
|
7
|
-
this.data = { version: 1, sessions: {}, seen: {}, artifacts: [] };
|
|
7
|
+
this.data = { version: 1, sessions: {}, seen: {}, artifacts: [], runtime: {} };
|
|
8
8
|
this.loaded = false;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -37,6 +37,17 @@ export class DurableStore {
|
|
|
37
37
|
this.save();
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
getRuntime() {
|
|
41
|
+
this.load();
|
|
42
|
+
return this.data.runtime || {};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
patchRuntime(patch) {
|
|
46
|
+
this.load();
|
|
47
|
+
this.data.runtime = { ...(this.data.runtime || {}), ...patch, updatedAt: new Date().toISOString() };
|
|
48
|
+
this.save();
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
hasSeen(id, ttlMs = 24 * 3600_000) {
|
|
41
52
|
this.load();
|
|
42
53
|
const now = Date.now();
|