adhdev 0.8.60 → 0.8.63

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/index.js CHANGED
@@ -3015,6 +3015,231 @@ var init_devtools = __esm({
3015
3015
  }
3016
3016
  });
3017
3017
 
3018
+ // ../../oss/packages/daemon-core/src/providers/io-contracts.ts
3019
+ function normalizeInputEnvelope(input) {
3020
+ const normalized = normalizeInputEnvelopePayload(input);
3021
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
3022
+ return {
3023
+ parts: normalized.parts,
3024
+ textFallback,
3025
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
3026
+ };
3027
+ }
3028
+ function normalizeMessageParts(content) {
3029
+ if (typeof content === "string") return [{ type: "text", text: content }];
3030
+ if (!Array.isArray(content)) {
3031
+ if (content && typeof content === "object" && typeof content.text === "string") {
3032
+ return [{ type: "text", text: String(content.text) }];
3033
+ }
3034
+ return [];
3035
+ }
3036
+ const parts = [];
3037
+ for (const raw of content) {
3038
+ if (typeof raw === "string") {
3039
+ parts.push({ type: "text", text: raw });
3040
+ continue;
3041
+ }
3042
+ if (!raw || typeof raw !== "object") continue;
3043
+ const part = normalizeMessagePartObject(raw);
3044
+ if (part) parts.push(part);
3045
+ }
3046
+ return parts;
3047
+ }
3048
+ function flattenMessageParts(parts) {
3049
+ return parts.map((part) => {
3050
+ if (part.type === "text") return part.text;
3051
+ if (part.type === "resource") return part.resource.text || "";
3052
+ return "";
3053
+ }).filter((value) => value.length > 0).join("\n");
3054
+ }
3055
+ function normalizeInputEnvelopePayload(input) {
3056
+ if (typeof input === "string") {
3057
+ return { parts: [{ type: "text", text: input }], textFallback: input };
3058
+ }
3059
+ if (!input || typeof input !== "object") {
3060
+ return { parts: [], textFallback: "" };
3061
+ }
3062
+ const record2 = input;
3063
+ const nestedInput = record2.input;
3064
+ if (nestedInput && typeof nestedInput === "object") {
3065
+ const nested = nestedInput;
3066
+ return {
3067
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
3068
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
3069
+ metadata: normalizeInputMetadata(nested.metadata)
3070
+ };
3071
+ }
3072
+ const directText = typeof record2.text === "string" ? record2.text : typeof record2.message === "string" ? record2.message : void 0;
3073
+ if (directText !== void 0) {
3074
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
3075
+ }
3076
+ const directParts = normalizeInputParts(record2.parts ?? record2.prompt);
3077
+ return {
3078
+ parts: directParts,
3079
+ textFallback: typeof record2.textFallback === "string" ? record2.textFallback : void 0,
3080
+ metadata: normalizeInputMetadata(record2.metadata)
3081
+ };
3082
+ }
3083
+ function normalizeInputMetadata(value) {
3084
+ if (!value || typeof value !== "object") return void 0;
3085
+ const record2 = value;
3086
+ const metadata = {};
3087
+ if (record2.source === "dashboard" || record2.source === "shortcut_api" || record2.source === "provider_script" || record2.source === "session_replay") {
3088
+ metadata.source = record2.source;
3089
+ }
3090
+ if (typeof record2.clientTimestamp === "number" && Number.isFinite(record2.clientTimestamp)) {
3091
+ metadata.clientTimestamp = record2.clientTimestamp;
3092
+ }
3093
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
3094
+ }
3095
+ function normalizeInputParts(value) {
3096
+ if (!Array.isArray(value)) return [];
3097
+ const parts = [];
3098
+ for (const raw of value) {
3099
+ if (typeof raw === "string") {
3100
+ parts.push({ type: "text", text: raw });
3101
+ continue;
3102
+ }
3103
+ if (!raw || typeof raw !== "object") continue;
3104
+ const part = normalizeInputPartObject(raw);
3105
+ if (part) parts.push(part);
3106
+ }
3107
+ return parts;
3108
+ }
3109
+ function normalizeInputPartObject(raw) {
3110
+ const type = raw.type;
3111
+ if (type === "text" && typeof raw.text === "string") {
3112
+ return { type, text: raw.text };
3113
+ }
3114
+ if (type === "image" && typeof raw.mimeType === "string") {
3115
+ return {
3116
+ type,
3117
+ mimeType: raw.mimeType,
3118
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
3119
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
3120
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
3121
+ };
3122
+ }
3123
+ if (type === "audio" && typeof raw.mimeType === "string") {
3124
+ return {
3125
+ type,
3126
+ mimeType: raw.mimeType,
3127
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
3128
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
3129
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
3130
+ };
3131
+ }
3132
+ if (type === "video" && typeof raw.mimeType === "string") {
3133
+ return {
3134
+ type,
3135
+ mimeType: raw.mimeType,
3136
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
3137
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
3138
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
3139
+ };
3140
+ }
3141
+ if (type === "resource" && typeof raw.uri === "string") {
3142
+ return {
3143
+ type,
3144
+ uri: raw.uri,
3145
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
3146
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
3147
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
3148
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
3149
+ };
3150
+ }
3151
+ if (type === "resource_link" && typeof raw.uri === "string") {
3152
+ return {
3153
+ type: "resource",
3154
+ uri: raw.uri,
3155
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
3156
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
3157
+ };
3158
+ }
3159
+ return null;
3160
+ }
3161
+ function normalizeMessagePartObject(raw) {
3162
+ const type = raw.type;
3163
+ if (type === "text" && typeof raw.text === "string") {
3164
+ return { type, text: raw.text };
3165
+ }
3166
+ if (type === "image" && typeof raw.mimeType === "string") {
3167
+ return {
3168
+ type,
3169
+ mimeType: raw.mimeType,
3170
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
3171
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
3172
+ };
3173
+ }
3174
+ if (type === "audio" && typeof raw.mimeType === "string") {
3175
+ return {
3176
+ type,
3177
+ mimeType: raw.mimeType,
3178
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
3179
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
3180
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
3181
+ };
3182
+ }
3183
+ if (type === "video" && typeof raw.mimeType === "string") {
3184
+ return {
3185
+ type,
3186
+ mimeType: raw.mimeType,
3187
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
3188
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
3189
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
3190
+ };
3191
+ }
3192
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
3193
+ return {
3194
+ type,
3195
+ uri: raw.uri,
3196
+ name: raw.name,
3197
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
3198
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
3199
+ };
3200
+ }
3201
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
3202
+ const resource = raw.resource;
3203
+ if (typeof resource.uri !== "string") return null;
3204
+ return {
3205
+ type,
3206
+ resource: {
3207
+ uri: resource.uri,
3208
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
3209
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
3210
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
3211
+ }
3212
+ };
3213
+ }
3214
+ return null;
3215
+ }
3216
+ function flattenInputParts(parts) {
3217
+ return parts.map((part) => {
3218
+ if (part.type === "text") return part.text;
3219
+ if (part.type === "audio") return part.transcript || "";
3220
+ if (part.type === "resource") return part.text || "";
3221
+ return "";
3222
+ }).filter((value) => value.length > 0).join("\n");
3223
+ }
3224
+ var init_io_contracts = __esm({
3225
+ "../../oss/packages/daemon-core/src/providers/io-contracts.ts"() {
3226
+ "use strict";
3227
+ }
3228
+ });
3229
+
3230
+ // ../../oss/packages/daemon-core/src/providers/contracts.ts
3231
+ function flattenContent(content) {
3232
+ if (typeof content === "string") return content;
3233
+ return flattenMessageParts(normalizeMessageParts(content));
3234
+ }
3235
+ var init_contracts = __esm({
3236
+ "../../oss/packages/daemon-core/src/providers/contracts.ts"() {
3237
+ "use strict";
3238
+ init_io_contracts();
3239
+ init_io_contracts();
3240
+ }
3241
+ });
3242
+
3018
3243
  // ../../oss/packages/daemon-core/src/providers/status-monitor.ts
3019
3244
  var DEFAULT_MONITOR_CONFIG, StatusMonitor;
3020
3245
  var init_status_monitor = __esm({
@@ -3133,6 +3358,64 @@ var init_status_monitor = __esm({
3133
3358
  }
3134
3359
  });
3135
3360
 
3361
+ // ../../oss/packages/daemon-core/src/providers/chat-message-normalization.ts
3362
+ function isBuiltinChatMessageKind(kind) {
3363
+ return typeof kind === "string" && KNOWN_CHAT_MESSAGE_KINDS.has(kind.trim().toLowerCase());
3364
+ }
3365
+ function normalizeChatMessageKind(kind, role) {
3366
+ const normalizedKind = typeof kind === "string" ? kind.trim().toLowerCase() : "";
3367
+ if (normalizedKind && KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
3368
+ const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
3369
+ return normalizedRole === "system" ? "system" : "standard";
3370
+ }
3371
+ function buildChatMessage(message) {
3372
+ return {
3373
+ ...message,
3374
+ kind: normalizeChatMessageKind(message?.kind, message?.role)
3375
+ };
3376
+ }
3377
+ function buildSystemChatMessage(message) {
3378
+ return buildChatMessage({
3379
+ ...message,
3380
+ role: "system",
3381
+ kind: message?.kind || "system"
3382
+ });
3383
+ }
3384
+ function buildRuntimeSystemChatMessage(message) {
3385
+ return buildSystemChatMessage({
3386
+ ...message,
3387
+ senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
3388
+ });
3389
+ }
3390
+ function buildAssistantChatMessage(message) {
3391
+ return buildChatMessage({
3392
+ ...message,
3393
+ role: "assistant",
3394
+ kind: message?.kind || "standard"
3395
+ });
3396
+ }
3397
+ function buildUserChatMessage(message) {
3398
+ return buildChatMessage({
3399
+ ...message,
3400
+ role: "user",
3401
+ kind: message?.kind || "standard"
3402
+ });
3403
+ }
3404
+ function normalizeChatMessage(message) {
3405
+ return buildChatMessage(message);
3406
+ }
3407
+ function normalizeChatMessages(messages) {
3408
+ return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
3409
+ }
3410
+ var BUILTIN_CHAT_MESSAGE_KINDS, KNOWN_CHAT_MESSAGE_KINDS;
3411
+ var init_chat_message_normalization = __esm({
3412
+ "../../oss/packages/daemon-core/src/providers/chat-message-normalization.ts"() {
3413
+ "use strict";
3414
+ BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
3415
+ KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
3416
+ }
3417
+ });
3418
+
3136
3419
  // ../../oss/packages/daemon-core/src/providers/control-effects.ts
3137
3420
  function extractProviderControlValues(controls, data) {
3138
3421
  if (!data || typeof data !== "object") return void 0;
@@ -3201,13 +3484,58 @@ function normalizeProviderEffects(data) {
3201
3484
  level: raw.notification.level === "success" || raw.notification.level === "warning" ? raw.notification.level : "info",
3202
3485
  channels: Array.isArray(raw.notification.channels) ? raw.notification.channels.filter((channel) => channel === "bubble" || channel === "toast" || channel === "browser") : void 0,
3203
3486
  preferenceKey: raw.notification.preferenceKey === "disconnect" || raw.notification.preferenceKey === "completion" || raw.notification.preferenceKey === "approval" || raw.notification.preferenceKey === "browser" ? raw.notification.preferenceKey : void 0,
3204
- bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0
3487
+ bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0,
3488
+ bubbleKind: typeof raw.notification.bubbleKind === "string" ? raw.notification.bubbleKind : void 0,
3489
+ bubbleRole: raw.notification.bubbleRole === "assistant" || raw.notification.bubbleRole === "user" ? raw.notification.bubbleRole : raw.notification.bubbleRole === "system" ? "system" : void 0,
3490
+ bubbleSenderName: typeof raw.notification.bubbleSenderName === "string" ? raw.notification.bubbleSenderName : void 0
3205
3491
  }
3206
3492
  });
3207
3493
  }
3208
3494
  }
3209
3495
  return effects;
3210
3496
  }
3497
+ function buildPersistedProviderEffectMessage(effect) {
3498
+ if (!effect) return null;
3499
+ if (effect.type === "message" && effect.message) {
3500
+ const role = effect.message.role === "assistant" || effect.message.role === "user" ? effect.message.role : "system";
3501
+ if (role === "system") {
3502
+ return buildRuntimeSystemChatMessage({
3503
+ content: effect.message.content,
3504
+ kind: effect.message.kind,
3505
+ senderName: effect.message.senderName
3506
+ });
3507
+ }
3508
+ return buildChatMessage({
3509
+ role,
3510
+ content: effect.message.content,
3511
+ kind: effect.message.kind,
3512
+ senderName: effect.message.senderName
3513
+ });
3514
+ }
3515
+ if (effect.type === "notification" && effect.notification) {
3516
+ const bubbleContent = effect.notification.bubbleContent ?? formatNotificationBubbleFallback(effect.notification.title, effect.notification.body);
3517
+ const flattened = typeof bubbleContent === "string" ? bubbleContent.trim() : flattenContent(bubbleContent).trim();
3518
+ if (!flattened && (!Array.isArray(bubbleContent) || bubbleContent.length === 0)) return null;
3519
+ const role = effect.notification.bubbleRole === "assistant" || effect.notification.bubbleRole === "user" ? effect.notification.bubbleRole : "system";
3520
+ if (role === "system") {
3521
+ return buildRuntimeSystemChatMessage({
3522
+ content: bubbleContent,
3523
+ kind: effect.notification.bubbleKind,
3524
+ senderName: effect.notification.bubbleSenderName
3525
+ });
3526
+ }
3527
+ return buildChatMessage({
3528
+ role,
3529
+ content: bubbleContent,
3530
+ kind: effect.notification.bubbleKind,
3531
+ senderName: effect.notification.bubbleSenderName
3532
+ });
3533
+ }
3534
+ if (effect.type === "toast" && effect.toast?.message) {
3535
+ return buildRuntimeSystemChatMessage({ content: effect.toast.message });
3536
+ }
3537
+ return null;
3538
+ }
3211
3539
  function normalizeControlListResult(data) {
3212
3540
  if (data && typeof data === "object" && Array.isArray(data.options)) {
3213
3541
  return {
@@ -3274,9 +3602,18 @@ function normalizeControlValue(value) {
3274
3602
  }
3275
3603
  return String(value);
3276
3604
  }
3605
+ function formatNotificationBubbleFallback(title, body) {
3606
+ const cleanTitle = typeof title === "string" ? title.trim() : "";
3607
+ const cleanBody = String(body || "").trim();
3608
+ if (cleanTitle && cleanBody) return `${cleanTitle}
3609
+ ${cleanBody}`;
3610
+ return cleanTitle || cleanBody;
3611
+ }
3277
3612
  var init_control_effects = __esm({
3278
3613
  "../../oss/packages/daemon-core/src/providers/control-effects.ts"() {
3279
3614
  "use strict";
3615
+ init_contracts();
3616
+ init_chat_message_normalization();
3280
3617
  }
3281
3618
  });
3282
3619
 
@@ -3464,6 +3801,7 @@ var init_chat_history = __esm({
3464
3801
  fs3 = __toESM(require("fs"));
3465
3802
  path7 = __toESM(require("path"));
3466
3803
  os6 = __toESM(require("os"));
3804
+ init_chat_message_normalization();
3467
3805
  HISTORY_DIR = path7.join(os6.homedir(), ".adhdev", "history");
3468
3806
  RETAIN_DAYS = 30;
3469
3807
  CODEX_STARTER_PROMPT_RE = /^(?:[›❯]\s*)?(?:Find and fix a bug in @filename|Improve documentation in @filename|Write tests for @filename|Explain this codebase|Summarize recent commits|Implement \{feature\}|Use \/skills(?: to list available skills)?|Run \/review on my current changes)$/i;
@@ -3613,11 +3951,11 @@ var init_chat_history = __esm({
3613
3951
  this.appendNewMessages(
3614
3952
  agentType,
3615
3953
  [{
3616
- role: "system",
3617
- kind: "system",
3618
- content,
3619
- receivedAt: options.receivedAt,
3620
- senderName: options.senderName,
3954
+ ...buildRuntimeSystemChatMessage({
3955
+ content,
3956
+ receivedAt: options.receivedAt,
3957
+ senderName: options.senderName
3958
+ }),
3621
3959
  historyDedupKey: options.dedupKey
3622
3960
  }],
3623
3961
  options.sessionTitle,
@@ -3865,10 +4203,12 @@ var ExtensionProviderInstance;
3865
4203
  var init_extension_provider_instance = __esm({
3866
4204
  "../../oss/packages/daemon-core/src/providers/extension-provider-instance.ts"() {
3867
4205
  "use strict";
4206
+ init_contracts();
3868
4207
  init_status_monitor();
3869
4208
  init_control_effects();
3870
4209
  init_chat_history();
3871
4210
  init_provider_patch_state();
4211
+ init_chat_message_normalization();
3872
4212
  ExtensionProviderInstance = class {
3873
4213
  type;
3874
4214
  category = "extension";
@@ -4075,8 +4415,8 @@ var init_extension_provider_instance = __esm({
4075
4415
  if (this.appliedEffectKeys.has(effectKey)) continue;
4076
4416
  this.appliedEffectKeys.add(effectKey);
4077
4417
  if (effect.persist !== false) {
4078
- const persisted = this.getPersistedEffectContent(effect);
4079
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
4418
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
4419
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
4080
4420
  }
4081
4421
  if (effect.type === "message" && effect.message) {
4082
4422
  this.pushEvent({
@@ -4111,34 +4451,42 @@ var init_extension_provider_instance = __esm({
4111
4451
  }
4112
4452
  }
4113
4453
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
4114
- const normalizedContent = String(content || "").trim();
4115
- if (!normalizedContent) return;
4454
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
4455
+ content,
4456
+ receivedAt,
4457
+ timestamp: receivedAt
4458
+ }), dedupKey);
4459
+ }
4460
+ appendRuntimeMessage(message, dedupKey) {
4461
+ const normalizedMessage = buildChatMessage({
4462
+ ...message,
4463
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
4464
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
4465
+ });
4466
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
4467
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
4116
4468
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
4117
4469
  this.runtimeMessages.push({
4118
4470
  key: dedupKey,
4119
- message: {
4120
- role: "system",
4121
- senderName: "System",
4122
- content: normalizedContent,
4123
- receivedAt,
4124
- timestamp: receivedAt
4125
- }
4471
+ message: normalizedMessage
4126
4472
  });
4127
4473
  if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
4128
- this.historyWriter.appendNewMessages(
4129
- this.type,
4130
- [{
4131
- role: "system",
4132
- senderName: "System",
4133
- content: normalizedContent,
4134
- kind: "system",
4135
- receivedAt,
4136
- historyDedupKey: dedupKey
4137
- }],
4138
- this.chatTitle || this.agentName || this.provider.name,
4139
- this.instanceId,
4140
- this.chatId || this.instanceId
4141
- );
4474
+ if (normalizedContent) {
4475
+ this.historyWriter.appendNewMessages(
4476
+ this.type,
4477
+ [{
4478
+ role: normalizedMessage.role,
4479
+ senderName: normalizedMessage.senderName,
4480
+ kind: normalizedMessage.kind,
4481
+ content: normalizedContent,
4482
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
4483
+ historyDedupKey: dedupKey
4484
+ }],
4485
+ this.chatTitle || this.agentName || this.provider.name,
4486
+ this.instanceId,
4487
+ this.chatId || this.instanceId
4488
+ );
4489
+ }
4142
4490
  }
4143
4491
  /**
4144
4492
  * Assign stable receivedAt to extension messages.
@@ -4155,16 +4503,16 @@ var init_extension_provider_instance = __esm({
4155
4503
  nextHashes.set(hash2, msg.receivedAt);
4156
4504
  }
4157
4505
  this.prevMessageHashes = nextHashes;
4158
- return messages;
4506
+ return normalizeChatMessages(messages);
4159
4507
  }
4160
4508
  mergeConversationMessages(messages) {
4161
- if (this.runtimeMessages.length === 0) return messages;
4162
- return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
4509
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
4510
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
4163
4511
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
4164
4512
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
4165
4513
  if (aTime !== bTime) return aTime - bTime;
4166
4514
  return a.index - b.index;
4167
- }).map((entry) => entry.message);
4515
+ }).map((entry) => entry.message));
4168
4516
  }
4169
4517
  getPersistedEffectContent(effect) {
4170
4518
  if (effect.type === "message") {
@@ -4288,6 +4636,7 @@ var init_ide_provider_instance = __esm({
4288
4636
  "../../oss/packages/daemon-core/src/providers/ide-provider-instance.ts"() {
4289
4637
  "use strict";
4290
4638
  crypto2 = __toESM(require("crypto"));
4639
+ init_contracts();
4291
4640
  init_extension_provider_instance();
4292
4641
  init_status_monitor();
4293
4642
  init_chat_history();
@@ -4295,6 +4644,7 @@ var init_ide_provider_instance = __esm({
4295
4644
  init_control_effects();
4296
4645
  init_approval_utils();
4297
4646
  init_provider_patch_state();
4647
+ init_chat_message_normalization();
4298
4648
  IdeProviderInstance = class {
4299
4649
  type;
4300
4650
  category = "ide";
@@ -4675,8 +5025,8 @@ var init_ide_provider_instance = __esm({
4675
5025
  if (this.appliedEffectKeys.has(effectKey)) continue;
4676
5026
  this.appliedEffectKeys.add(effectKey);
4677
5027
  if (effect.persist !== false) {
4678
- const persisted = this.getPersistedEffectContent(effect);
4679
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
5028
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
5029
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
4680
5030
  }
4681
5031
  if (effect.type === "message" && effect.message) {
4682
5032
  this.pushEvent({
@@ -4711,8 +5061,20 @@ var init_ide_provider_instance = __esm({
4711
5061
  }
4712
5062
  }
4713
5063
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
4714
- const normalizedContent = String(content || "").trim();
4715
- if (!normalizedContent) return;
5064
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
5065
+ content,
5066
+ receivedAt,
5067
+ timestamp: receivedAt
5068
+ }), dedupKey);
5069
+ }
5070
+ appendRuntimeMessage(message, dedupKey) {
5071
+ const normalizedMessage = buildChatMessage({
5072
+ ...message,
5073
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
5074
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
5075
+ });
5076
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
5077
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
4716
5078
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
4717
5079
  if (!this.cachedChat) {
4718
5080
  this.cachedChat = {
@@ -4726,38 +5088,34 @@ var init_ide_provider_instance = __esm({
4726
5088
  }
4727
5089
  this.runtimeMessages.push({
4728
5090
  key: dedupKey,
4729
- message: {
4730
- role: "system",
4731
- senderName: "System",
4732
- content: normalizedContent,
4733
- receivedAt,
4734
- timestamp: receivedAt
4735
- }
5091
+ message: normalizedMessage
4736
5092
  });
4737
5093
  if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
4738
- this.historyWriter.appendNewMessages(
4739
- this.type,
4740
- [{
4741
- role: "system",
4742
- senderName: "System",
4743
- content: normalizedContent,
4744
- kind: "system",
4745
- receivedAt,
4746
- historyDedupKey: dedupKey
4747
- }],
4748
- this.cachedChat?.title || this.provider.name,
4749
- this.instanceId,
4750
- this.cachedChat?.id || this.instanceId
4751
- );
5094
+ if (normalizedContent) {
5095
+ this.historyWriter.appendNewMessages(
5096
+ this.type,
5097
+ [{
5098
+ role: normalizedMessage.role,
5099
+ senderName: normalizedMessage.senderName,
5100
+ kind: normalizedMessage.kind,
5101
+ content: normalizedContent,
5102
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
5103
+ historyDedupKey: dedupKey
5104
+ }],
5105
+ this.cachedChat?.title || this.provider.name,
5106
+ this.instanceId,
5107
+ this.cachedChat?.id || this.instanceId
5108
+ );
5109
+ }
4752
5110
  }
4753
5111
  mergeConversationMessages(messages) {
4754
- if (this.runtimeMessages.length === 0) return messages;
4755
- return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
5112
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
5113
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
4756
5114
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
4757
5115
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
4758
5116
  if (aTime !== bTime) return aTime - bTime;
4759
5117
  return a.index - b.index;
4760
- }).map((entry) => entry.message);
5118
+ }).map((entry) => entry.message));
4761
5119
  }
4762
5120
  getPersistedEffectContent(effect) {
4763
5121
  if (effect.type === "message") {
@@ -5703,231 +6061,6 @@ var init_reconcile = __esm({
5703
6061
  }
5704
6062
  });
5705
6063
 
5706
- // ../../oss/packages/daemon-core/src/providers/io-contracts.ts
5707
- function normalizeInputEnvelope(input) {
5708
- const normalized = normalizeInputEnvelopePayload(input);
5709
- const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
5710
- return {
5711
- parts: normalized.parts,
5712
- textFallback,
5713
- ...normalized.metadata ? { metadata: normalized.metadata } : {}
5714
- };
5715
- }
5716
- function normalizeMessageParts(content) {
5717
- if (typeof content === "string") return [{ type: "text", text: content }];
5718
- if (!Array.isArray(content)) {
5719
- if (content && typeof content === "object" && typeof content.text === "string") {
5720
- return [{ type: "text", text: String(content.text) }];
5721
- }
5722
- return [];
5723
- }
5724
- const parts = [];
5725
- for (const raw of content) {
5726
- if (typeof raw === "string") {
5727
- parts.push({ type: "text", text: raw });
5728
- continue;
5729
- }
5730
- if (!raw || typeof raw !== "object") continue;
5731
- const part = normalizeMessagePartObject(raw);
5732
- if (part) parts.push(part);
5733
- }
5734
- return parts;
5735
- }
5736
- function flattenMessageParts(parts) {
5737
- return parts.map((part) => {
5738
- if (part.type === "text") return part.text;
5739
- if (part.type === "resource") return part.resource.text || "";
5740
- return "";
5741
- }).filter((value) => value.length > 0).join("\n");
5742
- }
5743
- function normalizeInputEnvelopePayload(input) {
5744
- if (typeof input === "string") {
5745
- return { parts: [{ type: "text", text: input }], textFallback: input };
5746
- }
5747
- if (!input || typeof input !== "object") {
5748
- return { parts: [], textFallback: "" };
5749
- }
5750
- const record2 = input;
5751
- const nestedInput = record2.input;
5752
- if (nestedInput && typeof nestedInput === "object") {
5753
- const nested = nestedInput;
5754
- return {
5755
- parts: normalizeInputParts(nested.parts ?? nested.prompt),
5756
- textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
5757
- metadata: normalizeInputMetadata(nested.metadata)
5758
- };
5759
- }
5760
- const directText = typeof record2.text === "string" ? record2.text : typeof record2.message === "string" ? record2.message : void 0;
5761
- if (directText !== void 0) {
5762
- return { parts: [{ type: "text", text: directText }], textFallback: directText };
5763
- }
5764
- const directParts = normalizeInputParts(record2.parts ?? record2.prompt);
5765
- return {
5766
- parts: directParts,
5767
- textFallback: typeof record2.textFallback === "string" ? record2.textFallback : void 0,
5768
- metadata: normalizeInputMetadata(record2.metadata)
5769
- };
5770
- }
5771
- function normalizeInputMetadata(value) {
5772
- if (!value || typeof value !== "object") return void 0;
5773
- const record2 = value;
5774
- const metadata = {};
5775
- if (record2.source === "dashboard" || record2.source === "shortcut_api" || record2.source === "provider_script" || record2.source === "session_replay") {
5776
- metadata.source = record2.source;
5777
- }
5778
- if (typeof record2.clientTimestamp === "number" && Number.isFinite(record2.clientTimestamp)) {
5779
- metadata.clientTimestamp = record2.clientTimestamp;
5780
- }
5781
- return Object.keys(metadata).length > 0 ? metadata : void 0;
5782
- }
5783
- function normalizeInputParts(value) {
5784
- if (!Array.isArray(value)) return [];
5785
- const parts = [];
5786
- for (const raw of value) {
5787
- if (typeof raw === "string") {
5788
- parts.push({ type: "text", text: raw });
5789
- continue;
5790
- }
5791
- if (!raw || typeof raw !== "object") continue;
5792
- const part = normalizeInputPartObject(raw);
5793
- if (part) parts.push(part);
5794
- }
5795
- return parts;
5796
- }
5797
- function normalizeInputPartObject(raw) {
5798
- const type = raw.type;
5799
- if (type === "text" && typeof raw.text === "string") {
5800
- return { type, text: raw.text };
5801
- }
5802
- if (type === "image" && typeof raw.mimeType === "string") {
5803
- return {
5804
- type,
5805
- mimeType: raw.mimeType,
5806
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5807
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5808
- ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
5809
- };
5810
- }
5811
- if (type === "audio" && typeof raw.mimeType === "string") {
5812
- return {
5813
- type,
5814
- mimeType: raw.mimeType,
5815
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5816
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5817
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5818
- };
5819
- }
5820
- if (type === "video" && typeof raw.mimeType === "string") {
5821
- return {
5822
- type,
5823
- mimeType: raw.mimeType,
5824
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5825
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5826
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5827
- };
5828
- }
5829
- if (type === "resource" && typeof raw.uri === "string") {
5830
- return {
5831
- type,
5832
- uri: raw.uri,
5833
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5834
- ...typeof raw.name === "string" ? { name: raw.name } : {},
5835
- ...typeof raw.text === "string" ? { text: raw.text } : {},
5836
- ...typeof raw.data === "string" ? { data: raw.data } : {}
5837
- };
5838
- }
5839
- if (type === "resource_link" && typeof raw.uri === "string") {
5840
- return {
5841
- type: "resource",
5842
- uri: raw.uri,
5843
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5844
- ...typeof raw.name === "string" ? { name: raw.name } : {}
5845
- };
5846
- }
5847
- return null;
5848
- }
5849
- function normalizeMessagePartObject(raw) {
5850
- const type = raw.type;
5851
- if (type === "text" && typeof raw.text === "string") {
5852
- return { type, text: raw.text };
5853
- }
5854
- if (type === "image" && typeof raw.mimeType === "string") {
5855
- return {
5856
- type,
5857
- mimeType: raw.mimeType,
5858
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5859
- ...typeof raw.data === "string" ? { data: raw.data } : {}
5860
- };
5861
- }
5862
- if (type === "audio" && typeof raw.mimeType === "string") {
5863
- return {
5864
- type,
5865
- mimeType: raw.mimeType,
5866
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5867
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5868
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5869
- };
5870
- }
5871
- if (type === "video" && typeof raw.mimeType === "string") {
5872
- return {
5873
- type,
5874
- mimeType: raw.mimeType,
5875
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5876
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5877
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5878
- };
5879
- }
5880
- if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
5881
- return {
5882
- type,
5883
- uri: raw.uri,
5884
- name: raw.name,
5885
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5886
- ...typeof raw.size === "number" ? { size: raw.size } : {}
5887
- };
5888
- }
5889
- if (type === "resource" && raw.resource && typeof raw.resource === "object") {
5890
- const resource = raw.resource;
5891
- if (typeof resource.uri !== "string") return null;
5892
- return {
5893
- type,
5894
- resource: {
5895
- uri: resource.uri,
5896
- ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
5897
- ...typeof resource.text === "string" ? { text: resource.text } : {},
5898
- ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
5899
- }
5900
- };
5901
- }
5902
- return null;
5903
- }
5904
- function flattenInputParts(parts) {
5905
- return parts.map((part) => {
5906
- if (part.type === "text") return part.text;
5907
- if (part.type === "audio") return part.transcript || "";
5908
- if (part.type === "resource") return part.text || "";
5909
- return "";
5910
- }).filter((value) => value.length > 0).join("\n");
5911
- }
5912
- var init_io_contracts = __esm({
5913
- "../../oss/packages/daemon-core/src/providers/io-contracts.ts"() {
5914
- "use strict";
5915
- }
5916
- });
5917
-
5918
- // ../../oss/packages/daemon-core/src/providers/contracts.ts
5919
- function flattenContent(content) {
5920
- if (typeof content === "string") return content;
5921
- return flattenMessageParts(normalizeMessageParts(content));
5922
- }
5923
- var init_contracts = __esm({
5924
- "../../oss/packages/daemon-core/src/providers/contracts.ts"() {
5925
- "use strict";
5926
- init_io_contracts();
5927
- init_io_contracts();
5928
- }
5929
- });
5930
-
5931
6064
  // ../../oss/packages/daemon-core/src/logging/debug-config.ts
5932
6065
  function normalizeCategories(categories) {
5933
6066
  if (!Array.isArray(categories)) return [];
@@ -6195,7 +6328,7 @@ function normalizeReadChatCursor(args) {
6195
6328
  }
6196
6329
  function normalizeReadChatMessages(payload) {
6197
6330
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
6198
- return messages;
6331
+ return normalizeChatMessages(messages);
6199
6332
  }
6200
6333
  function deriveHistoryDedupKey(message) {
6201
6334
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -7173,6 +7306,7 @@ var init_chat_commands = __esm({
7173
7306
  init_chat_history();
7174
7307
  init_logger();
7175
7308
  init_debug_trace();
7309
+ init_chat_message_normalization();
7176
7310
  RECENT_SEND_WINDOW_MS = 1200;
7177
7311
  recentSendByTarget = /* @__PURE__ */ new Map();
7178
7312
  }
@@ -10374,6 +10508,7 @@ function buildCliParseInput(options) {
10374
10508
  terminalScreenText,
10375
10509
  baseMessages,
10376
10510
  partialResponse,
10511
+ isWaitingForResponse,
10377
10512
  scope,
10378
10513
  runtimeSettings
10379
10514
  } = options;
@@ -10391,6 +10526,7 @@ function buildCliParseInput(options) {
10391
10526
  recentScreen: buildCliScreenSnapshot(recentBuffer),
10392
10527
  messages: [...baseMessages],
10393
10528
  partialResponse,
10529
+ isWaitingForResponse,
10394
10530
  promptText: scope?.prompt || "",
10395
10531
  settings: { ...runtimeSettings }
10396
10532
  };
@@ -10576,6 +10712,7 @@ var init_provider_cli_adapter = __esm({
10576
10712
  init_terminal_screen();
10577
10713
  init_pty_transport();
10578
10714
  init_provider_cli_shared();
10715
+ init_chat_message_normalization();
10579
10716
  init_provider_cli_parse();
10580
10717
  init_provider_cli_config();
10581
10718
  init_provider_cli_runtime();
@@ -11128,6 +11265,18 @@ var init_provider_cli_adapter = __esm({
11128
11265
  const holdMs = this.getStatusActivityHoldMs();
11129
11266
  return quietForMs < holdMs || screenStableMs < holdMs;
11130
11267
  }
11268
+ shouldDeferIdleTimeoutFinish() {
11269
+ if (!this.isWaitingForResponse || this.currentStatus === "waiting_approval") {
11270
+ return false;
11271
+ }
11272
+ const latestStatus = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
11273
+ if (latestStatus === "generating") {
11274
+ this.settledBuffer = this.recentOutputBuffer;
11275
+ this.evaluateSettled();
11276
+ return true;
11277
+ }
11278
+ return false;
11279
+ }
11131
11280
  getStartupConfirmationModal(screenText) {
11132
11281
  const text = sanitizeTerminalText(String(screenText || ""));
11133
11282
  if (!text.trim()) return null;
@@ -11286,6 +11435,7 @@ var init_provider_cli_adapter = __esm({
11286
11435
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
11287
11436
  this.idleTimeout = setTimeout(() => {
11288
11437
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
11438
+ if (this.shouldDeferIdleTimeoutFinish()) return;
11289
11439
  this.finishResponse();
11290
11440
  }
11291
11441
  }, this.timeouts.generatingIdle);
@@ -11321,6 +11471,7 @@ var init_provider_cli_adapter = __esm({
11321
11471
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
11322
11472
  this.idleTimeout = setTimeout(() => {
11323
11473
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
11474
+ if (this.shouldDeferIdleTimeoutFinish()) return;
11324
11475
  this.finishResponse();
11325
11476
  }
11326
11477
  }, this.timeouts.generatingIdle);
@@ -11363,7 +11514,10 @@ var init_provider_cli_adapter = __esm({
11363
11514
  this.setStatus("generating", "script_detect");
11364
11515
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
11365
11516
  this.idleTimeout = setTimeout(() => {
11366
- if (this.isWaitingForResponse) this.finishResponse();
11517
+ if (this.isWaitingForResponse) {
11518
+ if (this.shouldDeferIdleTimeoutFinish()) return;
11519
+ this.finishResponse();
11520
+ }
11367
11521
  }, this.timeouts.generatingIdle);
11368
11522
  this.onStatusChange?.();
11369
11523
  return;
@@ -11431,6 +11585,7 @@ var init_provider_cli_adapter = __esm({
11431
11585
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
11432
11586
  this.idleTimeout = setTimeout(() => {
11433
11587
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
11588
+ if (this.shouldDeferIdleTimeoutFinish()) return;
11434
11589
  this.clearIdleFinishCandidate("idle_timeout_finish");
11435
11590
  this.finishResponse();
11436
11591
  }
@@ -11569,6 +11724,7 @@ var init_provider_cli_adapter = __esm({
11569
11724
  tail: text.slice(-500),
11570
11725
  screenText,
11571
11726
  rawBuffer: this.accumulatedRawBuffer,
11727
+ isWaitingForResponse: this.isWaitingForResponse,
11572
11728
  screen: buildCliScreenSnapshot(screenText),
11573
11729
  tailScreen: buildCliScreenSnapshot(text.slice(-500))
11574
11730
  });
@@ -11633,11 +11789,10 @@ var init_provider_cli_adapter = __esm({
11633
11789
  );
11634
11790
  const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
11635
11791
  if (parsed && Array.isArray(parsed.messages)) {
11636
- const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => ({
11792
+ const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
11637
11793
  ...message,
11638
11794
  id: message.id || `msg_${index}`,
11639
11795
  index: typeof message.index === "number" ? message.index : index,
11640
- kind: message.kind || "standard",
11641
11796
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
11642
11797
  })) : hydrateCliParsedMessages(parsed.messages, {
11643
11798
  committedMessages: this.committedMessages,
@@ -11658,13 +11813,11 @@ var init_provider_cli_adapter = __esm({
11658
11813
  id: "cli_session",
11659
11814
  status: this.currentStatus,
11660
11815
  title: this.cliName,
11661
- messages: messages.slice(-50).map((message, index) => ({
11662
- id: `msg_${index}`,
11663
- role: message.role,
11664
- content: message.content,
11665
- timestamp: message.timestamp,
11666
- index,
11667
- kind: "standard"
11816
+ messages: messages.slice(-50).map((message, index) => buildChatMessage({
11817
+ ...message,
11818
+ id: message.id || `msg_${index}`,
11819
+ index: typeof message.index === "number" ? message.index : index,
11820
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
11668
11821
  })),
11669
11822
  activeModal: this.activeModal
11670
11823
  };
@@ -11681,6 +11834,7 @@ var init_provider_cli_adapter = __esm({
11681
11834
  terminalScreenText: this.terminalScreen.getText(),
11682
11835
  baseMessages: this.committedMessages,
11683
11836
  partialResponse: this.responseBuffer,
11837
+ isWaitingForResponse: this.isWaitingForResponse,
11684
11838
  scope: this.currentTurnScope,
11685
11839
  runtimeSettings: this.runtimeSettings
11686
11840
  });
@@ -11699,6 +11853,7 @@ var init_provider_cli_adapter = __esm({
11699
11853
  terminalScreenText: this.terminalScreen.getText(),
11700
11854
  baseMessages,
11701
11855
  partialResponse,
11856
+ isWaitingForResponse: this.isWaitingForResponse,
11702
11857
  scope,
11703
11858
  runtimeSettings: this.runtimeSettings
11704
11859
  });
@@ -12347,6 +12502,7 @@ var init_cli_provider_instance = __esm({
12347
12502
  init_approval_utils();
12348
12503
  init_cli_script_results();
12349
12504
  init_provider_patch_state();
12505
+ init_chat_message_normalization();
12350
12506
  CachedDatabaseSync = null;
12351
12507
  CliProviderInstance = class {
12352
12508
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
@@ -12797,8 +12953,8 @@ var init_cli_provider_instance = __esm({
12797
12953
  if (this.appliedEffectKeys.has(effectKey)) continue;
12798
12954
  this.appliedEffectKeys.add(effectKey);
12799
12955
  if (effect.persist !== false) {
12800
- const persisted = this.getPersistedEffectContent(effect);
12801
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
12956
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
12957
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
12802
12958
  }
12803
12959
  if (effect.type === "message" && effect.message) {
12804
12960
  const content = typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content);
@@ -12922,44 +13078,53 @@ ${effect.notification.body || ""}`.trim();
12922
13078
  );
12923
13079
  }
12924
13080
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
12925
- const normalizedContent = String(content || "").trim();
12926
- if (!normalizedContent) return;
13081
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
13082
+ content,
13083
+ receivedAt,
13084
+ timestamp: receivedAt
13085
+ }), dedupKey);
13086
+ }
13087
+ appendRuntimeMessage(message, dedupKey) {
13088
+ const normalizedMessage = buildChatMessage({
13089
+ ...message,
13090
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
13091
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
13092
+ });
13093
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
13094
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
12927
13095
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
12928
13096
  this.runtimeMessages.push({
12929
13097
  key: dedupKey,
12930
- message: {
12931
- role: "system",
12932
- senderName: "System",
12933
- content: normalizedContent,
12934
- receivedAt,
12935
- timestamp: receivedAt
12936
- }
13098
+ message: normalizedMessage
12937
13099
  });
12938
13100
  if (this.runtimeMessages.length > 50) {
12939
13101
  this.runtimeMessages = this.runtimeMessages.slice(-50);
12940
13102
  }
12941
- this.historyWriter.appendNewMessages(
12942
- this.type,
12943
- [{
12944
- role: "system",
12945
- senderName: "System",
12946
- content: normalizedContent,
12947
- receivedAt,
12948
- historyDedupKey: dedupKey
12949
- }],
12950
- this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
12951
- this.instanceId,
12952
- this.providerSessionId
12953
- );
13103
+ if (normalizedContent) {
13104
+ this.historyWriter.appendNewMessages(
13105
+ this.type,
13106
+ [{
13107
+ role: normalizedMessage.role,
13108
+ senderName: normalizedMessage.senderName,
13109
+ kind: normalizedMessage.kind,
13110
+ content: normalizedContent,
13111
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
13112
+ historyDedupKey: dedupKey
13113
+ }],
13114
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
13115
+ this.instanceId,
13116
+ this.providerSessionId
13117
+ );
13118
+ }
12954
13119
  }
12955
13120
  mergeConversationMessages(parsedMessages) {
12956
- if (this.runtimeMessages.length === 0) return parsedMessages;
12957
- return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
13121
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
13122
+ return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
12958
13123
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
12959
13124
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
12960
13125
  if (aTime !== bTime) return aTime - bTime;
12961
13126
  return a.index - b.index;
12962
- }).map((entry) => entry.message);
13127
+ }).map((entry) => entry.message));
12963
13128
  }
12964
13129
  formatApprovalRequestMessage(modalMessage, buttons) {
12965
13130
  const lines = ["Approval requested"];
@@ -29435,6 +29600,7 @@ var init_acp_provider_instance = __esm({
29435
29600
  init_contracts();
29436
29601
  init_status_monitor();
29437
29602
  init_summary_metadata();
29603
+ init_chat_message_normalization();
29438
29604
  init_logger();
29439
29605
  AcpProviderInstance = class {
29440
29606
  constructor(provider, workingDir, cliArgs = []) {
@@ -29505,24 +29671,21 @@ var init_acp_provider_instance = __esm({
29505
29671
  }
29506
29672
  getState() {
29507
29673
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
29508
- const recentMessages = this.messages.slice(-50).map((m) => {
29674
+ const recentMessages = normalizeChatMessages(this.messages.slice(-50).map((m) => {
29509
29675
  const content = this.truncateContent(m.content);
29510
- return {
29511
- role: m.role,
29512
- content,
29513
- timestamp: m.timestamp,
29514
- toolCalls: m.toolCalls
29515
- };
29516
- });
29676
+ return buildChatMessage({
29677
+ ...m,
29678
+ content
29679
+ });
29680
+ }));
29517
29681
  if (this.currentStatus === "generating" && (this.partialContent || this.partialBlocks.length > 0)) {
29518
29682
  const blocks = this.buildPartialBlocks();
29519
29683
  if (blocks.length > 0) {
29520
- recentMessages.push({
29521
- role: "assistant",
29684
+ recentMessages.push(buildAssistantChatMessage({
29522
29685
  content: blocks,
29523
29686
  timestamp: Date.now(),
29524
29687
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
29525
- });
29688
+ }));
29526
29689
  }
29527
29690
  }
29528
29691
  return {
@@ -29535,7 +29698,7 @@ var init_acp_provider_instance = __esm({
29535
29698
  id: this.sessionId || `${this.type}_${this.workingDir}`,
29536
29699
  title: `${this.provider.name} \xB7 ${dirName}`,
29537
29700
  status: this.currentStatus,
29538
- messages: recentMessages,
29701
+ messages: normalizeChatMessages(recentMessages),
29539
29702
  activeModal: this.currentStatus === "waiting_approval" ? {
29540
29703
  message: this.activeToolCalls.find((t) => t.status === "running")?.name || "Permission requested",
29541
29704
  buttons: ["Approve", "Reject"]
@@ -30067,11 +30230,10 @@ var init_acp_provider_instance = __esm({
30067
30230
  if (b.type === "resource") return { type: "resource", resource: b.resource };
30068
30231
  return { type: "text", text: flattenContent([b]) };
30069
30232
  }) : [{ type: "text", text }];
30070
- this.messages.push({
30071
- role: "user",
30233
+ this.messages.push(buildUserChatMessage({
30072
30234
  content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
30073
30235
  timestamp: Date.now()
30074
- });
30236
+ }));
30075
30237
  this.currentStatus = "generating";
30076
30238
  this.partialContent = "";
30077
30239
  this.partialBlocks = [];
@@ -30241,11 +30403,11 @@ var init_acp_provider_instance = __esm({
30241
30403
  content = m.content.filter((p) => p.type === "text").map((p) => p.text || "").join("\n");
30242
30404
  }
30243
30405
  if (content.trim()) {
30244
- this.messages.push({
30406
+ this.messages.push(buildChatMessage({
30245
30407
  role: m.role || "assistant",
30246
30408
  content: content.trim(),
30247
30409
  timestamp: Date.now()
30248
- });
30410
+ }));
30249
30411
  this.partialContent = "";
30250
30412
  }
30251
30413
  }
@@ -30321,12 +30483,11 @@ var init_acp_provider_instance = __esm({
30321
30483
  return b;
30322
30484
  }).filter((b) => b.type !== "text" || b.type === "text" && b.text.trim());
30323
30485
  if (finalBlocks.length > 0) {
30324
- this.messages.push({
30325
- role: "assistant",
30486
+ this.messages.push(buildAssistantChatMessage({
30326
30487
  content: finalBlocks.length === 1 && finalBlocks[0].type === "text" ? finalBlocks[0].text : finalBlocks,
30327
30488
  timestamp: Date.now(),
30328
30489
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
30329
- });
30490
+ }));
30330
30491
  }
30331
30492
  this.partialContent = "";
30332
30493
  this.partialBlocks = [];
@@ -30386,11 +30547,10 @@ var init_acp_provider_instance = __esm({
30386
30547
  appendSystemMessage(content, timestamp = Date.now()) {
30387
30548
  const normalizedContent = String(content || "").trim();
30388
30549
  if (!normalizedContent) return;
30389
- this.messages.push({
30390
- role: "system",
30550
+ this.messages.push(buildRuntimeSystemChatMessage({
30391
30551
  content: normalizedContent,
30392
30552
  timestamp
30393
- });
30553
+ }));
30394
30554
  if (this.messages.length > 200) {
30395
30555
  this.messages = this.messages.slice(-100);
30396
30556
  }
@@ -36943,6 +37103,7 @@ var init_poller = __esm({
36943
37103
  init_reconcile();
36944
37104
  init_logger();
36945
37105
  init_approval_utils();
37106
+ init_chat_message_normalization();
36946
37107
  AgentStreamPoller = class {
36947
37108
  deps;
36948
37109
  timer = null;
@@ -37098,12 +37259,9 @@ var init_poller = __esm({
37098
37259
  type: "message",
37099
37260
  id: effectId,
37100
37261
  persist: true,
37101
- message: {
37102
- role: "system",
37103
- senderName: "System",
37104
- kind: "system",
37262
+ message: buildRuntimeSystemChatMessage({
37105
37263
  content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
37106
- }
37264
+ })
37107
37265
  }
37108
37266
  ]
37109
37267
  };
@@ -43742,6 +43900,7 @@ var src_exports = {};
43742
43900
  __export(src_exports, {
43743
43901
  AcpProviderInstance: () => AcpProviderInstance,
43744
43902
  AgentStreamPoller: () => AgentStreamPoller,
43903
+ BUILTIN_CHAT_MESSAGE_KINDS: () => BUILTIN_CHAT_MESSAGE_KINDS,
43745
43904
  CdpDomHandlers: () => CdpDomHandlers,
43746
43905
  CliProviderInstance: () => CliProviderInstance,
43747
43906
  DAEMON_WS_PATH: () => DAEMON_WS_PATH,
@@ -43766,9 +43925,14 @@ __export(src_exports, {
43766
43925
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
43767
43926
  VersionArchive: () => VersionArchive,
43768
43927
  appendRecentActivity: () => appendRecentActivity,
43928
+ buildAssistantChatMessage: () => buildAssistantChatMessage,
43929
+ buildChatMessage: () => buildChatMessage,
43769
43930
  buildMachineInfo: () => buildMachineInfo,
43931
+ buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
43770
43932
  buildSessionEntries: () => buildSessionEntries,
43771
43933
  buildStatusSnapshot: () => buildStatusSnapshot,
43934
+ buildSystemChatMessage: () => buildSystemChatMessage,
43935
+ buildUserChatMessage: () => buildUserChatMessage,
43772
43936
  clearDebugTrace: () => clearDebugTrace,
43773
43937
  configureDebugTraceStore: () => configureDebugTraceStore,
43774
43938
  connectCdpManager: () => connectCdpManager,
@@ -43800,6 +43964,7 @@ __export(src_exports, {
43800
43964
  initDaemonComponents: () => initDaemonComponents,
43801
43965
  installExtensions: () => installExtensions,
43802
43966
  installGlobalInterceptor: () => installGlobalInterceptor,
43967
+ isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
43803
43968
  isCdpConnected: () => isCdpConnected,
43804
43969
  isExtensionInstalled: () => isExtensionInstalled,
43805
43970
  isIdeRunning: () => isIdeRunning,
@@ -43818,6 +43983,9 @@ __export(src_exports, {
43818
43983
  markSetupComplete: () => markSetupComplete,
43819
43984
  maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv,
43820
43985
  normalizeActiveChatData: () => normalizeActiveChatData,
43986
+ normalizeChatMessage: () => normalizeChatMessage,
43987
+ normalizeChatMessageKind: () => normalizeChatMessageKind,
43988
+ normalizeChatMessages: () => normalizeChatMessages,
43821
43989
  normalizeInputEnvelope: () => normalizeInputEnvelope,
43822
43990
  normalizeManagedStatus: () => normalizeManagedStatus,
43823
43991
  normalizeMessageParts: () => normalizeMessageParts,
@@ -43887,6 +44055,7 @@ var init_src = __esm({
43887
44055
  init_acp_provider_instance();
43888
44056
  init_provider_source_config();
43889
44057
  init_io_contracts();
44058
+ init_chat_message_normalization();
43890
44059
  init_version_archive();
43891
44060
  init_dev_server();
43892
44061
  init_provider_cli_adapter();
@@ -83957,7 +84126,7 @@ var init_adhdev_daemon = __esm({
83957
84126
  import_ws3 = require("ws");
83958
84127
  init_source();
83959
84128
  init_version();
83960
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.60" });
84129
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.63" });
83961
84130
  ACTIVE_CHAT_POLL_STATUSES = /* @__PURE__ */ new Set([
83962
84131
  "generating",
83963
84132
  "waiting_approval",