@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.js CHANGED
@@ -458,6 +458,64 @@ var init_logger = __esm({
458
458
  }
459
459
  });
460
460
 
461
+ // src/providers/chat-message-normalization.ts
462
+ function isBuiltinChatMessageKind(kind) {
463
+ return typeof kind === "string" && KNOWN_CHAT_MESSAGE_KINDS.has(kind.trim().toLowerCase());
464
+ }
465
+ function normalizeChatMessageKind(kind, role) {
466
+ const normalizedKind = typeof kind === "string" ? kind.trim().toLowerCase() : "";
467
+ if (normalizedKind && KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
468
+ const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
469
+ return normalizedRole === "system" ? "system" : "standard";
470
+ }
471
+ function buildChatMessage(message) {
472
+ return {
473
+ ...message,
474
+ kind: normalizeChatMessageKind(message?.kind, message?.role)
475
+ };
476
+ }
477
+ function buildSystemChatMessage(message) {
478
+ return buildChatMessage({
479
+ ...message,
480
+ role: "system",
481
+ kind: message?.kind || "system"
482
+ });
483
+ }
484
+ function buildRuntimeSystemChatMessage(message) {
485
+ return buildSystemChatMessage({
486
+ ...message,
487
+ senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
488
+ });
489
+ }
490
+ function buildAssistantChatMessage(message) {
491
+ return buildChatMessage({
492
+ ...message,
493
+ role: "assistant",
494
+ kind: message?.kind || "standard"
495
+ });
496
+ }
497
+ function buildUserChatMessage(message) {
498
+ return buildChatMessage({
499
+ ...message,
500
+ role: "user",
501
+ kind: message?.kind || "standard"
502
+ });
503
+ }
504
+ function normalizeChatMessage(message) {
505
+ return buildChatMessage(message);
506
+ }
507
+ function normalizeChatMessages(messages) {
508
+ return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
509
+ }
510
+ var BUILTIN_CHAT_MESSAGE_KINDS, KNOWN_CHAT_MESSAGE_KINDS;
511
+ var init_chat_message_normalization = __esm({
512
+ "src/providers/chat-message-normalization.ts"() {
513
+ "use strict";
514
+ BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
515
+ KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
516
+ }
517
+ });
518
+
461
519
  // src/cli-adapters/terminal-backends/ghostty-vt-backend.ts
462
520
  function isModuleNotFoundError(error, ref) {
463
521
  if (!(error instanceof Error)) return false;
@@ -1310,6 +1368,7 @@ var init_provider_cli_adapter = __esm({
1310
1368
  init_terminal_screen();
1311
1369
  init_pty_transport();
1312
1370
  init_provider_cli_shared();
1371
+ init_chat_message_normalization();
1313
1372
  init_provider_cli_parse();
1314
1373
  init_provider_cli_config();
1315
1374
  init_provider_cli_runtime();
@@ -2367,11 +2426,10 @@ var init_provider_cli_adapter = __esm({
2367
2426
  );
2368
2427
  const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
2369
2428
  if (parsed && Array.isArray(parsed.messages)) {
2370
- const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => ({
2429
+ const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
2371
2430
  ...message,
2372
2431
  id: message.id || `msg_${index}`,
2373
2432
  index: typeof message.index === "number" ? message.index : index,
2374
- kind: message.kind || "standard",
2375
2433
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2376
2434
  })) : hydrateCliParsedMessages(parsed.messages, {
2377
2435
  committedMessages: this.committedMessages,
@@ -2392,13 +2450,11 @@ var init_provider_cli_adapter = __esm({
2392
2450
  id: "cli_session",
2393
2451
  status: this.currentStatus,
2394
2452
  title: this.cliName,
2395
- messages: messages.slice(-50).map((message, index) => ({
2396
- id: `msg_${index}`,
2397
- role: message.role,
2398
- content: message.content,
2399
- timestamp: message.timestamp,
2400
- index,
2401
- kind: "standard"
2453
+ messages: messages.slice(-50).map((message, index) => buildChatMessage({
2454
+ ...message,
2455
+ id: message.id || `msg_${index}`,
2456
+ index: typeof message.index === "number" ? message.index : index,
2457
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2402
2458
  })),
2403
2459
  activeModal: this.activeModal
2404
2460
  };
@@ -3023,6 +3079,7 @@ var index_exports = {};
3023
3079
  __export(index_exports, {
3024
3080
  AcpProviderInstance: () => AcpProviderInstance,
3025
3081
  AgentStreamPoller: () => AgentStreamPoller,
3082
+ BUILTIN_CHAT_MESSAGE_KINDS: () => BUILTIN_CHAT_MESSAGE_KINDS,
3026
3083
  CdpDomHandlers: () => CdpDomHandlers,
3027
3084
  CliProviderInstance: () => CliProviderInstance,
3028
3085
  DAEMON_WS_PATH: () => DAEMON_WS_PATH,
@@ -3047,9 +3104,14 @@ __export(index_exports, {
3047
3104
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
3048
3105
  VersionArchive: () => VersionArchive,
3049
3106
  appendRecentActivity: () => appendRecentActivity,
3107
+ buildAssistantChatMessage: () => buildAssistantChatMessage,
3108
+ buildChatMessage: () => buildChatMessage,
3050
3109
  buildMachineInfo: () => buildMachineInfo,
3110
+ buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
3051
3111
  buildSessionEntries: () => buildSessionEntries,
3052
3112
  buildStatusSnapshot: () => buildStatusSnapshot,
3113
+ buildSystemChatMessage: () => buildSystemChatMessage,
3114
+ buildUserChatMessage: () => buildUserChatMessage,
3053
3115
  clearDebugTrace: () => clearDebugTrace,
3054
3116
  configureDebugTraceStore: () => configureDebugTraceStore,
3055
3117
  connectCdpManager: () => connectCdpManager,
@@ -3081,6 +3143,7 @@ __export(index_exports, {
3081
3143
  initDaemonComponents: () => initDaemonComponents,
3082
3144
  installExtensions: () => installExtensions,
3083
3145
  installGlobalInterceptor: () => installGlobalInterceptor,
3146
+ isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
3084
3147
  isCdpConnected: () => isCdpConnected,
3085
3148
  isExtensionInstalled: () => isExtensionInstalled,
3086
3149
  isIdeRunning: () => isIdeRunning,
@@ -3099,6 +3162,9 @@ __export(index_exports, {
3099
3162
  markSetupComplete: () => markSetupComplete,
3100
3163
  maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv,
3101
3164
  normalizeActiveChatData: () => normalizeActiveChatData,
3165
+ normalizeChatMessage: () => normalizeChatMessage,
3166
+ normalizeChatMessageKind: () => normalizeChatMessageKind,
3167
+ normalizeChatMessages: () => normalizeChatMessages,
3102
3168
  normalizeInputEnvelope: () => normalizeInputEnvelope,
3103
3169
  normalizeManagedStatus: () => normalizeManagedStatus,
3104
3170
  normalizeMessageParts: () => normalizeMessageParts,
@@ -5105,6 +5171,219 @@ var CdpDomHandlers = class {
5105
5171
  // src/providers/ide-provider-instance.ts
5106
5172
  var crypto2 = __toESM(require("crypto"));
5107
5173
 
5174
+ // src/providers/io-contracts.ts
5175
+ function normalizeInputEnvelope(input) {
5176
+ const normalized = normalizeInputEnvelopePayload(input);
5177
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
5178
+ return {
5179
+ parts: normalized.parts,
5180
+ textFallback,
5181
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
5182
+ };
5183
+ }
5184
+ function normalizeMessageParts(content) {
5185
+ if (typeof content === "string") return [{ type: "text", text: content }];
5186
+ if (!Array.isArray(content)) {
5187
+ if (content && typeof content === "object" && typeof content.text === "string") {
5188
+ return [{ type: "text", text: String(content.text) }];
5189
+ }
5190
+ return [];
5191
+ }
5192
+ const parts = [];
5193
+ for (const raw of content) {
5194
+ if (typeof raw === "string") {
5195
+ parts.push({ type: "text", text: raw });
5196
+ continue;
5197
+ }
5198
+ if (!raw || typeof raw !== "object") continue;
5199
+ const part = normalizeMessagePartObject(raw);
5200
+ if (part) parts.push(part);
5201
+ }
5202
+ return parts;
5203
+ }
5204
+ function flattenMessageParts(parts) {
5205
+ return parts.map((part) => {
5206
+ if (part.type === "text") return part.text;
5207
+ if (part.type === "resource") return part.resource.text || "";
5208
+ return "";
5209
+ }).filter((value) => value.length > 0).join("\n");
5210
+ }
5211
+ function normalizeInputEnvelopePayload(input) {
5212
+ if (typeof input === "string") {
5213
+ return { parts: [{ type: "text", text: input }], textFallback: input };
5214
+ }
5215
+ if (!input || typeof input !== "object") {
5216
+ return { parts: [], textFallback: "" };
5217
+ }
5218
+ const record = input;
5219
+ const nestedInput = record.input;
5220
+ if (nestedInput && typeof nestedInput === "object") {
5221
+ const nested = nestedInput;
5222
+ return {
5223
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
5224
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
5225
+ metadata: normalizeInputMetadata(nested.metadata)
5226
+ };
5227
+ }
5228
+ const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
5229
+ if (directText !== void 0) {
5230
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
5231
+ }
5232
+ const directParts = normalizeInputParts(record.parts ?? record.prompt);
5233
+ return {
5234
+ parts: directParts,
5235
+ textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
5236
+ metadata: normalizeInputMetadata(record.metadata)
5237
+ };
5238
+ }
5239
+ function normalizeInputMetadata(value) {
5240
+ if (!value || typeof value !== "object") return void 0;
5241
+ const record = value;
5242
+ const metadata = {};
5243
+ if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
5244
+ metadata.source = record.source;
5245
+ }
5246
+ if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
5247
+ metadata.clientTimestamp = record.clientTimestamp;
5248
+ }
5249
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
5250
+ }
5251
+ function normalizeInputParts(value) {
5252
+ if (!Array.isArray(value)) return [];
5253
+ const parts = [];
5254
+ for (const raw of value) {
5255
+ if (typeof raw === "string") {
5256
+ parts.push({ type: "text", text: raw });
5257
+ continue;
5258
+ }
5259
+ if (!raw || typeof raw !== "object") continue;
5260
+ const part = normalizeInputPartObject(raw);
5261
+ if (part) parts.push(part);
5262
+ }
5263
+ return parts;
5264
+ }
5265
+ function normalizeInputPartObject(raw) {
5266
+ const type = raw.type;
5267
+ if (type === "text" && typeof raw.text === "string") {
5268
+ return { type, text: raw.text };
5269
+ }
5270
+ if (type === "image" && typeof raw.mimeType === "string") {
5271
+ return {
5272
+ type,
5273
+ mimeType: raw.mimeType,
5274
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5275
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5276
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
5277
+ };
5278
+ }
5279
+ if (type === "audio" && typeof raw.mimeType === "string") {
5280
+ return {
5281
+ type,
5282
+ mimeType: raw.mimeType,
5283
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5284
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5285
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5286
+ };
5287
+ }
5288
+ if (type === "video" && typeof raw.mimeType === "string") {
5289
+ return {
5290
+ type,
5291
+ mimeType: raw.mimeType,
5292
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5293
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5294
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5295
+ };
5296
+ }
5297
+ if (type === "resource" && typeof raw.uri === "string") {
5298
+ return {
5299
+ type,
5300
+ uri: raw.uri,
5301
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5302
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
5303
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
5304
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
5305
+ };
5306
+ }
5307
+ if (type === "resource_link" && typeof raw.uri === "string") {
5308
+ return {
5309
+ type: "resource",
5310
+ uri: raw.uri,
5311
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5312
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
5313
+ };
5314
+ }
5315
+ return null;
5316
+ }
5317
+ function normalizeMessagePartObject(raw) {
5318
+ const type = raw.type;
5319
+ if (type === "text" && typeof raw.text === "string") {
5320
+ return { type, text: raw.text };
5321
+ }
5322
+ if (type === "image" && typeof raw.mimeType === "string") {
5323
+ return {
5324
+ type,
5325
+ mimeType: raw.mimeType,
5326
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5327
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
5328
+ };
5329
+ }
5330
+ if (type === "audio" && typeof raw.mimeType === "string") {
5331
+ return {
5332
+ type,
5333
+ mimeType: raw.mimeType,
5334
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5335
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5336
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5337
+ };
5338
+ }
5339
+ if (type === "video" && typeof raw.mimeType === "string") {
5340
+ return {
5341
+ type,
5342
+ mimeType: raw.mimeType,
5343
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5344
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5345
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5346
+ };
5347
+ }
5348
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
5349
+ return {
5350
+ type,
5351
+ uri: raw.uri,
5352
+ name: raw.name,
5353
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5354
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
5355
+ };
5356
+ }
5357
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
5358
+ const resource = raw.resource;
5359
+ if (typeof resource.uri !== "string") return null;
5360
+ return {
5361
+ type,
5362
+ resource: {
5363
+ uri: resource.uri,
5364
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
5365
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
5366
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
5367
+ }
5368
+ };
5369
+ }
5370
+ return null;
5371
+ }
5372
+ function flattenInputParts(parts) {
5373
+ return parts.map((part) => {
5374
+ if (part.type === "text") return part.text;
5375
+ if (part.type === "audio") return part.transcript || "";
5376
+ if (part.type === "resource") return part.text || "";
5377
+ return "";
5378
+ }).filter((value) => value.length > 0).join("\n");
5379
+ }
5380
+
5381
+ // src/providers/contracts.ts
5382
+ function flattenContent(content) {
5383
+ if (typeof content === "string") return content;
5384
+ return flattenMessageParts(normalizeMessageParts(content));
5385
+ }
5386
+
5108
5387
  // src/providers/status-monitor.ts
5109
5388
  var DEFAULT_MONITOR_CONFIG = {
5110
5389
  approvalAlert: true,
@@ -5218,6 +5497,7 @@ var StatusMonitor = class {
5218
5497
  };
5219
5498
 
5220
5499
  // src/providers/control-effects.ts
5500
+ init_chat_message_normalization();
5221
5501
  function extractProviderControlValues(controls, data) {
5222
5502
  if (!data || typeof data !== "object") return void 0;
5223
5503
  const values = {};
@@ -5285,13 +5565,58 @@ function normalizeProviderEffects(data) {
5285
5565
  level: raw.notification.level === "success" || raw.notification.level === "warning" ? raw.notification.level : "info",
5286
5566
  channels: Array.isArray(raw.notification.channels) ? raw.notification.channels.filter((channel) => channel === "bubble" || channel === "toast" || channel === "browser") : void 0,
5287
5567
  preferenceKey: raw.notification.preferenceKey === "disconnect" || raw.notification.preferenceKey === "completion" || raw.notification.preferenceKey === "approval" || raw.notification.preferenceKey === "browser" ? raw.notification.preferenceKey : void 0,
5288
- bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0
5568
+ bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0,
5569
+ bubbleKind: typeof raw.notification.bubbleKind === "string" ? raw.notification.bubbleKind : void 0,
5570
+ bubbleRole: raw.notification.bubbleRole === "assistant" || raw.notification.bubbleRole === "user" ? raw.notification.bubbleRole : raw.notification.bubbleRole === "system" ? "system" : void 0,
5571
+ bubbleSenderName: typeof raw.notification.bubbleSenderName === "string" ? raw.notification.bubbleSenderName : void 0
5289
5572
  }
5290
5573
  });
5291
5574
  }
5292
5575
  }
5293
5576
  return effects;
5294
5577
  }
5578
+ function buildPersistedProviderEffectMessage(effect) {
5579
+ if (!effect) return null;
5580
+ if (effect.type === "message" && effect.message) {
5581
+ const role = effect.message.role === "assistant" || effect.message.role === "user" ? effect.message.role : "system";
5582
+ if (role === "system") {
5583
+ return buildRuntimeSystemChatMessage({
5584
+ content: effect.message.content,
5585
+ kind: effect.message.kind,
5586
+ senderName: effect.message.senderName
5587
+ });
5588
+ }
5589
+ return buildChatMessage({
5590
+ role,
5591
+ content: effect.message.content,
5592
+ kind: effect.message.kind,
5593
+ senderName: effect.message.senderName
5594
+ });
5595
+ }
5596
+ if (effect.type === "notification" && effect.notification) {
5597
+ const bubbleContent = effect.notification.bubbleContent ?? formatNotificationBubbleFallback(effect.notification.title, effect.notification.body);
5598
+ const flattened = typeof bubbleContent === "string" ? bubbleContent.trim() : flattenContent(bubbleContent).trim();
5599
+ if (!flattened && (!Array.isArray(bubbleContent) || bubbleContent.length === 0)) return null;
5600
+ const role = effect.notification.bubbleRole === "assistant" || effect.notification.bubbleRole === "user" ? effect.notification.bubbleRole : "system";
5601
+ if (role === "system") {
5602
+ return buildRuntimeSystemChatMessage({
5603
+ content: bubbleContent,
5604
+ kind: effect.notification.bubbleKind,
5605
+ senderName: effect.notification.bubbleSenderName
5606
+ });
5607
+ }
5608
+ return buildChatMessage({
5609
+ role,
5610
+ content: bubbleContent,
5611
+ kind: effect.notification.bubbleKind,
5612
+ senderName: effect.notification.bubbleSenderName
5613
+ });
5614
+ }
5615
+ if (effect.type === "toast" && effect.toast?.message) {
5616
+ return buildRuntimeSystemChatMessage({ content: effect.toast.message });
5617
+ }
5618
+ return null;
5619
+ }
5295
5620
  function normalizeControlListResult(data) {
5296
5621
  if (data && typeof data === "object" && Array.isArray(data.options)) {
5297
5622
  return {
@@ -5358,11 +5683,19 @@ function normalizeControlValue(value) {
5358
5683
  }
5359
5684
  return String(value);
5360
5685
  }
5686
+ function formatNotificationBubbleFallback(title, body) {
5687
+ const cleanTitle = typeof title === "string" ? title.trim() : "";
5688
+ const cleanBody = String(body || "").trim();
5689
+ if (cleanTitle && cleanBody) return `${cleanTitle}
5690
+ ${cleanBody}`;
5691
+ return cleanTitle || cleanBody;
5692
+ }
5361
5693
 
5362
5694
  // src/config/chat-history.ts
5363
5695
  var fs3 = __toESM(require("fs"));
5364
5696
  var path7 = __toESM(require("path"));
5365
5697
  var os5 = __toESM(require("os"));
5698
+ init_chat_message_normalization();
5366
5699
  var HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
5367
5700
  var RETAIN_DAYS = 30;
5368
5701
  var 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;
@@ -5568,11 +5901,11 @@ var ChatHistoryWriter = class {
5568
5901
  this.appendNewMessages(
5569
5902
  agentType,
5570
5903
  [{
5571
- role: "system",
5572
- kind: "system",
5573
- content,
5574
- receivedAt: options.receivedAt,
5575
- senderName: options.senderName,
5904
+ ...buildRuntimeSystemChatMessage({
5905
+ content,
5906
+ receivedAt: options.receivedAt,
5907
+ senderName: options.senderName
5908
+ }),
5576
5909
  historyDedupKey: options.dedupKey
5577
5910
  }],
5578
5911
  options.sessionTitle,
@@ -5927,6 +6260,7 @@ function resolveProviderStateSurface(params) {
5927
6260
  }
5928
6261
 
5929
6262
  // src/providers/extension-provider-instance.ts
6263
+ init_chat_message_normalization();
5930
6264
  var ExtensionProviderInstance = class {
5931
6265
  type;
5932
6266
  category = "extension";
@@ -6133,8 +6467,8 @@ var ExtensionProviderInstance = class {
6133
6467
  if (this.appliedEffectKeys.has(effectKey)) continue;
6134
6468
  this.appliedEffectKeys.add(effectKey);
6135
6469
  if (effect.persist !== false) {
6136
- const persisted = this.getPersistedEffectContent(effect);
6137
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
6470
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
6471
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
6138
6472
  }
6139
6473
  if (effect.type === "message" && effect.message) {
6140
6474
  this.pushEvent({
@@ -6169,34 +6503,42 @@ var ExtensionProviderInstance = class {
6169
6503
  }
6170
6504
  }
6171
6505
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
6172
- const normalizedContent = String(content || "").trim();
6173
- if (!normalizedContent) return;
6506
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
6507
+ content,
6508
+ receivedAt,
6509
+ timestamp: receivedAt
6510
+ }), dedupKey);
6511
+ }
6512
+ appendRuntimeMessage(message, dedupKey) {
6513
+ const normalizedMessage = buildChatMessage({
6514
+ ...message,
6515
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
6516
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
6517
+ });
6518
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
6519
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
6174
6520
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
6175
6521
  this.runtimeMessages.push({
6176
6522
  key: dedupKey,
6177
- message: {
6178
- role: "system",
6179
- senderName: "System",
6180
- content: normalizedContent,
6181
- receivedAt,
6182
- timestamp: receivedAt
6183
- }
6523
+ message: normalizedMessage
6184
6524
  });
6185
6525
  if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
6186
- this.historyWriter.appendNewMessages(
6187
- this.type,
6188
- [{
6189
- role: "system",
6190
- senderName: "System",
6191
- content: normalizedContent,
6192
- kind: "system",
6193
- receivedAt,
6194
- historyDedupKey: dedupKey
6195
- }],
6196
- this.chatTitle || this.agentName || this.provider.name,
6197
- this.instanceId,
6198
- this.chatId || this.instanceId
6199
- );
6526
+ if (normalizedContent) {
6527
+ this.historyWriter.appendNewMessages(
6528
+ this.type,
6529
+ [{
6530
+ role: normalizedMessage.role,
6531
+ senderName: normalizedMessage.senderName,
6532
+ kind: normalizedMessage.kind,
6533
+ content: normalizedContent,
6534
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
6535
+ historyDedupKey: dedupKey
6536
+ }],
6537
+ this.chatTitle || this.agentName || this.provider.name,
6538
+ this.instanceId,
6539
+ this.chatId || this.instanceId
6540
+ );
6541
+ }
6200
6542
  }
6201
6543
  /**
6202
6544
  * Assign stable receivedAt to extension messages.
@@ -6213,16 +6555,16 @@ var ExtensionProviderInstance = class {
6213
6555
  nextHashes.set(hash, msg.receivedAt);
6214
6556
  }
6215
6557
  this.prevMessageHashes = nextHashes;
6216
- return messages;
6558
+ return normalizeChatMessages(messages);
6217
6559
  }
6218
6560
  mergeConversationMessages(messages) {
6219
- if (this.runtimeMessages.length === 0) return messages;
6220
- return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
6561
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
6562
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
6221
6563
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
6222
6564
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
6223
6565
  if (aTime !== bTime) return aTime - bTime;
6224
6566
  return a.index - b.index;
6225
- }).map((entry) => entry.message);
6567
+ }).map((entry) => entry.message));
6226
6568
  }
6227
6569
  getPersistedEffectContent(effect) {
6228
6570
  if (effect.type === "message") {
@@ -6336,6 +6678,7 @@ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
6336
6678
  }
6337
6679
 
6338
6680
  // src/providers/ide-provider-instance.ts
6681
+ init_chat_message_normalization();
6339
6682
  var IdeProviderInstance = class {
6340
6683
  type;
6341
6684
  category = "ide";
@@ -6716,8 +7059,8 @@ var IdeProviderInstance = class {
6716
7059
  if (this.appliedEffectKeys.has(effectKey)) continue;
6717
7060
  this.appliedEffectKeys.add(effectKey);
6718
7061
  if (effect.persist !== false) {
6719
- const persisted = this.getPersistedEffectContent(effect);
6720
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
7062
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
7063
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
6721
7064
  }
6722
7065
  if (effect.type === "message" && effect.message) {
6723
7066
  this.pushEvent({
@@ -6752,8 +7095,20 @@ var IdeProviderInstance = class {
6752
7095
  }
6753
7096
  }
6754
7097
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
6755
- const normalizedContent = String(content || "").trim();
6756
- if (!normalizedContent) return;
7098
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
7099
+ content,
7100
+ receivedAt,
7101
+ timestamp: receivedAt
7102
+ }), dedupKey);
7103
+ }
7104
+ appendRuntimeMessage(message, dedupKey) {
7105
+ const normalizedMessage = buildChatMessage({
7106
+ ...message,
7107
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
7108
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
7109
+ });
7110
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
7111
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
6757
7112
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
6758
7113
  if (!this.cachedChat) {
6759
7114
  this.cachedChat = {
@@ -6766,39 +7121,35 @@ var IdeProviderInstance = class {
6766
7121
  };
6767
7122
  }
6768
7123
  this.runtimeMessages.push({
6769
- key: dedupKey,
6770
- message: {
6771
- role: "system",
6772
- senderName: "System",
6773
- content: normalizedContent,
6774
- receivedAt,
6775
- timestamp: receivedAt
6776
- }
7124
+ key: dedupKey,
7125
+ message: normalizedMessage
6777
7126
  });
6778
7127
  if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
6779
- this.historyWriter.appendNewMessages(
6780
- this.type,
6781
- [{
6782
- role: "system",
6783
- senderName: "System",
6784
- content: normalizedContent,
6785
- kind: "system",
6786
- receivedAt,
6787
- historyDedupKey: dedupKey
6788
- }],
6789
- this.cachedChat?.title || this.provider.name,
6790
- this.instanceId,
6791
- this.cachedChat?.id || this.instanceId
6792
- );
7128
+ if (normalizedContent) {
7129
+ this.historyWriter.appendNewMessages(
7130
+ this.type,
7131
+ [{
7132
+ role: normalizedMessage.role,
7133
+ senderName: normalizedMessage.senderName,
7134
+ kind: normalizedMessage.kind,
7135
+ content: normalizedContent,
7136
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
7137
+ historyDedupKey: dedupKey
7138
+ }],
7139
+ this.cachedChat?.title || this.provider.name,
7140
+ this.instanceId,
7141
+ this.cachedChat?.id || this.instanceId
7142
+ );
7143
+ }
6793
7144
  }
6794
7145
  mergeConversationMessages(messages) {
6795
- if (this.runtimeMessages.length === 0) return messages;
6796
- return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
7146
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
7147
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
6797
7148
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
6798
7149
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
6799
7150
  if (aTime !== bTime) return aTime - bTime;
6800
7151
  return a.index - b.index;
6801
- }).map((entry) => entry.message);
7152
+ }).map((entry) => entry.message));
6802
7153
  }
6803
7154
  getPersistedEffectContent(effect) {
6804
7155
  if (effect.type === "message") {
@@ -7701,219 +8052,6 @@ function reconcileIdeRuntimeSessions(instanceManager, sessionRegistry) {
7701
8052
  // src/commands/handler.ts
7702
8053
  init_logger();
7703
8054
 
7704
- // src/providers/io-contracts.ts
7705
- function normalizeInputEnvelope(input) {
7706
- const normalized = normalizeInputEnvelopePayload(input);
7707
- const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
7708
- return {
7709
- parts: normalized.parts,
7710
- textFallback,
7711
- ...normalized.metadata ? { metadata: normalized.metadata } : {}
7712
- };
7713
- }
7714
- function normalizeMessageParts(content) {
7715
- if (typeof content === "string") return [{ type: "text", text: content }];
7716
- if (!Array.isArray(content)) {
7717
- if (content && typeof content === "object" && typeof content.text === "string") {
7718
- return [{ type: "text", text: String(content.text) }];
7719
- }
7720
- return [];
7721
- }
7722
- const parts = [];
7723
- for (const raw of content) {
7724
- if (typeof raw === "string") {
7725
- parts.push({ type: "text", text: raw });
7726
- continue;
7727
- }
7728
- if (!raw || typeof raw !== "object") continue;
7729
- const part = normalizeMessagePartObject(raw);
7730
- if (part) parts.push(part);
7731
- }
7732
- return parts;
7733
- }
7734
- function flattenMessageParts(parts) {
7735
- return parts.map((part) => {
7736
- if (part.type === "text") return part.text;
7737
- if (part.type === "resource") return part.resource.text || "";
7738
- return "";
7739
- }).filter((value) => value.length > 0).join("\n");
7740
- }
7741
- function normalizeInputEnvelopePayload(input) {
7742
- if (typeof input === "string") {
7743
- return { parts: [{ type: "text", text: input }], textFallback: input };
7744
- }
7745
- if (!input || typeof input !== "object") {
7746
- return { parts: [], textFallback: "" };
7747
- }
7748
- const record = input;
7749
- const nestedInput = record.input;
7750
- if (nestedInput && typeof nestedInput === "object") {
7751
- const nested = nestedInput;
7752
- return {
7753
- parts: normalizeInputParts(nested.parts ?? nested.prompt),
7754
- textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
7755
- metadata: normalizeInputMetadata(nested.metadata)
7756
- };
7757
- }
7758
- const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
7759
- if (directText !== void 0) {
7760
- return { parts: [{ type: "text", text: directText }], textFallback: directText };
7761
- }
7762
- const directParts = normalizeInputParts(record.parts ?? record.prompt);
7763
- return {
7764
- parts: directParts,
7765
- textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
7766
- metadata: normalizeInputMetadata(record.metadata)
7767
- };
7768
- }
7769
- function normalizeInputMetadata(value) {
7770
- if (!value || typeof value !== "object") return void 0;
7771
- const record = value;
7772
- const metadata = {};
7773
- if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
7774
- metadata.source = record.source;
7775
- }
7776
- if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
7777
- metadata.clientTimestamp = record.clientTimestamp;
7778
- }
7779
- return Object.keys(metadata).length > 0 ? metadata : void 0;
7780
- }
7781
- function normalizeInputParts(value) {
7782
- if (!Array.isArray(value)) return [];
7783
- const parts = [];
7784
- for (const raw of value) {
7785
- if (typeof raw === "string") {
7786
- parts.push({ type: "text", text: raw });
7787
- continue;
7788
- }
7789
- if (!raw || typeof raw !== "object") continue;
7790
- const part = normalizeInputPartObject(raw);
7791
- if (part) parts.push(part);
7792
- }
7793
- return parts;
7794
- }
7795
- function normalizeInputPartObject(raw) {
7796
- const type = raw.type;
7797
- if (type === "text" && typeof raw.text === "string") {
7798
- return { type, text: raw.text };
7799
- }
7800
- if (type === "image" && typeof raw.mimeType === "string") {
7801
- return {
7802
- type,
7803
- mimeType: raw.mimeType,
7804
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7805
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7806
- ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
7807
- };
7808
- }
7809
- if (type === "audio" && typeof raw.mimeType === "string") {
7810
- return {
7811
- type,
7812
- mimeType: raw.mimeType,
7813
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7814
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7815
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7816
- };
7817
- }
7818
- if (type === "video" && typeof raw.mimeType === "string") {
7819
- return {
7820
- type,
7821
- mimeType: raw.mimeType,
7822
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7823
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7824
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7825
- };
7826
- }
7827
- if (type === "resource" && typeof raw.uri === "string") {
7828
- return {
7829
- type,
7830
- uri: raw.uri,
7831
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7832
- ...typeof raw.name === "string" ? { name: raw.name } : {},
7833
- ...typeof raw.text === "string" ? { text: raw.text } : {},
7834
- ...typeof raw.data === "string" ? { data: raw.data } : {}
7835
- };
7836
- }
7837
- if (type === "resource_link" && typeof raw.uri === "string") {
7838
- return {
7839
- type: "resource",
7840
- uri: raw.uri,
7841
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7842
- ...typeof raw.name === "string" ? { name: raw.name } : {}
7843
- };
7844
- }
7845
- return null;
7846
- }
7847
- function normalizeMessagePartObject(raw) {
7848
- const type = raw.type;
7849
- if (type === "text" && typeof raw.text === "string") {
7850
- return { type, text: raw.text };
7851
- }
7852
- if (type === "image" && typeof raw.mimeType === "string") {
7853
- return {
7854
- type,
7855
- mimeType: raw.mimeType,
7856
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7857
- ...typeof raw.data === "string" ? { data: raw.data } : {}
7858
- };
7859
- }
7860
- if (type === "audio" && typeof raw.mimeType === "string") {
7861
- return {
7862
- type,
7863
- mimeType: raw.mimeType,
7864
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7865
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7866
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7867
- };
7868
- }
7869
- if (type === "video" && typeof raw.mimeType === "string") {
7870
- return {
7871
- type,
7872
- mimeType: raw.mimeType,
7873
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7874
- ...typeof raw.data === "string" ? { data: raw.data } : {},
7875
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7876
- };
7877
- }
7878
- if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
7879
- return {
7880
- type,
7881
- uri: raw.uri,
7882
- name: raw.name,
7883
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7884
- ...typeof raw.size === "number" ? { size: raw.size } : {}
7885
- };
7886
- }
7887
- if (type === "resource" && raw.resource && typeof raw.resource === "object") {
7888
- const resource = raw.resource;
7889
- if (typeof resource.uri !== "string") return null;
7890
- return {
7891
- type,
7892
- resource: {
7893
- uri: resource.uri,
7894
- ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
7895
- ...typeof resource.text === "string" ? { text: resource.text } : {},
7896
- ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
7897
- }
7898
- };
7899
- }
7900
- return null;
7901
- }
7902
- function flattenInputParts(parts) {
7903
- return parts.map((part) => {
7904
- if (part.type === "text") return part.text;
7905
- if (part.type === "audio") return part.transcript || "";
7906
- if (part.type === "resource") return part.text || "";
7907
- return "";
7908
- }).filter((value) => value.length > 0).join("\n");
7909
- }
7910
-
7911
- // src/providers/contracts.ts
7912
- function flattenContent(content) {
7913
- if (typeof content === "string") return content;
7914
- return flattenMessageParts(normalizeMessageParts(content));
7915
- }
7916
-
7917
8055
  // src/commands/chat-commands.ts
7918
8056
  init_logger();
7919
8057
 
@@ -8044,6 +8182,7 @@ function createInteractionId(prefix = "ix") {
8044
8182
  }
8045
8183
 
8046
8184
  // src/commands/chat-commands.ts
8185
+ init_chat_message_normalization();
8047
8186
  var RECENT_SEND_WINDOW_MS = 1200;
8048
8187
  var recentSendByTarget = /* @__PURE__ */ new Map();
8049
8188
  function hashSignatureParts(parts) {
@@ -8173,7 +8312,7 @@ function normalizeReadChatCursor(args) {
8173
8312
  }
8174
8313
  function normalizeReadChatMessages(payload) {
8175
8314
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
8176
- return messages;
8315
+ return normalizeChatMessages(messages);
8177
8316
  }
8178
8317
  function deriveHistoryDedupKey(message) {
8179
8318
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -10521,6 +10660,7 @@ var fs5 = __toESM(require("fs"));
10521
10660
  var import_node_module = require("module");
10522
10661
  init_provider_cli_adapter();
10523
10662
  init_logger();
10663
+ init_chat_message_normalization();
10524
10664
  var CachedDatabaseSync = null;
10525
10665
  function getDatabaseSync() {
10526
10666
  if (CachedDatabaseSync) return CachedDatabaseSync;
@@ -11015,8 +11155,8 @@ var CliProviderInstance = class {
11015
11155
  if (this.appliedEffectKeys.has(effectKey)) continue;
11016
11156
  this.appliedEffectKeys.add(effectKey);
11017
11157
  if (effect.persist !== false) {
11018
- const persisted = this.getPersistedEffectContent(effect);
11019
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
11158
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
11159
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
11020
11160
  }
11021
11161
  if (effect.type === "message" && effect.message) {
11022
11162
  const content = typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content);
@@ -11140,44 +11280,53 @@ ${effect.notification.body || ""}`.trim();
11140
11280
  );
11141
11281
  }
11142
11282
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
11143
- const normalizedContent = String(content || "").trim();
11144
- if (!normalizedContent) return;
11283
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
11284
+ content,
11285
+ receivedAt,
11286
+ timestamp: receivedAt
11287
+ }), dedupKey);
11288
+ }
11289
+ appendRuntimeMessage(message, dedupKey) {
11290
+ const normalizedMessage = buildChatMessage({
11291
+ ...message,
11292
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
11293
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
11294
+ });
11295
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
11296
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
11145
11297
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
11146
11298
  this.runtimeMessages.push({
11147
11299
  key: dedupKey,
11148
- message: {
11149
- role: "system",
11150
- senderName: "System",
11151
- content: normalizedContent,
11152
- receivedAt,
11153
- timestamp: receivedAt
11154
- }
11300
+ message: normalizedMessage
11155
11301
  });
11156
11302
  if (this.runtimeMessages.length > 50) {
11157
11303
  this.runtimeMessages = this.runtimeMessages.slice(-50);
11158
11304
  }
11159
- this.historyWriter.appendNewMessages(
11160
- this.type,
11161
- [{
11162
- role: "system",
11163
- senderName: "System",
11164
- content: normalizedContent,
11165
- receivedAt,
11166
- historyDedupKey: dedupKey
11167
- }],
11168
- this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
11169
- this.instanceId,
11170
- this.providerSessionId
11171
- );
11305
+ if (normalizedContent) {
11306
+ this.historyWriter.appendNewMessages(
11307
+ this.type,
11308
+ [{
11309
+ role: normalizedMessage.role,
11310
+ senderName: normalizedMessage.senderName,
11311
+ kind: normalizedMessage.kind,
11312
+ content: normalizedContent,
11313
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
11314
+ historyDedupKey: dedupKey
11315
+ }],
11316
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
11317
+ this.instanceId,
11318
+ this.providerSessionId
11319
+ );
11320
+ }
11172
11321
  }
11173
11322
  mergeConversationMessages(parsedMessages) {
11174
- if (this.runtimeMessages.length === 0) return parsedMessages;
11175
- return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
11323
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
11324
+ return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
11176
11325
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
11177
11326
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
11178
11327
  if (aTime !== bTime) return aTime - bTime;
11179
11328
  return a.index - b.index;
11180
- }).map((entry) => entry.message);
11329
+ }).map((entry) => entry.message));
11181
11330
  }
11182
11331
  formatApprovalRequestMessage(modalMessage, buttons) {
11183
11332
  const lines = ["Approval requested"];
@@ -11248,6 +11397,7 @@ var path12 = __toESM(require("path"));
11248
11397
  var import_stream = require("stream");
11249
11398
  var import_child_process5 = require("child_process");
11250
11399
  var import_sdk = require("@agentclientprotocol/sdk");
11400
+ init_chat_message_normalization();
11251
11401
  init_logger();
11252
11402
  function getPromptCapabilityFlags(agentCapabilities) {
11253
11403
  const prompt = agentCapabilities?.promptCapabilities || {};
@@ -11413,24 +11563,21 @@ var AcpProviderInstance = class {
11413
11563
  }
11414
11564
  getState() {
11415
11565
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
11416
- const recentMessages = this.messages.slice(-50).map((m) => {
11566
+ const recentMessages = normalizeChatMessages(this.messages.slice(-50).map((m) => {
11417
11567
  const content = this.truncateContent(m.content);
11418
- return {
11419
- role: m.role,
11420
- content,
11421
- timestamp: m.timestamp,
11422
- toolCalls: m.toolCalls
11423
- };
11424
- });
11568
+ return buildChatMessage({
11569
+ ...m,
11570
+ content
11571
+ });
11572
+ }));
11425
11573
  if (this.currentStatus === "generating" && (this.partialContent || this.partialBlocks.length > 0)) {
11426
11574
  const blocks = this.buildPartialBlocks();
11427
11575
  if (blocks.length > 0) {
11428
- recentMessages.push({
11429
- role: "assistant",
11576
+ recentMessages.push(buildAssistantChatMessage({
11430
11577
  content: blocks,
11431
11578
  timestamp: Date.now(),
11432
11579
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
11433
- });
11580
+ }));
11434
11581
  }
11435
11582
  }
11436
11583
  return {
@@ -11443,7 +11590,7 @@ var AcpProviderInstance = class {
11443
11590
  id: this.sessionId || `${this.type}_${this.workingDir}`,
11444
11591
  title: `${this.provider.name} \xB7 ${dirName}`,
11445
11592
  status: this.currentStatus,
11446
- messages: recentMessages,
11593
+ messages: normalizeChatMessages(recentMessages),
11447
11594
  activeModal: this.currentStatus === "waiting_approval" ? {
11448
11595
  message: this.activeToolCalls.find((t) => t.status === "running")?.name || "Permission requested",
11449
11596
  buttons: ["Approve", "Reject"]
@@ -11975,11 +12122,10 @@ var AcpProviderInstance = class {
11975
12122
  if (b.type === "resource") return { type: "resource", resource: b.resource };
11976
12123
  return { type: "text", text: flattenContent([b]) };
11977
12124
  }) : [{ type: "text", text }];
11978
- this.messages.push({
11979
- role: "user",
12125
+ this.messages.push(buildUserChatMessage({
11980
12126
  content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
11981
12127
  timestamp: Date.now()
11982
- });
12128
+ }));
11983
12129
  this.currentStatus = "generating";
11984
12130
  this.partialContent = "";
11985
12131
  this.partialBlocks = [];
@@ -12149,11 +12295,11 @@ var AcpProviderInstance = class {
12149
12295
  content = m.content.filter((p) => p.type === "text").map((p) => p.text || "").join("\n");
12150
12296
  }
12151
12297
  if (content.trim()) {
12152
- this.messages.push({
12298
+ this.messages.push(buildChatMessage({
12153
12299
  role: m.role || "assistant",
12154
12300
  content: content.trim(),
12155
12301
  timestamp: Date.now()
12156
- });
12302
+ }));
12157
12303
  this.partialContent = "";
12158
12304
  }
12159
12305
  }
@@ -12229,12 +12375,11 @@ var AcpProviderInstance = class {
12229
12375
  return b;
12230
12376
  }).filter((b) => b.type !== "text" || b.type === "text" && b.text.trim());
12231
12377
  if (finalBlocks.length > 0) {
12232
- this.messages.push({
12233
- role: "assistant",
12378
+ this.messages.push(buildAssistantChatMessage({
12234
12379
  content: finalBlocks.length === 1 && finalBlocks[0].type === "text" ? finalBlocks[0].text : finalBlocks,
12235
12380
  timestamp: Date.now(),
12236
12381
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
12237
- });
12382
+ }));
12238
12383
  }
12239
12384
  this.partialContent = "";
12240
12385
  this.partialBlocks = [];
@@ -12294,11 +12439,10 @@ var AcpProviderInstance = class {
12294
12439
  appendSystemMessage(content, timestamp = Date.now()) {
12295
12440
  const normalizedContent = String(content || "").trim();
12296
12441
  if (!normalizedContent) return;
12297
- this.messages.push({
12298
- role: "system",
12442
+ this.messages.push(buildRuntimeSystemChatMessage({
12299
12443
  content: normalizedContent,
12300
12444
  timestamp
12301
- });
12445
+ }));
12302
12446
  if (this.messages.length > 200) {
12303
12447
  this.messages = this.messages.slice(-100);
12304
12448
  }
@@ -16969,6 +17113,7 @@ var DaemonAgentStreamManager = class {
16969
17113
 
16970
17114
  // src/agent-stream/poller.ts
16971
17115
  init_logger();
17116
+ init_chat_message_normalization();
16972
17117
  var AgentStreamPoller = class {
16973
17118
  deps;
16974
17119
  timer = null;
@@ -17124,12 +17269,9 @@ var AgentStreamPoller = class {
17124
17269
  type: "message",
17125
17270
  id: effectId,
17126
17271
  persist: true,
17127
- message: {
17128
- role: "system",
17129
- senderName: "System",
17130
- kind: "system",
17272
+ message: buildRuntimeSystemChatMessage({
17131
17273
  content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
17132
- }
17274
+ })
17133
17275
  }
17134
17276
  ]
17135
17277
  };
@@ -17376,6 +17518,9 @@ var ProviderInstanceManager = class {
17376
17518
  }
17377
17519
  };
17378
17520
 
17521
+ // src/index.ts
17522
+ init_chat_message_normalization();
17523
+
17379
17524
  // src/providers/version-archive.ts
17380
17525
  var fs10 = __toESM(require("fs"));
17381
17526
  var path18 = __toESM(require("path"));
@@ -23651,6 +23796,7 @@ async function shutdownDaemonComponents(components) {
23651
23796
  0 && (module.exports = {
23652
23797
  AcpProviderInstance,
23653
23798
  AgentStreamPoller,
23799
+ BUILTIN_CHAT_MESSAGE_KINDS,
23654
23800
  CdpDomHandlers,
23655
23801
  CliProviderInstance,
23656
23802
  DAEMON_WS_PATH,
@@ -23675,9 +23821,14 @@ async function shutdownDaemonComponents(components) {
23675
23821
  SessionHostPtyTransportFactory,
23676
23822
  VersionArchive,
23677
23823
  appendRecentActivity,
23824
+ buildAssistantChatMessage,
23825
+ buildChatMessage,
23678
23826
  buildMachineInfo,
23827
+ buildRuntimeSystemChatMessage,
23679
23828
  buildSessionEntries,
23680
23829
  buildStatusSnapshot,
23830
+ buildSystemChatMessage,
23831
+ buildUserChatMessage,
23681
23832
  clearDebugTrace,
23682
23833
  configureDebugTraceStore,
23683
23834
  connectCdpManager,
@@ -23709,6 +23860,7 @@ async function shutdownDaemonComponents(components) {
23709
23860
  initDaemonComponents,
23710
23861
  installExtensions,
23711
23862
  installGlobalInterceptor,
23863
+ isBuiltinChatMessageKind,
23712
23864
  isCdpConnected,
23713
23865
  isExtensionInstalled,
23714
23866
  isIdeRunning,
@@ -23727,6 +23879,9 @@ async function shutdownDaemonComponents(components) {
23727
23879
  markSetupComplete,
23728
23880
  maybeRunDaemonUpgradeHelperFromEnv,
23729
23881
  normalizeActiveChatData,
23882
+ normalizeChatMessage,
23883
+ normalizeChatMessageKind,
23884
+ normalizeChatMessages,
23730
23885
  normalizeInputEnvelope,
23731
23886
  normalizeManagedStatus,
23732
23887
  normalizeMessageParts,