@adhdev/daemon-core 0.8.60 → 0.8.62

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.
Files changed (34) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +1 -0
  2. package/dist/cli-adapters/provider-cli-parse.d.ts +1 -0
  3. package/dist/cli-adapters/provider-cli-shared.d.ts +5 -2
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +521 -343
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +511 -343
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/providers/chat-message-normalization.d.ts +43 -0
  10. package/dist/providers/cli-provider-instance.d.ts +1 -0
  11. package/dist/providers/contracts.d.ts +5 -1
  12. package/dist/providers/control-effects.d.ts +2 -0
  13. package/dist/providers/extension-provider-instance.d.ts +2 -1
  14. package/dist/providers/ide-provider-instance.d.ts +2 -1
  15. package/dist/types.d.ts +2 -1
  16. package/node_modules/@adhdev/session-host-core/package.json +2 -2
  17. package/package.json +2 -2
  18. package/src/agent-stream/poller.ts +3 -5
  19. package/src/cli-adapters/provider-cli-adapter.ts +32 -10
  20. package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
  21. package/src/cli-adapters/provider-cli-parse.ts +3 -0
  22. package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
  23. package/src/cli-adapters/provider-cli-shared.ts +5 -2
  24. package/src/commands/chat-commands.ts +2 -1
  25. package/src/config/chat-history.ts +6 -5
  26. package/src/index.ts +13 -0
  27. package/src/providers/acp-provider-instance.ts +19 -24
  28. package/src/providers/chat-message-normalization.ts +68 -0
  29. package/src/providers/cli-provider-instance.ts +42 -29
  30. package/src/providers/contracts.ts +5 -1
  31. package/src/providers/control-effects.ts +72 -0
  32. package/src/providers/extension-provider-instance.ts +43 -31
  33. package/src/providers/ide-provider-instance.ts +42 -30
  34. package/src/types.ts +2 -1
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;
@@ -1106,6 +1164,7 @@ function buildCliParseInput(options) {
1106
1164
  terminalScreenText,
1107
1165
  baseMessages,
1108
1166
  partialResponse,
1167
+ isWaitingForResponse,
1109
1168
  scope,
1110
1169
  runtimeSettings
1111
1170
  } = options;
@@ -1123,6 +1182,7 @@ function buildCliParseInput(options) {
1123
1182
  recentScreen: buildCliScreenSnapshot(recentBuffer),
1124
1183
  messages: [...baseMessages],
1125
1184
  partialResponse,
1185
+ isWaitingForResponse,
1126
1186
  promptText: scope?.prompt || "",
1127
1187
  settings: { ...runtimeSettings }
1128
1188
  };
@@ -1307,6 +1367,7 @@ var init_provider_cli_adapter = __esm({
1307
1367
  init_terminal_screen();
1308
1368
  init_pty_transport();
1309
1369
  init_provider_cli_shared();
1370
+ init_chat_message_normalization();
1310
1371
  init_provider_cli_parse();
1311
1372
  init_provider_cli_config();
1312
1373
  init_provider_cli_runtime();
@@ -1859,6 +1920,18 @@ var init_provider_cli_adapter = __esm({
1859
1920
  const holdMs = this.getStatusActivityHoldMs();
1860
1921
  return quietForMs < holdMs || screenStableMs < holdMs;
1861
1922
  }
1923
+ shouldDeferIdleTimeoutFinish() {
1924
+ if (!this.isWaitingForResponse || this.currentStatus === "waiting_approval") {
1925
+ return false;
1926
+ }
1927
+ const latestStatus = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
1928
+ if (latestStatus === "generating") {
1929
+ this.settledBuffer = this.recentOutputBuffer;
1930
+ this.evaluateSettled();
1931
+ return true;
1932
+ }
1933
+ return false;
1934
+ }
1862
1935
  getStartupConfirmationModal(screenText) {
1863
1936
  const text = sanitizeTerminalText(String(screenText || ""));
1864
1937
  if (!text.trim()) return null;
@@ -2017,6 +2090,7 @@ var init_provider_cli_adapter = __esm({
2017
2090
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
2018
2091
  this.idleTimeout = setTimeout(() => {
2019
2092
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
2093
+ if (this.shouldDeferIdleTimeoutFinish()) return;
2020
2094
  this.finishResponse();
2021
2095
  }
2022
2096
  }, this.timeouts.generatingIdle);
@@ -2052,6 +2126,7 @@ var init_provider_cli_adapter = __esm({
2052
2126
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
2053
2127
  this.idleTimeout = setTimeout(() => {
2054
2128
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
2129
+ if (this.shouldDeferIdleTimeoutFinish()) return;
2055
2130
  this.finishResponse();
2056
2131
  }
2057
2132
  }, this.timeouts.generatingIdle);
@@ -2094,7 +2169,10 @@ var init_provider_cli_adapter = __esm({
2094
2169
  this.setStatus("generating", "script_detect");
2095
2170
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
2096
2171
  this.idleTimeout = setTimeout(() => {
2097
- if (this.isWaitingForResponse) this.finishResponse();
2172
+ if (this.isWaitingForResponse) {
2173
+ if (this.shouldDeferIdleTimeoutFinish()) return;
2174
+ this.finishResponse();
2175
+ }
2098
2176
  }, this.timeouts.generatingIdle);
2099
2177
  this.onStatusChange?.();
2100
2178
  return;
@@ -2162,6 +2240,7 @@ var init_provider_cli_adapter = __esm({
2162
2240
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
2163
2241
  this.idleTimeout = setTimeout(() => {
2164
2242
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
2243
+ if (this.shouldDeferIdleTimeoutFinish()) return;
2165
2244
  this.clearIdleFinishCandidate("idle_timeout_finish");
2166
2245
  this.finishResponse();
2167
2246
  }
@@ -2300,6 +2379,7 @@ var init_provider_cli_adapter = __esm({
2300
2379
  tail: text.slice(-500),
2301
2380
  screenText,
2302
2381
  rawBuffer: this.accumulatedRawBuffer,
2382
+ isWaitingForResponse: this.isWaitingForResponse,
2303
2383
  screen: buildCliScreenSnapshot(screenText),
2304
2384
  tailScreen: buildCliScreenSnapshot(text.slice(-500))
2305
2385
  });
@@ -2364,11 +2444,10 @@ var init_provider_cli_adapter = __esm({
2364
2444
  );
2365
2445
  const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
2366
2446
  if (parsed && Array.isArray(parsed.messages)) {
2367
- const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => ({
2447
+ const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
2368
2448
  ...message,
2369
2449
  id: message.id || `msg_${index}`,
2370
2450
  index: typeof message.index === "number" ? message.index : index,
2371
- kind: message.kind || "standard",
2372
2451
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2373
2452
  })) : hydrateCliParsedMessages(parsed.messages, {
2374
2453
  committedMessages: this.committedMessages,
@@ -2389,13 +2468,11 @@ var init_provider_cli_adapter = __esm({
2389
2468
  id: "cli_session",
2390
2469
  status: this.currentStatus,
2391
2470
  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"
2471
+ messages: messages.slice(-50).map((message, index) => buildChatMessage({
2472
+ ...message,
2473
+ id: message.id || `msg_${index}`,
2474
+ index: typeof message.index === "number" ? message.index : index,
2475
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2399
2476
  })),
2400
2477
  activeModal: this.activeModal
2401
2478
  };
@@ -2412,6 +2489,7 @@ var init_provider_cli_adapter = __esm({
2412
2489
  terminalScreenText: this.terminalScreen.getText(),
2413
2490
  baseMessages: this.committedMessages,
2414
2491
  partialResponse: this.responseBuffer,
2492
+ isWaitingForResponse: this.isWaitingForResponse,
2415
2493
  scope: this.currentTurnScope,
2416
2494
  runtimeSettings: this.runtimeSettings
2417
2495
  });
@@ -2430,6 +2508,7 @@ var init_provider_cli_adapter = __esm({
2430
2508
  terminalScreenText: this.terminalScreen.getText(),
2431
2509
  baseMessages,
2432
2510
  partialResponse,
2511
+ isWaitingForResponse: this.isWaitingForResponse,
2433
2512
  scope,
2434
2513
  runtimeSettings: this.runtimeSettings
2435
2514
  });
@@ -4993,6 +5072,219 @@ var CdpDomHandlers = class {
4993
5072
  // src/providers/ide-provider-instance.ts
4994
5073
  import * as crypto2 from "crypto";
4995
5074
 
5075
+ // src/providers/io-contracts.ts
5076
+ function normalizeInputEnvelope(input) {
5077
+ const normalized = normalizeInputEnvelopePayload(input);
5078
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
5079
+ return {
5080
+ parts: normalized.parts,
5081
+ textFallback,
5082
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
5083
+ };
5084
+ }
5085
+ function normalizeMessageParts(content) {
5086
+ if (typeof content === "string") return [{ type: "text", text: content }];
5087
+ if (!Array.isArray(content)) {
5088
+ if (content && typeof content === "object" && typeof content.text === "string") {
5089
+ return [{ type: "text", text: String(content.text) }];
5090
+ }
5091
+ return [];
5092
+ }
5093
+ const parts = [];
5094
+ for (const raw of content) {
5095
+ if (typeof raw === "string") {
5096
+ parts.push({ type: "text", text: raw });
5097
+ continue;
5098
+ }
5099
+ if (!raw || typeof raw !== "object") continue;
5100
+ const part = normalizeMessagePartObject(raw);
5101
+ if (part) parts.push(part);
5102
+ }
5103
+ return parts;
5104
+ }
5105
+ function flattenMessageParts(parts) {
5106
+ return parts.map((part) => {
5107
+ if (part.type === "text") return part.text;
5108
+ if (part.type === "resource") return part.resource.text || "";
5109
+ return "";
5110
+ }).filter((value) => value.length > 0).join("\n");
5111
+ }
5112
+ function normalizeInputEnvelopePayload(input) {
5113
+ if (typeof input === "string") {
5114
+ return { parts: [{ type: "text", text: input }], textFallback: input };
5115
+ }
5116
+ if (!input || typeof input !== "object") {
5117
+ return { parts: [], textFallback: "" };
5118
+ }
5119
+ const record = input;
5120
+ const nestedInput = record.input;
5121
+ if (nestedInput && typeof nestedInput === "object") {
5122
+ const nested = nestedInput;
5123
+ return {
5124
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
5125
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
5126
+ metadata: normalizeInputMetadata(nested.metadata)
5127
+ };
5128
+ }
5129
+ const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
5130
+ if (directText !== void 0) {
5131
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
5132
+ }
5133
+ const directParts = normalizeInputParts(record.parts ?? record.prompt);
5134
+ return {
5135
+ parts: directParts,
5136
+ textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
5137
+ metadata: normalizeInputMetadata(record.metadata)
5138
+ };
5139
+ }
5140
+ function normalizeInputMetadata(value) {
5141
+ if (!value || typeof value !== "object") return void 0;
5142
+ const record = value;
5143
+ const metadata = {};
5144
+ if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
5145
+ metadata.source = record.source;
5146
+ }
5147
+ if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
5148
+ metadata.clientTimestamp = record.clientTimestamp;
5149
+ }
5150
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
5151
+ }
5152
+ function normalizeInputParts(value) {
5153
+ if (!Array.isArray(value)) return [];
5154
+ const parts = [];
5155
+ for (const raw of value) {
5156
+ if (typeof raw === "string") {
5157
+ parts.push({ type: "text", text: raw });
5158
+ continue;
5159
+ }
5160
+ if (!raw || typeof raw !== "object") continue;
5161
+ const part = normalizeInputPartObject(raw);
5162
+ if (part) parts.push(part);
5163
+ }
5164
+ return parts;
5165
+ }
5166
+ function normalizeInputPartObject(raw) {
5167
+ const type = raw.type;
5168
+ if (type === "text" && typeof raw.text === "string") {
5169
+ return { type, text: raw.text };
5170
+ }
5171
+ if (type === "image" && typeof raw.mimeType === "string") {
5172
+ return {
5173
+ type,
5174
+ mimeType: raw.mimeType,
5175
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5176
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5177
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
5178
+ };
5179
+ }
5180
+ if (type === "audio" && typeof raw.mimeType === "string") {
5181
+ return {
5182
+ type,
5183
+ mimeType: raw.mimeType,
5184
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5185
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5186
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5187
+ };
5188
+ }
5189
+ if (type === "video" && typeof raw.mimeType === "string") {
5190
+ return {
5191
+ type,
5192
+ mimeType: raw.mimeType,
5193
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5194
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5195
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5196
+ };
5197
+ }
5198
+ if (type === "resource" && typeof raw.uri === "string") {
5199
+ return {
5200
+ type,
5201
+ uri: raw.uri,
5202
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5203
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
5204
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
5205
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
5206
+ };
5207
+ }
5208
+ if (type === "resource_link" && typeof raw.uri === "string") {
5209
+ return {
5210
+ type: "resource",
5211
+ uri: raw.uri,
5212
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5213
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
5214
+ };
5215
+ }
5216
+ return null;
5217
+ }
5218
+ function normalizeMessagePartObject(raw) {
5219
+ const type = raw.type;
5220
+ if (type === "text" && typeof raw.text === "string") {
5221
+ return { type, text: raw.text };
5222
+ }
5223
+ if (type === "image" && typeof raw.mimeType === "string") {
5224
+ return {
5225
+ type,
5226
+ mimeType: raw.mimeType,
5227
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5228
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
5229
+ };
5230
+ }
5231
+ if (type === "audio" && typeof raw.mimeType === "string") {
5232
+ return {
5233
+ type,
5234
+ mimeType: raw.mimeType,
5235
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5236
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5237
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5238
+ };
5239
+ }
5240
+ if (type === "video" && typeof raw.mimeType === "string") {
5241
+ return {
5242
+ type,
5243
+ mimeType: raw.mimeType,
5244
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5245
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
5246
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5247
+ };
5248
+ }
5249
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
5250
+ return {
5251
+ type,
5252
+ uri: raw.uri,
5253
+ name: raw.name,
5254
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5255
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
5256
+ };
5257
+ }
5258
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
5259
+ const resource = raw.resource;
5260
+ if (typeof resource.uri !== "string") return null;
5261
+ return {
5262
+ type,
5263
+ resource: {
5264
+ uri: resource.uri,
5265
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
5266
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
5267
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
5268
+ }
5269
+ };
5270
+ }
5271
+ return null;
5272
+ }
5273
+ function flattenInputParts(parts) {
5274
+ return parts.map((part) => {
5275
+ if (part.type === "text") return part.text;
5276
+ if (part.type === "audio") return part.transcript || "";
5277
+ if (part.type === "resource") return part.text || "";
5278
+ return "";
5279
+ }).filter((value) => value.length > 0).join("\n");
5280
+ }
5281
+
5282
+ // src/providers/contracts.ts
5283
+ function flattenContent(content) {
5284
+ if (typeof content === "string") return content;
5285
+ return flattenMessageParts(normalizeMessageParts(content));
5286
+ }
5287
+
4996
5288
  // src/providers/status-monitor.ts
4997
5289
  var DEFAULT_MONITOR_CONFIG = {
4998
5290
  approvalAlert: true,
@@ -5106,6 +5398,7 @@ var StatusMonitor = class {
5106
5398
  };
5107
5399
 
5108
5400
  // src/providers/control-effects.ts
5401
+ init_chat_message_normalization();
5109
5402
  function extractProviderControlValues(controls, data) {
5110
5403
  if (!data || typeof data !== "object") return void 0;
5111
5404
  const values = {};
@@ -5173,13 +5466,58 @@ function normalizeProviderEffects(data) {
5173
5466
  level: raw.notification.level === "success" || raw.notification.level === "warning" ? raw.notification.level : "info",
5174
5467
  channels: Array.isArray(raw.notification.channels) ? raw.notification.channels.filter((channel) => channel === "bubble" || channel === "toast" || channel === "browser") : void 0,
5175
5468
  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
5469
+ bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0,
5470
+ bubbleKind: typeof raw.notification.bubbleKind === "string" ? raw.notification.bubbleKind : void 0,
5471
+ bubbleRole: raw.notification.bubbleRole === "assistant" || raw.notification.bubbleRole === "user" ? raw.notification.bubbleRole : raw.notification.bubbleRole === "system" ? "system" : void 0,
5472
+ bubbleSenderName: typeof raw.notification.bubbleSenderName === "string" ? raw.notification.bubbleSenderName : void 0
5177
5473
  }
5178
5474
  });
5179
5475
  }
5180
5476
  }
5181
5477
  return effects;
5182
5478
  }
5479
+ function buildPersistedProviderEffectMessage(effect) {
5480
+ if (!effect) return null;
5481
+ if (effect.type === "message" && effect.message) {
5482
+ const role = effect.message.role === "assistant" || effect.message.role === "user" ? effect.message.role : "system";
5483
+ if (role === "system") {
5484
+ return buildRuntimeSystemChatMessage({
5485
+ content: effect.message.content,
5486
+ kind: effect.message.kind,
5487
+ senderName: effect.message.senderName
5488
+ });
5489
+ }
5490
+ return buildChatMessage({
5491
+ role,
5492
+ content: effect.message.content,
5493
+ kind: effect.message.kind,
5494
+ senderName: effect.message.senderName
5495
+ });
5496
+ }
5497
+ if (effect.type === "notification" && effect.notification) {
5498
+ const bubbleContent = effect.notification.bubbleContent ?? formatNotificationBubbleFallback(effect.notification.title, effect.notification.body);
5499
+ const flattened = typeof bubbleContent === "string" ? bubbleContent.trim() : flattenContent(bubbleContent).trim();
5500
+ if (!flattened && (!Array.isArray(bubbleContent) || bubbleContent.length === 0)) return null;
5501
+ const role = effect.notification.bubbleRole === "assistant" || effect.notification.bubbleRole === "user" ? effect.notification.bubbleRole : "system";
5502
+ if (role === "system") {
5503
+ return buildRuntimeSystemChatMessage({
5504
+ content: bubbleContent,
5505
+ kind: effect.notification.bubbleKind,
5506
+ senderName: effect.notification.bubbleSenderName
5507
+ });
5508
+ }
5509
+ return buildChatMessage({
5510
+ role,
5511
+ content: bubbleContent,
5512
+ kind: effect.notification.bubbleKind,
5513
+ senderName: effect.notification.bubbleSenderName
5514
+ });
5515
+ }
5516
+ if (effect.type === "toast" && effect.toast?.message) {
5517
+ return buildRuntimeSystemChatMessage({ content: effect.toast.message });
5518
+ }
5519
+ return null;
5520
+ }
5183
5521
  function normalizeControlListResult(data) {
5184
5522
  if (data && typeof data === "object" && Array.isArray(data.options)) {
5185
5523
  return {
@@ -5246,8 +5584,16 @@ function normalizeControlValue(value) {
5246
5584
  }
5247
5585
  return String(value);
5248
5586
  }
5587
+ function formatNotificationBubbleFallback(title, body) {
5588
+ const cleanTitle = typeof title === "string" ? title.trim() : "";
5589
+ const cleanBody = String(body || "").trim();
5590
+ if (cleanTitle && cleanBody) return `${cleanTitle}
5591
+ ${cleanBody}`;
5592
+ return cleanTitle || cleanBody;
5593
+ }
5249
5594
 
5250
5595
  // src/config/chat-history.ts
5596
+ init_chat_message_normalization();
5251
5597
  import * as fs3 from "fs";
5252
5598
  import * as path7 from "path";
5253
5599
  import * as os5 from "os";
@@ -5456,11 +5802,11 @@ var ChatHistoryWriter = class {
5456
5802
  this.appendNewMessages(
5457
5803
  agentType,
5458
5804
  [{
5459
- role: "system",
5460
- kind: "system",
5461
- content,
5462
- receivedAt: options.receivedAt,
5463
- senderName: options.senderName,
5805
+ ...buildRuntimeSystemChatMessage({
5806
+ content,
5807
+ receivedAt: options.receivedAt,
5808
+ senderName: options.senderName
5809
+ }),
5464
5810
  historyDedupKey: options.dedupKey
5465
5811
  }],
5466
5812
  options.sessionTitle,
@@ -5815,6 +6161,7 @@ function resolveProviderStateSurface(params) {
5815
6161
  }
5816
6162
 
5817
6163
  // src/providers/extension-provider-instance.ts
6164
+ init_chat_message_normalization();
5818
6165
  var ExtensionProviderInstance = class {
5819
6166
  type;
5820
6167
  category = "extension";
@@ -6021,8 +6368,8 @@ var ExtensionProviderInstance = class {
6021
6368
  if (this.appliedEffectKeys.has(effectKey)) continue;
6022
6369
  this.appliedEffectKeys.add(effectKey);
6023
6370
  if (effect.persist !== false) {
6024
- const persisted = this.getPersistedEffectContent(effect);
6025
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
6371
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
6372
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
6026
6373
  }
6027
6374
  if (effect.type === "message" && effect.message) {
6028
6375
  this.pushEvent({
@@ -6057,34 +6404,42 @@ var ExtensionProviderInstance = class {
6057
6404
  }
6058
6405
  }
6059
6406
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
6060
- const normalizedContent = String(content || "").trim();
6061
- if (!normalizedContent) return;
6407
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
6408
+ content,
6409
+ receivedAt,
6410
+ timestamp: receivedAt
6411
+ }), dedupKey);
6412
+ }
6413
+ appendRuntimeMessage(message, dedupKey) {
6414
+ const normalizedMessage = buildChatMessage({
6415
+ ...message,
6416
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
6417
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
6418
+ });
6419
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
6420
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
6062
6421
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
6063
6422
  this.runtimeMessages.push({
6064
6423
  key: dedupKey,
6065
- message: {
6066
- role: "system",
6067
- senderName: "System",
6068
- content: normalizedContent,
6069
- receivedAt,
6070
- timestamp: receivedAt
6071
- }
6424
+ message: normalizedMessage
6072
6425
  });
6073
6426
  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
- );
6427
+ if (normalizedContent) {
6428
+ this.historyWriter.appendNewMessages(
6429
+ this.type,
6430
+ [{
6431
+ role: normalizedMessage.role,
6432
+ senderName: normalizedMessage.senderName,
6433
+ kind: normalizedMessage.kind,
6434
+ content: normalizedContent,
6435
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
6436
+ historyDedupKey: dedupKey
6437
+ }],
6438
+ this.chatTitle || this.agentName || this.provider.name,
6439
+ this.instanceId,
6440
+ this.chatId || this.instanceId
6441
+ );
6442
+ }
6088
6443
  }
6089
6444
  /**
6090
6445
  * Assign stable receivedAt to extension messages.
@@ -6101,16 +6456,16 @@ var ExtensionProviderInstance = class {
6101
6456
  nextHashes.set(hash, msg.receivedAt);
6102
6457
  }
6103
6458
  this.prevMessageHashes = nextHashes;
6104
- return messages;
6459
+ return normalizeChatMessages(messages);
6105
6460
  }
6106
6461
  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) => {
6462
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
6463
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
6109
6464
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
6110
6465
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
6111
6466
  if (aTime !== bTime) return aTime - bTime;
6112
6467
  return a.index - b.index;
6113
- }).map((entry) => entry.message);
6468
+ }).map((entry) => entry.message));
6114
6469
  }
6115
6470
  getPersistedEffectContent(effect) {
6116
6471
  if (effect.type === "message") {
@@ -6224,6 +6579,7 @@ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
6224
6579
  }
6225
6580
 
6226
6581
  // src/providers/ide-provider-instance.ts
6582
+ init_chat_message_normalization();
6227
6583
  var IdeProviderInstance = class {
6228
6584
  type;
6229
6585
  category = "ide";
@@ -6604,8 +6960,8 @@ var IdeProviderInstance = class {
6604
6960
  if (this.appliedEffectKeys.has(effectKey)) continue;
6605
6961
  this.appliedEffectKeys.add(effectKey);
6606
6962
  if (effect.persist !== false) {
6607
- const persisted = this.getPersistedEffectContent(effect);
6608
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
6963
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
6964
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
6609
6965
  }
6610
6966
  if (effect.type === "message" && effect.message) {
6611
6967
  this.pushEvent({
@@ -6640,8 +6996,20 @@ var IdeProviderInstance = class {
6640
6996
  }
6641
6997
  }
6642
6998
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
6643
- const normalizedContent = String(content || "").trim();
6644
- if (!normalizedContent) return;
6999
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
7000
+ content,
7001
+ receivedAt,
7002
+ timestamp: receivedAt
7003
+ }), dedupKey);
7004
+ }
7005
+ appendRuntimeMessage(message, dedupKey) {
7006
+ const normalizedMessage = buildChatMessage({
7007
+ ...message,
7008
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
7009
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
7010
+ });
7011
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
7012
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
6645
7013
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
6646
7014
  if (!this.cachedChat) {
6647
7015
  this.cachedChat = {
@@ -6654,39 +7022,35 @@ var IdeProviderInstance = class {
6654
7022
  };
6655
7023
  }
6656
7024
  this.runtimeMessages.push({
6657
- key: dedupKey,
6658
- message: {
6659
- role: "system",
6660
- senderName: "System",
6661
- content: normalizedContent,
6662
- receivedAt,
6663
- timestamp: receivedAt
6664
- }
7025
+ key: dedupKey,
7026
+ message: normalizedMessage
6665
7027
  });
6666
7028
  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
- );
7029
+ if (normalizedContent) {
7030
+ this.historyWriter.appendNewMessages(
7031
+ this.type,
7032
+ [{
7033
+ role: normalizedMessage.role,
7034
+ senderName: normalizedMessage.senderName,
7035
+ kind: normalizedMessage.kind,
7036
+ content: normalizedContent,
7037
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
7038
+ historyDedupKey: dedupKey
7039
+ }],
7040
+ this.cachedChat?.title || this.provider.name,
7041
+ this.instanceId,
7042
+ this.cachedChat?.id || this.instanceId
7043
+ );
7044
+ }
6681
7045
  }
6682
7046
  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) => {
7047
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
7048
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
6685
7049
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
6686
7050
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
6687
7051
  if (aTime !== bTime) return aTime - bTime;
6688
7052
  return a.index - b.index;
6689
- }).map((entry) => entry.message);
7053
+ }).map((entry) => entry.message));
6690
7054
  }
6691
7055
  getPersistedEffectContent(effect) {
6692
7056
  if (effect.type === "message") {
@@ -7589,219 +7953,6 @@ function reconcileIdeRuntimeSessions(instanceManager, sessionRegistry) {
7589
7953
  // src/commands/handler.ts
7590
7954
  init_logger();
7591
7955
 
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
7956
  // src/commands/chat-commands.ts
7806
7957
  init_logger();
7807
7958
 
@@ -7932,6 +8083,7 @@ function createInteractionId(prefix = "ix") {
7932
8083
  }
7933
8084
 
7934
8085
  // src/commands/chat-commands.ts
8086
+ init_chat_message_normalization();
7935
8087
  var RECENT_SEND_WINDOW_MS = 1200;
7936
8088
  var recentSendByTarget = /* @__PURE__ */ new Map();
7937
8089
  function hashSignatureParts(parts) {
@@ -8061,7 +8213,7 @@ function normalizeReadChatCursor(args) {
8061
8213
  }
8062
8214
  function normalizeReadChatMessages(payload) {
8063
8215
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
8064
- return messages;
8216
+ return normalizeChatMessages(messages);
8065
8217
  }
8066
8218
  function deriveHistoryDedupKey(message) {
8067
8219
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -10409,6 +10561,7 @@ import * as fs5 from "fs";
10409
10561
  import { createRequire } from "module";
10410
10562
  init_provider_cli_adapter();
10411
10563
  init_logger();
10564
+ init_chat_message_normalization();
10412
10565
  var CachedDatabaseSync = null;
10413
10566
  function getDatabaseSync() {
10414
10567
  if (CachedDatabaseSync) return CachedDatabaseSync;
@@ -10903,8 +11056,8 @@ var CliProviderInstance = class {
10903
11056
  if (this.appliedEffectKeys.has(effectKey)) continue;
10904
11057
  this.appliedEffectKeys.add(effectKey);
10905
11058
  if (effect.persist !== false) {
10906
- const persisted = this.getPersistedEffectContent(effect);
10907
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
11059
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
11060
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
10908
11061
  }
10909
11062
  if (effect.type === "message" && effect.message) {
10910
11063
  const content = typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content);
@@ -11028,44 +11181,53 @@ ${effect.notification.body || ""}`.trim();
11028
11181
  );
11029
11182
  }
11030
11183
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
11031
- const normalizedContent = String(content || "").trim();
11032
- if (!normalizedContent) return;
11184
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
11185
+ content,
11186
+ receivedAt,
11187
+ timestamp: receivedAt
11188
+ }), dedupKey);
11189
+ }
11190
+ appendRuntimeMessage(message, dedupKey) {
11191
+ const normalizedMessage = buildChatMessage({
11192
+ ...message,
11193
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
11194
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
11195
+ });
11196
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
11197
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
11033
11198
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
11034
11199
  this.runtimeMessages.push({
11035
11200
  key: dedupKey,
11036
- message: {
11037
- role: "system",
11038
- senderName: "System",
11039
- content: normalizedContent,
11040
- receivedAt,
11041
- timestamp: receivedAt
11042
- }
11201
+ message: normalizedMessage
11043
11202
  });
11044
11203
  if (this.runtimeMessages.length > 50) {
11045
11204
  this.runtimeMessages = this.runtimeMessages.slice(-50);
11046
11205
  }
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
- );
11206
+ if (normalizedContent) {
11207
+ this.historyWriter.appendNewMessages(
11208
+ this.type,
11209
+ [{
11210
+ role: normalizedMessage.role,
11211
+ senderName: normalizedMessage.senderName,
11212
+ kind: normalizedMessage.kind,
11213
+ content: normalizedContent,
11214
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
11215
+ historyDedupKey: dedupKey
11216
+ }],
11217
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
11218
+ this.instanceId,
11219
+ this.providerSessionId
11220
+ );
11221
+ }
11060
11222
  }
11061
11223
  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) => {
11224
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
11225
+ return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
11064
11226
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
11065
11227
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
11066
11228
  if (aTime !== bTime) return aTime - bTime;
11067
11229
  return a.index - b.index;
11068
- }).map((entry) => entry.message);
11230
+ }).map((entry) => entry.message));
11069
11231
  }
11070
11232
  formatApprovalRequestMessage(modalMessage, buttons) {
11071
11233
  const lines = ["Approval requested"];
@@ -11141,6 +11303,7 @@ import {
11141
11303
  RequestError,
11142
11304
  PROTOCOL_VERSION
11143
11305
  } from "@agentclientprotocol/sdk";
11306
+ init_chat_message_normalization();
11144
11307
  init_logger();
11145
11308
  function getPromptCapabilityFlags(agentCapabilities) {
11146
11309
  const prompt = agentCapabilities?.promptCapabilities || {};
@@ -11306,24 +11469,21 @@ var AcpProviderInstance = class {
11306
11469
  }
11307
11470
  getState() {
11308
11471
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
11309
- const recentMessages = this.messages.slice(-50).map((m) => {
11472
+ const recentMessages = normalizeChatMessages(this.messages.slice(-50).map((m) => {
11310
11473
  const content = this.truncateContent(m.content);
11311
- return {
11312
- role: m.role,
11313
- content,
11314
- timestamp: m.timestamp,
11315
- toolCalls: m.toolCalls
11316
- };
11317
- });
11474
+ return buildChatMessage({
11475
+ ...m,
11476
+ content
11477
+ });
11478
+ }));
11318
11479
  if (this.currentStatus === "generating" && (this.partialContent || this.partialBlocks.length > 0)) {
11319
11480
  const blocks = this.buildPartialBlocks();
11320
11481
  if (blocks.length > 0) {
11321
- recentMessages.push({
11322
- role: "assistant",
11482
+ recentMessages.push(buildAssistantChatMessage({
11323
11483
  content: blocks,
11324
11484
  timestamp: Date.now(),
11325
11485
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
11326
- });
11486
+ }));
11327
11487
  }
11328
11488
  }
11329
11489
  return {
@@ -11336,7 +11496,7 @@ var AcpProviderInstance = class {
11336
11496
  id: this.sessionId || `${this.type}_${this.workingDir}`,
11337
11497
  title: `${this.provider.name} \xB7 ${dirName}`,
11338
11498
  status: this.currentStatus,
11339
- messages: recentMessages,
11499
+ messages: normalizeChatMessages(recentMessages),
11340
11500
  activeModal: this.currentStatus === "waiting_approval" ? {
11341
11501
  message: this.activeToolCalls.find((t) => t.status === "running")?.name || "Permission requested",
11342
11502
  buttons: ["Approve", "Reject"]
@@ -11868,11 +12028,10 @@ var AcpProviderInstance = class {
11868
12028
  if (b.type === "resource") return { type: "resource", resource: b.resource };
11869
12029
  return { type: "text", text: flattenContent([b]) };
11870
12030
  }) : [{ type: "text", text }];
11871
- this.messages.push({
11872
- role: "user",
12031
+ this.messages.push(buildUserChatMessage({
11873
12032
  content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
11874
12033
  timestamp: Date.now()
11875
- });
12034
+ }));
11876
12035
  this.currentStatus = "generating";
11877
12036
  this.partialContent = "";
11878
12037
  this.partialBlocks = [];
@@ -12042,11 +12201,11 @@ var AcpProviderInstance = class {
12042
12201
  content = m.content.filter((p) => p.type === "text").map((p) => p.text || "").join("\n");
12043
12202
  }
12044
12203
  if (content.trim()) {
12045
- this.messages.push({
12204
+ this.messages.push(buildChatMessage({
12046
12205
  role: m.role || "assistant",
12047
12206
  content: content.trim(),
12048
12207
  timestamp: Date.now()
12049
- });
12208
+ }));
12050
12209
  this.partialContent = "";
12051
12210
  }
12052
12211
  }
@@ -12122,12 +12281,11 @@ var AcpProviderInstance = class {
12122
12281
  return b;
12123
12282
  }).filter((b) => b.type !== "text" || b.type === "text" && b.text.trim());
12124
12283
  if (finalBlocks.length > 0) {
12125
- this.messages.push({
12126
- role: "assistant",
12284
+ this.messages.push(buildAssistantChatMessage({
12127
12285
  content: finalBlocks.length === 1 && finalBlocks[0].type === "text" ? finalBlocks[0].text : finalBlocks,
12128
12286
  timestamp: Date.now(),
12129
12287
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
12130
- });
12288
+ }));
12131
12289
  }
12132
12290
  this.partialContent = "";
12133
12291
  this.partialBlocks = [];
@@ -12187,11 +12345,10 @@ var AcpProviderInstance = class {
12187
12345
  appendSystemMessage(content, timestamp = Date.now()) {
12188
12346
  const normalizedContent = String(content || "").trim();
12189
12347
  if (!normalizedContent) return;
12190
- this.messages.push({
12191
- role: "system",
12348
+ this.messages.push(buildRuntimeSystemChatMessage({
12192
12349
  content: normalizedContent,
12193
12350
  timestamp
12194
- });
12351
+ }));
12195
12352
  if (this.messages.length > 200) {
12196
12353
  this.messages = this.messages.slice(-100);
12197
12354
  }
@@ -16862,6 +17019,7 @@ var DaemonAgentStreamManager = class {
16862
17019
 
16863
17020
  // src/agent-stream/poller.ts
16864
17021
  init_logger();
17022
+ init_chat_message_normalization();
16865
17023
  var AgentStreamPoller = class {
16866
17024
  deps;
16867
17025
  timer = null;
@@ -17017,12 +17175,9 @@ var AgentStreamPoller = class {
17017
17175
  type: "message",
17018
17176
  id: effectId,
17019
17177
  persist: true,
17020
- message: {
17021
- role: "system",
17022
- senderName: "System",
17023
- kind: "system",
17178
+ message: buildRuntimeSystemChatMessage({
17024
17179
  content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
17025
- }
17180
+ })
17026
17181
  }
17027
17182
  ]
17028
17183
  };
@@ -17269,6 +17424,9 @@ var ProviderInstanceManager = class {
17269
17424
  }
17270
17425
  };
17271
17426
 
17427
+ // src/index.ts
17428
+ init_chat_message_normalization();
17429
+
17272
17430
  // src/providers/version-archive.ts
17273
17431
  import * as fs10 from "fs";
17274
17432
  import * as path18 from "path";
@@ -23548,6 +23706,7 @@ async function shutdownDaemonComponents(components) {
23548
23706
  export {
23549
23707
  AcpProviderInstance,
23550
23708
  AgentStreamPoller,
23709
+ BUILTIN_CHAT_MESSAGE_KINDS,
23551
23710
  CdpDomHandlers,
23552
23711
  CliProviderInstance,
23553
23712
  DAEMON_WS_PATH,
@@ -23572,9 +23731,14 @@ export {
23572
23731
  SessionHostPtyTransportFactory,
23573
23732
  VersionArchive,
23574
23733
  appendRecentActivity,
23734
+ buildAssistantChatMessage,
23735
+ buildChatMessage,
23575
23736
  buildMachineInfo,
23737
+ buildRuntimeSystemChatMessage,
23576
23738
  buildSessionEntries,
23577
23739
  buildStatusSnapshot,
23740
+ buildSystemChatMessage,
23741
+ buildUserChatMessage,
23578
23742
  clearDebugTrace,
23579
23743
  configureDebugTraceStore,
23580
23744
  connectCdpManager,
@@ -23606,6 +23770,7 @@ export {
23606
23770
  initDaemonComponents,
23607
23771
  installExtensions,
23608
23772
  installGlobalInterceptor,
23773
+ isBuiltinChatMessageKind,
23609
23774
  isCdpConnected,
23610
23775
  isExtensionInstalled,
23611
23776
  isIdeRunning,
@@ -23624,6 +23789,9 @@ export {
23624
23789
  markSetupComplete,
23625
23790
  maybeRunDaemonUpgradeHelperFromEnv,
23626
23791
  normalizeActiveChatData,
23792
+ normalizeChatMessage,
23793
+ normalizeChatMessageKind,
23794
+ normalizeChatMessages,
23627
23795
  normalizeInputEnvelope,
23628
23796
  normalizeManagedStatus,
23629
23797
  normalizeMessageParts,