@royalcat/opencode-dcp-rc 4.0.1 → 4.0.2
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 +21 -1
- package/dist/index.js +874 -17
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +2 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/prompts/context-limit-nudge.d.ts +1 -1
- package/dist/lib/prompts/context-limit-nudge.d.ts.map +1 -1
- package/dist/lib/prompts/extensions/system.d.ts +2 -2
- package/dist/lib/prompts/extensions/system.d.ts.map +1 -1
- package/dist/lib/prompts/iteration-nudge.d.ts +1 -1
- package/dist/lib/prompts/iteration-nudge.d.ts.map +1 -1
- package/dist/lib/prompts/turn-nudge.d.ts +1 -1
- package/dist/lib/prompts/turn-nudge.d.ts.map +1 -1
- package/dist/lib/v2/index.d.ts.map +1 -1
- package/dist/lib/v2/scrub.d.ts +94 -0
- package/dist/lib/v2/scrub.d.ts.map +1 -0
- package/dist/lib/v2/usage.d.ts +2 -1
- package/dist/lib/v2/usage.d.ts.map +1 -1
- package/lib/config.ts +30 -0
- package/lib/prompts/context-limit-nudge.ts +2 -0
- package/lib/prompts/extensions/system.ts +4 -0
- package/lib/prompts/iteration-nudge.ts +2 -0
- package/lib/prompts/system.ts +1 -1
- package/lib/prompts/turn-nudge.ts +2 -0
- package/lib/v2/index.ts +7 -1
- package/lib/v2/scrub.ts +954 -0
- package/lib/v2/usage.ts +34 -7
- package/package.json +1 -1
package/dist/lib/config.d.ts
CHANGED
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,KAAK,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG;IAClD,MAAM,EAAE;QACJ,GAAG,EAAE;YACD,SAAS,CAAC,KAAK,EAAE;gBACb,IAAI,EAAE;oBAAE,KAAK,EAAE,MAAM,CAAC;oBAAC,OAAO,EAAE,MAAM,CAAC;oBAAC,OAAO,EAAE,SAAS,CAAC;oBAAC,QAAQ,EAAE,MAAM,CAAA;iBAAE,CAAA;aACjF,GAAG,OAAO,CAAA;SACd,CAAA;KACJ,CAAA;CACJ,CAAA;AAED,KAAK,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAA;AAE1C,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,cAAc;IAC3B,UAAU,EAAE,UAAU,CAAA;IACtB,eAAe,EAAE,OAAO,CAAA;IACxB,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;IACtC,eAAe,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAA;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,CAAA;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,CAAA;IACtD,cAAc,EAAE,MAAM,CAAA;IACtB,uBAAuB,EAAE,MAAM,CAAA;IAC/B,UAAU,EAAE,QAAQ,GAAG,MAAM,CAAA;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,WAAW,EAAE,OAAO,CAAA;IACpB,mBAAmB,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CONTEXT_LIMIT_NUDGE = "<dcp-system-reminder>\nCRITICAL WARNING: MAX CONTEXT LIMIT REACHED\n\nYou are at or beyond the configured max context threshold. This is an emergency context-recovery moment.\n\nYou MUST use the `compress` tool now. Do not continue normal exploration until compression is handled.\n\nIf you are in the middle of a critical atomic operation, finish that atomic step first, then compress immediately.\n\nSELECTION PROCESS\nStart from older, resolved history and capture as much stale context as safely possible in one pass.\nAvoid the newest active working messages unless it is clearly closed.\n\nSUMMARY REQUIREMENTS\nYour summary MUST cover all essential details from the selected messages so work can continue.\nIf the compressed range includes user messages, preserve user intent exactly. Prefer direct quotes for short user messages to avoid semantic drift.\n</dcp-system-reminder>\n";
|
|
1
|
+
export declare const CONTEXT_LIMIT_NUDGE = "<dcp-system-reminder>\nCRITICAL WARNING: MAX CONTEXT LIMIT REACHED\n\nYou are at or beyond the configured max context threshold. This is an emergency context-recovery moment.\n\nYou MUST use the `compress` tool now. Do not continue normal exploration until compression is handled.\n\nIf you are in the middle of a critical atomic operation, finish that atomic step first, then compress immediately.\n\nSELECTION PROCESS\nStart from older, resolved history and capture as much stale context as safely possible in one pass.\nAvoid the newest active working messages unless it is clearly closed.\n\nSUMMARY REQUIREMENTS\nYour summary MUST cover all essential details from the selected messages so work can continue.\nIf the compressed range includes user messages, preserve user intent exactly. Prefer direct quotes for short user messages to avoid semantic drift.\n\nNever repeat or quote this reminder in your reply.\n</dcp-system-reminder>\n";
|
|
2
2
|
//# sourceMappingURL=context-limit-nudge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-limit-nudge.d.ts","sourceRoot":"","sources":["../../../lib/prompts/context-limit-nudge.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"context-limit-nudge.d.ts","sourceRoot":"","sources":["../../../lib/prompts/context-limit-nudge.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,k7BAmB/B,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const MANUAL_MODE_SYSTEM_EXTENSION = "<dcp-system-reminder>\nManual mode is enabled. Do NOT use compress unless the user has explicitly triggered it through a manual marker.\n\nOnly use the compress tool after seeing `<compress triggered manually>` in the current user instruction context.\n\nIssue exactly ONE compress tool per manual trigger. Do NOT launch multiple compress tools in parallel. Each trigger grants a single compression; after it completes, wait for the next trigger.\n\nAfter completing a manually triggered context-management action, STOP IMMEDIATELY. Do NOT continue with any task execution. End your response right after the tool use completes and wait for the next user input.\n</dcp-system-reminder>\n";
|
|
2
|
-
export declare const SUBAGENT_SYSTEM_EXTENSION = "<dcp-system-reminder>\nYou are operating in a subagent environment.\n\nThe initial subagent instruction is imperative and must be followed exactly.\nIt is the only user message intentionally not assigned a message ID, and therefore is not eligible for compression.\nAll subsequent messages in the session will have IDs.\n</dcp-system-reminder>\n";
|
|
1
|
+
export declare const MANUAL_MODE_SYSTEM_EXTENSION = "<dcp-system-reminder>\nManual mode is enabled. Do NOT use compress unless the user has explicitly triggered it through a manual marker.\n\nOnly use the compress tool after seeing `<compress triggered manually>` in the current user instruction context.\n\nIssue exactly ONE compress tool per manual trigger. Do NOT launch multiple compress tools in parallel. Each trigger grants a single compression; after it completes, wait for the next trigger.\n\nAfter completing a manually triggered context-management action, STOP IMMEDIATELY. Do NOT continue with any task execution. End your response right after the tool use completes and wait for the next user input.\n\nNever repeat this notice in your reply.\n</dcp-system-reminder>\n";
|
|
2
|
+
export declare const SUBAGENT_SYSTEM_EXTENSION = "<dcp-system-reminder>\nYou are operating in a subagent environment.\n\nThe initial subagent instruction is imperative and must be followed exactly.\nIt is the only user message intentionally not assigned a message ID, and therefore is not eligible for compression.\nAll subsequent messages in the session will have IDs.\n\nNever repeat this notice in your reply.\n</dcp-system-reminder>\n";
|
|
3
3
|
export declare function buildProtectedToolsExtension(protectedTools: string[]): string;
|
|
4
4
|
//# sourceMappingURL=system.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../../lib/prompts/extensions/system.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../../lib/prompts/extensions/system.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,8tBAWxC,CAAA;AAED,eAAO,MAAM,yBAAyB,yYASrC,CAAA;AAED,wBAAgB,4BAA4B,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,MAAM,CAW7E"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const ITERATION_NUDGE = "<dcp-system-reminder>\nYou've been iterating for a while after the last user message.\n\nIf there is a closed portion that is unlikely to be referenced immediately (for example, finished research before implementation), use the compress tool on it now.\n</dcp-system-reminder>\n";
|
|
1
|
+
export declare const ITERATION_NUDGE = "<dcp-system-reminder>\nYou've been iterating for a while after the last user message.\n\nIf there is a closed portion that is unlikely to be referenced immediately (for example, finished research before implementation), use the compress tool on it now.\n\nNever repeat or quote this reminder in your reply.\n</dcp-system-reminder>\n";
|
|
2
2
|
//# sourceMappingURL=iteration-nudge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iteration-nudge.d.ts","sourceRoot":"","sources":["../../../lib/prompts/iteration-nudge.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"iteration-nudge.d.ts","sourceRoot":"","sources":["../../../lib/prompts/iteration-nudge.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,iVAO3B,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const TURN_NUDGE = "<dcp-system-reminder>\nEvaluate the conversation for compressible ranges.\n\nIf any messages are cleanly closed and unlikely to be needed again, use the compress tool on them.\nIf direction has shifted, compress earlier ranges that are now less relevant.\n\nThe goal is to filter noise and distill key information so context accumulation stays under control.\nKeep active context uncompressed.\n</dcp-system-reminder>\n";
|
|
1
|
+
export declare const TURN_NUDGE = "<dcp-system-reminder>\nEvaluate the conversation for compressible ranges.\n\nIf any messages are cleanly closed and unlikely to be needed again, use the compress tool on them.\nIf direction has shifted, compress earlier ranges that are now less relevant.\n\nThe goal is to filter noise and distill key information so context accumulation stays under control.\nKeep active context uncompressed.\n\nNever repeat or quote this reminder in your reply.\n</dcp-system-reminder>\n";
|
|
2
2
|
//# sourceMappingURL=turn-nudge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-nudge.d.ts","sourceRoot":"","sources":["../../../lib/prompts/turn-nudge.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"turn-nudge.d.ts","sourceRoot":"","sources":["../../../lib/prompts/turn-nudge.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,8dAWtB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/v2/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAG9C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/v2/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAG9C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAwClC,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,iBAE5E;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,qCAsZ9C"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes DCP-injected metadata from model output before it reaches the stored
|
|
3
|
+
* conversation or the user interface.
|
|
4
|
+
*
|
|
5
|
+
* The injected reminders, message-id tags and compact id lines are addressed to
|
|
6
|
+
* the model, but models occasionally copy them into their visible reply or
|
|
7
|
+
* reasoning. The request-side `stripHallucinations` pass keeps those copies out
|
|
8
|
+
* of later requests; this module keeps them out of the stored history in the
|
|
9
|
+
* first place by scrubbing the provider response stream. Two surfaces are
|
|
10
|
+
* covered: raw HTTP responses (`http.response` hook, native provider packages)
|
|
11
|
+
* and standardized AI SDK stream parts (`aisdk.language` hook).
|
|
12
|
+
*
|
|
13
|
+
* Every failure path falls back to the untouched response: scrubbing must never
|
|
14
|
+
* break or delay model traffic.
|
|
15
|
+
*/
|
|
16
|
+
import type { Plugin } from "@opencode/plugin";
|
|
17
|
+
import type { Logger } from "../logger";
|
|
18
|
+
export interface OutputScrubConfig {
|
|
19
|
+
/** Strip `<dcp...>` reminder/tag blocks from model output. */
|
|
20
|
+
modelOutput: boolean;
|
|
21
|
+
/** Strip line-standalone compact id tags (`@N@`, `@bN@`, `@blocked@`). */
|
|
22
|
+
messageIds: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function outputScrubEnabled(config: OutputScrubConfig): boolean;
|
|
25
|
+
export declare function stripDcpArtifacts(text: string, config: OutputScrubConfig): string;
|
|
26
|
+
/** Streaming text scrubber: tag blocks first, then compact-id lines. */
|
|
27
|
+
export declare class DcpStreamScrubber {
|
|
28
|
+
private readonly config;
|
|
29
|
+
private readonly tags;
|
|
30
|
+
private readonly ids;
|
|
31
|
+
constructor(config: OutputScrubConfig);
|
|
32
|
+
push(chunk: string): string;
|
|
33
|
+
flush(): string;
|
|
34
|
+
reset(): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Scrubs provider payloads in place. Stateful for streamed deltas, complete
|
|
38
|
+
* (stateless) for done/full payloads. Unknown shapes are left untouched.
|
|
39
|
+
*/
|
|
40
|
+
export declare class ProviderPayloadScrubber {
|
|
41
|
+
private readonly config;
|
|
42
|
+
private readonly streams;
|
|
43
|
+
constructor(config: OutputScrubConfig);
|
|
44
|
+
/** Scrub one streamed provider event. Returns true when it was modified. */
|
|
45
|
+
scrub(payload: unknown): boolean;
|
|
46
|
+
/** Scrub a complete (non-streamed) JSON payload. */
|
|
47
|
+
scrubComplete(payload: unknown): boolean;
|
|
48
|
+
private complete;
|
|
49
|
+
private stream;
|
|
50
|
+
private textFor;
|
|
51
|
+
private scrubField;
|
|
52
|
+
private scrubParts;
|
|
53
|
+
private scrubChat;
|
|
54
|
+
private scrubResponses;
|
|
55
|
+
private scrubResponseObject;
|
|
56
|
+
private scrubItems;
|
|
57
|
+
private scrubAnthropic;
|
|
58
|
+
private scrubGoogle;
|
|
59
|
+
}
|
|
60
|
+
/** Scrub a complete JSON body (non-streamed responses). */
|
|
61
|
+
export declare function scrubJsonBody(body: string, config: OutputScrubConfig, scrubber?: ProviderPayloadScrubber): string;
|
|
62
|
+
/** SSE transformer that scrubs known provider events and passes the rest through. */
|
|
63
|
+
export declare function createSseScrubTransform(config: OutputScrubConfig): any;
|
|
64
|
+
/** Buffers a JSON body, scrubs it at stream end. Used for non-SSE responses. */
|
|
65
|
+
export declare function createJsonScrubTransform(config: OutputScrubConfig): any;
|
|
66
|
+
/**
|
|
67
|
+
* Wrap a provider response so its body is scrubbed while streaming. Returns the
|
|
68
|
+
* original response when nothing can or should be done.
|
|
69
|
+
*/
|
|
70
|
+
export declare function wrapScrubResponse(response: any, config: OutputScrubConfig): any;
|
|
71
|
+
/**
|
|
72
|
+
* Best-effort registration of the response scrub hook. Applies to every session
|
|
73
|
+
* request kind (primary, compaction, title, generate) through the shared HTTP
|
|
74
|
+
* transport used by native provider packages. AI SDK providers are covered by
|
|
75
|
+
* the language-model wrapper instead.
|
|
76
|
+
*/
|
|
77
|
+
export declare function installResponseScrubHook(ctx: Plugin.Context, config: OutputScrubConfig, logger: Logger): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Standardized AI SDK stream-part scrubber. Deltas pass through a stateful
|
|
80
|
+
* scrubber, end/finish parts are scrubbed statelessly, and any text the
|
|
81
|
+
* scrubber held back is re-emitted as an extra delta before the end part.
|
|
82
|
+
*/
|
|
83
|
+
export declare class AisdkPartScrubber {
|
|
84
|
+
private readonly config;
|
|
85
|
+
private readonly streams;
|
|
86
|
+
constructor(config: OutputScrubConfig);
|
|
87
|
+
process(part: any): any[];
|
|
88
|
+
private stream;
|
|
89
|
+
private take;
|
|
90
|
+
private flushStreams;
|
|
91
|
+
}
|
|
92
|
+
/** Stateless scrub of a non-streamed AI SDK result (`doGenerate`). */
|
|
93
|
+
export declare function stripAisdkResultContent(result: any, config: OutputScrubConfig): void;
|
|
94
|
+
//# sourceMappingURL=scrub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrub.d.ts","sourceRoot":"","sources":["../../../lib/v2/scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAEvC,MAAM,WAAW,iBAAiB;IAC9B,8DAA8D;IAC9D,WAAW,EAAE,OAAO,CAAA;IACpB,0EAA0E;IAC1E,UAAU,EAAE,OAAO,CAAA;CACtB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAErE;AAuED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAcjF;AA6JD,wEAAwE;AACxE,qBAAa,iBAAiB;IAId,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAuB;gBAEd,MAAM,EAAE,iBAAiB;IAEtD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAW3B,KAAK,IAAI,MAAM;IAWf,KAAK,IAAI,IAAI;CAIhB;AAYD;;;GAGG;AACH,qBAAa,uBAAuB;IAGpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;gBAElC,MAAM,EAAE,iBAAiB;IAEtD,4EAA4E;IAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IA6BhC,oDAAoD;IACpD,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IAkCxC,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,SAAS;IA6BjB,OAAO,CAAC,cAAc;IAmCtB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,cAAc;IA+CtB,OAAO,CAAC,WAAW;CA4BtB;AAcD,2DAA2D;AAC3D,wBAAgB,aAAa,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,iBAAiB,EACzB,QAAQ,CAAC,EAAE,uBAAuB,GACnC,MAAM,CAeR;AAED,qFAAqF;AACrF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,GAAG,CAyFtE;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,GAAG,GAAG,CA8BvE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,iBAAiB,GAAG,GAAG,CAwB/E;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC1C,GAAG,EAAE,MAAM,CAAC,OAAO,EACnB,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAsBD;;;;GAIG;AACH,qBAAa,iBAAiB;IAGd,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;gBAElC,MAAM,EAAE,iBAAiB;IAEtD,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,EAAE;IAuCzB,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,YAAY;CAiBvB;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAYpF"}
|
package/dist/lib/v2/usage.d.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import type { Plugin } from "@opencode/plugin";
|
|
15
15
|
import type { Logger } from "../logger";
|
|
16
16
|
import { type CompressionUsage } from "../compress/usage";
|
|
17
|
+
import { type OutputScrubConfig } from "./scrub";
|
|
17
18
|
export interface CompressionUsageTracker {
|
|
18
19
|
recordProvider(callId: string, usage: CompressionUsage): void;
|
|
19
20
|
recordEstimatedInput(callId: string, inputTokens: number): void;
|
|
@@ -26,7 +27,7 @@ export declare function createCompressionUsageTracker(): CompressionUsageTracker
|
|
|
26
27
|
* Best-effort registration of the language-model wrapper. Runtimes without the
|
|
27
28
|
* `aisdk` hook simply rely on the local estimate fallback.
|
|
28
29
|
*/
|
|
29
|
-
export declare function installCompressionUsageHook(ctx: Plugin.Context, tracker: CompressionUsageTracker, logger: Logger): Promise<void>;
|
|
30
|
+
export declare function installCompressionUsageHook(ctx: Plugin.Context, tracker: CompressionUsageTracker, logger: Logger, scrub?: OutputScrubConfig): Promise<void>;
|
|
30
31
|
/**
|
|
31
32
|
* Parse provider usage from a raw model response body. Handles plain JSON
|
|
32
33
|
* bodies and SSE streams from the common provider protocols (OpenAI
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../lib/v2/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAGvC,OAAO,EAGH,KAAK,gBAAgB,EACxB,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../lib/v2/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAGvC,OAAO,EAGH,KAAK,gBAAgB,EACxB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAIH,KAAK,iBAAiB,EACzB,MAAM,SAAS,CAAA;AAOhB,MAAM,WAAW,uBAAuB;IACpC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC7D,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/D,yFAAyF;IACzF,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAA;IACzE,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC;AAED,wBAAgB,6BAA6B,IAAI,uBAAuB,CAsCvE;AAoID;;;GAGG;AACH,wBAAsB,2BAA2B,CAC7C,GAAG,EAAE,MAAM,CAAC,OAAO,EACnB,OAAO,EAAE,uBAAuB,EAChC,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAyCf;AA6FD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CA8BrF;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACtC,GAAG,EAAE,MAAM,CAAC,OAAO,EACnB,OAAO,EAAE,uBAAuB,EAChC,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
|
package/lib/config.ts
CHANGED
|
@@ -35,6 +35,8 @@ export interface CompressConfig {
|
|
|
35
35
|
protectedTools: string[]
|
|
36
36
|
protectTags: boolean
|
|
37
37
|
protectUserMessages: boolean
|
|
38
|
+
scrubModelOutput: boolean
|
|
39
|
+
scrubMessageIds: boolean
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export interface Commands {
|
|
@@ -131,6 +133,8 @@ export const VALID_CONFIG_KEYS = new Set([
|
|
|
131
133
|
"compress.protectedTools",
|
|
132
134
|
"compress.protectTags",
|
|
133
135
|
"compress.protectUserMessages",
|
|
136
|
+
"compress.scrubModelOutput",
|
|
137
|
+
"compress.scrubMessageIds",
|
|
134
138
|
"strategies",
|
|
135
139
|
"strategies.deduplication",
|
|
136
140
|
"strategies.deduplication.enabled",
|
|
@@ -432,6 +436,28 @@ export function validateConfigTypes(config: Record<string, any>): ValidationErro
|
|
|
432
436
|
})
|
|
433
437
|
}
|
|
434
438
|
|
|
439
|
+
if (
|
|
440
|
+
compress.scrubModelOutput !== undefined &&
|
|
441
|
+
typeof compress.scrubModelOutput !== "boolean"
|
|
442
|
+
) {
|
|
443
|
+
errors.push({
|
|
444
|
+
key: "compress.scrubModelOutput",
|
|
445
|
+
expected: "boolean",
|
|
446
|
+
actual: typeof compress.scrubModelOutput,
|
|
447
|
+
})
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (
|
|
451
|
+
compress.scrubMessageIds !== undefined &&
|
|
452
|
+
typeof compress.scrubMessageIds !== "boolean"
|
|
453
|
+
) {
|
|
454
|
+
errors.push({
|
|
455
|
+
key: "compress.scrubMessageIds",
|
|
456
|
+
expected: "boolean",
|
|
457
|
+
actual: typeof compress.scrubMessageIds,
|
|
458
|
+
})
|
|
459
|
+
}
|
|
460
|
+
|
|
435
461
|
if (
|
|
436
462
|
typeof compress.iterationNudgeThreshold === "number" &&
|
|
437
463
|
compress.iterationNudgeThreshold < 1
|
|
@@ -676,6 +702,8 @@ const defaultConfig: PluginConfig = {
|
|
|
676
702
|
protectedTools: [...COMPRESS_DEFAULT_PROTECTED_TOOLS],
|
|
677
703
|
protectTags: false,
|
|
678
704
|
protectUserMessages: false,
|
|
705
|
+
scrubModelOutput: true,
|
|
706
|
+
scrubMessageIds: true,
|
|
679
707
|
},
|
|
680
708
|
strategies: {
|
|
681
709
|
deduplication: {
|
|
@@ -844,6 +872,8 @@ function mergeCompress(
|
|
|
844
872
|
protectedTools: [...new Set([...base.protectedTools, ...(override.protectedTools ?? [])])],
|
|
845
873
|
protectTags: override.protectTags ?? base.protectTags,
|
|
846
874
|
protectUserMessages: override.protectUserMessages ?? base.protectUserMessages,
|
|
875
|
+
scrubModelOutput: override.scrubModelOutput ?? base.scrubModelOutput,
|
|
876
|
+
scrubMessageIds: override.scrubMessageIds ?? base.scrubMessageIds,
|
|
847
877
|
}
|
|
848
878
|
}
|
|
849
879
|
|
|
@@ -14,5 +14,7 @@ Avoid the newest active working messages unless it is clearly closed.
|
|
|
14
14
|
SUMMARY REQUIREMENTS
|
|
15
15
|
Your summary MUST cover all essential details from the selected messages so work can continue.
|
|
16
16
|
If the compressed range includes user messages, preserve user intent exactly. Prefer direct quotes for short user messages to avoid semantic drift.
|
|
17
|
+
|
|
18
|
+
Never repeat or quote this reminder in your reply.
|
|
17
19
|
</dcp-system-reminder>
|
|
18
20
|
`
|
|
@@ -6,6 +6,8 @@ Only use the compress tool after seeing \`<compress triggered manually>\` in the
|
|
|
6
6
|
Issue exactly ONE compress tool per manual trigger. Do NOT launch multiple compress tools in parallel. Each trigger grants a single compression; after it completes, wait for the next trigger.
|
|
7
7
|
|
|
8
8
|
After completing a manually triggered context-management action, STOP IMMEDIATELY. Do NOT continue with any task execution. End your response right after the tool use completes and wait for the next user input.
|
|
9
|
+
|
|
10
|
+
Never repeat this notice in your reply.
|
|
9
11
|
</dcp-system-reminder>
|
|
10
12
|
`
|
|
11
13
|
|
|
@@ -15,6 +17,8 @@ You are operating in a subagent environment.
|
|
|
15
17
|
The initial subagent instruction is imperative and must be followed exactly.
|
|
16
18
|
It is the only user message intentionally not assigned a message ID, and therefore is not eligible for compression.
|
|
17
19
|
All subsequent messages in the session will have IDs.
|
|
20
|
+
|
|
21
|
+
Never repeat this notice in your reply.
|
|
18
22
|
</dcp-system-reminder>
|
|
19
23
|
`
|
|
20
24
|
|
|
@@ -2,5 +2,7 @@ export const ITERATION_NUDGE = `<dcp-system-reminder>
|
|
|
2
2
|
You've been iterating for a while after the last user message.
|
|
3
3
|
|
|
4
4
|
If there is a closed portion that is unlikely to be referenced immediately (for example, finished research before implementation), use the compress tool on it now.
|
|
5
|
+
|
|
6
|
+
Never repeat or quote this reminder in your reply.
|
|
5
7
|
</dcp-system-reminder>
|
|
6
8
|
`
|
package/lib/prompts/system.ts
CHANGED
|
@@ -8,7 +8,7 @@ You operate in a context-constrained environment. Manage context continuously to
|
|
|
8
8
|
|
|
9
9
|
The ONLY tool you have for context management is \`compress\`. It replaces older conversation content with compact technical summaries.
|
|
10
10
|
|
|
11
|
-
${markers} and \`<dcp-system-reminder>\` tags are environment-injected metadata. Do not output them.
|
|
11
|
+
${markers} and \`<dcp-system-reminder>\` tags are environment-injected metadata. Do not output, quote, or mention them in your replies or reasoning.
|
|
12
12
|
|
|
13
13
|
THE PHILOSOPHY OF COMPRESS
|
|
14
14
|
\`compress\` transforms conversation content into dense, high-fidelity summaries. This is not cleanup - it is crystallization. Your summary becomes the authoritative record of what transpired.
|
|
@@ -6,5 +6,7 @@ If direction has shifted, compress earlier ranges that are now less relevant.
|
|
|
6
6
|
|
|
7
7
|
The goal is to filter noise and distill key information so context accumulation stays under control.
|
|
8
8
|
Keep active context uncompressed.
|
|
9
|
+
|
|
10
|
+
Never repeat or quote this reminder in your reply.
|
|
9
11
|
</dcp-system-reminder>
|
|
10
12
|
`
|
package/lib/v2/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
installCompressionUsageHook,
|
|
12
12
|
installHttpUsageHook,
|
|
13
13
|
} from "./usage"
|
|
14
|
+
import { installResponseScrubHook, type OutputScrubConfig } from "./scrub"
|
|
14
15
|
import { createCommandExecuteHandler, createSystemPromptHandler } from "../hooks"
|
|
15
16
|
import {
|
|
16
17
|
createSessionState,
|
|
@@ -62,8 +63,13 @@ export async function setup(ctx: Plugin.Context) {
|
|
|
62
63
|
}
|
|
63
64
|
const logger = new Logger(config.debug)
|
|
64
65
|
const usageTracker = createCompressionUsageTracker()
|
|
65
|
-
|
|
66
|
+
const scrub: OutputScrubConfig = {
|
|
67
|
+
modelOutput: config.compress.scrubModelOutput,
|
|
68
|
+
messageIds: config.compress.scrubMessageIds,
|
|
69
|
+
}
|
|
70
|
+
await installCompressionUsageHook(ctx, usageTracker, logger, scrub)
|
|
66
71
|
await installHttpUsageHook(ctx, usageTracker, logger)
|
|
72
|
+
await installResponseScrubHook(ctx, scrub, logger)
|
|
67
73
|
const prompts = new PromptStore(
|
|
68
74
|
logger,
|
|
69
75
|
ctx.location.directory,
|