@khorsheed/dsh-client-message-tools 0.1.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +82 -0
  4. package/README.i18n.yaml +6 -0
  5. package/README.md +82 -0
  6. package/cordis.patch.yml +6 -0
  7. package/lib/client.js +5824 -0
  8. package/lib/client.js.map +1 -0
  9. package/lib/index.js +644 -0
  10. package/lib/invariant.js +27 -0
  11. package/lib/tsconfig.client.tsbuildinfo +1 -0
  12. package/lib/tsconfig.host.tsbuildinfo +1 -0
  13. package/lib/typert.host.d.ts +3 -0
  14. package/lib/typert.host.js +250 -0
  15. package/lib/typert.remote-client.d.ts +26 -0
  16. package/lib/typert.remote-client.d.ts.map +1 -0
  17. package/lib/typert.remote-client.js +154 -0
  18. package/lib/types/client/ModelChip.d.ts +29 -0
  19. package/lib/types/client/ModelChip.d.ts.map +1 -0
  20. package/lib/types/client/ModelChip.js +86 -0
  21. package/lib/types/client/RestoredMessageView.d.ts +17 -0
  22. package/lib/types/client/RestoredMessageView.d.ts.map +1 -0
  23. package/lib/types/client/RestoredMessageView.js +9 -0
  24. package/lib/types/client/UserMessageView.d.ts +16 -0
  25. package/lib/types/client/UserMessageView.d.ts.map +1 -0
  26. package/lib/types/client/UserMessageView.js +172 -0
  27. package/lib/types/client/WithdrawnDividerView.d.ts +17 -0
  28. package/lib/types/client/WithdrawnDividerView.d.ts.map +1 -0
  29. package/lib/types/client/WithdrawnDividerView.js +59 -0
  30. package/lib/types/client/backfill.d.ts +19 -0
  31. package/lib/types/client/backfill.d.ts.map +1 -0
  32. package/lib/types/client/backfill.js +20 -0
  33. package/lib/types/client/dom-hider.d.ts +61 -0
  34. package/lib/types/client/dom-hider.d.ts.map +1 -0
  35. package/lib/types/client/dom-hider.js +195 -0
  36. package/lib/types/client/edit-in-place.d.ts +107 -0
  37. package/lib/types/client/edit-in-place.d.ts.map +1 -0
  38. package/lib/types/client/edit-in-place.js +97 -0
  39. package/lib/types/client/icons.d.ts +23 -0
  40. package/lib/types/client/icons.d.ts.map +1 -0
  41. package/lib/types/client/icons.js +11 -0
  42. package/lib/types/client/index.d.ts +39 -0
  43. package/lib/types/client/index.d.ts.map +1 -0
  44. package/lib/types/client/index.js +187 -0
  45. package/lib/types/client/locales.d.ts +74 -0
  46. package/lib/types/client/locales.d.ts.map +1 -0
  47. package/lib/types/client/locales.js +65 -0
  48. package/lib/types/client/slots.d.ts +44 -0
  49. package/lib/types/client/slots.d.ts.map +1 -0
  50. package/lib/types/client/slots.js +1 -0
  51. package/lib/types/client/withdraw-backfill.d.ts +25 -0
  52. package/lib/types/client/withdraw-backfill.d.ts.map +1 -0
  53. package/lib/types/client/withdraw-backfill.js +21 -0
  54. package/lib/types/client/withdrawn-node.d.ts +163 -0
  55. package/lib/types/client/withdrawn-node.d.ts.map +1 -0
  56. package/lib/types/client/withdrawn-node.js +297 -0
  57. package/lib/types/index.d.ts +69 -0
  58. package/lib/types/index.d.ts.map +1 -0
  59. package/lib/types/index.js +175 -0
  60. package/lib/types/invariant.d.ts +16 -0
  61. package/lib/types/invariant.d.ts.map +1 -0
  62. package/lib/types/invariant.js +25 -0
  63. package/lib/types/marker.d.ts +94 -0
  64. package/lib/types/marker.d.ts.map +1 -0
  65. package/lib/types/marker.js +131 -0
  66. package/lib/types/types.d.ts +116 -0
  67. package/lib/types/types.d.ts.map +1 -0
  68. package/lib/types/types.js +1 -0
  69. package/lib/types/withdraw.d.ts +112 -0
  70. package/lib/types/withdraw.d.ts.map +1 -0
  71. package/lib/types/withdraw.js +279 -0
  72. package/package.json +108 -0
@@ -0,0 +1,175 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
36
+ import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
37
+ import { EDIT_TRIGGER_NOTICE, MESSAGE_TOOLS_PLUGIN, WITHDRAWN_NOTICE, editReplacementSource, editTriggerSource, restoreAssistantSource, } from './marker.js';
38
+ import { planEdit, planRestore, planWithdrawal } from './withdraw.js';
39
+ /**
40
+ * messageTools Remote service: appends the withdrawal replacement to the
41
+ * owning Session and flushes it durable. The replacement event's
42
+ * plugin-tagged source is the audit trail; no new session event type is
43
+ * introduced, so session reload stays safe for harnesses without this plugin.
44
+ */
45
+ let MessageToolsService = (() => {
46
+ let _classSuper = TypertRemoteService;
47
+ let _instanceExtraInitializers = [];
48
+ let _withdraw_decorators;
49
+ let _restore_decorators;
50
+ let _edit_decorators;
51
+ return class MessageToolsService extends _classSuper {
52
+ static {
53
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
54
+ _withdraw_decorators = [Remote('withdraw')];
55
+ _restore_decorators = [Remote('restore')];
56
+ _edit_decorators = [Remote('edit')];
57
+ __esDecorate(this, null, _withdraw_decorators, { kind: "method", name: "withdraw", static: false, private: false, access: { has: obj => "withdraw" in obj, get: obj => obj.withdraw }, metadata: _metadata }, null, _instanceExtraInitializers);
58
+ __esDecorate(this, null, _restore_decorators, { kind: "method", name: "restore", static: false, private: false, access: { has: obj => "restore" in obj, get: obj => obj.restore }, metadata: _metadata }, null, _instanceExtraInitializers);
59
+ __esDecorate(this, null, _edit_decorators, { kind: "method", name: "edit", static: false, private: false, access: { has: obj => "edit" in obj, get: obj => obj.edit }, metadata: _metadata }, null, _instanceExtraInitializers);
60
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
61
+ }
62
+ static inject = ['sessions', 'agents'];
63
+ /**
64
+ * @param ctx - host context carrying the session store.
65
+ */
66
+ constructor(ctx) {
67
+ super(ctx, 'messageTools');
68
+ __runInitializers(this, _instanceExtraInitializers);
69
+ }
70
+ /**
71
+ * Withdraw a user message: replace it and every surface node after it with
72
+ * a minimal plugin-sourced placeholder, hiding the span from the model.
73
+ * @param request - session identity and target message seq.
74
+ * @returns the replacement receipt, or a rejection from the closed failure union.
75
+ */
76
+ async withdraw(request) {
77
+ const session = this.ctx.sessions.get(request.sessionId);
78
+ if (session === undefined)
79
+ return { ok: false, error: { code: 'session-not-found' } };
80
+ const planned = planWithdrawal(session.events, session.surface.nodes, request.targetSeq);
81
+ if (!planned.ok)
82
+ return { ok: false, error: { code: planned.code } };
83
+ const replacement = session.append('user/message', createUserMessage({
84
+ content: [{ type: 'text', text: WITHDRAWN_NOTICE }],
85
+ source: { kind: 'plugin', plugin: MESSAGE_TOOLS_PLUGIN },
86
+ }), {
87
+ surfaceOp: { op: 'replace', start: planned.plan.start, end: planned.plan.end },
88
+ sourceEventSeqs: [...planned.plan.sourceEventSeqs],
89
+ });
90
+ await this.ctx.sessions.flush(session);
91
+ return {
92
+ ok: true,
93
+ value: { replacementSeq: replacement.seq, shadowedCount: planned.plan.sourceEventSeqs.length },
94
+ };
95
+ }
96
+ /**
97
+ * Restore a withdrawn span: replay every replayable entry of it (user
98
+ * messages verbatim — including the last edit's new text — and framed
99
+ * assistant text; tool calls/results never replay) as fresh plugin-tagged
100
+ * `user/message` appends at the conversation tail, in original order, each
101
+ * citing its original event in `sourceEventSeqs`. The surface replace model
102
+ * is positional — a replaced span folds into one node — so the span cannot
103
+ * be restored in place; the replayed entries are simply the newest messages
104
+ * the model sees. Assistant text replays as framed user-role messages:
105
+ * `assistant/message` cannot carry a plugin source and the turn/step trace
106
+ * forbids assistant appends outside a step.
107
+ * @param request - session identity and withdrawn message seq.
108
+ * @returns the restore receipt, or a rejection from the closed failure union.
109
+ */
110
+ async restore(request) {
111
+ const session = this.ctx.sessions.get(request.sessionId);
112
+ if (session === undefined)
113
+ return { ok: false, error: { code: 'session-not-found' } };
114
+ const planned = planRestore(session.events, session.surface.nodes, request.targetSeq);
115
+ if (!planned.ok)
116
+ return { ok: false, error: { code: planned.code } };
117
+ const appendedSeqs = [];
118
+ for (const entry of planned.plan.entries) {
119
+ const message = entry.role === 'user'
120
+ ? createUserMessage({
121
+ content: [...entry.content],
122
+ source: { kind: 'plugin', plugin: MESSAGE_TOOLS_PLUGIN },
123
+ })
124
+ : createUserMessage({
125
+ content: [{ type: 'text', text: entry.text }],
126
+ source: restoreAssistantSource(),
127
+ });
128
+ appendedSeqs.push(session.append('user/message', message, {
129
+ surfaceOp: 'append',
130
+ sourceEventSeqs: [entry.sourceSeq],
131
+ }).seq);
132
+ }
133
+ await this.ctx.sessions.flush(session);
134
+ /* v8 ignore next -- entries is never empty (the target itself always replays), so [0] exists */
135
+ return { ok: true, value: { restoredSeq: appendedSeqs[0] ?? request.targetSeq } };
136
+ }
137
+ /**
138
+ * Edit a user message in place: replace it and every surface node after it
139
+ * with the edited text itself (no placeholder, no tail duplicate — the
140
+ * edited text appears exactly once, in the replacement event), then start a
141
+ * regeneration turn. The harness has no wake-without-append path, so the
142
+ * turn is started by `agent.followup` carrying a minimal plugin-sourced
143
+ * trigger message (the ankh-guard/schedule pattern); the trigger is not the
144
+ * edited text and lands once, as itself.
145
+ * @param request - session identity, target seq, edited text.
146
+ * @returns the replacement receipt and whether the turn was triggered, or a rejection.
147
+ */
148
+ async edit(request) {
149
+ const session = this.ctx.sessions.get(request.sessionId);
150
+ if (session === undefined)
151
+ return { ok: false, error: { code: 'session-not-found' } };
152
+ const planned = planEdit(session.events, session.surface.nodes, request.targetSeq, request.text);
153
+ if (!planned.ok)
154
+ return { ok: false, error: { code: planned.code } };
155
+ const replacement = session.append('user/message', createUserMessage({
156
+ content: [{ type: 'text', text: request.text }],
157
+ source: editReplacementSource(),
158
+ }), {
159
+ surfaceOp: { op: 'replace', start: planned.plan.start, end: planned.plan.end },
160
+ sourceEventSeqs: [...planned.plan.sourceEventSeqs],
161
+ });
162
+ await this.ctx.sessions.flush(session);
163
+ const agent = this.ctx.agents.get(request.sessionId);
164
+ if (agent !== undefined) {
165
+ agent.followup(createUserMessage({
166
+ content: [{ type: 'text', text: EDIT_TRIGGER_NOTICE }],
167
+ source: editTriggerSource(),
168
+ }));
169
+ }
170
+ return { ok: true, value: { replacementSeq: replacement.seq, triggered: agent !== undefined } };
171
+ }
172
+ };
173
+ })();
174
+ export { MessageToolsService };
175
+ export default MessageToolsService;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Package-owned invariant companion for `@khorsheed/dsh-client-message-tools`.
3
+ * @module @khorsheed/dsh-client-message-tools/invariant
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ /** Cordis companion plugin name. */
7
+ export declare const name = "client-message-tools-invariant";
8
+ /** Service required before the companion can reserve package ownership. */
9
+ export declare const inject: string[];
10
+ /**
11
+ * Register this package's invariant companion.
12
+ * @param ctx - Cordis context carrying the invariant service.
13
+ * @returns the installed registration's disposer after setup succeeds.
14
+ */
15
+ export declare const apply: (ctx: Context) => Promise<() => void>;
16
+ //# sourceMappingURL=invariant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant.d.ts","sourceRoot":"","sources":["../../src/invariant.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,oCAAoC;AACpC,eAAO,MAAM,IAAI,mCAAmC,CAAA;AACpD,2EAA2E;AAC3E,eAAO,MAAM,MAAM,UAAiB,CAAA;AAYpC;;;;GAIG;AACH,eAAO,MAAM,KAAK,QAAS,OAAO,KAAG,OAAO,CAAC,MAAM,IAAI,CACU,CAAA"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Package-owned invariant companion for `@khorsheed/dsh-client-message-tools`.
3
+ * @module @khorsheed/dsh-client-message-tools/invariant
4
+ */
5
+ const PACKAGE_NAME = '@khorsheed/dsh-client-message-tools';
6
+ /** Cordis companion plugin name. */
7
+ export const name = 'client-message-tools-invariant';
8
+ /** Service required before the companion can reserve package ownership. */
9
+ export const inject = ['invariants'];
10
+ /**
11
+ * No runtime invariant: the withdrawal write passes through Session.append,
12
+ * whose surface validation rejects any replacement that misses a shadowed
13
+ * surface node, and the client contributions (one Definition, two slot
14
+ * entries) ride the slot/declaration lifecycles disposed with the plugin
15
+ * fiber. The package's unit tests exercise the plan fold and the projection
16
+ * helpers, so no second authority exists to check at runtime.
17
+ */
18
+ const install = () => { };
19
+ /**
20
+ * Register this package's invariant companion.
21
+ * @param ctx - Cordis context carrying the invariant service.
22
+ * @returns the installed registration's disposer after setup succeeds.
23
+ */
24
+ export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
25
+ /* jscpd:ignore-end */
@@ -0,0 +1,94 @@
1
+ import type { MessageSource } from '@deepseek-ai/dsh-llm/message';
2
+ import type { SessionEvent } from '@deepseek-ai/dsh-session/types';
3
+ /** Plugin source tag identifying every message-tools event. */
4
+ export declare const MESSAGE_TOOLS_PLUGIN = "message-tools";
5
+ /**
6
+ * Model-facing placeholder left on the surface in place of the withdrawn
7
+ * span. The span itself is hidden from the model; this minimal user message
8
+ * keeps the surface non-empty and tells the model why the transcript jumps.
9
+ */
10
+ export declare const WITHDRAWN_NOTICE = "(\u7528\u6237\u64A4\u56DE\u4E86\u8FD9\u6761\u6D88\u606F\u53CA\u5176\u540E\u7684\u6240\u6709\u5185\u5BB9)";
11
+ /**
12
+ * Model-facing trigger message that starts the regeneration turn after an
13
+ * edit replacement lands (no wake-without-append path exists in the harness;
14
+ * `agent.followup` is the sanctioned seam). It is NOT the edited text — that
15
+ * appears exactly once, in the replacement event.
16
+ */
17
+ export declare const EDIT_TRIGGER_NOTICE = "(\u7528\u6237\u7F16\u8F91\u4E86\u4E0A\u4E00\u6761\u6D88\u606F\uFF0C\u8BF7\u6309\u7F16\u8F91\u540E\u7684\u5185\u5BB9\u91CD\u65B0\u56DE\u7B54)";
18
+ /**
19
+ * Model-facing frame preceding a replayed assistant text in a restore: the
20
+ * replay lands as a user-role message (assistant/message cannot carry a
21
+ * plugin source, and the session turn/step trace forbids ad-hoc assistant
22
+ * appends), so the frame keeps the role honest for the model.
23
+ */
24
+ export declare const RESTORED_ASSISTANT_NOTICE = "(\u4EE5\u4E0B\u662F\u5148\u524D\u88AB\u64A4\u56DE\u3001\u73B0\u968F\u6062\u590D\u653E\u56DE\u7684\u52A9\u624B\u56DE\u590D)";
25
+ /** The `op` discriminator on a message-tools plugin source. */
26
+ export type MessageToolsOp = 'edit' | 'edit-trigger' | 'restore-assistant';
27
+ /** The plugin-tagged source of an edit replacement (op: 'edit'). */
28
+ export declare function editReplacementSource(): MessageSource;
29
+ /** The plugin-tagged source of an edit trigger message (op: 'edit-trigger'). */
30
+ export declare function editTriggerSource(): MessageSource;
31
+ /** The plugin-tagged source of a restored assistant-text replay (op: 'restore-assistant'). */
32
+ export declare function restoreAssistantSource(): MessageSource;
33
+ /** Read the op discriminator off a message source (absent on legacy events). */
34
+ export declare function messageToolsOp(source: unknown): MessageToolsOp | undefined;
35
+ /**
36
+ * Strip the model-facing restore frame from a replayed assistant text for
37
+ * DISPLAY: the frame belongs to the model context (role honesty), never to
38
+ * the transcript row. Texts without the frame pass through unchanged.
39
+ * @param text - the replayed content's joined text.
40
+ * @returns the display text without the frame prefix.
41
+ */
42
+ export declare function stripRestoreAssistantFrame(text: string): string;
43
+ /** One message-tools withdrawal replacement event, narrowed. */
44
+ export type MessageToolsReplacementEvent = SessionEvent<'user/message'> & {
45
+ readonly surfaceOp: {
46
+ readonly op: 'replace';
47
+ readonly start: number;
48
+ readonly end: number;
49
+ };
50
+ };
51
+ /** One message-tools edit replacement event, narrowed (same shape, `op: 'edit'` source). */
52
+ export type MessageToolsEditEvent = MessageToolsReplacementEvent;
53
+ /** One message-tools append-side event (restore or edit trigger), narrowed. */
54
+ export type MessageToolsRestoreEvent = SessionEvent<'user/message'> & {
55
+ readonly surfaceOp: 'append';
56
+ };
57
+ /**
58
+ * Whether the event is a message-tools WITHDRAWAL replacement: a
59
+ * `user/message` surface replacement whose source carries this plugin's tag
60
+ * and no `op` discriminator (legacy and current withdrawals both).
61
+ * @param event - the session event to test.
62
+ * @returns the event narrowed to a withdrawal replacement when matched.
63
+ */
64
+ export declare function isMessageToolsReplacement(event: SessionEvent): event is MessageToolsReplacementEvent;
65
+ /**
66
+ * Whether the event is a message-tools EDIT replacement: a `user/message`
67
+ * surface replacement whose content IS the edited text (`op: 'edit'`).
68
+ * @param event - the session event to test.
69
+ * @returns the event narrowed to an edit replacement when matched.
70
+ */
71
+ export declare function isMessageToolsEdit(event: SessionEvent): event is MessageToolsEditEvent;
72
+ /**
73
+ * Whether the event is a message-tools restore: an append-surface
74
+ * `user/message` replaying a withdrawn message at the conversation tail.
75
+ * @param event - the session event to test.
76
+ * @returns the event narrowed to a message-tools restore when matched.
77
+ */
78
+ export declare function isMessageToolsRestore(event: SessionEvent): event is MessageToolsRestoreEvent;
79
+ /**
80
+ * Whether the event is a message-tools edit trigger: the minimal
81
+ * plugin-sourced message that starts the regeneration turn after an edit.
82
+ * @param event - the session event to test.
83
+ * @returns the event narrowed to an edit trigger when matched.
84
+ */
85
+ export declare function isMessageToolsTrigger(event: SessionEvent): event is MessageToolsRestoreEvent;
86
+ /**
87
+ * Whether the event is a message-tools ASSISTANT-text restore replay: an
88
+ * append-surface `user/message` carrying a withdrawn assistant reply's text
89
+ * (framed, user-role — see {@link RESTORED_ASSISTANT_NOTICE}).
90
+ * @param event - the session event to test.
91
+ * @returns the event narrowed to a restore-assistant replay when matched.
92
+ */
93
+ export declare function isMessageToolsRestoreAssistant(event: SessionEvent): event is MessageToolsRestoreEvent;
94
+ //# sourceMappingURL=marker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker.d.ts","sourceRoot":"","sources":["../../src/marker.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAElE,+DAA+D;AAC/D,eAAO,MAAM,oBAAoB,kBAAkB,CAAA;AAEnD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6GAAwB,CAAA;AAErD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,iJAA8B,CAAA;AAE9D;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,+HAA2B,CAAA;AAEjE,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,cAAc,GAAG,mBAAmB,CAAA;AAE1E,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,aAAa,CAErD;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,IAAI,aAAa,CAEjD;AAED,8FAA8F;AAC9F,wBAAgB,sBAAsB,IAAI,aAAa,CAEtD;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAG1E;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,gEAAgE;AAChE,MAAM,MAAM,4BAA4B,GAAG,YAAY,CAAC,cAAc,CAAC,GAAG;IACxE,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAC7F,CAAA;AAED,4FAA4F;AAC5F,MAAM,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AAEhE,+EAA+E;AAC/E,MAAM,MAAM,wBAAwB,GAAG,YAAY,CAAC,cAAc,CAAC,GAAG;IACpE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAA;CAC7B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,4BAA4B,CAMpG;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,qBAAqB,CAMtF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,wBAAwB,CAM5F;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,wBAAwB,CAM5F;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,wBAAwB,CAMrG"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Shared message-tools markers: the plugin source tag stamped on withdrawal
3
+ * replacement events, the `op` discriminator telling edit replacements, edit
4
+ * triggers, and assistant-text restore replays apart from withdrawals and
5
+ * user-message restores, the model-facing placeholder and trigger texts, and
6
+ * the pure predicates both the Host service and the browser projection
7
+ * consume. No new session event type is ever written — an
8
+ * out-of-harness event type cannot carry `ignorable: true` (Session.append
9
+ * assigns the envelope), so a persisted unknown type would make
10
+ * session-persistence refuse the log on reload. The events themselves are the
11
+ * durable audit trail.
12
+ * @module @khorsheed/dsh-client-message-tools/marker
13
+ */
14
+ import { isReplacementSurfaceEvent } from '@deepseek-ai/dsh-session/surface';
15
+ /** Plugin source tag identifying every message-tools event. */
16
+ export const MESSAGE_TOOLS_PLUGIN = 'message-tools';
17
+ /**
18
+ * Model-facing placeholder left on the surface in place of the withdrawn
19
+ * span. The span itself is hidden from the model; this minimal user message
20
+ * keeps the surface non-empty and tells the model why the transcript jumps.
21
+ */
22
+ export const WITHDRAWN_NOTICE = '(用户撤回了这条消息及其后的所有内容)';
23
+ /**
24
+ * Model-facing trigger message that starts the regeneration turn after an
25
+ * edit replacement lands (no wake-without-append path exists in the harness;
26
+ * `agent.followup` is the sanctioned seam). It is NOT the edited text — that
27
+ * appears exactly once, in the replacement event.
28
+ */
29
+ export const EDIT_TRIGGER_NOTICE = '(用户编辑了上一条消息,请按编辑后的内容重新回答)';
30
+ /**
31
+ * Model-facing frame preceding a replayed assistant text in a restore: the
32
+ * replay lands as a user-role message (assistant/message cannot carry a
33
+ * plugin source, and the session turn/step trace forbids ad-hoc assistant
34
+ * appends), so the frame keeps the role honest for the model.
35
+ */
36
+ export const RESTORED_ASSISTANT_NOTICE = '(以下是先前被撤回、现随恢复放回的助手回复)';
37
+ /** The plugin-tagged source of an edit replacement (op: 'edit'). */
38
+ export function editReplacementSource() {
39
+ return Object.freeze({ kind: 'plugin', plugin: MESSAGE_TOOLS_PLUGIN, op: 'edit' });
40
+ }
41
+ /** The plugin-tagged source of an edit trigger message (op: 'edit-trigger'). */
42
+ export function editTriggerSource() {
43
+ return Object.freeze({ kind: 'plugin', plugin: MESSAGE_TOOLS_PLUGIN, op: 'edit-trigger' });
44
+ }
45
+ /** The plugin-tagged source of a restored assistant-text replay (op: 'restore-assistant'). */
46
+ export function restoreAssistantSource() {
47
+ return Object.freeze({ kind: 'plugin', plugin: MESSAGE_TOOLS_PLUGIN, op: 'restore-assistant' });
48
+ }
49
+ /** Read the op discriminator off a message source (absent on legacy events). */
50
+ export function messageToolsOp(source) {
51
+ const op = source?.op;
52
+ return op === 'edit' || op === 'edit-trigger' || op === 'restore-assistant' ? op : undefined;
53
+ }
54
+ /**
55
+ * Strip the model-facing restore frame from a replayed assistant text for
56
+ * DISPLAY: the frame belongs to the model context (role honesty), never to
57
+ * the transcript row. Texts without the frame pass through unchanged.
58
+ * @param text - the replayed content's joined text.
59
+ * @returns the display text without the frame prefix.
60
+ */
61
+ export function stripRestoreAssistantFrame(text) {
62
+ const prefix = `${RESTORED_ASSISTANT_NOTICE}\n`;
63
+ return text.startsWith(prefix) ? text.slice(prefix.length) : text;
64
+ }
65
+ /**
66
+ * Whether the event is a message-tools WITHDRAWAL replacement: a
67
+ * `user/message` surface replacement whose source carries this plugin's tag
68
+ * and no `op` discriminator (legacy and current withdrawals both).
69
+ * @param event - the session event to test.
70
+ * @returns the event narrowed to a withdrawal replacement when matched.
71
+ */
72
+ export function isMessageToolsReplacement(event) {
73
+ return event.type === 'user/message'
74
+ && isReplacementSurfaceEvent(event)
75
+ && event.data.source.kind === 'plugin'
76
+ && event.data.source.plugin === MESSAGE_TOOLS_PLUGIN
77
+ && messageToolsOp(event.data.source) === undefined;
78
+ }
79
+ /**
80
+ * Whether the event is a message-tools EDIT replacement: a `user/message`
81
+ * surface replacement whose content IS the edited text (`op: 'edit'`).
82
+ * @param event - the session event to test.
83
+ * @returns the event narrowed to an edit replacement when matched.
84
+ */
85
+ export function isMessageToolsEdit(event) {
86
+ return event.type === 'user/message'
87
+ && isReplacementSurfaceEvent(event)
88
+ && event.data.source.kind === 'plugin'
89
+ && event.data.source.plugin === MESSAGE_TOOLS_PLUGIN
90
+ && messageToolsOp(event.data.source) === 'edit';
91
+ }
92
+ /**
93
+ * Whether the event is a message-tools restore: an append-surface
94
+ * `user/message` replaying a withdrawn message at the conversation tail.
95
+ * @param event - the session event to test.
96
+ * @returns the event narrowed to a message-tools restore when matched.
97
+ */
98
+ export function isMessageToolsRestore(event) {
99
+ return event.type === 'user/message'
100
+ && event.surfaceOp === 'append'
101
+ && event.data.source.kind === 'plugin'
102
+ && event.data.source.plugin === MESSAGE_TOOLS_PLUGIN
103
+ && messageToolsOp(event.data.source) === undefined;
104
+ }
105
+ /**
106
+ * Whether the event is a message-tools edit trigger: the minimal
107
+ * plugin-sourced message that starts the regeneration turn after an edit.
108
+ * @param event - the session event to test.
109
+ * @returns the event narrowed to an edit trigger when matched.
110
+ */
111
+ export function isMessageToolsTrigger(event) {
112
+ return event.type === 'user/message'
113
+ && event.surfaceOp === 'append'
114
+ && event.data.source.kind === 'plugin'
115
+ && event.data.source.plugin === MESSAGE_TOOLS_PLUGIN
116
+ && messageToolsOp(event.data.source) === 'edit-trigger';
117
+ }
118
+ /**
119
+ * Whether the event is a message-tools ASSISTANT-text restore replay: an
120
+ * append-surface `user/message` carrying a withdrawn assistant reply's text
121
+ * (framed, user-role — see {@link RESTORED_ASSISTANT_NOTICE}).
122
+ * @param event - the session event to test.
123
+ * @returns the event narrowed to a restore-assistant replay when matched.
124
+ */
125
+ export function isMessageToolsRestoreAssistant(event) {
126
+ return event.type === 'user/message'
127
+ && event.surfaceOp === 'append'
128
+ && event.data.source.kind === 'plugin'
129
+ && event.data.source.plugin === MESSAGE_TOOLS_PLUGIN
130
+ && messageToolsOp(event.data.source) === 'restore-assistant';
131
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Wire vocabulary shared by the messageTools Host Remote and its browser
3
+ * callers. Types only: the generated Remote codecs import this module
4
+ * type-side, and the client bundle never inlines host runtime code.
5
+ * @module @khorsheed/dsh-client-message-tools/types
6
+ */
7
+ import type { SessionId } from '@deepseek-ai/dsh-session/types';
8
+ /**
9
+ * Withdraw one user message: hide it and everything logged after it from the
10
+ * model surface and the chat projection.
11
+ */
12
+ export interface MessageToolsWithdrawRequest {
13
+ /** Session that owns the target message. */
14
+ readonly sessionId: SessionId;
15
+ /** Seq of the append-surface `user/message` event to withdraw. */
16
+ readonly targetSeq: number;
17
+ }
18
+ /** What a landed withdrawal appended. */
19
+ export interface MessageToolsWithdrawal {
20
+ /** Seq of the replacement event now standing in for the withdrawn span. */
21
+ readonly replacementSeq: number;
22
+ /** Count of surface nodes the replacement shadows. */
23
+ readonly shadowedCount: number;
24
+ }
25
+ /** Withdrawal failure vocabulary (closed union). */
26
+ export type MessageToolsWithdrawFailure = {
27
+ readonly code: 'session-not-found';
28
+ } | {
29
+ readonly code: 'target-not-found';
30
+ } | {
31
+ readonly code: 'not-a-user-message';
32
+ } | {
33
+ readonly code: 'already-withdrawn';
34
+ };
35
+ /** Withdrawal outcome: a landed receipt or a rejected failure. */
36
+ export type MessageToolsWithdrawResult = {
37
+ readonly ok: true;
38
+ readonly value: MessageToolsWithdrawal;
39
+ } | {
40
+ readonly ok: false;
41
+ readonly error: MessageToolsWithdrawFailure;
42
+ };
43
+ /**
44
+ * Restore a withdrawn user message: replay its content as a fresh user
45
+ * message at the conversation tail (positional restore is impossible — see
46
+ * the package README).
47
+ */
48
+ export interface MessageToolsRestoreRequest {
49
+ /** Session that owns the withdrawn message. */
50
+ readonly sessionId: SessionId;
51
+ /** Seq of the withdrawn append-surface `user/message` event to restore. */
52
+ readonly targetSeq: number;
53
+ }
54
+ /** What a landed restore appended. */
55
+ export interface MessageToolsRestoration {
56
+ /** Seq of the appended replay event. */
57
+ readonly restoredSeq: number;
58
+ }
59
+ /** Restore failure vocabulary (closed union). */
60
+ export type MessageToolsRestoreFailure = {
61
+ readonly code: 'session-not-found';
62
+ } | {
63
+ readonly code: 'target-not-found';
64
+ } | {
65
+ readonly code: 'not-a-user-message';
66
+ } | {
67
+ readonly code: 'not-withdrawn';
68
+ };
69
+ /** Restore outcome: a landed receipt or a rejected failure. */
70
+ export type MessageToolsRestoreResult = {
71
+ readonly ok: true;
72
+ readonly value: MessageToolsRestoration;
73
+ } | {
74
+ readonly ok: false;
75
+ readonly error: MessageToolsRestoreFailure;
76
+ };
77
+ /**
78
+ * Edit a user message in place: replace it (and the surface tail) with the
79
+ * edited text, then start a regeneration turn over the replaced surface.
80
+ */
81
+ export interface MessageToolsEditRequest {
82
+ /** Session that owns the target message. */
83
+ readonly sessionId: SessionId;
84
+ /** Seq of the editable user message (an original or a previous edit's replacement). */
85
+ readonly targetSeq: number;
86
+ /** The edited text (non-blank). */
87
+ readonly text: string;
88
+ }
89
+ /** What a landed edit appended and started. */
90
+ export interface MessageToolsEdit {
91
+ /** Seq of the replacement event carrying the edited text. */
92
+ readonly replacementSeq: number;
93
+ /** Whether the regeneration turn was triggered (false when no live agent). */
94
+ readonly triggered: boolean;
95
+ }
96
+ /** Edit failure vocabulary (closed union). */
97
+ export type MessageToolsEditFailure = {
98
+ readonly code: 'session-not-found';
99
+ } | {
100
+ readonly code: 'target-not-found';
101
+ } | {
102
+ readonly code: 'not-a-user-message';
103
+ } | {
104
+ readonly code: 'already-withdrawn';
105
+ } | {
106
+ readonly code: 'empty-text';
107
+ };
108
+ /** Edit outcome: a landed receipt or a rejected failure. */
109
+ export type MessageToolsEditResult = {
110
+ readonly ok: true;
111
+ readonly value: MessageToolsEdit;
112
+ } | {
113
+ readonly ok: false;
114
+ readonly error: MessageToolsEditFailure;
115
+ };
116
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};