adhdev 0.8.60 → 0.8.61

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
  }
@@ -10576,6 +10710,7 @@ var init_provider_cli_adapter = __esm({
10576
10710
  init_terminal_screen();
10577
10711
  init_pty_transport();
10578
10712
  init_provider_cli_shared();
10713
+ init_chat_message_normalization();
10579
10714
  init_provider_cli_parse();
10580
10715
  init_provider_cli_config();
10581
10716
  init_provider_cli_runtime();
@@ -11633,11 +11768,10 @@ var init_provider_cli_adapter = __esm({
11633
11768
  );
11634
11769
  const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
11635
11770
  if (parsed && Array.isArray(parsed.messages)) {
11636
- const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => ({
11771
+ const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
11637
11772
  ...message,
11638
11773
  id: message.id || `msg_${index}`,
11639
11774
  index: typeof message.index === "number" ? message.index : index,
11640
- kind: message.kind || "standard",
11641
11775
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
11642
11776
  })) : hydrateCliParsedMessages(parsed.messages, {
11643
11777
  committedMessages: this.committedMessages,
@@ -11658,13 +11792,11 @@ var init_provider_cli_adapter = __esm({
11658
11792
  id: "cli_session",
11659
11793
  status: this.currentStatus,
11660
11794
  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"
11795
+ messages: messages.slice(-50).map((message, index) => buildChatMessage({
11796
+ ...message,
11797
+ id: message.id || `msg_${index}`,
11798
+ index: typeof message.index === "number" ? message.index : index,
11799
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
11668
11800
  })),
11669
11801
  activeModal: this.activeModal
11670
11802
  };
@@ -12347,6 +12479,7 @@ var init_cli_provider_instance = __esm({
12347
12479
  init_approval_utils();
12348
12480
  init_cli_script_results();
12349
12481
  init_provider_patch_state();
12482
+ init_chat_message_normalization();
12350
12483
  CachedDatabaseSync = null;
12351
12484
  CliProviderInstance = class {
12352
12485
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
@@ -12797,8 +12930,8 @@ var init_cli_provider_instance = __esm({
12797
12930
  if (this.appliedEffectKeys.has(effectKey)) continue;
12798
12931
  this.appliedEffectKeys.add(effectKey);
12799
12932
  if (effect.persist !== false) {
12800
- const persisted = this.getPersistedEffectContent(effect);
12801
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
12933
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
12934
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
12802
12935
  }
12803
12936
  if (effect.type === "message" && effect.message) {
12804
12937
  const content = typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content);
@@ -12922,44 +13055,53 @@ ${effect.notification.body || ""}`.trim();
12922
13055
  );
12923
13056
  }
12924
13057
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
12925
- const normalizedContent = String(content || "").trim();
12926
- if (!normalizedContent) return;
13058
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
13059
+ content,
13060
+ receivedAt,
13061
+ timestamp: receivedAt
13062
+ }), dedupKey);
13063
+ }
13064
+ appendRuntimeMessage(message, dedupKey) {
13065
+ const normalizedMessage = buildChatMessage({
13066
+ ...message,
13067
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
13068
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
13069
+ });
13070
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
13071
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
12927
13072
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
12928
13073
  this.runtimeMessages.push({
12929
13074
  key: dedupKey,
12930
- message: {
12931
- role: "system",
12932
- senderName: "System",
12933
- content: normalizedContent,
12934
- receivedAt,
12935
- timestamp: receivedAt
12936
- }
13075
+ message: normalizedMessage
12937
13076
  });
12938
13077
  if (this.runtimeMessages.length > 50) {
12939
13078
  this.runtimeMessages = this.runtimeMessages.slice(-50);
12940
13079
  }
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
- );
13080
+ if (normalizedContent) {
13081
+ this.historyWriter.appendNewMessages(
13082
+ this.type,
13083
+ [{
13084
+ role: normalizedMessage.role,
13085
+ senderName: normalizedMessage.senderName,
13086
+ kind: normalizedMessage.kind,
13087
+ content: normalizedContent,
13088
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
13089
+ historyDedupKey: dedupKey
13090
+ }],
13091
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
13092
+ this.instanceId,
13093
+ this.providerSessionId
13094
+ );
13095
+ }
12954
13096
  }
12955
13097
  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) => {
13098
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
13099
+ return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
12958
13100
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
12959
13101
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
12960
13102
  if (aTime !== bTime) return aTime - bTime;
12961
13103
  return a.index - b.index;
12962
- }).map((entry) => entry.message);
13104
+ }).map((entry) => entry.message));
12963
13105
  }
12964
13106
  formatApprovalRequestMessage(modalMessage, buttons) {
12965
13107
  const lines = ["Approval requested"];
@@ -29435,6 +29577,7 @@ var init_acp_provider_instance = __esm({
29435
29577
  init_contracts();
29436
29578
  init_status_monitor();
29437
29579
  init_summary_metadata();
29580
+ init_chat_message_normalization();
29438
29581
  init_logger();
29439
29582
  AcpProviderInstance = class {
29440
29583
  constructor(provider, workingDir, cliArgs = []) {
@@ -29505,24 +29648,21 @@ var init_acp_provider_instance = __esm({
29505
29648
  }
29506
29649
  getState() {
29507
29650
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
29508
- const recentMessages = this.messages.slice(-50).map((m) => {
29651
+ const recentMessages = normalizeChatMessages(this.messages.slice(-50).map((m) => {
29509
29652
  const content = this.truncateContent(m.content);
29510
- return {
29511
- role: m.role,
29512
- content,
29513
- timestamp: m.timestamp,
29514
- toolCalls: m.toolCalls
29515
- };
29516
- });
29653
+ return buildChatMessage({
29654
+ ...m,
29655
+ content
29656
+ });
29657
+ }));
29517
29658
  if (this.currentStatus === "generating" && (this.partialContent || this.partialBlocks.length > 0)) {
29518
29659
  const blocks = this.buildPartialBlocks();
29519
29660
  if (blocks.length > 0) {
29520
- recentMessages.push({
29521
- role: "assistant",
29661
+ recentMessages.push(buildAssistantChatMessage({
29522
29662
  content: blocks,
29523
29663
  timestamp: Date.now(),
29524
29664
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
29525
- });
29665
+ }));
29526
29666
  }
29527
29667
  }
29528
29668
  return {
@@ -29535,7 +29675,7 @@ var init_acp_provider_instance = __esm({
29535
29675
  id: this.sessionId || `${this.type}_${this.workingDir}`,
29536
29676
  title: `${this.provider.name} \xB7 ${dirName}`,
29537
29677
  status: this.currentStatus,
29538
- messages: recentMessages,
29678
+ messages: normalizeChatMessages(recentMessages),
29539
29679
  activeModal: this.currentStatus === "waiting_approval" ? {
29540
29680
  message: this.activeToolCalls.find((t) => t.status === "running")?.name || "Permission requested",
29541
29681
  buttons: ["Approve", "Reject"]
@@ -30067,11 +30207,10 @@ var init_acp_provider_instance = __esm({
30067
30207
  if (b.type === "resource") return { type: "resource", resource: b.resource };
30068
30208
  return { type: "text", text: flattenContent([b]) };
30069
30209
  }) : [{ type: "text", text }];
30070
- this.messages.push({
30071
- role: "user",
30210
+ this.messages.push(buildUserChatMessage({
30072
30211
  content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
30073
30212
  timestamp: Date.now()
30074
- });
30213
+ }));
30075
30214
  this.currentStatus = "generating";
30076
30215
  this.partialContent = "";
30077
30216
  this.partialBlocks = [];
@@ -30241,11 +30380,11 @@ var init_acp_provider_instance = __esm({
30241
30380
  content = m.content.filter((p) => p.type === "text").map((p) => p.text || "").join("\n");
30242
30381
  }
30243
30382
  if (content.trim()) {
30244
- this.messages.push({
30383
+ this.messages.push(buildChatMessage({
30245
30384
  role: m.role || "assistant",
30246
30385
  content: content.trim(),
30247
30386
  timestamp: Date.now()
30248
- });
30387
+ }));
30249
30388
  this.partialContent = "";
30250
30389
  }
30251
30390
  }
@@ -30321,12 +30460,11 @@ var init_acp_provider_instance = __esm({
30321
30460
  return b;
30322
30461
  }).filter((b) => b.type !== "text" || b.type === "text" && b.text.trim());
30323
30462
  if (finalBlocks.length > 0) {
30324
- this.messages.push({
30325
- role: "assistant",
30463
+ this.messages.push(buildAssistantChatMessage({
30326
30464
  content: finalBlocks.length === 1 && finalBlocks[0].type === "text" ? finalBlocks[0].text : finalBlocks,
30327
30465
  timestamp: Date.now(),
30328
30466
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
30329
- });
30467
+ }));
30330
30468
  }
30331
30469
  this.partialContent = "";
30332
30470
  this.partialBlocks = [];
@@ -30386,11 +30524,10 @@ var init_acp_provider_instance = __esm({
30386
30524
  appendSystemMessage(content, timestamp = Date.now()) {
30387
30525
  const normalizedContent = String(content || "").trim();
30388
30526
  if (!normalizedContent) return;
30389
- this.messages.push({
30390
- role: "system",
30527
+ this.messages.push(buildRuntimeSystemChatMessage({
30391
30528
  content: normalizedContent,
30392
30529
  timestamp
30393
- });
30530
+ }));
30394
30531
  if (this.messages.length > 200) {
30395
30532
  this.messages = this.messages.slice(-100);
30396
30533
  }
@@ -36943,6 +37080,7 @@ var init_poller = __esm({
36943
37080
  init_reconcile();
36944
37081
  init_logger();
36945
37082
  init_approval_utils();
37083
+ init_chat_message_normalization();
36946
37084
  AgentStreamPoller = class {
36947
37085
  deps;
36948
37086
  timer = null;
@@ -37098,12 +37236,9 @@ var init_poller = __esm({
37098
37236
  type: "message",
37099
37237
  id: effectId,
37100
37238
  persist: true,
37101
- message: {
37102
- role: "system",
37103
- senderName: "System",
37104
- kind: "system",
37239
+ message: buildRuntimeSystemChatMessage({
37105
37240
  content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
37106
- }
37241
+ })
37107
37242
  }
37108
37243
  ]
37109
37244
  };
@@ -43742,6 +43877,7 @@ var src_exports = {};
43742
43877
  __export(src_exports, {
43743
43878
  AcpProviderInstance: () => AcpProviderInstance,
43744
43879
  AgentStreamPoller: () => AgentStreamPoller,
43880
+ BUILTIN_CHAT_MESSAGE_KINDS: () => BUILTIN_CHAT_MESSAGE_KINDS,
43745
43881
  CdpDomHandlers: () => CdpDomHandlers,
43746
43882
  CliProviderInstance: () => CliProviderInstance,
43747
43883
  DAEMON_WS_PATH: () => DAEMON_WS_PATH,
@@ -43766,9 +43902,14 @@ __export(src_exports, {
43766
43902
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
43767
43903
  VersionArchive: () => VersionArchive,
43768
43904
  appendRecentActivity: () => appendRecentActivity,
43905
+ buildAssistantChatMessage: () => buildAssistantChatMessage,
43906
+ buildChatMessage: () => buildChatMessage,
43769
43907
  buildMachineInfo: () => buildMachineInfo,
43908
+ buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
43770
43909
  buildSessionEntries: () => buildSessionEntries,
43771
43910
  buildStatusSnapshot: () => buildStatusSnapshot,
43911
+ buildSystemChatMessage: () => buildSystemChatMessage,
43912
+ buildUserChatMessage: () => buildUserChatMessage,
43772
43913
  clearDebugTrace: () => clearDebugTrace,
43773
43914
  configureDebugTraceStore: () => configureDebugTraceStore,
43774
43915
  connectCdpManager: () => connectCdpManager,
@@ -43800,6 +43941,7 @@ __export(src_exports, {
43800
43941
  initDaemonComponents: () => initDaemonComponents,
43801
43942
  installExtensions: () => installExtensions,
43802
43943
  installGlobalInterceptor: () => installGlobalInterceptor,
43944
+ isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
43803
43945
  isCdpConnected: () => isCdpConnected,
43804
43946
  isExtensionInstalled: () => isExtensionInstalled,
43805
43947
  isIdeRunning: () => isIdeRunning,
@@ -43818,6 +43960,9 @@ __export(src_exports, {
43818
43960
  markSetupComplete: () => markSetupComplete,
43819
43961
  maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv,
43820
43962
  normalizeActiveChatData: () => normalizeActiveChatData,
43963
+ normalizeChatMessage: () => normalizeChatMessage,
43964
+ normalizeChatMessageKind: () => normalizeChatMessageKind,
43965
+ normalizeChatMessages: () => normalizeChatMessages,
43821
43966
  normalizeInputEnvelope: () => normalizeInputEnvelope,
43822
43967
  normalizeManagedStatus: () => normalizeManagedStatus,
43823
43968
  normalizeMessageParts: () => normalizeMessageParts,
@@ -43887,6 +44032,7 @@ var init_src = __esm({
43887
44032
  init_acp_provider_instance();
43888
44033
  init_provider_source_config();
43889
44034
  init_io_contracts();
44035
+ init_chat_message_normalization();
43890
44036
  init_version_archive();
43891
44037
  init_dev_server();
43892
44038
  init_provider_cli_adapter();
@@ -83957,7 +84103,7 @@ var init_adhdev_daemon = __esm({
83957
84103
  import_ws3 = require("ws");
83958
84104
  init_source();
83959
84105
  init_version();
83960
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.60" });
84106
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.61" });
83961
84107
  ACTIVE_CHAT_POLL_STATUSES = /* @__PURE__ */ new Set([
83962
84108
  "generating",
83963
84109
  "waiting_approval",