dsh-agent-toolkit 0.2.9 → 0.3.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/lib/client.js +103 -87
- package/lib/client.js.map +1 -1
- package/lib/index.js +77 -14
- package/lib/index.js.map +1 -1
- package/package.json +8 -4
package/lib/index.js
CHANGED
|
@@ -71,7 +71,10 @@ function isTeamVisible(role) {
|
|
|
71
71
|
const BASIC_TOOLS = [
|
|
72
72
|
{
|
|
73
73
|
id: "@deepseek-ai/dsh-persona",
|
|
74
|
-
config: {
|
|
74
|
+
config: {
|
|
75
|
+
prefix: "You are a coding agent powered by the {{model}} model. If you need information or a decision from the user, ask directly in your reply and wait for their next message.",
|
|
76
|
+
suffix: "Your working directory is {{cwd}}."
|
|
77
|
+
}
|
|
75
78
|
},
|
|
76
79
|
{
|
|
77
80
|
id: "@deepseek-ai/dsh-agent-instructions",
|
|
@@ -1469,8 +1472,6 @@ function createDelegateTool(toolName, deps) {
|
|
|
1469
1472
|
}
|
|
1470
1473
|
//#endregion
|
|
1471
1474
|
//#region src/delegate/index.ts
|
|
1472
|
-
/** 团队名册段在 prompt 中的位置:紧随内置 subagent 段(116.5)之后。 */
|
|
1473
|
-
const TEAM_SECTION_ORDER = 116.6;
|
|
1474
1475
|
/**
|
|
1475
1476
|
* 团队名册段文本:仅当该 agent scope 的可见工具里确有委派工具时渲染,否则空
|
|
1476
1477
|
* (空段渲染时被丢弃)。工具白名单 restrict 只作用于 tools 视图,名册段必须
|
|
@@ -1530,7 +1531,7 @@ function setupDelegate(ctx, config, registry, channels) {
|
|
|
1530
1531
|
else ctx.logger.info(`dsh-agent-toolkit: subagent provider "${provider}" 尚未注册;team_delegate 将等它出现时挂载`);
|
|
1531
1532
|
ctx.systemPrompt.section({
|
|
1532
1533
|
name: "plugin:dsh-agent-toolkit:team",
|
|
1533
|
-
order:
|
|
1534
|
+
order: ctx.systemPrompt.getSectionOrder("TOOL_SUBAGENT") + .1,
|
|
1534
1535
|
text: (context) => teamSectionText(config.toolName, registry.list(), ctx.tools.get(config.toolName, context.scope) !== void 0)
|
|
1535
1536
|
});
|
|
1536
1537
|
}
|
|
@@ -2931,6 +2932,13 @@ const projectBotDomain = defineDomain({
|
|
|
2931
2932
|
function bindingKey(botId, chatId) {
|
|
2932
2933
|
return `${botId}:${chatId}`;
|
|
2933
2934
|
}
|
|
2935
|
+
//#endregion
|
|
2936
|
+
//#region src/channels/outbound.ts
|
|
2937
|
+
/** 从 assistant 消息内容块取最后一个 text 块的纯文本;无 text 块返回 ''(非 undefined)。 */
|
|
2938
|
+
function lastTextOf(content) {
|
|
2939
|
+
const texts = content.filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text);
|
|
2940
|
+
return texts.length === 0 ? "" : texts[texts.length - 1];
|
|
2941
|
+
}
|
|
2934
2942
|
/** 向段序列追加内容:与尾段同类则合并,异类开新段。 */
|
|
2935
2943
|
function appendToSegments(segments, kind, text) {
|
|
2936
2944
|
const tail = segments[segments.length - 1];
|
|
@@ -2940,6 +2948,30 @@ function appendToSegments(segments, kind, text) {
|
|
|
2940
2948
|
content: text
|
|
2941
2949
|
});
|
|
2942
2950
|
}
|
|
2951
|
+
/** 向段序列应用一个流式 chunk:text-delta → text、reasoning-delta → process、reasoning block-end → 过程段段落分隔;其余类型不消费返回 false。 */
|
|
2952
|
+
function applyStreamChunk(segments, chunk) {
|
|
2953
|
+
if (chunk.type === "text-delta") appendToSegments(segments, "text", chunk.text);
|
|
2954
|
+
else if (chunk.type === "reasoning-delta") appendToSegments(segments, "process", chunk.text);
|
|
2955
|
+
else if (chunk.type === "block-end" && chunk.block?.type === "reasoning" && segments[segments.length - 1]?.kind === "process") appendToSegments(segments, "process", "\n\n");
|
|
2956
|
+
else return false;
|
|
2957
|
+
return true;
|
|
2958
|
+
}
|
|
2959
|
+
/**
|
|
2960
|
+
* 对账尾 text 段:把最后一个 text 段的内容替换为权威全文(丢帧补齐)。
|
|
2961
|
+
* 前置条件:调用方已保证尾 text 段归属本结算 step(lastTextStep 命中结算 step)。
|
|
2962
|
+
* 返回是否发生替换;authoritative 为空、无 text 段或内容已相等时返回 false。
|
|
2963
|
+
*/
|
|
2964
|
+
function reconcileTrailingText(segments, authoritative) {
|
|
2965
|
+
if (authoritative === "") return false;
|
|
2966
|
+
let tail;
|
|
2967
|
+
for (let i = segments.length - 1; i >= 0; i--) if (segments[i].kind === "text") {
|
|
2968
|
+
tail = segments[i];
|
|
2969
|
+
break;
|
|
2970
|
+
}
|
|
2971
|
+
if (tail === void 0 || tail.content === authoritative) return false;
|
|
2972
|
+
tail.content = authoritative;
|
|
2973
|
+
return true;
|
|
2974
|
+
}
|
|
2943
2975
|
function mapTurnEnd(reason) {
|
|
2944
2976
|
if (reason.kind === "completed") return "done";
|
|
2945
2977
|
if (reason.kind === "aborted" || reason.kind === "interrupted") return "cancelled";
|
|
@@ -2975,14 +3007,12 @@ var Outbound = class {
|
|
|
2975
3007
|
};
|
|
2976
3008
|
return;
|
|
2977
3009
|
}
|
|
2978
|
-
if (event.type === "assistant/
|
|
3010
|
+
if (event.type === "assistant/message") {
|
|
2979
3011
|
const turn = rt.turn;
|
|
2980
3012
|
if (turn === void 0 || turn.n !== event.data.turn) return;
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
else if (chunk.type === "block-end" && chunk.block?.type === "reasoning" && turn.segments[turn.segments.length - 1]?.kind === "process") appendToSegments(turn.segments, "process", "\n\n");
|
|
2985
|
-
else return;
|
|
3013
|
+
if (turn.lastTextStep !== event.data.step) return;
|
|
3014
|
+
const authoritative = lastTextOf(event.data.message.content ?? []);
|
|
3015
|
+
if (!reconcileTrailingText(turn.segments, authoritative)) return;
|
|
2986
3016
|
const snapshot = turn.segments.map((s) => ({ ...s }));
|
|
2987
3017
|
this.enqueue(rt, async () => {
|
|
2988
3018
|
if (rt.reply === void 0) return;
|
|
@@ -3027,6 +3057,36 @@ var Outbound = class {
|
|
|
3027
3057
|
}
|
|
3028
3058
|
}
|
|
3029
3059
|
/**
|
|
3060
|
+
* 出站:瞬态流式帧 → 段构建 + 打字机。chunk 帧不携带 turn/step,由 start 帧建 attempt 基线
|
|
3061
|
+
* (turn/step,宿主 accumulator 同款取数);end 帧不消费;生命周期仍由 turn/start、turn/end 驱动。
|
|
3062
|
+
* 帧为 fire-and-forget,丢帧后无重传,正文由 assistant/message 结算对账有界恢复。
|
|
3063
|
+
*/
|
|
3064
|
+
handleAssistantFrame(sessionId, frame) {
|
|
3065
|
+
const rt = this.sessions.get(sessionId);
|
|
3066
|
+
if (rt === void 0) return;
|
|
3067
|
+
const turn = rt.turn;
|
|
3068
|
+
if (turn === void 0) return;
|
|
3069
|
+
if (frame.type === "start") {
|
|
3070
|
+
if (turn.n !== frame.turn) return;
|
|
3071
|
+
turn.attemptStep = frame.step;
|
|
3072
|
+
return;
|
|
3073
|
+
}
|
|
3074
|
+
if (frame.type !== "chunk") return;
|
|
3075
|
+
const step = turn.attemptStep;
|
|
3076
|
+
if (step === void 0) return;
|
|
3077
|
+
if (!applyStreamChunk(turn.segments, frame.chunk)) return;
|
|
3078
|
+
if (frame.chunk.type === "text-delta") turn.lastTextStep = step;
|
|
3079
|
+
const snapshot = turn.segments.map((s) => ({ ...s }));
|
|
3080
|
+
this.enqueue(rt, async () => {
|
|
3081
|
+
if (rt.reply === void 0) return;
|
|
3082
|
+
if (!turn.began) {
|
|
3083
|
+
await rt.reply.beginTurn();
|
|
3084
|
+
turn.began = true;
|
|
3085
|
+
}
|
|
3086
|
+
await rt.reply.update(snapshot);
|
|
3087
|
+
});
|
|
3088
|
+
}
|
|
3089
|
+
/**
|
|
3030
3090
|
* turn 外错误(agent/error:resume/驱动边界失败等没有 turn/end 的场景):
|
|
3031
3091
|
* notice 错误摘要并释放 inflight 槽 + 删除表情;turn 进行中的错误由 turn/end 报告,跳过防双发。
|
|
3032
3092
|
*/
|
|
@@ -3291,7 +3351,7 @@ var Router = class {
|
|
|
3291
3351
|
//#endregion
|
|
3292
3352
|
//#region src/channels/approval/center.ts
|
|
3293
3353
|
/** 审批中心(渠道无关):自有 bot 会话的 approval ask → 渠道审批卡片挂起 → 卡片回调 resolve。
|
|
3294
|
-
* spec: docs/superpowers/specs/2026-09-08-feishu-approval-card-design.md(飞书独占 / 仅发起人 / 不超时)。 */
|
|
3354
|
+
* spec: docs/superpowers/specs/archive/2026-09-08-feishu-approval-card-design.md(飞书独占 / 仅发起人 / 不超时)。 */
|
|
3295
3355
|
var ApprovalCenter = class {
|
|
3296
3356
|
sessions;
|
|
3297
3357
|
channelFor;
|
|
@@ -3927,7 +3987,7 @@ function setupBots(ctx, config, deps) {
|
|
|
3927
3987
|
return ref;
|
|
3928
3988
|
};
|
|
3929
3989
|
/** 创作期注入已迁至 agent-setup.ts + tool-scope.ts(基础工具行 standing scope 挂载 + persona/tools)。
|
|
3930
|
-
* preset 优先 joiner(agent-bot 组合):mount 成功后委派子会话 composeFrom 认父(spec: docs/superpowers/specs/2026-09-07-bot-delegation-preset-mount-design.md)。 */
|
|
3990
|
+
* preset 优先 joiner(agent-bot 组合):mount 成功后委派子会话 composeFrom 认父(spec: docs/superpowers/specs/archive/2026-09-07-bot-delegation-preset-mount-design.md)。 */
|
|
3931
3991
|
const toolsScope = createToolsScope(ctx);
|
|
3932
3992
|
const agentsPort = createAgentsPort(ctx, deps.botPresetId !== void 0 ? createScopeJoiner(ctx, deps.botPresetId, toolsScope, log.warn) : toolsScope, deps.ownedSessions);
|
|
3933
3993
|
const workspaceRegistry = ctx.get("workspaceRegistry", false);
|
|
@@ -3995,6 +4055,9 @@ function setupBots(ctx, config, deps) {
|
|
|
3995
4055
|
ctx.on("session/event", (session, event) => {
|
|
3996
4056
|
runtime?.outbound.handleSessionEvent(String(session.header.id), event);
|
|
3997
4057
|
});
|
|
4058
|
+
ctx.on("agent/assistant-stream", ({ agent, frame }) => {
|
|
4059
|
+
runtime?.outbound.handleAssistantFrame(String(agent.session.id), frame);
|
|
4060
|
+
});
|
|
3998
4061
|
if (config.approval) ctx.on("approval/request", createApprovalAnswerer(() => runtime?.approval), { prepend: true });
|
|
3999
4062
|
ctx.on("agent/error", ({ agent, error }) => {
|
|
4000
4063
|
const text = error instanceof Error ? error.message : String(error?.message ?? error);
|
|
@@ -4046,7 +4109,7 @@ function setupBots(ctx, config, deps) {
|
|
|
4046
4109
|
//#endregion
|
|
4047
4110
|
//#region src/agents/bot-preset.ts
|
|
4048
4111
|
/** agent-bot preset 组合序列化:BASIC_TOOLS → preset 行(bot 会话挂载的最小组合,
|
|
4049
|
-
* 委派子会话 composeFrom 认父的前提;spec: docs/superpowers/specs/2026-09-07-bot-delegation-preset-mount-design.md)。 */
|
|
4112
|
+
* 委派子会话 composeFrom 认父的前提;spec: docs/superpowers/specs/archive/2026-09-07-bot-delegation-preset-mount-design.md)。 */
|
|
4050
4113
|
/** BASIC_TOOLS 插件包名 → preset 行 id(与 standard/agent-team 的行 id 对齐)。新增 BASIC_TOOLS 行必须在此登记。 */
|
|
4051
4114
|
const ROW_IDS = {
|
|
4052
4115
|
"@deepseek-ai/dsh-persona": "persona",
|
|
@@ -4079,7 +4142,7 @@ function botPresetComposition() {
|
|
|
4079
4142
|
/**
|
|
4080
4143
|
* Agent 团队 preset 自动生成:派生宿主当前 shipped standard composition,
|
|
4081
4144
|
* 文本级禁用 subagent 工具族 4 个行,写入首个 trust=user 的 preset root。
|
|
4082
|
-
* 设计:docs/superpowers/specs/2026-09-02-agent-team-preset-design.md
|
|
4145
|
+
* 设计:docs/superpowers/specs/archive/2026-09-02-agent-team-preset-design.md
|
|
4083
4146
|
*/
|
|
4084
4147
|
/** 禁用目标行:覆盖与 team_delegate 竞争/配套的 5 个模型可见工具所属的 4 个行。 */
|
|
4085
4148
|
const TEAM_PRESET_DISABLED_ROWS = [
|