@adhdev/daemon-core 0.8.60 → 0.8.62
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/cli-adapters/provider-cli-adapter.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +5 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +521 -343
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +511 -343
- package/dist/index.mjs.map +1 -1
- package/dist/providers/chat-message-normalization.d.ts +43 -0
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/dist/providers/contracts.d.ts +5 -1
- package/dist/providers/control-effects.d.ts +2 -0
- package/dist/providers/extension-provider-instance.d.ts +2 -1
- package/dist/providers/ide-provider-instance.d.ts +2 -1
- package/dist/types.d.ts +2 -1
- package/node_modules/@adhdev/session-host-core/package.json +2 -2
- package/package.json +2 -2
- package/src/agent-stream/poller.ts +3 -5
- package/src/cli-adapters/provider-cli-adapter.ts +32 -10
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +3 -0
- package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.ts +5 -2
- package/src/commands/chat-commands.ts +2 -1
- package/src/config/chat-history.ts +6 -5
- package/src/index.ts +13 -0
- package/src/providers/acp-provider-instance.ts +19 -24
- package/src/providers/chat-message-normalization.ts +68 -0
- package/src/providers/cli-provider-instance.ts +42 -29
- package/src/providers/contracts.ts +5 -1
- package/src/providers/control-effects.ts +72 -0
- package/src/providers/extension-provider-instance.ts +43 -31
- package/src/providers/ide-provider-instance.ts +42 -30
- package/src/types.ts +2 -1
|
@@ -10,7 +10,7 @@ import * as path from 'path';
|
|
|
10
10
|
import * as crypto from 'crypto';
|
|
11
11
|
import * as fs from 'fs';
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
|
-
import { normalizeInputEnvelope, type ProviderModule } from './contracts.js';
|
|
13
|
+
import { normalizeInputEnvelope, type ProviderModule, flattenContent } from './contracts.js';
|
|
14
14
|
import type { ProviderInstance, ProviderState, ProviderEvent, InstanceContext } from './provider-instance.js';
|
|
15
15
|
import { ProviderCliAdapter } from '../cli-adapters/provider-cli-adapter.js';
|
|
16
16
|
import type { CliProviderModule } from '../cli-adapters/provider-cli-adapter.js';
|
|
@@ -19,10 +19,11 @@ 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 { normalizeProviderEffects } from './control-effects.js';
|
|
22
|
+
import { buildPersistedProviderEffectMessage, 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
25
|
import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
|
|
26
|
+
import { buildChatMessage, buildRuntimeSystemChatMessage, normalizeChatMessages } from './chat-message-normalization.js';
|
|
26
27
|
|
|
27
28
|
let CachedDatabaseSync: (new (path: string, options?: { readOnly?: boolean }) => {
|
|
28
29
|
prepare(sql: string): { get(...params: Array<string | number>): unknown };
|
|
@@ -628,8 +629,8 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
628
629
|
this.appliedEffectKeys.add(effectKey);
|
|
629
630
|
|
|
630
631
|
if (effect.persist !== false) {
|
|
631
|
-
const
|
|
632
|
-
if (
|
|
632
|
+
const persistedMessage = buildPersistedProviderEffectMessage(effect);
|
|
633
|
+
if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
|
|
633
634
|
}
|
|
634
635
|
|
|
635
636
|
if (effect.type === 'message' && effect.message) {
|
|
@@ -772,43 +773,55 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
772
773
|
}
|
|
773
774
|
|
|
774
775
|
private appendRuntimeSystemMessage(content: string, dedupKey: string, receivedAt = Date.now()): void {
|
|
775
|
-
|
|
776
|
-
|
|
776
|
+
this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
|
|
777
|
+
content,
|
|
778
|
+
receivedAt,
|
|
779
|
+
timestamp: receivedAt,
|
|
780
|
+
}), dedupKey);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
private appendRuntimeMessage(message: ChatMessage, dedupKey: string): void {
|
|
784
|
+
const normalizedMessage = buildChatMessage({
|
|
785
|
+
...message,
|
|
786
|
+
receivedAt: typeof message.receivedAt === 'number' ? message.receivedAt : (message.timestamp || Date.now()),
|
|
787
|
+
timestamp: typeof message.timestamp === 'number' ? message.timestamp : (message.receivedAt || Date.now()),
|
|
788
|
+
} as ChatMessage);
|
|
789
|
+
const normalizedContent = typeof normalizedMessage.content === 'string'
|
|
790
|
+
? normalizedMessage.content.trim()
|
|
791
|
+
: flattenContent(normalizedMessage.content).trim();
|
|
792
|
+
if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
|
|
777
793
|
if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
|
|
778
794
|
|
|
779
795
|
this.runtimeMessages.push({
|
|
780
796
|
key: dedupKey,
|
|
781
|
-
message:
|
|
782
|
-
role: 'system',
|
|
783
|
-
senderName: 'System',
|
|
784
|
-
content: normalizedContent,
|
|
785
|
-
receivedAt,
|
|
786
|
-
timestamp: receivedAt,
|
|
787
|
-
},
|
|
797
|
+
message: normalizedMessage,
|
|
788
798
|
});
|
|
789
799
|
if (this.runtimeMessages.length > 50) {
|
|
790
800
|
this.runtimeMessages = this.runtimeMessages.slice(-50);
|
|
791
801
|
}
|
|
792
802
|
|
|
793
|
-
|
|
794
|
-
this.
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
803
|
+
if (normalizedContent) {
|
|
804
|
+
this.historyWriter.appendNewMessages(
|
|
805
|
+
this.type,
|
|
806
|
+
[{
|
|
807
|
+
role: normalizedMessage.role,
|
|
808
|
+
senderName: normalizedMessage.senderName,
|
|
809
|
+
kind: normalizedMessage.kind,
|
|
810
|
+
content: normalizedContent,
|
|
811
|
+
receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
|
|
812
|
+
historyDedupKey: dedupKey,
|
|
813
|
+
}],
|
|
814
|
+
this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split('/').filter(Boolean).pop() || 'session',
|
|
815
|
+
this.instanceId,
|
|
816
|
+
this.providerSessionId,
|
|
817
|
+
);
|
|
818
|
+
}
|
|
806
819
|
}
|
|
807
820
|
|
|
808
821
|
private mergeConversationMessages(parsedMessages: any[]): ChatMessage[] {
|
|
809
|
-
if (this.runtimeMessages.length === 0) return parsedMessages;
|
|
822
|
+
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
810
823
|
|
|
811
|
-
return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)]
|
|
824
|
+
return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)]
|
|
812
825
|
.map((message, index) => ({ message, index }))
|
|
813
826
|
.sort((a, b) => {
|
|
814
827
|
const aTime = a.message.receivedAt || a.message.timestamp || 0;
|
|
@@ -816,7 +829,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
816
829
|
if (aTime !== bTime) return aTime - bTime;
|
|
817
830
|
return a.index - b.index;
|
|
818
831
|
})
|
|
819
|
-
.map((entry) => entry.message);
|
|
832
|
+
.map((entry) => entry.message));
|
|
820
833
|
}
|
|
821
834
|
|
|
822
835
|
private formatApprovalRequestMessage(modalMessage?: string, buttons?: string[]): string {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// ─── readChat() return value ───────────────────────────
|
|
11
11
|
|
|
12
12
|
import type { ProviderSummaryMetadata } from '../shared-types.js';
|
|
13
|
+
import type { ChatMessageKind } from './chat-message-normalization.js';
|
|
13
14
|
|
|
14
15
|
export interface ReadChatResult {
|
|
15
16
|
messages: ChatMessage[];
|
|
@@ -70,7 +71,7 @@ export interface ModalInfo {
|
|
|
70
71
|
export interface ProviderEffectMessage {
|
|
71
72
|
role?: 'system' | 'assistant' | 'user';
|
|
72
73
|
content: string | MessagePart[];
|
|
73
|
-
kind?:
|
|
74
|
+
kind?: ChatMessageKind;
|
|
74
75
|
senderName?: string;
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -89,6 +90,9 @@ export interface ProviderEffectNotification {
|
|
|
89
90
|
channels?: ProviderNotificationChannel[];
|
|
90
91
|
preferenceKey?: ProviderNotificationPreferenceKey;
|
|
91
92
|
bubbleContent?: string | MessagePart[];
|
|
93
|
+
bubbleKind?: ChatMessageKind;
|
|
94
|
+
bubbleRole?: 'system' | 'assistant' | 'user';
|
|
95
|
+
bubbleSenderName?: string;
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
export interface ProviderEffect {
|
|
@@ -6,6 +6,9 @@ import type {
|
|
|
6
6
|
ProviderControlOption,
|
|
7
7
|
ProviderEffect,
|
|
8
8
|
} from './contracts.js';
|
|
9
|
+
import { flattenContent } from './contracts.js';
|
|
10
|
+
import type { ChatMessage } from '../types.js';
|
|
11
|
+
import { buildChatMessage, buildRuntimeSystemChatMessage } from './chat-message-normalization.js';
|
|
9
12
|
|
|
10
13
|
export type ProviderControlValue = string | number | boolean;
|
|
11
14
|
|
|
@@ -97,6 +100,15 @@ export function normalizeProviderEffects(data: any): ProviderEffect[] {
|
|
|
97
100
|
bubbleContent: typeof raw.notification.bubbleContent === 'string' || Array.isArray(raw.notification.bubbleContent)
|
|
98
101
|
? raw.notification.bubbleContent
|
|
99
102
|
: undefined,
|
|
103
|
+
bubbleKind: typeof raw.notification.bubbleKind === 'string'
|
|
104
|
+
? raw.notification.bubbleKind
|
|
105
|
+
: undefined,
|
|
106
|
+
bubbleRole: raw.notification.bubbleRole === 'assistant' || raw.notification.bubbleRole === 'user'
|
|
107
|
+
? raw.notification.bubbleRole
|
|
108
|
+
: (raw.notification.bubbleRole === 'system' ? 'system' : undefined),
|
|
109
|
+
bubbleSenderName: typeof raw.notification.bubbleSenderName === 'string'
|
|
110
|
+
? raw.notification.bubbleSenderName
|
|
111
|
+
: undefined,
|
|
100
112
|
},
|
|
101
113
|
});
|
|
102
114
|
}
|
|
@@ -105,6 +117,59 @@ export function normalizeProviderEffects(data: any): ProviderEffect[] {
|
|
|
105
117
|
return effects;
|
|
106
118
|
}
|
|
107
119
|
|
|
120
|
+
export function buildPersistedProviderEffectMessage(effect: ProviderEffect | null | undefined): ChatMessage | null {
|
|
121
|
+
if (!effect) return null;
|
|
122
|
+
|
|
123
|
+
if (effect.type === 'message' && effect.message) {
|
|
124
|
+
const role = effect.message.role === 'assistant' || effect.message.role === 'user'
|
|
125
|
+
? effect.message.role
|
|
126
|
+
: 'system';
|
|
127
|
+
if (role === 'system') {
|
|
128
|
+
return buildRuntimeSystemChatMessage({
|
|
129
|
+
content: effect.message.content,
|
|
130
|
+
kind: effect.message.kind,
|
|
131
|
+
senderName: effect.message.senderName,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return buildChatMessage({
|
|
135
|
+
role,
|
|
136
|
+
content: effect.message.content,
|
|
137
|
+
kind: effect.message.kind,
|
|
138
|
+
senderName: effect.message.senderName,
|
|
139
|
+
} as ChatMessage);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (effect.type === 'notification' && effect.notification) {
|
|
143
|
+
const bubbleContent = effect.notification.bubbleContent
|
|
144
|
+
?? formatNotificationBubbleFallback(effect.notification.title, effect.notification.body);
|
|
145
|
+
const flattened = typeof bubbleContent === 'string' ? bubbleContent.trim() : flattenContent(bubbleContent).trim();
|
|
146
|
+
if (!flattened && (!Array.isArray(bubbleContent) || bubbleContent.length === 0)) return null;
|
|
147
|
+
|
|
148
|
+
const role = effect.notification.bubbleRole === 'assistant' || effect.notification.bubbleRole === 'user'
|
|
149
|
+
? effect.notification.bubbleRole
|
|
150
|
+
: 'system';
|
|
151
|
+
if (role === 'system') {
|
|
152
|
+
return buildRuntimeSystemChatMessage({
|
|
153
|
+
content: bubbleContent,
|
|
154
|
+
kind: effect.notification.bubbleKind,
|
|
155
|
+
senderName: effect.notification.bubbleSenderName,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return buildChatMessage({
|
|
159
|
+
role,
|
|
160
|
+
content: bubbleContent,
|
|
161
|
+
kind: effect.notification.bubbleKind,
|
|
162
|
+
senderName: effect.notification.bubbleSenderName,
|
|
163
|
+
} as ChatMessage);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (effect.type === 'toast' && effect.toast?.message) {
|
|
167
|
+
return buildRuntimeSystemChatMessage({ content: effect.toast.message });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
108
173
|
export function normalizeControlListResult(data: any): ControlListResult {
|
|
109
174
|
if (data && typeof data === 'object' && Array.isArray(data.options)) {
|
|
110
175
|
return {
|
|
@@ -196,3 +261,10 @@ function normalizeControlValue(value: any): ProviderControlValue {
|
|
|
196
261
|
}
|
|
197
262
|
return String(value);
|
|
198
263
|
}
|
|
264
|
+
|
|
265
|
+
function formatNotificationBubbleFallback(title: string | undefined, body: string): string {
|
|
266
|
+
const cleanTitle = typeof title === 'string' ? title.trim() : '';
|
|
267
|
+
const cleanBody = String(body || '').trim();
|
|
268
|
+
if (cleanTitle && cleanBody) return `${cleanTitle}\n${cleanBody}`;
|
|
269
|
+
return cleanTitle || cleanBody;
|
|
270
|
+
}
|
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
* CDP webview discovery + agent stream collection moved here.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type
|
|
8
|
+
import { flattenContent, 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 { normalizeProviderEffects } from './control-effects.js';
|
|
11
|
+
import { buildPersistedProviderEffectMessage, normalizeProviderEffects } from './control-effects.js';
|
|
12
12
|
import { ChatHistoryWriter } from '../config/chat-history.js';
|
|
13
13
|
import type { ChatMessage } from '../types.js';
|
|
14
14
|
import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
|
|
15
|
+
import { buildChatMessage, buildRuntimeSystemChatMessage, normalizeChatMessages } from './chat-message-normalization.js';
|
|
15
16
|
|
|
16
17
|
export class ExtensionProviderInstance implements ProviderInstance {
|
|
17
18
|
readonly type: string;
|
|
@@ -259,8 +260,8 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
259
260
|
this.appliedEffectKeys.add(effectKey);
|
|
260
261
|
|
|
261
262
|
if (effect.persist !== false) {
|
|
262
|
-
const
|
|
263
|
-
if (
|
|
263
|
+
const persistedMessage = buildPersistedProviderEffectMessage(effect);
|
|
264
|
+
if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
if (effect.type === 'message' && effect.message) {
|
|
@@ -299,36 +300,47 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
299
300
|
}
|
|
300
301
|
|
|
301
302
|
private appendRuntimeSystemMessage(content: string, dedupKey: string, receivedAt = Date.now()): void {
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
|
|
304
|
+
content,
|
|
305
|
+
receivedAt,
|
|
306
|
+
timestamp: receivedAt,
|
|
307
|
+
}), dedupKey);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private appendRuntimeMessage(message: ChatMessage, dedupKey: string): void {
|
|
311
|
+
const normalizedMessage = buildChatMessage({
|
|
312
|
+
...message,
|
|
313
|
+
receivedAt: typeof message.receivedAt === 'number' ? message.receivedAt : (message.timestamp || Date.now()),
|
|
314
|
+
timestamp: typeof message.timestamp === 'number' ? message.timestamp : (message.receivedAt || Date.now()),
|
|
315
|
+
} as ChatMessage);
|
|
316
|
+
const normalizedContent = typeof normalizedMessage.content === 'string'
|
|
317
|
+
? normalizedMessage.content.trim()
|
|
318
|
+
: flattenContent(normalizedMessage.content).trim();
|
|
319
|
+
if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
|
|
304
320
|
if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
|
|
305
321
|
|
|
306
322
|
this.runtimeMessages.push({
|
|
307
323
|
key: dedupKey,
|
|
308
|
-
message:
|
|
309
|
-
role: 'system',
|
|
310
|
-
senderName: 'System',
|
|
311
|
-
content: normalizedContent,
|
|
312
|
-
receivedAt,
|
|
313
|
-
timestamp: receivedAt,
|
|
314
|
-
},
|
|
324
|
+
message: normalizedMessage,
|
|
315
325
|
});
|
|
316
326
|
if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
|
|
317
327
|
|
|
318
|
-
|
|
319
|
-
this.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
328
|
+
if (normalizedContent) {
|
|
329
|
+
this.historyWriter.appendNewMessages(
|
|
330
|
+
this.type,
|
|
331
|
+
[{
|
|
332
|
+
role: normalizedMessage.role,
|
|
333
|
+
senderName: normalizedMessage.senderName,
|
|
334
|
+
kind: normalizedMessage.kind,
|
|
335
|
+
content: normalizedContent,
|
|
336
|
+
receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
|
|
337
|
+
historyDedupKey: dedupKey,
|
|
338
|
+
}],
|
|
339
|
+
this.chatTitle || this.agentName || this.provider.name,
|
|
340
|
+
this.instanceId,
|
|
341
|
+
this.chatId || this.instanceId,
|
|
342
|
+
);
|
|
343
|
+
}
|
|
332
344
|
}
|
|
333
345
|
|
|
334
346
|
/**
|
|
@@ -348,12 +360,12 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
348
360
|
}
|
|
349
361
|
|
|
350
362
|
this.prevMessageHashes = nextHashes;
|
|
351
|
-
return messages;
|
|
363
|
+
return normalizeChatMessages(messages);
|
|
352
364
|
}
|
|
353
365
|
|
|
354
366
|
private mergeConversationMessages(messages: any[]): ChatMessage[] {
|
|
355
|
-
if (this.runtimeMessages.length === 0) return messages;
|
|
356
|
-
return [...messages, ...this.runtimeMessages.map((entry) => entry.message)]
|
|
367
|
+
if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
|
|
368
|
+
return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)]
|
|
357
369
|
.map((message, index) => ({ message, index }))
|
|
358
370
|
.sort((a, b) => {
|
|
359
371
|
const aTime = a.message.receivedAt || a.message.timestamp || 0;
|
|
@@ -361,7 +373,7 @@ export class ExtensionProviderInstance implements ProviderInstance {
|
|
|
361
373
|
if (aTime !== bTime) return aTime - bTime;
|
|
362
374
|
return a.index - b.index;
|
|
363
375
|
})
|
|
364
|
-
.map((entry) => entry.message);
|
|
376
|
+
.map((entry) => entry.message));
|
|
365
377
|
}
|
|
366
378
|
|
|
367
379
|
private getPersistedEffectContent(effect: { type: string; message?: { content?: unknown }; toast?: { message?: string }; notification?: { title?: string; body?: string; bubbleContent?: unknown } }): string | null {
|
|
@@ -11,16 +11,17 @@
|
|
|
11
11
|
|
|
12
12
|
import * as os from 'os';
|
|
13
13
|
import * as crypto from 'crypto';
|
|
14
|
-
import type
|
|
14
|
+
import { flattenContent, type ProviderModule } from './contracts.js';
|
|
15
15
|
import type { ProviderInstance, ProviderState, ProviderEvent, InstanceContext } from './provider-instance.js';
|
|
16
16
|
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 { normalizeProviderEffects } from './control-effects.js';
|
|
20
|
+
import { buildPersistedProviderEffectMessage, normalizeProviderEffects } from './control-effects.js';
|
|
21
21
|
import type { ChatMessage } from '../types.js';
|
|
22
22
|
import { formatAutoApprovalMessage, pickApprovalButton } from './approval-utils.js';
|
|
23
23
|
import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
|
|
24
|
+
import { buildChatMessage, buildRuntimeSystemChatMessage, normalizeChatMessages } from './chat-message-normalization.js';
|
|
24
25
|
|
|
25
26
|
type ReadChatModal = {
|
|
26
27
|
message?: string;
|
|
@@ -497,8 +498,8 @@ export class IdeProviderInstance implements ProviderInstance {
|
|
|
497
498
|
this.appliedEffectKeys.add(effectKey);
|
|
498
499
|
|
|
499
500
|
if (effect.persist !== false) {
|
|
500
|
-
const
|
|
501
|
-
if (
|
|
501
|
+
const persistedMessage = buildPersistedProviderEffectMessage(effect);
|
|
502
|
+
if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
|
|
502
503
|
}
|
|
503
504
|
|
|
504
505
|
if (effect.type === 'message' && effect.message) {
|
|
@@ -537,8 +538,23 @@ export class IdeProviderInstance implements ProviderInstance {
|
|
|
537
538
|
}
|
|
538
539
|
|
|
539
540
|
private appendRuntimeSystemMessage(content: string, dedupKey: string, receivedAt = Date.now()): void {
|
|
540
|
-
|
|
541
|
-
|
|
541
|
+
this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
|
|
542
|
+
content,
|
|
543
|
+
receivedAt,
|
|
544
|
+
timestamp: receivedAt,
|
|
545
|
+
}), dedupKey);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
private appendRuntimeMessage(message: ChatMessage, dedupKey: string): void {
|
|
549
|
+
const normalizedMessage = buildChatMessage({
|
|
550
|
+
...message,
|
|
551
|
+
receivedAt: typeof message.receivedAt === 'number' ? message.receivedAt : (message.timestamp || Date.now()),
|
|
552
|
+
timestamp: typeof message.timestamp === 'number' ? message.timestamp : (message.receivedAt || Date.now()),
|
|
553
|
+
} as ChatMessage);
|
|
554
|
+
const normalizedContent = typeof normalizedMessage.content === 'string'
|
|
555
|
+
? normalizedMessage.content.trim()
|
|
556
|
+
: flattenContent(normalizedMessage.content).trim();
|
|
557
|
+
if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
|
|
542
558
|
if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
|
|
543
559
|
if (!this.cachedChat) {
|
|
544
560
|
this.cachedChat = {
|
|
@@ -553,35 +569,31 @@ export class IdeProviderInstance implements ProviderInstance {
|
|
|
553
569
|
|
|
554
570
|
this.runtimeMessages.push({
|
|
555
571
|
key: dedupKey,
|
|
556
|
-
message:
|
|
557
|
-
role: 'system',
|
|
558
|
-
senderName: 'System',
|
|
559
|
-
content: normalizedContent,
|
|
560
|
-
receivedAt,
|
|
561
|
-
timestamp: receivedAt,
|
|
562
|
-
},
|
|
572
|
+
message: normalizedMessage,
|
|
563
573
|
});
|
|
564
574
|
if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
|
|
565
575
|
|
|
566
|
-
|
|
567
|
-
this.
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
576
|
+
if (normalizedContent) {
|
|
577
|
+
this.historyWriter.appendNewMessages(
|
|
578
|
+
this.type,
|
|
579
|
+
[{
|
|
580
|
+
role: normalizedMessage.role,
|
|
581
|
+
senderName: normalizedMessage.senderName,
|
|
582
|
+
kind: normalizedMessage.kind,
|
|
583
|
+
content: normalizedContent,
|
|
584
|
+
receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
|
|
585
|
+
historyDedupKey: dedupKey,
|
|
586
|
+
}],
|
|
587
|
+
this.cachedChat?.title || this.provider.name,
|
|
588
|
+
this.instanceId,
|
|
589
|
+
this.cachedChat?.id || this.instanceId,
|
|
590
|
+
);
|
|
591
|
+
}
|
|
580
592
|
}
|
|
581
593
|
|
|
582
594
|
private mergeConversationMessages(messages: any[]): ChatMessage[] {
|
|
583
|
-
if (this.runtimeMessages.length === 0) return messages;
|
|
584
|
-
return [...messages, ...this.runtimeMessages.map((entry) => entry.message)]
|
|
595
|
+
if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
|
|
596
|
+
return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)]
|
|
585
597
|
.map((message, index) => ({ message, index }))
|
|
586
598
|
.sort((a, b) => {
|
|
587
599
|
const aTime = a.message.receivedAt || a.message.timestamp || 0;
|
|
@@ -589,7 +601,7 @@ export class IdeProviderInstance implements ProviderInstance {
|
|
|
589
601
|
if (aTime !== bTime) return aTime - bTime;
|
|
590
602
|
return a.index - b.index;
|
|
591
603
|
})
|
|
592
|
-
.map((entry) => entry.message);
|
|
604
|
+
.map((entry) => entry.message));
|
|
593
605
|
}
|
|
594
606
|
|
|
595
607
|
private getPersistedEffectContent(effect: { type: string; message?: { content?: unknown }; toast?: { message?: string }; notification?: { title?: string; body?: string; bubbleContent?: unknown } }): string | null {
|
package/src/types.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* When modifying this file, also update interface contracts in AGENT_PROTOCOL.md.
|
|
6
6
|
*/
|
|
7
7
|
import type { StatusReportPayload, AvailableProviderInfo } from './shared-types.js';
|
|
8
|
+
import type { ChatMessageKind } from './providers/chat-message-normalization.js';
|
|
8
9
|
|
|
9
10
|
// ── Daemon Status ──
|
|
10
11
|
|
|
@@ -29,7 +30,7 @@ export interface ChatMessage {
|
|
|
29
30
|
role: string; // 'user' | 'assistant' | 'system' | 'human'
|
|
30
31
|
/** Plain text (legacy) or canonical message parts */
|
|
31
32
|
content: string | MessagePart[];
|
|
32
|
-
kind?:
|
|
33
|
+
kind?: ChatMessageKind; // built-ins: standard | thought | tool | terminal | system; custom kinds allowed
|
|
33
34
|
id?: string;
|
|
34
35
|
index?: number;
|
|
35
36
|
timestamp?: number;
|