dsh-advisor 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.
- package/LICENSE +21 -0
- package/README.i18n.yaml +7 -0
- package/README.md +303 -0
- package/README.zh.md +166 -0
- package/cordis.patch.yml +6 -0
- package/lib/advisor-runtime.d.ts +242 -0
- package/lib/advisor-runtime.js +662 -0
- package/lib/advisor-runtime.js.map +1 -0
- package/lib/client/advisor-card.d.ts +90 -0
- package/lib/client/advisor-store.d.ts +310 -0
- package/lib/client/index.d.ts +39 -0
- package/lib/client/locales.d.ts +40 -0
- package/lib/client.d.ts +1 -0
- package/lib/client.js +840 -0
- package/lib/commands.d.ts +136 -0
- package/lib/commands.js +185 -0
- package/lib/commands.js.map +1 -0
- package/lib/config.d.ts +74 -0
- package/lib/config.js +93 -0
- package/lib/config.js.map +1 -0
- package/lib/delivery.d.ts +129 -0
- package/lib/delivery.js +169 -0
- package/lib/delivery.js.map +1 -0
- package/lib/emission-guard.d.ts +99 -0
- package/lib/emission-guard.js +155 -0
- package/lib/emission-guard.js.map +1 -0
- package/lib/gateway.d.ts +116 -0
- package/lib/gateway.js +214 -0
- package/lib/gateway.js.map +1 -0
- package/lib/index.d.ts +48 -0
- package/lib/index.js +485 -0
- package/lib/index.js.map +1 -0
- package/lib/kinds.d.ts +38 -0
- package/lib/kinds.js +24 -0
- package/lib/kinds.js.map +1 -0
- package/lib/prompts.d.ts +22 -0
- package/lib/prompts.js +38 -0
- package/lib/prompts.js.map +1 -0
- package/lib/settings.d.ts +96 -0
- package/lib/settings.js +141 -0
- package/lib/settings.js.map +1 -0
- package/lib/transcript.d.ts +257 -0
- package/lib/transcript.js +530 -0
- package/lib/transcript.js.map +1 -0
- package/package.json +90 -0
- package/scripts/build-client.mjs +268 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh advisor plugin — a per-session reviewer model (port of the omp
|
|
3
|
+
* "advisor" subsystem). Observes the primary transcript, reviews each stepped
|
|
4
|
+
* turn with an explicitly configured model, and injects severity-ranked
|
|
5
|
+
* advice (nit/concern/blocker) without polluting or recursively reviewing
|
|
6
|
+
* itself.
|
|
7
|
+
*
|
|
8
|
+
* T1 scaffold: declares the Cordis plugin entry (`name`/`inject`/`apply`).
|
|
9
|
+
* T2: config contract — the Loader schema (`Config`) plus the explicit
|
|
10
|
+
* provider/model gate via `resolveAdvisorConfig` (spec §5 / S4).
|
|
11
|
+
* T3: session observation — subscribe `session/event`, detect stepped
|
|
12
|
+
* `turn/end` (reason.kind ∈ {completed, 'max-tokens', error}, spec §4), drive
|
|
13
|
+
* a per-session bounded delta renderer, and dispose per-session state on
|
|
14
|
+
* `session/disposed` / `agent/disposed` (KD-5).
|
|
15
|
+
* T4: the per-session advisor runtime — queue each rendered delta, drain
|
|
16
|
+
* asynchronously via `ctx.llm.stream` (system prompt + delta, `purpose` left
|
|
17
|
+
* unset, KD-5), extract `{note, severity}` (KD-2), and apply the failure
|
|
18
|
+
* policy (retry-light → drop, 3-drop backlog flush, quota pause, permanent
|
|
19
|
+
* halt — never park the primary). The emission guard (T5) gates extracted
|
|
20
|
+
* notes before delivery; the delivery router (T6) routes accepted notes into
|
|
21
|
+
* the primary agent (nit → inject, concern/blocker → steer, immuneTurns
|
|
22
|
+
* cooldown, KD-4 agent map). T7: `/advisor` toggle/on/off/status commands
|
|
23
|
+
* (registered through the conditional `ctx.inject(['commands'], ...)` child)
|
|
24
|
+
* drive a per-session override consulted by the runtime gate — the commands
|
|
25
|
+
* start/stop per-session runtimes without touching the persisted config.
|
|
26
|
+
* Settings (plan dsh-advisor-settings-n2): the plugin-row config is the
|
|
27
|
+
* composition base of the `advisor` settings namespace (`src/settings.ts`),
|
|
28
|
+
* read live through the bridge source; committed settings edits re-apply
|
|
29
|
+
* derived state (immuneTurns / maxDeltaMessages / per-session runtimes)
|
|
30
|
+
* without a restart.
|
|
31
|
+
* Config gateway (plan dsh-advisor-settings-gateway-n5): `apply` also
|
|
32
|
+
* registers the host-side `AdvisorConfigGateway` (`src/gateway.ts`) — the
|
|
33
|
+
* `/api/advisor/get` + `/api/advisor/set` endpoints (explicit
|
|
34
|
+
* `ctx.typert.register` contribution — the host typertGateway claims
|
|
35
|
+
* `ctx.typert.local` first, so link-plugin module identity never matters)
|
|
36
|
+
* that make the Settings card truly readable/writable from the web client.
|
|
37
|
+
*
|
|
38
|
+
* @module dsh-advisor
|
|
39
|
+
*/
|
|
40
|
+
import { resolveAdvisorConfig } from './config.js';
|
|
41
|
+
import { installAdvisorSettings } from './settings.js';
|
|
42
|
+
import { AdvisorConfigGateway, advisorTypertContribution } from './gateway.js';
|
|
43
|
+
import { SessionTranscriptObserver } from './transcript.js';
|
|
44
|
+
import { AdvisorRuntime } from './advisor-runtime.js';
|
|
45
|
+
import { AdvisorDelivery } from './delivery.js';
|
|
46
|
+
import { DEFAULT_ADVISOR_SYSTEM_PROMPT } from './prompts.js';
|
|
47
|
+
import { AdvisorSessionOverrides, registerAdvisorCommands } from './commands.js';
|
|
48
|
+
export const name = 'dsh-advisor';
|
|
49
|
+
/** Services the advisor consumes; the row loads once all are available. */
|
|
50
|
+
export const inject = ['sessions', 'agents', 'llm'];
|
|
51
|
+
/** Loader schema (schemastery, strict) — validated by the cordis Loader. */
|
|
52
|
+
export { Config } from './config.js';
|
|
53
|
+
/** n4 QC F-6: single-reviewer guard. The host composes multiple dsh-advisor
|
|
54
|
+
* fibers (observed: 3 active); with the global session/event subscription every
|
|
55
|
+
* instance would observe every session and N×-review/N×-call per round. The
|
|
56
|
+
* FIRST apply to claim the reviewer role wires the observer/runtime/delivery
|
|
57
|
+
* and the /advisor commands; later instances attempt the settings registration
|
|
58
|
+
* only (qc1 W-5: it is NOT idempotent — dsh-settings register throws on a
|
|
59
|
+
* duplicate; installAdvisorSettings dedupes it and falls back to the entry
|
|
60
|
+
* source, so the first registration owns the live namespace) and stay inert
|
|
61
|
+
* otherwise. The claim is taken only AFTER the construction-time config gate
|
|
62
|
+
* (qc1 W-4: a rejected first row never leaves the flag claimed) and is
|
|
63
|
+
* released when the claiming fiber is disposed, so a later re-apply/re-mount
|
|
64
|
+
* can take over. The flag rides globalThis so it survives even module-copy
|
|
65
|
+
* divergence. */
|
|
66
|
+
const REVIEWER_KEY = '__dshAdvisorReviewer__';
|
|
67
|
+
function claimReviewer() {
|
|
68
|
+
const g = globalThis;
|
|
69
|
+
if (g[REVIEWER_KEY] === true)
|
|
70
|
+
return false;
|
|
71
|
+
g[REVIEWER_KEY] = true;
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
export function apply(ctx, config) {
|
|
75
|
+
// T2: the explicit provider/model gate — no model call without both
|
|
76
|
+
// (spec §5.2). Unknown keys / malformed config throw here, rejecting the
|
|
77
|
+
// plugin row at load; the gate resolves to disabled-with-reason instead.
|
|
78
|
+
//
|
|
79
|
+
// T1-settings (plan dsh-advisor-settings-n2): the plugin-row config is the
|
|
80
|
+
// composition BASE of the `advisor` settings namespace. The runtime reads
|
|
81
|
+
// the LIVE composed value through the bridge source (schema defaults →
|
|
82
|
+
// base → settings user layer); with no settings service the source is
|
|
83
|
+
// exactly `config` — behavior identical to today. The hard gate is applied
|
|
84
|
+
// to every read: `resolveAdvisorConfig` stays the SSOT for the
|
|
85
|
+
// disabled-with-reason resolution.
|
|
86
|
+
const bridge = installAdvisorSettings(ctx, config);
|
|
87
|
+
// n5 (plan dsh-advisor-settings-gateway-n5): the host-side `advisor` config
|
|
88
|
+
// gateway — the `/api/advisor/get` + `/api/advisor/set` endpoints. The
|
|
89
|
+
// endpoints are registered EXPLICITLY through `ctx.typert.register(...)`
|
|
90
|
+
// (NOT the @Remote SRC markers): the host typertGateway checks
|
|
91
|
+
// `ctx.typert.local` FIRST for claim + dispatch, while SRC discovery reads
|
|
92
|
+
// a module-private marker table that a locally-linked plugin can never
|
|
93
|
+
// share with the host installation (link plugins resolve their peers from
|
|
94
|
+
// their real directory, physically separate from the dlx host tree — the
|
|
95
|
+
// observed failure was zero claimed endpoints → `/api/advisor/*` 404).
|
|
96
|
+
// It reads the SAME bridge the runtime reads, so get/set always operate on
|
|
97
|
+
// the live composed config. Multi-fiber dedupe mirrors the settings
|
|
98
|
+
// registration (qc1 W-5): the cordis Service registration fails loud on a
|
|
99
|
+
// duplicate key, so the catch lets the FIRST fiber own the `advisor` service
|
|
100
|
+
// key while later fibers fall back (no gateway) — a later fiber's typert
|
|
101
|
+
// re-registration fails the same way (`already registered`). The
|
|
102
|
+
// registrations are fiber effects (unregistered when this fiber disposes),
|
|
103
|
+
// so a re-apply/re-mount can take over. The instance needs no handle here:
|
|
104
|
+
// the typertGateway dispatches through `ctx.get('advisor')`.
|
|
105
|
+
try {
|
|
106
|
+
new AdvisorConfigGateway(ctx, bridge);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (!(error instanceof Error) || !error.message.includes('has been registered'))
|
|
110
|
+
throw error;
|
|
111
|
+
ctx.logger('advisor').debug('advisor gateway already registered — no gateway on this fiber (multi-fiber dedupe)');
|
|
112
|
+
}
|
|
113
|
+
// The typert endpoint registration is OPTIONAL, like the settings service:
|
|
114
|
+
// it activates through a conditional inject child, so compositions without
|
|
115
|
+
// a typert registry (headless/standalone/integration harnesses) keep the
|
|
116
|
+
// advisor runtime working and simply omit the /api endpoints. The child
|
|
117
|
+
// disposer is the registration's own effect disposer, so the endpoints
|
|
118
|
+
// withdraw when this fiber (or the typert service) goes away.
|
|
119
|
+
ctx.inject(['typert'], (tctx) => {
|
|
120
|
+
try {
|
|
121
|
+
return tctx.typert.register(advisorTypertContribution());
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (!(error instanceof Error) || !error.message.includes('already registered'))
|
|
125
|
+
throw error;
|
|
126
|
+
tctx.logger('advisor').debug('advisor typert endpoints already registered — no endpoints on this fiber (multi-fiber dedupe)');
|
|
127
|
+
return () => { };
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
const sourceConfig = () => bridge.source();
|
|
131
|
+
const resolved = () => resolveAdvisorConfig(sourceConfig());
|
|
132
|
+
// qc2 W-1 containment: a settings user layer the resolver rejects (e.g. an
|
|
133
|
+
// unknown key survives the non-strict settings schema) must never wedge the
|
|
134
|
+
// live hot path — every read that can run inside an event handler goes
|
|
135
|
+
// through the safe wrappers, which catch resolver throws and return
|
|
136
|
+
// disabled-with-reason carrying the message, so gate semantics hold (no
|
|
137
|
+
// model call can start) and handlers stay functional. The LOAD-TIME
|
|
138
|
+
// plugin-row throw contract is unchanged: construction-time reads below
|
|
139
|
+
// (delivery/observer latches) still use the throwing `resolved()`, so a bad
|
|
140
|
+
// entry rejects the plugin row at load (config.test.ts ⑤).
|
|
141
|
+
const safeFallback = (reason) => ({
|
|
142
|
+
enabled: false,
|
|
143
|
+
systemPrompt: '',
|
|
144
|
+
immuneTurns: 3,
|
|
145
|
+
maxDeltaMessages: 60,
|
|
146
|
+
disabledReason: reason,
|
|
147
|
+
});
|
|
148
|
+
const safeResolved = () => {
|
|
149
|
+
try {
|
|
150
|
+
return resolveAdvisorConfig(sourceConfig());
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
return safeFallback(error instanceof Error ? error.message : String(error));
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const safeEffective = (sessionId) => {
|
|
157
|
+
try {
|
|
158
|
+
return resolveAdvisorConfig({ ...sourceConfig(), enabled: effectiveEnabled(sessionId) });
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
return safeFallback(error instanceof Error ? error.message : String(error));
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
ctx.logger('advisor').debug('dsh-advisor loaded', {
|
|
165
|
+
enabled: safeResolved().enabled,
|
|
166
|
+
disabledReason: safeResolved().disabledReason,
|
|
167
|
+
});
|
|
168
|
+
// T7: the per-session override mechanism — `/advisor on|off|toggle` write
|
|
169
|
+
// here and the runtime gate consults `override ?? config.enabled`, so the
|
|
170
|
+
// commands start/stop per-session runtimes WITHOUT touching the persisted
|
|
171
|
+
// config (spec §4 mapping — omp `/advisor` semantics). Ephemeral: entries
|
|
172
|
+
// are cleared on `agent/disposed` / `session/disposed` below. Seeded with
|
|
173
|
+
// the RAW config switch (not the post-gate `resolved.enabled`): a config-
|
|
174
|
+
// enabled-but-gate-blocked session (enabled without provider/model) then
|
|
175
|
+
// re-derives the disabled-with-reason through the resolver, so `/advisor
|
|
176
|
+
// status` shows the reason (spec §5.2; qc3 I-1) — the gate itself still
|
|
177
|
+
// blocks every runtime (the resolver is the SSOT for the gate).
|
|
178
|
+
const overrides = new AdvisorSessionOverrides(config.enabled);
|
|
179
|
+
const effectiveEnabled = (sessionId) => overrides.effective(sessionId);
|
|
180
|
+
// Live-path alias: every consumer reads the effective config through the
|
|
181
|
+
// safe wrapper (qc2 W-1 — a throwing resolver must not break the
|
|
182
|
+
// session/event handler or `/advisor status`).
|
|
183
|
+
const effectiveConfig = (sessionId) => safeEffective(sessionId);
|
|
184
|
+
// T3+T4: per-session transcript observation wired into one advisor runtime
|
|
185
|
+
// per session. On each stepped reviewable turn/end a bounded markdown delta
|
|
186
|
+
// is rendered and queued on the session's runtime; the runtime drains it
|
|
187
|
+
// asynchronously through `ctx.llm.stream`, gates the extracted `AdviceNote`
|
|
188
|
+
// through the T5 emission guard (inside the runtime, between extraction and
|
|
189
|
+
// delivery), and hands accepted notes to `onNote` (T6 routes them).
|
|
190
|
+
// T6: the delivery router. Owns the KD-4 per-session agent map (keyed by
|
|
191
|
+
// agent.id === session.id, maintained on agent/created / agent/disposed
|
|
192
|
+
// below), the severity → channel mapping (nit → inject; concern/blocker →
|
|
193
|
+
// steer), and the immuneTurns cooldown (spec §6). Accepted notes from the
|
|
194
|
+
// runtime's onNote are routed here; missing agent → drop + log (KD-4).
|
|
195
|
+
const delivery = new AdvisorDelivery({
|
|
196
|
+
immuneTurns: resolved().immuneTurns,
|
|
197
|
+
// Registry fallback (KD-4): covers agents published before this plugin
|
|
198
|
+
// loaded, whose `agent/created` was never observed. The delivery module is
|
|
199
|
+
// session-id-string-typed; the registry key is the branded SessionId.
|
|
200
|
+
lookupAgent: (sessionId) => ctx.agents.get(sessionId),
|
|
201
|
+
logger: ctx.logger('advisor'),
|
|
202
|
+
});
|
|
203
|
+
const runtimes = new Map();
|
|
204
|
+
/**
|
|
205
|
+
* Runtime-affecting signature per session — the values that pin one
|
|
206
|
+
* {@link AdvisorRuntime}: the effective switch, the post-gate enable (S4),
|
|
207
|
+
* and the {provider, model, systemPrompt} triple. Recorded at runtime
|
|
208
|
+
* creation and compared on every settings change (qc3 W-1 / qc1 W-2): only
|
|
209
|
+
* a signature change tears the runtime down — an immuneTurns/
|
|
210
|
+
* maxDeltaMessages-only edit updates the latches in place and keeps every
|
|
211
|
+
* in-flight call and backlog.
|
|
212
|
+
*/
|
|
213
|
+
const runtimeSignatures = new Map();
|
|
214
|
+
const runtimeSignature = (sessionId) => {
|
|
215
|
+
const effective = safeEffective(sessionId);
|
|
216
|
+
return [
|
|
217
|
+
effectiveEnabled(sessionId) ? 1 : 0,
|
|
218
|
+
effective.enabled ? 1 : 0,
|
|
219
|
+
effective.provider ?? '',
|
|
220
|
+
effective.model ?? '',
|
|
221
|
+
effective.systemPrompt,
|
|
222
|
+
].join('\u0000');
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Create (or return) the runtime for one session, gated on the effective
|
|
226
|
+
* switch: `undefined` when the session is disabled or the S4 explicit gate
|
|
227
|
+
* blocks model calls (effective enabled without provider/model — spec
|
|
228
|
+
* §5.2). T7's `/advisor on` turns a session on without a config change by
|
|
229
|
+
* flipping the override, which this gate reads.
|
|
230
|
+
*/
|
|
231
|
+
const ensureRuntime = (sessionId) => {
|
|
232
|
+
if (!effectiveEnabled(sessionId))
|
|
233
|
+
return undefined;
|
|
234
|
+
let runtime = runtimes.get(sessionId);
|
|
235
|
+
if (runtime !== undefined)
|
|
236
|
+
return runtime;
|
|
237
|
+
const effective = effectiveConfig(sessionId);
|
|
238
|
+
// The re-resolved config guarantees provider + model when enabled — the
|
|
239
|
+
// runtime is only constructed behind the gate.
|
|
240
|
+
if (!effective.enabled)
|
|
241
|
+
return undefined;
|
|
242
|
+
runtime = new AdvisorRuntime({
|
|
243
|
+
provider: effective.provider,
|
|
244
|
+
model: effective.model,
|
|
245
|
+
systemPrompt: safeResolved().systemPrompt || DEFAULT_ADVISOR_SYSTEM_PROMPT,
|
|
246
|
+
// n4 root-cause (host-observed NO_ADAPTER): this plugin's ctx may live in
|
|
247
|
+
// an isolated scope whose local llm service lacks the provider adapters
|
|
248
|
+
// (adapter registrations live on the application root's LlmRuntime). Resolve
|
|
249
|
+
// the llm service from the APPLICATION ROOT so the advisor's model calls
|
|
250
|
+
// reach the registered deepseek-official adapter.
|
|
251
|
+
llm: ctx.root?.get?.('llm') ?? ctx.llm,
|
|
252
|
+
onNote: (note) => {
|
|
253
|
+
// Accepted notes only — the runtime's emission guard (T5) already
|
|
254
|
+
// filtered suppressed ones. T6 routes the accepted note to the primary
|
|
255
|
+
// agent (inject/steer); delivery throws stay contained in the runtime
|
|
256
|
+
// path (T4 F1), so a failing agent can only drop its own advice.
|
|
257
|
+
const channel = delivery.route(sessionId, note);
|
|
258
|
+
ctx.logger('advisor').debug('advice note delivered', {
|
|
259
|
+
sessionId,
|
|
260
|
+
severity: note.severity,
|
|
261
|
+
channel,
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
runtimes.set(sessionId, runtime);
|
|
266
|
+
runtimeSignatures.set(sessionId, runtimeSignature(sessionId));
|
|
267
|
+
return runtime;
|
|
268
|
+
};
|
|
269
|
+
const disposeRuntime = (sessionId) => {
|
|
270
|
+
const runtime = runtimes.get(sessionId);
|
|
271
|
+
if (runtime === undefined)
|
|
272
|
+
return;
|
|
273
|
+
runtimes.delete(sessionId);
|
|
274
|
+
runtimeSignatures.delete(sessionId);
|
|
275
|
+
runtime.dispose();
|
|
276
|
+
};
|
|
277
|
+
// n4 QC F-6: claim the single-reviewer role HERE — after every
|
|
278
|
+
// construction-time throwing read (the delivery latch above resolves the
|
|
279
|
+
// config and can throw on a rejected row), so a first fiber whose config
|
|
280
|
+
// fails the gate never leaves the flag claimed (qc1 W-4). Non-reviewer
|
|
281
|
+
// instances stop here — observer/runtime/delivery and the /advisor commands
|
|
282
|
+
// are wired only by the single claimed reviewer. The settings registration
|
|
283
|
+
// (installAdvisorSettings above) already ran deduped (qc1 W-5): the first
|
|
284
|
+
// registration owns the live namespace on every composition.
|
|
285
|
+
const reviewer = claimReviewer();
|
|
286
|
+
if (!reviewer) {
|
|
287
|
+
ctx.logger('advisor').debug('non-reviewer instance — observer/runtime/commands skipped (single-reviewer guard)');
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
// qc1 W-4: release the claim when THIS (reviewer) fiber is disposed, so a
|
|
291
|
+
// later re-apply/re-mount (plugin-row removal, composition reload, host hot
|
|
292
|
+
// reload) can take over instead of leaving the advisor silently inert for
|
|
293
|
+
// the process lifetime. Registered only on the claiming fiber.
|
|
294
|
+
ctx.effect(() => () => {
|
|
295
|
+
delete globalThis[REVIEWER_KEY];
|
|
296
|
+
}, 'advisor: release reviewer claim');
|
|
297
|
+
const observer = new SessionTranscriptObserver({
|
|
298
|
+
maxDeltaMessages: resolved().maxDeltaMessages,
|
|
299
|
+
onSteppedTurnEnd: (sessionId) => {
|
|
300
|
+
// One completed stepped primary turn — decrement the immuneTurns
|
|
301
|
+
// cooldown (T6, spec §6). Fires before the delta render, so the note
|
|
302
|
+
// this very turn produces is routed with the decremented cooldown.
|
|
303
|
+
delivery.onSteppedTurnEnd(sessionId);
|
|
304
|
+
},
|
|
305
|
+
onRewrite: (sessionId) => {
|
|
306
|
+
// KD-5: a compaction / surface rewrite resets the immuneTurns latch
|
|
307
|
+
// (delivery) AND the emission-guard dedupe history (runtime) — session
|
|
308
|
+
// state is being rewritten, so both latches' basis no longer applies.
|
|
309
|
+
// T8: guard reset wired through the runtime (T5 ⚠️ follow-through).
|
|
310
|
+
delivery.reset(sessionId);
|
|
311
|
+
runtimes.get(sessionId)?.resetGuard();
|
|
312
|
+
},
|
|
313
|
+
onDelta: (sessionId, delta) => {
|
|
314
|
+
// Lazy creation fallback covers agents that existed before this plugin
|
|
315
|
+
// loaded (their `agent/created` was never observed); `agent/created`
|
|
316
|
+
// below creates eagerly for the common path. The runtime gate drops the
|
|
317
|
+
// delta for sessions that are disabled or S4-gate-blocked (T7).
|
|
318
|
+
ensureRuntime(sessionId)?.enqueue(delta);
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
// `session/event` is scope-filtered: the dsh scope carrier sets a
|
|
322
|
+
// `[Context.filter]` on emitted events — untagged listeners pass, but a
|
|
323
|
+
// tagged listener only receives events whose carrier key is on its own
|
|
324
|
+
// key's ancestor chain (see `packages/core/scope/src/index.ts` scopeTarget).
|
|
325
|
+
// Cordis dispatch skips the filter for global hooks
|
|
326
|
+
// (`hook.global || !filter || filter.call(...)` — `cordis/src/events.ts`
|
|
327
|
+
// dispatch), and the plugin's instances may be composed in isolated scopes
|
|
328
|
+
// (dsh-advisor appears as multiple active fibers, e.g. 3), so `{ global:
|
|
329
|
+
// true }` is required for the observer to receive every session's events
|
|
330
|
+
// regardless of scope placement. Q2=grill-me-locked fix; verified by host
|
|
331
|
+
// test (PM operator step, evidence in iteration guides).
|
|
332
|
+
//
|
|
333
|
+
// The three lifecycle listeners below dispatch through the SAME
|
|
334
|
+
// scope-filtered carrier as `session/event` (dsh-session/dsh-agent
|
|
335
|
+
// `announce`/`emitDisposed`), so they must be `{ global: true }` too (qc3
|
|
336
|
+
// F4): a scoped fiber that observes out-of-scope sessions via the global
|
|
337
|
+
// session/event listener would otherwise create per-session state —
|
|
338
|
+
// renderers, runtimes, cooldowns, overrides — whose dispose events are
|
|
339
|
+
// filtered out, a per-session leak for the host's lifetime. Create/dispose
|
|
340
|
+
// symmetry restored; both dispose listeners are documented idempotent
|
|
341
|
+
// (a runtime is disposed at most once, whichever signal lands first).
|
|
342
|
+
ctx.on('session/event', (session, event) => {
|
|
343
|
+
observer.handleEvent(session.id, session.events, event);
|
|
344
|
+
}, { global: true });
|
|
345
|
+
// Per-session runtime lifecycle. Spec KD-5(c) pins `agent/disposed`;
|
|
346
|
+
// `session/disposed` is the store-level pair (both are idempotent — a
|
|
347
|
+
// runtime is disposed at most once, whichever signal lands first). `agent/created`
|
|
348
|
+
// creates the runtime eagerly (plan T4) when the session is enabled and
|
|
349
|
+
// registers the agent in the KD-4 delivery map (T6); the observer fallback
|
|
350
|
+
// covers pre-existing agents (KD-4-style robustness).
|
|
351
|
+
ctx.on('agent/created', ({ agent }) => {
|
|
352
|
+
ensureRuntime(agent.id);
|
|
353
|
+
delivery.registerAgent(agent);
|
|
354
|
+
}, { global: true });
|
|
355
|
+
ctx.on('agent/disposed', ({ agent }) => {
|
|
356
|
+
observer.disposeSession(agent.id);
|
|
357
|
+
disposeRuntime(agent.id);
|
|
358
|
+
delivery.unregisterAgent(agent.id);
|
|
359
|
+
overrides.clear(agent.id);
|
|
360
|
+
}, { global: true });
|
|
361
|
+
ctx.on('session/disposed', (session) => {
|
|
362
|
+
observer.disposeSession(session.id);
|
|
363
|
+
disposeRuntime(session.id);
|
|
364
|
+
delivery.unregisterAgent(session.id);
|
|
365
|
+
overrides.clear(session.id);
|
|
366
|
+
}, { global: true });
|
|
367
|
+
// T1-settings live re-apply: construction-time latches (immuneTurns on the
|
|
368
|
+
// delivery, maxDeltaMessages on the observer, systemPrompt + provider/model
|
|
369
|
+
// on each per-session runtime) are re-derived from the NEW source on every
|
|
370
|
+
// committed settings change and re-applied — delivery/observer update in
|
|
371
|
+
// place, per-session runtimes rebuild only when their runtime-affecting
|
|
372
|
+
// signature actually changed (qc3 W-1 / qc1 W-2: an immuneTurns/
|
|
373
|
+
// maxDeltaMessages-only edit must not abort in-flight advisor calls or drop
|
|
374
|
+
// backlogs). The S4 gate is re-applied by the resolver on every read, so a
|
|
375
|
+
// settings edit can never start a gated model call (SSOT unchanged); the
|
|
376
|
+
// config-level fallback switch follows the live source so new sessions pick
|
|
377
|
+
// up a Settings-page `enabled` edit immediately. A settings user layer the
|
|
378
|
+
// resolver rejects (qc2 W-1 — unknown key) stops the advisor without
|
|
379
|
+
// wedging the re-apply path, and the last-good latches stay until the
|
|
380
|
+
// config is repaired.
|
|
381
|
+
bridge.onChange(() => {
|
|
382
|
+
let next;
|
|
383
|
+
try {
|
|
384
|
+
next = resolveAdvisorConfig(sourceConfig());
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
// The raw source is still readable for the switch even when the
|
|
388
|
+
// resolver rejects the composed value; if even that fails, keep the
|
|
389
|
+
// current config-level switch (the gate below still blocks runtimes).
|
|
390
|
+
try {
|
|
391
|
+
overrides.setConfigEnabled(sourceConfig().enabled);
|
|
392
|
+
}
|
|
393
|
+
catch {
|
|
394
|
+
// unreadable source — the effective switch stays as-is
|
|
395
|
+
}
|
|
396
|
+
for (const sessionId of [...runtimes.keys()])
|
|
397
|
+
disposeRuntime(sessionId);
|
|
398
|
+
ctx.logger('advisor').warn('settings change: invalid advisor config — advisor stopped', {
|
|
399
|
+
disabledReason: error instanceof Error ? error.message : String(error),
|
|
400
|
+
});
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
delivery.setImmuneTurns(next.immuneTurns);
|
|
404
|
+
observer.setMaxDeltaMessages(next.maxDeltaMessages);
|
|
405
|
+
overrides.setConfigEnabled(sourceConfig().enabled);
|
|
406
|
+
let rebuilt = 0;
|
|
407
|
+
for (const sessionId of [...runtimes.keys()]) {
|
|
408
|
+
if (runtimeSignatures.get(sessionId) === runtimeSignature(sessionId))
|
|
409
|
+
continue;
|
|
410
|
+
disposeRuntime(sessionId);
|
|
411
|
+
ensureRuntime(sessionId);
|
|
412
|
+
rebuilt += 1;
|
|
413
|
+
}
|
|
414
|
+
if (rebuilt > 0) {
|
|
415
|
+
ctx.logger('advisor').debug('settings change rebuilt session runtimes', {
|
|
416
|
+
rebuilt,
|
|
417
|
+
provider: next.provider,
|
|
418
|
+
model: next.model,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
// T7: the `/advisor` command controller — the commands' session-scoped
|
|
423
|
+
// operations against the observer/runtimes above. `/advisor on` seeds the
|
|
424
|
+
// observer cursor to the current transcript length (KD-5 seed-on-enable —
|
|
425
|
+
// no full-history replay) and creates/resumes/recoveries the session runtime;
|
|
426
|
+
// `/advisor off` disposes it (abort in-flight, drop backlog). The S4 gate
|
|
427
|
+
// reason is re-derived through the config resolver, the SSOT for the
|
|
428
|
+
// disabled-with-reason text (spec §5.2).
|
|
429
|
+
const controller = {
|
|
430
|
+
setEnabled(sessionId, enabled, sessionLength) {
|
|
431
|
+
// Recovery, not just a switch flip: `/advisor on` (and toggle-to-on)
|
|
432
|
+
// must restart a session advisor that is `quota_exhausted` (KD-5 —
|
|
433
|
+
// manual resume, no auto-resume timer) or `halted` (permanent model
|
|
434
|
+
// error — terminal in place, rebuilt fresh here) (qc1/qc2/qc3 W-1/I-4).
|
|
435
|
+
// The override is written only when the effective switch actually
|
|
436
|
+
// changes; enabling an already-effectively-enabled session still routes
|
|
437
|
+
// through the recovery path below instead of early-returning.
|
|
438
|
+
const already = effectiveEnabled(sessionId) === enabled;
|
|
439
|
+
if (!already)
|
|
440
|
+
overrides.set(sessionId, enabled);
|
|
441
|
+
if (!enabled) {
|
|
442
|
+
if (!already)
|
|
443
|
+
disposeRuntime(sessionId);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
// enabled (newly or already): KD-5 seed — no full-history replay of
|
|
447
|
+
// deltas that predate (or occurred while paused/halted under) the enable.
|
|
448
|
+
if (sessionLength !== undefined)
|
|
449
|
+
observer.seedTo(sessionId, sessionLength);
|
|
450
|
+
const runtime = ensureRuntime(sessionId);
|
|
451
|
+
if (runtime === undefined)
|
|
452
|
+
return; // S4 explicit gate blocks model calls
|
|
453
|
+
if (runtime.status() === 'halted') {
|
|
454
|
+
// KD-5 halting is terminal in place; `/advisor on` is the manual
|
|
455
|
+
// recovery path — rebuild a fresh runtime (the S4 gate is re-applied
|
|
456
|
+
// by ensureRuntime, so this can never start a gated model call).
|
|
457
|
+
disposeRuntime(sessionId);
|
|
458
|
+
ensureRuntime(sessionId);
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
runtime.resume(); // no-op on 'running'; resumes 'quota_exhausted' (KD-5)
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
getStatus(sessionId) {
|
|
465
|
+
const runtime = runtimes.get(sessionId);
|
|
466
|
+
const effective = effectiveConfig(sessionId);
|
|
467
|
+
return {
|
|
468
|
+
enabled: effective.enabled,
|
|
469
|
+
...(effective.disabledReason === undefined ? {} : { disabledReason: effective.disabledReason }),
|
|
470
|
+
provider: safeResolved().provider,
|
|
471
|
+
model: safeResolved().model,
|
|
472
|
+
runtimeStatus: runtime?.status() ?? 'disabled',
|
|
473
|
+
pendingCount: runtime?.pendingCount ?? 0,
|
|
474
|
+
lastActivityAt: runtime?.lastActivity,
|
|
475
|
+
};
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
// T7: the command child activates ONLY when a command registry is composed
|
|
479
|
+
// (conditional child activation — `commands` must NOT join the top-level
|
|
480
|
+
// `inject` list, T1 fix). `/advisor` toggle/on/off/status (spec §2 S5).
|
|
481
|
+
ctx.inject(['commands'], (commandCtx) => {
|
|
482
|
+
registerAdvisorCommands(commandCtx.commands, controller);
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/kinds.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisor source kind + the `MessageSourceMap` merge extension (spec §6).
|
|
3
|
+
*
|
|
4
|
+
* Advisor-injected messages enter the session as user-role messages carrying
|
|
5
|
+
* `source.kind === 'advisor'` (via the plugin's `MessageSourceMap` merge
|
|
6
|
+
* declaration, `declare module '@deepseek-ai/dsh-llm'`). The delta renderer
|
|
7
|
+
* (T3) and the delivery router (T6) both key off this kind:
|
|
8
|
+
*
|
|
9
|
+
* - **Self-review exclusion (spec §6):** every advisor-source message is
|
|
10
|
+
* excluded from subsequent advisor deltas, so the advisor never reads its
|
|
11
|
+
* own injected advice back.
|
|
12
|
+
* - **Delivery tagging (T6):** `createUserMessage({ ..., source: { kind:
|
|
13
|
+
* ADVISOR_SOURCE_KIND } })` marks injected advice so it is visible in the
|
|
14
|
+
* session stream yet excluded from later deltas.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-advisor/kinds
|
|
17
|
+
*/
|
|
18
|
+
import type { ContextFormed, Message } from '@deepseek-ai/dsh-llm';
|
|
19
|
+
declare module '@deepseek-ai/dsh-llm' {
|
|
20
|
+
interface MessageSourceMap {
|
|
21
|
+
/**
|
|
22
|
+
* An advisor-injected message (user-role, self-describing
|
|
23
|
+
* `[advisor:{severity}] {note}` content). Never derived into advisor
|
|
24
|
+
* deltas (self-review guard, spec §6). Extends {@link ContextFormed} so
|
|
25
|
+
* the plugin can declare the `notice` form + one-line `summary` the web
|
|
26
|
+
* shell renders on a collapsed context row.
|
|
27
|
+
*/
|
|
28
|
+
advisor: {
|
|
29
|
+
readonly kind: 'advisor';
|
|
30
|
+
} & ContextFormed;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The `source.kind` value carried by every advisor-injected message. */
|
|
34
|
+
export declare const ADVISOR_SOURCE_KIND: "advisor";
|
|
35
|
+
/** Type of a message source carrying the advisor kind. */
|
|
36
|
+
export type AdvisorSourceKind = typeof ADVISOR_SOURCE_KIND;
|
|
37
|
+
/** True when a message was injected by the advisor itself. */
|
|
38
|
+
export declare function isAdvisorMessage(message: Message): boolean;
|
package/lib/kinds.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisor source kind + the `MessageSourceMap` merge extension (spec §6).
|
|
3
|
+
*
|
|
4
|
+
* Advisor-injected messages enter the session as user-role messages carrying
|
|
5
|
+
* `source.kind === 'advisor'` (via the plugin's `MessageSourceMap` merge
|
|
6
|
+
* declaration, `declare module '@deepseek-ai/dsh-llm'`). The delta renderer
|
|
7
|
+
* (T3) and the delivery router (T6) both key off this kind:
|
|
8
|
+
*
|
|
9
|
+
* - **Self-review exclusion (spec §6):** every advisor-source message is
|
|
10
|
+
* excluded from subsequent advisor deltas, so the advisor never reads its
|
|
11
|
+
* own injected advice back.
|
|
12
|
+
* - **Delivery tagging (T6):** `createUserMessage({ ..., source: { kind:
|
|
13
|
+
* ADVISOR_SOURCE_KIND } })` marks injected advice so it is visible in the
|
|
14
|
+
* session stream yet excluded from later deltas.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-advisor/kinds
|
|
17
|
+
*/
|
|
18
|
+
/** The `source.kind` value carried by every advisor-injected message. */
|
|
19
|
+
export const ADVISOR_SOURCE_KIND = 'advisor';
|
|
20
|
+
/** True when a message was injected by the advisor itself. */
|
|
21
|
+
export function isAdvisorMessage(message) {
|
|
22
|
+
return message.source.kind === ADVISOR_SOURCE_KIND;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=kinds.js.map
|
package/lib/kinds.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kinds.js","sourceRoot":"","sources":["../src/kinds.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAiBH,yEAAyE;AACzE,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAkB,CAAA;AAKrD,8DAA8D;AAC9D,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,mBAAmB,CAAA;AACpD,CAAC"}
|
package/lib/prompts.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-advisor reviewer system prompt (spec §6, §8.2 KD-2).
|
|
3
|
+
*
|
|
4
|
+
* The advisor is an independent reviewer attached to a coding session: it
|
|
5
|
+
* receives an incremental markdown delta prefixed with `### Session update`
|
|
6
|
+
* (the T3 `DeltaRenderer` output) after each stepped primary turn and replies
|
|
7
|
+
* with exactly one JSON object `{"note", "severity"}`.
|
|
8
|
+
*
|
|
9
|
+
* The prompt pins the delivery contract KD-2 relies on:
|
|
10
|
+
* - the reviewer framing (independent, advisory-only — never approves actions);
|
|
11
|
+
* - the severity definitions from spec §6 (nit / concern / blocker);
|
|
12
|
+
* - the JSON-frame output contract: exactly one object, `severity` optional
|
|
13
|
+
* (omitted = nit), `note` non-empty, one note per update;
|
|
14
|
+
* - a valid "nothing to add" frame, which the T5 emission guard's content-free
|
|
15
|
+
* suppression filters out at delivery time.
|
|
16
|
+
*
|
|
17
|
+
* The extraction code tolerates prose/fences defensively, but the prompt asks
|
|
18
|
+
* for a bare frame so the happy path is a clean parse.
|
|
19
|
+
*
|
|
20
|
+
* @module dsh-advisor/prompts
|
|
21
|
+
*/
|
|
22
|
+
export declare const DEFAULT_ADVISOR_SYSTEM_PROMPT = "You are an independent reviewer attached to a coding-agent session. You observe the primary agent's work and surface concise, severity-ranked advice. You are advisory only: you never approve or reject the agent's actions, and you never issue commands as if you were the primary agent.\n\nAfter each completed primary turn you receive an incremental transcript update prefixed with \"### Session update\" (a user message). Review only what changed in this update.\n\nSeverity levels:\n- nit: a minor style, clarity, or quality suggestion; no course change is needed.\n- concern: a material risk or a clearly better direction that the primary should weigh before continuing.\n- blocker: continuing clearly wastes work \u2014 the primary contradicts an explicit user instruction, is going in circles, or the approach is fundamentally unsound.\n\nReply with EXACTLY ONE JSON object and nothing else:\n{\"note\": \"<your note>\", \"severity\": \"nit\"|\"concern\"|\"blocker\"}\n\n- \"severity\" is optional; when omitted it means \"nit\".\n- \"note\" must be a non-empty string: one concise, specific, actionable observation about this update. One note per update.\n- If there is genuinely nothing worth advising, respond with {\"note\": \"Nothing to add\"}.\n- Do not include prose, markdown fences, or anything outside the JSON object.";
|
package/lib/prompts.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-advisor reviewer system prompt (spec §6, §8.2 KD-2).
|
|
3
|
+
*
|
|
4
|
+
* The advisor is an independent reviewer attached to a coding session: it
|
|
5
|
+
* receives an incremental markdown delta prefixed with `### Session update`
|
|
6
|
+
* (the T3 `DeltaRenderer` output) after each stepped primary turn and replies
|
|
7
|
+
* with exactly one JSON object `{"note", "severity"}`.
|
|
8
|
+
*
|
|
9
|
+
* The prompt pins the delivery contract KD-2 relies on:
|
|
10
|
+
* - the reviewer framing (independent, advisory-only — never approves actions);
|
|
11
|
+
* - the severity definitions from spec §6 (nit / concern / blocker);
|
|
12
|
+
* - the JSON-frame output contract: exactly one object, `severity` optional
|
|
13
|
+
* (omitted = nit), `note` non-empty, one note per update;
|
|
14
|
+
* - a valid "nothing to add" frame, which the T5 emission guard's content-free
|
|
15
|
+
* suppression filters out at delivery time.
|
|
16
|
+
*
|
|
17
|
+
* The extraction code tolerates prose/fences defensively, but the prompt asks
|
|
18
|
+
* for a bare frame so the happy path is a clean parse.
|
|
19
|
+
*
|
|
20
|
+
* @module dsh-advisor/prompts
|
|
21
|
+
*/
|
|
22
|
+
export const DEFAULT_ADVISOR_SYSTEM_PROMPT = `You are an independent reviewer attached to a coding-agent session. You observe the primary agent's work and surface concise, severity-ranked advice. You are advisory only: you never approve or reject the agent's actions, and you never issue commands as if you were the primary agent.
|
|
23
|
+
|
|
24
|
+
After each completed primary turn you receive an incremental transcript update prefixed with "### Session update" (a user message). Review only what changed in this update.
|
|
25
|
+
|
|
26
|
+
Severity levels:
|
|
27
|
+
- nit: a minor style, clarity, or quality suggestion; no course change is needed.
|
|
28
|
+
- concern: a material risk or a clearly better direction that the primary should weigh before continuing.
|
|
29
|
+
- blocker: continuing clearly wastes work — the primary contradicts an explicit user instruction, is going in circles, or the approach is fundamentally unsound.
|
|
30
|
+
|
|
31
|
+
Reply with EXACTLY ONE JSON object and nothing else:
|
|
32
|
+
{"note": "<your note>", "severity": "nit"|"concern"|"blocker"}
|
|
33
|
+
|
|
34
|
+
- "severity" is optional; when omitted it means "nit".
|
|
35
|
+
- "note" must be a non-empty string: one concise, specific, actionable observation about this update. One note per update.
|
|
36
|
+
- If there is genuinely nothing worth advising, respond with {"note": "Nothing to add"}.
|
|
37
|
+
- Do not include prose, markdown fences, or anything outside the JSON object.`;
|
|
38
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG;;;;;;;;;;;;;;;8EAeiC,CAAA"}
|