dsh-ntr 0.1.3 → 0.1.4
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.en.md +8 -4
- package/README.md +8 -4
- package/lib/bridge.js +116 -28
- package/lib/client/acp-ui.js +3 -1
- package/lib/client/panel.js +6 -4
- package/lib/client/session-controls.js +27 -11
- package/lib/client.js +40 -17
- package/lib/client.js.map +1 -1
- package/lib/impl.js +102 -9
- package/lib/types/bridge.d.ts +32 -6
- package/lib/types/client/acp-ui.d.ts +6 -0
- package/lib/types/client/session-controls.d.ts +2 -0
- package/lib/types/client/store.d.ts +1 -1
- package/lib/types/impl.d.ts +36 -1
- package/lib/types/protocol.d.ts +22 -8
- package/package.json +1 -1
- package/src/bridge.ts +116 -32
- package/src/client/acp-ui.tsx +13 -2
- package/src/client/panel.tsx +6 -4
- package/src/client/session-controls.tsx +29 -11
- package/src/client/store.ts +1 -1
- package/src/impl.ts +101 -10
- package/src/protocol.ts +22 -8
package/lib/impl.js
CHANGED
|
@@ -222,8 +222,9 @@ export function validateAgentDef(entry, label = 'agent') {
|
|
|
222
222
|
const exposedModels = row.exposedModels === undefined
|
|
223
223
|
? undefined
|
|
224
224
|
: normalizeExposedModels(row.exposedModels, `agent "${id}" exposedModels`, 'bad_config');
|
|
225
|
-
// Optional boolean
|
|
226
|
-
// "
|
|
225
|
+
// Optional boolean, ON by default. Only the explicit opt-out is stored:
|
|
226
|
+
// `true` and absent are the same "on" state, so the persisted file does not
|
|
227
|
+
// carry noise.
|
|
227
228
|
const autoDiscoverModels = row.autoDiscoverModels;
|
|
228
229
|
if (autoDiscoverModels !== undefined && typeof autoDiscoverModels !== 'boolean') {
|
|
229
230
|
throw new AcpError('bad_config', `acp: agent "${id}" autoDiscoverModels must be a boolean`);
|
|
@@ -245,7 +246,7 @@ export function validateAgentDef(entry, label = 'agent') {
|
|
|
245
246
|
cwd: cwd,
|
|
246
247
|
allowedCwdRoots: roots,
|
|
247
248
|
...(exposedModels !== undefined ? { exposedModels } : {}),
|
|
248
|
-
...(autoDiscoverModels ===
|
|
249
|
+
...(autoDiscoverModels === false ? { autoDiscoverModels: false } : {}),
|
|
249
250
|
...(idleTimeoutMs === undefined ? {} : { idleTimeoutMs: idleTimeoutMs }),
|
|
250
251
|
};
|
|
251
252
|
}
|
|
@@ -603,25 +604,113 @@ export function parseCatalogOptions(configOptions) {
|
|
|
603
604
|
continue;
|
|
604
605
|
const choices = [];
|
|
605
606
|
collectCatalogChoices(row.options, choices);
|
|
607
|
+
// A boolean toggle has no `options` at all; its current value is a JSON
|
|
608
|
+
// boolean. It is encoded as 'true' / 'false' so the catalog stays
|
|
609
|
+
// string-typed for every existing reader, and carries `kind` so the
|
|
610
|
+
// composer renders a checkbox instead of a select.
|
|
611
|
+
const booleanKind = row.type === 'boolean'
|
|
612
|
+
|| (typeof row.currentValue === 'boolean' && choices.length === 0);
|
|
606
613
|
const option = {
|
|
607
614
|
configId,
|
|
608
615
|
name: typeof row.name === 'string' && row.name !== '' ? row.name : configId,
|
|
609
|
-
|
|
616
|
+
...(booleanKind ? { kind: 'boolean' } : {}),
|
|
617
|
+
currentValue: booleanKind
|
|
618
|
+
? row.currentValue === true || row.currentValue === 'true'
|
|
619
|
+
? 'true'
|
|
620
|
+
: row.currentValue === false || row.currentValue === 'false' ? 'false' : null
|
|
621
|
+
: typeof row.currentValue === 'string' && row.currentValue !== '' ? row.currentValue : null,
|
|
610
622
|
choices,
|
|
611
623
|
};
|
|
612
|
-
|
|
624
|
+
// A toggle is never a model / thought / mode SELECT: those controls pick
|
|
625
|
+
// among choices. It belongs to the advanced base, where it is a checkbox.
|
|
626
|
+
if (slot !== undefined && !booleanKind) {
|
|
613
627
|
out[slot] = option;
|
|
614
628
|
continue;
|
|
615
629
|
}
|
|
616
630
|
// Choice-less options have nothing to pick; they would render an empty
|
|
617
|
-
// section in the advanced menu, so they stay out of the catalog entirely
|
|
618
|
-
|
|
631
|
+
// section in the advanced menu, so they stay out of the catalog entirely —
|
|
632
|
+
// except a boolean, whose whole point is that it has no choices.
|
|
633
|
+
if (choices.length > 0 || booleanKind)
|
|
619
634
|
extras.set(configId, option);
|
|
620
635
|
}
|
|
621
636
|
if (extras.size > 0)
|
|
622
637
|
out.extras = [...extras.values()];
|
|
623
638
|
return out;
|
|
624
639
|
}
|
|
640
|
+
/**
|
|
641
|
+
* Fold one per-session option answer's SHAPE into an agent-level catalog.
|
|
642
|
+
*
|
|
643
|
+
* `session/set_config_option` answers are often the ONLY place an agent
|
|
644
|
+
* publishes how its option set changes with the model — opencode offers
|
|
645
|
+
* `thought_level` (`effort`) just for models with variants and never
|
|
646
|
+
* re-notifies after a client-driven set — and the composer's thought chip is
|
|
647
|
+
* driven by the agent-level catalog. What is agent knowledge there is the
|
|
648
|
+
* SHAPE (which slots exist, which choices they offer); `currentValue` is not:
|
|
649
|
+
* in a per-session answer it is that session's pick, and promoting it would
|
|
650
|
+
* turn one conversation's choice into `reasoning.defaultEffort` for every
|
|
651
|
+
* other one. A merged slot therefore keeps the catalog's known current value
|
|
652
|
+
* while the observed choices still offer it, and `null` ("the agent's own
|
|
653
|
+
* default") otherwise. Slots the answer does not mention are left alone — a
|
|
654
|
+
* different model may still offer them.
|
|
655
|
+
*/
|
|
656
|
+
export function mergeCatalogShape(existing, observed) {
|
|
657
|
+
const out = {};
|
|
658
|
+
const merge = (prev, next) => {
|
|
659
|
+
const kept = prev?.currentValue ?? null;
|
|
660
|
+
return {
|
|
661
|
+
configId: next.configId,
|
|
662
|
+
name: next.name,
|
|
663
|
+
...(next.kind === 'boolean' ? { kind: 'boolean' } : {}),
|
|
664
|
+
// A boolean has no choices to test `kept` against; it keeps the
|
|
665
|
+
// catalog's known default like any other slot (the answer's value is
|
|
666
|
+
// still one session's truth, not the agent's).
|
|
667
|
+
currentValue: kept !== null && (next.choices.length === 0 || next.choices.some(choice => choice.value === kept)) ? kept : null,
|
|
668
|
+
choices: next.choices,
|
|
669
|
+
};
|
|
670
|
+
};
|
|
671
|
+
for (const slot of ['model', 'thought', 'mode']) {
|
|
672
|
+
const prev = existing?.[slot];
|
|
673
|
+
const next = observed[slot];
|
|
674
|
+
if (next === undefined) {
|
|
675
|
+
if (prev !== undefined)
|
|
676
|
+
out[slot] = prev;
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
out[slot] = merge(prev, next);
|
|
680
|
+
}
|
|
681
|
+
// Extras merge by configId: observed entries refresh their shape, entries
|
|
682
|
+
// only the earlier answer knew survive (another model may still offer them).
|
|
683
|
+
const extras = new Map();
|
|
684
|
+
for (const option of existing?.extras ?? [])
|
|
685
|
+
extras.set(option.configId, option);
|
|
686
|
+
for (const option of observed.extras ?? [])
|
|
687
|
+
extras.set(option.configId, merge(extras.get(option.configId), option));
|
|
688
|
+
if (extras.size > 0)
|
|
689
|
+
out.extras = [...extras.values()];
|
|
690
|
+
return out;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Size ceiling for one `configOptions` answer to be believed. Normal answers
|
|
694
|
+
* are a few KB (a 500-model catalog is well under this); beyond it the agent is
|
|
695
|
+
* misbehaving and absorbing/persisting it would turn every notification into
|
|
696
|
+
* an unbounded write.
|
|
697
|
+
*/
|
|
698
|
+
export const MAX_CONFIG_OPTIONS_BYTES = 1 << 20;
|
|
699
|
+
/**
|
|
700
|
+
* Whether a `configOptions` answer may overwrite known state.
|
|
701
|
+
*
|
|
702
|
+
* An EMPTY (or absent) answer is a non-answer: observed agents return
|
|
703
|
+
* `configOptions: []` in intermediate states, and treating that as "this agent
|
|
704
|
+
* now has no options" would wipe a perfectly good catalog and session
|
|
705
|
+
* snapshot for a state that passes (the rule OmniTerm settles on for the same
|
|
706
|
+
* observation — empty sets never overwrite the last known state). Oversized
|
|
707
|
+
* answers are dropped for the same reason: see {@link MAX_CONFIG_OPTIONS_BYTES}.
|
|
708
|
+
*/
|
|
709
|
+
export function usableConfigOptions(configOptions) {
|
|
710
|
+
if (!Array.isArray(configOptions) || configOptions.length === 0)
|
|
711
|
+
return false;
|
|
712
|
+
return JSON.stringify(configOptions).length <= MAX_CONFIG_OPTIONS_BYTES;
|
|
713
|
+
}
|
|
625
714
|
/** Flatten select `options` (plain values or `SessionConfigSelectGroup`s) into choices, deduped by value. */
|
|
626
715
|
function collectCatalogChoices(options, out) {
|
|
627
716
|
if (!Array.isArray(options))
|
|
@@ -1353,8 +1442,12 @@ export async function dispatchRpc(manager, endpoint, payload) {
|
|
|
1353
1442
|
case 'session/chat-config-set': {
|
|
1354
1443
|
const dshSessionId = str(body, 'dshSessionId', 128);
|
|
1355
1444
|
const configId = str(body, 'configId', 128);
|
|
1356
|
-
const value =
|
|
1357
|
-
|
|
1445
|
+
const value = body.value;
|
|
1446
|
+
if (typeof value === 'boolean') {
|
|
1447
|
+
await manager.setChatSessionConfig?.(dshSessionId, configId, value, optionalStr(body, 'agentId', 64));
|
|
1448
|
+
return ok({ done: true });
|
|
1449
|
+
}
|
|
1450
|
+
await manager.setChatSessionConfig?.(dshSessionId, configId, str(body, 'value', 512), optionalStr(body, 'agentId', 64));
|
|
1358
1451
|
return ok({ done: true });
|
|
1359
1452
|
}
|
|
1360
1453
|
case 'preset/status':
|
package/lib/types/bridge.d.ts
CHANGED
|
@@ -203,7 +203,13 @@ export declare class AgentBridge {
|
|
|
203
203
|
private readonly transcriptMax;
|
|
204
204
|
/** Called when the connection dies so the manager can settle outstanding prompts. */
|
|
205
205
|
private readonly onConnectionLost;
|
|
206
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* Observes `configOptions` from any real session so the manager's model
|
|
208
|
+
* catalog stays warm. `shapeOnly` marks a per-session answer (a
|
|
209
|
+
* `session/set_config_option` response): only the option SHAPE belongs in
|
|
210
|
+
* the agent-level catalog, never its `currentValue` — see
|
|
211
|
+
* {@link BridgeManager.absorbCatalogShape}.
|
|
212
|
+
*/
|
|
207
213
|
private readonly onCatalog?;
|
|
208
214
|
/** Observes `availableCommands` from any real session so the agent's slash menu survives its sessions. */
|
|
209
215
|
private readonly onCommands?;
|
|
@@ -279,8 +285,14 @@ export declare class AgentBridge {
|
|
|
279
285
|
constructor(def: AcpAgentDef, hub: EventHub, transcriptMax: number,
|
|
280
286
|
/** Called when the connection dies so the manager can settle outstanding prompts. */
|
|
281
287
|
onConnectionLost: (bridge: AgentBridge, reason: string) => void,
|
|
282
|
-
/**
|
|
283
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Observes `configOptions` from any real session so the manager's model
|
|
290
|
+
* catalog stays warm. `shapeOnly` marks a per-session answer (a
|
|
291
|
+
* `session/set_config_option` response): only the option SHAPE belongs in
|
|
292
|
+
* the agent-level catalog, never its `currentValue` — see
|
|
293
|
+
* {@link BridgeManager.absorbCatalogShape}.
|
|
294
|
+
*/
|
|
295
|
+
onCatalog?: ((agentId: string, configOptions: unknown, shapeOnly?: boolean) => void) | undefined,
|
|
284
296
|
/** Observes `availableCommands` from any real session so the agent's slash menu survives its sessions. */
|
|
285
297
|
onCommands?: ((agentId: string, commands: NonNullable<SessionView["availableCommands"]>) => void) | undefined, tuning?: BridgeTuning,
|
|
286
298
|
/**
|
|
@@ -1095,7 +1107,7 @@ export declare class BridgeManager {
|
|
|
1095
1107
|
* A live session is updated immediately; a failure there is warned about and
|
|
1096
1108
|
* the pick still stands, exactly like the model/effort alignment path.
|
|
1097
1109
|
*/
|
|
1098
|
-
setChatSessionConfig(dshSessionId: string, configId: string, value: string, agentId?: string): Promise<void>;
|
|
1110
|
+
setChatSessionConfig(dshSessionId: string, configId: string, value: string | boolean, agentId?: string): Promise<void>;
|
|
1099
1111
|
/**
|
|
1100
1112
|
* Apply a conversation's persisted pick to a session that just materialized —
|
|
1101
1113
|
* created by the first turn, or resumed through `session/load` after a crash.
|
|
@@ -1209,6 +1221,18 @@ export declare class BridgeManager {
|
|
|
1209
1221
|
* current `parseCatalogOptions` has now seen this agent's real answer.
|
|
1210
1222
|
*/
|
|
1211
1223
|
private absorbCatalog;
|
|
1224
|
+
/**
|
|
1225
|
+
* Fold a per-session option answer's SHAPE into the agent's catalog.
|
|
1226
|
+
*
|
|
1227
|
+
* The counterpart of {@link absorbCatalog} for `session/set_config_option`
|
|
1228
|
+
* responses: which options exist and which choices they offer is agent
|
|
1229
|
+
* knowledge the seat must show (the composer's thought chip only renders
|
|
1230
|
+
* when the catalog has `thought_level`, and some agents publish it only in
|
|
1231
|
+
* the answer to a model change), while a per-session `currentValue` stays
|
|
1232
|
+
* out of it. No auto-exposure and no staleness discharge either — this is
|
|
1233
|
+
* one session's answer, not the agent-level observation those marks track.
|
|
1234
|
+
*/
|
|
1235
|
+
private absorbCatalogShape;
|
|
1212
1236
|
/**
|
|
1213
1237
|
* Remember the slash commands an agent declared in a real session.
|
|
1214
1238
|
*
|
|
@@ -1229,7 +1253,8 @@ export declare class BridgeManager {
|
|
|
1229
1253
|
* selection would resurrect a model the user deliberately unchecked every
|
|
1230
1254
|
* time the agent repeats its catalog. The first observation has no baseline
|
|
1231
1255
|
* (`before === undefined`), so it adds nothing; the user can still add the
|
|
1232
|
-
* whole list with one click in the settings card.
|
|
1256
|
+
* whole list with one click in the settings card. Discovery is ON unless the
|
|
1257
|
+
* agent definition explicitly opts out with `autoDiscoverModels: false`.
|
|
1233
1258
|
*/
|
|
1234
1259
|
private autoExposeNewModels;
|
|
1235
1260
|
/** Tell the browser an agent's model-visibility surface changed outside `agent/save`. */
|
|
@@ -1382,7 +1407,8 @@ export declare class BridgeManager {
|
|
|
1382
1407
|
* Toggle auto-discovery of newly published models. Lightweight like
|
|
1383
1408
|
* `setExposedModels`: the def is mutated in place (live bridges share the
|
|
1384
1409
|
* object) and persisted; no process is restarted, and the current selection
|
|
1385
|
-
* is left exactly as it is.
|
|
1410
|
+
* is left exactly as it is. On is the default, so only the opt-out
|
|
1411
|
+
* (`false`) is written to the file.
|
|
1386
1412
|
*/
|
|
1387
1413
|
setAutoDiscoverModels(agentId: string, autoDiscoverModels: boolean): Promise<void>;
|
|
1388
1414
|
deleteAgent(agentId: string): Promise<void>;
|
|
@@ -299,6 +299,12 @@ export interface AcpMenuItem {
|
|
|
299
299
|
disabled?: boolean;
|
|
300
300
|
/** Leading status dot color (agent process state). */
|
|
301
301
|
dot?: string;
|
|
302
|
+
/**
|
|
303
|
+
* Render as a checkbox row (`menuitemcheckbox`) rather than a radio row.
|
|
304
|
+
* The advanced base uses it for the agent's boolean config options: one row
|
|
305
|
+
* whose check IS the current value, whose `id` is the value a click sets.
|
|
306
|
+
*/
|
|
307
|
+
checkbox?: boolean;
|
|
302
308
|
}
|
|
303
309
|
/** One titled block of rows. */
|
|
304
310
|
export interface AcpMenuSection {
|
|
@@ -182,6 +182,8 @@ export declare function describeRoute(agents: readonly AgentView[], bound: ChatS
|
|
|
182
182
|
export interface AdvancedOption {
|
|
183
183
|
configId: string;
|
|
184
184
|
name: string;
|
|
185
|
+
/** `'boolean'` for an on/off toggle (`value` is `'true'` / `'false'`, no choices). */
|
|
186
|
+
kind?: 'boolean';
|
|
185
187
|
/** The conversation's pick, else the value the agent reports as current. */
|
|
186
188
|
value?: string;
|
|
187
189
|
choices: readonly {
|
|
@@ -579,7 +579,7 @@ export declare class AcpStore {
|
|
|
579
579
|
/** Switch the bound agent's reasoning effort for one chat session. */
|
|
580
580
|
setChatSessionEffort(dshSessionId: string, effort: string | undefined, agentId?: string): Promise<void>;
|
|
581
581
|
/** Set one of the bound agent's EXTRA config options for one chat session. */
|
|
582
|
-
setChatSessionConfig(dshSessionId: string, configId: string, value: string, agentId?: string): Promise<void>;
|
|
582
|
+
setChatSessionConfig(dshSessionId: string, configId: string, value: string | boolean, agentId?: string): Promise<void>;
|
|
583
583
|
/**
|
|
584
584
|
* Patch one conversation's optimistic pick. The agent half is required by the
|
|
585
585
|
* record (a model or thought level belongs to an agent). Its owner is the
|
package/lib/types/impl.d.ts
CHANGED
|
@@ -145,6 +145,41 @@ export declare function childEnv(parent: NodeJS.ProcessEnv, extra: Record<string
|
|
|
145
145
|
* anything unusable is skipped silently.
|
|
146
146
|
*/
|
|
147
147
|
export declare function parseCatalogOptions(configOptions: unknown): AcpAgentCatalog;
|
|
148
|
+
/**
|
|
149
|
+
* Fold one per-session option answer's SHAPE into an agent-level catalog.
|
|
150
|
+
*
|
|
151
|
+
* `session/set_config_option` answers are often the ONLY place an agent
|
|
152
|
+
* publishes how its option set changes with the model — opencode offers
|
|
153
|
+
* `thought_level` (`effort`) just for models with variants and never
|
|
154
|
+
* re-notifies after a client-driven set — and the composer's thought chip is
|
|
155
|
+
* driven by the agent-level catalog. What is agent knowledge there is the
|
|
156
|
+
* SHAPE (which slots exist, which choices they offer); `currentValue` is not:
|
|
157
|
+
* in a per-session answer it is that session's pick, and promoting it would
|
|
158
|
+
* turn one conversation's choice into `reasoning.defaultEffort` for every
|
|
159
|
+
* other one. A merged slot therefore keeps the catalog's known current value
|
|
160
|
+
* while the observed choices still offer it, and `null` ("the agent's own
|
|
161
|
+
* default") otherwise. Slots the answer does not mention are left alone — a
|
|
162
|
+
* different model may still offer them.
|
|
163
|
+
*/
|
|
164
|
+
export declare function mergeCatalogShape(existing: AcpAgentCatalog | undefined, observed: AcpAgentCatalog): AcpAgentCatalog;
|
|
165
|
+
/**
|
|
166
|
+
* Size ceiling for one `configOptions` answer to be believed. Normal answers
|
|
167
|
+
* are a few KB (a 500-model catalog is well under this); beyond it the agent is
|
|
168
|
+
* misbehaving and absorbing/persisting it would turn every notification into
|
|
169
|
+
* an unbounded write.
|
|
170
|
+
*/
|
|
171
|
+
export declare const MAX_CONFIG_OPTIONS_BYTES: number;
|
|
172
|
+
/**
|
|
173
|
+
* Whether a `configOptions` answer may overwrite known state.
|
|
174
|
+
*
|
|
175
|
+
* An EMPTY (or absent) answer is a non-answer: observed agents return
|
|
176
|
+
* `configOptions: []` in intermediate states, and treating that as "this agent
|
|
177
|
+
* now has no options" would wipe a perfectly good catalog and session
|
|
178
|
+
* snapshot for a state that passes (the rule OmniTerm settles on for the same
|
|
179
|
+
* observation — empty sets never overwrite the last known state). Oversized
|
|
180
|
+
* answers are dropped for the same reason: see {@link MAX_CONFIG_OPTIONS_BYTES}.
|
|
181
|
+
*/
|
|
182
|
+
export declare function usableConfigOptions(configOptions: unknown): configOptions is unknown[];
|
|
148
183
|
/**
|
|
149
184
|
* Split an adapter model id into its agent id and optional model choice.
|
|
150
185
|
* `@` is the separator because agent ids are restricted to `[a-z0-9._-]`.
|
|
@@ -598,7 +633,7 @@ export interface AcpManager {
|
|
|
598
633
|
/** Switch the reasoning effort for one chat session (agentId names the default-agent case). */
|
|
599
634
|
setChatSessionEffort?(dshSessionId: string, effort: string | undefined, agentId?: string): Promise<void>;
|
|
600
635
|
/** Set one of the agent's EXTRA config options for one chat session. */
|
|
601
|
-
setChatSessionConfig?(dshSessionId: string, configId: string, value: string, agentId?: string): Promise<void>;
|
|
636
|
+
setChatSessionConfig?(dshSessionId: string, configId: string, value: string | boolean, agentId?: string): Promise<void>;
|
|
602
637
|
/**
|
|
603
638
|
* State of the ACP-mode agent preset in the harness's OWN roster. Read-only
|
|
604
639
|
* report for the settings panel: the preset is a declaration this package
|
package/lib/types/protocol.d.ts
CHANGED
|
@@ -62,12 +62,13 @@ export interface AcpAgentDef {
|
|
|
62
62
|
*/
|
|
63
63
|
exposedModels?: string[];
|
|
64
64
|
/**
|
|
65
|
-
* Auto-discovery for {@link exposedModels}
|
|
66
|
-
* NEWLY publishes (present in an observed catalog but absent from the
|
|
67
|
-
* known before it) is appended to `exposedModels` automatically. It never
|
|
65
|
+
* Auto-discovery for {@link exposedModels}, ON by default: every model the
|
|
66
|
+
* agent NEWLY publishes (present in an observed catalog but absent from the
|
|
67
|
+
* one known before it) is appended to `exposedModels` automatically. It never
|
|
68
68
|
* touches models the user already had selected, and the very first catalog
|
|
69
|
-
* observation is a baseline (nothing is "new" yet).
|
|
70
|
-
*
|
|
69
|
+
* observation is a baseline (nothing is "new" yet). `false` is the explicit
|
|
70
|
+
* opt-out and the only value persisted; unset means "on". Flipped from the
|
|
71
|
+
* settings card's lightweight `agent/set-auto-discover-models` RPC — never by
|
|
71
72
|
* `agent/save`, which restarts the process for connection changes.
|
|
72
73
|
*/
|
|
73
74
|
autoDiscoverModels?: boolean;
|
|
@@ -566,7 +567,7 @@ export interface ChatEffortSetPayload {
|
|
|
566
567
|
export interface ChatConfigSetPayload {
|
|
567
568
|
dshSessionId: string;
|
|
568
569
|
configId: string;
|
|
569
|
-
value: string;
|
|
570
|
+
value: string | boolean;
|
|
570
571
|
agentId?: string;
|
|
571
572
|
}
|
|
572
573
|
/** Host-detected agent presence and tested defaults. */
|
|
@@ -593,7 +594,7 @@ export interface AgentSavePayload {
|
|
|
593
594
|
allowedCwdRoots?: string[];
|
|
594
595
|
env?: Record<string, string>;
|
|
595
596
|
exposedModels?: string[];
|
|
596
|
-
/**
|
|
597
|
+
/** Opt out of auto-discovery with `false`; absent keeps the default (on). See {@link AcpAgentDef.autoDiscoverModels}. */
|
|
597
598
|
autoDiscoverModels?: boolean;
|
|
598
599
|
/** Absent → keep the host default (30 minutes); `0` = never release. */
|
|
599
600
|
idleTimeoutMs?: number;
|
|
@@ -636,6 +637,12 @@ export interface AcpCatalogChoice {
|
|
|
636
637
|
export interface AcpCatalogOption {
|
|
637
638
|
configId: string;
|
|
638
639
|
name: string;
|
|
640
|
+
/**
|
|
641
|
+
* `'boolean'` for an on/off toggle: `currentValue` is the string `'true'` /
|
|
642
|
+
* `'false'` (the catalog stays string-typed so every existing reader keeps
|
|
643
|
+
* working) and `choices` is empty. Absent means the ordinary select.
|
|
644
|
+
*/
|
|
645
|
+
kind?: 'boolean';
|
|
639
646
|
/** Currently selected value at parse time (may be absent from `choices`). */
|
|
640
647
|
currentValue: string | null;
|
|
641
648
|
choices: AcpCatalogChoice[];
|
|
@@ -713,7 +720,7 @@ export interface AcpConversationChoice {
|
|
|
713
720
|
* accepts, persisted per conversation so a pick survives a restart and is
|
|
714
721
|
* re-applied when its ACP session is recreated or resumed.
|
|
715
722
|
*/
|
|
716
|
-
extraConfigs?: Record<string, string>;
|
|
723
|
+
extraConfigs?: Record<string, string | boolean>;
|
|
717
724
|
}
|
|
718
725
|
/** Result of `agent/probe-models`: the freshly probed (or cached) catalog. */
|
|
719
726
|
export interface AgentProbeModelsResult {
|
|
@@ -726,6 +733,13 @@ export interface AgentCatalogExtraOption {
|
|
|
726
733
|
configId: string;
|
|
727
734
|
/** The agent's own option name (falls back to the config id host-side). */
|
|
728
735
|
name: string;
|
|
736
|
+
/**
|
|
737
|
+
* `'boolean'` for an on/off toggle (`currentValue` is `'true'` / `'false'`,
|
|
738
|
+
* `choices` is empty and the composer renders a checkbox row). Absent means
|
|
739
|
+
* the ordinary select. Kept optional so cached catalogs written before
|
|
740
|
+
* toggles existed still read.
|
|
741
|
+
*/
|
|
742
|
+
kind?: 'boolean';
|
|
729
743
|
/** The value the agent reports as current, when it reports one. */
|
|
730
744
|
currentValue?: string;
|
|
731
745
|
choices: Array<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ntr",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Interactive Agent Client Protocol (ACP) client for the DSH web UI: attach any ACP-capable agent and stream its session.",
|
|
5
5
|
"repository": "https://github.com/GDWhisper/dsh-ntr.git",
|
|
6
6
|
"type": "module",
|