opencode-acp 1.13.8-dev.1 → 1.13.9-dev.1
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/README.md +8 -0
- package/README.zh-CN.md +8 -0
- package/dist/index.js +1 -161
- package/dist/index.js.map +1 -1
- package/dist/lib/compress/message.d.ts.map +1 -1
- package/dist/lib/compress/protected-content.d.ts +1 -1
- package/dist/lib/compress/protected-content.d.ts.map +1 -1
- package/dist/lib/compress/range.d.ts.map +1 -1
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/messages/index.d.ts +0 -1
- package/dist/lib/messages/index.d.ts.map +1 -1
- package/dist/lib/state/state.d.ts.map +1 -1
- package/dist/lib/state/types.d.ts +0 -1
- package/dist/lib/state/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/lib/messages/inject/subagent-results.d.ts +0 -4
- package/dist/lib/messages/inject/subagent-results.d.ts.map +0 -1
- package/dist/lib/subagents/subagent-results.d.ts +0 -5
- package/dist/lib/subagents/subagent-results.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -475,6 +475,14 @@ For the complete list with root cause analysis, see the [bug tracker](https://gi
|
|
|
475
475
|
|
|
476
476
|
## Changelog
|
|
477
477
|
|
|
478
|
+
### v1.13.9-dev.1 — Remove Subagent History Rewriting (PR #180)
|
|
479
|
+
|
|
480
|
+
**Problem**: `injectExtendedSubAgentResults` rewrote historical `<task_result>` tool outputs in the parent agent's message history on every transform run when `experimental.allowSubAgents: true`. The `subAgentResultCache` was cleared on every parent↔child session switch and was never persisted, so each transform run re-fetched the subagent session and produced a new historical message body — invalidating the provider prefix cache (observed: ~56% hit rate vs healthy 96–98%, prefix frozen at ~22K tokens).
|
|
481
|
+
|
|
482
|
+
**Fix**: PR #180 — Removed `injectExtendedSubAgentResults` from the message-transform pipeline and `appendProtectedTools`. Deleted `lib/messages/inject/subagent-results.ts` (82 lines) and `lib/subagents/subagent-results.ts` (74 lines). Dropped `subAgentResultCache` field from `SessionState`. The rewrite was redundant: OpenCode natively appends a `state="completed"` message with the full subagent result immediately after the `task` call completes. `experimental.allowSubAgents` still controls whether ACP runs inside subagent sessions — only the parent-history rewriting is gone. Dual-agent reviewed (both APPROVE).
|
|
483
|
+
|
|
484
|
+
Files: `lib/hooks.ts`, `lib/compress/protected-content.ts`, `lib/compress/{message,range}.ts`, `lib/state/{state,types}.ts`, `lib/messages/index.ts`, `AGENTS.md`. 851 tests pass.
|
|
485
|
+
|
|
478
486
|
### v1.13.8-dev.1 — Dev Prerelease Sync (master @ v1.13.7)
|
|
479
487
|
|
|
480
488
|
**Purpose**: Sync the `dev` npm tag with v1.13.7 stable. Content is identical to v1.13.7 — no new code changes. This brings `opencode-acp@dev` up to parity with `opencode-acp@latest` (1.13.7).
|
package/README.zh-CN.md
CHANGED
|
@@ -443,6 +443,14 @@ ACP 在首次启动时自动将配置从 `dcp.jsonc` 迁移到 `acp.jsonc`,将
|
|
|
443
443
|
|
|
444
444
|
## 更新日志
|
|
445
445
|
|
|
446
|
+
### v1.13.9-dev.1 — 移除子代理历史重写(PR #180)
|
|
447
|
+
|
|
448
|
+
**问题**:`injectExtendedSubAgentResults` 在 `experimental.allowSubAgents: true` 时,每次消息变换都会重写父代理历史中的 `<task_result>` 工具输出。`subAgentResultCache` 在每次父↔子会话切换时被清空且从不持久化,导致每次变换都重新获取子代理会话并生成新的历史消息体 —— 使 provider prefix cache 失效(观察到的命中率约 56%,健康水平为 96-98%,prefix 冻结在约 22K tokens)。
|
|
449
|
+
|
|
450
|
+
**修复**:PR #180 —— 从消息变换管道和 `appendProtectedTools` 中移除 `injectExtendedSubAgentResults`。删除 `lib/messages/inject/subagent-results.ts`(82 行)和 `lib/subagents/subagent-results.ts`(74 行)。从 `SessionState` 中移除 `subAgentResultCache` 字段。重写是冗余的:OpenCode 原生在 `task` 调用完成后立即追加一条 `state="completed"` 消息(含完整子代理结果)。`experimental.allowSubAgents` 仍然控制 ACP 是否在子代理会话中运行 —— 只是移除了父历史重写。经双 Agent 审查(均 APPROVE)。
|
|
451
|
+
|
|
452
|
+
文件:`lib/hooks.ts`、`lib/compress/protected-content.ts`、`lib/compress/{message,range}.ts`、`lib/state/{state,types}.ts`、`lib/messages/index.ts`、`AGENTS.md`。851 项测试通过。
|
|
453
|
+
|
|
446
454
|
### v1.13.8-dev.1 — Dev 预发布同步(master @ v1.13.7)
|
|
447
455
|
|
|
448
456
|
**目的**:将 npm `dev` 标签同步到 v1.13.7 稳定版。内容与 v1.13.7 完全相同 —— 无新代码变更。使 `opencode-acp@dev` 与 `opencode-acp@latest`(1.13.7)保持一致。
|
package/dist/index.js
CHANGED
|
@@ -2851,64 +2851,6 @@ function isToolNameProtected(toolName, patterns) {
|
|
|
2851
2851
|
return globPatterns.some((pattern) => matchesGlob(toolName, pattern));
|
|
2852
2852
|
}
|
|
2853
2853
|
|
|
2854
|
-
// lib/subagents/subagent-results.ts
|
|
2855
|
-
var SUB_AGENT_RESULT_BLOCK_REGEX = /(<task_result>\s*)([\s\S]*?)(\s*<\/task_result>)/i;
|
|
2856
|
-
function getSubAgentId(part) {
|
|
2857
|
-
const sessionId = part?.state?.metadata?.sessionId;
|
|
2858
|
-
if (typeof sessionId !== "string") {
|
|
2859
|
-
return null;
|
|
2860
|
-
}
|
|
2861
|
-
const value = sessionId.trim();
|
|
2862
|
-
return value.length > 0 ? value : null;
|
|
2863
|
-
}
|
|
2864
|
-
function buildSubagentResultText(messages) {
|
|
2865
|
-
const assistantMessages = messages.filter((message) => message.info.role === "assistant");
|
|
2866
|
-
if (assistantMessages.length === 0) {
|
|
2867
|
-
return "";
|
|
2868
|
-
}
|
|
2869
|
-
const lastAssistant = assistantMessages[assistantMessages.length - 1];
|
|
2870
|
-
const lastText = getLastTextPart(lastAssistant);
|
|
2871
|
-
if (assistantMessages.length < 2) {
|
|
2872
|
-
return lastText;
|
|
2873
|
-
}
|
|
2874
|
-
const secondToLastAssistant = assistantMessages[assistantMessages.length - 2];
|
|
2875
|
-
if (!assistantMessageHasCompressTool(secondToLastAssistant)) {
|
|
2876
|
-
return lastText;
|
|
2877
|
-
}
|
|
2878
|
-
const secondToLastText = getLastTextPart(secondToLastAssistant);
|
|
2879
|
-
return [secondToLastText, lastText].filter((text) => text.length > 0).join("\n\n");
|
|
2880
|
-
}
|
|
2881
|
-
function mergeSubagentResult(output, subAgentResultText) {
|
|
2882
|
-
if (!subAgentResultText || typeof output !== "string") {
|
|
2883
|
-
return output;
|
|
2884
|
-
}
|
|
2885
|
-
return output.replace(
|
|
2886
|
-
SUB_AGENT_RESULT_BLOCK_REGEX,
|
|
2887
|
-
(_match, openTag, _body, closeTag) => `${openTag}${subAgentResultText}${closeTag}`
|
|
2888
|
-
);
|
|
2889
|
-
}
|
|
2890
|
-
function getLastTextPart(message) {
|
|
2891
|
-
const parts = Array.isArray(message.parts) ? message.parts : [];
|
|
2892
|
-
for (let index = parts.length - 1; index >= 0; index--) {
|
|
2893
|
-
const part = parts[index];
|
|
2894
|
-
if (part.type !== "text" || typeof part.text !== "string") {
|
|
2895
|
-
continue;
|
|
2896
|
-
}
|
|
2897
|
-
const text = part.text.trim();
|
|
2898
|
-
if (!text) {
|
|
2899
|
-
continue;
|
|
2900
|
-
}
|
|
2901
|
-
return text;
|
|
2902
|
-
}
|
|
2903
|
-
return "";
|
|
2904
|
-
}
|
|
2905
|
-
function assistantMessageHasCompressTool(message) {
|
|
2906
|
-
const parts = Array.isArray(message.parts) ? message.parts : [];
|
|
2907
|
-
return parts.some(
|
|
2908
|
-
(part) => part.type === "tool" && part.tool === "compress" && part.state?.status === "completed"
|
|
2909
|
-
);
|
|
2910
|
-
}
|
|
2911
|
-
|
|
2912
2854
|
// lib/compress/protected-content.ts
|
|
2913
2855
|
function appendProtectedUserMessages(summary, selection, searchContext, state, enabled) {
|
|
2914
2856
|
if (!enabled) return summary;
|
|
@@ -2975,7 +2917,7 @@ function extractProtectedPromptInfo(text) {
|
|
|
2975
2917
|
}
|
|
2976
2918
|
return protectedTexts;
|
|
2977
2919
|
}
|
|
2978
|
-
async function appendProtectedTools(client, state,
|
|
2920
|
+
async function appendProtectedTools(client, state, summary, selection, searchContext, protectedTools, protectedFilePatterns = []) {
|
|
2979
2921
|
const protectedOutputs = [];
|
|
2980
2922
|
for (const messageId of selection.messageIds) {
|
|
2981
2923
|
const existingCompressionEntry = state.prune.messages.byMessageId.get(messageId);
|
|
@@ -3000,38 +2942,6 @@ async function appendProtectedTools(client, state, allowSubAgents, summary, sele
|
|
|
3000
2942
|
if (part.state?.status === "completed" && part.state?.output) {
|
|
3001
2943
|
output = typeof part.state.output === "string" ? part.state.output : JSON.stringify(part.state.output);
|
|
3002
2944
|
}
|
|
3003
|
-
if (allowSubAgents && part.tool === "task" && part.state?.status === "completed" && typeof part.state?.output === "string") {
|
|
3004
|
-
const cachedSubAgentResult = state.subAgentResultCache.get(part.callID);
|
|
3005
|
-
if (cachedSubAgentResult !== void 0) {
|
|
3006
|
-
if (cachedSubAgentResult) {
|
|
3007
|
-
output = mergeSubagentResult(
|
|
3008
|
-
part.state.output,
|
|
3009
|
-
cachedSubAgentResult
|
|
3010
|
-
);
|
|
3011
|
-
}
|
|
3012
|
-
} else {
|
|
3013
|
-
const subAgentSessionId = getSubAgentId(part);
|
|
3014
|
-
if (subAgentSessionId) {
|
|
3015
|
-
let subAgentResultText = "";
|
|
3016
|
-
try {
|
|
3017
|
-
const subAgentMessages = await fetchSessionMessages(
|
|
3018
|
-
client,
|
|
3019
|
-
subAgentSessionId
|
|
3020
|
-
);
|
|
3021
|
-
subAgentResultText = buildSubagentResultText(subAgentMessages);
|
|
3022
|
-
} catch {
|
|
3023
|
-
subAgentResultText = "";
|
|
3024
|
-
}
|
|
3025
|
-
if (subAgentResultText) {
|
|
3026
|
-
state.subAgentResultCache.set(part.callID, subAgentResultText);
|
|
3027
|
-
output = mergeSubagentResult(
|
|
3028
|
-
part.state.output,
|
|
3029
|
-
subAgentResultText
|
|
3030
|
-
);
|
|
3031
|
-
}
|
|
3032
|
-
}
|
|
3033
|
-
}
|
|
3034
|
-
}
|
|
3035
2945
|
if (output) {
|
|
3036
2946
|
protectedOutputs.push(`
|
|
3037
2947
|
### ${title}
|
|
@@ -4487,7 +4397,6 @@ function createSessionState() {
|
|
|
4487
4397
|
pendingByCallId: /* @__PURE__ */ new Map()
|
|
4488
4398
|
},
|
|
4489
4399
|
toolParameters: /* @__PURE__ */ new Map(),
|
|
4490
|
-
subAgentResultCache: /* @__PURE__ */ new Map(),
|
|
4491
4400
|
toolIdList: [],
|
|
4492
4401
|
messageIds: {
|
|
4493
4402
|
byRawId: /* @__PURE__ */ new Map(),
|
|
@@ -4527,7 +4436,6 @@ function resetSessionState(state) {
|
|
|
4527
4436
|
totalPruneTokens: 0
|
|
4528
4437
|
};
|
|
4529
4438
|
state.toolParameters.clear();
|
|
4530
|
-
state.subAgentResultCache.clear();
|
|
4531
4439
|
state.toolIdList = [];
|
|
4532
4440
|
state.messageIds = {
|
|
4533
4441
|
byRawId: /* @__PURE__ */ new Map(),
|
|
@@ -6535,7 +6443,6 @@ function createCompressMessageTool(factoryCtx) {
|
|
|
6535
6443
|
const summaryWithTools = await appendProtectedTools(
|
|
6536
6444
|
ctx.client,
|
|
6537
6445
|
ctx.state,
|
|
6538
|
-
ctx.config.experimental.allowSubAgents,
|
|
6539
6446
|
summaryWithPromptInfo,
|
|
6540
6447
|
plan.selection,
|
|
6541
6448
|
searchContext,
|
|
@@ -6780,7 +6687,6 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
6780
6687
|
const summaryWithTools = await appendProtectedTools(
|
|
6781
6688
|
ctx.client,
|
|
6782
6689
|
ctx.state,
|
|
6783
|
-
ctx.config.experimental.allowSubAgents,
|
|
6784
6690
|
summaryWithPromptInfo,
|
|
6785
6691
|
plan.selection,
|
|
6786
6692
|
searchContext,
|
|
@@ -8608,65 +8514,6 @@ var injectMessageIds = (state, config, messages, compressionPriorities) => {
|
|
|
8608
8514
|
}
|
|
8609
8515
|
};
|
|
8610
8516
|
|
|
8611
|
-
// lib/messages/inject/subagent-results.ts
|
|
8612
|
-
async function fetchSubAgentMessages(client, sessionId) {
|
|
8613
|
-
const response = await client.session.messages({
|
|
8614
|
-
path: { id: sessionId }
|
|
8615
|
-
});
|
|
8616
|
-
return filterMessages(response?.data || response);
|
|
8617
|
-
}
|
|
8618
|
-
var injectExtendedSubAgentResults = async (client, state, logger, messages, allowSubAgents) => {
|
|
8619
|
-
if (!allowSubAgents) {
|
|
8620
|
-
return;
|
|
8621
|
-
}
|
|
8622
|
-
for (const message of messages) {
|
|
8623
|
-
const parts = Array.isArray(message.parts) ? message.parts : [];
|
|
8624
|
-
for (const part of parts) {
|
|
8625
|
-
if (part.type !== "tool" || part.tool !== "task" || !part.callID) {
|
|
8626
|
-
continue;
|
|
8627
|
-
}
|
|
8628
|
-
if (state.prune.tools.has(part.callID)) {
|
|
8629
|
-
continue;
|
|
8630
|
-
}
|
|
8631
|
-
if (part.state?.status !== "completed" || typeof part.state.output !== "string") {
|
|
8632
|
-
continue;
|
|
8633
|
-
}
|
|
8634
|
-
const cachedResult = state.subAgentResultCache.get(part.callID);
|
|
8635
|
-
if (cachedResult !== void 0) {
|
|
8636
|
-
if (cachedResult) {
|
|
8637
|
-
part.state.output = stripHallucinationsFromString(
|
|
8638
|
-
mergeSubagentResult(part.state.output, cachedResult)
|
|
8639
|
-
);
|
|
8640
|
-
}
|
|
8641
|
-
continue;
|
|
8642
|
-
}
|
|
8643
|
-
const subAgentSessionId = getSubAgentId(part);
|
|
8644
|
-
if (!subAgentSessionId) {
|
|
8645
|
-
continue;
|
|
8646
|
-
}
|
|
8647
|
-
let subAgentMessages = [];
|
|
8648
|
-
try {
|
|
8649
|
-
subAgentMessages = await fetchSubAgentMessages(client, subAgentSessionId);
|
|
8650
|
-
} catch (error) {
|
|
8651
|
-
logger.warn("Failed to fetch subagent session for output expansion", {
|
|
8652
|
-
subAgentSessionId,
|
|
8653
|
-
callID: part.callID,
|
|
8654
|
-
error: error instanceof Error ? error.message : String(error)
|
|
8655
|
-
});
|
|
8656
|
-
continue;
|
|
8657
|
-
}
|
|
8658
|
-
const subAgentResultText = buildSubagentResultText(subAgentMessages);
|
|
8659
|
-
if (!subAgentResultText) {
|
|
8660
|
-
continue;
|
|
8661
|
-
}
|
|
8662
|
-
state.subAgentResultCache.set(part.callID, subAgentResultText);
|
|
8663
|
-
part.state.output = stripHallucinationsFromString(
|
|
8664
|
-
mergeSubagentResult(part.state.output, subAgentResultText)
|
|
8665
|
-
);
|
|
8666
|
-
}
|
|
8667
|
-
}
|
|
8668
|
-
};
|
|
8669
|
-
|
|
8670
8517
|
// lib/messages/reasoning-strip.ts
|
|
8671
8518
|
function stripStaleMetadata(messages) {
|
|
8672
8519
|
const lastUserMessage = getLastUserMessage(messages);
|
|
@@ -11777,13 +11624,6 @@ function createChatMessageTransformHandler(client, registry3, logger, config, pr
|
|
|
11777
11624
|
const prePruneTokens = getCurrentTokenUsage(state, output.messages);
|
|
11778
11625
|
prune(state, logger, config, output.messages);
|
|
11779
11626
|
assignMessageRefs(state, output.messages);
|
|
11780
|
-
await injectExtendedSubAgentResults(
|
|
11781
|
-
client,
|
|
11782
|
-
state,
|
|
11783
|
-
logger,
|
|
11784
|
-
output.messages,
|
|
11785
|
-
config.experimental.allowSubAgents
|
|
11786
|
-
);
|
|
11787
11627
|
const compressionPriorities = buildPriorityMap(config, state, output.messages);
|
|
11788
11628
|
prompts.reload();
|
|
11789
11629
|
injectCompressNudges(
|