adhdev 0.8.60 → 0.8.63

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
  }
@@ -9433,6 +9567,7 @@ function buildCliParseInput(options) {
9433
9567
  terminalScreenText,
9434
9568
  baseMessages,
9435
9569
  partialResponse,
9570
+ isWaitingForResponse,
9436
9571
  scope,
9437
9572
  runtimeSettings
9438
9573
  } = options;
@@ -9450,6 +9585,7 @@ function buildCliParseInput(options) {
9450
9585
  recentScreen: buildCliScreenSnapshot(recentBuffer),
9451
9586
  messages: [...baseMessages],
9452
9587
  partialResponse,
9588
+ isWaitingForResponse,
9453
9589
  promptText: scope?.prompt || "",
9454
9590
  settings: { ...runtimeSettings }
9455
9591
  };
@@ -9635,6 +9771,7 @@ var init_provider_cli_adapter = __esm({
9635
9771
  init_terminal_screen();
9636
9772
  init_pty_transport();
9637
9773
  init_provider_cli_shared();
9774
+ init_chat_message_normalization();
9638
9775
  init_provider_cli_parse();
9639
9776
  init_provider_cli_config();
9640
9777
  init_provider_cli_runtime();
@@ -10187,6 +10324,18 @@ var init_provider_cli_adapter = __esm({
10187
10324
  const holdMs = this.getStatusActivityHoldMs();
10188
10325
  return quietForMs < holdMs || screenStableMs < holdMs;
10189
10326
  }
10327
+ shouldDeferIdleTimeoutFinish() {
10328
+ if (!this.isWaitingForResponse || this.currentStatus === "waiting_approval") {
10329
+ return false;
10330
+ }
10331
+ const latestStatus = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
10332
+ if (latestStatus === "generating") {
10333
+ this.settledBuffer = this.recentOutputBuffer;
10334
+ this.evaluateSettled();
10335
+ return true;
10336
+ }
10337
+ return false;
10338
+ }
10190
10339
  getStartupConfirmationModal(screenText) {
10191
10340
  const text = sanitizeTerminalText(String(screenText || ""));
10192
10341
  if (!text.trim()) return null;
@@ -10345,6 +10494,7 @@ var init_provider_cli_adapter = __esm({
10345
10494
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
10346
10495
  this.idleTimeout = setTimeout(() => {
10347
10496
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
10497
+ if (this.shouldDeferIdleTimeoutFinish()) return;
10348
10498
  this.finishResponse();
10349
10499
  }
10350
10500
  }, this.timeouts.generatingIdle);
@@ -10380,6 +10530,7 @@ var init_provider_cli_adapter = __esm({
10380
10530
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
10381
10531
  this.idleTimeout = setTimeout(() => {
10382
10532
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
10533
+ if (this.shouldDeferIdleTimeoutFinish()) return;
10383
10534
  this.finishResponse();
10384
10535
  }
10385
10536
  }, this.timeouts.generatingIdle);
@@ -10422,7 +10573,10 @@ var init_provider_cli_adapter = __esm({
10422
10573
  this.setStatus("generating", "script_detect");
10423
10574
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
10424
10575
  this.idleTimeout = setTimeout(() => {
10425
- if (this.isWaitingForResponse) this.finishResponse();
10576
+ if (this.isWaitingForResponse) {
10577
+ if (this.shouldDeferIdleTimeoutFinish()) return;
10578
+ this.finishResponse();
10579
+ }
10426
10580
  }, this.timeouts.generatingIdle);
10427
10581
  this.onStatusChange?.();
10428
10582
  return;
@@ -10490,6 +10644,7 @@ var init_provider_cli_adapter = __esm({
10490
10644
  if (this.idleTimeout) clearTimeout(this.idleTimeout);
10491
10645
  this.idleTimeout = setTimeout(() => {
10492
10646
  if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
10647
+ if (this.shouldDeferIdleTimeoutFinish()) return;
10493
10648
  this.clearIdleFinishCandidate("idle_timeout_finish");
10494
10649
  this.finishResponse();
10495
10650
  }
@@ -10628,6 +10783,7 @@ var init_provider_cli_adapter = __esm({
10628
10783
  tail: text.slice(-500),
10629
10784
  screenText,
10630
10785
  rawBuffer: this.accumulatedRawBuffer,
10786
+ isWaitingForResponse: this.isWaitingForResponse,
10631
10787
  screen: buildCliScreenSnapshot(screenText),
10632
10788
  tailScreen: buildCliScreenSnapshot(text.slice(-500))
10633
10789
  });
@@ -10692,11 +10848,10 @@ var init_provider_cli_adapter = __esm({
10692
10848
  );
10693
10849
  const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
10694
10850
  if (parsed && Array.isArray(parsed.messages)) {
10695
- const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => ({
10851
+ const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
10696
10852
  ...message,
10697
10853
  id: message.id || `msg_${index}`,
10698
10854
  index: typeof message.index === "number" ? message.index : index,
10699
- kind: message.kind || "standard",
10700
10855
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
10701
10856
  })) : hydrateCliParsedMessages(parsed.messages, {
10702
10857
  committedMessages: this.committedMessages,
@@ -10717,13 +10872,11 @@ var init_provider_cli_adapter = __esm({
10717
10872
  id: "cli_session",
10718
10873
  status: this.currentStatus,
10719
10874
  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"
10875
+ messages: messages.slice(-50).map((message, index) => buildChatMessage({
10876
+ ...message,
10877
+ id: message.id || `msg_${index}`,
10878
+ index: typeof message.index === "number" ? message.index : index,
10879
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
10727
10880
  })),
10728
10881
  activeModal: this.activeModal
10729
10882
  };
@@ -10740,6 +10893,7 @@ var init_provider_cli_adapter = __esm({
10740
10893
  terminalScreenText: this.terminalScreen.getText(),
10741
10894
  baseMessages: this.committedMessages,
10742
10895
  partialResponse: this.responseBuffer,
10896
+ isWaitingForResponse: this.isWaitingForResponse,
10743
10897
  scope: this.currentTurnScope,
10744
10898
  runtimeSettings: this.runtimeSettings
10745
10899
  });
@@ -10758,6 +10912,7 @@ var init_provider_cli_adapter = __esm({
10758
10912
  terminalScreenText: this.terminalScreen.getText(),
10759
10913
  baseMessages,
10760
10914
  partialResponse,
10915
+ isWaitingForResponse: this.isWaitingForResponse,
10761
10916
  scope,
10762
10917
  runtimeSettings: this.runtimeSettings
10763
10918
  });
@@ -11406,6 +11561,7 @@ var init_cli_provider_instance = __esm({
11406
11561
  init_approval_utils();
11407
11562
  init_cli_script_results();
11408
11563
  init_provider_patch_state();
11564
+ init_chat_message_normalization();
11409
11565
  CachedDatabaseSync = null;
11410
11566
  CliProviderInstance = class {
11411
11567
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
@@ -11856,8 +12012,8 @@ var init_cli_provider_instance = __esm({
11856
12012
  if (this.appliedEffectKeys.has(effectKey)) continue;
11857
12013
  this.appliedEffectKeys.add(effectKey);
11858
12014
  if (effect.persist !== false) {
11859
- const persisted = this.getPersistedEffectContent(effect);
11860
- if (persisted) this.appendRuntimeSystemMessage(persisted, effectKey);
12015
+ const persistedMessage = buildPersistedProviderEffectMessage(effect);
12016
+ if (persistedMessage) this.appendRuntimeMessage(persistedMessage, effectKey);
11861
12017
  }
11862
12018
  if (effect.type === "message" && effect.message) {
11863
12019
  const content = typeof effect.message.content === "string" ? effect.message.content : JSON.stringify(effect.message.content);
@@ -11981,44 +12137,53 @@ ${effect.notification.body || ""}`.trim();
11981
12137
  );
11982
12138
  }
11983
12139
  appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
11984
- const normalizedContent = String(content || "").trim();
11985
- if (!normalizedContent) return;
12140
+ this.appendRuntimeMessage(buildRuntimeSystemChatMessage({
12141
+ content,
12142
+ receivedAt,
12143
+ timestamp: receivedAt
12144
+ }), dedupKey);
12145
+ }
12146
+ appendRuntimeMessage(message, dedupKey) {
12147
+ const normalizedMessage = buildChatMessage({
12148
+ ...message,
12149
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp || Date.now(),
12150
+ timestamp: typeof message.timestamp === "number" ? message.timestamp : message.receivedAt || Date.now()
12151
+ });
12152
+ const normalizedContent = typeof normalizedMessage.content === "string" ? normalizedMessage.content.trim() : flattenContent(normalizedMessage.content).trim();
12153
+ if (!normalizedContent && (!Array.isArray(normalizedMessage.content) || normalizedMessage.content.length === 0)) return;
11986
12154
  if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
11987
12155
  this.runtimeMessages.push({
11988
12156
  key: dedupKey,
11989
- message: {
11990
- role: "system",
11991
- senderName: "System",
11992
- content: normalizedContent,
11993
- receivedAt,
11994
- timestamp: receivedAt
11995
- }
12157
+ message: normalizedMessage
11996
12158
  });
11997
12159
  if (this.runtimeMessages.length > 50) {
11998
12160
  this.runtimeMessages = this.runtimeMessages.slice(-50);
11999
12161
  }
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
- );
12162
+ if (normalizedContent) {
12163
+ this.historyWriter.appendNewMessages(
12164
+ this.type,
12165
+ [{
12166
+ role: normalizedMessage.role,
12167
+ senderName: normalizedMessage.senderName,
12168
+ kind: normalizedMessage.kind,
12169
+ content: normalizedContent,
12170
+ receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
12171
+ historyDedupKey: dedupKey
12172
+ }],
12173
+ this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
12174
+ this.instanceId,
12175
+ this.providerSessionId
12176
+ );
12177
+ }
12013
12178
  }
12014
12179
  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) => {
12180
+ if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
12181
+ return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
12017
12182
  const aTime = a.message.receivedAt || a.message.timestamp || 0;
12018
12183
  const bTime = b.message.receivedAt || b.message.timestamp || 0;
12019
12184
  if (aTime !== bTime) return aTime - bTime;
12020
12185
  return a.index - b.index;
12021
- }).map((entry) => entry.message);
12186
+ }).map((entry) => entry.message));
12022
12187
  }
12023
12188
  formatApprovalRequestMessage(modalMessage, buttons) {
12024
12189
  const lines = ["Approval requested"];
@@ -28494,6 +28659,7 @@ var init_acp_provider_instance = __esm({
28494
28659
  init_contracts();
28495
28660
  init_status_monitor();
28496
28661
  init_summary_metadata();
28662
+ init_chat_message_normalization();
28497
28663
  init_logger();
28498
28664
  AcpProviderInstance = class {
28499
28665
  constructor(provider, workingDir, cliArgs = []) {
@@ -28564,24 +28730,21 @@ var init_acp_provider_instance = __esm({
28564
28730
  }
28565
28731
  getState() {
28566
28732
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
28567
- const recentMessages = this.messages.slice(-50).map((m) => {
28733
+ const recentMessages = normalizeChatMessages(this.messages.slice(-50).map((m) => {
28568
28734
  const content = this.truncateContent(m.content);
28569
- return {
28570
- role: m.role,
28571
- content,
28572
- timestamp: m.timestamp,
28573
- toolCalls: m.toolCalls
28574
- };
28575
- });
28735
+ return buildChatMessage({
28736
+ ...m,
28737
+ content
28738
+ });
28739
+ }));
28576
28740
  if (this.currentStatus === "generating" && (this.partialContent || this.partialBlocks.length > 0)) {
28577
28741
  const blocks = this.buildPartialBlocks();
28578
28742
  if (blocks.length > 0) {
28579
- recentMessages.push({
28580
- role: "assistant",
28743
+ recentMessages.push(buildAssistantChatMessage({
28581
28744
  content: blocks,
28582
28745
  timestamp: Date.now(),
28583
28746
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
28584
- });
28747
+ }));
28585
28748
  }
28586
28749
  }
28587
28750
  return {
@@ -28594,7 +28757,7 @@ var init_acp_provider_instance = __esm({
28594
28757
  id: this.sessionId || `${this.type}_${this.workingDir}`,
28595
28758
  title: `${this.provider.name} \xB7 ${dirName}`,
28596
28759
  status: this.currentStatus,
28597
- messages: recentMessages,
28760
+ messages: normalizeChatMessages(recentMessages),
28598
28761
  activeModal: this.currentStatus === "waiting_approval" ? {
28599
28762
  message: this.activeToolCalls.find((t) => t.status === "running")?.name || "Permission requested",
28600
28763
  buttons: ["Approve", "Reject"]
@@ -29126,11 +29289,10 @@ var init_acp_provider_instance = __esm({
29126
29289
  if (b.type === "resource") return { type: "resource", resource: b.resource };
29127
29290
  return { type: "text", text: flattenContent([b]) };
29128
29291
  }) : [{ type: "text", text }];
29129
- this.messages.push({
29130
- role: "user",
29292
+ this.messages.push(buildUserChatMessage({
29131
29293
  content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
29132
29294
  timestamp: Date.now()
29133
- });
29295
+ }));
29134
29296
  this.currentStatus = "generating";
29135
29297
  this.partialContent = "";
29136
29298
  this.partialBlocks = [];
@@ -29300,11 +29462,11 @@ var init_acp_provider_instance = __esm({
29300
29462
  content = m.content.filter((p) => p.type === "text").map((p) => p.text || "").join("\n");
29301
29463
  }
29302
29464
  if (content.trim()) {
29303
- this.messages.push({
29465
+ this.messages.push(buildChatMessage({
29304
29466
  role: m.role || "assistant",
29305
29467
  content: content.trim(),
29306
29468
  timestamp: Date.now()
29307
- });
29469
+ }));
29308
29470
  this.partialContent = "";
29309
29471
  }
29310
29472
  }
@@ -29380,12 +29542,11 @@ var init_acp_provider_instance = __esm({
29380
29542
  return b;
29381
29543
  }).filter((b) => b.type !== "text" || b.type === "text" && b.text.trim());
29382
29544
  if (finalBlocks.length > 0) {
29383
- this.messages.push({
29384
- role: "assistant",
29545
+ this.messages.push(buildAssistantChatMessage({
29385
29546
  content: finalBlocks.length === 1 && finalBlocks[0].type === "text" ? finalBlocks[0].text : finalBlocks,
29386
29547
  timestamp: Date.now(),
29387
29548
  toolCalls: this.turnToolCalls.length > 0 ? [...this.turnToolCalls] : void 0
29388
- });
29549
+ }));
29389
29550
  }
29390
29551
  this.partialContent = "";
29391
29552
  this.partialBlocks = [];
@@ -29445,11 +29606,10 @@ var init_acp_provider_instance = __esm({
29445
29606
  appendSystemMessage(content, timestamp = Date.now()) {
29446
29607
  const normalizedContent = String(content || "").trim();
29447
29608
  if (!normalizedContent) return;
29448
- this.messages.push({
29449
- role: "system",
29609
+ this.messages.push(buildRuntimeSystemChatMessage({
29450
29610
  content: normalizedContent,
29451
29611
  timestamp
29452
- });
29612
+ }));
29453
29613
  if (this.messages.length > 200) {
29454
29614
  this.messages = this.messages.slice(-100);
29455
29615
  }
@@ -36002,6 +36162,7 @@ var init_poller = __esm({
36002
36162
  init_reconcile();
36003
36163
  init_logger();
36004
36164
  init_approval_utils();
36165
+ init_chat_message_normalization();
36005
36166
  AgentStreamPoller = class {
36006
36167
  deps;
36007
36168
  timer = null;
@@ -36157,12 +36318,9 @@ var init_poller = __esm({
36157
36318
  type: "message",
36158
36319
  id: effectId,
36159
36320
  persist: true,
36160
- message: {
36161
- role: "system",
36162
- senderName: "System",
36163
- kind: "system",
36321
+ message: buildRuntimeSystemChatMessage({
36164
36322
  content: formatAutoApprovalMessage(stream.activeModal?.message, buttonLabel)
36165
- }
36323
+ })
36166
36324
  }
36167
36325
  ]
36168
36326
  };
@@ -42801,6 +42959,7 @@ var src_exports = {};
42801
42959
  __export(src_exports, {
42802
42960
  AcpProviderInstance: () => AcpProviderInstance,
42803
42961
  AgentStreamPoller: () => AgentStreamPoller,
42962
+ BUILTIN_CHAT_MESSAGE_KINDS: () => BUILTIN_CHAT_MESSAGE_KINDS,
42804
42963
  CdpDomHandlers: () => CdpDomHandlers,
42805
42964
  CliProviderInstance: () => CliProviderInstance,
42806
42965
  DAEMON_WS_PATH: () => DAEMON_WS_PATH,
@@ -42825,9 +42984,14 @@ __export(src_exports, {
42825
42984
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
42826
42985
  VersionArchive: () => VersionArchive,
42827
42986
  appendRecentActivity: () => appendRecentActivity,
42987
+ buildAssistantChatMessage: () => buildAssistantChatMessage,
42988
+ buildChatMessage: () => buildChatMessage,
42828
42989
  buildMachineInfo: () => buildMachineInfo,
42990
+ buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
42829
42991
  buildSessionEntries: () => buildSessionEntries,
42830
42992
  buildStatusSnapshot: () => buildStatusSnapshot,
42993
+ buildSystemChatMessage: () => buildSystemChatMessage,
42994
+ buildUserChatMessage: () => buildUserChatMessage,
42831
42995
  clearDebugTrace: () => clearDebugTrace,
42832
42996
  configureDebugTraceStore: () => configureDebugTraceStore,
42833
42997
  connectCdpManager: () => connectCdpManager,
@@ -42859,6 +43023,7 @@ __export(src_exports, {
42859
43023
  initDaemonComponents: () => initDaemonComponents,
42860
43024
  installExtensions: () => installExtensions,
42861
43025
  installGlobalInterceptor: () => installGlobalInterceptor,
43026
+ isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
42862
43027
  isCdpConnected: () => isCdpConnected,
42863
43028
  isExtensionInstalled: () => isExtensionInstalled,
42864
43029
  isIdeRunning: () => isIdeRunning,
@@ -42877,6 +43042,9 @@ __export(src_exports, {
42877
43042
  markSetupComplete: () => markSetupComplete,
42878
43043
  maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv,
42879
43044
  normalizeActiveChatData: () => normalizeActiveChatData,
43045
+ normalizeChatMessage: () => normalizeChatMessage,
43046
+ normalizeChatMessageKind: () => normalizeChatMessageKind,
43047
+ normalizeChatMessages: () => normalizeChatMessages,
42880
43048
  normalizeInputEnvelope: () => normalizeInputEnvelope,
42881
43049
  normalizeManagedStatus: () => normalizeManagedStatus,
42882
43050
  normalizeMessageParts: () => normalizeMessageParts,
@@ -42946,6 +43114,7 @@ var init_src = __esm({
42946
43114
  init_acp_provider_instance();
42947
43115
  init_provider_source_config();
42948
43116
  init_io_contracts();
43117
+ init_chat_message_normalization();
42949
43118
  init_version_archive();
42950
43119
  init_dev_server();
42951
43120
  init_provider_cli_adapter();
@@ -52253,7 +52422,7 @@ var init_adhdev_daemon = __esm({
52253
52422
  import_ws3 = require("ws");
52254
52423
  init_source2();
52255
52424
  init_version();
52256
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.60" });
52425
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.63" });
52257
52426
  ACTIVE_CHAT_POLL_STATUSES = /* @__PURE__ */ new Set([
52258
52427
  "generating",
52259
52428
  "waiting_approval",