@co0ontty/wand 4.76.0 → 4.77.0-beta.g6c4df97
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 +46 -0
- package/dist/agent-dispatch.js +84 -0
- package/dist/ai-team-availability.d.ts +69 -0
- package/dist/ai-team-availability.js +100 -0
- package/dist/ai-team-prompts.d.ts +113 -0
- package/dist/ai-team-prompts.js +435 -0
- package/dist/ai-team-runner.d.ts +241 -0
- package/dist/ai-team-runner.js +1370 -0
- package/dist/ai-team-types.d.ts +147 -0
- package/dist/ai-team-types.js +32 -0
- package/dist/attention.d.ts +40 -0
- package/dist/attention.js +86 -0
- package/dist/build-info.json +4 -4
- package/dist/claude-sdk-runner.d.ts +5 -0
- package/dist/claude-sdk-runner.js +2 -1
- package/dist/commit-task-archive.d.ts +3 -0
- package/dist/commit-task-archive.js +43 -0
- package/dist/config.js +0 -2
- package/dist/git-quick-commit.d.ts +2 -1
- package/dist/git-quick-commit.js +72 -60
- package/dist/message-truncator.d.ts +41 -5
- package/dist/message-truncator.js +255 -38
- package/dist/missions.d.ts +4 -2
- package/dist/missions.js +2 -2
- package/dist/process-manager.d.ts +1 -0
- package/dist/process-manager.js +17 -8
- package/dist/prompt-optimizer.js +13 -13
- package/dist/server-ai-team-routes.d.ts +11 -0
- package/dist/server-ai-team-routes.js +283 -0
- package/dist/server-attention-routes.d.ts +9 -0
- package/dist/server-attention-routes.js +26 -0
- package/dist/server-file-routes.js +1 -1
- package/dist/server-session-routes.js +41 -5
- package/dist/server-settings-routes.js +1 -1
- package/dist/server-task-routes.d.ts +2 -0
- package/dist/server-task-routes.js +6 -40
- package/dist/server-workspace-routes.js +13 -5
- package/dist/server.js +43 -0
- package/dist/session-topic.js +13 -13
- package/dist/session-transport.d.ts +3 -0
- package/dist/session-transport.js +1 -0
- package/dist/storage.d.ts +54 -1
- package/dist/storage.js +413 -2
- package/dist/structured-claude-adapter.d.ts +5 -0
- package/dist/structured-claude-adapter.js +13 -2
- package/dist/structured-claude-protocol.d.ts +2 -0
- package/dist/structured-claude-protocol.js +4 -0
- package/dist/structured-codex-adapter.js +2 -2
- package/dist/structured-grok-adapter.js +2 -1
- package/dist/structured-opencode-adapter.js +2 -2
- package/dist/structured-pi-adapter.js +2 -1
- package/dist/structured-provider-common.d.ts +17 -0
- package/dist/structured-provider-common.js +52 -0
- package/dist/structured-qoder-adapter.js +2 -1
- package/dist/structured-session-manager.d.ts +18 -1
- package/dist/structured-session-manager.js +67 -10
- package/dist/system-ai.d.ts +13 -2
- package/dist/system-ai.js +9 -5
- package/dist/task-title.js +10 -10
- package/dist/types.d.ts +25 -2
- package/dist/wand-task-sync.d.ts +1 -0
- package/dist/wand-task-sync.js +1 -0
- package/dist/web-ui/content/ai-teams.js +12 -0
- package/dist/web-ui/content/scripts.js +86 -5301
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +1 -0
- package/dist/web-ui/embedded-assets.js +3 -2
- package/dist/web-ui/scripts.d.ts +8 -0
- package/dist/web-ui/scripts.js +28 -2
- package/dist/ws-broadcast.js +52 -19
- package/package.json +1 -1
|
@@ -1,4 +1,56 @@
|
|
|
1
|
+
import { shellQuote } from "./shell-quote.js";
|
|
1
2
|
const NATIVE_THINKING_EFFORT = /^(claude|codex|opencode|grok|qoder|pi):[a-z0-9][a-z0-9_-]{0,31}$/;
|
|
3
|
+
/**
|
|
4
|
+
* 把会话级系统提示交给 CLI 的开关。Claude / Qoder / Pi 用 `--append-system-prompt`,
|
|
5
|
+
* Grok 用 `--rules`;Codex / OpenCode 没有这个入口,只能退回并入本轮消息。
|
|
6
|
+
* 各 provider 的支持情况由 `--help` 实测得出,新增 provider 前先验。
|
|
7
|
+
*/
|
|
8
|
+
export function systemPromptFlag(provider) {
|
|
9
|
+
switch (provider) {
|
|
10
|
+
case "claude":
|
|
11
|
+
case "qoder":
|
|
12
|
+
case "pi":
|
|
13
|
+
return "--append-system-prompt";
|
|
14
|
+
case "grok":
|
|
15
|
+
return "--rules";
|
|
16
|
+
default:
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** 结构化 runner 的 args:provider 支持时把系统提示当成独立参数传。 */
|
|
21
|
+
export function systemPromptArgs(session) {
|
|
22
|
+
const text = session.systemPrompt?.trim();
|
|
23
|
+
if (!text)
|
|
24
|
+
return [];
|
|
25
|
+
const flag = systemPromptFlag(session.provider);
|
|
26
|
+
return flag ? [flag, text] : [];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* provider 没有系统提示通道时的兜底:把它放在本会话第一条消息最前面,并写明它不是用户输入。
|
|
30
|
+
* 只在首轮拼一次:后续轮次的消息已经接在有它的对话历史后面。有通道的 provider 不会走这里。
|
|
31
|
+
*/
|
|
32
|
+
export function promptWithSystemFallback(session, prompt) {
|
|
33
|
+
const text = session.systemPrompt?.trim();
|
|
34
|
+
if (!text || systemPromptFlag(session.provider))
|
|
35
|
+
return prompt;
|
|
36
|
+
if ((session.messages?.length ?? 0) > 1)
|
|
37
|
+
return prompt;
|
|
38
|
+
return composeSystemFallback(text, prompt);
|
|
39
|
+
}
|
|
40
|
+
/** provider 没有系统提示通道时的并接格式:明确标出这不是用户输入。 */
|
|
41
|
+
export function composeSystemFallback(systemPrompt, prompt) {
|
|
42
|
+
return `以下是本会话的固定要求(来自系统,不是用户输入,优先级高于后面的内容):\n\n${systemPrompt.trim()}\n\n---\n\n${prompt}`;
|
|
43
|
+
}
|
|
44
|
+
/** 把系统提示接到 CLI 命令上(provider 支持时);不支持时原样返回,由调用方并进首条输入。 */
|
|
45
|
+
export function commandWithSystemPrompt(command, provider, systemPrompt) {
|
|
46
|
+
const text = systemPrompt?.trim();
|
|
47
|
+
if (!text)
|
|
48
|
+
return command;
|
|
49
|
+
const flag = systemPromptFlag(provider);
|
|
50
|
+
if (!flag || command.includes(flag))
|
|
51
|
+
return command;
|
|
52
|
+
return `${command} ${flag} ${shellQuote(text)}`;
|
|
53
|
+
}
|
|
2
54
|
/** 判断任意值是否为合法的 thinking effort(旧四档,或 `provider:level`)。 */
|
|
3
55
|
export function isThinkingEffort(value) {
|
|
4
56
|
return value === "off"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { ClaudeCliProtocolReducer } from "./structured-claude-protocol.js";
|
|
3
3
|
import { startStructuredCli } from "./structured-exec-pump.js";
|
|
4
|
-
import { thinkingEffortToQoderEffort } from "./structured-provider-common.js";
|
|
4
|
+
import { systemPromptArgs, thinkingEffortToQoderEffort } from "./structured-provider-common.js";
|
|
5
5
|
export function buildQoderArgs(session, prompt) {
|
|
6
6
|
const args = ["-p", prompt, "--output-format", "stream-json"];
|
|
7
7
|
const model = session.selectedModel?.trim();
|
|
@@ -13,6 +13,7 @@ export function buildQoderArgs(session, prompt) {
|
|
|
13
13
|
// 与 PTY runner 一致:Qoder 一律以 yolo(bypass_permissions)启动。结构化 runner 没有
|
|
14
14
|
// 权限桥,--print 下未批准的调用只会被拒绝,因此不做任何模式降级。
|
|
15
15
|
args.push("--permission-mode", "bypass_permissions");
|
|
16
|
+
args.push(...systemPromptArgs(session));
|
|
16
17
|
if (session.claudeSessionId)
|
|
17
18
|
args.push("-r", session.claudeSessionId);
|
|
18
19
|
return args;
|
|
@@ -2,7 +2,7 @@ import { query as sdkQuery } from "@anthropic-ai/claude-agent-sdk";
|
|
|
2
2
|
import { type WorktreeSetupSpec } from "./git-worktree.js";
|
|
3
3
|
import { SessionLogger } from "./session-logger.js";
|
|
4
4
|
import { WandStorage } from "./storage.js";
|
|
5
|
-
import { ExecutionMode, ProcessEvent, SessionProvider, SessionRunner, SessionSnapshot, SessionSource, WandConfig } from "./types.js";
|
|
5
|
+
import { ConversationTurn, ExecutionMode, ProcessEvent, SessionProvider, SessionRunner, SessionSnapshot, SessionSource, WandConfig } from "./types.js";
|
|
6
6
|
import { type StructuredExecHost } from "./structured-exec-host.js";
|
|
7
7
|
import type { StructuredRunnerAdapter } from "./structured-runner.js";
|
|
8
8
|
export interface StructuredSessionManagerRunners {
|
|
@@ -26,6 +26,8 @@ interface CreateStructuredSessionOptions {
|
|
|
26
26
|
thinkingEffort?: SessionSnapshot["thinkingEffort"];
|
|
27
27
|
sessionSource?: SessionSource;
|
|
28
28
|
automationId?: string;
|
|
29
|
+
/** 会话级系统提示(团队 / 自动化的角色与规则);走 provider 的系统提示通道。 */
|
|
30
|
+
systemPrompt?: string;
|
|
29
31
|
/** 所属工作空间 ID(多标签 / 分屏项目)。 */
|
|
30
32
|
workspaceId?: string;
|
|
31
33
|
/** 所属工作空间任务 ID(任务 = 独立 worktree + 一组标签)。 */
|
|
@@ -38,6 +40,12 @@ interface CreateStructuredSessionOptions {
|
|
|
38
40
|
*/
|
|
39
41
|
claudeSessionId?: string;
|
|
40
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* 转发会话(AI 团队群聊):外观是普通结构化会话,但不起 CLI。
|
|
45
|
+
* 用户发的话交给 handler,别的参与者的发言由 appendRelayTurns 写进来。
|
|
46
|
+
* 按 automationId 前缀识别,重启后照样生效。
|
|
47
|
+
*/
|
|
48
|
+
export type StructuredRelayHandler = (sessionId: string, text: string) => void | Promise<void>;
|
|
41
49
|
/**
|
|
42
50
|
* 返回最近一次真正提交给结构化会话的用户输入。
|
|
43
51
|
*
|
|
@@ -89,6 +97,7 @@ export declare class StructuredSessionManager {
|
|
|
89
97
|
* map 大小溢出时按时间裁剪。
|
|
90
98
|
*/
|
|
91
99
|
private readonly seenIdempotencyKeys;
|
|
100
|
+
private readonly relayHandlers;
|
|
92
101
|
private emitEvent;
|
|
93
102
|
private archiveTimer;
|
|
94
103
|
private readonly topicCoordinator;
|
|
@@ -139,6 +148,14 @@ export declare class StructuredSessionManager {
|
|
|
139
148
|
setWorktreeMergeState(id: string, status: SessionSnapshot["worktreeMergeStatus"], info: SessionSnapshot["worktreeMergeInfo"]): SessionSnapshot | null;
|
|
140
149
|
private maybeGenerateSessionTopic;
|
|
141
150
|
createSession(options: CreateStructuredSessionOptions): SessionSnapshot;
|
|
151
|
+
registerRelay(automationIdPrefix: string, handler: StructuredRelayHandler): void;
|
|
152
|
+
private relayHandlerFor;
|
|
153
|
+
createRelaySession(options: CreateStructuredSessionOptions & {
|
|
154
|
+
automationId: string;
|
|
155
|
+
title: string;
|
|
156
|
+
}): SessionSnapshot;
|
|
157
|
+
/** 往转发会话里追加别的参与者的发言。 */
|
|
158
|
+
appendRelayTurns(id: string, turns: ConversationTurn[]): SessionSnapshot | null;
|
|
142
159
|
sendMessage(id: string, input: string, opts?: {
|
|
143
160
|
interrupt?: boolean;
|
|
144
161
|
idempotencyKey?: string;
|
|
@@ -14,7 +14,7 @@ import { resolveSystemAiContext } from "./session-ai-context.js";
|
|
|
14
14
|
import { CodexRunner } from "./structured-codex-adapter.js";
|
|
15
15
|
import { CodexProtocolReducer } from "./structured-codex-protocol.js";
|
|
16
16
|
import { normalizeStructuredToolResultContent } from "./structured-content.js";
|
|
17
|
-
import {
|
|
17
|
+
import { buildClaudeSdkThinking, buildSessionSystemPromptParts, ClaudeCliRunner, derivePermissionPolicy, } from "./structured-claude-adapter.js";
|
|
18
18
|
import { inferStructuredEscalation, structuredPermissionDenied } from "./structured-permission.js";
|
|
19
19
|
import { captureTaskMeta, extractClaudeAssistantMessage, extractClaudeModelName, normalizeClaudeToolInput, stampParentTaskResults, stampSelfTask, tagSubagentBlocks, ClaudeCliProtocolReducer, } from "./structured-claude-protocol.js";
|
|
20
20
|
import { OpenCodeRunner, applyOpenCodeEvent } from "./structured-opencode-adapter.js";
|
|
@@ -24,7 +24,6 @@ import { PiRunner, applyPiEvent, isMissingPiSession } from "./structured-pi-adap
|
|
|
24
24
|
import { structuredRunId, } from "./structured-exec-host.js";
|
|
25
25
|
import { defaultStructuredRunner, defaultStructuredState, isStructuredRunnerForProvider, normalizeThinkingEffort, resolveStructuredRunner, } from "./structured-provider-common.js";
|
|
26
26
|
import { enrichStructuredMessages, WAND_PROTOCOL_VERSION } from "./structured-client-protocol.js";
|
|
27
|
-
/** The runner already persisted/emitted its detailed terminal snapshot. */
|
|
28
27
|
class PersistedStructuredRunnerError extends Error {
|
|
29
28
|
constructor(message) {
|
|
30
29
|
super(message);
|
|
@@ -416,6 +415,7 @@ export class StructuredSessionManager {
|
|
|
416
415
|
* map 大小溢出时按时间裁剪。
|
|
417
416
|
*/
|
|
418
417
|
seenIdempotencyKeys = new Map();
|
|
418
|
+
relayHandlers = new Map();
|
|
419
419
|
emitEvent = null;
|
|
420
420
|
archiveTimer = null;
|
|
421
421
|
topicCoordinator = new SessionTopicCoordinator();
|
|
@@ -1168,6 +1168,7 @@ export class StructuredSessionManager {
|
|
|
1168
1168
|
sessionKind: "structured",
|
|
1169
1169
|
sessionSource: options.sessionSource ?? "interactive",
|
|
1170
1170
|
automationId: options.automationId,
|
|
1171
|
+
systemPrompt: options.systemPrompt?.trim() || null,
|
|
1171
1172
|
workspaceId: options.workspaceId,
|
|
1172
1173
|
workspaceTaskId: options.workspaceTaskId,
|
|
1173
1174
|
provider,
|
|
@@ -1218,6 +1219,43 @@ export class StructuredSessionManager {
|
|
|
1218
1219
|
this.emit({ type: "started", sessionId: id, data: { sessionKind: "structured" } });
|
|
1219
1220
|
return snapshot;
|
|
1220
1221
|
}
|
|
1222
|
+
registerRelay(automationIdPrefix, handler) {
|
|
1223
|
+
this.relayHandlers.set(automationIdPrefix, handler);
|
|
1224
|
+
}
|
|
1225
|
+
relayHandlerFor(session) {
|
|
1226
|
+
const automationId = session.automationId ?? "";
|
|
1227
|
+
for (const [prefix, handler] of this.relayHandlers) {
|
|
1228
|
+
if (automationId.startsWith(prefix))
|
|
1229
|
+
return handler;
|
|
1230
|
+
}
|
|
1231
|
+
return null;
|
|
1232
|
+
}
|
|
1233
|
+
createRelaySession(options) {
|
|
1234
|
+
const created = this.createSession(options);
|
|
1235
|
+
const titled = { ...created, title: options.title };
|
|
1236
|
+
this.sessions.set(titled.id, titled);
|
|
1237
|
+
this.storage.saveSession(titled);
|
|
1238
|
+
this.emitStructuredSnapshot(titled);
|
|
1239
|
+
return titled;
|
|
1240
|
+
}
|
|
1241
|
+
/** 往转发会话里追加别的参与者的发言。 */
|
|
1242
|
+
appendRelayTurns(id, turns) {
|
|
1243
|
+
const session = this.sessions.get(id);
|
|
1244
|
+
if (!session || turns.length === 0)
|
|
1245
|
+
return session ?? null;
|
|
1246
|
+
const createdAt = new Date().toISOString();
|
|
1247
|
+
const updated = {
|
|
1248
|
+
...session,
|
|
1249
|
+
messages: [
|
|
1250
|
+
...(session.messages ?? []),
|
|
1251
|
+
...turns.map((turn) => ({ ...turn, createdAt: turn.createdAt ?? createdAt })),
|
|
1252
|
+
],
|
|
1253
|
+
};
|
|
1254
|
+
this.sessions.set(id, updated);
|
|
1255
|
+
this.storage.saveSession(updated);
|
|
1256
|
+
this.emitStructuredSnapshot(updated);
|
|
1257
|
+
return updated;
|
|
1258
|
+
}
|
|
1221
1259
|
async sendMessage(id, input, opts) {
|
|
1222
1260
|
if (this.disposed)
|
|
1223
1261
|
throw new Error("StructuredSessionManager has been disposed.");
|
|
@@ -1225,6 +1263,20 @@ export class StructuredSessionManager {
|
|
|
1225
1263
|
const prompt = input.trim();
|
|
1226
1264
|
if (!prompt)
|
|
1227
1265
|
return session;
|
|
1266
|
+
const relay = this.relayHandlerFor(session);
|
|
1267
|
+
if (relay) {
|
|
1268
|
+
// 群聊不起 CLI:先落下用户这句话,再交给转发方;转发失败以提示行告诉用户。
|
|
1269
|
+
const posted = this.appendRelayTurns(id, [{ role: "user", content: [{ type: "text", text: prompt }] }]);
|
|
1270
|
+
try {
|
|
1271
|
+
await relay(id, prompt);
|
|
1272
|
+
}
|
|
1273
|
+
catch (error) {
|
|
1274
|
+
this.appendRelayTurns(id, [{
|
|
1275
|
+
role: "assistant", notice: true, content: [{ type: "text", text: `没能转达:${getErrorMessage(error)}` }],
|
|
1276
|
+
}]);
|
|
1277
|
+
}
|
|
1278
|
+
return this.sessions.get(id) ?? posted;
|
|
1279
|
+
}
|
|
1228
1280
|
const skills = opts?.skills ?? [];
|
|
1229
1281
|
if (opts?.idempotencyKey) {
|
|
1230
1282
|
const mapKey = `${id}:${opts.idempotencyKey}`;
|
|
@@ -2639,13 +2691,18 @@ export class StructuredSessionManager {
|
|
|
2639
2691
|
const interruptedByUser = this.interruptedWith.has(sessionId);
|
|
2640
2692
|
const interruptedForQuestion = result.stopReason === "ask-user-question";
|
|
2641
2693
|
const failedExit = (result.exitCode !== null && result.exitCode !== 0) || result.signal !== null;
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2694
|
+
// Pi 等 CLI 在 provider 报错(额度用尽、鉴权失败)时仍以 0 退出;这一轮没有任何产出时
|
|
2695
|
+
// 必须按失败落盘,否则会被当成一次空回复,用户和团队调度都看不到真正的错误。
|
|
2696
|
+
const erroredEmptyTurn = !failedExit && !!result.primaryError && !result.state.blocks.some((block) => block.type === "tool_use" || (block.type === "text" && block.text.trim() !== ""));
|
|
2697
|
+
if ((failedExit || erroredEmptyTurn) && !interruptedByUser && !interruptedForQuestion) {
|
|
2698
|
+
const errorText = erroredEmptyTurn
|
|
2699
|
+
? result.primaryError.trim()
|
|
2700
|
+
: this.formatStructuredExitError(commandLabel, result.exitCode, result.signal, {
|
|
2701
|
+
stderr: result.stderr,
|
|
2702
|
+
stdoutTail: result.stdoutTail,
|
|
2703
|
+
primary: result.primaryError,
|
|
2704
|
+
});
|
|
2705
|
+
const failed = this.finishStructuredFailure(current, failedExit && typeof result.exitCode === "number" ? result.exitCode : 1, errorText, result.state);
|
|
2649
2706
|
if (provider === "pi" && isMissingPiSession(result.stderr, current.claudeSessionId)) {
|
|
2650
2707
|
failed.claudeSessionId = null;
|
|
2651
2708
|
}
|
|
@@ -2734,7 +2791,7 @@ export class StructuredSessionManager {
|
|
|
2734
2791
|
let killedForAskUserQuestion = false;
|
|
2735
2792
|
// 权限策略 + 系统提示词都通过共享 helper 派生,与 CLI runner 一字不差。
|
|
2736
2793
|
const permPolicy = derivePermissionPolicy(session.mode, session.autoApprovePermissions ?? false, session.cwd);
|
|
2737
|
-
const systemPromptParts =
|
|
2794
|
+
const systemPromptParts = buildSessionSystemPromptParts(session, this.config.language);
|
|
2738
2795
|
const sdkClaudeBinary = resolveSdkClaudeBinary();
|
|
2739
2796
|
// SDK 默认会把整个 process.env 透传给 claude 子进程;这里显式按 inheritEnv 配置组装,
|
|
2740
2797
|
// 否则关闭"继承环境变量"开关时 SDK 路径会被静默忽略。
|
package/dist/system-ai.d.ts
CHANGED
|
@@ -11,6 +11,17 @@ export declare function systemAiProfiles(config: SystemAiConfig | undefined, for
|
|
|
11
11
|
* Later groups are appended after earlier groups and duplicate routes are skipped.
|
|
12
12
|
*/
|
|
13
13
|
export declare function mergeSystemAiConfigs(...groups: Array<SystemAiConfig | SystemAiConfig[] | undefined>): SystemAiConfig | undefined;
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* 一次性 AI 请求:规则 / 角色走系统提示,内容走用户消息。
|
|
16
|
+
* 直连 API 用各协议的 system 通道;CLI 用各 provider 自己的系统提示开关
|
|
17
|
+
* (`systemPromptFlag`),没有开关的 provider 退回把规则并在内容前面。
|
|
18
|
+
*/
|
|
19
|
+
export interface AiTextRequest {
|
|
20
|
+
/** 规则、角色、输出格式。空字符串表示这次调用不需要系统提示。 */
|
|
21
|
+
system: string;
|
|
22
|
+
/** 本次要处理的内容(diff、用户原话、对话摘要…)。 */
|
|
23
|
+
prompt: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function callSystemAiText(request: AiTextRequest, config: SystemAiConfig, timeoutMs?: number): Promise<string>;
|
|
15
26
|
/** Try every configured API in order. Empty responses are treated as unavailable. */
|
|
16
|
-
export declare function callSystemAiTextWithFallback(
|
|
27
|
+
export declare function callSystemAiTextWithFallback(request: AiTextRequest, config: SystemAiConfig, timeoutMs?: number): Promise<string>;
|
package/dist/system-ai.js
CHANGED
|
@@ -344,11 +344,15 @@ function endpoint(baseUrl, protocol) {
|
|
|
344
344
|
}
|
|
345
345
|
return url.toString();
|
|
346
346
|
}
|
|
347
|
-
|
|
347
|
+
function requestParts(request) {
|
|
348
|
+
return { system: request.system?.trim() ?? "", prompt: request.prompt ?? "" };
|
|
349
|
+
}
|
|
350
|
+
export async function callSystemAiText(request, config, timeoutMs = SYSTEM_AI_TIMEOUT_MS) {
|
|
348
351
|
const normalized = normalizeSystemAiConfig(config);
|
|
349
352
|
if (!normalized.enabled || !normalized.baseUrl || !normalized.apiKey || !normalized.model) {
|
|
350
353
|
throw new SystemAiError("系统 AI API 配置不完整。", "SYSTEM_AI_CONFIG_INVALID");
|
|
351
354
|
}
|
|
355
|
+
const { system, prompt } = requestParts(request);
|
|
352
356
|
const headers = { "content-type": "application/json" };
|
|
353
357
|
if (normalized.protocol === "anthropic") {
|
|
354
358
|
headers["anthropic-version"] = "2023-06-01";
|
|
@@ -364,14 +368,14 @@ export async function callSystemAiText(prompt, config, timeoutMs = SYSTEM_AI_TIM
|
|
|
364
368
|
headers.authorization = `Bearer ${normalized.apiKey}`;
|
|
365
369
|
}
|
|
366
370
|
const body = normalized.protocol === "anthropic"
|
|
367
|
-
? { model: normalized.model, max_tokens: 2048, messages: [{ role: "user", content: prompt }] }
|
|
371
|
+
? { model: normalized.model, max_tokens: 2048, ...(system ? { system } : {}), messages: [{ role: "user", content: prompt }] }
|
|
368
372
|
: {
|
|
369
373
|
model: normalized.model,
|
|
370
374
|
// Quick system tasks should not silently inherit a model's expensive
|
|
371
375
|
// default reasoning level. Settings probes a route with this same
|
|
372
376
|
// payload, so an incompatible endpoint fails visibly before it is used.
|
|
373
377
|
reasoning_effort: "low",
|
|
374
|
-
messages: [{ role: "user", content: prompt }],
|
|
378
|
+
messages: [...(system ? [{ role: "system", content: system }] : []), { role: "user", content: prompt }],
|
|
375
379
|
stream: false,
|
|
376
380
|
};
|
|
377
381
|
let response;
|
|
@@ -399,7 +403,7 @@ export async function callSystemAiText(prompt, config, timeoutMs = SYSTEM_AI_TIM
|
|
|
399
403
|
}
|
|
400
404
|
}
|
|
401
405
|
/** Try every configured API in order. Empty responses are treated as unavailable. */
|
|
402
|
-
export async function callSystemAiTextWithFallback(
|
|
406
|
+
export async function callSystemAiTextWithFallback(request, config, timeoutMs = SYSTEM_AI_TIMEOUT_MS) {
|
|
403
407
|
const profiles = systemAiProfiles(config, true);
|
|
404
408
|
if (!profiles.length) {
|
|
405
409
|
throw new SystemAiError("系统 AI API 配置不完整。", "SYSTEM_AI_CONFIG_INVALID");
|
|
@@ -407,7 +411,7 @@ export async function callSystemAiTextWithFallback(prompt, config, timeoutMs = S
|
|
|
407
411
|
const errors = [];
|
|
408
412
|
for (const profile of profiles) {
|
|
409
413
|
try {
|
|
410
|
-
const text = await callSystemAiText(
|
|
414
|
+
const text = await callSystemAiText(request, profile, timeoutMs);
|
|
411
415
|
if (text.trim())
|
|
412
416
|
return text;
|
|
413
417
|
errors.push(`${profile.source ?? "custom"}: 返回空结果`);
|
package/dist/task-title.js
CHANGED
|
@@ -69,16 +69,16 @@ export async function generateWandTaskTitle(description, cwd, language = "", ai
|
|
|
69
69
|
if (!input)
|
|
70
70
|
throw new Error("没有可总结的任务描述。");
|
|
71
71
|
const outputLanguage = language.trim() || "与描述相同的语言";
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
input
|
|
80
|
-
|
|
81
|
-
const raw = await callConfiguredAiText(
|
|
72
|
+
const request = {
|
|
73
|
+
system: [
|
|
74
|
+
"根据用户消息里的任务描述,写一个用于任务列表的具体标题。",
|
|
75
|
+
`使用${outputLanguage}输出。`,
|
|
76
|
+
"只输出标题本身:一行纯文本,不要引号、不要 Markdown、不要编号、不要「标题:」这类前缀、不要任何解释。",
|
|
77
|
+
"不超过 20 个字,必须点出描述里的具体对象或动作,不要使用「任务」「待办」「关于」「请求」等空泛词。",
|
|
78
|
+
].join("\n"),
|
|
79
|
+
prompt: `任务描述:\n${input}`,
|
|
80
|
+
};
|
|
81
|
+
const raw = await callConfiguredAiText(request, cwd || process.cwd(), language, ai);
|
|
82
82
|
const stripped = stripGeneratedTitle(raw);
|
|
83
83
|
// 拿到报错文案 / 整段解释时宁可保留占位标题,也不能把垃圾写进看板。
|
|
84
84
|
// 先判可信度再裁剪:截断过的长句看起来就像标题,会绕过长度检查。
|
package/dist/types.d.ts
CHANGED
|
@@ -57,8 +57,6 @@ export interface CardExpandDefaults {
|
|
|
57
57
|
terminal?: boolean;
|
|
58
58
|
/** Thinking blocks (default: false) */
|
|
59
59
|
thinking?: boolean;
|
|
60
|
-
/** Tool groups (default: false) */
|
|
61
|
-
toolGroup?: boolean;
|
|
62
60
|
}
|
|
63
61
|
export interface AndroidApkConfig {
|
|
64
62
|
enabled?: boolean;
|
|
@@ -363,6 +361,11 @@ export interface CommandRequest {
|
|
|
363
361
|
cwd?: string;
|
|
364
362
|
mode?: ExecutionMode;
|
|
365
363
|
initialInput?: string;
|
|
364
|
+
/**
|
|
365
|
+
* 会话级系统提示(角色、规则):走 provider 自己的系统提示开关,
|
|
366
|
+
* 不要拼进 initialInput。见 AGENTS.md「Session 输入契约」。
|
|
367
|
+
*/
|
|
368
|
+
systemPrompt?: string;
|
|
366
369
|
worktreeEnabled?: boolean;
|
|
367
370
|
/** 模型(别名或完整 ID)。留空则按 provider 回落到服务端默认模型。 */
|
|
368
371
|
model?: string;
|
|
@@ -514,9 +517,24 @@ export interface ToolResultBlock {
|
|
|
514
517
|
__subagent?: SubagentMeta;
|
|
515
518
|
}
|
|
516
519
|
export type ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock;
|
|
520
|
+
/** 群聊(AI 团队)里的发言人;普通会话没有,按 role 用默认人设。 */
|
|
521
|
+
export interface ConversationAuthor {
|
|
522
|
+
/** 团队成员 id;用户发言为 "user"。 */
|
|
523
|
+
id: string;
|
|
524
|
+
name: string;
|
|
525
|
+
/** 成员头像:上传的 data URL、"cat:<n>" 指定毛色,或空(按 id 哈希毛色)。 */
|
|
526
|
+
avatar?: string;
|
|
527
|
+
leader?: boolean;
|
|
528
|
+
provider?: SessionProvider;
|
|
529
|
+
/** 这条发言对应的成员会话,可点开看完整过程。 */
|
|
530
|
+
sessionId?: string;
|
|
531
|
+
}
|
|
517
532
|
export interface ConversationTurn {
|
|
518
533
|
role: "user" | "assistant";
|
|
519
534
|
content: ContentBlock[];
|
|
535
|
+
author?: ConversationAuthor;
|
|
536
|
+
/** 群聊里的进度提示(派工、开始、出错):渲染成居中的一行,不是气泡。 */
|
|
537
|
+
notice?: boolean;
|
|
520
538
|
/** ISO time when this turn was first recorded (user send / assistant start). */
|
|
521
539
|
createdAt?: string;
|
|
522
540
|
/** ISO time when an assistant turn finished streaming. */
|
|
@@ -550,6 +568,11 @@ export interface SessionSnapshot {
|
|
|
550
568
|
sessionSource?: SessionSource;
|
|
551
569
|
/** 自动化创建会话时关联的自动化任务 ID。 */
|
|
552
570
|
automationId?: string;
|
|
571
|
+
/**
|
|
572
|
+
* 会话级系统提示:自动化 / 团队会话的角色与规则放这里,走 provider 的系统提示通道,
|
|
573
|
+
* 不要拼进首条用户消息。provider 没有该通道时(codex / opencode)由调用方退回并入消息。
|
|
574
|
+
*/
|
|
575
|
+
systemPrompt?: string | null;
|
|
553
576
|
/** 所属工作空间 ID(多标签 / 分屏项目)。会话在该工作空间窗口内作为一个标签。 */
|
|
554
577
|
workspaceId?: string;
|
|
555
578
|
/** 所属工作空间任务 ID;任务独占一个 worktree,其下所有会话共享该 worktree 目录。 */
|
package/dist/wand-task-sync.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare function taskAutoNameSignature(source: string): string;
|
|
|
22
22
|
export declare function ensureBoardTaskForWorkspaceTask(storage: WandStorage, task: WorkspaceTask, workspace: Workspace, options?: {
|
|
23
23
|
titleSource?: WandTaskTitleSource;
|
|
24
24
|
description?: string;
|
|
25
|
+
parentTaskId?: string | null;
|
|
25
26
|
}): WandTask;
|
|
26
27
|
/** A board task always has a sidebar container, even before its first session. */
|
|
27
28
|
export declare function ensureWorkspaceTaskForBoardTask(storage: WandStorage, card: WandTask): WorkspaceTask;
|
package/dist/wand-task-sync.js
CHANGED
|
@@ -112,6 +112,7 @@ export function ensureBoardTaskForWorkspaceTask(storage, task, workspace, option
|
|
|
112
112
|
return storage.createWandTask({
|
|
113
113
|
workspaceId: workspace.kind === "global" ? null : workspace.id,
|
|
114
114
|
workspaceTaskId: task.id,
|
|
115
|
+
parentTaskId: options.parentTaskId ?? null,
|
|
115
116
|
title: task.name,
|
|
116
117
|
// 占位名(未命名任务 / 新任务 / 空)走自动命名;用户填过名就是 user,永不被模型覆盖。
|
|
117
118
|
titleSource: options.titleSource ?? (isUnnamedWorkspaceTaskName(task.name) ? "auto" : "user"),
|