@adhdev/daemon-core 0.8.58 → 0.8.60
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/dist/agent-stream/types.d.ts +3 -4
- package/dist/cli-adapters/provider-cli-adapter.d.ts +3 -0
- package/dist/commands/router.d.ts +1 -0
- package/dist/commands/stream-commands.d.ts +1 -0
- package/dist/config/recent-activity.d.ts +2 -1
- package/dist/config/saved-sessions.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +579 -190
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +579 -190
- package/dist/index.mjs.map +1 -1
- package/dist/providers/acp-provider-instance.d.ts +8 -2
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/dist/providers/contracts.d.ts +3 -2
- package/dist/providers/extension-provider-instance.d.ts +1 -2
- package/dist/providers/provider-instance.d.ts +3 -4
- package/dist/providers/provider-patch-state.d.ts +23 -0
- package/dist/providers/summary-metadata.d.ts +22 -0
- package/dist/shared-types.d.ts +15 -9
- package/dist/status/snapshot.d.ts +16 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/agent-stream/forward.ts +1 -2
- package/src/agent-stream/manager.ts +2 -1
- package/src/agent-stream/provider-adapter.ts +7 -3
- package/src/agent-stream/types.d.ts +3 -4
- package/src/agent-stream/types.ts +3 -4
- package/src/cli-adapters/provider-cli-adapter.ts +26 -9
- package/src/commands/cli-manager.ts +10 -5
- package/src/commands/router.ts +155 -22
- package/src/commands/stream-commands.ts +19 -2
- package/src/config/recent-activity.d.ts +2 -1
- package/src/config/recent-activity.ts +12 -1
- package/src/config/saved-sessions.d.ts +2 -1
- package/src/config/saved-sessions.ts +12 -2
- package/src/daemon/dev-auto-implement.ts +1 -1
- package/src/daemon/dev-cli-debug.ts +0 -1
- package/src/daemon/dev-server.ts +1 -1
- package/src/daemon/scaffold-template.ts +8 -1
- package/src/index.d.ts +1 -1
- package/src/index.ts +2 -0
- package/src/providers/acp-provider-instance.d.ts +8 -2
- package/src/providers/acp-provider-instance.ts +80 -23
- package/src/providers/cli-provider-instance.ts +17 -22
- package/src/providers/contracts.d.ts +3 -2
- package/src/providers/contracts.ts +6 -4
- package/src/providers/control-effects.ts +3 -4
- package/src/providers/extension-provider-instance.d.ts +1 -2
- package/src/providers/extension-provider-instance.ts +26 -14
- package/src/providers/ide-provider-instance.ts +28 -15
- package/src/providers/provider-instance.d.ts +3 -4
- package/src/providers/provider-instance.ts +6 -7
- package/src/providers/provider-patch-state.ts +91 -0
- package/src/providers/summary-metadata.ts +118 -0
- package/src/shared-types.d.ts +15 -9
- package/src/shared-types.ts +17 -9
- package/src/status/builders.ts +18 -13
- package/src/status/reporter.ts +2 -4
- package/src/status/snapshot.ts +60 -2
|
@@ -50,6 +50,7 @@ import type { ProviderModule, ContentBlock, InputEnvelope, InputPart, ToolCallIn
|
|
|
50
50
|
import { normalizeContent, flattenContent, normalizeInputEnvelope } from './contracts.js';
|
|
51
51
|
import type { ProviderInstance, ProviderState, AcpProviderState, ProviderErrorReason, ProviderEvent, InstanceContext } from './provider-instance.js';
|
|
52
52
|
import { StatusMonitor } from './status-monitor.js';
|
|
53
|
+
import { buildLegacyModelModeSummaryMetadata } from './summary-metadata.js';
|
|
53
54
|
import { LOG } from '../logging/logger.js';
|
|
54
55
|
|
|
55
56
|
// ─── Internal Display Types (for dashboard) ────────────────────────────
|
|
@@ -84,6 +85,8 @@ interface AcpMode {
|
|
|
84
85
|
description?: string;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
type SelectionCategory = 'model' | 'mode';
|
|
89
|
+
|
|
87
90
|
interface PromptCapabilityFlags {
|
|
88
91
|
image: boolean;
|
|
89
92
|
audio: boolean;
|
|
@@ -223,8 +226,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
223
226
|
private lastStatus: string = 'starting';
|
|
224
227
|
private generatingStartedAt = 0;
|
|
225
228
|
private agentCapabilities: Record<string, any> = {};
|
|
226
|
-
private
|
|
227
|
-
private currentMode: string | undefined;
|
|
229
|
+
private currentSelections: Partial<Record<SelectionCategory, string>> = {};
|
|
228
230
|
private activeToolCalls: AcpToolCall[] = [];
|
|
229
231
|
private stopReason: string | null = null;
|
|
230
232
|
private partialContent = '';
|
|
@@ -332,8 +334,6 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
332
334
|
inputContent: '',
|
|
333
335
|
},
|
|
334
336
|
workspace: this.workingDir,
|
|
335
|
-
currentModel: this.currentModel,
|
|
336
|
-
currentPlan: this.currentMode,
|
|
337
337
|
instanceId: this.instanceId,
|
|
338
338
|
lastUpdated: Date.now(),
|
|
339
339
|
settings: this.settings,
|
|
@@ -344,11 +344,9 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
344
344
|
// Error details for dashboard display
|
|
345
345
|
errorMessage: this.errorMessage || undefined,
|
|
346
346
|
errorReason: this.errorReason || undefined,
|
|
347
|
-
controlValues:
|
|
348
|
-
...(this.currentModel ? { model: this.currentModel } : {}),
|
|
349
|
-
...(this.currentMode ? { mode: this.currentMode } : {}),
|
|
350
|
-
},
|
|
347
|
+
controlValues: this.getSelectionControlValues(),
|
|
351
348
|
providerControls: this.provider.controls,
|
|
349
|
+
summaryMetadata: this.buildSelectionSummaryMetadata(),
|
|
352
350
|
};
|
|
353
351
|
}
|
|
354
352
|
|
|
@@ -386,6 +384,61 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
386
384
|
return this.instanceId;
|
|
387
385
|
}
|
|
388
386
|
|
|
387
|
+
private resolveConfigOptionLabel(category: string, value: string | undefined): string | undefined {
|
|
388
|
+
if (!value) return undefined;
|
|
389
|
+
const option = this.configOptions.find((entry) => entry.category === category);
|
|
390
|
+
return option?.options.find((candidate) => candidate.value === value)?.name || value;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private resolveModeLabel(modeId: string | undefined): string | undefined {
|
|
394
|
+
if (!modeId) return undefined;
|
|
395
|
+
return this.availableModes.find((mode) => mode.id === modeId)?.name || modeId;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private getCurrentSelection(category: SelectionCategory): string | undefined {
|
|
399
|
+
return this.currentSelections[category];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private setCurrentSelection(category: SelectionCategory, value: string | null | undefined): void {
|
|
403
|
+
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
404
|
+
if (normalized) {
|
|
405
|
+
this.currentSelections[category] = normalized;
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
delete this.currentSelections[category];
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
private getSelectionControlValues(): Record<string, string> {
|
|
412
|
+
const model = this.getCurrentSelection('model');
|
|
413
|
+
const mode = this.getCurrentSelection('mode');
|
|
414
|
+
return {
|
|
415
|
+
...(model ? { model } : {}),
|
|
416
|
+
...(mode ? { mode } : {}),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private resolveSelectionLabel(category: SelectionCategory, value: string | undefined): string | undefined {
|
|
421
|
+
if (!value) return undefined;
|
|
422
|
+
const configLabel = this.resolveConfigOptionLabel(category, value);
|
|
423
|
+
if (configLabel && configLabel !== value) return configLabel;
|
|
424
|
+
if (category === 'mode') {
|
|
425
|
+
const modeLabel = this.resolveModeLabel(value);
|
|
426
|
+
if (modeLabel) return modeLabel;
|
|
427
|
+
}
|
|
428
|
+
return configLabel || value;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
private buildSelectionSummaryMetadata() {
|
|
432
|
+
const model = this.getCurrentSelection('model');
|
|
433
|
+
const mode = this.getCurrentSelection('mode');
|
|
434
|
+
return buildLegacyModelModeSummaryMetadata({
|
|
435
|
+
model,
|
|
436
|
+
mode,
|
|
437
|
+
modelLabel: this.resolveSelectionLabel('model', model),
|
|
438
|
+
modeLabel: this.resolveSelectionLabel('mode', mode),
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
389
442
|
// ─── ACP Config Options & Modes ─────────────────────
|
|
390
443
|
|
|
391
444
|
private parseConfigOptions(raw: any): void {
|
|
@@ -425,15 +478,17 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
425
478
|
|
|
426
479
|
this.configOptions.push({ category: category as 'model' | 'mode' | 'thought_level' | 'other', configId, currentValue, options: flatOptions });
|
|
427
480
|
|
|
428
|
-
// Auto-set
|
|
429
|
-
if (category === 'model'
|
|
481
|
+
// Auto-set current selections from config
|
|
482
|
+
if (category === 'model' || category === 'mode') {
|
|
483
|
+
this.setCurrentSelection(category, currentValue);
|
|
484
|
+
}
|
|
430
485
|
}
|
|
431
486
|
}
|
|
432
487
|
|
|
433
488
|
private parseModes(raw: any): void {
|
|
434
489
|
if (!raw) return;
|
|
435
490
|
// modes: { currentModeId, availableModes: [{ id, name, description }] }
|
|
436
|
-
|
|
491
|
+
this.setCurrentSelection('mode', raw.currentModeId);
|
|
437
492
|
if (Array.isArray(raw.availableModes)) {
|
|
438
493
|
this.availableModes = raw.availableModes.map((m: any) => ({
|
|
439
494
|
id: m.id, name: m.name || m.id, description: m.description,
|
|
@@ -454,8 +509,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
454
509
|
if (this.useStaticConfig) {
|
|
455
510
|
opt.currentValue = value;
|
|
456
511
|
this.selectedConfig[opt.configId] = value;
|
|
457
|
-
if (category === 'model') this.
|
|
458
|
-
if (category === 'mode') this.currentMode = value;
|
|
512
|
+
if (category === 'model' || category === 'mode') this.setCurrentSelection(category, value);
|
|
459
513
|
this.log.info(`[${this.type}] Static config ${category} set to: ${value} — restarting agent`);
|
|
460
514
|
await this.restartWithNewConfig();
|
|
461
515
|
return;
|
|
@@ -476,7 +530,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
476
530
|
});
|
|
477
531
|
// Update local state
|
|
478
532
|
opt.currentValue = value;
|
|
479
|
-
if (category === 'model') this.
|
|
533
|
+
if (category === 'model' || category === 'mode') this.setCurrentSelection(category, value);
|
|
480
534
|
// Response may include updated configOptions
|
|
481
535
|
if (result?.configOptions) this.parseConfigOptions(result.configOptions);
|
|
482
536
|
this.log.info(`[${this.type}] Config ${category} set to: ${value} | response: ${JSON.stringify(result)?.slice(0, 300)}`);
|
|
@@ -495,7 +549,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
495
549
|
opt.currentValue = modeId;
|
|
496
550
|
this.selectedConfig[opt.configId] = modeId;
|
|
497
551
|
}
|
|
498
|
-
this.
|
|
552
|
+
this.setCurrentSelection('mode', modeId);
|
|
499
553
|
this.log.info(`[${this.type}] Static mode set to: ${modeId} — restarting agent`);
|
|
500
554
|
await this.restartWithNewConfig();
|
|
501
555
|
return;
|
|
@@ -512,7 +566,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
512
566
|
sessionId: this.sessionId,
|
|
513
567
|
modeId,
|
|
514
568
|
});
|
|
515
|
-
this.
|
|
569
|
+
this.setCurrentSelection('mode', modeId);
|
|
516
570
|
this.log.info(`[${this.type}] Mode set to: ${modeId}`);
|
|
517
571
|
} catch (e: any) {
|
|
518
572
|
const message = e?.message || 'Unknown ACP mode error';
|
|
@@ -845,8 +899,8 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
845
899
|
this.parseModes(result?.modes);
|
|
846
900
|
|
|
847
901
|
// Legacy: models.currentModelId (some agent compat)
|
|
848
|
-
if (!this.
|
|
849
|
-
this.
|
|
902
|
+
if (!this.getCurrentSelection('model') && result?.models?.currentModelId) {
|
|
903
|
+
this.setCurrentSelection('model', result.models.currentModelId);
|
|
850
904
|
}
|
|
851
905
|
|
|
852
906
|
// ─── Static config fallback (for agents without config/* support) ───
|
|
@@ -862,14 +916,17 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
862
916
|
});
|
|
863
917
|
if (defaultVal) {
|
|
864
918
|
this.selectedConfig[sc.configId] = defaultVal;
|
|
865
|
-
if (sc.category === 'model'
|
|
866
|
-
|
|
919
|
+
if (sc.category === 'model' || sc.category === 'mode') {
|
|
920
|
+
this.setCurrentSelection(sc.category, defaultVal);
|
|
921
|
+
}
|
|
867
922
|
}
|
|
868
923
|
}
|
|
869
924
|
this.log.info(`[${this.type}] Using static configOptions (${this.configOptions.length} options)`);
|
|
870
925
|
}
|
|
871
926
|
|
|
872
|
-
|
|
927
|
+
const currentModel = this.getCurrentSelection('model');
|
|
928
|
+
const currentMode = this.getCurrentSelection('mode');
|
|
929
|
+
this.log.info(`[${this.type}] Session created: ${this.sessionId}${currentModel ? ` (model: ${currentModel})` : ''}${currentMode ? ` (mode: ${currentMode})` : ''}`);
|
|
873
930
|
if (this.configOptions.length > 0) {
|
|
874
931
|
this.log.info(`[${this.type}] Config options: ${this.configOptions.map(c => `${c.category}(${c.options.length})`).join(', ')}`);
|
|
875
932
|
}
|
|
@@ -1073,7 +1130,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
1073
1130
|
break;
|
|
1074
1131
|
}
|
|
1075
1132
|
case 'current_mode_update': {
|
|
1076
|
-
this.
|
|
1133
|
+
this.setCurrentSelection('mode', update.currentModeId);
|
|
1077
1134
|
break;
|
|
1078
1135
|
}
|
|
1079
1136
|
case 'config_option_update': {
|
|
@@ -1162,7 +1219,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
1162
1219
|
|
|
1163
1220
|
// Legacy: model info
|
|
1164
1221
|
if (params.model) {
|
|
1165
|
-
this.
|
|
1222
|
+
this.setCurrentSelection('model', params.model);
|
|
1166
1223
|
}
|
|
1167
1224
|
}
|
|
1168
1225
|
|
|
@@ -19,9 +19,10 @@ import { StatusMonitor } from './status-monitor.js';
|
|
|
19
19
|
import { ChatHistoryWriter, readChatHistory } from '../config/chat-history.js';
|
|
20
20
|
import { LOG } from '../logging/logger.js';
|
|
21
21
|
import type { ChatMessage } from '../types.js';
|
|
22
|
-
import {
|
|
22
|
+
import { normalizeProviderEffects } from './control-effects.js';
|
|
23
23
|
import { formatAutoApprovalMessage, pickApprovalButton } from './approval-utils.js';
|
|
24
24
|
import { getCliScriptCommand, parseCliScriptResult } from './cli-script-results.js';
|
|
25
|
+
import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
|
|
25
26
|
|
|
26
27
|
let CachedDatabaseSync: (new (path: string, options?: { readOnly?: boolean }) => {
|
|
27
28
|
prepare(sql: string): { get(...params: Array<string | number>): unknown };
|
|
@@ -104,6 +105,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
104
105
|
private generatingDebouncePending: { chatTitle: string; timestamp: number } | null = null;
|
|
105
106
|
private lastApprovalEventAt = 0;
|
|
106
107
|
private controlValues: Record<string, string | number | boolean> = {};
|
|
108
|
+
private summaryMetadata: unknown = undefined;
|
|
107
109
|
private appliedEffectKeys = new Set<string>();
|
|
108
110
|
private historyWriter: ChatHistoryWriter;
|
|
109
111
|
private runtimeMessages: Array<{ key: string; message: ChatMessage }> = [];
|
|
@@ -317,21 +319,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
317
319
|
? parsedMessages.slice(-historyMessageCount)
|
|
318
320
|
: [];
|
|
319
321
|
}
|
|
320
|
-
const controlValues = extractProviderControlValues(this.provider.controls, parsedStatus);
|
|
321
|
-
if (controlValues) {
|
|
322
|
-
this.controlValues = { ...this.controlValues, ...controlValues };
|
|
323
|
-
}
|
|
324
322
|
const mergedMessages = this.mergeConversationMessages(parsedMessages);
|
|
325
|
-
const currentModel = typeof parsedStatus?.model === 'string' && parsedStatus.model.trim()
|
|
326
|
-
? parsedStatus.model.trim()
|
|
327
|
-
: (typeof this.controlValues.model === 'string' && this.controlValues.model.trim()
|
|
328
|
-
? this.controlValues.model.trim()
|
|
329
|
-
: undefined);
|
|
330
|
-
const currentPlan = typeof parsedStatus?.mode === 'string' && parsedStatus.mode.trim()
|
|
331
|
-
? parsedStatus.mode.trim()
|
|
332
|
-
: (typeof this.controlValues.mode === 'string' && this.controlValues.mode.trim()
|
|
333
|
-
? this.controlValues.mode.trim()
|
|
334
|
-
: undefined);
|
|
335
323
|
|
|
336
324
|
const dirName = this.workingDir.split('/').filter(Boolean).pop() || 'session';
|
|
337
325
|
|
|
@@ -359,6 +347,10 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
359
347
|
}
|
|
360
348
|
|
|
361
349
|
this.applyProviderResponse(parsedStatus, { phase: 'immediate' });
|
|
350
|
+
const surface = resolveProviderStateSurface({
|
|
351
|
+
summaryMetadata: this.summaryMetadata as any,
|
|
352
|
+
controlValues: this.controlValues,
|
|
353
|
+
});
|
|
362
354
|
|
|
363
355
|
return {
|
|
364
356
|
type: this.type,
|
|
@@ -377,8 +369,6 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
377
369
|
inputContent: '',
|
|
378
370
|
},
|
|
379
371
|
workspace: this.workingDir,
|
|
380
|
-
currentModel,
|
|
381
|
-
currentPlan,
|
|
382
372
|
instanceId: this.instanceId,
|
|
383
373
|
providerSessionId: this.providerSessionId,
|
|
384
374
|
lastUpdated: Date.now(),
|
|
@@ -393,8 +383,9 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
393
383
|
attachedClients: runtime.attachedClients || [],
|
|
394
384
|
} : undefined,
|
|
395
385
|
resume: this.provider.resume,
|
|
396
|
-
controlValues:
|
|
386
|
+
controlValues: surface.controlValues,
|
|
397
387
|
providerControls: this.provider.controls,
|
|
388
|
+
summaryMetadata: surface.summaryMetadata as any,
|
|
398
389
|
};
|
|
399
390
|
}
|
|
400
391
|
|
|
@@ -617,10 +608,14 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
617
608
|
this.adapter.clearHistory();
|
|
618
609
|
}
|
|
619
610
|
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
611
|
+
const patchedState = mergeProviderPatchState({
|
|
612
|
+
providerControls: this.provider.controls,
|
|
613
|
+
data,
|
|
614
|
+
currentControlValues: this.controlValues,
|
|
615
|
+
currentSummaryMetadata: this.summaryMetadata,
|
|
616
|
+
});
|
|
617
|
+
this.controlValues = patchedState.controlValues;
|
|
618
|
+
this.summaryMetadata = patchedState.summaryMetadata;
|
|
624
619
|
|
|
625
620
|
const effects = normalizeProviderEffects(data);
|
|
626
621
|
for (const effect of effects) {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* - Common across all categories (cli, ide, extension)
|
|
7
7
|
* - User custom providers use the same contracts
|
|
8
8
|
*/
|
|
9
|
+
import type { ProviderSummaryMetadata } from '../shared-types.js';
|
|
9
10
|
export interface ReadChatResult {
|
|
10
11
|
messages: ChatMessage[];
|
|
11
12
|
status: AgentStatus;
|
|
@@ -21,10 +22,10 @@ export interface ReadChatResult {
|
|
|
21
22
|
isVisible?: boolean;
|
|
22
23
|
isWelcomeScreen?: boolean;
|
|
23
24
|
inputContent?: string;
|
|
24
|
-
model?: string;
|
|
25
|
-
autoApprove?: string;
|
|
26
25
|
/** Explicit dynamic control values returned by the provider */
|
|
27
26
|
controlValues?: Record<string, string | number | boolean>;
|
|
27
|
+
/** Flexible always-visible metadata for compact/live surfaces. */
|
|
28
|
+
summaryMetadata?: ProviderSummaryMetadata;
|
|
28
29
|
/** Provider-driven UI effects derived from chat state */
|
|
29
30
|
effects?: ProviderEffect[];
|
|
30
31
|
}
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
// ─── readChat() return value ───────────────────────────
|
|
11
11
|
|
|
12
|
+
import type { ProviderSummaryMetadata } from '../shared-types.js';
|
|
13
|
+
|
|
12
14
|
export interface ReadChatResult {
|
|
13
15
|
messages: ChatMessage[];
|
|
14
16
|
status: AgentStatus;
|
|
@@ -20,15 +22,15 @@ export interface ReadChatResult {
|
|
|
20
22
|
agentType?: string;
|
|
21
23
|
agentName?: string;
|
|
22
24
|
extensionId?: string;
|
|
23
|
-
|
|
25
|
+
/** Status metadata */
|
|
24
26
|
isVisible?: boolean;
|
|
25
27
|
isWelcomeScreen?: boolean;
|
|
26
28
|
inputContent?: string;
|
|
27
|
-
model?: string;
|
|
28
|
-
autoApprove?: string;
|
|
29
29
|
/** Explicit dynamic control values returned by the provider */
|
|
30
30
|
controlValues?: Record<string, string | number | boolean>;
|
|
31
|
-
/**
|
|
31
|
+
/** Flexible always-visible metadata for compact/live surfaces. */
|
|
32
|
+
summaryMetadata?: ProviderSummaryMetadata;
|
|
33
|
+
/** Provider-driven UI effects derived from chat state */
|
|
32
34
|
effects?: ProviderEffect[];
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -32,9 +32,6 @@ export function extractProviderControlValues(
|
|
|
32
32
|
values[ctrl.id] = normalizeControlValue(rawValue);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
if (data.model !== undefined && values.model === undefined) values.model = normalizeControlValue(data.model);
|
|
36
|
-
if (data.mode !== undefined && values.mode === undefined) values.mode = normalizeControlValue(data.mode);
|
|
37
|
-
|
|
38
35
|
return Object.keys(values).length > 0 ? values : undefined;
|
|
39
36
|
}
|
|
40
37
|
|
|
@@ -171,7 +168,9 @@ function normalizeControlOption(option: unknown): ProviderControlOption | null {
|
|
|
171
168
|
const record = option as Record<string, unknown>;
|
|
172
169
|
const value = typeof record.value === 'string'
|
|
173
170
|
? record.value
|
|
174
|
-
: (typeof record.id === 'string'
|
|
171
|
+
: (typeof record.id === 'string'
|
|
172
|
+
? record.id
|
|
173
|
+
: (typeof record.name === 'string' ? record.name : null));
|
|
175
174
|
if (!value) return null;
|
|
176
175
|
const label = typeof record.label === 'string'
|
|
177
176
|
? record.label
|
|
@@ -18,9 +18,8 @@ export declare class ExtensionProviderInstance implements ProviderInstance {
|
|
|
18
18
|
private messages;
|
|
19
19
|
private prevMessageHashes;
|
|
20
20
|
private activeModal;
|
|
21
|
-
private currentModel;
|
|
22
|
-
private currentMode;
|
|
23
21
|
private controlValues;
|
|
22
|
+
private summaryMetadata;
|
|
24
23
|
private appliedEffectKeys;
|
|
25
24
|
private runtimeMessages;
|
|
26
25
|
private lastAgentStatus;
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
import type { ProviderModule } from './contracts.js';
|
|
9
9
|
import type { ProviderInstance, ProviderState, ProviderEvent, InstanceContext } from './provider-instance.js';
|
|
10
10
|
import { StatusMonitor } from './status-monitor.js';
|
|
11
|
-
import {
|
|
11
|
+
import { normalizeProviderEffects } from './control-effects.js';
|
|
12
12
|
import { ChatHistoryWriter } from '../config/chat-history.js';
|
|
13
13
|
import type { ChatMessage } from '../types.js';
|
|
14
|
+
import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
|
|
14
15
|
|
|
15
16
|
export class ExtensionProviderInstance implements ProviderInstance {
|
|
16
17
|
readonly type: string;
|
|
@@ -27,9 +28,8 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
27
28
|
private messages: any[] = [];
|
|
28
29
|
private prevMessageHashes = new Map<string, number>();
|
|
29
30
|
private activeModal: any = null;
|
|
30
|
-
private currentModel: string = '';
|
|
31
|
-
private currentMode: string = '';
|
|
32
31
|
private controlValues: Record<string, string | number | boolean> = {};
|
|
32
|
+
private summaryMetadata: unknown = undefined;
|
|
33
33
|
private appliedEffectKeys = new Set<string>();
|
|
34
34
|
private runtimeMessages: Array<{ key: string; message: ChatMessage }> = [];
|
|
35
35
|
private lastAgentStatus: string = 'idle';
|
|
@@ -76,6 +76,11 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
getState(): ProviderState {
|
|
79
|
+
const surface = resolveProviderStateSurface({
|
|
80
|
+
summaryMetadata: this.summaryMetadata as any,
|
|
81
|
+
controlValues: this.controlValues,
|
|
82
|
+
})
|
|
83
|
+
|
|
79
84
|
return {
|
|
80
85
|
type: this.type,
|
|
81
86
|
name: this.provider.name,
|
|
@@ -89,10 +94,9 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
89
94
|
activeModal: this.activeModal,
|
|
90
95
|
inputContent: '',
|
|
91
96
|
} : null,
|
|
92
|
-
|
|
93
|
-
currentPlan: this.currentMode || undefined,
|
|
94
|
-
controlValues: this.controlValues,
|
|
97
|
+
controlValues: surface.controlValues,
|
|
95
98
|
providerControls: this.provider.controls,
|
|
99
|
+
summaryMetadata: surface.summaryMetadata as any,
|
|
96
100
|
agentStreams: this.agentStreams,
|
|
97
101
|
instanceId: this.instanceId,
|
|
98
102
|
lastUpdated: Date.now(),
|
|
@@ -107,10 +111,14 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
107
111
|
if (data?.streams) this.agentStreams = data.streams;
|
|
108
112
|
if (data?.messages) this.messages = this.assignReceivedAt(data.messages);
|
|
109
113
|
if (data?.activeModal !== undefined) this.activeModal = data.activeModal;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
const patchedState = mergeProviderPatchState({
|
|
115
|
+
providerControls: this.provider.controls,
|
|
116
|
+
data,
|
|
117
|
+
currentControlValues: this.controlValues,
|
|
118
|
+
currentSummaryMetadata: this.summaryMetadata,
|
|
119
|
+
});
|
|
120
|
+
this.controlValues = patchedState.controlValues;
|
|
121
|
+
this.summaryMetadata = patchedState.summaryMetadata;
|
|
114
122
|
if (typeof data?.sessionId === 'string' && data.sessionId.trim()) this.chatId = data.sessionId;
|
|
115
123
|
if (typeof data?.title === 'string' && data.title.trim()) this.chatTitle = data.title;
|
|
116
124
|
if (typeof data?.agentName === 'string' && data.agentName.trim()) this.agentName = data.agentName;
|
|
@@ -231,8 +239,14 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
231
239
|
private applyProviderResponse(data: any, options: { phase: 'immediate' | 'turn_completed' }): void {
|
|
232
240
|
if (!data || typeof data !== 'object') return;
|
|
233
241
|
|
|
234
|
-
const
|
|
235
|
-
|
|
242
|
+
const patchedState = mergeProviderPatchState({
|
|
243
|
+
providerControls: this.provider.controls,
|
|
244
|
+
data,
|
|
245
|
+
currentControlValues: this.controlValues,
|
|
246
|
+
currentSummaryMetadata: this.summaryMetadata,
|
|
247
|
+
});
|
|
248
|
+
this.controlValues = patchedState.controlValues;
|
|
249
|
+
this.summaryMetadata = patchedState.summaryMetadata;
|
|
236
250
|
|
|
237
251
|
const effects = normalizeProviderEffects(data);
|
|
238
252
|
for (const effect of effects) {
|
|
@@ -406,8 +420,6 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
406
420
|
this.messages = [];
|
|
407
421
|
this.prevMessageHashes.clear();
|
|
408
422
|
this.activeModal = null;
|
|
409
|
-
this.currentModel = '';
|
|
410
|
-
this.currentMode = '';
|
|
411
423
|
this.controlValues = {};
|
|
412
424
|
this.currentStatus = 'idle';
|
|
413
425
|
this.chatId = null;
|
|
@@ -17,9 +17,10 @@ import { ExtensionProviderInstance } from './extension-provider-instance.js';
|
|
|
17
17
|
import { StatusMonitor } from './status-monitor.js';
|
|
18
18
|
import { ChatHistoryWriter } from '../config/chat-history.js';
|
|
19
19
|
import { LOG } from '../logging/logger.js';
|
|
20
|
-
import {
|
|
20
|
+
import { normalizeProviderEffects } from './control-effects.js';
|
|
21
21
|
import type { ChatMessage } from '../types.js';
|
|
22
22
|
import { formatAutoApprovalMessage, pickApprovalButton } from './approval-utils.js';
|
|
23
|
+
import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
|
|
23
24
|
|
|
24
25
|
type ReadChatModal = {
|
|
25
26
|
message?: string;
|
|
@@ -134,6 +135,11 @@ export class IdeProviderInstance implements ProviderInstance {
|
|
|
134
135
|
extensionStates.push(ext.getState());
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
const surface = resolveProviderStateSurface({
|
|
139
|
+
summaryMetadata: this.cachedChat?.summaryMetadata,
|
|
140
|
+
controlValues: this.cachedChat?.controlValues,
|
|
141
|
+
});
|
|
142
|
+
|
|
137
143
|
return {
|
|
138
144
|
type: this.type,
|
|
139
145
|
name: this.provider.name,
|
|
@@ -152,11 +158,9 @@ export class IdeProviderInstance implements ProviderInstance {
|
|
|
152
158
|
workspace: this.workspace || null,
|
|
153
159
|
extensions: extensionStates,
|
|
154
160
|
cdpConnected: cdp?.isConnected || false,
|
|
155
|
-
|
|
156
|
-
currentPlan: this.cachedChat?.mode || undefined,
|
|
157
|
-
currentAutoApprove: this.cachedChat?.autoApprove || undefined,
|
|
158
|
-
controlValues: this.cachedChat?.controlValues || undefined,
|
|
161
|
+
controlValues: surface.controlValues,
|
|
159
162
|
providerControls: this.provider.controls,
|
|
163
|
+
summaryMetadata: surface.summaryMetadata as any,
|
|
160
164
|
instanceId: this.instanceId,
|
|
161
165
|
lastUpdated: Date.now(),
|
|
162
166
|
settings: this.settings,
|
|
@@ -348,8 +352,13 @@ export class IdeProviderInstance implements ProviderInstance {
|
|
|
348
352
|
}
|
|
349
353
|
}
|
|
350
354
|
|
|
351
|
-
const
|
|
352
|
-
|
|
355
|
+
const patchedState = mergeProviderPatchState({
|
|
356
|
+
providerControls: this.provider.controls,
|
|
357
|
+
data: chat,
|
|
358
|
+
mergeWithCurrent: false,
|
|
359
|
+
});
|
|
360
|
+
chat.controlValues = Object.keys(patchedState.controlValues).length > 0 ? patchedState.controlValues : undefined;
|
|
361
|
+
chat.summaryMetadata = patchedState.summaryMetadata;
|
|
353
362
|
|
|
354
363
|
this.cachedChat = { ...chat, activeModal };
|
|
355
364
|
this.detectAgentTransitions(chat, now);
|
|
@@ -464,14 +473,18 @@ export class IdeProviderInstance implements ProviderInstance {
|
|
|
464
473
|
private applyProviderResponse(data: any, options: { phase: 'immediate' | 'turn_completed' }): void {
|
|
465
474
|
if (!data || typeof data !== 'object') return;
|
|
466
475
|
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
476
|
+
const patchedState = mergeProviderPatchState({
|
|
477
|
+
providerControls: this.provider.controls,
|
|
478
|
+
data,
|
|
479
|
+
currentControlValues: this.cachedChat?.controlValues,
|
|
480
|
+
currentSummaryMetadata: this.cachedChat?.summaryMetadata,
|
|
481
|
+
});
|
|
482
|
+
this.cachedChat = {
|
|
483
|
+
...(this.cachedChat || {}),
|
|
484
|
+
...data,
|
|
485
|
+
controlValues: Object.keys(patchedState.controlValues).length > 0 ? patchedState.controlValues : undefined,
|
|
486
|
+
summaryMetadata: patchedState.summaryMetadata,
|
|
487
|
+
};
|
|
475
488
|
|
|
476
489
|
const effects = normalizeProviderEffects(data);
|
|
477
490
|
for (const effect of effects) {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Each Instance manages its own status.
|
|
9
9
|
*/
|
|
10
10
|
import type { ProviderResumeCapability } from './contracts.js';
|
|
11
|
-
import type { AcpConfigOption, AcpMode, ProviderControlSchema } from '../shared-types.js';
|
|
11
|
+
import type { AcpConfigOption, AcpMode, ProviderControlSchema, ProviderSummaryMetadata } from '../shared-types.js';
|
|
12
12
|
import type { ChatMessage } from '../types.js';
|
|
13
13
|
export type ProviderStatus = 'idle' | 'generating' | 'waiting_approval' | 'error' | 'stopped' | 'starting';
|
|
14
14
|
export interface ProviderRuntimeWriteOwner {
|
|
@@ -54,8 +54,6 @@ interface ProviderStateBase {
|
|
|
54
54
|
/** Workspace — project path or name (all categories) */
|
|
55
55
|
workspace?: string | null;
|
|
56
56
|
/** Runtime info (real-time detection) */
|
|
57
|
-
currentModel?: string;
|
|
58
|
-
currentPlan?: string;
|
|
59
57
|
/** Error details (when status === 'error') */
|
|
60
58
|
errorMessage?: string;
|
|
61
59
|
errorReason?: ProviderErrorReason;
|
|
@@ -72,6 +70,8 @@ interface ProviderStateBase {
|
|
|
72
70
|
controlValues?: Record<string, string | number | boolean>;
|
|
73
71
|
/** Provider-declared controls schema (from provider.controls) */
|
|
74
72
|
providerControls?: ProviderControlSchema[];
|
|
73
|
+
/** Flexible always-visible metadata for compact/live surfaces. */
|
|
74
|
+
summaryMetadata?: ProviderSummaryMetadata;
|
|
75
75
|
}
|
|
76
76
|
/** IDE provider state */
|
|
77
77
|
export interface IdeProviderState extends ProviderStateBase {
|
|
@@ -79,7 +79,6 @@ export interface IdeProviderState extends ProviderStateBase {
|
|
|
79
79
|
cdpConnected: boolean;
|
|
80
80
|
/** IDE child Extension Instance status */
|
|
81
81
|
extensions: ProviderState[];
|
|
82
|
-
currentAutoApprove?: string;
|
|
83
82
|
}
|
|
84
83
|
/** CLI provider state */
|
|
85
84
|
export interface CliProviderState extends ProviderStateBase {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import type { ProviderModule, ProviderSettingDef, ProviderResumeCapability } from './contracts.js';
|
|
12
|
-
import type { AcpConfigOption, AcpMode, ProviderControlSchema } from '../shared-types.js';
|
|
12
|
+
import type { AcpConfigOption, AcpMode, ProviderControlSchema, ProviderSummaryMetadata } from '../shared-types.js';
|
|
13
13
|
import type { ChatMessage } from '../types.js';
|
|
14
14
|
|
|
15
15
|
// ─── ProviderState — Discriminated union by category ─────────────
|
|
@@ -68,10 +68,8 @@ interface ProviderStateBase {
|
|
|
68
68
|
activeChat: ActiveChatData | null;
|
|
69
69
|
/** Workspace — project path or name (all categories) */
|
|
70
70
|
workspace?: string | null;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
currentPlan?: string;
|
|
74
|
-
/** Error details (when status === 'error') */
|
|
71
|
+
/** Runtime info (real-time detection) */
|
|
72
|
+
/** Error details (when status === 'error') */
|
|
75
73
|
errorMessage?: string;
|
|
76
74
|
errorReason?: ProviderErrorReason;
|
|
77
75
|
/** meta */
|
|
@@ -85,8 +83,10 @@ interface ProviderStateBase {
|
|
|
85
83
|
resume?: ProviderResumeCapability;
|
|
86
84
|
/** Dynamic control current values */
|
|
87
85
|
controlValues?: Record<string, string | number | boolean>;
|
|
88
|
-
|
|
86
|
+
/** Provider-declared controls schema (from provider.controls) */
|
|
89
87
|
providerControls?: ProviderControlSchema[];
|
|
88
|
+
/** Flexible always-visible metadata for compact/live surfaces. */
|
|
89
|
+
summaryMetadata?: ProviderSummaryMetadata;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/** IDE provider state */
|
|
@@ -95,7 +95,6 @@ export interface IdeProviderState extends ProviderStateBase {
|
|
|
95
95
|
cdpConnected: boolean;
|
|
96
96
|
/** IDE child Extension Instance status */
|
|
97
97
|
extensions: ProviderState[];
|
|
98
|
-
currentAutoApprove?: string;
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
/** CLI provider state */
|