@adhdev/daemon-core 0.9.82-rc.111 → 0.9.82-rc.113
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/chat/subscription-updates.d.ts +1 -0
- package/dist/index.js +91 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +91 -15
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +2 -0
- package/package.json +1 -1
- package/src/chat/subscription-updates.ts +5 -1
- package/src/commands/chat-commands.ts +49 -10
- package/src/config/recent-activity.ts +8 -2
- package/src/providers/cli-provider-instance.ts +61 -13
|
@@ -128,6 +128,8 @@ export declare class CliProviderInstance implements ProviderInstance {
|
|
|
128
128
|
private mergeConversationMessages;
|
|
129
129
|
private formatApprovalRequestMessage;
|
|
130
130
|
private promoteProviderSessionId;
|
|
131
|
+
private shouldHydrateExistingProviderHistory;
|
|
132
|
+
private shouldSuppressFreshLaunchStartupReplay;
|
|
131
133
|
private syncCanonicalSavedHistoryIfNeeded;
|
|
132
134
|
private restorePersistedHistoryFromCurrentSession;
|
|
133
135
|
private getProbeDirectories;
|
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@ export interface ChatTailSubscriptionCursor {
|
|
|
17
17
|
export type SessionChatTailCommandResult = Partial<Omit<ReadChatSyncResult, 'activeModal'>> & {
|
|
18
18
|
success?: boolean
|
|
19
19
|
activeModal?: unknown
|
|
20
|
+
messagesTail?: unknown
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export interface PrepareSessionChatTailUpdateInput {
|
|
@@ -102,7 +103,10 @@ export function prepareSessionChatTailUpdate(
|
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
const
|
|
106
|
+
const rawMessages = Array.isArray(result.messages)
|
|
107
|
+
? result.messages as any[]
|
|
108
|
+
: (Array.isArray(result.messagesTail) ? result.messagesTail as any[] : [])
|
|
109
|
+
const fullMessages = normalizeChatMessages(rawMessages)
|
|
106
110
|
const messages = fullMessages
|
|
107
111
|
const title = typeof result.title === 'string' ? result.title : undefined
|
|
108
112
|
const activeModal = normalizeChatTailActiveModal(result.activeModal)
|
|
@@ -1165,16 +1165,55 @@ export async function handleChatHistory(h: CommandHelpers, args: any): Promise<C
|
|
|
1165
1165
|
: typeof (h.currentSession as any)?.workspace === 'string'
|
|
1166
1166
|
? (h.currentSession as any).workspace
|
|
1167
1167
|
: undefined;
|
|
1168
|
-
const
|
|
1169
|
-
|
|
1170
|
-
historySessionId
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1168
|
+
const exactNativeHistoryScope = Boolean(
|
|
1169
|
+
(typeof args?.targetSessionId === 'string' && args.targetSessionId.trim())
|
|
1170
|
+
|| (typeof args?.historySessionId === 'string' && args.historySessionId.trim())
|
|
1171
|
+
|| (typeof args?.providerSessionId === 'string' && args.providerSessionId.trim())
|
|
1172
|
+
);
|
|
1173
|
+
const result = supportsCliNativeTranscript(agentStr, provider) && isNativeSourceCanonicalHistory(provider?.canonicalHistory)
|
|
1174
|
+
? readCliProviderNativeHistory(agentStr, {
|
|
1175
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
1176
|
+
historySessionId,
|
|
1177
|
+
workspace,
|
|
1178
|
+
offset: offset || 0,
|
|
1179
|
+
limit: limit || 30,
|
|
1180
|
+
excludeRecentCount,
|
|
1181
|
+
historyBehavior: provider?.historyBehavior,
|
|
1182
|
+
scripts: provider?.scripts as any,
|
|
1183
|
+
exactSessionScoped: exactNativeHistoryScope,
|
|
1184
|
+
})
|
|
1185
|
+
: readProviderChatHistory(agentStr, {
|
|
1186
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
1187
|
+
historySessionId,
|
|
1188
|
+
workspace,
|
|
1189
|
+
offset: offset || 0,
|
|
1190
|
+
limit: limit || 30,
|
|
1191
|
+
excludeRecentCount,
|
|
1192
|
+
historyBehavior: provider?.historyBehavior,
|
|
1193
|
+
scripts: provider?.scripts as any,
|
|
1194
|
+
});
|
|
1195
|
+
if (supportsCliNativeTranscript(agentStr, provider) && isNativeSourceCanonicalHistory(provider?.canonicalHistory)) {
|
|
1196
|
+
const lookup = (result as any).lookup === 'workspace' ? 'workspace' : 'session';
|
|
1197
|
+
const messages = Array.isArray((result as any).messages) ? normalizeNativeHistoryMessages(agentStr, (result as any).messages as ChatMessage[]) : [];
|
|
1198
|
+
const historyProviderSessionId = typeof (result as any)?.providerSessionId === 'string'
|
|
1199
|
+
? (result as any).providerSessionId
|
|
1200
|
+
: readHistorySessionIdFromMessages(messages) || historySessionId;
|
|
1201
|
+
const safeMapping = hasSafeNativeHistoryMapping({
|
|
1202
|
+
historySessionId: lookup === 'workspace' ? undefined : historySessionId,
|
|
1203
|
+
providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
|
|
1204
|
+
workspace,
|
|
1205
|
+
nativeMessages: messages,
|
|
1206
|
+
});
|
|
1207
|
+
if ((result as any).source === 'provider-native' && messages.length > 0 && !safeMapping) {
|
|
1208
|
+
return {
|
|
1209
|
+
success: true,
|
|
1210
|
+
messages: [],
|
|
1211
|
+
hasMore: false,
|
|
1212
|
+
source: 'native-unavailable',
|
|
1213
|
+
agent: agentStr,
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1178
1217
|
return { success: true, ...result, agent: agentStr };
|
|
1179
1218
|
} catch (e: any) {
|
|
1180
1219
|
return { success: false, error: e.message };
|
|
@@ -92,12 +92,18 @@ export function buildSessionReadStateKey(sessionId: string, providerSessionId?:
|
|
|
92
92
|
|
|
93
93
|
export function getSessionSeenAt(state: DaemonState, sessionId: string, providerSessionId?: string | null): number {
|
|
94
94
|
const providerKey = buildSessionReadStateKey(sessionId, providerSessionId);
|
|
95
|
-
return state.sessionReads?.[providerKey] || state.sessionReads?.[sessionId] || 0;
|
|
95
|
+
return Math.max(state.sessionReads?.[providerKey] || 0, state.sessionReads?.[sessionId] || 0);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
export function getSessionSeenMarker(state: DaemonState, sessionId: string, providerSessionId?: string | null): string {
|
|
99
99
|
const providerKey = buildSessionReadStateKey(sessionId, providerSessionId);
|
|
100
|
-
|
|
100
|
+
const providerSeenAt = state.sessionReads?.[providerKey] || 0;
|
|
101
|
+
const sessionSeenAt = state.sessionReads?.[sessionId] || 0;
|
|
102
|
+
const providerMarker = state.sessionReadMarkers?.[providerKey] || '';
|
|
103
|
+
const sessionMarker = state.sessionReadMarkers?.[sessionId] || '';
|
|
104
|
+
if (sessionSeenAt > providerSeenAt && sessionMarker) return sessionMarker;
|
|
105
|
+
if (providerSeenAt > sessionSeenAt && providerMarker) return providerMarker;
|
|
106
|
+
return providerMarker || sessionMarker;
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
export function getSessionNotificationDismissal(state: DaemonState, sessionId: string, providerSessionId?: string | null): string {
|
|
@@ -43,6 +43,18 @@ type CompletedDebouncePending = {
|
|
|
43
43
|
loggedBlockReason?: string;
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
+
function isIdleStatus(value: unknown): boolean {
|
|
47
|
+
const status = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
48
|
+
return !status || status === 'idle' || status === 'ready';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getMessageTime(message: unknown): number {
|
|
52
|
+
if (!message || typeof message !== 'object') return 0;
|
|
53
|
+
const record = message as { receivedAt?: unknown; timestamp?: unknown };
|
|
54
|
+
const value = Number(record.receivedAt ?? record.timestamp ?? 0);
|
|
55
|
+
return Number.isFinite(value) ? value : 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
type CompletedFinalizationBlock = {
|
|
47
59
|
reason: string;
|
|
48
60
|
terminal?: boolean;
|
|
@@ -417,7 +429,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
417
429
|
await this.adapter.spawn();
|
|
418
430
|
await this.enforceFreshSessionLaunchIfNeeded();
|
|
419
431
|
this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
|
|
420
|
-
if (this.providerSessionId) {
|
|
432
|
+
if (this.providerSessionId && this.shouldHydrateExistingProviderHistory()) {
|
|
421
433
|
this.restorePersistedHistoryFromCurrentSession();
|
|
422
434
|
}
|
|
423
435
|
if (this.providerSessionId && this.launchMode === 'resume') {
|
|
@@ -518,26 +530,35 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
518
530
|
this.provider,
|
|
519
531
|
typeof adapterStatus?.providerSessionId === 'string' ? adapterStatus.providerSessionId : '',
|
|
520
532
|
);
|
|
521
|
-
if (adapterProviderSessionId) {
|
|
522
|
-
this.promoteProviderSessionId(adapterProviderSessionId);
|
|
523
|
-
}
|
|
524
533
|
const autoApproveActive = this.maybeAutoApproveStatus(adapterStatus, Date.now());
|
|
525
534
|
const visibleStatus = parseErrorMessage || parsedStatus?.status === 'error'
|
|
526
535
|
? 'error'
|
|
527
536
|
: (autoApproveActive ? 'generating' : adapterStatus.status);
|
|
537
|
+
const runtime = this.adapter.getRuntimeMetadata();
|
|
538
|
+
this.maybeAppendRuntimeRecoveryMessage(runtime);
|
|
539
|
+
let parsedMessages = Array.isArray(parsedStatus?.messages)
|
|
540
|
+
? parsedStatus.messages
|
|
541
|
+
: [];
|
|
528
542
|
const parsedProviderSessionId = normalizeProviderSessionId(
|
|
529
543
|
this.provider,
|
|
530
544
|
typeof parsedStatus?.providerSessionId === 'string' ? parsedStatus.providerSessionId : '',
|
|
531
545
|
);
|
|
532
|
-
|
|
546
|
+
const suppressFreshLaunchStartupReplay = this.shouldSuppressFreshLaunchStartupReplay(
|
|
547
|
+
parsedMessages,
|
|
548
|
+
parsedStatus,
|
|
549
|
+
adapterStatus,
|
|
550
|
+
parsedProviderSessionId,
|
|
551
|
+
);
|
|
552
|
+
if (adapterProviderSessionId && !suppressFreshLaunchStartupReplay) {
|
|
553
|
+
this.promoteProviderSessionId(adapterProviderSessionId);
|
|
554
|
+
}
|
|
555
|
+
if (parsedProviderSessionId && !suppressFreshLaunchStartupReplay) {
|
|
533
556
|
this.promoteProviderSessionId(parsedProviderSessionId);
|
|
534
557
|
}
|
|
535
|
-
|
|
536
|
-
|
|
558
|
+
if (suppressFreshLaunchStartupReplay) {
|
|
559
|
+
parsedMessages = [];
|
|
560
|
+
}
|
|
537
561
|
const activeChatId = this.providerSessionId || runtime?.runtimeId || this.instanceId;
|
|
538
|
-
let parsedMessages = Array.isArray(parsedStatus?.messages)
|
|
539
|
-
? parsedStatus.messages
|
|
540
|
-
: [];
|
|
541
562
|
const historyMessageCount = Number.isFinite(parsedStatus?.historyMessageCount)
|
|
542
563
|
? Math.max(0, Number(parsedStatus.historyMessageCount))
|
|
543
564
|
: null;
|
|
@@ -547,7 +568,9 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
547
568
|
: [];
|
|
548
569
|
}
|
|
549
570
|
const mergedMessages = this.mergeConversationMessages(parsedMessages);
|
|
550
|
-
const canonicalBackedHistory = this.
|
|
571
|
+
const canonicalBackedHistory = this.shouldHydrateExistingProviderHistory()
|
|
572
|
+
? this.syncCanonicalSavedHistoryIfNeeded()
|
|
573
|
+
: false;
|
|
551
574
|
const statusMessages = canonicalBackedHistory && this.lastPersistedHistoryMessages.length > 0
|
|
552
575
|
? this.lastPersistedHistoryMessages.map((message) => ({
|
|
553
576
|
role: message.role,
|
|
@@ -600,7 +623,12 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
600
623
|
}
|
|
601
624
|
}
|
|
602
625
|
|
|
603
|
-
this.applyProviderResponse(
|
|
626
|
+
this.applyProviderResponse(
|
|
627
|
+
suppressFreshLaunchStartupReplay && parsedStatus && typeof parsedStatus === 'object'
|
|
628
|
+
? { ...parsedStatus, providerSessionId: undefined }
|
|
629
|
+
: parsedStatus,
|
|
630
|
+
{ phase: 'immediate' },
|
|
631
|
+
);
|
|
604
632
|
const surface = resolveProviderStateSurface({
|
|
605
633
|
summaryMetadata: this.summaryMetadata as any,
|
|
606
634
|
controlValues: this.controlValues,
|
|
@@ -1466,7 +1494,9 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1466
1494
|
this.providerSessionId = nextSessionId;
|
|
1467
1495
|
this.historyWriter.promoteHistorySession(this.type, previousHistorySessionId, nextSessionId);
|
|
1468
1496
|
this.historyWriter.writeSessionStart(this.type, nextSessionId, this.workingDir, this.instanceId);
|
|
1469
|
-
this.
|
|
1497
|
+
if (this.shouldHydrateExistingProviderHistory()) {
|
|
1498
|
+
this.restorePersistedHistoryFromCurrentSession();
|
|
1499
|
+
}
|
|
1470
1500
|
this.adapter.updateRuntimeMeta({ providerSessionId: nextSessionId });
|
|
1471
1501
|
this.onProviderSessionResolved?.({
|
|
1472
1502
|
instanceId: this.instanceId,
|
|
@@ -1479,6 +1509,24 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1479
1509
|
LOG.info('CLI', `[${this.type}] discovered provider session id: ${nextSessionId}`);
|
|
1480
1510
|
}
|
|
1481
1511
|
|
|
1512
|
+
private shouldHydrateExistingProviderHistory(): boolean {
|
|
1513
|
+
return this.launchMode === 'resume' || this.launchMode === 'manual';
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
private shouldSuppressFreshLaunchStartupReplay(parsedMessages: unknown[], parsedStatus: any, adapterStatus: any, parsedProviderSessionId = ''): boolean {
|
|
1517
|
+
if (this.launchMode !== 'new') return false;
|
|
1518
|
+
if (this.providerSessionId) return false;
|
|
1519
|
+
if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return false;
|
|
1520
|
+
if (!isIdleStatus(adapterStatus?.status) || !isIdleStatus(parsedStatus?.status)) return false;
|
|
1521
|
+
if (parsedProviderSessionId) return true;
|
|
1522
|
+
|
|
1523
|
+
const newestMessageAt = parsedMessages.reduce<number>((newest, message) => Math.max(newest, getMessageTime(message)), 0);
|
|
1524
|
+
|
|
1525
|
+
// Untimestamped idle parser output during a fresh launch is usually the
|
|
1526
|
+
// provider's last workspace transcript before a new turn exists.
|
|
1527
|
+
return newestMessageAt === 0;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1482
1530
|
private syncCanonicalSavedHistoryIfNeeded(): boolean {
|
|
1483
1531
|
if (!this.providerSessionId) return false;
|
|
1484
1532
|
const canonicalHistory = this.provider.canonicalHistory;
|