adhdev 0.8.60 → 0.8.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2495,6 +2495,231 @@ var init_devtools = __esm({
2495
2495
  }
2496
2496
  });
2497
2497
 
2498
+ // ../../oss/packages/daemon-core/src/providers/io-contracts.ts
2499
+ function normalizeInputEnvelope(input) {
2500
+ const normalized = normalizeInputEnvelopePayload(input);
2501
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
2502
+ return {
2503
+ parts: normalized.parts,
2504
+ textFallback,
2505
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
2506
+ };
2507
+ }
2508
+ function normalizeMessageParts(content) {
2509
+ if (typeof content === "string") return [{ type: "text", text: content }];
2510
+ if (!Array.isArray(content)) {
2511
+ if (content && typeof content === "object" && typeof content.text === "string") {
2512
+ return [{ type: "text", text: String(content.text) }];
2513
+ }
2514
+ return [];
2515
+ }
2516
+ const parts = [];
2517
+ for (const raw of content) {
2518
+ if (typeof raw === "string") {
2519
+ parts.push({ type: "text", text: raw });
2520
+ continue;
2521
+ }
2522
+ if (!raw || typeof raw !== "object") continue;
2523
+ const part = normalizeMessagePartObject(raw);
2524
+ if (part) parts.push(part);
2525
+ }
2526
+ return parts;
2527
+ }
2528
+ function flattenMessageParts(parts) {
2529
+ return parts.map((part) => {
2530
+ if (part.type === "text") return part.text;
2531
+ if (part.type === "resource") return part.resource.text || "";
2532
+ return "";
2533
+ }).filter((value) => value.length > 0).join("\n");
2534
+ }
2535
+ function normalizeInputEnvelopePayload(input) {
2536
+ if (typeof input === "string") {
2537
+ return { parts: [{ type: "text", text: input }], textFallback: input };
2538
+ }
2539
+ if (!input || typeof input !== "object") {
2540
+ return { parts: [], textFallback: "" };
2541
+ }
2542
+ const record2 = input;
2543
+ const nestedInput = record2.input;
2544
+ if (nestedInput && typeof nestedInput === "object") {
2545
+ const nested = nestedInput;
2546
+ return {
2547
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
2548
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
2549
+ metadata: normalizeInputMetadata(nested.metadata)
2550
+ };
2551
+ }
2552
+ const directText = typeof record2.text === "string" ? record2.text : typeof record2.message === "string" ? record2.message : void 0;
2553
+ if (directText !== void 0) {
2554
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
2555
+ }
2556
+ const directParts = normalizeInputParts(record2.parts ?? record2.prompt);
2557
+ return {
2558
+ parts: directParts,
2559
+ textFallback: typeof record2.textFallback === "string" ? record2.textFallback : void 0,
2560
+ metadata: normalizeInputMetadata(record2.metadata)
2561
+ };
2562
+ }
2563
+ function normalizeInputMetadata(value) {
2564
+ if (!value || typeof value !== "object") return void 0;
2565
+ const record2 = value;
2566
+ const metadata = {};
2567
+ if (record2.source === "dashboard" || record2.source === "shortcut_api" || record2.source === "provider_script" || record2.source === "session_replay") {
2568
+ metadata.source = record2.source;
2569
+ }
2570
+ if (typeof record2.clientTimestamp === "number" && Number.isFinite(record2.clientTimestamp)) {
2571
+ metadata.clientTimestamp = record2.clientTimestamp;
2572
+ }
2573
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
2574
+ }
2575
+ function normalizeInputParts(value) {
2576
+ if (!Array.isArray(value)) return [];
2577
+ const parts = [];
2578
+ for (const raw of value) {
2579
+ if (typeof raw === "string") {
2580
+ parts.push({ type: "text", text: raw });
2581
+ continue;
2582
+ }
2583
+ if (!raw || typeof raw !== "object") continue;
2584
+ const part = normalizeInputPartObject(raw);
2585
+ if (part) parts.push(part);
2586
+ }
2587
+ return parts;
2588
+ }
2589
+ function normalizeInputPartObject(raw) {
2590
+ const type = raw.type;
2591
+ if (type === "text" && typeof raw.text === "string") {
2592
+ return { type, text: raw.text };
2593
+ }
2594
+ if (type === "image" && typeof raw.mimeType === "string") {
2595
+ return {
2596
+ type,
2597
+ mimeType: raw.mimeType,
2598
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
2599
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
2600
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
2601
+ };
2602
+ }
2603
+ if (type === "audio" && typeof raw.mimeType === "string") {
2604
+ return {
2605
+ type,
2606
+ mimeType: raw.mimeType,
2607
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
2608
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
2609
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
2610
+ };
2611
+ }
2612
+ if (type === "video" && typeof raw.mimeType === "string") {
2613
+ return {
2614
+ type,
2615
+ mimeType: raw.mimeType,
2616
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
2617
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
2618
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
2619
+ };
2620
+ }
2621
+ if (type === "resource" && typeof raw.uri === "string") {
2622
+ return {
2623
+ type,
2624
+ uri: raw.uri,
2625
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
2626
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
2627
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
2628
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
2629
+ };
2630
+ }
2631
+ if (type === "resource_link" && typeof raw.uri === "string") {
2632
+ return {
2633
+ type: "resource",
2634
+ uri: raw.uri,
2635
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
2636
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
2637
+ };
2638
+ }
2639
+ return null;
2640
+ }
2641
+ function normalizeMessagePartObject(raw) {
2642
+ const type = raw.type;
2643
+ if (type === "text" && typeof raw.text === "string") {
2644
+ return { type, text: raw.text };
2645
+ }
2646
+ if (type === "image" && typeof raw.mimeType === "string") {
2647
+ return {
2648
+ type,
2649
+ mimeType: raw.mimeType,
2650
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
2651
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
2652
+ };
2653
+ }
2654
+ if (type === "audio" && typeof raw.mimeType === "string") {
2655
+ return {
2656
+ type,
2657
+ mimeType: raw.mimeType,
2658
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
2659
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
2660
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
2661
+ };
2662
+ }
2663
+ if (type === "video" && typeof raw.mimeType === "string") {
2664
+ return {
2665
+ type,
2666
+ mimeType: raw.mimeType,
2667
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
2668
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
2669
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
2670
+ };
2671
+ }
2672
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
2673
+ return {
2674
+ type,
2675
+ uri: raw.uri,
2676
+ name: raw.name,
2677
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
2678
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
2679
+ };
2680
+ }
2681
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
2682
+ const resource = raw.resource;
2683
+ if (typeof resource.uri !== "string") return null;
2684
+ return {
2685
+ type,
2686
+ resource: {
2687
+ uri: resource.uri,
2688
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
2689
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
2690
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
2691
+ }
2692
+ };
2693
+ }
2694
+ return null;
2695
+ }
2696
+ function flattenInputParts(parts) {
2697
+ return parts.map((part) => {
2698
+ if (part.type === "text") return part.text;
2699
+ if (part.type === "audio") return part.transcript || "";
2700
+ if (part.type === "resource") return part.text || "";
2701
+ return "";
2702
+ }).filter((value) => value.length > 0).join("\n");
2703
+ }
2704
+ var init_io_contracts = __esm({
2705
+ "../../oss/packages/daemon-core/src/providers/io-contracts.ts"() {
2706
+ "use strict";
2707
+ }
2708
+ });
2709
+
2710
+ // ../../oss/packages/daemon-core/src/providers/contracts.ts
2711
+ function flattenContent(content) {
2712
+ if (typeof content === "string") return content;
2713
+ return flattenMessageParts(normalizeMessageParts(content));
2714
+ }
2715
+ var init_contracts = __esm({
2716
+ "../../oss/packages/daemon-core/src/providers/contracts.ts"() {
2717
+ "use strict";
2718
+ init_io_contracts();
2719
+ init_io_contracts();
2720
+ }
2721
+ });
2722
+
2498
2723
  // ../../oss/packages/daemon-core/src/providers/status-monitor.ts
2499
2724
  var DEFAULT_MONITOR_CONFIG, StatusMonitor;
2500
2725
  var init_status_monitor = __esm({
@@ -2613,6 +2838,64 @@ var init_status_monitor = __esm({
2613
2838
  }
2614
2839
  });
2615
2840
 
2841
+ // ../../oss/packages/daemon-core/src/providers/chat-message-normalization.ts
2842
+ function isBuiltinChatMessageKind(kind) {
2843
+ return typeof kind === "string" && KNOWN_CHAT_MESSAGE_KINDS.has(kind.trim().toLowerCase());
2844
+ }
2845
+ function normalizeChatMessageKind(kind, role) {
2846
+ const normalizedKind = typeof kind === "string" ? kind.trim().toLowerCase() : "";
2847
+ if (normalizedKind && KNOWN_CHAT_MESSAGE_KINDS.has(normalizedKind)) return normalizedKind;
2848
+ const normalizedRole = typeof role === "string" ? role.trim().toLowerCase() : "";
2849
+ return normalizedRole === "system" ? "system" : "standard";
2850
+ }
2851
+ function buildChatMessage(message) {
2852
+ return {
2853
+ ...message,
2854
+ kind: normalizeChatMessageKind(message?.kind, message?.role)
2855
+ };
2856
+ }
2857
+ function buildSystemChatMessage(message) {
2858
+ return buildChatMessage({
2859
+ ...message,
2860
+ role: "system",
2861
+ kind: message?.kind || "system"
2862
+ });
2863
+ }
2864
+ function buildRuntimeSystemChatMessage(message) {
2865
+ return buildSystemChatMessage({
2866
+ ...message,
2867
+ senderName: typeof message?.senderName === "string" && message.senderName.trim() ? message.senderName : "System"
2868
+ });
2869
+ }
2870
+ function buildAssistantChatMessage(message) {
2871
+ return buildChatMessage({
2872
+ ...message,
2873
+ role: "assistant",
2874
+ kind: message?.kind || "standard"
2875
+ });
2876
+ }
2877
+ function buildUserChatMessage(message) {
2878
+ return buildChatMessage({
2879
+ ...message,
2880
+ role: "user",
2881
+ kind: message?.kind || "standard"
2882
+ });
2883
+ }
2884
+ function normalizeChatMessage(message) {
2885
+ return buildChatMessage(message);
2886
+ }
2887
+ function normalizeChatMessages(messages) {
2888
+ return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
2889
+ }
2890
+ var BUILTIN_CHAT_MESSAGE_KINDS, KNOWN_CHAT_MESSAGE_KINDS;
2891
+ var init_chat_message_normalization = __esm({
2892
+ "../../oss/packages/daemon-core/src/providers/chat-message-normalization.ts"() {
2893
+ "use strict";
2894
+ BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
2895
+ KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
2896
+ }
2897
+ });
2898
+
2616
2899
  // ../../oss/packages/daemon-core/src/providers/control-effects.ts
2617
2900
  function extractProviderControlValues(controls, data) {
2618
2901
  if (!data || typeof data !== "object") return void 0;
@@ -2681,13 +2964,58 @@ function normalizeProviderEffects(data) {
2681
2964
  level: raw.notification.level === "success" || raw.notification.level === "warning" ? raw.notification.level : "info",
2682
2965
  channels: Array.isArray(raw.notification.channels) ? raw.notification.channels.filter((channel) => channel === "bubble" || channel === "toast" || channel === "browser") : void 0,
2683
2966
  preferenceKey: raw.notification.preferenceKey === "disconnect" || raw.notification.preferenceKey === "completion" || raw.notification.preferenceKey === "approval" || raw.notification.preferenceKey === "browser" ? raw.notification.preferenceKey : void 0,
2684
- bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0
2967
+ bubbleContent: typeof raw.notification.bubbleContent === "string" || Array.isArray(raw.notification.bubbleContent) ? raw.notification.bubbleContent : void 0,
2968
+ bubbleKind: typeof raw.notification.bubbleKind === "string" ? raw.notification.bubbleKind : void 0,
2969
+ bubbleRole: raw.notification.bubbleRole === "assistant" || raw.notification.bubbleRole === "user" ? raw.notification.bubbleRole : raw.notification.bubbleRole === "system" ? "system" : void 0,
2970
+ bubbleSenderName: typeof raw.notification.bubbleSenderName === "string" ? raw.notification.bubbleSenderName : void 0
2685
2971
  }
2686
2972
  });
2687
2973
  }
2688
2974
  }
2689
2975
  return effects;
2690
2976
  }
2977
+ function buildPersistedProviderEffectMessage(effect) {
2978
+ if (!effect) return null;
2979
+ if (effect.type === "message" && effect.message) {
2980
+ const role = effect.message.role === "assistant" || effect.message.role === "user" ? effect.message.role : "system";
2981
+ if (role === "system") {
2982
+ return buildRuntimeSystemChatMessage({
2983
+ content: effect.message.content,
2984
+ kind: effect.message.kind,
2985
+ senderName: effect.message.senderName
2986
+ });
2987
+ }
2988
+ return buildChatMessage({
2989
+ role,
2990
+ content: effect.message.content,
2991
+ kind: effect.message.kind,
2992
+ senderName: effect.message.senderName
2993
+ });
2994
+ }
2995
+ if (effect.type === "notification" && effect.notification) {
2996
+ const bubbleContent = effect.notification.bubbleContent ?? formatNotificationBubbleFallback(effect.notification.title, effect.notification.body);
2997
+ const flattened = typeof bubbleContent === "string" ? bubbleContent.trim() : flattenContent(bubbleContent).trim();
2998
+ if (!flattened && (!Array.isArray(bubbleContent) || bubbleContent.length === 0)) return null;
2999
+ const role = effect.notification.bubbleRole === "assistant" || effect.notification.bubbleRole === "user" ? effect.notification.bubbleRole : "system";
3000
+ if (role === "system") {
3001
+ return buildRuntimeSystemChatMessage({
3002
+ content: bubbleContent,
3003
+ kind: effect.notification.bubbleKind,
3004
+ senderName: effect.notification.bubbleSenderName
3005
+ });
3006
+ }
3007
+ return buildChatMessage({
3008
+ role,
3009
+ content: bubbleContent,
3010
+ kind: effect.notification.bubbleKind,
3011
+ senderName: effect.notification.bubbleSenderName
3012
+ });
3013
+ }
3014
+ if (effect.type === "toast" && effect.toast?.message) {
3015
+ return buildRuntimeSystemChatMessage({ content: effect.toast.message });
3016
+ }
3017
+ return null;
3018
+ }
2691
3019
  function normalizeControlListResult(data) {
2692
3020
  if (data && typeof data === "object" && Array.isArray(data.options)) {
2693
3021
  return {
@@ -2754,9 +3082,18 @@ function normalizeControlValue(value) {
2754
3082
  }
2755
3083
  return String(value);
2756
3084
  }
3085
+ function formatNotificationBubbleFallback(title, body) {
3086
+ const cleanTitle = typeof title === "string" ? title.trim() : "";
3087
+ const cleanBody = String(body || "").trim();
3088
+ if (cleanTitle && cleanBody) return `${cleanTitle}
3089
+ ${cleanBody}`;
3090
+ return cleanTitle || cleanBody;
3091
+ }
2757
3092
  var init_control_effects = __esm({
2758
3093
  "../../oss/packages/daemon-core/src/providers/control-effects.ts"() {
2759
3094
  "use strict";
3095
+ init_contracts();
3096
+ init_chat_message_normalization();
2760
3097
  }
2761
3098
  });
2762
3099
 
@@ -2944,6 +3281,7 @@ var init_chat_history = __esm({
2944
3281
  fs3 = __toESM(require("fs"));
2945
3282
  path7 = __toESM(require("path"));
2946
3283
  os5 = __toESM(require("os"));
3284
+ init_chat_message_normalization();
2947
3285
  HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
2948
3286
  RETAIN_DAYS = 30;
2949
3287
  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;
@@ -3093,11 +3431,11 @@ var init_chat_history = __esm({
3093
3431
  this.appendNewMessages(
3094
3432
  agentType,
3095
3433
  [{
3096
- role: "system",
3097
- kind: "system",
3098
- content,
3099
- receivedAt: options.receivedAt,
3100
- senderName: options.senderName,
3434
+ ...buildRuntimeSystemChatMessage({
3435
+ content,
3436
+ receivedAt: options.receivedAt,
3437
+ senderName: options.senderName
3438
+ }),
3101
3439
  historyDedupKey: options.dedupKey
3102
3440
  }],
3103
3441
  options.sessionTitle,
@@ -3345,10 +3683,12 @@ var ExtensionProviderInstance;
3345
3683
  var init_extension_provider_instance = __esm({
3346
3684
  "../../oss/packages/daemon-core/src/providers/extension-provider-instance.ts"() {
3347
3685
  "use strict";
3686
+ init_contracts();
3348
3687
  init_status_monitor();
3349
3688
  init_control_effects();
3350
3689
  init_chat_history();
3351
3690
  init_provider_patch_state();
3691
+ init_chat_message_normalization();
3352
3692
  ExtensionProviderInstance = class {
3353
3693
  type;
3354
3694
  category = "extension";
@@ -3555,8 +3895,8 @@ var init_extension_provider_instance = __esm({
3555
3895
  if (this.appliedEffectKeys.has(effectKey)) continue;
3556
3896
  this.appliedEffectKeys.add(effectKey);
3557
3897
  if (effect.persist !== false) {
3558
- const persisted = this.getPersistedEffectContent(effect);
3559
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
3898
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
3899
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
3560
3900
  }
3561
3901
  if (effect.type === "message" && effect.message) {
3562
3902
  this.pushEvent({
@@ -3591,34 +3931,42 @@ var init_extension_provider_instance = __esm({
3591
3931
  }
3592
3932
  }
3593
3933
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
3594
- const normalizedContent = String(content || "").trim();
3595
- if (!normalizedContent) return;
3934
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
3935
+ content,
3936
+ receivedAt,
3937
+ timestamp: receivedAt
3938
+ }), dedupKey);
3939
+ }
3940
+ appendRuntimeMessage(message, dedupKey) {
3941
+ const normalizedMessage = buildChatMessage({
3942
+ ...message,
3943
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
3944
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
3945
+ });
3946
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
3947
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
3596
3948
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
3597
3949
  this.runtimeMessages.push({
3598
3950
  key: dedupKey,
3599
- message: {
3600
- role: "system",
3601
- senderName: "System",
3602
- content: normalizedContent,
3603
- receivedAt,
3604
- timestamp: receivedAt
3605
- }
3951
+ message: normalizedMessage
3606
3952
  });
3607
3953
  if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
3608
- this.historyWriter.appendNewMessages(
3609
- this.type,
3610
- [{
3611
- role: "system",
3612
- senderName: "System",
3613
- content: normalizedContent,
3614
- kind: "system",
3615
- receivedAt,
3616
- historyDedupKey: dedupKey
3617
- }],
3618
- this.chatTitle || this.agentName || this.provider.name,
3619
- this.instanceId,
3620
- this.chatId || this.instanceId
3621
- );
3954
+ if (normalizedContent) {
3955
+ this.historyWriter.appendNewMessages(
3956
+ this.type,
3957
+ [{
3958
+ role: normalizedMessage.role,
3959
+ senderName: normalizedMessage.senderName,
3960
+ kind: normalizedMessage.kind,
3961
+ content: normalizedContent,
3962
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
3963
+ historyDedupKey: dedupKey
3964
+ }],
3965
+ this.chatTitle || this.agentName || this.provider.name,
3966
+ this.instanceId,
3967
+ this.chatId || this.instanceId
3968
+ );
3969
+ }
3622
3970
  }
3623
3971
  /**
3624
3972
  * Assign stable receivedAt to extension messages.
@@ -3635,16 +3983,16 @@ var init_extension_provider_instance = __esm({
3635
3983
  nextHashes.set(hash2, msg.receivedAt);
3636
3984
  }
3637
3985
  this.prevMessageHashes = nextHashes;
3638
- return messages;
3986
+ return normalizeChatMessages(messages);
3639
3987
  }
3640
3988
  mergeConversationMessages(messages) {
3641
- if (this.runtimeMessages.length === 0) return messages;
3642
- return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
3989
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
3990
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
3643
3991
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
3644
3992
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
3645
3993
  if (aTime !== bTime) return aTime - bTime;
3646
3994
  return a.index - b.index;
3647
- }).map((entry) => entry.message);
3995
+ }).map((entry) => entry.message));
3648
3996
  }
3649
3997
  getPersistedEffectContent(effect) {
3650
3998
  if (effect.type === "message") {
@@ -3768,6 +4116,7 @@ var init_ide_provider_instance = __esm({
3768
4116
  "../../oss/packages/daemon-core/src/providers/ide-provider-instance.ts"() {
3769
4117
  "use strict";
3770
4118
  crypto2 = __toESM(require("crypto"));
4119
+ init_contracts();
3771
4120
  init_extension_provider_instance();
3772
4121
  init_status_monitor();
3773
4122
  init_chat_history();
@@ -3775,6 +4124,7 @@ var init_ide_provider_instance = __esm({
3775
4124
  init_control_effects();
3776
4125
  init_approval_utils();
3777
4126
  init_provider_patch_state();
4127
+ init_chat_message_normalization();
3778
4128
  IdeProviderInstance = class {
3779
4129
  type;
3780
4130
  category = "ide";
@@ -4155,8 +4505,8 @@ var init_ide_provider_instance = __esm({
4155
4505
  if (this.appliedEffectKeys.has(effectKey)) continue;
4156
4506
  this.appliedEffectKeys.add(effectKey);
4157
4507
  if (effect.persist !== false) {
4158
- const persisted = this.getPersistedEffectContent(effect);
4159
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
4508
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
4509
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
4160
4510
  }
4161
4511
  if (effect.type === "message" && effect.message) {
4162
4512
  this.pushEvent({
@@ -4191,8 +4541,20 @@ var init_ide_provider_instance = __esm({
4191
4541
  }
4192
4542
  }
4193
4543
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
4194
- const normalizedContent = String(content || "").trim();
4195
- if (!normalizedContent) return;
4544
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
4545
+ content,
4546
+ receivedAt,
4547
+ timestamp: receivedAt
4548
+ }), dedupKey);
4549
+ }
4550
+ appendRuntimeMessage(message, dedupKey) {
4551
+ const normalizedMessage = buildChatMessage({
4552
+ ...message,
4553
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
4554
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
4555
+ });
4556
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
4557
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
4196
4558
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
4197
4559
  if (!this.cachedChat) {
4198
4560
  this.cachedChat = {
@@ -4206,38 +4568,34 @@ var init_ide_provider_instance = __esm({
4206
4568
  }
4207
4569
  this.runtimeMessages.push({
4208
4570
  key: dedupKey,
4209
- message: {
4210
- role: "system",
4211
- senderName: "System",
4212
- content: normalizedContent,
4213
- receivedAt,
4214
- timestamp: receivedAt
4215
- }
4571
+ message: normalizedMessage
4216
4572
  });
4217
4573
  if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
4218
- this.historyWriter.appendNewMessages(
4219
- this.type,
4220
- [{
4221
- role: "system",
4222
- senderName: "System",
4223
- content: normalizedContent,
4224
- kind: "system",
4225
- receivedAt,
4226
- historyDedupKey: dedupKey
4227
- }],
4228
- this.cachedChat?.title || this.provider.name,
4229
- this.instanceId,
4230
- this.cachedChat?.id || this.instanceId
4231
- );
4574
+ if (normalizedContent) {
4575
+ this.historyWriter.appendNewMessages(
4576
+ this.type,
4577
+ [{
4578
+ role: normalizedMessage.role,
4579
+ senderName: normalizedMessage.senderName,
4580
+ kind: normalizedMessage.kind,
4581
+ content: normalizedContent,
4582
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
4583
+ historyDedupKey: dedupKey
4584
+ }],
4585
+ this.cachedChat?.title || this.provider.name,
4586
+ this.instanceId,
4587
+ this.cachedChat?.id || this.instanceId
4588
+ );
4589
+ }
4232
4590
  }
4233
4591
  mergeConversationMessages(messages) {
4234
- if (this.runtimeMessages.length === 0) return messages;
4235
- return [...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
4592
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(messages);
4593
+ return normalizeChatMessages([...messages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
4236
4594
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
4237
4595
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
4238
4596
  if (aTime !== bTime) return aTime - bTime;
4239
4597
  return a.index - b.index;
4240
- }).map((entry) => entry.message);
4598
+ }).map((entry) => entry.message));
4241
4599
  }
4242
4600
  getPersistedEffectContent(effect) {
4243
4601
  if (effect.type === "message") {
@@ -5183,231 +5541,6 @@ var init_reconcile = __esm({
5183
5541
  }
5184
5542
  });
5185
5543
 
5186
- // ../../oss/packages/daemon-core/src/providers/io-contracts.ts
5187
- function normalizeInputEnvelope(input) {
5188
- const normalized = normalizeInputEnvelopePayload(input);
5189
- const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
5190
- return {
5191
- parts: normalized.parts,
5192
- textFallback,
5193
- ...normalized.metadata ? { metadata: normalized.metadata } : {}
5194
- };
5195
- }
5196
- function normalizeMessageParts(content) {
5197
- if (typeof content === "string") return [{ type: "text", text: content }];
5198
- if (!Array.isArray(content)) {
5199
- if (content && typeof content === "object" && typeof content.text === "string") {
5200
- return [{ type: "text", text: String(content.text) }];
5201
- }
5202
- return [];
5203
- }
5204
- const parts = [];
5205
- for (const raw of content) {
5206
- if (typeof raw === "string") {
5207
- parts.push({ type: "text", text: raw });
5208
- continue;
5209
- }
5210
- if (!raw || typeof raw !== "object") continue;
5211
- const part = normalizeMessagePartObject(raw);
5212
- if (part) parts.push(part);
5213
- }
5214
- return parts;
5215
- }
5216
- function flattenMessageParts(parts) {
5217
- return parts.map((part) => {
5218
- if (part.type === "text") return part.text;
5219
- if (part.type === "resource") return part.resource.text || "";
5220
- return "";
5221
- }).filter((value) => value.length > 0).join("\n");
5222
- }
5223
- function normalizeInputEnvelopePayload(input) {
5224
- if (typeof input === "string") {
5225
- return { parts: [{ type: "text", text: input }], textFallback: input };
5226
- }
5227
- if (!input || typeof input !== "object") {
5228
- return { parts: [], textFallback: "" };
5229
- }
5230
- const record2 = input;
5231
- const nestedInput = record2.input;
5232
- if (nestedInput && typeof nestedInput === "object") {
5233
- const nested = nestedInput;
5234
- return {
5235
- parts: normalizeInputParts(nested.parts ?? nested.prompt),
5236
- textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
5237
- metadata: normalizeInputMetadata(nested.metadata)
5238
- };
5239
- }
5240
- const directText = typeof record2.text === "string" ? record2.text : typeof record2.message === "string" ? record2.message : void 0;
5241
- if (directText !== void 0) {
5242
- return { parts: [{ type: "text", text: directText }], textFallback: directText };
5243
- }
5244
- const directParts = normalizeInputParts(record2.parts ?? record2.prompt);
5245
- return {
5246
- parts: directParts,
5247
- textFallback: typeof record2.textFallback === "string" ? record2.textFallback : void 0,
5248
- metadata: normalizeInputMetadata(record2.metadata)
5249
- };
5250
- }
5251
- function normalizeInputMetadata(value) {
5252
- if (!value || typeof value !== "object") return void 0;
5253
- const record2 = value;
5254
- const metadata = {};
5255
- if (record2.source === "dashboard" || record2.source === "shortcut_api" || record2.source === "provider_script" || record2.source === "session_replay") {
5256
- metadata.source = record2.source;
5257
- }
5258
- if (typeof record2.clientTimestamp === "number" && Number.isFinite(record2.clientTimestamp)) {
5259
- metadata.clientTimestamp = record2.clientTimestamp;
5260
- }
5261
- return Object.keys(metadata).length > 0 ? metadata : void 0;
5262
- }
5263
- function normalizeInputParts(value) {
5264
- if (!Array.isArray(value)) return [];
5265
- const parts = [];
5266
- for (const raw of value) {
5267
- if (typeof raw === "string") {
5268
- parts.push({ type: "text", text: raw });
5269
- continue;
5270
- }
5271
- if (!raw || typeof raw !== "object") continue;
5272
- const part = normalizeInputPartObject(raw);
5273
- if (part) parts.push(part);
5274
- }
5275
- return parts;
5276
- }
5277
- function normalizeInputPartObject(raw) {
5278
- const type = raw.type;
5279
- if (type === "text" && typeof raw.text === "string") {
5280
- return { type, text: raw.text };
5281
- }
5282
- if (type === "image" && typeof raw.mimeType === "string") {
5283
- return {
5284
- type,
5285
- mimeType: raw.mimeType,
5286
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5287
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5288
- ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
5289
- };
5290
- }
5291
- if (type === "audio" && typeof raw.mimeType === "string") {
5292
- return {
5293
- type,
5294
- mimeType: raw.mimeType,
5295
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5296
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5297
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5298
- };
5299
- }
5300
- if (type === "video" && typeof raw.mimeType === "string") {
5301
- return {
5302
- type,
5303
- mimeType: raw.mimeType,
5304
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5305
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5306
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5307
- };
5308
- }
5309
- if (type === "resource" && typeof raw.uri === "string") {
5310
- return {
5311
- type,
5312
- uri: raw.uri,
5313
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5314
- ...typeof raw.name === "string" ? { name: raw.name } : {},
5315
- ...typeof raw.text === "string" ? { text: raw.text } : {},
5316
- ...typeof raw.data === "string" ? { data: raw.data } : {}
5317
- };
5318
- }
5319
- if (type === "resource_link" && typeof raw.uri === "string") {
5320
- return {
5321
- type: "resource",
5322
- uri: raw.uri,
5323
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5324
- ...typeof raw.name === "string" ? { name: raw.name } : {}
5325
- };
5326
- }
5327
- return null;
5328
- }
5329
- function normalizeMessagePartObject(raw) {
5330
- const type = raw.type;
5331
- if (type === "text" && typeof raw.text === "string") {
5332
- return { type, text: raw.text };
5333
- }
5334
- if (type === "image" && typeof raw.mimeType === "string") {
5335
- return {
5336
- type,
5337
- mimeType: raw.mimeType,
5338
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5339
- ...typeof raw.data === "string" ? { data: raw.data } : {}
5340
- };
5341
- }
5342
- if (type === "audio" && typeof raw.mimeType === "string") {
5343
- return {
5344
- type,
5345
- mimeType: raw.mimeType,
5346
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5347
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5348
- ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
5349
- };
5350
- }
5351
- if (type === "video" && typeof raw.mimeType === "string") {
5352
- return {
5353
- type,
5354
- mimeType: raw.mimeType,
5355
- ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
5356
- ...typeof raw.data === "string" ? { data: raw.data } : {},
5357
- ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
5358
- };
5359
- }
5360
- if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
5361
- return {
5362
- type,
5363
- uri: raw.uri,
5364
- name: raw.name,
5365
- ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
5366
- ...typeof raw.size === "number" ? { size: raw.size } : {}
5367
- };
5368
- }
5369
- if (type === "resource" && raw.resource && typeof raw.resource === "object") {
5370
- const resource = raw.resource;
5371
- if (typeof resource.uri !== "string") return null;
5372
- return {
5373
- type,
5374
- resource: {
5375
- uri: resource.uri,
5376
- ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
5377
- ...typeof resource.text === "string" ? { text: resource.text } : {},
5378
- ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
5379
- }
5380
- };
5381
- }
5382
- return null;
5383
- }
5384
- function flattenInputParts(parts) {
5385
- return parts.map((part) => {
5386
- if (part.type === "text") return part.text;
5387
- if (part.type === "audio") return part.transcript || "";
5388
- if (part.type === "resource") return part.text || "";
5389
- return "";
5390
- }).filter((value) => value.length > 0).join("\n");
5391
- }
5392
- var init_io_contracts = __esm({
5393
- "../../oss/packages/daemon-core/src/providers/io-contracts.ts"() {
5394
- "use strict";
5395
- }
5396
- });
5397
-
5398
- // ../../oss/packages/daemon-core/src/providers/contracts.ts
5399
- function flattenContent(content) {
5400
- if (typeof content === "string") return content;
5401
- return flattenMessageParts(normalizeMessageParts(content));
5402
- }
5403
- var init_contracts = __esm({
5404
- "../../oss/packages/daemon-core/src/providers/contracts.ts"() {
5405
- "use strict";
5406
- init_io_contracts();
5407
- init_io_contracts();
5408
- }
5409
- });
5410
-
5411
5544
  // ../../oss/packages/daemon-core/src/logging/debug-config.ts
5412
5545
  function normalizeCategories(categories) {
5413
5546
  if (!Array.isArray(categories)) return [];
@@ -5675,7 +5808,7 @@ function normalizeReadChatCursor(args) {
5675
5808
  }
5676
5809
  function normalizeReadChatMessages(payload) {
5677
5810
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
5678
- return messages;
5811
+ return normalizeChatMessages(messages);
5679
5812
  }
5680
5813
  function deriveHistoryDedupKey(message) {
5681
5814
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -6653,6 +6786,7 @@ var init_chat_commands = __esm({
6653
6786
  init_chat_history();
6654
6787
  init_logger();
6655
6788
  init_debug_trace();
6789
+ init_chat_message_normalization();
6656
6790
  RECENT_SEND_WINDOW_MS = 1200;
6657
6791
  recentSendByTarget = /* @__PURE__ */ new Map();
6658
6792
  }
@@ -9635,6 +9769,7 @@ var init_provider_cli_adapter = __esm({
9635
9769
  init_terminal_screen();
9636
9770
  init_pty_transport();
9637
9771
  init_provider_cli_shared();
9772
+ init_chat_message_normalization();
9638
9773
  init_provider_cli_parse();
9639
9774
  init_provider_cli_config();
9640
9775
  init_provider_cli_runtime();
@@ -10692,11 +10827,10 @@ var init_provider_cli_adapter = __esm({
10692
10827
  );
10693
10828
  const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
10694
10829
  if (parsed && Array.isArray(parsed.messages)) {
10695
- const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => ({
10830
+ const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
10696
10831
  ...message,
10697
10832
  id: message.id || `msg_${index}`,
10698
10833
  index: typeof message.index === "number" ? message.index : index,
10699
- kind: message.kind || "standard",
10700
10834
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
10701
10835
  })) : hydrateCliParsedMessages(parsed.messages, {
10702
10836
  committedMessages: this.committedMessages,
@@ -10717,13 +10851,11 @@ var init_provider_cli_adapter = __esm({
10717
10851
  id: "cli_session",
10718
10852
  status: this.currentStatus,
10719
10853
  title: this.cliName,
10720
- messages: messages.slice(-50).map((message, index) => ({
10721
- id: `msg_${index}`,
10722
- role: message.role,
10723
- content: message.content,
10724
- timestamp: message.timestamp,
10725
- index,
10726
- kind: "standard"
10854
+ messages: messages.slice(-50).map((message, index) => buildChatMessage({
10855
+ ...message,
10856
+ id: message.id || `msg_${index}`,
10857
+ index: typeof message.index === "number" ? message.index : index,
10858
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
10727
10859
  })),
10728
10860
  activeModal: this.activeModal
10729
10861
  };
@@ -11406,6 +11538,7 @@ var init_cli_provider_instance = __esm({
11406
11538
  init_approval_utils();
11407
11539
  init_cli_script_results();
11408
11540
  init_provider_patch_state();
11541
+ init_chat_message_normalization();
11409
11542
  CachedDatabaseSync = null;
11410
11543
  CliProviderInstance = class {
11411
11544
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
@@ -11856,8 +11989,8 @@ var init_cli_provider_instance = __esm({
11856
11989
  if (this.appliedEffectKeys.has(effectKey)) continue;
11857
11990
  this.appliedEffectKeys.add(effectKey);
11858
11991
  if (effect.persist !== false) {
11859
- const persisted = this.getPersistedEffectContent(effect);
11860
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
11992
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
11993
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
11861
11994
  }
11862
11995
  if (effect.type === "message" && effect.message) {
11863
11996
  const content = typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content);
@@ -11981,44 +12114,53 @@ ${effect.notification.body || ""}`.trim();
11981
12114
  );
11982
12115
  }
11983
12116
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
11984
- const normalizedContent = String(content || "").trim();
11985
- if (!normalizedContent) return;
12117
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
12118
+ content,
12119
+ receivedAt,
12120
+ timestamp: receivedAt
12121
+ }), dedupKey);
12122
+ }
12123
+ appendRuntimeMessage(message, dedupKey) {
12124
+ const normalizedMessage = buildChatMessage({
12125
+ ...message,
12126
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
12127
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
12128
+ });
12129
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
12130
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
11986
12131
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
11987
12132
  this.runtimeMessages.push({
11988
12133
  key: dedupKey,
11989
- message: {
11990
- role: "system",
11991
- senderName: "System",
11992
- content: normalizedContent,
11993
- receivedAt,
11994
- timestamp: receivedAt
11995
- }
12134
+ message: normalizedMessage
11996
12135
  });
11997
12136
  if (this.runtimeMessages.length > 50) {
11998
12137
  this.runtimeMessages = this.runtimeMessages.slice(-50);
11999
12138
  }
12000
- this.historyWriter.appendNewMessages(
12001
- this.type,
12002
- [{
12003
- role: "system",
12004
- senderName: "System",
12005
- content: normalizedContent,
12006
- receivedAt,
12007
- historyDedupKey: dedupKey
12008
- }],
12009
- this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
12010
- this.instanceId,
12011
- this.providerSessionId
12012
- );
12139
+ if (normalizedContent) {
12140
+ this.historyWriter.appendNewMessages(
12141
+ this.type,
12142
+ [{
12143
+ role: normalizedMessage.role,
12144
+ senderName: normalizedMessage.senderName,
12145
+ kind: normalizedMessage.kind,
12146
+ content: normalizedContent,
12147
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
12148
+ historyDedupKey: dedupKey
12149
+ }],
12150
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
12151
+ this.instanceId,
12152
+ this.providerSessionId
12153
+ );
12154
+ }
12013
12155
  }
12014
12156
  mergeConversationMessages(parsedMessages) {
12015
- if (this.runtimeMessages.length === 0) return parsedMessages;
12016
- return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
12157
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
12158
+ return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
12017
12159
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
12018
12160
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
12019
12161
  if (aTime !== bTime) return aTime - bTime;
12020
12162
  return a.index - b.index;
12021
- }).map((entry) => entry.message);
12163
+ }).map((entry) => entry.message));
12022
12164
  }
12023
12165
  formatApprovalRequestMessage(modalMessage, buttons) {
12024
12166
  const lines = ["Approval requested"];
@@ -28494,6 +28636,7 @@ var init_acp_provider_instance = __esm({
28494
28636
  init_contracts();
28495
28637
  init_status_monitor();
28496
28638
  init_summary_metadata();
28639
+ init_chat_message_normalization();
28497
28640
  init_logger();
28498
28641
  AcpProviderInstance = class {
28499
28642
  constructor(provider, workingDir, cliArgs = []) {
@@ -28564,24 +28707,21 @@ var init_acp_provider_instance = __esm({
28564
28707
  }
28565
28708
  getState() {
28566
28709
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
28567
- const recentMessages = this.messages.slice(-50).map((m) => {
28710
+ const recentMessages = normalizeChatMessages(this.messages.slice(-50).map((m) => {
28568
28711
  const content = this.truncateContent(m.content);
28569
- return {
28570
- role: m.role,
28571
- content,
28572
- timestamp: m.timestamp,
28573
- toolCalls: m.toolCalls
28574
- };
28575
- });
28712
+ return buildChatMessage({
28713
+ ...m,
28714
+ content
28715
+ });
28716
+ }));
28576
28717
  if (this.currentStatus === "generating" && (this.partialContent || this.partialBlocks.length > 0)) {
28577
28718
  const blocks = this.buildPartialBlocks();
28578
28719
  if (blocks.length > 0) {
28579
- recentMessages.push({
28580
- role: "assistant",
28720
+ recentMessages.push(buildAssistantChatMessage({
28581
28721
  content: blocks,
28582
28722
  timestamp: Date.now(),
28583
28723
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
28584
- });
28724
+ }));
28585
28725
  }
28586
28726
  }
28587
28727
  return {
@@ -28594,7 +28734,7 @@ var init_acp_provider_instance = __esm({
28594
28734
  id: this.sessionId || `${this.type}_${this.workingDir}`,
28595
28735
  title: `${this.provider.name} \xB7 ${dirName}`,
28596
28736
  status: this.currentStatus,
28597
- messages: recentMessages,
28737
+ messages: normalizeChatMessages(recentMessages),
28598
28738
  activeModal: this.currentStatus === "waiting_approval" ? {
28599
28739
  message: this.activeToolCalls.find((t) => t.status === "running")?.name || "Permission requested",
28600
28740
  buttons: ["Approve", "Reject"]
@@ -29126,11 +29266,10 @@ var init_acp_provider_instance = __esm({
29126
29266
  if (b.type === "resource") return { type: "resource", resource: b.resource };
29127
29267
  return { type: "text", text: flattenContent([b]) };
29128
29268
  }) : [{ type: "text", text }];
29129
- this.messages.push({
29130
- role: "user",
29269
+ this.messages.push(buildUserChatMessage({
29131
29270
  content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
29132
29271
  timestamp: Date.now()
29133
- });
29272
+ }));
29134
29273
  this.currentStatus = "generating";
29135
29274
  this.partialContent = "";
29136
29275
  this.partialBlocks = [];
@@ -29300,11 +29439,11 @@ var init_acp_provider_instance = __esm({
29300
29439
  content = m.content.filter((p) => p.type === "text").map((p) => p.text || "").join("\n");
29301
29440
  }
29302
29441
  if (content.trim()) {
29303
- this.messages.push({
29442
+ this.messages.push(buildChatMessage({
29304
29443
  role: m.role || "assistant",
29305
29444
  content: content.trim(),
29306
29445
  timestamp: Date.now()
29307
- });
29446
+ }));
29308
29447
  this.partialContent = "";
29309
29448
  }
29310
29449
  }
@@ -29380,12 +29519,11 @@ var init_acp_provider_instance = __esm({
29380
29519
  return b;
29381
29520
  }).filter((b) => b.type !== "text" || b.type === "text" && b.text.trim());
29382
29521
  if (finalBlocks.length > 0) {
29383
- this.messages.push({
29384
- role: "assistant",
29522
+ this.messages.push(buildAssistantChatMessage({
29385
29523
  content: finalBlocks.length === 1 && finalBlocks[0].type === "text" ? finalBlocks[0].text : finalBlocks,
29386
29524
  timestamp: Date.now(),
29387
29525
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
29388
- });
29526
+ }));
29389
29527
  }
29390
29528
  this.partialContent = "";
29391
29529
  this.partialBlocks = [];
@@ -29445,11 +29583,10 @@ var init_acp_provider_instance = __esm({
29445
29583
  appendSystemMessage(content, timestamp = Date.now()) {
29446
29584
  const normalizedContent = String(content || "").trim();
29447
29585
  if (!normalizedContent) return;
29448
- this.messages.push({
29449
- role: "system",
29586
+ this.messages.push(buildRuntimeSystemChatMessage({
29450
29587
  content: normalizedContent,
29451
29588
  timestamp
29452
- });
29589
+ }));
29453
29590
  if (this.messages.length > 200) {
29454
29591
  this.messages = this.messages.slice(-100);
29455
29592
  }
@@ -36002,6 +36139,7 @@ var init_poller = __esm({
36002
36139
  init_reconcile();
36003
36140
  init_logger();
36004
36141
  init_approval_utils();
36142
+ init_chat_message_normalization();
36005
36143
  AgentStreamPoller = class {
36006
36144
  deps;
36007
36145
  timer = null;
@@ -36157,12 +36295,9 @@ var init_poller = __esm({
36157
36295
  type: "message",
36158
36296
  id: effectId,
36159
36297
  persist: true,
36160
- message: {
36161
- role: "system",
36162
- senderName: "System",
36163
- kind: "system",
36298
+ message: buildRuntimeSystemChatMessage({
36164
36299
  content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
36165
- }
36300
+ })
36166
36301
  }
36167
36302
  ]
36168
36303
  };
@@ -42801,6 +42936,7 @@ var src_exports = {};
42801
42936
  __export(src_exports, {
42802
42937
  AcpProviderInstance: () => AcpProviderInstance,
42803
42938
  AgentStreamPoller: () => AgentStreamPoller,
42939
+ BUILTIN_CHAT_MESSAGE_KINDS: () => BUILTIN_CHAT_MESSAGE_KINDS,
42804
42940
  CdpDomHandlers: () => CdpDomHandlers,
42805
42941
  CliProviderInstance: () => CliProviderInstance,
42806
42942
  DAEMON_WS_PATH: () => DAEMON_WS_PATH,
@@ -42825,9 +42961,14 @@ __export(src_exports, {
42825
42961
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
42826
42962
  VersionArchive: () => VersionArchive,
42827
42963
  appendRecentActivity: () => appendRecentActivity,
42964
+ buildAssistantChatMessage: () => buildAssistantChatMessage,
42965
+ buildChatMessage: () => buildChatMessage,
42828
42966
  buildMachineInfo: () => buildMachineInfo,
42967
+ buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
42829
42968
  buildSessionEntries: () => buildSessionEntries,
42830
42969
  buildStatusSnapshot: () => buildStatusSnapshot,
42970
+ buildSystemChatMessage: () => buildSystemChatMessage,
42971
+ buildUserChatMessage: () => buildUserChatMessage,
42831
42972
  clearDebugTrace: () => clearDebugTrace,
42832
42973
  configureDebugTraceStore: () => configureDebugTraceStore,
42833
42974
  connectCdpManager: () => connectCdpManager,
@@ -42859,6 +43000,7 @@ __export(src_exports, {
42859
43000
  initDaemonComponents: () => initDaemonComponents,
42860
43001
  installExtensions: () => installExtensions,
42861
43002
  installGlobalInterceptor: () => installGlobalInterceptor,
43003
+ isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
42862
43004
  isCdpConnected: () => isCdpConnected,
42863
43005
  isExtensionInstalled: () => isExtensionInstalled,
42864
43006
  isIdeRunning: () => isIdeRunning,
@@ -42877,6 +43019,9 @@ __export(src_exports, {
42877
43019
  markSetupComplete: () => markSetupComplete,
42878
43020
  maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv,
42879
43021
  normalizeActiveChatData: () => normalizeActiveChatData,
43022
+ normalizeChatMessage: () => normalizeChatMessage,
43023
+ normalizeChatMessageKind: () => normalizeChatMessageKind,
43024
+ normalizeChatMessages: () => normalizeChatMessages,
42880
43025
  normalizeInputEnvelope: () => normalizeInputEnvelope,
42881
43026
  normalizeManagedStatus: () => normalizeManagedStatus,
42882
43027
  normalizeMessageParts: () => normalizeMessageParts,
@@ -42946,6 +43091,7 @@ var init_src = __esm({
42946
43091
  init_acp_provider_instance();
42947
43092
  init_provider_source_config();
42948
43093
  init_io_contracts();
43094
+ init_chat_message_normalization();
42949
43095
  init_version_archive();
42950
43096
  init_dev_server();
42951
43097
  init_provider_cli_adapter();
@@ -52253,7 +52399,7 @@ var init_adhdev_daemon = __esm({
52253
52399
  import_ws3 = require("ws");
52254
52400
  init_source2();
52255
52401
  init_version();
52256
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.60" });
52402
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.61" });
52257
52403
  ACTIVE_CHAT_POLL_STATUSES = /* @__PURE__ */ new Set([
52258
52404
  "generating",
52259
52405
  "waiting_approval",