@co0ontty/wand 4.89.0 → 4.89.2-beta.gd071c20
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/dist/agent-dispatch.d.ts +5 -0
- package/dist/agent-dispatch.js +8 -0
- package/dist/ai-team-employee-binding.d.ts +1 -0
- package/dist/ai-team-employee-binding.js +1 -1
- package/dist/ai-team-runner.d.ts +1 -1
- package/dist/ai-team-runner.js +13 -5
- package/dist/ai-team-types.d.ts +2 -2
- package/dist/ai-team-types.js +3 -2
- package/dist/build-info.json +4 -4
- package/dist/commit-task-archive.d.ts +3 -0
- package/dist/commit-task-archive.js +15 -0
- package/dist/config.js +1 -0
- package/dist/daemon-maintenance-targets.js +1 -1
- package/dist/decision-expert-employee.d.ts +1 -1
- package/dist/decision-expert-employee.js +3 -3
- package/dist/decision-expert-service.d.ts +6 -5
- package/dist/decision-expert-service.js +75 -49
- package/dist/decision-types.d.ts +2 -1
- package/dist/default-employee.d.ts +5 -1
- package/dist/default-employee.js +17 -5
- package/dist/employee-text.d.ts +28 -0
- package/dist/employee-text.js +124 -0
- package/dist/fixed-employee-avatar.d.ts +19 -0
- package/dist/fixed-employee-avatar.js +13 -0
- package/dist/git-quick-commit.d.ts +13 -4
- package/dist/git-quick-commit.js +112 -33
- package/dist/local-model-setup.d.ts +7 -1
- package/dist/local-model-setup.js +54 -7
- package/dist/local-model-types.d.ts +2 -1
- package/dist/plush-avatar.d.ts +100 -0
- package/dist/plush-avatar.js +96 -0
- package/dist/process-manager.d.ts +4 -1
- package/dist/process-manager.js +9 -7
- package/dist/server-employee-routes.d.ts +6 -2
- package/dist/server-employee-routes.js +55 -53
- package/dist/server-file-routes.js +61 -25
- package/dist/server-local-model-routes.js +12 -0
- package/dist/server-session-routes.d.ts +2 -1
- package/dist/server-session-routes.js +13 -10
- package/dist/server-speech-routes.d.ts +2 -0
- package/dist/server-speech-routes.js +7 -1
- package/dist/server-task-routes.d.ts +3 -0
- package/dist/server-task-routes.js +19 -10
- package/dist/server.js +25 -8
- package/dist/session-ai-context.d.ts +6 -4
- package/dist/session-ai-context.js +10 -9
- package/dist/silicon-employee-dispatch.d.ts +4 -6
- package/dist/silicon-employee-dispatch.js +9 -6
- package/dist/speech-polisher-employee.d.ts +6 -0
- package/dist/speech-polisher-employee.js +23 -0
- package/dist/speech-polisher-identity.d.ts +4 -0
- package/dist/speech-polisher-identity.js +4 -0
- package/dist/speech-polisher-service.d.ts +31 -0
- package/dist/speech-polisher-service.js +88 -0
- package/dist/speech-service.d.ts +3 -1
- package/dist/speech-service.js +15 -4
- package/dist/speech-support.d.ts +6 -0
- package/dist/speech-support.js +26 -0
- package/dist/speech-types.d.ts +5 -0
- package/dist/storage.d.ts +13 -4
- package/dist/storage.js +84 -32
- package/dist/structured-session-manager.d.ts +3 -2
- package/dist/structured-session-manager.js +11 -7
- package/dist/system-employee.d.ts +6 -4
- package/dist/system-employee.js +13 -10
- package/dist/types.d.ts +3 -1
- package/dist/user-memory.d.ts +2 -0
- package/dist/user-memory.js +1 -1
- package/dist/wand-task-sync.js +13 -2
- package/dist/web-ui/content/ai-teams.js +13 -13
- package/dist/web-ui/content/plush-avatar.js +4220 -0
- package/dist/web-ui/content/scripts.js +572 -209
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/content/tailwind.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +2 -0
- package/dist/web-ui/embedded-assets.js +5 -3
- package/dist/web-ui/index.js +3 -3
- package/dist/web-ui/provider-identity.d.ts +2 -0
- package/dist/web-ui/provider-identity.js +7 -1
- package/dist/web-ui/scripts.d.ts +7 -0
- package/dist/web-ui/scripts.js +30 -5
- package/package.json +3 -1
package/dist/storage.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
+
import { FIXED_EMPLOYEE_AVATARS, fixedEmployeeAvatar, isFixedAvatarEmployee } from "./fixed-employee-avatar.js";
|
|
2
3
|
import { CONVERSATION_OWNER } from "./conversation-types.js";
|
|
3
4
|
import { chmodSync, existsSync, mkdirSync } from "node:fs";
|
|
4
5
|
import path from "node:path";
|
|
@@ -20,6 +21,8 @@ import { isThinkingEffort } from "./structured-provider-common.js";
|
|
|
20
21
|
import { DEFAULT_EMPLOYEE_KEY } from "./ai-team-types.js";
|
|
21
22
|
import { defaultEmployeeDefinition, legacyPtyRoleIdentity } from "./default-employee.js";
|
|
22
23
|
import { DECISION_EXPERT_KEY } from "./decision-expert-identity.js";
|
|
24
|
+
import { SPEECH_POLISHER_KEY } from "./speech-polisher-identity.js";
|
|
25
|
+
import { speechPolisherDefinition } from "./speech-polisher-employee.js";
|
|
23
26
|
import { decisionExpertDefinition } from "./decision-expert-employee.js";
|
|
24
27
|
import { normalizeEmployeeKnowledge } from "./employee-knowledge-content.js";
|
|
25
28
|
import { EMPLOYEE_KNOWLEDGE_MAX_ENTRIES } from "./employee-knowledge-types.js";
|
|
@@ -322,7 +325,11 @@ function parseQueuedMessages(raw) {
|
|
|
322
325
|
function parseWorktreeInfo(raw) {
|
|
323
326
|
const parsed = safeJsonParse(raw);
|
|
324
327
|
if (parsed && typeof parsed.branch === "string" && typeof parsed.path === "string") {
|
|
325
|
-
return {
|
|
328
|
+
return {
|
|
329
|
+
branch: parsed.branch, path: parsed.path,
|
|
330
|
+
...(typeof parsed.baseRef === "string" ? { baseRef: parsed.baseRef } : {}),
|
|
331
|
+
...(typeof parsed.repoRoot === "string" ? { repoRoot: parsed.repoRoot } : {}),
|
|
332
|
+
};
|
|
326
333
|
}
|
|
327
334
|
return undefined;
|
|
328
335
|
}
|
|
@@ -2713,9 +2720,14 @@ export class WandStorage {
|
|
|
2713
2720
|
const state = this.getUserMemoryState();
|
|
2714
2721
|
return defaultEmployeeDefinition(employee.agents, employee.updatedAt, employee, state.enabled ? state.profile : null);
|
|
2715
2722
|
}
|
|
2716
|
-
|
|
2723
|
+
/** Saved definition without generated short-term preferences. */
|
|
2724
|
+
getSiliconEmployeeDefinition(id) {
|
|
2717
2725
|
const row = this.db.prepare("SELECT * FROM silicon_employees WHERE id = ?").get(id);
|
|
2718
|
-
return row ?
|
|
2726
|
+
return row ? mapSiliconEmployeeRow(row) : null;
|
|
2727
|
+
}
|
|
2728
|
+
getSiliconEmployee(id) {
|
|
2729
|
+
const employee = this.getSiliconEmployeeDefinition(id);
|
|
2730
|
+
return employee ? this.projectDefaultEmployee(employee) : null;
|
|
2719
2731
|
}
|
|
2720
2732
|
getDefaultSiliconEmployee() {
|
|
2721
2733
|
const employee = this.getSystemSiliconEmployee(DEFAULT_EMPLOYEE_KEY);
|
|
@@ -2724,43 +2736,25 @@ export class WandStorage {
|
|
|
2724
2736
|
/** Seed once, preserve execution choices, and never reset learned preferences on restart. */
|
|
2725
2737
|
ensureDefaultSiliconEmployee(provider) {
|
|
2726
2738
|
const existing = this.getSystemSiliconEmployee(DEFAULT_EMPLOYEE_KEY);
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
this.saveSiliconEmployee(definition);
|
|
2733
|
-
return definition;
|
|
2734
|
-
}
|
|
2735
|
-
return existing;
|
|
2739
|
+
if (existing)
|
|
2740
|
+
return this.projectDefaultEmployee(existing);
|
|
2741
|
+
const definition = defaultEmployeeDefinition(systemEmployeeSeedAgents({ provider }), new Date().toISOString());
|
|
2742
|
+
this.saveSiliconEmployee(definition);
|
|
2743
|
+
return this.projectDefaultEmployee(definition);
|
|
2736
2744
|
}
|
|
2737
2745
|
/** 内置「系统运维」员工;未创建(或被删除过)时返回 null。 */
|
|
2738
2746
|
getSystemSiliconEmployee(key = SYSTEM_EMPLOYEE_KEY) {
|
|
2739
2747
|
const row = this.db.prepare("SELECT * FROM silicon_employees WHERE system_key = ?").get(key);
|
|
2740
2748
|
return row ? mapSiliconEmployeeRow(row) : null;
|
|
2741
2749
|
}
|
|
2742
|
-
/**
|
|
2743
|
-
* 幂等地保证内置员工存在。已存在时只补齐锁定字段(防止旧的同名定义漂移),
|
|
2744
|
-
* 候选保留用户当下的设置;不存在时按 seed 建首条候选。
|
|
2745
|
-
*/
|
|
2750
|
+
/** Seed only when missing; restart never overwrites user profile, candidates, or legacy avatars. */
|
|
2746
2751
|
ensureSystemSiliconEmployee(seed = {}) {
|
|
2747
2752
|
const existing = this.getSystemSiliconEmployee();
|
|
2748
|
-
if (
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
const locked = systemEmployeeDefinition(existing.agents, new Date().toISOString(), existing);
|
|
2754
|
-
if (existing.name !== locked.name
|
|
2755
|
-
|| existing.duty !== locked.duty
|
|
2756
|
-
|| existing.prompt !== locked.prompt
|
|
2757
|
-
|| existing.avatar !== locked.avatar
|
|
2758
|
-
|| existing.archivedAt !== undefined
|
|
2759
|
-
|| existing.agents.length === 0) {
|
|
2760
|
-
this.saveSiliconEmployee(locked);
|
|
2761
|
-
return locked;
|
|
2762
|
-
}
|
|
2763
|
-
return existing;
|
|
2753
|
+
if (existing)
|
|
2754
|
+
return existing;
|
|
2755
|
+
const employee = systemEmployeeDefinition(systemEmployeeSeedAgents(seed), new Date().toISOString());
|
|
2756
|
+
this.saveSiliconEmployee(employee);
|
|
2757
|
+
return employee;
|
|
2764
2758
|
}
|
|
2765
2759
|
/** Stable built-in decision employee; seed once and retain the user's ordered call chain. */
|
|
2766
2760
|
ensureDecisionExpertEmployee() {
|
|
@@ -2773,7 +2767,32 @@ export class WandStorage {
|
|
|
2773
2767
|
}
|
|
2774
2768
|
return existing;
|
|
2775
2769
|
}
|
|
2770
|
+
/** Seed the SDK free group once, then preserve independent user choices. */
|
|
2771
|
+
ensureSpeechPolisherEmployee() {
|
|
2772
|
+
const existing = this.getSystemSiliconEmployee(SPEECH_POLISHER_KEY);
|
|
2773
|
+
const definition = speechPolisherDefinition(new Date().toISOString(), existing);
|
|
2774
|
+
if (!existing || existing.name !== definition.name || existing.duty !== definition.duty || existing.prompt !== definition.prompt
|
|
2775
|
+
|| existing.avatar !== definition.avatar || existing.archivedAt || !existing.agents.length) {
|
|
2776
|
+
this.saveSiliconEmployee(definition);
|
|
2777
|
+
return definition;
|
|
2778
|
+
}
|
|
2779
|
+
return existing;
|
|
2780
|
+
}
|
|
2776
2781
|
saveSiliconEmployee(employee) {
|
|
2782
|
+
const existing = this.getSiliconEmployeeDefinition(employee.id);
|
|
2783
|
+
const target = FIXED_EMPLOYEE_AVATARS.find((entry) => entry.id === employee.id || entry.systemKey === employee.systemKey);
|
|
2784
|
+
if (target) {
|
|
2785
|
+
if (employee.id !== target.id || employee.systemKey !== target.systemKey)
|
|
2786
|
+
throw new Error("内置员工身份不可修改或冒用。");
|
|
2787
|
+
if (existing && !isFixedAvatarEmployee(existing))
|
|
2788
|
+
throw new Error("内置员工身份冲突,不能覆盖已有记录。");
|
|
2789
|
+
if (employee.avatar !== (existing?.avatar ?? target.avatar))
|
|
2790
|
+
throw new Error("该员工是内置的,头像不可修改。");
|
|
2791
|
+
if (existing && JSON.stringify(employee.tags) !== JSON.stringify(existing.tags))
|
|
2792
|
+
throw new Error("该员工是内置的,标签不可修改。");
|
|
2793
|
+
if (employee.archivedAt !== existing?.archivedAt)
|
|
2794
|
+
throw new Error("内置员工不可归档。");
|
|
2795
|
+
}
|
|
2777
2796
|
const tags = isBuiltinSiliconEmployee(employee)
|
|
2778
2797
|
? siliconEmployeeTags(employee)
|
|
2779
2798
|
: parseSiliconEmployeeTags(employee.tags ?? []);
|
|
@@ -2791,13 +2810,46 @@ export class WandStorage {
|
|
|
2791
2810
|
archived_at = excluded.archived_at,
|
|
2792
2811
|
updated_at = excluded.updated_at`).run(employee.id, employee.name, employee.duty, employee.prompt, employee.avatar, JSON.stringify(employee.agents), employee.systemKey ?? null, employee.archivedAt ?? null, employee.createdAt, employee.updatedAt, JSON.stringify(tags));
|
|
2793
2812
|
}
|
|
2813
|
+
/** Explicit, atomic migration; not called from GET, config load, seeds, or ordinary saves.
|
|
2814
|
+
* Compare all expected avatar values first; change only avatar, including preserving timestamps.
|
|
2815
|
+
*/
|
|
2816
|
+
migrateFixedEmployeeAvatars(expected) {
|
|
2817
|
+
return this.transaction(() => {
|
|
2818
|
+
if (expected.length !== FIXED_EMPLOYEE_AVATARS.length || new Set(expected.map((entry) => entry.id)).size !== expected.length) {
|
|
2819
|
+
throw new Error("固定头像迁移需要两个精确且不同的目标。");
|
|
2820
|
+
}
|
|
2821
|
+
const rows = FIXED_EMPLOYEE_AVATARS.map((target) => {
|
|
2822
|
+
const prior = expected.find((entry) => entry.id === target.id && entry.systemKey === target.systemKey);
|
|
2823
|
+
const employee = this.getSiliconEmployeeDefinition(target.id);
|
|
2824
|
+
if (!prior || !employee || fixedEmployeeAvatar(employee) !== target.avatar)
|
|
2825
|
+
throw new Error("固定头像迁移目标不存在或身份冲突。");
|
|
2826
|
+
if (employee.avatar !== prior.avatar && employee.avatar !== target.avatar)
|
|
2827
|
+
throw new Error("固定头像迁移检测到头像已变化,请重新核对。");
|
|
2828
|
+
return { target, employee };
|
|
2829
|
+
});
|
|
2830
|
+
let changed = 0;
|
|
2831
|
+
for (const { target, employee } of rows) {
|
|
2832
|
+
if (employee.avatar === target.avatar)
|
|
2833
|
+
continue;
|
|
2834
|
+
changed += Number(this.db.prepare("UPDATE silicon_employees SET avatar = ? WHERE id = ? AND system_key = ? AND avatar = ?")
|
|
2835
|
+
.run(target.avatar, target.id, target.systemKey, employee.avatar).changes);
|
|
2836
|
+
}
|
|
2837
|
+
return changed;
|
|
2838
|
+
});
|
|
2839
|
+
}
|
|
2794
2840
|
archiveSiliconEmployee(id, archivedAt = new Date().toISOString()) {
|
|
2841
|
+
if (isFixedAvatarEmployee(this.getSiliconEmployeeDefinition(id) ?? {}))
|
|
2842
|
+
throw new Error("内置员工不可归档。");
|
|
2795
2843
|
this.db.prepare("UPDATE silicon_employees SET archived_at = ?, updated_at = ? WHERE id = ?").run(archivedAt, new Date().toISOString(), id);
|
|
2796
2844
|
}
|
|
2797
2845
|
unarchiveSiliconEmployee(id) {
|
|
2846
|
+
if (isFixedAvatarEmployee(this.getSiliconEmployeeDefinition(id) ?? {}))
|
|
2847
|
+
throw new Error("内置员工不能恢复归档。");
|
|
2798
2848
|
this.db.prepare("UPDATE silicon_employees SET archived_at = NULL, updated_at = ? WHERE id = ?").run(new Date().toISOString(), id);
|
|
2799
2849
|
}
|
|
2800
2850
|
deleteSiliconEmployee(id) {
|
|
2851
|
+
if (isFixedAvatarEmployee(this.getSiliconEmployeeDefinition(id) ?? {}))
|
|
2852
|
+
throw new Error("内置员工不可删除。");
|
|
2801
2853
|
this.db.prepare("DELETE FROM silicon_employees WHERE id = ?").run(id);
|
|
2802
2854
|
}
|
|
2803
2855
|
// ============ Employee-owned explicit knowledge ============
|
|
@@ -86,6 +86,7 @@ export declare class StructuredSessionManager {
|
|
|
86
86
|
private readonly logger;
|
|
87
87
|
private readonly execHost?;
|
|
88
88
|
private readonly decisionRuntime;
|
|
89
|
+
private readonly openRouter?;
|
|
89
90
|
/** 「智能分配」专用的本地决策入口:只有真正能跑时才注入,没注入则用系统员工回退。 */
|
|
90
91
|
private readonly autoAssignEvaluate;
|
|
91
92
|
private readonly sessions;
|
|
@@ -140,7 +141,7 @@ export declare class StructuredSessionManager {
|
|
|
140
141
|
private detachedRecoveryRetryTimer;
|
|
141
142
|
private detachedRecoveryFailureLogged;
|
|
142
143
|
private disposed;
|
|
143
|
-
constructor(storage: WandStorage, config: WandConfig, logger?: SessionLogger | null, runners?: StructuredSessionManagerRunners, execHost?: StructuredExecHost | undefined, decisionRuntime?: () => DecisionRuntimeAccess | null, openRouter?: OpenRouterFreeModelsService,
|
|
144
|
+
constructor(storage: WandStorage, config: WandConfig, logger?: SessionLogger | null, runners?: StructuredSessionManagerRunners, execHost?: StructuredExecHost | undefined, decisionRuntime?: () => DecisionRuntimeAccess | null, openRouter?: OpenRouterFreeModelsService | undefined,
|
|
144
145
|
/** 「智能分配」专用的本地决策入口:只有真正能跑时才注入,没注入则用系统员工回退。 */
|
|
145
146
|
autoAssignEvaluate?: () => DecisionRuntimeAccess["evaluate"]);
|
|
146
147
|
private archiveExpiredSessions;
|
|
@@ -173,7 +174,7 @@ export declare class StructuredSessionManager {
|
|
|
173
174
|
get(id: string): SessionSnapshot | null;
|
|
174
175
|
setSessionWorkspace(id: string, membership: Pick<SessionSnapshot, "workspaceId" | "workspaceTaskId">): void;
|
|
175
176
|
setSessionTopic(id: string, title: string, description: string): SessionSnapshot;
|
|
176
|
-
/**
|
|
177
|
+
/** 归档只写标记,正在执行的回合和历史继续保留。 */
|
|
177
178
|
setSessionArchived(id: string, archived: boolean): SessionSnapshot;
|
|
178
179
|
private setSessionTopicGenerating;
|
|
179
180
|
/**
|
|
@@ -10,6 +10,7 @@ import { stampNewToolUseTimes } from "./tool-use-timestamps.js";
|
|
|
10
10
|
import { buildChildEnv } from "./env-utils.js";
|
|
11
11
|
import { getErrorMessage } from "./error-utils.js";
|
|
12
12
|
import { getDefaultModelForProvider } from "./config.js";
|
|
13
|
+
import { isLocalDecisionModel } from "./decision-expert-identity.js";
|
|
13
14
|
import { recordIterationPrompt } from "./iteration-log.js";
|
|
14
15
|
import { startEmployeeKnowledgeRunner } from "./employee-knowledge.js";
|
|
15
16
|
import { CoreRunner } from "./core-runner.js";
|
|
@@ -436,6 +437,7 @@ export class StructuredSessionManager {
|
|
|
436
437
|
logger;
|
|
437
438
|
execHost;
|
|
438
439
|
decisionRuntime;
|
|
440
|
+
openRouter;
|
|
439
441
|
autoAssignEvaluate;
|
|
440
442
|
sessions = new Map();
|
|
441
443
|
// Both freshly started runners and adopted daemon runs own the same input gate.
|
|
@@ -500,6 +502,7 @@ export class StructuredSessionManager {
|
|
|
500
502
|
this.logger = logger;
|
|
501
503
|
this.execHost = execHost;
|
|
502
504
|
this.decisionRuntime = decisionRuntime;
|
|
505
|
+
this.openRouter = openRouter;
|
|
503
506
|
this.autoAssignEvaluate = autoAssignEvaluate;
|
|
504
507
|
const wrap = (runner) => withModelGroups(withDecisionAccess(runner, storage, decisionRuntime), config);
|
|
505
508
|
this.claudeCliRunner = wrap(runners.claudeCli ?? new ClaudeCliRunner({ language: () => this.config.language }, this.execHost));
|
|
@@ -1238,11 +1241,9 @@ export class StructuredSessionManager {
|
|
|
1238
1241
|
this.emitStructuredSnapshot(updated);
|
|
1239
1242
|
return updated;
|
|
1240
1243
|
}
|
|
1241
|
-
/**
|
|
1244
|
+
/** 归档只写标记,正在执行的回合和历史继续保留。 */
|
|
1242
1245
|
setSessionArchived(id, archived) {
|
|
1243
|
-
const current =
|
|
1244
|
-
? this.stop(id)
|
|
1245
|
-
: this.requireSession(id);
|
|
1246
|
+
const current = this.requireSession(id);
|
|
1246
1247
|
const archivedAt = archived ? new Date().toISOString() : null;
|
|
1247
1248
|
const updated = { ...current, archived, archivedAt };
|
|
1248
1249
|
this.sessions.set(id, updated);
|
|
@@ -1309,7 +1310,7 @@ export class StructuredSessionManager {
|
|
|
1309
1310
|
input,
|
|
1310
1311
|
cwd: session.cwd,
|
|
1311
1312
|
language: this.config.language,
|
|
1312
|
-
ai: resolveSystemAiContext(session, this.config, this.storage.getSystemSiliconEmployee()),
|
|
1313
|
+
ai: resolveSystemAiContext(session, this.config, this.storage.getSystemSiliconEmployee(), this.openRouter),
|
|
1313
1314
|
readNativeTitle: () => readNativeSessionTitle(resolveSessionProvider(session), session.claudeSessionId, session.cwd),
|
|
1314
1315
|
hasNativeTitle,
|
|
1315
1316
|
onGenerating: (generating) => {
|
|
@@ -1499,7 +1500,10 @@ export class StructuredSessionManager {
|
|
|
1499
1500
|
return null;
|
|
1500
1501
|
const candidates = original.employeeCandidates ?? [];
|
|
1501
1502
|
const index = original.employeeCandidateIndex ?? 0;
|
|
1502
|
-
|
|
1503
|
+
let nextIndex = index + 1;
|
|
1504
|
+
// LAYA has no chat adapter; keep original candidate indices while skipping bounded-only models.
|
|
1505
|
+
while (nextIndex < candidates.length && isLocalDecisionModel(candidates[nextIndex].model))
|
|
1506
|
+
nextIndex += 1;
|
|
1503
1507
|
if (!original.employeeId || (original.messages?.length ?? 0) !== 0 || original.claudeSessionId
|
|
1504
1508
|
|| !error.failure.retryable || nextIndex >= candidates.length)
|
|
1505
1509
|
return null;
|
|
@@ -1688,7 +1692,7 @@ export class StructuredSessionManager {
|
|
|
1688
1692
|
prompt,
|
|
1689
1693
|
groups: this.config.modelGroups,
|
|
1690
1694
|
evaluate: this.autoAssignEvaluate(),
|
|
1691
|
-
ai: resolveSystemAiContext(session, this.config, this.storage.getSystemSiliconEmployee()),
|
|
1695
|
+
ai: resolveSystemAiContext(session, this.config, this.storage.getSystemSiliconEmployee(), this.openRouter),
|
|
1692
1696
|
cwd: session.cwd,
|
|
1693
1697
|
language: this.config.language,
|
|
1694
1698
|
});
|
|
@@ -6,8 +6,8 @@ export { SYSTEM_EMPLOYEE_ID, SYSTEM_EMPLOYEE_KEY, SYSTEM_EMPLOYEE_NAME, SYSTEM_E
|
|
|
6
6
|
* 内置的「系统运维」员工。
|
|
7
7
|
*
|
|
8
8
|
* Wand 自己的 AI 调用(commit message / tag、提示词优化、会话与任务标题、
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* 员工起草)都通过这位员工的候选链执行:身份和头像固定,不可归档、不可删除;
|
|
10
|
+
* 名字、职责、人设与执行候选(工具 + 引擎 + 模型 + 思考深度)由用户维护。
|
|
11
11
|
*/
|
|
12
12
|
export declare const SYSTEM_EMPLOYEE_DUTY = "Wand \u7CFB\u7EDF\u8FD0\u7EF4\uFF1A\u670D\u52A1\u4E0E CLI \u7EBF\u8DEF\u3001\u66F4\u65B0\u5206\u53D1\u3001\u4ED3\u5E93\u4E0E\u4F1A\u8BDD\u64CD\u4F5C\uFF0CWand \u81EA\u6709 AI \u4EFB\u52A1\u7684\u6267\u884C\u8005\u3002";
|
|
13
13
|
/**
|
|
@@ -29,6 +29,8 @@ export declare function systemEmployeeSeedAgents(seed?: SystemEmployeeSeed): Wan
|
|
|
29
29
|
export declare function systemEmployeeDefinition(agents: WandTaskAgent[], now: string, existing?: SiliconEmployee | null): SiliconEmployee;
|
|
30
30
|
export declare function isSdkEmployeeAgent(agent: Pick<WandTaskAgent, "engine">): boolean;
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* 系统应用沿用员工配置顺序和引擎;不按触发来源过滤工具。
|
|
33
33
|
*/
|
|
34
|
-
export declare function
|
|
34
|
+
export declare function systemEmployeeCandidates(employee: Pick<SiliconEmployee, "agents"> | null | undefined): AiCliCandidate[];
|
|
35
|
+
/** Compatibility name for existing callers; the chain also includes Wand Agent. */
|
|
36
|
+
export declare const systemEmployeeCliCandidates: typeof systemEmployeeCandidates;
|
package/dist/system-employee.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SYSTEM_EMPLOYEE_ID, SYSTEM_EMPLOYEE_KEY, SYSTEM_EMPLOYEE_NAME, SYSTEM_EMPLOYEE_TAG, isSystemSiliconEmployee, } from "./ai-team-types.js";
|
|
2
|
+
import { fixedEmployeeAvatar } from "./fixed-employee-avatar.js";
|
|
2
3
|
import { isSessionProvider } from "./session-provider.js";
|
|
3
4
|
import { DEFAULT_WAND_TASK_AGENT_KIND, DEFAULT_WAND_TASK_AGENT_MODE, normalizeWandTaskAgentMode } from "./task-types.js";
|
|
4
5
|
// 常量与判定定义在 ai-team-types(浏览器也要用),这里再导出一次,服务端只从一个地方引用。
|
|
@@ -7,8 +8,8 @@ export { SYSTEM_EMPLOYEE_ID, SYSTEM_EMPLOYEE_KEY, SYSTEM_EMPLOYEE_NAME, SYSTEM_E
|
|
|
7
8
|
* 内置的「系统运维」员工。
|
|
8
9
|
*
|
|
9
10
|
* Wand 自己的 AI 调用(commit message / tag、提示词优化、会话与任务标题、
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* 员工起草)都通过这位员工的候选链执行:身份和头像固定,不可归档、不可删除;
|
|
12
|
+
* 名字、职责、人设与执行候选(工具 + 引擎 + 模型 + 思考深度)由用户维护。
|
|
12
13
|
*/
|
|
13
14
|
export const SYSTEM_EMPLOYEE_DUTY = "Wand 系统运维:服务与 CLI 线路、更新分发、仓库与会话操作,Wand 自有 AI 任务的执行者。";
|
|
14
15
|
/**
|
|
@@ -45,11 +46,10 @@ export function systemEmployeeSeedAgents(seed = {}) {
|
|
|
45
46
|
export function systemEmployeeDefinition(agents, now, existing) {
|
|
46
47
|
return {
|
|
47
48
|
id: existing?.id ?? SYSTEM_EMPLOYEE_ID,
|
|
48
|
-
name: SYSTEM_EMPLOYEE_NAME,
|
|
49
|
-
duty: SYSTEM_EMPLOYEE_DUTY,
|
|
50
|
-
prompt: SYSTEM_EMPLOYEE_PROMPT,
|
|
51
|
-
|
|
52
|
-
avatar: "",
|
|
49
|
+
name: existing?.name ?? SYSTEM_EMPLOYEE_NAME,
|
|
50
|
+
duty: existing?.duty ?? SYSTEM_EMPLOYEE_DUTY,
|
|
51
|
+
prompt: existing?.prompt ?? SYSTEM_EMPLOYEE_PROMPT,
|
|
52
|
+
avatar: existing?.avatar ?? fixedEmployeeAvatar({ id: SYSTEM_EMPLOYEE_ID, systemKey: SYSTEM_EMPLOYEE_KEY }),
|
|
53
53
|
agents: agents.length ? agents : systemEmployeeSeedAgents(),
|
|
54
54
|
systemKey: SYSTEM_EMPLOYEE_KEY,
|
|
55
55
|
tags: [SYSTEM_EMPLOYEE_TAG],
|
|
@@ -61,19 +61,22 @@ export function isSdkEmployeeAgent(agent) {
|
|
|
61
61
|
return agent.engine === "sdk";
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
64
|
+
* 系统应用沿用员工配置顺序和引擎;不按触发来源过滤工具。
|
|
65
65
|
*/
|
|
66
|
-
export function
|
|
66
|
+
export function systemEmployeeCandidates(employee) {
|
|
67
67
|
if (!employee)
|
|
68
68
|
return [];
|
|
69
69
|
return employee.agents
|
|
70
|
-
.filter((agent) => agent.kind === "structured"
|
|
70
|
+
.filter((agent) => agent.kind === "structured")
|
|
71
71
|
.map((agent) => {
|
|
72
72
|
const model = (agent.model ?? "").trim();
|
|
73
73
|
return {
|
|
74
74
|
provider: agent.provider,
|
|
75
|
+
...(agent.engine ? { engine: agent.engine } : {}),
|
|
75
76
|
model: !model || model === "default" ? undefined : model,
|
|
76
77
|
thinkingEffort: agent.thinkingEffort,
|
|
77
78
|
};
|
|
78
79
|
});
|
|
79
80
|
}
|
|
81
|
+
/** Compatibility name for existing callers; the chain also includes Wand Agent. */
|
|
82
|
+
export const systemEmployeeCliCandidates = systemEmployeeCandidates;
|
package/dist/types.d.ts
CHANGED
|
@@ -226,11 +226,13 @@ export interface AiTextRequest {
|
|
|
226
226
|
prompt: string;
|
|
227
227
|
}
|
|
228
228
|
/**
|
|
229
|
-
* Wand 自有 AI 调用(commit message
|
|
229
|
+
* Wand 自有 AI 调用(commit message、标题、提示词优化…)的一条执行候选。
|
|
230
230
|
* 候选顺序即降级顺序;由内置「系统运维」员工维护。
|
|
231
231
|
*/
|
|
232
232
|
export interface AiCliCandidate {
|
|
233
233
|
provider: SessionProvider;
|
|
234
|
+
/** 缺省为 CLI;显式 sdk 保持 Wand Agent 引擎身份。 */
|
|
235
|
+
engine?: "cli" | "sdk";
|
|
234
236
|
/** 具体模型 ID;未设置表示跟随 provider 默认模型。 */
|
|
235
237
|
model?: string;
|
|
236
238
|
thinkingEffort?: ThinkingEffort;
|
package/dist/user-memory.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EmployeeTextDeps } from "./employee-text.js";
|
|
1
2
|
import type { WandStorage } from "./storage.js";
|
|
2
3
|
import type { WandConfig } from "./types.js";
|
|
3
4
|
import { type UserMemoryEvent, type UserMemoryPreference, type UserMemoryView } from "./user-memory-types.js";
|
|
@@ -18,6 +19,7 @@ export declare class UserMemoryService {
|
|
|
18
19
|
constructor(deps: {
|
|
19
20
|
storage: WandStorage;
|
|
20
21
|
config: WandConfig;
|
|
22
|
+
free?: EmployeeTextDeps["free"];
|
|
21
23
|
notifyChanged?: (id: string) => void;
|
|
22
24
|
now?: () => number;
|
|
23
25
|
generate?: (events: UserMemoryEvent[]) => Promise<UserMemoryPreference[]>;
|
package/dist/user-memory.js
CHANGED
|
@@ -160,7 +160,7 @@ export class UserMemoryService {
|
|
|
160
160
|
}, config.defaultCwd, config.language ?? "", resolveSystemAiContext({
|
|
161
161
|
provider: config.defaultProvider ?? "claude", command: config.defaultProvider ?? "claude",
|
|
162
162
|
selectedModel: null, thinkingEffort: config.defaultThinkingEffort,
|
|
163
|
-
}, config, storage.getSystemSiliconEmployee()), (raw) => parseUserMemoryPreferences(raw, events));
|
|
163
|
+
}, config, storage.getSystemSiliconEmployee(), this.deps.free), (raw) => parseUserMemoryPreferences(raw, events));
|
|
164
164
|
// Test seam and production share the exact same validator.
|
|
165
165
|
const validated = parseUserMemoryPreferences(JSON.stringify({ preferences }), events);
|
|
166
166
|
const referenced = new Set(validated.flatMap((entry) => entry.evidenceIds));
|
package/dist/wand-task-sync.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { isSessionProvider } from "./session-provider.js";
|
|
2
3
|
import { provisionalTaskTitleFromDescription } from "./task-title.js";
|
|
3
4
|
/** 未命名任务的占位名;服务端新建时写入,自动命名成功后被真实标题覆盖。 */
|
|
4
5
|
export const UNNAMED_WORKSPACE_TASK_NAME = "未命名任务";
|
|
@@ -10,6 +11,8 @@ export function isUnnamedWorkspaceTaskName(name) {
|
|
|
10
11
|
}
|
|
11
12
|
/** Legacy title helper; prompts name sessions, not their containing task. */
|
|
12
13
|
export function boardTitleFromSession(session) {
|
|
14
|
+
if (isBlankTerminal(session))
|
|
15
|
+
return "";
|
|
13
16
|
const title = session.title?.trim();
|
|
14
17
|
if (title && !isUnnamedWorkspaceTaskName(title))
|
|
15
18
|
return provisionalTaskTitleFromDescription(title);
|
|
@@ -26,6 +29,9 @@ export function boardTitleFromSession(session) {
|
|
|
26
29
|
}
|
|
27
30
|
return "";
|
|
28
31
|
}
|
|
32
|
+
function isBlankTerminal(session) {
|
|
33
|
+
return session.sessionKind !== "structured" && !isSessionProvider(session.provider);
|
|
34
|
+
}
|
|
29
35
|
/**
|
|
30
36
|
* 自动命名只覆盖「还没有人为名字」的任务:标题来源是 auto,或仍是占位名的历史卡片
|
|
31
37
|
* (老版本把未命名任务写成了 titleSource=user)。用户在面板 / 侧栏改过名后此处为 false。
|
|
@@ -46,8 +52,9 @@ function taskNamingSessions(storage, card) {
|
|
|
46
52
|
return;
|
|
47
53
|
add(session);
|
|
48
54
|
// boardTitleFromSession 只在 title/description 都缺时才翻 messages 找首条用户输入。
|
|
49
|
-
if (!session.title?.trim() && !session.description?.trim())
|
|
55
|
+
if (!isBlankTerminal(session) && !session.title?.trim() && !session.description?.trim()) {
|
|
50
56
|
needsMessageFallback.push(session.id);
|
|
57
|
+
}
|
|
51
58
|
};
|
|
52
59
|
if (card.workspaceTaskId) {
|
|
53
60
|
for (const session of storage.listSessionsByWorkspaceTaskSlim(card.workspaceTaskId))
|
|
@@ -68,6 +75,10 @@ function taskNamingSessions(storage, card) {
|
|
|
68
75
|
* 为空表示这个任务还没有可命名的内容,调用方应保留占位标题。
|
|
69
76
|
*/
|
|
70
77
|
export function taskAutoNameSourceText(storage, card) {
|
|
78
|
+
const sessions = taskNamingSessions(storage, card);
|
|
79
|
+
// 只有空白终端的任务不总结;后来加入 Agent 时再按真实任务内容命名。
|
|
80
|
+
if (sessions.length > 0 && sessions.every(isBlankTerminal))
|
|
81
|
+
return "";
|
|
71
82
|
const parts = [];
|
|
72
83
|
for (const line of card.description.split(/\r?\n/)) {
|
|
73
84
|
const trimmed = line.trim();
|
|
@@ -75,7 +86,7 @@ export function taskAutoNameSourceText(storage, card) {
|
|
|
75
86
|
continue;
|
|
76
87
|
parts.push(trimmed);
|
|
77
88
|
}
|
|
78
|
-
for (const session of
|
|
89
|
+
for (const session of sessions) {
|
|
79
90
|
const candidate = boardTitleFromSession(session);
|
|
80
91
|
if (candidate)
|
|
81
92
|
parts.push(candidate);
|