@co0ontty/wand 4.81.0 → 4.82.0
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.js +7 -4
- package/dist/ai-team-prompts.d.ts +1 -1
- package/dist/ai-team-prompts.js +2 -2
- package/dist/ai-team-runner.d.ts +2 -0
- package/dist/ai-team-runner.js +60 -7
- package/dist/ai-team-types.d.ts +6 -0
- package/dist/ai-team-types.js +11 -0
- package/dist/build-info.json +3 -3
- package/dist/cli.js +11 -0
- package/dist/config.js +2 -0
- package/dist/default-employee.d.ts +11 -0
- package/dist/default-employee.js +33 -0
- package/dist/employee-knowledge-cli.d.ts +2 -0
- package/dist/employee-knowledge-cli.js +52 -0
- package/dist/employee-knowledge-content.d.ts +4 -0
- package/dist/employee-knowledge-content.js +23 -0
- package/dist/employee-knowledge-types.d.ts +15 -0
- package/dist/employee-knowledge-types.js +3 -0
- package/dist/employee-knowledge.d.ts +6 -0
- package/dist/employee-knowledge.js +84 -0
- package/dist/git-quick-commit.d.ts +2 -0
- package/dist/git-quick-commit.js +121 -58
- package/dist/iteration-log.d.ts +5 -0
- package/dist/iteration-log.js +12 -1
- package/dist/message-truncator.js +13 -9
- package/dist/models.d.ts +4 -0
- package/dist/models.js +38 -10
- package/dist/pi-model-discovery.d.ts +12 -0
- package/dist/pi-model-discovery.js +281 -0
- package/dist/process-manager.d.ts +23 -1
- package/dist/process-manager.js +68 -1
- package/dist/prompt-optimizer.js +10 -11
- package/dist/pty-turn-activity.d.ts +27 -0
- package/dist/pty-turn-activity.js +31 -0
- package/dist/server-employee-routes.js +52 -6
- package/dist/server-session-routes.js +11 -5
- package/dist/server-task-routes.js +6 -1
- package/dist/server-user-memory.d.ts +9 -0
- package/dist/server-user-memory.js +96 -0
- package/dist/server.js +22 -2
- package/dist/session-topic.js +6 -5
- package/dist/silicon-employee-draft.js +1 -3
- package/dist/storage.d.ts +38 -0
- package/dist/storage.js +276 -3
- package/dist/structured-claude-adapter.d.ts +1 -1
- package/dist/structured-claude-adapter.js +2 -0
- package/dist/structured-provider-common.d.ts +2 -2
- package/dist/structured-provider-common.js +6 -6
- package/dist/structured-session-manager.js +5 -4
- package/dist/task-title.js +8 -7
- package/dist/team-report-file-link.d.ts +6 -0
- package/dist/team-report-file-link.js +54 -0
- package/dist/team-report-preview.d.ts +3 -0
- package/dist/team-report-preview.js +70 -0
- package/dist/types.d.ts +15 -0
- package/dist/user-memory-types.d.ts +42 -0
- package/dist/user-memory-types.js +6 -0
- package/dist/user-memory.d.ts +30 -0
- package/dist/user-memory.js +190 -0
- package/dist/web-ui/content/ai-teams.js +13 -13
- package/dist/web-ui/content/scripts.js +59 -61
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.js +3 -3
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { PtyInputDeliveryError, SessionInputError } from "./process-manager.js";
|
|
3
3
|
import { getDefaultModelForProvider, isExecutionMode } from "./config.js";
|
|
4
|
+
import { defaultRoleForCli } from "./default-employee.js";
|
|
4
5
|
import { alignedBlockStart, blockWindowMessagesForTransport, compactToolMessagesForTransport, sliceTurnBlocksForTransport, truncateMessagesForTransport, visibleBlockCount, windowMessagesForTransport } from "./message-truncator.js";
|
|
5
6
|
import { toSessionDetailDTO, toSessionListItemDTO } from "./session-transport.js";
|
|
6
7
|
import { checkSessionWorktreeMergeabilityAsync, cleanupSessionWorktreeAsync, getWorktreeMergeErrorCode, mergeSessionWorktreeAsync, WorktreeMergeError, } from "./git-worktree.js";
|
|
@@ -463,9 +464,14 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
463
464
|
res.status(400).json({ error: "结构化会话当前仅支持 Claude、Codex、OpenCode、Grok、Qoder、Pi 或 Gemini provider。" });
|
|
464
465
|
return;
|
|
465
466
|
}
|
|
466
|
-
const provider = employeeAgent?.provider
|
|
467
|
+
const provider = employeeAgent?.provider
|
|
468
|
+
?? (isSessionProvider(body.provider) ? body.provider : config.defaultProvider ?? "claude");
|
|
467
469
|
const rawModel = typeof body.model === "string" ? body.model.trim() : "";
|
|
468
470
|
const origin = parseSessionCreationOrigin(body);
|
|
471
|
+
// Explicit employees/custom role rules and internal automation retain their own role.
|
|
472
|
+
const defaultEmployee = !employee && !body.systemPrompt?.trim()
|
|
473
|
+
&& origin.sessionSource === "interactive" ? defaultRoleForCli(storage, provider) : null;
|
|
474
|
+
const role = employee ?? defaultEmployee;
|
|
469
475
|
const cwd = resolveSessionCwd(body.cwd, config.defaultCwd);
|
|
470
476
|
const snapshot = structured.createSession({
|
|
471
477
|
cwd,
|
|
@@ -484,10 +490,10 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
484
490
|
workspaceId: resolveWorkspaceIdForNewSession(storage, cwd, body.workspaceId),
|
|
485
491
|
workspaceTaskId: body.workspaceTaskId,
|
|
486
492
|
// 角色与规则走系统提示通道,不拼进 prompt(见 AGENTS.md「Session 输入契约」)。
|
|
487
|
-
systemPrompt:
|
|
488
|
-
employeeId:
|
|
489
|
-
employeeName:
|
|
490
|
-
employeeAvatar:
|
|
493
|
+
systemPrompt: role?.prompt ?? body.systemPrompt,
|
|
494
|
+
employeeId: role?.id,
|
|
495
|
+
employeeName: role?.name,
|
|
496
|
+
employeeAvatar: role?.avatar,
|
|
491
497
|
employeeCandidates: employee?.agents,
|
|
492
498
|
employeeCandidateIndex: selectedEmployeeCandidate?.index,
|
|
493
499
|
...origin,
|
|
@@ -9,6 +9,7 @@ import { recordIterationPromptForTask } from "./iteration-log.js";
|
|
|
9
9
|
import { resolveSystemAiContext } from "./session-ai-context.js";
|
|
10
10
|
import { memberAgents } from "./ai-team-types.js";
|
|
11
11
|
import { selectEmployeeCandidate } from "./silicon-employee-dispatch.js";
|
|
12
|
+
import { defaultRoleForCli } from "./default-employee.js";
|
|
12
13
|
import { DEFAULT_WAND_TASK_AGENT_KIND, DEFAULT_WAND_TASK_AGENT_MODE, DEFAULT_WAND_TASK_PRIORITY, isWandTaskAgentKind, isWandTaskAgentMode, normalizeWandTaskAgentMode, WAND_MILESTONE_NAME_MAX_LENGTH } from "./task-types.js";
|
|
13
14
|
import { isAutoNameableBoardTask, taskAutoNameSignature, taskAutoNameSourceText } from "./wand-task-sync.js";
|
|
14
15
|
import { isSessionProvider } from "./session-provider.js";
|
|
@@ -697,8 +698,12 @@ export function registerTaskRoutes(app, deps) {
|
|
|
697
698
|
const cliDefault = subject?.type === "cli"
|
|
698
699
|
? parseTaskAgent({ ...cliAgentForSubject(subject, task.agent), ...(body.kind === "pty" ? { kind: "pty" } : {}) })
|
|
699
700
|
: null;
|
|
701
|
+
const fallbackCandidate = !subject && body.agent === undefined && !task.agent
|
|
702
|
+
&& !body.provider ? selectEmployeeCandidate(defaultRoleForCli(storage, config.defaultProvider)).agent : null;
|
|
703
|
+
const fallbackAgent = fallbackCandidate && body.kind === "pty"
|
|
704
|
+
? { ...fallbackCandidate, kind: "pty" } : fallbackCandidate;
|
|
700
705
|
const agent = selected?.agent ?? (body.agent === undefined
|
|
701
|
-
? cliDefault ?? task.agent ?? parseWandTaskAgent(JSON.stringify(body))
|
|
706
|
+
? cliDefault ?? task.agent ?? fallbackAgent ?? parseWandTaskAgent(JSON.stringify(body))
|
|
702
707
|
: parseTaskAgent(body.agent, task.agent?.mode, task.agent?.kind));
|
|
703
708
|
if (!agent)
|
|
704
709
|
throw new Error("请先为该任务选择 CLI 工具。");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Express, RequestHandler } from "express";
|
|
2
|
+
import type { WandStorage } from "./storage.js";
|
|
3
|
+
import { type UserMemoryService } from "./user-memory.js";
|
|
4
|
+
export declare function userMemoryOperationLog(storage: WandStorage): RequestHandler;
|
|
5
|
+
export declare function registerUserMemoryRoutes(app: Express, deps: {
|
|
6
|
+
storage: WandStorage;
|
|
7
|
+
service: UserMemoryService;
|
|
8
|
+
notifyChanged?: (id: string) => void;
|
|
9
|
+
}): void;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { asyncRoute } from "./express-async.js";
|
|
2
|
+
import { bodyObject, sendRouteError } from "./server-request.js";
|
|
3
|
+
import { recordUserMemory } from "./user-memory.js";
|
|
4
|
+
import { DEFAULT_EMPLOYEE_ID } from "./ai-team-types.js";
|
|
5
|
+
import { isTaskExecutionSubject } from "./task-types.js";
|
|
6
|
+
import { shouldGenerateSessionTopicFromInput } from "./session-topic.js";
|
|
7
|
+
/** Explicit allowlist: never collect GET polling, auth, vault, config, files or tool bodies. */
|
|
8
|
+
const OPERATIONS = [
|
|
9
|
+
{ method: "POST", path: /^\/api\/(?:wand-tasks|tasks|workspaces\/[^/]+\/tasks)$/, feature: "task.create", fields: ["description", "title", "name"] },
|
|
10
|
+
{ method: "PATCH", path: /^\/api\/(?:wand-tasks|workspace-tasks)\/[^/]+$/, feature: "task.edit", fields: ["description", "title", "name"] },
|
|
11
|
+
{ method: "POST", path: /^\/api\/wand-tasks\/[^/]+\/dispatch$/, feature: "task.dispatch", fields: ["prompt"] },
|
|
12
|
+
{ method: "POST", path: /^\/api\/(?:ai-teams\/[^/]+\/runs|wand-tasks\/[^/]+\/team-runs)$/, feature: "team.start", fields: ["note"] },
|
|
13
|
+
{ method: "POST", path: /^\/api\/sessions\/[^/]+\/model$/, feature: "session.model" },
|
|
14
|
+
{ method: "POST", path: /^\/api\/sessions\/[^/]+\/thinking-effort$/, feature: "session.thinking" },
|
|
15
|
+
{ method: "POST", path: /^\/api\/sessions\/[^/]+\/mode$/, feature: "session.mode" },
|
|
16
|
+
{ method: "POST", path: /^\/api\/sessions\/[^/]+\/quick-commit$/, feature: "git.quick-commit" },
|
|
17
|
+
{ method: "POST", path: /^\/api\/sessions\/[^/]+\/upload$/, feature: "file.upload" },
|
|
18
|
+
{ method: "POST", path: /^\/api\/sessions\/[^/]+\/worktree\/merge$/, feature: "worktree.merge" },
|
|
19
|
+
{ method: "POST", path: /^\/api\/optimize-prompt$/, feature: "prompt.optimize", fields: ["text"] },
|
|
20
|
+
{ method: "POST", path: /^\/api\/(?:sessions\/[^/]+\/input|structured-sessions\/[^/]+\/messages)$/, feature: "session.prompt", fields: ["input"] },
|
|
21
|
+
];
|
|
22
|
+
export function userMemoryOperationLog(storage) {
|
|
23
|
+
return (req, res, next) => {
|
|
24
|
+
const operation = OPERATIONS.find((entry) => entry.method === req.method && entry.path.test(req.path));
|
|
25
|
+
if (operation) {
|
|
26
|
+
const epoch = storage.userMemoryCaptureState();
|
|
27
|
+
const body = bodyObject(req.body);
|
|
28
|
+
const subject = body.executionSubject ?? body.subject;
|
|
29
|
+
const privateEmployee = isTaskExecutionSubject(subject) && subject.type === "employee"
|
|
30
|
+
&& subject.id !== DEFAULT_EMPLOYEE_ID;
|
|
31
|
+
const observation = privateEmployee ? "" : (operation.fields ?? [])
|
|
32
|
+
.map((field) => typeof body[field] === "string" ? body[field] : "").filter(Boolean).join("\n");
|
|
33
|
+
// Only the successful user action is evidence. IDs/URLs and arbitrary request fields aren't logged.
|
|
34
|
+
res.once("finish", () => {
|
|
35
|
+
if (epoch.enabled && storage.userMemoryCaptureState().enabled
|
|
36
|
+
&& storage.userMemoryCaptureState().revision === epoch.revision
|
|
37
|
+
&& res.statusCode >= 200 && res.statusCode < 300) {
|
|
38
|
+
if (operation.feature === "session.prompt") {
|
|
39
|
+
// Team-generated instructions never pass through these authenticated input requests.
|
|
40
|
+
// Only collect direct user replies here; interactive/wand-task runners already capture theirs.
|
|
41
|
+
const sessionId = req.path.split("/")[3];
|
|
42
|
+
const session = storage.getSessionSlim(sessionId);
|
|
43
|
+
if (session?.sessionKind === "structured" && session.automationId?.startsWith("ai-team")
|
|
44
|
+
&& !/^[\/!]/.test(observation.trim()) && shouldGenerateSessionTopicFromInput(observation)) {
|
|
45
|
+
recordUserMemory(storage, operation.feature, observation, sessionId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const taskId = operation.feature === "task.dispatch" || operation.feature === "task.edit"
|
|
50
|
+
? req.path.split("/")[3] : undefined;
|
|
51
|
+
const taskSubject = taskId ? (req.path.split("/")[2] === "workspace-tasks"
|
|
52
|
+
? storage.getWandTaskByWorkspaceTaskId(taskId) : storage.getWandTask(taskId))?.executionSubject : null;
|
|
53
|
+
const text = taskSubject?.type === "employee" && taskSubject.id !== DEFAULT_EMPLOYEE_ID
|
|
54
|
+
? "" : observation;
|
|
55
|
+
recordUserMemory(storage, operation.feature, text, req.path);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
next();
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function registerUserMemoryRoutes(app, deps) {
|
|
64
|
+
const { storage, service, notifyChanged } = deps;
|
|
65
|
+
app.get("/api/user-memory", (_req, res) => {
|
|
66
|
+
res.setHeader("Cache-Control", "no-store");
|
|
67
|
+
res.json(service.view());
|
|
68
|
+
});
|
|
69
|
+
app.patch("/api/user-memory", (req, res) => {
|
|
70
|
+
try {
|
|
71
|
+
const body = bodyObject(req.body);
|
|
72
|
+
if (typeof body.enabled !== "boolean")
|
|
73
|
+
throw new Error("enabled 必须是布尔值。");
|
|
74
|
+
storage.setUserMemoryEnabled(body.enabled);
|
|
75
|
+
notifyChanged?.(DEFAULT_EMPLOYEE_ID);
|
|
76
|
+
res.json(service.view());
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
sendRouteError(res, error, "无法调整短期记忆。");
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
app.delete("/api/user-memory", (_req, res) => {
|
|
83
|
+
storage.clearUserMemory();
|
|
84
|
+
notifyChanged?.(DEFAULT_EMPLOYEE_ID);
|
|
85
|
+
res.json(service.view());
|
|
86
|
+
});
|
|
87
|
+
app.post("/api/user-memory/refresh", asyncRoute(async (_req, res) => {
|
|
88
|
+
const updated = await service.refresh(true);
|
|
89
|
+
const view = service.view();
|
|
90
|
+
if (!updated && view.lastError) {
|
|
91
|
+
res.status(503).json({ error: view.lastError });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
res.json({ updated, ...view });
|
|
95
|
+
}));
|
|
96
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -33,6 +33,9 @@ import { Missions } from "./missions.js";
|
|
|
33
33
|
import { createAiTeamRunner } from "./ai-team-runner.js";
|
|
34
34
|
import { registerAiTeamRoutes } from "./server-ai-team-routes.js";
|
|
35
35
|
import { registerSiliconEmployeeRoutes } from "./server-employee-routes.js";
|
|
36
|
+
import { defaultRoleForCli } from "./default-employee.js";
|
|
37
|
+
import { UserMemoryService } from "./user-memory.js";
|
|
38
|
+
import { registerUserMemoryRoutes, userMemoryOperationLog } from "./server-user-memory.js";
|
|
36
39
|
import { registerAttentionRoutes } from "./server-attention-routes.js";
|
|
37
40
|
import { refreshProviderCliUpdateState, registerAdminUpdateRoutes, registerPublicUpdateRoutes, ServerUpdateState, } from "./server-update-routes.js";
|
|
38
41
|
import { parseSessionCreationOrigin, registerClaudeHistoryRoutes, registerSessionRoutes } from "./server-session-routes.js";
|
|
@@ -288,6 +291,7 @@ export async function startServer(config, configPath, options = {}) {
|
|
|
288
291
|
}
|
|
289
292
|
const app = express();
|
|
290
293
|
let shuttingDown = false;
|
|
294
|
+
const testMode = process.env.WAND_TEST_MODE === "1";
|
|
291
295
|
app.set("trust proxy", "loopback, 172.16.0.0/12");
|
|
292
296
|
const storage = new WandStorage(resolveDatabasePath(configPath));
|
|
293
297
|
const runtimeConfig = new RuntimeConfigState(config);
|
|
@@ -310,6 +314,7 @@ export async function startServer(config, configPath, options = {}) {
|
|
|
310
314
|
inheritEnv: config.inheritEnv !== false,
|
|
311
315
|
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
312
316
|
...injected,
|
|
317
|
+
piEndpointDiscovery: injected.piEndpointDiscovery ?? { enabled: !testMode },
|
|
313
318
|
configuredClaudeModels: [
|
|
314
319
|
currentDefaults.claude,
|
|
315
320
|
config.commitCli === "claude" ? (storage.getPreference("pref:commitModel", config.commitModel) ?? "") : undefined,
|
|
@@ -599,6 +604,7 @@ export async function startServer(config, configPath, options = {}) {
|
|
|
599
604
|
"/api/session-directories",
|
|
600
605
|
"/api/structured-sessions",
|
|
601
606
|
"/api/commands",
|
|
607
|
+
"/api/user-memory",
|
|
602
608
|
"/api/claude-history",
|
|
603
609
|
"/api/codex-history",
|
|
604
610
|
"/api/opencode-history",
|
|
@@ -635,6 +641,16 @@ export async function startServer(config, configPath, options = {}) {
|
|
|
635
641
|
"/api/local-file",
|
|
636
642
|
], requireFiles);
|
|
637
643
|
app.use("/api/browser-extension", requirePasswordVault);
|
|
644
|
+
app.use("/api/silicon-employees/:employeeId/knowledge", requireSessions);
|
|
645
|
+
app.use(userMemoryOperationLog(storage));
|
|
646
|
+
const userMemory = new UserMemoryService({
|
|
647
|
+
storage, config,
|
|
648
|
+
notifyChanged: (employeeId) => notifyAiTeamRun({ kind: "silicon-employee-definition", employeeId }),
|
|
649
|
+
});
|
|
650
|
+
registerUserMemoryRoutes(app, {
|
|
651
|
+
storage, service: userMemory,
|
|
652
|
+
notifyChanged: (employeeId) => notifyAiTeamRun({ kind: "silicon-employee-definition", employeeId }),
|
|
653
|
+
});
|
|
638
654
|
// ── Config & Session info ──
|
|
639
655
|
app.get("/api/config", asyncRoute(async (req, res) => {
|
|
640
656
|
const structuredChatPersona = await buildStructuredChatPersonaPayload(configPath, config);
|
|
@@ -833,7 +849,9 @@ export async function startServer(config, configPath, options = {}) {
|
|
|
833
849
|
cols: reqCols,
|
|
834
850
|
rows: reqRows,
|
|
835
851
|
thinkingEffort: body.thinkingEffort ?? config.defaultThinkingEffort,
|
|
836
|
-
systemPrompt: body.systemPrompt
|
|
852
|
+
systemPrompt: body.systemPrompt?.trim() || (origin.sessionSource === "interactive"
|
|
853
|
+
&& (isSessionProvider(body.provider) || inferProviderFromCommand(command))
|
|
854
|
+
? defaultRoleForCli(storage, provider).prompt : undefined),
|
|
837
855
|
workspaceId,
|
|
838
856
|
workspaceTaskId: body.workspaceTaskId,
|
|
839
857
|
...origin,
|
|
@@ -1049,8 +1067,9 @@ export async function startServer(config, configPath, options = {}) {
|
|
|
1049
1067
|
if (!storage.hasCustomPassword() && config.password === "change-me") {
|
|
1050
1068
|
wandWarn("正在使用默认密码(change-me),任何能访问本机的人都可以登录。", "修改方法:在界面右上角「设置」中修改密码,或运行:node dist/cli.js config:set password <你的新密码>");
|
|
1051
1069
|
}
|
|
1052
|
-
const testMode = process.env.WAND_TEST_MODE === "1";
|
|
1053
1070
|
const updateChecksEnabled = !testMode && process.env.WAND_DISABLE_UPDATE_CHECK !== "1";
|
|
1071
|
+
if (!testMode)
|
|
1072
|
+
userMemory.start();
|
|
1054
1073
|
// Start configured background sessions after the server is already reachable.
|
|
1055
1074
|
if (!testMode) {
|
|
1056
1075
|
void processes.runStartupCommands().catch((error) => {
|
|
@@ -1222,6 +1241,7 @@ export async function startServer(config, configPath, options = {}) {
|
|
|
1222
1241
|
return closePromise;
|
|
1223
1242
|
closePromise = (async () => {
|
|
1224
1243
|
shuttingDown = true;
|
|
1244
|
+
await userMemory.dispose();
|
|
1225
1245
|
if (updateCheckTimer) {
|
|
1226
1246
|
clearInterval(updateCheckTimer);
|
|
1227
1247
|
updateCheckTimer = null;
|
package/dist/session-topic.js
CHANGED
|
@@ -257,11 +257,12 @@ export async function generateSessionTopic(userMessages, cwd, language, ai = {})
|
|
|
257
257
|
].join("\n"),
|
|
258
258
|
prompt: `按发送顺序排列的用户消息:\n${input}`,
|
|
259
259
|
};
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
260
|
+
return callConfiguredAiText(request, cwd ?? process.cwd(), language ?? "", ai, (raw) => {
|
|
261
|
+
const topic = parseTopic(raw);
|
|
262
|
+
if (!topic)
|
|
263
|
+
throw new Error("模型返回的会话主题格式无效。");
|
|
264
|
+
return topic;
|
|
265
|
+
});
|
|
265
266
|
}
|
|
266
267
|
/**
|
|
267
268
|
* Coalesces title refreshes per session. A newer user message invalidates an
|
|
@@ -132,9 +132,8 @@ export async function generateSiliconEmployeeDraft(expectation, ai = {}, options
|
|
|
132
132
|
const available = availableEmployeeProviders(options.preferredProvider, options.isProviderAvailable);
|
|
133
133
|
const providers = available.length ? available : [options.preferredProvider ?? "claude", ...SESSION_PROVIDERS];
|
|
134
134
|
const request = buildEmployeeDraftPrompt(trimmed, providers, options.existingNames);
|
|
135
|
-
let raw;
|
|
136
135
|
try {
|
|
137
|
-
|
|
136
|
+
return await callConfiguredAiText(request, options.cwd || process.cwd(), options.language ?? "", ai, (raw) => parseSiliconEmployeeDraft(raw, { allowedProviders: providers, fallbackProvider: providers[0] }));
|
|
138
137
|
}
|
|
139
138
|
catch (error) {
|
|
140
139
|
if (error instanceof SiliconEmployeeDraftError)
|
|
@@ -142,5 +141,4 @@ export async function generateSiliconEmployeeDraft(expectation, ai = {}, options
|
|
|
142
141
|
const message = error instanceof Error ? error.message : String(error);
|
|
143
142
|
throw new SiliconEmployeeDraftError(message || "AI 生成员工配置失败。", "DRAFT_AI_FAILED");
|
|
144
143
|
}
|
|
145
|
-
return parseSiliconEmployeeDraft(raw, { allowedProviders: providers, fallbackProvider: providers[0] });
|
|
146
144
|
}
|
package/dist/storage.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { SessionSnapshot, ConversationTurn, SessionProvider, StructuredSessionSt
|
|
|
2
2
|
import type { AiTeam, AiTeamRun, AiTeamRunChatMarker, AiTeamRunStatus, AiTeamStep, AiTeamStepSessionMarker, CandidateFailureKind, SiliconEmployee, StepDispatchInfo } from "./ai-team-types.js";
|
|
3
3
|
import type { WandTask, WandTaskAgent, WandTaskAgentKind, WandTaskTitleSource } from "./task-types.js";
|
|
4
4
|
import { type SystemEmployeeSeed } from "./system-employee.js";
|
|
5
|
+
import { type EmployeeKnowledgeEntry } from "./employee-knowledge-types.js";
|
|
6
|
+
import { type UserMemoryEvent, type UserMemoryProfile, type UserMemoryState } from "./user-memory-types.js";
|
|
5
7
|
import type { AgentActivityItem, Mission, MissionAttempt, MissionReviewComment, MissionReviewStatus, MissionStatus } from "./mission-types.js";
|
|
6
8
|
import { type PasswordVault, type PasswordVaultItem, type PasswordVaultItemFilter, type PasswordVaultItemInput } from "./password-manager.js";
|
|
7
9
|
/** `ai_team_runs.run_state_json`:本次运行的候选黑名单(§3.4 修正 B12 两层键值 + host-disabled)。 */
|
|
@@ -62,8 +64,10 @@ type WandTaskPatch = Partial<Pick<WandTask, "workspaceId" | "workspaceTaskId" |
|
|
|
62
64
|
export declare class WandStorage {
|
|
63
65
|
private readonly db;
|
|
64
66
|
private readonly dbPath;
|
|
67
|
+
private memoryCapture;
|
|
65
68
|
constructor(dbPath: string);
|
|
66
69
|
directory(): string;
|
|
70
|
+
databasePath(): string;
|
|
67
71
|
close(): void;
|
|
68
72
|
/**
|
|
69
73
|
* Run a synchronous group of storage operations atomically. Calls must not
|
|
@@ -315,7 +319,11 @@ export declare class WandStorage {
|
|
|
315
319
|
listSiliconEmployees(options?: {
|
|
316
320
|
includeArchived?: boolean;
|
|
317
321
|
}): SiliconEmployee[];
|
|
322
|
+
private projectDefaultEmployee;
|
|
318
323
|
getSiliconEmployee(id: string): SiliconEmployee | null;
|
|
324
|
+
getDefaultSiliconEmployee(): SiliconEmployee | null;
|
|
325
|
+
/** Seed once, preserve execution choices, and never reset learned preferences on restart. */
|
|
326
|
+
ensureDefaultSiliconEmployee(provider?: SessionProvider): SiliconEmployee;
|
|
319
327
|
/** 内置「系统运维」员工;未创建(或被删除过)时返回 null。 */
|
|
320
328
|
getSystemSiliconEmployee(key?: string): SiliconEmployee | null;
|
|
321
329
|
/**
|
|
@@ -327,6 +335,36 @@ export declare class WandStorage {
|
|
|
327
335
|
archiveSiliconEmployee(id: string, archivedAt?: string): void;
|
|
328
336
|
unarchiveSiliconEmployee(id: string): void;
|
|
329
337
|
deleteSiliconEmployee(id: string): void;
|
|
338
|
+
private requireKnowledgeEmployee;
|
|
339
|
+
listEmployeeKnowledge(employeeId: string, query?: string, limit?: number): EmployeeKnowledgeEntry[];
|
|
340
|
+
countEmployeeKnowledge(employeeId: string): number;
|
|
341
|
+
rememberEmployeeKnowledge(employeeId: string, value: string, accessToken?: string): EmployeeKnowledgeEntry;
|
|
342
|
+
forgetEmployeeKnowledge(employeeId: string, entryId: string, accessToken?: string): boolean;
|
|
343
|
+
clearEmployeeKnowledge(employeeId: string): void;
|
|
344
|
+
/** Opaque per-execution capability: no employee selector, app token or DB secret in model prompts. */
|
|
345
|
+
issueEmployeeKnowledgeAccess(sessionId: string, employeeId: string, now?: number): string;
|
|
346
|
+
resolveEmployeeKnowledgeAccess(token: string, now?: number): string | null;
|
|
347
|
+
revokeEmployeeKnowledgeAccess(token: string): void;
|
|
348
|
+
/** No IO on input hot paths; queued observations still CAS against the database before writing. */
|
|
349
|
+
userMemoryCaptureState(): Readonly<{
|
|
350
|
+
enabled: boolean;
|
|
351
|
+
revision: number;
|
|
352
|
+
}>;
|
|
353
|
+
stopUserMemoryCapture(): void;
|
|
354
|
+
getUserMemoryState(now?: number): UserMemoryState;
|
|
355
|
+
listUserMemoryEvents(now?: number, limit?: number): UserMemoryEvent[];
|
|
356
|
+
userMemoryFeatureCounts(now?: number): Array<{
|
|
357
|
+
feature: string;
|
|
358
|
+
count: number;
|
|
359
|
+
}>;
|
|
360
|
+
/** Only already-redacted, bounded observations reach this table. Queued writes use revision CAS. */
|
|
361
|
+
appendUserMemoryEvent(feature: string, text: string, dedupKey: string, revision: number, now?: number): void;
|
|
362
|
+
pruneUserMemory(now?: number): void;
|
|
363
|
+
setUserMemoryEnabled(enabled: boolean): void;
|
|
364
|
+
clearUserMemory(): void;
|
|
365
|
+
markUserMemoryAttempt(revision: number, now: number): boolean;
|
|
366
|
+
/** Read fresh candidates inside the transaction; a late model result cannot undo user edits/clear. */
|
|
367
|
+
applyUserMemoryProfile(profile: UserMemoryProfile, revision: number, sourceId: number, now?: number): boolean;
|
|
330
368
|
listAiTeams(): AiTeam[];
|
|
331
369
|
getAiTeam(id: string): AiTeam | null;
|
|
332
370
|
saveAiTeam(team: AiTeam): void;
|