@adhdev/daemon-core 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/index.mjs CHANGED
@@ -453,6 +453,64 @@ var init_logger = __esm({
453
453
  }
454
454
  });
455
455
 
456
+ // src/providers/chat-message-normalization.ts
457
+ function isBuiltinChatMessageKind(kind) {
458
+ return typeof kind === "string" && KNOWN_CHAT_MESSAGE_KINDS.has(kind.trim().toLowerCase());
459
+ }
460
+ function normalizeChatMessageKind(kind, role) {
461
+ const normalizedKind = typeof kind === "string" ? kind.trim().toLowerCase() : "";
462
+ if (normalizedKind && KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
463
+ const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
464
+ return normalizedRole === "system" ? "system" : "standard";
465
+ }
466
+ function buildChatMessage(message) {
467
+ return {
468
+ ...message,
469
+ kind: normalizeChatMessageKind(message?.kind, message?.role)
470
+ };
471
+ }
472
+ function buildSystemChatMessage(message) {
473
+ return buildChatMessage({
474
+ ...message,
475
+ role: "system",
476
+ kind: message?.kind || "system"
477
+ });
478
+ }
479
+ function buildRuntimeSystemChatMessage(message) {
480
+ return buildSystemChatMessage({
481
+ ...message,
482
+ senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
483
+ });
484
+ }
485
+ function buildAssistantChatMessage(message) {
486
+ return buildChatMessage({
487
+ ...message,
488
+ role: "assistant",
489
+ kind: message?.kind || "standard"
490
+ });
491
+ }
492
+ function buildUserChatMessage(message) {
493
+ return buildChatMessage({
494
+ ...message,
495
+ role: "user",
496
+ kind: message?.kind || "standard"
497
+ });
498
+ }
499
+ function normalizeChatMessage(message) {
500
+ return buildChatMessage(message);
501
+ }
502
+ function normalizeChatMessages(messages) {
503
+ return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
504
+ }
505
+ var BUILTIN_CHAT_MESSAGE_KINDS, KNOWN_CHAT_MESSAGE_KINDS;
506
+ var init_chat_message_normalization = __esm({
507
+ "src/providers/chat-message-normalization.ts"() {
508
+ "use strict";
509
+ BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
510
+ KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
511
+ }
512
+ });
513
+
456
514
  // src/cli-adapters/terminal-backends/ghostty-vt-backend.ts
457
515
  function isModuleNotFoundError(error, ref) {
458
516
  if (!(error instanceof Error)) return false;
@@ -1307,6 +1365,7 @@ var init_provider_cli_adapter = __esm({
1307
1365
  init_terminal_screen();
1308
1366
  init_pty_transport();
1309
1367
  init_provider_cli_shared();
1368
+ init_chat_message_normalization();
1310
1369
  init_provider_cli_parse();
1311
1370
  init_provider_cli_config();
1312
1371
  init_provider_cli_runtime();
@@ -2364,11 +2423,10 @@ var init_provider_cli_adapter = __esm({
2364
2423
  );
2365
2424
  const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
2366
2425
  if (parsed && Array.isArray(parsed.messages)) {
2367
- const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => ({
2426
+ const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
2368
2427
  ...message,
2369
2428
  id: message.id || `msg_${index}`,
2370
2429
  index: typeof message.index === "number" ? message.index : index,
2371
- kind: message.kind || "standard",
2372
2430
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2373
2431
  })) : hydrateCliParsedMessages(parsed.messages, {
2374
2432
  committedMessages: this.committedMessages,
@@ -2389,13 +2447,11 @@ var init_provider_cli_adapter = __esm({
2389
2447
  id: "cli_session",
2390
2448
  status: this.currentStatus,
2391
2449
  title: this.cliName,
2392
- messages: messages.slice(-50).map((message, index) => ({
2393
- id: `msg_${index}`,
2394
- role: message.role,
2395
- content: message.content,
2396
- timestamp: message.timestamp,
2397
- index,
2398
- kind: "standard"
2450
+ messages: messages.slice(-50).map((message, index) => buildChatMessage({
2451
+ ...message,
2452
+ id: message.id || `msg_${index}`,
2453
+ index: typeof message.index === "number" ? message.index : index,
2454
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2399
2455
  })),
2400
2456
  activeModal: this.activeModal
2401
2457
  };
@@ -4993,6 +5049,219 @@ var CdpDomHandlers = class {
4993
5049
  // src/providers/ide-provider-instance.ts
4994
5050
  import * as crypto2 from "crypto";
4995
5051
 
5052
+ // src/providers/io-contracts.ts
5053
+ function normalizeInputEnvelope(input) {
5054
+ const normalized = normalizeInputEnvelopePayload(input);
5055
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
5056
+ return {
5057
+ parts: normalized.parts,
5058
+ textFallback,
5059
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
5060
+ };
5061
+ }
5062
+ function normalizeMessageParts(content) {
5063
+ if (typeof content === "string") return [{ type: "text", text: content }];
5064
+ if (!Array.isArray(content)) {
5065
+ if (content && typeof content === "object" && typeof content.text === "string") {
5066
+ return [{ type: "text", text: String(content.text) }];
5067
+ }
5068
+ return [];
5069
+ }
5070
+ const parts = [];
5071
+ for (const raw of content) {
5072
+ if (typeof raw === "string") {
5073
+ parts.push({ type: "text", text: raw });
5074
+ continue;
5075
+ }
5076
+ if (!raw || typeof raw !== "object") continue;
5077
+ const part = normalizeMessagePartObject(raw);
5078
+ if (part) parts.push(part);
5079
+ }
5080
+ return parts;
5081
+ }
5082
+ function flattenMessageParts(parts) {
5083
+ return parts.map((part) => {
5084
+ if (part.type === "text") return part.text;
5085
+ if (part.type === "resource") return part.resource.text || "";
5086
+ return "";
5087
+ }).filter((value) => value.length > 0).join("\n");
5088
+ }
5089
+ function normalizeInputEnvelopePayload(input) {
5090
+ if (typeof input === "string") {
5091
+ return { parts: [{ type: "text", text: input }], textFallback: input };
5092
+ }
5093
+ if (!input || typeof input !== "object") {
5094
+ return { parts: [], textFallback: "" };
5095
+ }
5096
+ const record = input;
5097
+ const nestedInput = record.input;
5098
+ if (nestedInput && typeof nestedInput === "object") {
5099
+ const nested = nestedInput;
5100
+ return {
5101
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
5102
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
5103
+ metadata: normalizeInputMetadata(nested.metadata)
5104
+ };
5105
+ }
5106
+ const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
5107
+ if (directText !== void 0) {
5108
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
5109
+ }
5110
+ const directParts = normalizeInputParts(record.parts ?? record.prompt);
5111
+ return {
5112
+ parts: directParts,
5113
+ textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
5114
+ metadata: normalizeInputMetadata(record.metadata)
5115
+ };
5116
+ }
5117
+ function normalizeInputMetadata(value) {
5118
+ if (!value || typeof value !== "object") return void 0;
5119
+ const record = value;
5120
+ const metadata = {};
5121
+ if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
5122
+ metadata.source = record.source;
5123
+ }
5124
+ if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
5125
+ metadata.clientTimestamp = record.clientTimestamp;
5126
+ }
5127
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
5128
+ }
5129
+ function normalizeInputParts(value) {
5130
+ if (!Array.isArray(value)) return [];
5131
+ const parts = [];
5132
+ for (const raw of value) {
5133
+ if (typeof raw === "string") {
5134
+ parts.push({ type: "text", text: raw });
5135
+ continue;
5136
+ }
5137
+ if (!raw || typeof raw !== "object") continue;
5138
+ const part = normalizeInputPartObject(raw);
5139
+ if (part) parts.push(part);
5140
+ }
5141
+ return parts;
5142
+ }
5143
+ function normalizeInputPartObject(raw) {
5144
+ const type = raw.type;
5145
+ if (type === "text" && typeof raw.text === "string") {
5146
+ return { type, text: raw.text };
5147
+ }
5148
+ if (type === "image" && typeof raw.mimeType === "string") {
5149
+ return {
5150
+ type,
5151
+ mimeType: raw.mimeType,
5152
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5153
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5154
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
5155
+ };
5156
+ }
5157
+ if (type === "audio" && typeof raw.mimeType === "string") {
5158
+ return {
5159
+ type,
5160
+ mimeType: raw.mimeType,
5161
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5162
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5163
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5164
+ };
5165
+ }
5166
+ if (type === "video" && typeof raw.mimeType === "string") {
5167
+ return {
5168
+ type,
5169
+ mimeType: raw.mimeType,
5170
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5171
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5172
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5173
+ };
5174
+ }
5175
+ if (type === "resource" && typeof raw.uri === "string") {
5176
+ return {
5177
+ type,
5178
+ uri: raw.uri,
5179
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5180
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
5181
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
5182
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
5183
+ };
5184
+ }
5185
+ if (type === "resource_link" && typeof raw.uri === "string") {
5186
+ return {
5187
+ type: "resource",
5188
+ uri: raw.uri,
5189
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5190
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
5191
+ };
5192
+ }
5193
+ return null;
5194
+ }
5195
+ function normalizeMessagePartObject(raw) {
5196
+ const type = raw.type;
5197
+ if (type === "text" && typeof raw.text === "string") {
5198
+ return { type, text: raw.text };
5199
+ }
5200
+ if (type === "image" && typeof raw.mimeType === "string") {
5201
+ return {
5202
+ type,
5203
+ mimeType: raw.mimeType,
5204
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5205
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
5206
+ };
5207
+ }
5208
+ if (type === "audio" && typeof raw.mimeType === "string") {
5209
+ return {
5210
+ type,
5211
+ mimeType: raw.mimeType,
5212
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5213
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5214
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5215
+ };
5216
+ }
5217
+ if (type === "video" && typeof raw.mimeType === "string") {
5218
+ return {
5219
+ type,
5220
+ mimeType: raw.mimeType,
5221
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5222
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5223
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5224
+ };
5225
+ }
5226
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
5227
+ return {
5228
+ type,
5229
+ uri: raw.uri,
5230
+ name: raw.name,
5231
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5232
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
5233
+ };
5234
+ }
5235
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
5236
+ const resource = raw.resource;
5237
+ if (typeof resource.uri !== "string") return null;
5238
+ return {
5239
+ type,
5240
+ resource: {
5241
+ uri: resource.uri,
5242
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
5243
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
5244
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
5245
+ }
5246
+ };
5247
+ }
5248
+ return null;
5249
+ }
5250
+ function flattenInputParts(parts) {
5251
+ return parts.map((part) => {
5252
+ if (part.type === "text") return part.text;
5253
+ if (part.type === "audio") return part.transcript || "";
5254
+ if (part.type === "resource") return part.text || "";
5255
+ return "";
5256
+ }).filter((value) => value.length > 0).join("\n");
5257
+ }
5258
+
5259
+ // src/providers/contracts.ts
5260
+ function flattenContent(content) {
5261
+ if (typeof content === "string") return content;
5262
+ return flattenMessageParts(normalizeMessageParts(content));
5263
+ }
5264
+
4996
5265
  // src/providers/status-monitor.ts
4997
5266
  var DEFAULT_MONITOR_CONFIG = {
4998
5267
  approvalAlert: true,
@@ -5106,6 +5375,7 @@ var StatusMonitor = class {
5106
5375
  };
5107
5376
 
5108
5377
  // src/providers/control-effects.ts
5378
+ init_chat_message_normalization();
5109
5379
  function extractProviderControlValues(controls, data) {
5110
5380
  if (!data || typeof data !== "object") return void 0;
5111
5381
  const values = {};
@@ -5173,13 +5443,58 @@ function normalizeProviderEffects(data) {
5173
5443
  level: raw.notification.level === "success" || raw.notification.level === "warning" ? raw.notification.level : "info",
5174
5444
  channels: Array.isArray(raw.notification.channels) ? raw.notification.channels.filter((channel) => channel === "bubble" || channel === "toast" || channel === "browser") : void 0,
5175
5445
  preferenceKey: raw.notification.preferenceKey === "disconnect" || raw.notification.preferenceKey === "completion" || raw.notification.preferenceKey === "approval" || raw.notification.preferenceKey === "browser" ? raw.notification.preferenceKey : void 0,
5176
- bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0
5446
+ bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0,
5447
+ bubbleKind: typeof raw.notification.bubbleKind === "string" ? raw.notification.bubbleKind : void 0,
5448
+ bubbleRole: raw.notification.bubbleRole === "assistant" || raw.notification.bubbleRole === "user" ? raw.notification.bubbleRole : raw.notification.bubbleRole === "system" ? "system" : void 0,
5449
+ bubbleSenderName: typeof raw.notification.bubbleSenderName === "string" ? raw.notification.bubbleSenderName : void 0
5177
5450
  }
5178
5451
  });
5179
5452
  }
5180
5453
  }
5181
5454
  return effects;
5182
5455
  }
5456
+ function buildPersistedProviderEffectMessage(effect) {
5457
+ if (!effect) return null;
5458
+ if (effect.type === "message" && effect.message) {
5459
+ const role = effect.message.role === "assistant" || effect.message.role === "user" ? effect.message.role : "system";
5460
+ if (role === "system") {
5461
+ return buildRuntimeSystemChatMessage({
5462
+ content: effect.message.content,
5463
+ kind: effect.message.kind,
5464
+ senderName: effect.message.senderName
5465
+ });
5466
+ }
5467
+ return buildChatMessage({
5468
+ role,
5469
+ content: effect.message.content,
5470
+ kind: effect.message.kind,
5471
+ senderName: effect.message.senderName
5472
+ });
5473
+ }
5474
+ if (effect.type === "notification" && effect.notification) {
5475
+ const bubbleContent = effect.notification.bubbleContent ?? formatNotificationBubbleFallback(effect.notification.title, effect.notification.body);
5476
+ const flattened = typeof bubbleContent === "string" ? bubbleContent.trim() : flattenContent(bubbleContent).trim();
5477
+ if (!flattened && (!Array.isArray(bubbleContent) || bubbleContent.length === 0)) return null;
5478
+ const role = effect.notification.bubbleRole === "assistant" || effect.notification.bubbleRole === "user" ? effect.notification.bubbleRole : "system";
5479
+ if (role === "system") {
5480
+ return buildRuntimeSystemChatMessage({
5481
+ content: bubbleContent,
5482
+ kind: effect.notification.bubbleKind,
5483
+ senderName: effect.notification.bubbleSenderName
5484
+ });
5485
+ }
5486
+ return buildChatMessage({
5487
+ role,
5488
+ content: bubbleContent,
5489
+ kind: effect.notification.bubbleKind,
5490
+ senderName: effect.notification.bubbleSenderName
5491
+ });
5492
+ }
5493
+ if (effect.type === "toast" && effect.toast?.message) {
5494
+ return buildRuntimeSystemChatMessage({ content: effect.toast.message });
5495
+ }
5496
+ return null;
5497
+ }
5183
5498
  function normalizeControlListResult(data) {
5184
5499
  if (data && typeof data === "object" && Array.isArray(data.options)) {
5185
5500
  return {
@@ -5246,8 +5561,16 @@ function normalizeControlValue(value) {
5246
5561
  }
5247
5562
  return String(value);
5248
5563
  }
5564
+ function formatNotificationBubbleFallback(title, body) {
5565
+ const cleanTitle = typeof title === "string" ? title.trim() : "";
5566
+ const cleanBody = String(body || "").trim();
5567
+ if (cleanTitle && cleanBody) return `${cleanTitle}
5568
+ ${cleanBody}`;
5569
+ return cleanTitle || cleanBody;
5570
+ }
5249
5571
 
5250
5572
  // src/config/chat-history.ts
5573
+ init_chat_message_normalization();
5251
5574
  import * as fs3 from "fs";
5252
5575
  import * as path7 from "path";
5253
5576
  import * as os5 from "os";
@@ -5456,11 +5779,11 @@ var ChatHistoryWriter = class {
5456
5779
  this.appendNewMessages(
5457
5780
  agentType,
5458
5781
  [{
5459
- role: "system",
5460
- kind: "system",
5461
- content,
5462
- receivedAt: options.receivedAt,
5463
- senderName: options.senderName,
5782
+ ...buildRuntimeSystemChatMessage({
5783
+ content,
5784
+ receivedAt: options.receivedAt,
5785
+ senderName: options.senderName
5786
+ }),
5464
5787
  historyDedupKey: options.dedupKey
5465
5788
  }],
5466
5789
  options.sessionTitle,
@@ -5815,6 +6138,7 @@ function resolveProviderStateSurface(params) {
5815
6138
  }
5816
6139
 
5817
6140
  // src/providers/extension-provider-instance.ts
6141
+ init_chat_message_normalization();
5818
6142
  var ExtensionProviderInstance = class {
5819
6143
  type;
5820
6144
  category = "extension";
@@ -6021,8 +6345,8 @@ var ExtensionProviderInstance = class {
6021
6345
  if (this.appliedEffectKeys.has(effectKey)) continue;
6022
6346
  this.appliedEffectKeys.add(effectKey);
6023
6347
  if (effect.persist !== false) {
6024
- const persisted = this.getPersistedEffectContent(effect);
6025
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
6348
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
6349
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
6026
6350
  }
6027
6351
  if (effect.type === "message" && effect.message) {
6028
6352
  this.pushEvent({
@@ -6057,34 +6381,42 @@ var ExtensionProviderInstance = class {
6057
6381
  }
6058
6382
  }
6059
6383
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
6060
- const normalizedContent = String(content || "").trim();
6061
- if (!normalizedContent) return;
6384
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
6385
+ content,
6386
+ receivedAt,
6387
+ timestamp: receivedAt
6388
+ }), dedupKey);
6389
+ }
6390
+ appendRuntimeMessage(message, dedupKey) {
6391
+ const normalizedMessage = buildChatMessage({
6392
+ ...message,
6393
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
6394
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
6395
+ });
6396
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
6397
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
6062
6398
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
6063
6399
  this.runtimeMessages.push({
6064
6400
  key: dedupKey,
6065
- message: {
6066
- role: "system",
6067
- senderName: "System",
6068
- content: normalizedContent,
6069
- receivedAt,
6070
- timestamp: receivedAt
6071
- }
6401
+ message: normalizedMessage
6072
6402
  });
6073
6403
  if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
6074
- this.historyWriter.appendNewMessages(
6075
- this.type,
6076
- [{
6077
- role: "system",
6078
- senderName: "System",
6079
- content: normalizedContent,
6080
- kind: "system",
6081
- receivedAt,
6082
- historyDedupKey: dedupKey
6083
- }],
6084
- this.chatTitle || this.agentName || this.provider.name,
6085
- this.instanceId,
6086
- this.chatId || this.instanceId
6087
- );
6404
+ if (normalizedContent) {
6405
+ this.historyWriter.appendNewMessages(
6406
+ this.type,
6407
+ [{
6408
+ role: normalizedMessage.role,
6409
+ senderName: normalizedMessage.senderName,
6410
+ kind: normalizedMessage.kind,
6411
+ content: normalizedContent,
6412
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
6413
+ historyDedupKey: dedupKey
6414
+ }],
6415
+ this.chatTitle || this.agentName || this.provider.name,
6416
+ this.instanceId,
6417
+ this.chatId || this.instanceId
6418
+ );
6419
+ }
6088
6420
  }
6089
6421
  /**
6090
6422
  * Assign stable receivedAt to extension messages.
@@ -6101,16 +6433,16 @@ var ExtensionProviderInstance = class {
6101
6433
  nextHashes.set(hash, msg.receivedAt);
6102
6434
  }
6103
6435
  this.prevMessageHashes = nextHashes;
6104
- return messages;
6436
+ return normalizeChatMessages(messages);
6105
6437
  }
6106
6438
  mergeConversationMessages(messages) {
6107
- if (this.runtimeMessages.length === 0) return messages;
6108
- return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
6439
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
6440
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
6109
6441
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
6110
6442
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
6111
6443
  if (aTime !== bTime) return aTime - bTime;
6112
6444
  return a.index - b.index;
6113
- }).map((entry) => entry.message);
6445
+ }).map((entry) => entry.message));
6114
6446
  }
6115
6447
  getPersistedEffectContent(effect) {
6116
6448
  if (effect.type === "message") {
@@ -6224,6 +6556,7 @@ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
6224
6556
  }
6225
6557
 
6226
6558
  // src/providers/ide-provider-instance.ts
6559
+ init_chat_message_normalization();
6227
6560
  var IdeProviderInstance = class {
6228
6561
  type;
6229
6562
  category = "ide";
@@ -6604,8 +6937,8 @@ var IdeProviderInstance = class {
6604
6937
  if (this.appliedEffectKeys.has(effectKey)) continue;
6605
6938
  this.appliedEffectKeys.add(effectKey);
6606
6939
  if (effect.persist !== false) {
6607
- const persisted = this.getPersistedEffectContent(effect);
6608
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
6940
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
6941
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
6609
6942
  }
6610
6943
  if (effect.type === "message" && effect.message) {
6611
6944
  this.pushEvent({
@@ -6640,8 +6973,20 @@ var IdeProviderInstance = class {
6640
6973
  }
6641
6974
  }
6642
6975
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
6643
- const normalizedContent = String(content || "").trim();
6644
- if (!normalizedContent) return;
6976
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
6977
+ content,
6978
+ receivedAt,
6979
+ timestamp: receivedAt
6980
+ }), dedupKey);
6981
+ }
6982
+ appendRuntimeMessage(message, dedupKey) {
6983
+ const normalizedMessage = buildChatMessage({
6984
+ ...message,
6985
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
6986
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
6987
+ });
6988
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
6989
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
6645
6990
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
6646
6991
  if (!this.cachedChat) {
6647
6992
  this.cachedChat = {
@@ -6654,39 +6999,35 @@ var IdeProviderInstance = class {
6654
6999
  };
6655
7000
  }
6656
7001
  this.runtimeMessages.push({
6657
- key: dedupKey,
6658
- message: {
6659
- role: "system",
6660
- senderName: "System",
6661
- content: normalizedContent,
6662
- receivedAt,
6663
- timestamp: receivedAt
6664
- }
7002
+ key: dedupKey,
7003
+ message: normalizedMessage
6665
7004
  });
6666
7005
  if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
6667
- this.historyWriter.appendNewMessages(
6668
- this.type,
6669
- [{
6670
- role: "system",
6671
- senderName: "System",
6672
- content: normalizedContent,
6673
- kind: "system",
6674
- receivedAt,
6675
- historyDedupKey: dedupKey
6676
- }],
6677
- this.cachedChat?.title || this.provider.name,
6678
- this.instanceId,
6679
- this.cachedChat?.id || this.instanceId
6680
- );
7006
+ if (normalizedContent) {
7007
+ this.historyWriter.appendNewMessages(
7008
+ this.type,
7009
+ [{
7010
+ role: normalizedMessage.role,
7011
+ senderName: normalizedMessage.senderName,
7012
+ kind: normalizedMessage.kind,
7013
+ content: normalizedContent,
7014
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
7015
+ historyDedupKey: dedupKey
7016
+ }],
7017
+ this.cachedChat?.title || this.provider.name,
7018
+ this.instanceId,
7019
+ this.cachedChat?.id || this.instanceId
7020
+ );
7021
+ }
6681
7022
  }
6682
7023
  mergeConversationMessages(messages) {
6683
- if (this.runtimeMessages.length === 0) return messages;
6684
- return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
7024
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
7025
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
6685
7026
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
6686
7027
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
6687
7028
  if (aTime !== bTime) return aTime - bTime;
6688
7029
  return a.index - b.index;
6689
- }).map((entry) => entry.message);
7030
+ }).map((entry) => entry.message));
6690
7031
  }
6691
7032
  getPersistedEffectContent(effect) {
6692
7033
  if (effect.type === "message") {
@@ -7589,219 +7930,6 @@ function reconcileIdeRuntimeSessions(instanceManager, sessionRegistry) {
7589
7930
  // src/commands/handler.ts
7590
7931
  init_logger();
7591
7932
 
7592
- // src/providers/io-contracts.ts
7593
- function normalizeInputEnvelope(input) {
7594
- const normalized = normalizeInputEnvelopePayload(input);
7595
- const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
7596
- return {
7597
- parts: normalized.parts,
7598
- textFallback,
7599
- ...normalized.metadata ? { metadata: normalized.metadata } : {}
7600
- };
7601
- }
7602
- function normalizeMessageParts(content) {
7603
- if (typeof content === "string") return [{ type: "text", text: content }];
7604
- if (!Array.isArray(content)) {
7605
- if (content && typeof content === "object" && typeof content.text === "string") {
7606
- return [{ type: "text", text: String(content.text) }];
7607
- }
7608
- return [];
7609
- }
7610
- const parts = [];
7611
- for (const raw of content) {
7612
- if (typeof raw === "string") {
7613
- parts.push({ type: "text", text: raw });
7614
- continue;
7615
- }
7616
- if (!raw || typeof raw !== "object") continue;
7617
- const part = normalizeMessagePartObject(raw);
7618
- if (part) parts.push(part);
7619
- }
7620
- return parts;
7621
- }
7622
- function flattenMessageParts(parts) {
7623
- return parts.map((part) => {
7624
- if (part.type === "text") return part.text;
7625
- if (part.type === "resource") return part.resource.text || "";
7626
- return "";
7627
- }).filter((value) => value.length > 0).join("\n");
7628
- }
7629
- function normalizeInputEnvelopePayload(input) {
7630
- if (typeof input === "string") {
7631
- return { parts: [{ type: "text", text: input }], textFallback: input };
7632
- }
7633
- if (!input || typeof input !== "object") {
7634
- return { parts: [], textFallback: "" };
7635
- }
7636
- const record = input;
7637
- const nestedInput = record.input;
7638
- if (nestedInput && typeof nestedInput === "object") {
7639
- const nested = nestedInput;
7640
- return {
7641
- parts: normalizeInputParts(nested.parts ?? nested.prompt),
7642
- textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
7643
- metadata: normalizeInputMetadata(nested.metadata)
7644
- };
7645
- }
7646
- const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
7647
- if (directText !== void 0) {
7648
- return { parts: [{ type: "text", text: directText }], textFallback: directText };
7649
- }
7650
- const directParts = normalizeInputParts(record.parts ?? record.prompt);
7651
- return {
7652
- parts: directParts,
7653
- textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
7654
- metadata: normalizeInputMetadata(record.metadata)
7655
- };
7656
- }
7657
- function normalizeInputMetadata(value) {
7658
- if (!value || typeof value !== "object") return void 0;
7659
- const record = value;
7660
- const metadata = {};
7661
- if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
7662
- metadata.source = record.source;
7663
- }
7664
- if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
7665
- metadata.clientTimestamp = record.clientTimestamp;
7666
- }
7667
- return Object.keys(metadata).length > 0 ? metadata : void 0;
7668
- }
7669
- function normalizeInputParts(value) {
7670
- if (!Array.isArray(value)) return [];
7671
- const parts = [];
7672
- for (const raw of value) {
7673
- if (typeof raw === "string") {
7674
- parts.push({ type: "text", text: raw });
7675
- continue;
7676
- }
7677
- if (!raw || typeof raw !== "object") continue;
7678
- const part = normalizeInputPartObject(raw);
7679
- if (part) parts.push(part);
7680
- }
7681
- return parts;
7682
- }
7683
- function normalizeInputPartObject(raw) {
7684
- const type = raw.type;
7685
- if (type === "text" && typeof raw.text === "string") {
7686
- return { type, text: raw.text };
7687
- }
7688
- if (type === "image" && typeof raw.mimeType === "string") {
7689
- return {
7690
- type,
7691
- mimeType: raw.mimeType,
7692
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7693
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7694
- ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
7695
- };
7696
- }
7697
- if (type === "audio" && typeof raw.mimeType === "string") {
7698
- return {
7699
- type,
7700
- mimeType: raw.mimeType,
7701
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7702
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7703
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7704
- };
7705
- }
7706
- if (type === "video" && typeof raw.mimeType === "string") {
7707
- return {
7708
- type,
7709
- mimeType: raw.mimeType,
7710
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7711
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7712
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7713
- };
7714
- }
7715
- if (type === "resource" && typeof raw.uri === "string") {
7716
- return {
7717
- type,
7718
- uri: raw.uri,
7719
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7720
- ...typeof raw.name === "string" ? { name: raw.name } : {},
7721
- ...typeof raw.text === "string" ? { text: raw.text } : {},
7722
- ...typeof raw.data === "string" ? { data: raw.data } : {}
7723
- };
7724
- }
7725
- if (type === "resource_link" && typeof raw.uri === "string") {
7726
- return {
7727
- type: "resource",
7728
- uri: raw.uri,
7729
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7730
- ...typeof raw.name === "string" ? { name: raw.name } : {}
7731
- };
7732
- }
7733
- return null;
7734
- }
7735
- function normalizeMessagePartObject(raw) {
7736
- const type = raw.type;
7737
- if (type === "text" && typeof raw.text === "string") {
7738
- return { type, text: raw.text };
7739
- }
7740
- if (type === "image" && typeof raw.mimeType === "string") {
7741
- return {
7742
- type,
7743
- mimeType: raw.mimeType,
7744
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7745
- ...typeof raw.data === "string" ? { data: raw.data } : {}
7746
- };
7747
- }
7748
- if (type === "audio" && typeof raw.mimeType === "string") {
7749
- return {
7750
- type,
7751
- mimeType: raw.mimeType,
7752
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7753
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7754
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7755
- };
7756
- }
7757
- if (type === "video" && typeof raw.mimeType === "string") {
7758
- return {
7759
- type,
7760
- mimeType: raw.mimeType,
7761
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7762
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7763
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7764
- };
7765
- }
7766
- if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
7767
- return {
7768
- type,
7769
- uri: raw.uri,
7770
- name: raw.name,
7771
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7772
- ...typeof raw.size === "number" ? { size: raw.size } : {}
7773
- };
7774
- }
7775
- if (type === "resource" && raw.resource && typeof raw.resource === "object") {
7776
- const resource = raw.resource;
7777
- if (typeof resource.uri !== "string") return null;
7778
- return {
7779
- type,
7780
- resource: {
7781
- uri: resource.uri,
7782
- ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
7783
- ...typeof resource.text === "string" ? { text: resource.text } : {},
7784
- ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
7785
- }
7786
- };
7787
- }
7788
- return null;
7789
- }
7790
- function flattenInputParts(parts) {
7791
- return parts.map((part) => {
7792
- if (part.type === "text") return part.text;
7793
- if (part.type === "audio") return part.transcript || "";
7794
- if (part.type === "resource") return part.text || "";
7795
- return "";
7796
- }).filter((value) => value.length > 0).join("\n");
7797
- }
7798
-
7799
- // src/providers/contracts.ts
7800
- function flattenContent(content) {
7801
- if (typeof content === "string") return content;
7802
- return flattenMessageParts(normalizeMessageParts(content));
7803
- }
7804
-
7805
7933
  // src/commands/chat-commands.ts
7806
7934
  init_logger();
7807
7935
 
@@ -7932,6 +8060,7 @@ function createInteractionId(prefix = "ix") {
7932
8060
  }
7933
8061
 
7934
8062
  // src/commands/chat-commands.ts
8063
+ init_chat_message_normalization();
7935
8064
  var RECENT_SEND_WINDOW_MS = 1200;
7936
8065
  var recentSendByTarget = /* @__PURE__ */ new Map();
7937
8066
  function hashSignatureParts(parts) {
@@ -8061,7 +8190,7 @@ function normalizeReadChatCursor(args) {
8061
8190
  }
8062
8191
  function normalizeReadChatMessages(payload) {
8063
8192
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
8064
- return messages;
8193
+ return normalizeChatMessages(messages);
8065
8194
  }
8066
8195
  function deriveHistoryDedupKey(message) {
8067
8196
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -10409,6 +10538,7 @@ import * as fs5 from "fs";
10409
10538
  import { createRequire } from "module";
10410
10539
  init_provider_cli_adapter();
10411
10540
  init_logger();
10541
+ init_chat_message_normalization();
10412
10542
  var CachedDatabaseSync = null;
10413
10543
  function getDatabaseSync() {
10414
10544
  if (CachedDatabaseSync) return CachedDatabaseSync;
@@ -10903,8 +11033,8 @@ var CliProviderInstance = class {
10903
11033
  if (this.appliedEffectKeys.has(effectKey)) continue;
10904
11034
  this.appliedEffectKeys.add(effectKey);
10905
11035
  if (effect.persist !== false) {
10906
- const persisted = this.getPersistedEffectContent(effect);
10907
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
11036
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
11037
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
10908
11038
  }
10909
11039
  if (effect.type === "message" && effect.message) {
10910
11040
  const content = typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content);
@@ -11028,44 +11158,53 @@ ${effect.notification.body || ""}`.trim();
11028
11158
  );
11029
11159
  }
11030
11160
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
11031
- const normalizedContent = String(content || "").trim();
11032
- if (!normalizedContent) return;
11161
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
11162
+ content,
11163
+ receivedAt,
11164
+ timestamp: receivedAt
11165
+ }), dedupKey);
11166
+ }
11167
+ appendRuntimeMessage(message, dedupKey) {
11168
+ const normalizedMessage = buildChatMessage({
11169
+ ...message,
11170
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
11171
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
11172
+ });
11173
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
11174
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
11033
11175
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
11034
11176
  this.runtimeMessages.push({
11035
11177
  key: dedupKey,
11036
- message: {
11037
- role: "system",
11038
- senderName: "System",
11039
- content: normalizedContent,
11040
- receivedAt,
11041
- timestamp: receivedAt
11042
- }
11178
+ message: normalizedMessage
11043
11179
  });
11044
11180
  if (this.runtimeMessages.length > 50) {
11045
11181
  this.runtimeMessages = this.runtimeMessages.slice(-50);
11046
11182
  }
11047
- this.historyWriter.appendNewMessages(
11048
- this.type,
11049
- [{
11050
- role: "system",
11051
- senderName: "System",
11052
- content: normalizedContent,
11053
- receivedAt,
11054
- historyDedupKey: dedupKey
11055
- }],
11056
- this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
11057
- this.instanceId,
11058
- this.providerSessionId
11059
- );
11183
+ if (normalizedContent) {
11184
+ this.historyWriter.appendNewMessages(
11185
+ this.type,
11186
+ [{
11187
+ role: normalizedMessage.role,
11188
+ senderName: normalizedMessage.senderName,
11189
+ kind: normalizedMessage.kind,
11190
+ content: normalizedContent,
11191
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
11192
+ historyDedupKey: dedupKey
11193
+ }],
11194
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
11195
+ this.instanceId,
11196
+ this.providerSessionId
11197
+ );
11198
+ }
11060
11199
  }
11061
11200
  mergeConversationMessages(parsedMessages) {
11062
- if (this.runtimeMessages.length === 0) return parsedMessages;
11063
- return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
11201
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
11202
+ return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
11064
11203
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
11065
11204
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
11066
11205
  if (aTime !== bTime) return aTime - bTime;
11067
11206
  return a.index - b.index;
11068
- }).map((entry) => entry.message);
11207
+ }).map((entry) => entry.message));
11069
11208
  }
11070
11209
  formatApprovalRequestMessage(modalMessage, buttons) {
11071
11210
  const lines = ["Approval requested"];
@@ -11141,6 +11280,7 @@ import {
11141
11280
  RequestError,
11142
11281
  PROTOCOL_VERSION
11143
11282
  } from "@agentclientprotocol/sdk";
11283
+ init_chat_message_normalization();
11144
11284
  init_logger();
11145
11285
  function getPromptCapabilityFlags(agentCapabilities) {
11146
11286
  const prompt = agentCapabilities?.promptCapabilities || {};
@@ -11306,24 +11446,21 @@ var AcpProviderInstance = class {
11306
11446
  }
11307
11447
  getState() {
11308
11448
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
11309
- const recentMessages = this.messages.slice(-50).map((m) => {
11449
+ const recentMessages = normalizeChatMessages(this.messages.slice(-50).map((m) => {
11310
11450
  const content = this.truncateContent(m.content);
11311
- return {
11312
- role: m.role,
11313
- content,
11314
- timestamp: m.timestamp,
11315
- toolCalls: m.toolCalls
11316
- };
11317
- });
11451
+ return buildChatMessage({
11452
+ ...m,
11453
+ content
11454
+ });
11455
+ }));
11318
11456
  if (this.currentStatus === "generating" && (this.partialContent || this.partialBlocks.length > 0)) {
11319
11457
  const blocks = this.buildPartialBlocks();
11320
11458
  if (blocks.length > 0) {
11321
- recentMessages.push({
11322
- role: "assistant",
11459
+ recentMessages.push(buildAssistantChatMessage({
11323
11460
  content: blocks,
11324
11461
  timestamp: Date.now(),
11325
11462
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
11326
- });
11463
+ }));
11327
11464
  }
11328
11465
  }
11329
11466
  return {
@@ -11336,7 +11473,7 @@ var AcpProviderInstance = class {
11336
11473
  id: this.sessionId || `${this.type}_${this.workingDir}`,
11337
11474
  title: `${this.provider.name} \xB7 ${dirName}`,
11338
11475
  status: this.currentStatus,
11339
- messages: recentMessages,
11476
+ messages: normalizeChatMessages(recentMessages),
11340
11477
  activeModal: this.currentStatus === "waiting_approval" ? {
11341
11478
  message: this.activeToolCalls.find((t) => t.status === "running")?.name || "Permission requested",
11342
11479
  buttons: ["Approve", "Reject"]
@@ -11868,11 +12005,10 @@ var AcpProviderInstance = class {
11868
12005
  if (b.type === "resource") return { type: "resource", resource: b.resource };
11869
12006
  return { type: "text", text: flattenContent([b]) };
11870
12007
  }) : [{ type: "text", text }];
11871
- this.messages.push({
11872
- role: "user",
12008
+ this.messages.push(buildUserChatMessage({
11873
12009
  content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
11874
12010
  timestamp: Date.now()
11875
- });
12011
+ }));
11876
12012
  this.currentStatus = "generating";
11877
12013
  this.partialContent = "";
11878
12014
  this.partialBlocks = [];
@@ -12042,11 +12178,11 @@ var AcpProviderInstance = class {
12042
12178
  content = m.content.filter((p) => p.type === "text").map((p) => p.text || "").join("\n");
12043
12179
  }
12044
12180
  if (content.trim()) {
12045
- this.messages.push({
12181
+ this.messages.push(buildChatMessage({
12046
12182
  role: m.role || "assistant",
12047
12183
  content: content.trim(),
12048
12184
  timestamp: Date.now()
12049
- });
12185
+ }));
12050
12186
  this.partialContent = "";
12051
12187
  }
12052
12188
  }
@@ -12122,12 +12258,11 @@ var AcpProviderInstance = class {
12122
12258
  return b;
12123
12259
  }).filter((b) => b.type !== "text" || b.type === "text" && b.text.trim());
12124
12260
  if (finalBlocks.length > 0) {
12125
- this.messages.push({
12126
- role: "assistant",
12261
+ this.messages.push(buildAssistantChatMessage({
12127
12262
  content: finalBlocks.length === 1 && finalBlocks[0].type === "text" ? finalBlocks[0].text : finalBlocks,
12128
12263
  timestamp: Date.now(),
12129
12264
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
12130
- });
12265
+ }));
12131
12266
  }
12132
12267
  this.partialContent = "";
12133
12268
  this.partialBlocks = [];
@@ -12187,11 +12322,10 @@ var AcpProviderInstance = class {
12187
12322
  appendSystemMessage(content, timestamp = Date.now()) {
12188
12323
  const normalizedContent = String(content || "").trim();
12189
12324
  if (!normalizedContent) return;
12190
- this.messages.push({
12191
- role: "system",
12325
+ this.messages.push(buildRuntimeSystemChatMessage({
12192
12326
  content: normalizedContent,
12193
12327
  timestamp
12194
- });
12328
+ }));
12195
12329
  if (this.messages.length > 200) {
12196
12330
  this.messages = this.messages.slice(-100);
12197
12331
  }
@@ -16862,6 +16996,7 @@ var DaemonAgentStreamManager = class {
16862
16996
 
16863
16997
  // src/agent-stream/poller.ts
16864
16998
  init_logger();
16999
+ init_chat_message_normalization();
16865
17000
  var AgentStreamPoller = class {
16866
17001
  deps;
16867
17002
  timer = null;
@@ -17017,12 +17152,9 @@ var AgentStreamPoller = class {
17017
17152
  type: "message",
17018
17153
  id: effectId,
17019
17154
  persist: true,
17020
- message: {
17021
- role: "system",
17022
- senderName: "System",
17023
- kind: "system",
17155
+ message: buildRuntimeSystemChatMessage({
17024
17156
  content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
17025
- }
17157
+ })
17026
17158
  }
17027
17159
  ]
17028
17160
  };
@@ -17269,6 +17401,9 @@ var ProviderInstanceManager = class {
17269
17401
  }
17270
17402
  };
17271
17403
 
17404
+ // src/index.ts
17405
+ init_chat_message_normalization();
17406
+
17272
17407
  // src/providers/version-archive.ts
17273
17408
  import * as fs10 from "fs";
17274
17409
  import * as path18 from "path";
@@ -23548,6 +23683,7 @@ async function shutdownDaemonComponents(components) {
23548
23683
  export {
23549
23684
  AcpProviderInstance,
23550
23685
  AgentStreamPoller,
23686
+ BUILTIN_CHAT_MESSAGE_KINDS,
23551
23687
  CdpDomHandlers,
23552
23688
  CliProviderInstance,
23553
23689
  DAEMON_WS_PATH,
@@ -23572,9 +23708,14 @@ export {
23572
23708
  SessionHostPtyTransportFactory,
23573
23709
  VersionArchive,
23574
23710
  appendRecentActivity,
23711
+ buildAssistantChatMessage,
23712
+ buildChatMessage,
23575
23713
  buildMachineInfo,
23714
+ buildRuntimeSystemChatMessage,
23576
23715
  buildSessionEntries,
23577
23716
  buildStatusSnapshot,
23717
+ buildSystemChatMessage,
23718
+ buildUserChatMessage,
23578
23719
  clearDebugTrace,
23579
23720
  configureDebugTraceStore,
23580
23721
  connectCdpManager,
@@ -23606,6 +23747,7 @@ export {
23606
23747
  initDaemonComponents,
23607
23748
  installExtensions,
23608
23749
  installGlobalInterceptor,
23750
+ isBuiltinChatMessageKind,
23609
23751
  isCdpConnected,
23610
23752
  isExtensionInstalled,
23611
23753
  isIdeRunning,
@@ -23624,6 +23766,9 @@ export {
23624
23766
  markSetupComplete,
23625
23767
  maybeRunDaemonUpgradeHelperFromEnv,
23626
23768
  normalizeActiveChatData,
23769
+ normalizeChatMessage,
23770
+ normalizeChatMessageKind,
23771
+ normalizeChatMessages,
23627
23772
  normalizeInputEnvelope,
23628
23773
  normalizeManagedStatus,
23629
23774
  normalizeMessageParts,