@jrkropp/codex-js 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/ClientNotification-B6-FhXQf.d.ts +5 -0
  3. package/dist/DynamicToolCallResponse-82DFjES2.d.ts +8 -0
  4. package/dist/DynamicToolSpec-CfnhqAYK.d.ts +29 -0
  5. package/dist/PermissionsRequestApprovalResponse-DxzPPDRb.d.ts +55 -0
  6. package/dist/ProviderStatusBanner-BlP6lzwE.d.ts +441 -0
  7. package/dist/ServerRequest-B5cKVJjr.d.ts +2181 -0
  8. package/dist/{session-DPhHN7RZ.d.ts → ThreadResumeResponse-DvmE1juU.d.ts} +3 -306
  9. package/dist/ToolRequestUserInputQuestion-CeZa5X1J.d.ts +23 -0
  10. package/dist/ToolRequestUserInputResponse-zcPLwbiK.d.ts +17 -0
  11. package/dist/TurnSteerResponse-0kBCfplh.d.ts +209 -0
  12. package/dist/WebSearchToolConfig-D3ep0625.d.ts +18 -0
  13. package/dist/chat-runtime-B6azJyKo.d.ts +381 -0
  14. package/dist/chunk-2DZRMCI2.js +1258 -0
  15. package/dist/chunk-2DZRMCI2.js.map +1 -0
  16. package/dist/chunk-4DPLJPB5.js +396 -0
  17. package/dist/chunk-4DPLJPB5.js.map +1 -0
  18. package/dist/chunk-5JMJ6OI5.js +3 -0
  19. package/dist/chunk-5JMJ6OI5.js.map +1 -0
  20. package/dist/chunk-6ZMJ34KE.js +1153 -0
  21. package/dist/chunk-6ZMJ34KE.js.map +1 -0
  22. package/dist/chunk-CGBS37IU.js +128 -0
  23. package/dist/chunk-CGBS37IU.js.map +1 -0
  24. package/dist/chunk-DCMKA2A6.js +18 -0
  25. package/dist/chunk-DCMKA2A6.js.map +1 -0
  26. package/dist/chunk-DYLHN3HG.js +937 -0
  27. package/dist/chunk-DYLHN3HG.js.map +1 -0
  28. package/dist/chunk-ILXA6HLX.js +1973 -0
  29. package/dist/chunk-ILXA6HLX.js.map +1 -0
  30. package/dist/{chunk-SVK6PLGO.js → chunk-LWQNX4LI.js} +12009 -18768
  31. package/dist/chunk-LWQNX4LI.js.map +1 -0
  32. package/dist/{chunk-JLDH4U5L.js → chunk-NCI4MAWZ.js} +317 -1967
  33. package/dist/chunk-NCI4MAWZ.js.map +1 -0
  34. package/dist/chunk-O44XP7LH.js +214 -0
  35. package/dist/chunk-O44XP7LH.js.map +1 -0
  36. package/dist/chunk-PST3ZWX2.js +555 -0
  37. package/dist/chunk-PST3ZWX2.js.map +1 -0
  38. package/dist/chunk-SYPHCDRD.js +1133 -0
  39. package/dist/chunk-SYPHCDRD.js.map +1 -0
  40. package/dist/chunk-V4BMZWBM.js +2401 -0
  41. package/dist/chunk-V4BMZWBM.js.map +1 -0
  42. package/dist/chunk-YHVCFD2D.js +117 -0
  43. package/dist/chunk-YHVCFD2D.js.map +1 -0
  44. package/dist/chunk-Z63UPBS3.js +152 -0
  45. package/dist/chunk-Z63UPBS3.js.map +1 -0
  46. package/dist/client/index.d.ts +16 -4
  47. package/dist/client/index.js +13 -1
  48. package/dist/codex-rs/app-server/index.d.ts +161 -0
  49. package/dist/codex-rs/app-server/index.js +13 -0
  50. package/dist/codex-rs/app-server/index.js.map +1 -0
  51. package/dist/codex-rs/app-server-protocol/index.d.ts +1722 -0
  52. package/dist/codex-rs/app-server-protocol/index.js +6 -0
  53. package/dist/codex-rs/app-server-protocol/index.js.map +1 -0
  54. package/dist/codex-rs/app-server-protocol/protocol.d.ts +19 -0
  55. package/dist/codex-rs/app-server-protocol/protocol.js +4 -0
  56. package/dist/codex-rs/app-server-protocol/protocol.js.map +1 -0
  57. package/dist/codex-rs/codex-api/index.d.ts +104 -0
  58. package/dist/codex-rs/codex-api/index.js +11 -0
  59. package/dist/codex-rs/codex-api/index.js.map +1 -0
  60. package/dist/codex-rs/config/index.d.ts +88 -0
  61. package/dist/codex-rs/config/index.js +4 -0
  62. package/dist/codex-rs/config/index.js.map +1 -0
  63. package/dist/codex-rs/core/config/index.d.ts +61 -0
  64. package/dist/codex-rs/core/config/index.js +5 -0
  65. package/dist/codex-rs/core/config/index.js.map +1 -0
  66. package/dist/codex-rs/core/index.d.ts +1393 -0
  67. package/dist/codex-rs/core/index.js +11 -0
  68. package/dist/codex-rs/core/index.js.map +1 -0
  69. package/dist/codex-rs/model-provider/index.d.ts +2 -0
  70. package/dist/codex-rs/model-provider/index.js +4 -0
  71. package/dist/codex-rs/model-provider/index.js.map +1 -0
  72. package/dist/codex-rs/models-manager/index.d.ts +2 -0
  73. package/dist/codex-rs/models-manager/index.js +4 -0
  74. package/dist/codex-rs/models-manager/index.js.map +1 -0
  75. package/dist/codex-rs/parity.d.ts +26 -0
  76. package/dist/codex-rs/parity.js +3 -0
  77. package/dist/codex-rs/parity.js.map +1 -0
  78. package/dist/codex-rs/thread-store/index.d.ts +5 -0
  79. package/dist/codex-rs/thread-store/index.js +4 -0
  80. package/dist/codex-rs/thread-store/index.js.map +1 -0
  81. package/dist/codex-rs/unsupported.d.ts +15 -0
  82. package/dist/codex-rs/unsupported.js +22 -0
  83. package/dist/codex-rs/unsupported.js.map +1 -0
  84. package/dist/codex-rs/utils/output-truncation.d.ts +21 -0
  85. package/dist/codex-rs/utils/output-truncation.js +4 -0
  86. package/dist/codex-rs/utils/output-truncation.js.map +1 -0
  87. package/dist/codex-rs/utils/string.d.ts +7 -0
  88. package/dist/codex-rs/utils/string.js +3 -0
  89. package/dist/codex-rs/utils/string.js.map +1 -0
  90. package/dist/common-CTyph5x8.d.ts +40 -0
  91. package/dist/event-mapping-CbISdQ1D.d.ts +43 -0
  92. package/dist/history-CfM-4V7b.d.ts +1654 -0
  93. package/dist/index-77U_Oc-a.d.ts +63 -0
  94. package/dist/index-CoDZosq0.d.ts +261 -0
  95. package/dist/index.d.ts +18 -7
  96. package/dist/index.js +16 -2
  97. package/dist/lib-nXlaKiS-.d.ts +48 -0
  98. package/dist/live-thread-BMvlflzM.d.ts +30 -0
  99. package/dist/merge-B_AWVmnI.d.ts +24 -0
  100. package/dist/mod-DYVLSWO4.d.ts +91 -0
  101. package/dist/plan-mode-Cv6KWb_S.d.ts +14 -0
  102. package/dist/proposed-plan-DpN1ma0Y.d.ts +53 -0
  103. package/dist/protocol-mpBcYHrm.d.ts +1655 -0
  104. package/dist/react/index.d.ts +20 -52
  105. package/dist/react/index.js +16 -2
  106. package/dist/{remote-_6TDvg-g.d.ts → remote-ClZbq9KN.d.ts} +3 -1
  107. package/dist/rendered-thread-AOxw3V5b.d.ts +29 -0
  108. package/dist/responses_websocket-BhxSgCzK.d.ts +183 -0
  109. package/dist/runtime-Cm6ml53h.d.ts +528 -0
  110. package/dist/server/index.d.ts +29 -2416
  111. package/dist/server/index.js +13 -1
  112. package/dist/session-BRYzi8OT.d.ts +46 -0
  113. package/dist/shadcn/index.d.ts +1 -1
  114. package/dist/{sidebar-DT2XoitN.d.ts → sidebar-DMMij22z.d.ts} +1 -1
  115. package/dist/spec_plan_types-CmsJ-Tfn.d.ts +260 -0
  116. package/dist/{store-GYldc9EJ.d.ts → store-AGRxhgQ3.d.ts} +2 -1
  117. package/dist/t3code/apps/web/components/chat.d.ts +508 -0
  118. package/dist/t3code/apps/web/components/chat.js +12 -0
  119. package/dist/t3code/apps/web/components/chat.js.map +1 -0
  120. package/dist/t3code/apps/web/index.d.ts +12 -0
  121. package/dist/t3code/apps/web/index.js +13 -0
  122. package/dist/t3code/apps/web/index.js.map +1 -0
  123. package/dist/testing/index.d.ts +9 -91
  124. package/dist/testing/index.js +13 -1
  125. package/dist/thread-history-builder-zW0zeqcS.d.ts +58 -0
  126. package/dist/thread_event_store-C0zYzukG.d.ts +77 -0
  127. package/dist/types-BTeabLYr.d.ts +126 -0
  128. package/package.json +65 -1
  129. package/dist/chat-runtime-D7wu_KbX.d.ts +0 -747
  130. package/dist/chunk-JLDH4U5L.js.map +0 -1
  131. package/dist/chunk-SVK6PLGO.js.map +0 -1
  132. package/dist/index-CB9la6xE.d.ts +0 -112
  133. package/dist/thread_event_store-B9CoQUIA.d.ts +0 -3868
@@ -1,7 +1,6 @@
1
- import { Sidebar, SidebarProvider, SidebarInset } from './chunk-FN3SWHRH.js';
2
- import { defaultModelsManager, resolveReasoningEffortForModel, ThreadEventStore, AppServerSession, threadEventSnapshotHasStarted, asThreadId, thread_token_usage_updated_notification_from_rollout_items } from './chunk-SVK6PLGO.js';
3
- import { memo, useState, useMemo, useCallback, useRef, useEffect, useLayoutEffect, forwardRef, useImperativeHandle, Suspense, createContext, Children, isValidElement, useContext, createElement, Fragment as Fragment$1 } from 'react';
4
- import { ChevronRightIcon, FolderIcon, FolderClosedIcon, FileIcon, CheckIcon, UserRoundIcon, BoxIcon, BotIcon, SparklesIcon, ArchiveIcon, MessageSquarePlusIcon, ChevronDownIcon, EllipsisIcon, LockOpenIcon, PenLineIcon, LockIcon, ListTodoIcon, StarIcon, Clock3Icon, SearchIcon, ChevronLeftIcon, XIcon, GlobeIcon, ImageIcon, LightbulbIcon, SettingsIcon, FileDiffIcon, TerminalIcon, PaperclipIcon, CopyIcon, InfoIcon, TriangleAlertIcon, CheckCircleIcon, AlertCircleIcon } from 'lucide-react';
1
+ import { defaultModelsManager, resolveReasoningEffortForModel } from './chunk-PST3ZWX2.js';
2
+ import { ChevronRightIcon, FolderIcon, FolderClosedIcon, FileIcon, CheckIcon, UserRoundIcon, BoxIcon, BotIcon, SparklesIcon, ArchiveIcon, MessageSquarePlusIcon, ChevronDownIcon, EllipsisIcon, LockOpenIcon, PenLineIcon, LockIcon, ListTodoIcon, StarIcon, Clock3Icon, SearchIcon, ChevronLeftIcon, XIcon, GlobeIcon, ImageIcon, LightbulbIcon, SettingsIcon, FileDiffIcon, TerminalIcon, PaperclipIcon, CopyIcon, MicIcon, CircleAlertIcon, InfoIcon, TriangleAlertIcon, CheckCircleIcon, AlertCircleIcon } from 'lucide-react';
3
+ import { memo, useState, useMemo, useCallback, useRef, useEffect, useLayoutEffect, forwardRef, useImperativeHandle, Suspense, createContext, Children, isValidElement, useContext } from 'react';
5
4
  import { cva } from 'class-variance-authority';
6
5
  import { Slot, DropdownMenu as DropdownMenu$1, Tooltip as Tooltip$1, Popover as Popover$1, Separator as Separator$1 } from 'radix-ui';
7
6
  import { clsx } from 'clsx';
@@ -22,91 +21,6 @@ import { LegendList } from '@legendapp/list/react';
22
21
  import ReactMarkdown, { defaultUrlTransform } from 'react-markdown';
23
22
  import remarkGfm from 'remark-gfm';
24
23
 
25
- function createLocalDispatchSnapshot(threadState) {
26
- return {
27
- errorCount: threadState?.errors.length ?? 0,
28
- itemIds: threadTurnItemIds(threadState),
29
- runningTurnIds: [...threadState?.activeTurnIds ?? []],
30
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
31
- };
32
- }
33
- function hasServerAcknowledgedLocalDispatch(input) {
34
- const localDispatch = input.localDispatch;
35
- if (!localDispatch) {
36
- return false;
37
- }
38
- if (input.hasPendingRequest || Boolean(input.runtimeError)) {
39
- return true;
40
- }
41
- const runningTurnIds = input.threadState?.activeTurnIds ?? [];
42
- if (runningTurnIds.some(
43
- (turnId) => !localDispatch.runningTurnIds.includes(turnId)
44
- )) {
45
- return true;
46
- }
47
- if (threadTurnItemIds(input.threadState).some(
48
- (itemId) => !localDispatch.itemIds.includes(itemId)
49
- )) {
50
- return true;
51
- }
52
- return (input.threadState?.errors.length ?? 0) > localDispatch.errorCount;
53
- }
54
- function useLocalDispatchState(input) {
55
- const [localDispatch, setLocalDispatch] = useState(null);
56
- const beginLocalDispatch = useCallback(() => {
57
- setLocalDispatch(
58
- (current) => current ?? createLocalDispatchSnapshot(input.threadState)
59
- );
60
- }, [input.threadState]);
61
- const resetLocalDispatch = useCallback(() => {
62
- setLocalDispatch(null);
63
- }, []);
64
- const serverAcknowledgedLocalDispatch = useMemo(
65
- () => hasServerAcknowledgedLocalDispatch({
66
- hasPendingRequest: input.hasPendingRequest,
67
- localDispatch,
68
- runtimeError: input.runtimeError,
69
- threadState: input.threadState
70
- }),
71
- [
72
- input.hasPendingRequest,
73
- input.runtimeError,
74
- input.threadState,
75
- localDispatch
76
- ]
77
- );
78
- return {
79
- beginLocalDispatch,
80
- isSendBusy: localDispatch !== null && !serverAcknowledgedLocalDispatch,
81
- localDispatch,
82
- localDispatchStartedAt: localDispatch?.startedAt ?? null,
83
- resetLocalDispatch,
84
- serverAcknowledgedLocalDispatch
85
- };
86
- }
87
- function deriveActiveWorkStartedAt(input) {
88
- if (!input.isWorking) {
89
- return null;
90
- }
91
- return input.sendStartedAt ?? input.runtimeStartedAt;
92
- }
93
- function deriveAssistantStreaming(threadState) {
94
- if (!threadState || threadState.activeTurnIds.length === 0) {
95
- return false;
96
- }
97
- const activeTurnIds = new Set(threadState.activeTurnIds);
98
- return threadState.turns.some(
99
- (turn) => activeTurnIds.has(turn.id) && turn.items.some(
100
- (item) => item.type === "agentMessage" && item.text.length > 0
101
- )
102
- );
103
- }
104
- function deriveChatLifecycleWorkingState(input) {
105
- return Boolean(input.threadState?.activeTurnIds.length) || input.isSendBusy || input.connectionStatus === "connecting" || input.connectionStatus === "reconnecting";
106
- }
107
- function threadTurnItemIds(threadState) {
108
- return threadState?.turns.flatMap((turn) => turn.items.map((item) => item.id)) ?? [];
109
- }
110
24
  function cn(...inputs) {
111
25
  return twMerge(clsx(inputs));
112
26
  }
@@ -952,12 +866,16 @@ var PROJECT_MENTION_SIGIL = "@";
952
866
  var LEGACY_PROJECT_MENTION_SIGIL = "$";
953
867
  var SKILL_MENTION_SIGIL = "$";
954
868
  var TOOL_MENTION_SIGIL = PROJECT_MENTION_SIGIL;
869
+ var PLUGIN_TEXT_MENTION_SIGIL = PROJECT_MENTION_SIGIL;
955
870
  function isMentionNameChar(byte) {
956
871
  return byte >= 48 && byte <= 57 || byte >= 65 && byte <= 90 || byte >= 97 && byte <= 122 || byte === 95 || byte === 45;
957
872
  }
958
873
  function mentionToken(name) {
959
874
  return `${PROJECT_MENTION_SIGIL}${name}`;
960
875
  }
876
+ function legacyMentionToken(name) {
877
+ return `${LEGACY_PROJECT_MENTION_SIGIL}${name}`;
878
+ }
961
879
  function skillToken(name) {
962
880
  return `${SKILL_MENTION_SIGIL}${name}`;
963
881
  }
@@ -1247,6 +1165,9 @@ function replaceTextRange(text, rangeStart, rangeEnd, replacement) {
1247
1165
  text: nextText
1248
1166
  };
1249
1167
  }
1168
+ function parseStandaloneComposerSlashCommand(text) {
1169
+ return text.trim().match(/^\/([a-z][a-z0-9-]*)$/)?.[1] ?? null;
1170
+ }
1250
1171
 
1251
1172
  // src/upstream/t3code/apps/web/src/lib/searchRanking.ts
1252
1173
  function normalizeSearchQuery(input, options) {
@@ -1911,13 +1832,19 @@ var CompactComposerControlsMenu = memo(
1911
1832
  ] });
1912
1833
  }
1913
1834
  );
1835
+
1836
+ // src/upstream/t3code/apps/web/src/components/chat/composer-footer-layout.ts
1837
+ var COMPOSER_FOOTER_COMPACT_BREAKPOINT_PX = 620;
1914
1838
  var COMPOSER_FOOTER_WIDE_ACTIONS_COMPACT_BREAKPOINT_PX = 780;
1915
1839
  var COMPOSER_PRIMARY_ACTIONS_COMPACT_BREAKPOINT_PX = COMPOSER_FOOTER_WIDE_ACTIONS_COMPACT_BREAKPOINT_PX;
1916
1840
  function shouldUseCompactComposerFooter(width, options) {
1917
- const breakpoint = COMPOSER_FOOTER_WIDE_ACTIONS_COMPACT_BREAKPOINT_PX ;
1841
+ const breakpoint = options?.hasWideActions ? COMPOSER_FOOTER_WIDE_ACTIONS_COMPACT_BREAKPOINT_PX : COMPOSER_FOOTER_COMPACT_BREAKPOINT_PX;
1918
1842
  return width !== null && width < breakpoint;
1919
1843
  }
1920
1844
  function shouldUseCompactComposerPrimaryActions(width, options) {
1845
+ if (!options?.hasWideActions) {
1846
+ return false;
1847
+ }
1921
1848
  return width !== null && width < COMPOSER_PRIMARY_ACTIONS_COMPACT_BREAKPOINT_PX;
1922
1849
  }
1923
1850
  var ComposerMentionNode = class _ComposerMentionNode extends DecoratorNode {
@@ -4248,6 +4175,7 @@ function createMemoryStorage() {
4248
4175
  }
4249
4176
  };
4250
4177
  }
4178
+ var composerFooterHasWideActions = true;
4251
4179
  var defaultComposerPlaceholder = "Ask anything, @tag files/folders, or use / to show available commands";
4252
4180
  var runtimeModeConfig = {
4253
4181
  "approval-required": {
@@ -4608,8 +4536,12 @@ var ChatComposer = forwardRef(function ChatComposer2({
4608
4536
  }
4609
4537
  const measureCompactness = () => {
4610
4538
  const width = composerForm.clientWidth;
4611
- const footerCompact = shouldUseCompactComposerFooter(width);
4612
- const primaryActionsCompact = footerCompact && shouldUseCompactComposerPrimaryActions(width);
4539
+ const footerCompact = shouldUseCompactComposerFooter(width, {
4540
+ hasWideActions: composerFooterHasWideActions
4541
+ });
4542
+ const primaryActionsCompact = footerCompact && shouldUseCompactComposerPrimaryActions(width, {
4543
+ hasWideActions: composerFooterHasWideActions
4544
+ });
4613
4545
  return { footerCompact, primaryActionsCompact };
4614
4546
  };
4615
4547
  const initialCompactness = measureCompactness();
@@ -5868,6 +5800,20 @@ function buildOptimisticUserMessageTurnItem(input) {
5868
5800
  ]
5869
5801
  };
5870
5802
  }
5803
+ function mergeOptimisticUserMessageTurnItems(items, optimisticMessages) {
5804
+ if (optimisticMessages.length === 0) {
5805
+ return [...items];
5806
+ }
5807
+ const serverUserMessageIds = new Set(
5808
+ items.flatMap(
5809
+ (item) => item.type === "UserMessage" ? [item.id] : []
5810
+ )
5811
+ );
5812
+ const pendingOptimisticMessages = optimisticMessages.filter(
5813
+ (message) => !serverUserMessageIds.has(message.id)
5814
+ );
5815
+ return pendingOptimisticMessages.length > 0 ? [...pendingOptimisticMessages, ...items] : [...items];
5816
+ }
5871
5817
  function resolveAssistantMessageCopyState(input) {
5872
5818
  const text = normalizeCopyText(input.text ?? "");
5873
5819
  return {
@@ -6025,6 +5971,34 @@ function visibleTimelineWorkEntries(input) {
6025
5971
  hiddenCount: input.entries.length - maxVisible
6026
5972
  };
6027
5973
  }
5974
+ function messagesTimelineFingerprint(rows) {
5975
+ const last = rows.at(-1);
5976
+ if (!last) {
5977
+ return "empty";
5978
+ }
5979
+ if (last.kind === "message" && last.item.type === "AgentMessage") {
5980
+ const text = last.item.content.map((part) => part.text).join("");
5981
+ return `${rows.length}:${last.id}:${text.length}:${last.item.phase ?? "done"}:${last.completedAt ?? ""}`;
5982
+ }
5983
+ if (last.kind === "proposed-plan") {
5984
+ return `${rows.length}:${last.id}:${last.item.text.length}`;
5985
+ }
5986
+ if (last.kind === "work") {
5987
+ const lastEntry = last.groupedEntries.at(-1);
5988
+ return `${rows.length}:${last.id}:${last.groupedEntries.length}:${lastEntry?.status ?? ""}`;
5989
+ }
5990
+ return `${rows.length}:${last.id}`;
5991
+ }
5992
+ function turnItemTextForCopy(item) {
5993
+ switch (item.type) {
5994
+ case "AgentMessage":
5995
+ return normalizeCopyText(item.content.map((part) => part.text).join("\n\n"));
5996
+ case "Plan":
5997
+ return normalizeCopyText(item.text);
5998
+ default:
5999
+ return null;
6000
+ }
6001
+ }
6028
6002
  function isAssistantCredentialError(message) {
6029
6003
  return /OpenAI API key|OpenAI platform credentials|OpenAI credential|Saved OpenAI credentials/i.test(
6030
6004
  message
@@ -6581,6 +6555,17 @@ function normalizePlanMarkdownForExport(planMarkdown) {
6581
6555
  return `${planMarkdown.trimEnd()}
6582
6556
  `;
6583
6557
  }
6558
+ function downloadPlanAsTextFile(filename, contents) {
6559
+ const blob = new Blob([contents], { type: "text/markdown;charset=utf-8" });
6560
+ const url = URL.createObjectURL(blob);
6561
+ const anchor = document.createElement("a");
6562
+ anchor.href = url;
6563
+ anchor.download = filename;
6564
+ anchor.click();
6565
+ window.setTimeout(() => {
6566
+ URL.revokeObjectURL(url);
6567
+ }, 0);
6568
+ }
6584
6569
  var ProposedPlanCard = memo(function ProposedPlanCard2({
6585
6570
  planMarkdown
6586
6571
  }) {
@@ -7425,6 +7410,164 @@ var ChatView = memo(function ChatView2({
7425
7410
  }
7426
7411
  );
7427
7412
  });
7413
+ var ComposerPendingApprovalActions = memo(
7414
+ function ComposerPendingApprovalActions2({
7415
+ isResponding,
7416
+ requestId,
7417
+ onRespondToApproval
7418
+ }) {
7419
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
7420
+ /* @__PURE__ */ jsx(
7421
+ Button,
7422
+ {
7423
+ size: "sm",
7424
+ variant: "ghost",
7425
+ disabled: isResponding,
7426
+ onClick: () => void onRespondToApproval(requestId, "cancel"),
7427
+ children: "Cancel turn"
7428
+ }
7429
+ ),
7430
+ /* @__PURE__ */ jsx(
7431
+ Button,
7432
+ {
7433
+ size: "sm",
7434
+ variant: "destructive",
7435
+ disabled: isResponding,
7436
+ onClick: () => void onRespondToApproval(requestId, "decline"),
7437
+ children: "Decline"
7438
+ }
7439
+ ),
7440
+ /* @__PURE__ */ jsx(
7441
+ Button,
7442
+ {
7443
+ size: "sm",
7444
+ variant: "outline",
7445
+ disabled: isResponding,
7446
+ onClick: () => void onRespondToApproval(requestId, "acceptForSession"),
7447
+ children: "Always allow this session"
7448
+ }
7449
+ ),
7450
+ /* @__PURE__ */ jsx(
7451
+ Button,
7452
+ {
7453
+ size: "sm",
7454
+ variant: "default",
7455
+ disabled: isResponding,
7456
+ onClick: () => void onRespondToApproval(requestId, "accept"),
7457
+ children: "Approve once"
7458
+ }
7459
+ )
7460
+ ] });
7461
+ }
7462
+ );
7463
+ var ComposerPendingApprovalPanel = memo(
7464
+ function ComposerPendingApprovalPanel2({
7465
+ approval,
7466
+ pendingCount
7467
+ }) {
7468
+ const approvalSummary = approval.requestKind === "command" ? "Command approval requested" : approval.requestKind === "file-read" ? "File-read approval requested" : "File-change approval requested";
7469
+ return /* @__PURE__ */ jsx("div", { className: "px-4 py-3.5 sm:px-5 sm:py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
7470
+ /* @__PURE__ */ jsx("span", { className: "text-sm uppercase tracking-[0.2em]", children: "PENDING APPROVAL" }),
7471
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-sm", children: approvalSummary }),
7472
+ pendingCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
7473
+ "1/",
7474
+ pendingCount
7475
+ ] }) : null
7476
+ ] }) });
7477
+ }
7478
+ );
7479
+
7480
+ // src/upstream/t3code/apps/web/src/components/composerInlineChip.ts
7481
+ var COMPOSER_INLINE_CHIP_CLASS_NAME = "inline-flex max-w-full select-none items-center gap-1 rounded-md border border-border/70 bg-accent/40 px-1.5 py-px font-medium text-[12px] leading-[1.1] text-foreground align-middle";
7482
+ var COMPOSER_INLINE_CHIP_ICON_CLASS_NAME = "size-3.5 shrink-0 opacity-85";
7483
+ var COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME = "truncate select-none leading-tight";
7484
+ var COMPOSER_INLINE_SKILL_CHIP_CLASS_NAME = "inline-flex max-w-full select-none items-center gap-1 rounded-md border border-fuchsia-500/25 bg-fuchsia-500/12 px-1.5 py-px font-medium text-[12px] leading-[1.1] text-fuchsia-700 align-middle dark:text-fuchsia-300";
7485
+ var COMPOSER_INLINE_CHIP_DISMISS_BUTTON_CLASS_NAME = "ml-0.5 inline-flex size-3.5 shrink-0 cursor-pointer items-center justify-center rounded-sm text-muted-foreground/72 transition-colors hover:bg-foreground/6 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
7486
+ function TerminalContextInlineChip(props) {
7487
+ const { expired = false, label, tooltipText } = props;
7488
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
7489
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
7490
+ "span",
7491
+ {
7492
+ className: cn(
7493
+ COMPOSER_INLINE_CHIP_CLASS_NAME,
7494
+ expired && "border-destructive/35 bg-destructive/8 text-destructive"
7495
+ ),
7496
+ "data-terminal-context-expired": expired ? "true" : void 0,
7497
+ children: [
7498
+ /* @__PURE__ */ jsx(
7499
+ TerminalIcon,
7500
+ {
7501
+ "aria-hidden": "true",
7502
+ className: cn(
7503
+ COMPOSER_INLINE_CHIP_ICON_CLASS_NAME,
7504
+ "size-3.5",
7505
+ expired && "opacity-100"
7506
+ )
7507
+ }
7508
+ ),
7509
+ /* @__PURE__ */ jsx("span", { className: COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME, children: label })
7510
+ ]
7511
+ }
7512
+ ) }),
7513
+ /* @__PURE__ */ jsx(TooltipContent, { className: "max-w-80 whitespace-pre-wrap leading-tight", side: "top", children: tooltipText })
7514
+ ] });
7515
+ }
7516
+ function formatTerminalContextLabel(context) {
7517
+ return context.label?.trim() || `Terminal ${context.id}`;
7518
+ }
7519
+ function isTerminalContextExpired(context) {
7520
+ return typeof context.expiresAt === "number" && context.expiresAt <= Date.now();
7521
+ }
7522
+ function ComposerPendingTerminalContextChip({
7523
+ context
7524
+ }) {
7525
+ const label = formatTerminalContextLabel(context);
7526
+ const expired = isTerminalContextExpired(context);
7527
+ const tooltipText = expired ? `Terminal context expired. Remove and re-add ${label} to include it in your message.` : context.text;
7528
+ return /* @__PURE__ */ jsx(
7529
+ TerminalContextInlineChip,
7530
+ {
7531
+ expired,
7532
+ label,
7533
+ tooltipText
7534
+ }
7535
+ );
7536
+ }
7537
+ function ComposerPendingTerminalContexts({
7538
+ className,
7539
+ contexts
7540
+ }) {
7541
+ if (contexts.length === 0) {
7542
+ return null;
7543
+ }
7544
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-wrap gap-1.5", className), children: contexts.map((context) => /* @__PURE__ */ jsx(ComposerPendingTerminalContextChip, { context }, context.id)) });
7545
+ }
7546
+ function getComposerProviderState(input) {
7547
+ const promptEffort = input.modelOptions?.find((option) => option.name === "effort")?.value ?? null;
7548
+ return {
7549
+ modelOptionsForDispatch: input.modelOptions ?? void 0,
7550
+ promptEffort,
7551
+ provider: input.provider
7552
+ };
7553
+ }
7554
+ function renderProviderTraitsMenuContent(_input) {
7555
+ return null;
7556
+ }
7557
+ function renderProviderTraitsPicker(input) {
7558
+ if (!input.onEffortChange) {
7559
+ return null;
7560
+ }
7561
+ const effortValue = input.modelOptions?.find((option) => option.name === "effort")?.value ?? "medium";
7562
+ const effort = isCodexReasoningEffort(effortValue) ? effortValue : "medium";
7563
+ return /* @__PURE__ */ jsx(
7564
+ TraitsPicker,
7565
+ {
7566
+ effort,
7567
+ onEffortChange: input.onEffortChange
7568
+ }
7569
+ );
7570
+ }
7428
7571
 
7429
7572
  // src/upstream/t3code/apps/web/src/components/chat/composer-realtime-conversation.logic.ts
7430
7573
  function isRealtimeConversationLive(phase) {
@@ -7499,1885 +7642,92 @@ var RecordingMeterState = class {
7499
7642
  return this.history.join("");
7500
7643
  }
7501
7644
  };
7502
-
7503
- // src/hooks/chat-lifecycle.tsx
7504
- function createDefaultTurnStartParams({
7505
- clientMessageId,
7506
- imageUrls,
7507
- interactionMode = "default",
7508
- runtimeMode,
7509
- sendContext,
7510
- threadId
7511
- }) {
7512
- const collaborationMode = interactionMode === "plan" ? {
7513
- mode: "plan",
7514
- settings: {
7515
- model: sendContext.model,
7516
- reasoning_effort: sendContext.effort ?? null,
7517
- developer_instructions: null
7518
- }
7519
- } : void 0;
7520
- return {
7521
- clientMessageId,
7522
- ...collaborationMode ? { collaborationMode } : {},
7523
- ...runtimeModeToTurnPolicy(runtimeMode),
7524
- effort: sendContext.effort,
7525
- input: [
7526
- ...sendContext.items.map(composerUserInputToProtocolUserInput),
7527
- ...imageUrls.map((url) => ({ type: "image", url }))
7528
- ],
7529
- model: sendContext.model,
7530
- threadId
7531
- };
7532
- }
7533
- function runtimeModeToTurnPolicy(runtimeMode) {
7534
- if (runtimeMode === "approval-required") {
7535
- return {
7536
- approvalPolicy: "on-request",
7537
- sandboxPolicy: {
7538
- type: "workspaceWrite",
7539
- writableRoots: [],
7540
- networkAccess: false,
7541
- excludeTmpdirEnvVar: false,
7542
- excludeSlashTmp: false
7543
- }
7544
- };
7545
- }
7546
- if (runtimeMode === "auto-accept-edits") {
7547
- return {
7548
- approvalPolicy: "on-failure",
7549
- sandboxPolicy: {
7550
- type: "workspaceWrite",
7551
- writableRoots: [],
7552
- networkAccess: false,
7553
- excludeTmpdirEnvVar: false,
7554
- excludeSlashTmp: false
7645
+ var ComposerRealtimeConversationControl = memo(
7646
+ function ComposerRealtimeConversationControl2({
7647
+ compact,
7648
+ disabled = false,
7649
+ preserveComposerFocusOnPointerDown = false,
7650
+ realtimeConversation
7651
+ }) {
7652
+ const state = getRealtimeConversationControlState(realtimeConversation);
7653
+ const pointerFocusProps = preserveComposerFocusOnPointerDown ? { onPointerDown: preventPointerFocus2 } : void 0;
7654
+ return /* @__PURE__ */ jsxs(
7655
+ Button,
7656
+ {
7657
+ type: "button",
7658
+ variant: "ghost",
7659
+ size: compact ? "icon-sm" : "sm",
7660
+ className: cn(
7661
+ "shrink-0 text-muted-foreground/80 hover:text-foreground",
7662
+ state.isActive && "text-primary hover:text-primary",
7663
+ state.isBusy && "animate-pulse"
7664
+ ),
7665
+ ...pointerFocusProps,
7666
+ "aria-label": state.label,
7667
+ "aria-pressed": state.isActive,
7668
+ "data-realtime-conversation-phase": realtimeConversation.phase,
7669
+ disabled: disabled || realtimeConversation.disabled || state.isBusy,
7670
+ title: state.title,
7671
+ onClick: state.action === "stop" ? realtimeConversation.onStop : realtimeConversation.onStart,
7672
+ children: [
7673
+ state.isBusy ? /* @__PURE__ */ jsx(
7674
+ "svg",
7675
+ {
7676
+ width: "14",
7677
+ height: "14",
7678
+ viewBox: "0 0 14 14",
7679
+ fill: "none",
7680
+ className: "animate-spin",
7681
+ "aria-hidden": "true",
7682
+ children: /* @__PURE__ */ jsx(
7683
+ "circle",
7684
+ {
7685
+ cx: "7",
7686
+ cy: "7",
7687
+ r: "5.5",
7688
+ stroke: "currentColor",
7689
+ strokeWidth: "1.5",
7690
+ strokeLinecap: "round",
7691
+ strokeDasharray: "20 12"
7692
+ }
7693
+ )
7694
+ }
7695
+ ) : /* @__PURE__ */ jsx(MicIcon, { "aria-hidden": "true" }),
7696
+ /* @__PURE__ */ jsx("span", { className: compact ? "sr-only" : "hidden sm:inline", children: state.isActive ? "Live voice" : "Realtime" })
7697
+ ]
7555
7698
  }
7556
- };
7699
+ );
7557
7700
  }
7558
- if (runtimeMode === "full-access") {
7559
- return {
7560
- approvalPolicy: "never",
7561
- sandboxPolicy: { type: "dangerFullAccess" }
7562
- };
7701
+ );
7702
+ var preventPointerFocus2 = (event) => {
7703
+ event.preventDefault();
7704
+ };
7705
+ var ProviderStatusBanner = memo(function ProviderStatusBanner2({
7706
+ status
7707
+ }) {
7708
+ if (!status || status.status === "ready" || status.status === "disabled") {
7709
+ return null;
7563
7710
  }
7564
- return {};
7565
- }
7566
- function useCodexChatLifecycle(options) {
7567
- const threadId = useMemo(() => normalizeThreadId(options.threadId), [options.threadId]);
7568
- const [threadSnapshot, setThreadSnapshot] = useState(
7569
- options.initialState?.thread?.id === threadId ? options.initialState : null
7570
- );
7571
- const [activeThread, setActiveThread] = useState(null);
7572
- const [runtimeError, setRuntimeError] = useState(null);
7573
- const [isSending, setIsSending] = useState(false);
7574
- const [reconnectToken, setReconnectToken] = useState(0);
7575
- const [optimisticUserMessages, setOptimisticUserMessages] = useState([]);
7576
- const [activeRuntimeStartedAt, setActiveRuntimeStartedAt] = useState(
7577
- null
7578
- );
7579
- const activeRuntimeStartedAtRef = useRef(null);
7580
- const localDispatchStartedAtRef = useRef(null);
7581
- const pendingComposerSendRef = useRef(null);
7582
- const sendInFlightRef = useRef(false);
7583
- const threadStoreRef = useRef(
7584
- options.initialState?.thread?.id === threadId ? ThreadEventStore.fromThread(options.initialState.thread) : null
7585
- );
7586
- const threadSnapshotRef = useRef(threadSnapshot);
7587
- const activeEventsIteratorRef = useRef(null);
7588
- const lifecycleGenerationRef = useRef(0);
7589
- const lifecycleKeyRef = useRef(null);
7590
- const subscriptionAbortRef = useRef(null);
7591
- const appServerSession = useMemo(
7592
- () => new AppServerSession(options.appServer),
7593
- [options.appServer]
7594
- );
7595
- const lifecycleKey = `${threadId}:${options.connectOnMount === false ? "draft" : "server"}`;
7596
- if (lifecycleKeyRef.current !== lifecycleKey) {
7597
- lifecycleKeyRef.current = lifecycleKey;
7598
- lifecycleGenerationRef.current += 1;
7599
- }
7600
- const visibleRuntimeError = runtimeError?.threadId === threadId ? runtimeError.message : null;
7601
- const closeActiveSubscription = useCallback(() => {
7602
- subscriptionAbortRef.current?.abort();
7603
- subscriptionAbortRef.current = null;
7604
- const iterator = activeEventsIteratorRef.current;
7605
- activeEventsIteratorRef.current = null;
7606
- void iterator?.return?.();
7607
- }, []);
7608
- const visibleOptimisticUserMessages = useMemo(
7609
- () => optimisticUserMessages.filter((message) => message.threadId === threadId).map((message) => message.item),
7610
- [optimisticUserMessages, threadId]
7611
- );
7612
- const setProtocolConnectionStatus = useCallback(
7613
- (status) => {
7614
- const store = threadStoreRef.current;
7615
- if (!store) {
7616
- return;
7617
- }
7618
- const snapshot = store.setConnectionStatus(status);
7619
- threadSnapshotRef.current = snapshot;
7620
- setThreadSnapshot(snapshot);
7621
- },
7622
- []
7623
- );
7624
- const hasPendingRequest = Boolean(threadSnapshot?.pendingRequests.length);
7625
- const {
7626
- beginLocalDispatch,
7627
- isSendBusy,
7628
- localDispatchStartedAt,
7629
- resetLocalDispatch,
7630
- serverAcknowledgedLocalDispatch
7631
- } = useLocalDispatchState({
7632
- hasPendingRequest,
7633
- runtimeError: visibleRuntimeError,
7634
- threadState: threadSnapshot
7635
- });
7636
- useEffect(() => {
7637
- threadSnapshotRef.current = threadSnapshot;
7638
- options.onState?.(threadSnapshot);
7639
- }, [options, threadSnapshot]);
7640
- useEffect(() => {
7641
- activeRuntimeStartedAtRef.current = activeRuntimeStartedAt;
7642
- }, [activeRuntimeStartedAt]);
7643
- useEffect(() => {
7644
- localDispatchStartedAtRef.current = localDispatchStartedAt;
7645
- }, [localDispatchStartedAt]);
7646
- const removeOptimisticUserMessage = useCallback((itemId) => {
7647
- setOptimisticUserMessages(
7648
- (current) => current.filter((message) => message.item.id !== itemId)
7649
- );
7650
- }, []);
7651
- const restorePendingComposerSend = useCallback(() => {
7652
- const pendingComposerSend = pendingComposerSendRef.current;
7653
- if (!pendingComposerSend) {
7654
- return;
7655
- }
7656
- removeOptimisticUserMessage(pendingComposerSend.optimisticItemId);
7657
- pendingComposerSend.restore?.();
7658
- }, [removeOptimisticUserMessage]);
7659
- const handleRuntimeError = useCallback(
7660
- (error) => {
7661
- options.onRuntimeError?.(error);
7662
- if (options.isRecoverableConnectionError?.(error) && !pendingComposerSendRef.current) {
7663
- resetLocalDispatch();
7664
- setActiveRuntimeStartedAt(null);
7665
- setIsSending(false);
7666
- setProtocolConnectionStatus("error");
7667
- return;
7668
- }
7669
- setRuntimeError({ message: error.message, threadId });
7670
- if (pendingComposerSendRef.current) {
7671
- if (!pendingComposerSendRef.current.serverUserMessageAcknowledged) {
7672
- restorePendingComposerSend();
7673
- }
7674
- pendingComposerSendRef.current = null;
7675
- sendInFlightRef.current = false;
7676
- setIsSending(false);
7677
- resetLocalDispatch();
7678
- setActiveRuntimeStartedAt(null);
7679
- }
7680
- setProtocolConnectionStatus("error");
7681
- },
7682
- [
7683
- options,
7684
- resetLocalDispatch,
7685
- restorePendingComposerSend,
7686
- setProtocolConnectionStatus,
7687
- threadId
7688
- ]
7689
- );
7690
- const handleSubmittedUserMessage = useCallback(
7691
- (state) => {
7692
- const pendingComposerSend = pendingComposerSendRef.current;
7693
- if (pendingComposerSend) {
7694
- pendingComposerSendRef.current = {
7695
- ...pendingComposerSend,
7696
- serverUserMessageAcknowledged: true
7697
- };
7698
- }
7699
- sendInFlightRef.current = false;
7700
- setIsSending(false);
7701
- options.onThreadListChanged?.();
7702
- options.onSubmittedUserMessage?.(state);
7703
- pendingComposerSendRef.current = null;
7704
- },
7705
- [options]
7706
- );
7707
- const handleThreadStarted = useCallback(
7708
- (state) => {
7709
- const runtimeStartedAt = activeRuntimeStartedAtRef.current ?? localDispatchStartedAtRef.current ?? (/* @__PURE__ */ new Date()).toISOString();
7710
- setActiveRuntimeStartedAt((current) => current ?? runtimeStartedAt);
7711
- if (pendingComposerSendRef.current) {
7712
- pendingComposerSendRef.current = null;
7713
- sendInFlightRef.current = false;
7714
- setIsSending(false);
7715
- options.onThreadListChanged?.();
7716
- }
7717
- options.onThreadStarted?.(state);
7718
- },
7719
- [options]
7720
- );
7721
- const applyServerNotification = useCallback(
7722
- (notification) => {
7723
- const store = threadStoreRef.current;
7724
- if (!store) {
7725
- return;
7726
- }
7727
- const next = store.applyNotification(notification);
7728
- threadSnapshotRef.current = next;
7729
- setThreadSnapshot(next);
7730
- if (notification.method === "item/completed" && notification.params.item.type === "userMessage") {
7731
- window.setTimeout(() => handleSubmittedUserMessage(next), 0);
7732
- }
7733
- if (threadEventSnapshotHasStarted(next)) {
7734
- window.setTimeout(() => handleThreadStarted(next), 0);
7735
- }
7736
- },
7737
- [handleSubmittedUserMessage, handleThreadStarted]
7738
- );
7739
- const applyServerRequest = useCallback(
7740
- (request) => {
7741
- const store = threadStoreRef.current;
7742
- if (!store) {
7743
- return;
7744
- }
7745
- const next = store.applyRequest(request);
7746
- threadSnapshotRef.current = next;
7747
- setThreadSnapshot(next);
7748
- },
7749
- []
7750
- );
7751
- const connectThread = useCallback(
7752
- async (input = {}) => {
7753
- const generation = lifecycleGenerationRef.current;
7754
- const isCurrentLifecycle = (abortController2) => !abortController2.signal.aborted && lifecycleGenerationRef.current === generation;
7755
- closeActiveSubscription();
7756
- const abortController = new AbortController();
7757
- subscriptionAbortRef.current = abortController;
7758
- try {
7759
- setRuntimeError(null);
7760
- let resumeThread = null;
7761
- if (options.buildThreadStartParams) {
7762
- const response = await appServerSession.threadStart(
7763
- options.buildThreadStartParams({ threadId })
7764
- );
7765
- resumeThread = response.thread;
7766
- } else {
7767
- const response = await appServerSession.threadResume({ threadId });
7768
- resumeThread = response.thread;
7769
- }
7770
- if (!isCurrentLifecycle(abortController)) {
7771
- return;
7772
- }
7773
- const currentSnapshot = threadSnapshotRef.current;
7774
- const handoffSnapshot = currentSnapshot?.thread?.id === threadId && threadEventSnapshotHasStarted(currentSnapshot) ? currentSnapshot : options.initialState?.thread?.id === threadId ? options.initialState : null;
7775
- const shouldDeferVisibleResumeSnapshot = Boolean(pendingComposerSendRef.current) && !handoffSnapshot && currentSnapshot === null;
7776
- const handoffWorkStartedAt = activeRuntimeStartedAtRef.current ?? localDispatchStartedAtRef.current;
7777
- if (handoffWorkStartedAt) {
7778
- setActiveRuntimeStartedAt((current) => current ?? handoffWorkStartedAt);
7779
- }
7780
- if (!handoffSnapshot) {
7781
- threadStoreRef.current = ThreadEventStore.fromThread(resumeThread);
7782
- }
7783
- const storedThread = options.threadReader ? await options.threadReader.readThread({
7784
- thread_id: threadId,
7785
- include_archived: false,
7786
- include_history: false
7787
- }) : storedThreadFromAppServerThread(resumeThread);
7788
- const tokenUsageReplay = options.threadReader ? await storedTokenUsageReplayNotification({
7789
- thread: resumeThread,
7790
- threadId,
7791
- threadReader: options.threadReader
7792
- }) : null;
7793
- if (!isCurrentLifecycle(abortController)) {
7794
- return;
7795
- }
7796
- setActiveThread(storedThread);
7797
- options.onActiveThread?.(storedThread);
7798
- const store = threadStoreRef.current ?? ThreadEventStore.fromThread(resumeThread);
7799
- threadStoreRef.current = store;
7800
- if (tokenUsageReplay) {
7801
- store.applyNotification(tokenUsageReplay);
7802
- }
7803
- const nextSnapshot = store.setConnectionStatus(
7804
- input.force ? "reconnecting" : "connecting"
7805
- );
7806
- if (!shouldDeferVisibleResumeSnapshot) {
7807
- threadSnapshotRef.current = nextSnapshot;
7808
- setThreadSnapshot(nextSnapshot);
7809
- if (threadEventSnapshotHasStarted(nextSnapshot)) {
7810
- window.setTimeout(() => handleThreadStarted(nextSnapshot), 0);
7811
- }
7812
- }
7813
- const events = appServerSession.events();
7814
- if (!events) {
7815
- setProtocolConnectionStatus("connected");
7816
- return;
7817
- }
7818
- if (shouldDeferVisibleResumeSnapshot) {
7819
- store.setConnectionStatus("connected");
7820
- } else {
7821
- setProtocolConnectionStatus("connected");
7822
- }
7823
- const iterator = events[Symbol.asyncIterator]();
7824
- activeEventsIteratorRef.current = iterator;
7825
- void (async () => {
7826
- try {
7827
- while (true) {
7828
- const result = await iterator.next();
7829
- if (!isCurrentLifecycle(abortController)) {
7830
- return;
7831
- }
7832
- if (result.done) {
7833
- break;
7834
- }
7835
- applyAppServerEvent(result.value, {
7836
- applyServerNotification,
7837
- applyServerRequest,
7838
- onServerRequest: options.onServerRequest
7839
- });
7840
- }
7841
- if (isCurrentLifecycle(abortController)) {
7842
- setProtocolConnectionStatus("closed");
7843
- }
7844
- } catch (error) {
7845
- if (isCurrentLifecycle(abortController)) {
7846
- handleRuntimeError(
7847
- error instanceof Error ? error : new Error("Codex chat connection failed.")
7848
- );
7849
- }
7850
- } finally {
7851
- if (activeEventsIteratorRef.current === iterator) {
7852
- activeEventsIteratorRef.current = null;
7853
- }
7854
- }
7855
- })();
7856
- } catch (error) {
7857
- if (isCurrentLifecycle(abortController)) {
7858
- handleRuntimeError(
7859
- error instanceof Error ? error : new Error("Codex chat could not connect.")
7860
- );
7861
- }
7711
+ const providerLabel = status.displayName?.trim() || (status.driver ? formatProviderDriverKindLabel(status.driver) : "Codex");
7712
+ const defaultMessage = status.status === "error" ? `${providerLabel} provider is unavailable.` : `${providerLabel} provider has limited availability.`;
7713
+ const title = `${providerLabel} provider status`;
7714
+ return /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-3xl pt-3", children: /* @__PURE__ */ jsxs(Alert, { variant: status.status === "error" ? "destructive" : "default", children: [
7715
+ /* @__PURE__ */ jsx(CircleAlertIcon, { "aria-hidden": "true" }),
7716
+ /* @__PURE__ */ jsx(AlertTitle, { children: title }),
7717
+ /* @__PURE__ */ jsx(
7718
+ AlertDescription,
7719
+ {
7720
+ className: "line-clamp-3",
7721
+ title: status.message ?? defaultMessage,
7722
+ children: status.message ?? defaultMessage
7862
7723
  }
7863
- },
7864
- [
7865
- appServerSession,
7866
- applyServerNotification,
7867
- applyServerRequest,
7868
- closeActiveSubscription,
7869
- handleRuntimeError,
7870
- handleThreadStarted,
7871
- options,
7872
- setProtocolConnectionStatus,
7873
- threadId
7874
- ]
7875
- );
7876
- useEffect(() => {
7877
- if (options.connectOnMount === false) {
7878
- closeActiveSubscription();
7879
- setActiveThread(null);
7880
- options.onActiveThread?.(null);
7881
- setRuntimeError(null);
7882
- if (!pendingComposerSendRef.current) {
7883
- setActiveRuntimeStartedAt(null);
7884
- threadStoreRef.current = null;
7885
- threadSnapshotRef.current = null;
7886
- setThreadSnapshot(null);
7887
- setIsSending(false);
7888
- }
7889
- return;
7890
- }
7891
- void connectThread({ force: reconnectToken > 0 });
7892
- return () => {
7893
- closeActiveSubscription();
7894
- };
7895
- }, [closeActiveSubscription, connectThread, options, options.connectOnMount, reconnectToken]);
7896
- useEffect(() => {
7897
- if (!threadSnapshot?.turns.length || optimisticUserMessages.length === 0) {
7898
- return;
7899
- }
7900
- const serverUserMessages = threadSnapshot.turns.flatMap(
7901
- (turn) => turn.items.flatMap(
7902
- (item) => item.type === "userMessage" ? [
7903
- {
7904
- contentFingerprint: protocolUserInputFingerprint(item.content),
7905
- id: item.id
7906
- }
7907
- ] : []
7908
- )
7909
- );
7910
- const serverUserMessageIds = new Set(
7911
- serverUserMessages.map((message) => message.id)
7912
- );
7913
- const serverUserMessageFingerprints = new Set(
7914
- serverUserMessages.map((message) => message.contentFingerprint)
7915
- );
7916
- const acknowledgedOptimisticIds = optimisticUserMessages.flatMap((message) => {
7917
- if (message.threadId !== threadId) {
7918
- return [];
7919
- }
7920
- if (serverUserMessageIds.has(message.item.id)) {
7921
- return [message.item.id];
7922
- }
7923
- return serverUserMessageFingerprints.has(
7924
- coreUserInputFingerprint(message.item.content)
7925
- ) ? [message.item.id] : [];
7926
- });
7927
- if (acknowledgedOptimisticIds.length === 0) {
7928
- return;
7929
- }
7930
- const timerId = window.setTimeout(() => {
7931
- setOptimisticUserMessages(
7932
- (current) => current.filter(
7933
- (message) => !acknowledgedOptimisticIds.includes(message.item.id)
7934
- )
7935
- );
7936
- }, 0);
7937
- return () => window.clearTimeout(timerId);
7938
- }, [optimisticUserMessages, threadId, threadSnapshot?.turns]);
7939
- useEffect(() => {
7940
- const timerId = window.setTimeout(() => {
7941
- setOptimisticUserMessages((current) => {
7942
- const next = current.filter((message) => message.threadId === threadId);
7943
- return next.length === current.length ? current : next;
7944
- });
7945
- }, 0);
7946
- return () => window.clearTimeout(timerId);
7947
- }, [threadId]);
7948
- useEffect(() => {
7949
- if (!serverAcknowledgedLocalDispatch) {
7950
- return;
7951
- }
7952
- const timerId = window.setTimeout(() => {
7953
- resetLocalDispatch();
7954
- sendInFlightRef.current = false;
7955
- setIsSending(false);
7956
- }, 0);
7957
- return () => window.clearTimeout(timerId);
7958
- }, [resetLocalDispatch, serverAcknowledgedLocalDispatch]);
7959
- const connectionStatus = threadSnapshot?.connectionStatus ?? "idle";
7960
- const turnRunning = Boolean(threadSnapshot?.activeTurnIds.length);
7961
- const assistantStreaming = deriveAssistantStreaming(threadSnapshot);
7962
- const isWorking = deriveChatLifecycleWorkingState({
7963
- connectionStatus,
7964
- isSendBusy,
7965
- threadState: threadSnapshot
7966
- });
7967
- const activeWorkStartedAt = deriveActiveWorkStartedAt({
7968
- isWorking,
7969
- runtimeStartedAt: activeRuntimeStartedAt,
7970
- sendStartedAt: localDispatchStartedAt
7971
- });
7972
- useEffect(() => {
7973
- if (isWorking || activeRuntimeStartedAt === null) {
7974
- return;
7975
- }
7976
- const timerId = window.setTimeout(() => {
7977
- setActiveRuntimeStartedAt(null);
7978
- }, 0);
7979
- return () => window.clearTimeout(timerId);
7980
- }, [activeRuntimeStartedAt, isWorking]);
7981
- const resolveServerRequest = useCallback(
7982
- async (requestId, response) => {
7983
- try {
7984
- await appServerSession.resolveServerRequest(requestId, response);
7985
- return true;
7986
- } catch (error) {
7987
- setRuntimeError({
7988
- message: error instanceof Error ? error.message : "Codex server-request response failed.",
7989
- threadId
7990
- });
7991
- return false;
7992
- }
7993
- },
7994
- [appServerSession, threadId]
7995
- );
7996
- const rejectServerRequest = useCallback(
7997
- async (requestId, error) => {
7998
- try {
7999
- await appServerSession.rejectServerRequest(requestId, error);
8000
- return true;
8001
- } catch (rejectError) {
8002
- setRuntimeError({
8003
- message: rejectError instanceof Error ? rejectError.message : "Codex server-request rejection failed.",
8004
- threadId
8005
- });
8006
- return false;
8007
- }
8008
- },
8009
- [appServerSession, threadId]
8010
- );
8011
- const sendComposerMessage = useCallback(
8012
- async (sendContext, controls, sendOptions = {}) => {
8013
- if (sendInFlightRef.current || isSending || isSendBusy) {
8014
- return;
8015
- }
8016
- if (sendContext.items.length === 0 && sendContext.files.length === 0) {
8017
- return;
8018
- }
8019
- sendInFlightRef.current = true;
8020
- setIsSending(true);
8021
- beginLocalDispatch();
8022
- try {
8023
- const imageUrls = await Promise.all(sendContext.files.map(fileToDataUrl));
8024
- const clientMessageId = defaultId();
8025
- const turnStartParams = (options.buildTurnStartParams ?? createDefaultTurnStartParams)({
8026
- clientMessageId,
8027
- imageUrls,
8028
- interactionMode: sendOptions.interactionMode,
8029
- runtimeMode: sendOptions.runtimeMode,
8030
- sendContext,
8031
- threadId
8032
- });
8033
- const optimisticItemId = optimisticUserMessageIdForClientMessageId(
8034
- clientMessageId
8035
- );
8036
- const optimisticMessage = buildOptimisticUserMessageTurnItem({
8037
- id: optimisticItemId,
8038
- imageUrls,
8039
- items: sendContext.items
8040
- });
8041
- pendingComposerSendRef.current = {
8042
- optimisticItemId,
8043
- restore: () => controls.restoreComposer(sendContext),
8044
- serverUserMessageAcknowledged: false,
8045
- targetThreadId: threadId
8046
- };
8047
- await controls.prepareForOptimisticAppend();
8048
- setOptimisticUserMessages((current) => [
8049
- ...current.filter((message) => message.item.id !== optimisticItemId),
8050
- { item: optimisticMessage, threadId }
8051
- ]);
8052
- controls.clearComposer();
8053
- options.onThreadListChanged?.();
8054
- if (options.connectOnMount === false || !threadSnapshotRef.current) {
8055
- await connectThread({ force: true });
8056
- }
8057
- const activeTurnId = currentActiveTurnId(threadSnapshotRef.current);
8058
- if (activeTurnId) {
8059
- await appServerSession.turnSteer({
8060
- expectedTurnId: activeTurnId,
8061
- input: turnStartParams.input,
8062
- threadId
8063
- });
8064
- } else {
8065
- await appServerSession.turnStart(turnStartParams);
8066
- }
8067
- } catch (error) {
8068
- restorePendingComposerSend();
8069
- pendingComposerSendRef.current = null;
8070
- sendInFlightRef.current = false;
8071
- resetLocalDispatch();
8072
- setActiveRuntimeStartedAt(null);
8073
- setIsSending(false);
8074
- setRuntimeError({
8075
- message: error instanceof Error ? error.message : "Codex could not send the message.",
8076
- threadId
8077
- });
8078
- }
8079
- },
8080
- [
8081
- beginLocalDispatch,
8082
- appServerSession,
8083
- connectThread,
8084
- isSendBusy,
8085
- isSending,
8086
- options,
8087
- resetLocalDispatch,
8088
- restorePendingComposerSend,
8089
- threadId
8090
- ]
8091
- );
8092
- const interrupt = useCallback(async () => {
8093
- const turnId = currentActiveTurnId(threadSnapshotRef.current);
8094
- if (!turnId) {
8095
- setRuntimeError({
8096
- message: "Codex has no active response to stop.",
8097
- threadId
8098
- });
8099
- return false;
8100
- }
8101
- try {
8102
- await appServerSession.turnInterrupt({ threadId, turnId });
8103
- } catch (error) {
8104
- setRuntimeError({
8105
- message: error instanceof Error ? error.message : "Codex could not stop the active response.",
8106
- threadId
8107
- });
8108
- return false;
8109
- }
8110
- if (pendingComposerSendRef.current) {
8111
- removeOptimisticUserMessage(pendingComposerSendRef.current.optimisticItemId);
8112
- }
8113
- pendingComposerSendRef.current = null;
8114
- sendInFlightRef.current = false;
8115
- resetLocalDispatch();
8116
- setActiveRuntimeStartedAt(null);
8117
- setIsSending(false);
8118
- return true;
8119
- }, [appServerSession, removeOptimisticUserMessage, resetLocalDispatch, threadId]);
8120
- const compact = useCallback(async () => {
8121
- if (turnRunning || isSending || isSendBusy) {
8122
- setRuntimeError({
8123
- message: "Wait for the current response to finish before compacting.",
8124
- threadId
8125
- });
8126
- return false;
8127
- }
8128
- try {
8129
- await appServerSession.threadCompactStart({ threadId });
8130
- return true;
8131
- } catch (error) {
8132
- setRuntimeError({
8133
- message: error instanceof Error ? error.message : "Codex compact failed.",
8134
- threadId
8135
- });
8136
- return false;
8137
- }
8138
- }, [appServerSession, isSendBusy, isSending, threadId, turnRunning]);
8139
- const reconnect = useCallback(() => {
8140
- closeActiveSubscription();
8141
- if (pendingComposerSendRef.current) {
8142
- removeOptimisticUserMessage(pendingComposerSendRef.current.optimisticItemId);
8143
- }
8144
- pendingComposerSendRef.current = null;
8145
- sendInFlightRef.current = false;
8146
- setIsSending(false);
8147
- resetLocalDispatch();
8148
- setActiveRuntimeStartedAt(null);
8149
- setRuntimeError(null);
8150
- setProtocolConnectionStatus("reconnecting");
8151
- setReconnectToken((current) => current + 1);
8152
- }, [
8153
- closeActiveSubscription,
8154
- removeOptimisticUserMessage,
8155
- resetLocalDispatch,
8156
- setProtocolConnectionStatus
8157
- ]);
8158
- return {
8159
- activeThread,
8160
- activeWorkStartedAt,
8161
- assistantStreaming,
8162
- compact,
8163
- connectionStatus,
8164
- interrupt,
8165
- isSendBusy,
8166
- isSending,
8167
- isWorking,
8168
- pendingPermissionRequestActive: Boolean(
8169
- threadSnapshot?.pendingRequests.some(
8170
- (request) => request.method === "item/permissions/requestApproval"
8171
- )
8172
- ),
8173
- pendingUserInputActive: Boolean(
8174
- threadSnapshot?.pendingRequests.some(
8175
- (request) => request.method === "item/tool/requestUserInput"
8176
- )
8177
- ),
8178
- reconnect,
8179
- rejectServerRequest,
8180
- runtimeError: visibleRuntimeError,
8181
- sendComposerMessage,
8182
- resolveServerRequest,
8183
- threadSnapshot,
8184
- threadId,
8185
- turnRunning,
8186
- visibleOptimisticUserMessages
8187
- };
8188
- }
8189
- function normalizeThreadId(threadId) {
8190
- return typeof threadId === "string" ? asThreadId(threadId) : threadId;
8191
- }
8192
- function optimisticUserMessageIdForClientMessageId(clientMessageId) {
8193
- return `user-${clientMessageId}`;
8194
- }
8195
- function fileToDataUrl(file) {
8196
- const blob = new Blob([file], { type: file.type || "image/png" });
8197
- return new Promise((resolve, reject) => {
8198
- const reader = new FileReader();
8199
- reader.onload = () => resolve(String(reader.result));
8200
- reader.onerror = () => reject(reader.error ?? new Error("Could not read file."));
8201
- reader.readAsDataURL(blob);
8202
- });
8203
- }
8204
- function defaultId() {
8205
- return globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
8206
- }
8207
- function currentActiveTurnId(snapshot) {
8208
- return snapshot?.activeTurnIds.at(-1) ?? null;
8209
- }
8210
- function protocolUserInputFingerprint(items) {
8211
- return JSON.stringify(items.map(protocolUserInputFingerprintPart));
8212
- }
8213
- function protocolUserInputFingerprintPart(item) {
8214
- switch (item.type) {
8215
- case "text":
8216
- return { text: item.text, type: "text" };
8217
- case "image":
8218
- return { type: "image", url: item.url };
8219
- case "localImage":
8220
- return { path: item.path, type: "localImage" };
8221
- case "skill":
8222
- return { name: item.name, path: item.path, type: "skill" };
8223
- case "mention":
8224
- return { name: item.name, path: item.path, type: "mention" };
8225
- }
8226
- }
8227
- function coreUserInputFingerprint(items) {
8228
- return JSON.stringify(items.map(coreUserInputFingerprintPart));
8229
- }
8230
- function coreUserInputFingerprintPart(item) {
8231
- switch (item.type) {
8232
- case "text":
8233
- return { text: item.text, type: "text" };
8234
- case "image":
8235
- return { type: "image", url: item.image_url };
8236
- case "local_image":
8237
- return { path: item.path, type: "localImage" };
8238
- case "skill":
8239
- return { name: item.name, path: item.path, type: "skill" };
8240
- case "mention":
8241
- return { name: item.name, path: item.path, type: "mention" };
8242
- }
8243
- }
8244
- function composerUserInputToProtocolUserInput(item) {
8245
- switch (item.type) {
8246
- case "text":
8247
- return {
8248
- text: item.text,
8249
- text_elements: (item.text_elements ?? []).map((element) => ({
8250
- byteRange: element.byte_range,
8251
- placeholder: element.placeholder ?? null
8252
- })),
8253
- type: "text"
8254
- };
8255
- case "image":
8256
- return { type: "image", url: item.image_url };
8257
- case "local_image":
8258
- return { path: item.path, type: "localImage" };
8259
- case "skill":
8260
- return { name: item.name, path: item.path, type: "skill" };
8261
- case "mention":
8262
- return { name: item.name, path: item.path, type: "mention" };
8263
- }
8264
- }
8265
- async function storedTokenUsageReplayNotification(input) {
8266
- try {
8267
- const history = await input.threadReader.loadHistory({
8268
- thread_id: input.threadId,
8269
- include_archived: false
8270
- });
8271
- return thread_token_usage_updated_notification_from_rollout_items({
8272
- rolloutItems: history.items,
8273
- thread: input.thread,
8274
- threadId: input.threadId
8275
- });
8276
- } catch {
8277
- return null;
8278
- }
8279
- }
8280
- function storedThreadFromAppServerThread(thread) {
8281
- return {
8282
- thread_id: asThreadId(thread.id),
8283
- rollout_path: thread.path ?? null,
8284
- forked_from_id: thread.forkedFromId ? asThreadId(thread.forkedFromId) : null,
8285
- preview: thread.preview,
8286
- name: thread.name,
8287
- model_provider: thread.modelProvider,
8288
- model: null,
8289
- reasoning_effort: null,
8290
- created_at: new Date(thread.createdAt * 1e3).toISOString(),
8291
- updated_at: new Date(thread.updatedAt * 1e3).toISOString(),
8292
- archived_at: null,
8293
- cwd: thread.cwd,
8294
- cli_version: thread.cliVersion,
8295
- source: typeof thread.source === "string" ? thread.source : "custom",
8296
- thread_source: typeof thread.threadSource === "string" ? thread.threadSource : null,
8297
- agent_nickname: thread.agentNickname,
8298
- agent_role: thread.agentRole,
8299
- git_info: thread.gitInfo,
8300
- history: null
8301
- };
8302
- }
8303
- function applyAppServerEvent(event, handlers) {
8304
- switch (event.type) {
8305
- case "server_notification":
8306
- handlers.applyServerNotification(event.notification);
8307
- return;
8308
- case "server_request":
8309
- handlers.applyServerRequest(event.request);
8310
- handlers.onServerRequest?.(event.request);
8311
- return;
8312
- case "disconnected":
8313
- throw new Error(event.message);
8314
- case "lagged":
8315
- return;
8316
- }
8317
- }
8318
-
8319
- // src/components/codex-chat-render-state.ts
8320
- function createCodexChatRenderState({
8321
- interactionMode = "default",
8322
- lifecycle,
8323
- snapshot
8324
- }) {
8325
- const activeTurnIds = new Set(snapshot?.activeTurnIds ?? []);
8326
- const turns = (snapshot?.turns ?? []).map(
8327
- (turn) => t3TurnFromAppServerTurn(turn, activeTurnIds.has(turn.id))
8328
- );
8329
- const pendingRequests = (snapshot?.pendingRequests ?? []).map(codexChatPendingRequest);
8330
- const pendingDynamicToolCallRequests = pendingRequests.flatMap(
8331
- (request) => request.kind === "dynamicToolCall" ? [request.compatRequest] : []
8332
- );
8333
- const pendingPermissionRequest = pendingRequests.find((request) => request.kind === "permissions") ?? null;
8334
- const pendingUserInputRequest = pendingRequests.find((request) => request.kind === "userInput") ?? null;
8335
- const activeTurnStartedAt = lifecycle?.activeWorkStartedAt ?? null;
8336
- const errors = snapshot?.errors ?? [];
8337
- const isWorking = lifecycle?.isWorking ?? false;
8338
- const optimisticUserMessages = lifecycle?.visibleOptimisticUserMessages ?? [];
8339
- const runtimeError = lifecycle?.runtimeError ?? null;
8340
- const warnings = snapshot?.warnings ?? [];
8341
- const activeProposedPlan = findActiveProposedPlan(snapshot);
8342
- const contextWindow = deriveContextWindowSnapshotFromTokenUsage({
8343
- tokenUsage: snapshot?.tokenUsage?.tokenUsage,
8344
- updatedAt: snapshot?.tokenUsage?.updatedAt
8345
- });
8346
- const banners = defaultRenderBanners({
8347
- pendingRequests,
8348
- runtimeError
8349
- });
8350
- return {
8351
- activeProposedPlan,
8352
- activeTurnStartedAt,
8353
- banners,
8354
- composer: {
8355
- contextWindow,
8356
- pendingUserInput: pendingUserInputRequest?.pendingUserInput ?? null,
8357
- pendingUserInputAdapter: pendingUserInputRequest
8358
- },
8359
- errors,
8360
- interactionMode,
8361
- items: turns.flatMap((turn) => turn.items),
8362
- isWorking,
8363
- optimisticUserMessages,
8364
- pending_dynamic_tool_call_requests: pendingDynamicToolCallRequests,
8365
- pendingRequests,
8366
- pendingPermissionRequest,
8367
- pendingUserInputRequest,
8368
- runtimeError,
8369
- running_turn_ids: snapshot?.activeTurnIds ?? [],
8370
- showPlanFollowUpPrompt: interactionMode === "plan" && Boolean(activeProposedPlan) && !isWorking && !pendingUserInputRequest,
8371
- timeline: {
8372
- activeTurnStartedAt,
8373
- errors,
8374
- isWorking,
8375
- optimisticUserMessages,
8376
- runtimeError,
8377
- turns,
8378
- warnings
8379
- },
8380
- turns,
8381
- warnings
8382
- };
8383
- }
8384
- function findActiveProposedPlan(snapshot) {
8385
- if (!snapshot) {
8386
- return null;
8387
- }
8388
- for (const turn of [...snapshot.turns].reverse()) {
8389
- for (const item of [...turn.items].reverse()) {
8390
- if (item.type !== "plan" || item.text.trim().length === 0) {
8391
- continue;
8392
- }
8393
- return {
8394
- id: `${turn.id}:${item.id}`,
8395
- planMarkdown: item.text,
8396
- title: proposedPlanTitle(item.text),
8397
- turnId: turn.id
8398
- };
8399
- }
8400
- }
8401
- return null;
8402
- }
8403
- function codexChatPendingRequest(request) {
8404
- switch (request.method) {
8405
- case "item/tool/requestUserInput":
8406
- return {
8407
- kind: "userInput",
8408
- itemId: request.params.itemId,
8409
- pendingUserInput: pendingUserInputFromServerRequest(request),
8410
- request,
8411
- requestId: request.id,
8412
- threadId: request.params.threadId,
8413
- turnId: request.params.turnId
8414
- };
8415
- case "item/permissions/requestApproval":
8416
- return {
8417
- kind: "permissions",
8418
- composerRequest: requestPermissionsFromServerRequest(request),
8419
- request,
8420
- requestId: request.id,
8421
- threadId: request.params.threadId,
8422
- turnId: request.params.turnId
8423
- };
8424
- case "item/tool/call":
8425
- return {
8426
- kind: "dynamicToolCall",
8427
- compatRequest: {
8428
- arguments: request.params.arguments,
8429
- call_id: request.params.callId,
8430
- namespace: request.params.namespace,
8431
- tool: request.params.tool,
8432
- turn_id: request.params.turnId
8433
- },
8434
- request,
8435
- requestId: request.id,
8436
- threadId: request.params.threadId,
8437
- turnId: request.params.turnId
8438
- };
8439
- case "mcpServer/elicitation/request":
8440
- return {
8441
- kind: "mcpElicitation",
8442
- request,
8443
- requestId: request.id,
8444
- threadId: request.params.threadId,
8445
- turnId: request.params.turnId
8446
- };
8447
- case "item/commandExecution/requestApproval":
8448
- return {
8449
- kind: "commandApproval",
8450
- request,
8451
- requestId: request.id,
8452
- threadId: request.params.threadId,
8453
- turnId: request.params.turnId
8454
- };
8455
- case "item/fileChange/requestApproval":
8456
- return {
8457
- kind: "fileChangeApproval",
8458
- request,
8459
- requestId: request.id,
8460
- threadId: request.params.threadId,
8461
- turnId: request.params.turnId
8462
- };
8463
- case "account/chatgptAuthTokens/refresh":
8464
- return {
8465
- kind: "chatgptAuthTokensRefresh",
8466
- request,
8467
- requestId: request.id,
8468
- threadId: null,
8469
- turnId: null
8470
- };
8471
- case "applyPatchApproval":
8472
- return {
8473
- kind: "applyPatchApproval",
8474
- request,
8475
- requestId: request.id,
8476
- threadId: request.params.conversationId,
8477
- turnId: null
8478
- };
8479
- case "execCommandApproval":
8480
- return {
8481
- kind: "execCommandApproval",
8482
- request,
8483
- requestId: request.id,
8484
- threadId: request.params.conversationId,
8485
- turnId: null
8486
- };
8487
- }
8488
- }
8489
- function defaultRenderBanners({
8490
- pendingRequests,
8491
- runtimeError
8492
- }) {
8493
- const banners = [];
8494
- if (runtimeError) {
8495
- banners.push({
8496
- id: "runtime-error",
8497
- title: "Codex connection interrupted",
8498
- description: runtimeError,
8499
- variant: "error",
8500
- tone: "destructive"
8501
- });
8502
- }
8503
- for (const request of pendingRequests) {
8504
- if (request.kind === "userInput" || request.kind === "dynamicToolCall") {
8505
- continue;
8506
- }
8507
- if (request.kind === "permissions") {
8508
- banners.push({
8509
- id: `request-permissions:${request.requestId}`,
8510
- request,
8511
- title: "Permissions requested",
8512
- description: "Codex requested extra permissions. Approval controls are not available yet, so the request was denied for this turn.",
8513
- variant: "warning"
8514
- });
8515
- continue;
8516
- }
8517
- banners.push({
8518
- id: `server-request:${request.requestId}`,
8519
- request,
8520
- title: "Codex needs input",
8521
- description: `No default renderer is available for ${request.request.method}.`,
8522
- variant: "warning"
8523
- });
8524
- }
8525
- return banners;
8526
- }
8527
- function t3TurnFromAppServerTurn(turn, isActive) {
8528
- return {
8529
- completed_at: epochMillis(turn.completedAt),
8530
- duration_ms: turn.durationMs,
8531
- error: turn.error ? {
8532
- additional_details: turn.error.additionalDetails,
8533
- codex_error_info: turn.error.codexErrorInfo,
8534
- message: turn.error.message
8535
- } : null,
8536
- id: turn.id,
8537
- items: turn.items.flatMap((item) => t3TurnItemFromThreadItem(item, isActive)),
8538
- items_view: turn.itemsView === "notLoaded" ? "not_loaded" : turn.itemsView,
8539
- started_at: epochMillis(turn.startedAt),
8540
- status: t3TurnStatusFromAppServer(turn.status)
8541
- };
8542
- }
8543
- function t3TurnItemFromThreadItem(item, turnIsActive) {
8544
- switch (item.type) {
8545
- case "userMessage":
8546
- return [
8547
- {
8548
- content: item.content.map(coreUserInputFromAppServer),
8549
- id: item.id,
8550
- type: "UserMessage"
8551
- }
8552
- ];
8553
- case "agentMessage":
8554
- return [
8555
- {
8556
- content: [{ text: item.text, type: "Text" }],
8557
- id: item.id,
8558
- memory_citation: item.memoryCitation ? {
8559
- entries: item.memoryCitation.entries,
8560
- rolloutIds: item.memoryCitation.threadIds
8561
- } : null,
8562
- phase: turnIsActive && item.text.trim().length > 0 ? "streaming" : item.phase,
8563
- type: "AgentMessage"
8564
- }
8565
- ];
8566
- case "plan":
8567
- return [{ id: item.id, text: item.text, type: "Plan" }];
8568
- case "reasoning":
8569
- return [
8570
- {
8571
- id: item.id,
8572
- raw_content: item.content,
8573
- summary_text: item.summary,
8574
- type: "Reasoning"
8575
- }
8576
- ];
8577
- case "commandExecution":
8578
- return [
8579
- {
8580
- command: [item.command],
8581
- cwd: item.cwd,
8582
- duration_ms: item.durationMs,
8583
- exit_code: item.exitCode,
8584
- id: item.id,
8585
- status: item.status === "inProgress" ? "in_progress" : item.status === "declined" ? "cancelled" : item.status,
8586
- stdout: item.aggregatedOutput ?? "",
8587
- type: "CommandExecution"
8588
- }
8589
- ];
8590
- case "fileChange":
8591
- return [
8592
- {
8593
- auto_approved: false,
8594
- changes: {},
8595
- id: item.id,
8596
- status: item.status === "completed" || item.status === "failed" || item.status === "declined" ? item.status : null,
8597
- stderr: "",
8598
- stdout: "",
8599
- type: "FileChange"
8600
- }
8601
- ];
8602
- case "dynamicToolCall":
8603
- return [
8604
- {
8605
- arguments: item.arguments,
8606
- content_items: item.contentItems,
8607
- duration: item.durationMs === null ? null : String(item.durationMs),
8608
- id: item.id,
8609
- namespace: item.namespace,
8610
- status: item.status,
8611
- success: item.success,
8612
- tool: item.tool,
8613
- type: "DynamicToolCall"
8614
- }
8615
- ];
8616
- case "contextCompaction":
8617
- return [{ id: item.id, type: "ContextCompaction" }];
8618
- default:
8619
- return [];
8620
- }
8621
- }
8622
- function pendingUserInputFromServerRequest(request) {
8623
- return {
8624
- itemId: request.params.itemId,
8625
- questions: request.params.questions.map((question) => {
8626
- const normalized = normalizePendingUserInputQuestion(question);
8627
- return {
8628
- ...normalized,
8629
- options: normalized.options.map((option) => ({ ...option }))
8630
- };
8631
- }),
8632
- requestId: request.id,
8633
- threadId: request.params.threadId,
8634
- turnId: request.params.turnId
8635
- };
8636
- }
8637
- function requestPermissionsFromServerRequest(request) {
8638
- return {
8639
- call_id: String(request.id),
8640
- cwd: request.params.cwd,
8641
- permissions: request.params.permissions,
8642
- reason: request.params.reason,
8643
- turn_id: request.params.turnId
8644
- };
8645
- }
8646
- function coreUserInputFromAppServer(input) {
8647
- if (input.type === "image") {
8648
- return { image_url: input.url, type: "image" };
8649
- }
8650
- if (input.type === "localImage") {
8651
- return { path: input.path, type: "local_image" };
8652
- }
8653
- if (input.type === "text") {
8654
- return {
8655
- text: input.text,
8656
- text_elements: input.text_elements.map((element) => ({
8657
- byte_range: element.byteRange,
8658
- placeholder: element.placeholder ?? void 0
8659
- })),
8660
- type: "text"
8661
- };
8662
- }
8663
- return {
8664
- text: input.name,
8665
- text_elements: [],
8666
- type: "text"
8667
- };
8668
- }
8669
- function t3TurnStatusFromAppServer(status) {
8670
- return status === "inProgress" ? "in_progress" : status;
8671
- }
8672
- function epochMillis(value) {
8673
- return typeof value === "number" ? value * 1e3 : null;
8674
- }
8675
- function CodexChatView(props) {
8676
- if (isLifecycleCodexChatViewProps(props)) {
8677
- return createElement(CodexLifecycleChatView, props);
8678
- }
8679
- const { composer, ...chatViewProps } = props;
8680
- return createElement(
8681
- TooltipProvider,
8682
- null,
8683
- createElement(ChatView, {
8684
- ...chatViewProps,
8685
- composer: createElement(ChatComposer, composer)
8686
- })
8687
- );
8688
- }
8689
- function CodexLifecycleChatView({
8690
- actions,
8691
- bannerItems = [],
8692
- className,
8693
- composerCommands,
8694
- composerSkills,
8695
- composerDraftKey,
8696
- composerRef: externalComposerRef,
8697
- defaultInteractionMode = "default",
8698
- defaultRuntimeMode = "full-access",
8699
- editorAriaLabel,
8700
- headerLeading,
8701
- interactionMode,
8702
- isEnvironmentUnavailable = false,
8703
- listRef: externalListRef,
8704
- lifecycle: lifecycleOptions,
8705
- mentionRefs,
8706
- modelOptions,
8707
- placeholder,
8708
- providerStatus = null,
8709
- realtimeConversation,
8710
- renderBannerItems,
8711
- renderPendingRequest,
8712
- renderPendingUserInput,
8713
- renderTimelineExtras,
8714
- runtimeMode,
8715
- showInteractionModeToggle = true,
8716
- showPlanToggle = false,
8717
- planSidebarLabel = "Plan",
8718
- planSidebarOpen = false,
8719
- subtitle,
8720
- threadKey,
8721
- title,
8722
- onCommand,
8723
- onComposerError,
8724
- onControlsChange,
8725
- onInteractionModeChange,
8726
- onRuntimeModeChange,
8727
- onTogglePlanSidebar,
8728
- onImplementProposedPlan,
8729
- onIsAtEndChange
8730
- }) {
8731
- const lifecycle = useCodexChatLifecycle(lifecycleOptions);
8732
- const [localInteractionMode, setLocalInteractionMode] = useState(defaultInteractionMode);
8733
- const [localRuntimeMode, setLocalRuntimeMode] = useState(defaultRuntimeMode);
8734
- const effectiveInteractionMode = interactionMode ?? localInteractionMode;
8735
- const effectiveRuntimeMode = runtimeMode ?? localRuntimeMode;
8736
- const setInteractionMode = useCallback(
8737
- (nextMode) => {
8738
- if (interactionMode === void 0) {
8739
- setLocalInteractionMode(nextMode);
8740
- }
8741
- onInteractionModeChange?.(nextMode);
8742
- },
8743
- [interactionMode, onInteractionModeChange]
8744
- );
8745
- const setRuntimeMode = useCallback(
8746
- (nextMode) => {
8747
- if (runtimeMode === void 0) {
8748
- setLocalRuntimeMode(nextMode);
8749
- }
8750
- onRuntimeModeChange?.(nextMode);
8751
- },
8752
- [runtimeMode, onRuntimeModeChange]
8753
- );
8754
- const effectiveThreadKey = threadKey ?? String(lifecycle.threadId);
8755
- const effectiveComposerDraftKey = composerDraftKey ?? `codex:${String(lifecycle.threadId)}`;
8756
- const effectiveEditorAriaLabel = editorAriaLabel ?? "Message Codex";
8757
- const effectivePlaceholder = placeholder ?? "Ask anything, @tag files/folders, or use / to show available commands";
8758
- const effectiveTitle = title ?? "Codex";
8759
- const renderState = createCodexChatRenderState({
8760
- interactionMode: effectiveInteractionMode,
8761
- lifecycle,
8762
- snapshot: lifecycle.threadSnapshot
8763
- });
8764
- const activeProposedPlan = renderState.activeProposedPlan;
8765
- const showPlanFollowUpPrompt = renderState.showPlanFollowUpPrompt && Boolean(activeProposedPlan);
8766
- const pendingUserInput = renderState.composer.pendingUserInputAdapter;
8767
- const pendingRequestRenderItems = renderPendingRequest ? renderState.pendingRequests.flatMap((request) => {
8768
- if (request.kind === "userInput") {
8769
- return [];
8770
- }
8771
- const defaultNode = defaultPendingRequestNode(request);
8772
- const node = renderPendingRequest({
8773
- defaultNode,
8774
- reject: (error) => rejectPendingRequest(request, error),
8775
- request,
8776
- resolve: (result) => lifecycle.resolveServerRequest(request.requestId, result),
8777
- state: renderState
8778
- });
8779
- if (node === defaultNode) {
8780
- return [];
8781
- }
8782
- return node ? [{ node, request }] : [];
8783
- }) : [];
8784
- const customPendingRequestIds = new Set(
8785
- pendingRequestRenderItems.map(({ request }) => request.requestId)
8786
- );
8787
- const customUserInputNode = pendingUserInput ? renderPendingUserInput?.({
8788
- defaultNode: null,
8789
- reject: (error) => rejectPendingRequest(pendingUserInput, error),
8790
- request: pendingUserInput,
8791
- resolve: (result) => lifecycle.resolveServerRequest(pendingUserInput.requestId, result),
8792
- state: renderState
8793
- }) : null;
8794
- const timelineExtras = renderTimelineExtras?.({ state: renderState });
8795
- const internalComposerRef = useRef(null);
8796
- const composerRef = externalComposerRef ?? internalComposerRef;
8797
- const internalListRef = useRef(null);
8798
- const listRef = externalListRef ?? internalListRef;
8799
- const controlsRef = useRef(null);
8800
- const shouldAutoScrollRef = useRef(true);
8801
- const [composerNotice, setComposerNotice] = useState(null);
8802
- const setComposerDraftPrompt = useComposerDraftStore((store) => store.setPrompt);
8803
- const addComposerDraftImages = useComposerDraftStore((store) => store.addImages);
8804
- const setNotice = useCallback(
8805
- (message) => {
8806
- setComposerNotice(message);
8807
- onComposerError?.(message);
8808
- },
8809
- [onComposerError]
8810
- );
8811
- const scheduleStickToBottom = useCallback(() => {
8812
- controlsRef.current?.scheduleStickToBottom();
8813
- }, []);
8814
- function restoreComposer(sendContext) {
8815
- const snapshot = composerRef.current?.readSnapshot();
8816
- const composerIsEmpty = !snapshot || snapshot.value.trim().length === 0;
8817
- if (!composerIsEmpty) {
8818
- return;
8819
- }
8820
- const restoredImages = createComposerImageAttachments(sendContext.files);
8821
- setComposerDraftPrompt(effectiveComposerDraftKey, sendContext.text);
8822
- addComposerDraftImages(effectiveComposerDraftKey, restoredImages);
8823
- composerRef.current?.setDraft({
8824
- mentionBindings: sendContext.mentionBindings,
8825
- message: sendContext.text
8826
- });
8827
- }
8828
- async function sendComposerMessage() {
8829
- const sendContext = composerRef.current?.getSendContext();
8830
- if (!sendContext) {
8831
- setNotice("Composer is not ready. Try again.");
8832
- return;
8833
- }
8834
- const activePlan = activeProposedPlan;
8835
- const shouldSubmitPlanFollowUp = Boolean(activePlan) && showPlanFollowUpPrompt && sendContext.items.length === 0 && sendContext.files.length === 0;
8836
- const effectiveSendContext = shouldSubmitPlanFollowUp && activePlan ? planImplementationSendContext(sendContext, activePlan) : sendContext;
8837
- const submitInteractionMode = shouldSubmitPlanFollowUp && activePlan ? resolvePlanFollowUpSubmission({
8838
- draftText: sendContext.text,
8839
- planMarkdown: activePlan.planMarkdown
8840
- }).interactionMode : effectiveInteractionMode;
8841
- if (effectiveSendContext.items.length === 0 && effectiveSendContext.files.length === 0) {
8842
- return;
8843
- }
8844
- await lifecycle.sendComposerMessage(effectiveSendContext, {
8845
- clearComposer: () => {
8846
- composerRef.current?.clear();
8847
- setNotice(null);
8848
- },
8849
- prepareForOptimisticAppend: async () => {
8850
- shouldAutoScrollRef.current = true;
8851
- await (controlsRef.current?.prepareForOptimisticAppend?.() ?? listRef.current?.scrollToEnd?.({ animated: false }));
8852
- },
8853
- restoreComposer
8854
- }, { interactionMode: submitInteractionMode, runtimeMode: effectiveRuntimeMode });
8855
- if (submitInteractionMode !== effectiveInteractionMode) {
8856
- setInteractionMode(submitInteractionMode);
8857
- }
8858
- }
8859
- const submitPendingUserInput = (response) => {
8860
- const request = pendingUserInput;
8861
- if (!request) {
8862
- setNotice("Codex thread is not connected. Reconnect and try again.");
8863
- return false;
8864
- }
8865
- void lifecycle.resolveServerRequest(request.requestId, response);
8866
- return true;
8867
- };
8868
- const dismissPendingUserInput = () => {
8869
- const request = pendingUserInput;
8870
- if (!request) {
8871
- return;
8872
- }
8873
- submitPendingUserInput(buildRequestUserInputResponse(request.pendingUserInput, {}));
8874
- };
8875
- function rejectPendingRequest(request, error = "Codex server request was dismissed.") {
8876
- const jsonRpcError = typeof error === "string" ? { code: -32e3, message: error } : error;
8877
- return lifecycle.rejectServerRequest(request.requestId, jsonRpcError);
8878
- }
8879
- const interrupt = useCallback(() => {
8880
- void lifecycle.interrupt().then((accepted) => {
8881
- if (!accepted) {
8882
- setNotice(
8883
- "Codex could not stop the active response. Reconnect and try again."
8884
- );
8885
- }
8886
- });
8887
- }, [lifecycle, setNotice]);
8888
- const handleCommand = useCallback(
8889
- (command) => {
8890
- if (command === "plan") {
8891
- setInteractionMode("plan");
8892
- return;
8893
- }
8894
- if (command === "default") {
8895
- setInteractionMode("default");
8896
- return;
8897
- }
8898
- if (command === "compact") {
8899
- void lifecycle.compact().then((accepted) => {
8900
- if (!accepted) {
8901
- setNotice("Codex thread is not connected. Reconnect and try again.");
8902
- }
8903
- });
8904
- return;
8905
- }
8906
- onCommand?.(command);
8907
- },
8908
- [lifecycle, onCommand, setInteractionMode, setNotice]
8909
- );
8910
- const implementProposedPlanInNewThread = useCallback(
8911
- (plan) => {
8912
- onImplementProposedPlan?.(plan);
8913
- },
8914
- [onImplementProposedPlan]
8915
- );
8916
- const lifecycleBannerItems = [...bannerItems];
8917
- if (composerNotice) {
8918
- lifecycleBannerItems.push({
8919
- id: "composer-notice",
8920
- title: "Composer needs attention",
8921
- description: composerNotice,
8922
- variant: "warning",
8923
- onDismiss: () => setNotice(null)
8924
- });
8925
- }
8926
- if (providerStatus && providerStatus.status !== "ready" && providerStatus.status !== "disabled") {
8927
- const providerLabel = providerStatus.displayName?.trim() || (providerStatus.driver ? providerStatus.driver.split(/[-_\s]+/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ") : "Codex");
8928
- const description = providerStatus.message ?? (providerStatus.status === "error" ? `${providerLabel} provider is unavailable.` : `${providerLabel} provider has limited availability.`);
8929
- lifecycleBannerItems.push({
8930
- description,
8931
- id: "provider-status",
8932
- title: `${providerLabel} provider status`,
8933
- variant: providerStatus.status === "error" ? "error" : "warning"
8934
- });
8935
- }
8936
- lifecycleBannerItems.push(
8937
- ...renderState.banners.filter(
8938
- (banner) => !banner.request || !customPendingRequestIds.has(banner.request.requestId)
8939
- ).map((banner) => ({
8940
- ...banner,
8941
- action: banner.id === "runtime-error" ? { label: "Reconnect", onClick: lifecycle.reconnect } : void 0
8942
- }))
8943
- );
8944
- lifecycleBannerItems.push(
8945
- ...pendingRequestRenderItems.map(({ node, request }) => ({
8946
- id: `custom-pending-request:${request.requestId}`,
8947
- title: "Codex needs input",
8948
- description: node,
8949
- variant: "info"
8950
- }))
8951
- );
8952
- if (customUserInputNode) {
8953
- lifecycleBannerItems.push({
8954
- id: `custom-pending-request:${pendingUserInput?.requestId ?? "user-input"}`,
8955
- title: "Codex needs input",
8956
- description: customUserInputNode,
8957
- variant: "info"
8958
- });
8959
- }
8960
- lifecycleBannerItems.push(...renderBannerItems?.(renderState) ?? []);
8961
- const effectiveActions = showInteractionModeToggle ? /* @__PURE__ */ jsxs(Fragment, { children: [
8962
- /* @__PURE__ */ jsx(
8963
- CodexInteractionModeToggle,
8964
- {
8965
- mode: effectiveInteractionMode,
8966
- onChange: setInteractionMode
8967
- }
8968
- ),
8969
- actions
8970
- ] }) : actions;
8971
- const chatView = /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(
8972
- ChatView,
8973
- {
8974
- actions: effectiveActions,
8975
- bannerItems: lifecycleBannerItems,
8976
- className,
8977
- headerLeading,
8978
- listRef,
8979
- subtitle,
8980
- threadKey: effectiveThreadKey,
8981
- timeline: renderState.timeline,
8982
- title: effectiveTitle,
8983
- onControlsChange: (controls) => {
8984
- controlsRef.current = controls;
8985
- onControlsChange?.(controls);
8986
- },
8987
- onIsAtEndChange: (isAtEnd) => {
8988
- shouldAutoScrollRef.current = isAtEnd;
8989
- onIsAtEndChange?.(isAtEnd);
8990
- },
8991
- composer: /* @__PURE__ */ jsx(
8992
- ChatComposer,
8993
- {
8994
- ref: composerRef,
8995
- contextWindow: renderState.composer.contextWindow,
8996
- disabled: Boolean(lifecycle.runtimeError) || lifecycle.connectionStatus === "connecting" || lifecycle.connectionStatus === "reconnecting",
8997
- draftKey: effectiveComposerDraftKey,
8998
- editorAriaLabel: effectiveEditorAriaLabel,
8999
- interactionMode: effectiveInteractionMode,
9000
- isConnecting: lifecycle.connectionStatus === "connecting" || lifecycle.connectionStatus === "reconnecting",
9001
- isEnvironmentUnavailable,
9002
- isRunning: lifecycle.turnRunning,
9003
- isSending: lifecycle.isSending || lifecycle.isSendBusy,
9004
- mentionRefs: mentionRefs ?? [],
9005
- composerCommands,
9006
- composerSkills,
9007
- modelOptions,
9008
- pendingUserInput: customUserInputNode ? null : renderState.composer.pendingUserInput,
9009
- pendingRequestDisabled: lifecycle.connectionStatus !== "connected",
9010
- placeholder: effectivePlaceholder,
9011
- planFollowUpTitle: activeProposedPlan?.title ?? null,
9012
- planSidebarLabel,
9013
- planSidebarOpen,
9014
- realtimeConversation,
9015
- runtimeMode: effectiveRuntimeMode,
9016
- showInteractionModeToggle,
9017
- showPlanFollowUpPrompt,
9018
- showPlanToggle,
9019
- onCommand: handleCommand,
9020
- onComposerError: setNotice,
9021
- onImplementPlanInNewThread: activeProposedPlan && onImplementProposedPlan ? () => implementProposedPlanInNewThread(activeProposedPlan) : void 0,
9022
- onToggleInteractionMode: () => setInteractionMode(
9023
- effectiveInteractionMode === "plan" ? "default" : "plan"
9024
- ),
9025
- onRuntimeModeChange: setRuntimeMode,
9026
- onTogglePlanSidebar,
9027
- onPendingRequestDismiss: dismissPendingUserInput,
9028
- onPendingRequestSubmit: submitPendingUserInput,
9029
- onInterrupt: interrupt,
9030
- scheduleStickToBottom,
9031
- shouldAutoScrollRef,
9032
- onSend: () => void sendComposerMessage()
9033
- }
9034
- )
9035
- }
9036
- ) });
9037
- if (!timelineExtras) {
9038
- return chatView;
9039
- }
9040
- return /* @__PURE__ */ jsxs(Fragment, { children: [
9041
- chatView,
9042
- timelineExtras
9043
- ] });
9044
- }
9045
- function isLifecycleCodexChatViewProps(props) {
9046
- return "lifecycle" in props && Boolean(props.lifecycle);
9047
- }
9048
- function defaultPendingRequestNode(request) {
9049
- if (request.kind === "permissions") {
9050
- return null;
9051
- }
9052
- return `No default renderer is available for ${request.request.method}.`;
9053
- }
9054
- function CodexInteractionModeToggle({
9055
- mode,
9056
- onChange
9057
- }) {
9058
- return /* @__PURE__ */ jsxs(
9059
- "div",
9060
- {
9061
- "aria-label": "Interaction mode",
9062
- className: "flex shrink-0 items-center rounded-md border bg-background p-0.5",
9063
- role: "group",
9064
- children: [
9065
- /* @__PURE__ */ jsx(
9066
- "button",
9067
- {
9068
- "aria-pressed": mode === "default",
9069
- className: mode === "default" ? "rounded px-2 py-1 font-medium text-foreground text-xs shadow-xs" : "rounded px-2 py-1 text-muted-foreground text-xs hover:text-foreground",
9070
- type: "button",
9071
- onClick: () => onChange("default"),
9072
- children: "Build"
9073
- }
9074
- ),
9075
- /* @__PURE__ */ jsx(
9076
- "button",
9077
- {
9078
- "aria-pressed": mode === "plan",
9079
- className: mode === "plan" ? "rounded px-2 py-1 font-medium text-foreground text-xs shadow-xs" : "rounded px-2 py-1 text-muted-foreground text-xs hover:text-foreground",
9080
- type: "button",
9081
- onClick: () => onChange("plan"),
9082
- children: "Plan"
9083
- }
9084
- )
9085
- ]
9086
- }
9087
- );
9088
- }
9089
- function planImplementationSendContext(sendContext, plan) {
9090
- const text = buildPlanImplementationPrompt(plan.planMarkdown);
9091
- return {
9092
- ...sendContext,
9093
- files: [],
9094
- items: [{ text, text_elements: [], type: "text" }],
9095
- text
9096
- };
9097
- }
9098
-
9099
- // src/components/codex-chat.tsx
9100
- function CodexChat({
9101
- appServer,
9102
- buildThreadStartParams,
9103
- buildTurnStartParams,
9104
- connectOnMount,
9105
- initialState,
9106
- isRecoverableConnectionError,
9107
- onActiveThread,
9108
- onRuntimeError,
9109
- onServerRequest,
9110
- onState,
9111
- onSubmittedUserMessage,
9112
- onThreadListChanged,
9113
- onThreadStarted,
9114
- threadId,
9115
- threadReader,
9116
- ...viewProps
9117
- }) {
9118
- const lifecycle = {
9119
- appServer,
9120
- buildThreadStartParams,
9121
- buildTurnStartParams: buildTurnStartParams ?? createDefaultTurnStartParams,
9122
- connectOnMount,
9123
- initialState,
9124
- isRecoverableConnectionError,
9125
- onActiveThread,
9126
- onRuntimeError,
9127
- onServerRequest,
9128
- onState,
9129
- onSubmittedUserMessage,
9130
- onThreadListChanged,
9131
- onThreadStarted,
9132
- threadId,
9133
- threadReader
9134
- };
9135
- return createElement(CodexChatView, {
9136
- ...viewProps,
9137
- lifecycle
9138
- });
9139
- }
9140
- function CodexChatSidebar(props) {
9141
- return createElement(Sidebar, props);
9142
- }
9143
- function CodexChatLayout({
9144
- children,
9145
- className,
9146
- collapsible,
9147
- defaultOpen,
9148
- onOpenChange,
9149
- open,
9150
- side,
9151
- sidebar
9152
- }) {
9153
- if (!sidebar) {
9154
- return createElement(Fragment$1, null, children);
9155
- }
9156
- return createElement(
9157
- SidebarProvider,
9158
- {
9159
- className,
9160
- defaultOpen,
9161
- onOpenChange,
9162
- open
9163
- },
9164
- createElement(CodexChatSidebar, { collapsible, side }, sidebar),
9165
- createElement(SidebarInset, null, children)
9166
- );
9167
- }
9168
- var CodexChatContext = createContext(null);
9169
- function CodexChatProvider({
9170
- appServer,
9171
- children,
9172
- threadReader,
9173
- threadId
9174
- }) {
9175
- const runtime = useCodexChat({ appServer, threadReader, threadId });
9176
- return createElement(
9177
- CodexChatContext.Provider,
9178
- { value: runtime },
9179
- children
9180
- );
9181
- }
9182
- function useCodexChatRuntime() {
9183
- const runtime = useContext(CodexChatContext);
9184
- if (!runtime) {
9185
- throw new Error("useCodexChatRuntime must be used inside CodexChatProvider.");
9186
- }
9187
- return runtime;
9188
- }
9189
- function useCodexChat(options) {
9190
- const [activeThreadId, setActiveThreadId] = useState(options.threadId ?? null);
9191
- const normalizedThreadId = useMemo(
9192
- () => activeThreadId ? normalizeThreadId2(activeThreadId) : asThreadId("00000000-0000-4000-8000-000000000000"),
9193
- [activeThreadId]
9194
- );
9195
- const lifecycle = useCodexChatLifecycle({
9196
- appServer: options.appServer,
9197
- connectOnMount: activeThreadId !== null,
9198
- threadId: normalizedThreadId,
9199
- threadReader: options.threadReader
9200
- });
9201
- const threadState = useMemo(
9202
- () => createCodexChatRenderState({
9203
- lifecycle,
9204
- snapshot: lifecycle.threadSnapshot
9205
- }),
9206
- [lifecycle]
9207
- );
9208
- const error = lifecycle.runtimeError ? new Error(lifecycle.runtimeError) : null;
9209
- return {
9210
- error,
9211
- messages: messagesFromRenderState(threadState),
9212
- async sendMessage(input) {
9213
- if (!activeThreadId) {
9214
- throw new Error("Cannot send a Codex chat message without a thread.");
9215
- }
9216
- const sendContext = sendContextFromMessageInput(input);
9217
- await lifecycle.sendComposerMessage(sendContext, {
9218
- clearComposer: () => {
9219
- },
9220
- prepareForOptimisticAppend: async () => {
9221
- },
9222
- restoreComposer: () => {
9223
- }
9224
- });
9225
- },
9226
- setThread(nextThreadId) {
9227
- setActiveThreadId(nextThreadId);
9228
- },
9229
- status: chatRuntimeStatus(lifecycle, activeThreadId !== null),
9230
- async stop() {
9231
- await lifecycle.interrupt();
9232
- },
9233
- threadId: activeThreadId,
9234
- threadSnapshot: lifecycle.threadSnapshot,
9235
- threadState
9236
- };
9237
- }
9238
- function chatRuntimeStatus(lifecycle, hasThread) {
9239
- if (!hasThread) {
9240
- return "idle";
9241
- }
9242
- if (lifecycle.runtimeError) {
9243
- return "error";
9244
- }
9245
- if (lifecycle.connectionStatus === "connecting" || lifecycle.connectionStatus === "reconnecting") {
9246
- return "loading";
9247
- }
9248
- if (lifecycle.isSending || lifecycle.isSendBusy) {
9249
- return "submitting";
9250
- }
9251
- if (lifecycle.turnRunning || lifecycle.assistantStreaming) {
9252
- return "streaming";
9253
- }
9254
- return "ready";
9255
- }
9256
- function sendContextFromMessageInput(input) {
9257
- const text = input.text?.trim() ?? "";
9258
- const files = messageInputFiles(input.files);
9259
- const fileParts = input.files && !isFileList(input.files) && !isFileArray(input.files) ? input.files : [];
9260
- const items = [
9261
- ...text ? [{
9262
- text,
9263
- text_elements: [],
9264
- type: "text"
9265
- }] : [],
9266
- ...fileParts.flatMap(messagePartToComposerItem)
9267
- ];
9268
- return {
9269
- effort: defaultCodexReasoningEffort,
9270
- files,
9271
- items,
9272
- mentionBindings: [],
9273
- model: defaultCodexModel,
9274
- text
9275
- };
9276
- }
9277
- function messageInputFiles(files) {
9278
- if (!files) {
9279
- return [];
9280
- }
9281
- if (isFileList(files)) {
9282
- return Array.from(files);
9283
- }
9284
- if (isFileArray(files)) {
9285
- return files;
9286
- }
9287
- return [];
9288
- }
9289
- function messagePartToComposerItem(part) {
9290
- if (part.type === "image") {
9291
- return [{ image_url: part.url, type: "image" }];
9292
- }
9293
- if (part.type === "file") {
9294
- return [{ path: part.url, type: "local_image" }];
9295
- }
9296
- return [];
9297
- }
9298
- function isFileList(files) {
9299
- return typeof FileList !== "undefined" && files instanceof FileList;
9300
- }
9301
- function isFileArray(files) {
9302
- return typeof File !== "undefined" && Array.isArray(files) && files.every((file) => file instanceof File);
9303
- }
9304
- function messagesFromRenderState(threadState) {
9305
- return threadState.items.flatMap((item) => {
9306
- if (item.type === "UserMessage") {
9307
- return [
9308
- {
9309
- id: item.id,
9310
- parts: item.content.flatMap(userInputToMessageParts),
9311
- role: "user"
9312
- }
9313
- ];
9314
- }
9315
- if (item.type === "AgentMessage") {
9316
- return [
9317
- {
9318
- id: item.id,
9319
- parts: item.content.map((part) => ({
9320
- type: "text",
9321
- text: part.text
9322
- })),
9323
- role: "assistant"
9324
- }
9325
- ];
9326
- }
9327
- return [];
9328
- });
9329
- }
9330
- function userInputToMessageParts(input) {
9331
- if (input.type === "text") {
9332
- return [{ type: "text", text: input.text }];
9333
- }
9334
- if (input.type === "image") {
9335
- return [{ type: "image", url: input.image_url }];
9336
- }
9337
- if (input.type === "local_image") {
9338
- return [{ type: "file", url: input.path }];
9339
- }
9340
- return [];
9341
- }
9342
- function normalizeThreadId2(threadId) {
9343
- return typeof threadId === "string" ? asThreadId(threadId) : threadId;
9344
- }
9345
- function CodexThread({ children }) {
9346
- return createElement("div", { "data-codex-thread": "" }, children);
9347
- }
9348
- function CodexMessages() {
9349
- const runtime = useCodexChatRuntime();
9350
- return createElement(
9351
- "div",
9352
- { "data-codex-messages": "" },
9353
- runtime.messages.map(
9354
- (message) => createElement(
9355
- "div",
9356
- { "data-role": message.role, key: message.id },
9357
- message.parts.filter((part) => part.type === "text").map((part) => part.text).join("\n")
9358
- )
9359
7724
  )
9360
- );
9361
- }
9362
- function CodexComposer() {
9363
- const runtime = useCodexChatRuntime();
9364
- const sendMessage = useCallback(
9365
- async (formData) => {
9366
- const text = String(formData.get("message") ?? "");
9367
- if (text.trim()) {
9368
- await runtime.sendMessage({ text });
9369
- }
9370
- },
9371
- [runtime]
9372
- );
9373
- return createElement(
9374
- "form",
9375
- { action: sendMessage, "data-codex-composer": "" },
9376
- createElement("textarea", { name: "message" }),
9377
- createElement("button", { type: "submit" }, "Send")
9378
- );
7725
+ ] }) });
7726
+ });
7727
+ function formatProviderDriverKindLabel(driver) {
7728
+ return driver.split(/[-_\s]+/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
9379
7729
  }
9380
7730
 
9381
- export { CodexChat, CodexChatLayout, CodexChatProvider, CodexChatSidebar, CodexChatView, CodexComposer, CodexMessages, CodexThread, PROJECT_MENTION_SIGIL, RecordingMeterState, SKILL_MENTION_SIGIL, TOOL_MENTION_SIGIL, WORKSPACE_CHAT_MAX_IMAGE_ATTACHMENTS, WORKSPACE_CHAT_MAX_IMAGE_BYTES, assistantComposerDraftKey, buildCollapsedProposedPlanPreviewMarkdown, buildExpandedImagePreview, buildPlanImplementationPrompt, buildPlanImplementationThreadTitle, buildProposedPlanMarkdownFilename, codexModelOptions, codexReasoningEffortOptions, createCodexChatRenderState, createComposerImageAttachments, createDefaultTurnStartParams, decodeHistoryMentions, defaultCodexModel, defaultCodexProviderInstance, defaultCodexReasoningEffort, encodeHistoryMentions, findLinkedMentions, getRealtimeConversationControlState, isAcceptedComposerImageFile, isCodexReasoningEffort, isRealtimeConversationLive, linkedMentionTextElements, mentionBindingRangesForText, mentionBindingsAfterReplacement, mentionToken, normalizeMentionBindingsForText, normalizePlanMarkdownForExport, persistComposerDraftAttachments, proposedPlanTitle, resolveCodexModelOption, resolveCodexReasoningEffortForModel, resolveCodexReasoningEffortOption, resolveDraftEffort, resolveDraftModel, resolvePlanFollowUpSubmission, restoreComposerDraftAttachments, revokeComposerImageAttachments, skillToken, stripDisplayedPlanMarkdown, useCodexChat, useCodexChatLifecycle, useCodexChatRuntime, useComposerDraftStore, useComposerThreadDraft, validateComposerImageFiles };
9382
- //# sourceMappingURL=chunk-JLDH4U5L.js.map
9383
- //# sourceMappingURL=chunk-JLDH4U5L.js.map
7731
+ export { AssistantChangedFilesSection, COMPOSER_FOOTER_COMPACT_BREAKPOINT_PX, COMPOSER_FOOTER_WIDE_ACTIONS_COMPACT_BREAKPOINT_PX, COMPOSER_INLINE_CHIP_CLASS_NAME, COMPOSER_INLINE_CHIP_DISMISS_BUTTON_CLASS_NAME, COMPOSER_INLINE_CHIP_ICON_CLASS_NAME, COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME, COMPOSER_INLINE_SKILL_CHIP_CLASS_NAME, COMPOSER_PRIMARY_ACTIONS_COMPACT_BREAKPOINT_PX, ChatComposer, ChatMarkdown, ChatView, CompactComposerControlsMenu, ComposerBannerStack, ComposerCommandMenu, ComposerPendingApprovalActions, ComposerPendingApprovalPanel, ComposerPendingTerminalContextChip, ComposerPendingTerminalContexts, ComposerPendingUserInputPanel, ComposerPlanFollowUpBanner, ComposerPrimaryActions, ComposerPromptEditor, ComposerRealtimeConversationControl, ExpandedImageDialog, LEGACY_PROJECT_MENTION_SIGIL, MAX_VISIBLE_WORK_LOG_ENTRIES, MessagesTimeline, ModelListRow, ModelPickerContent, PLUGIN_TEXT_MENTION_SIGIL, PROJECT_MENTION_SIGIL, ProposedPlanCard, ProviderModelPicker, ProviderStatusBanner, RecordingMeterState, SKILL_MENTION_SIGIL, TIMELINE_WORKING_ROW_ID, TOOL_MENTION_SIGIL, TerminalContextInlineChip, TooltipProvider, TraitsPicker, WORKSPACE_CHAT_MAX_IMAGE_ATTACHMENTS, WORKSPACE_CHAT_MAX_IMAGE_BYTES, assistantComposerDraftKey, buildChangedFilesTree, buildCollapsedProposedPlanPreviewMarkdown, buildExpandedImagePreview, buildModelPickerSearchText, buildOptimisticUserMessageTurnItem, buildPendingUserInputAnswers, buildPlanImplementationPrompt, buildPlanImplementationThreadTitle, buildProposedPlanMarkdownFilename, buildRequestUserInputResponse, changedFilesForFileChangeTurnItem, codexModelOptions, codexReasoningEffortOptions, composerSnapshotUserInputItems, computeStableMessagesTimelineRows, countAnsweredPendingUserInputQuestions, createComposerImageAttachments, createComposerPromptSnapshot, decodeHistoryMentions, defaultCodexModel, defaultCodexProviderInstance, defaultCodexReasoningEffort, deriveComposerSendState, deriveContextWindowSnapshotFromTokenUsage, deriveMessagesTimelineRows, derivePendingUserInputProgress, detectComposerTrigger, downloadPlanAsTextFile, encodeHistoryMentions, filterCodexModelPickerOptions, findLinkedMentions, findNextMentionTokenRange, formatPendingPrimaryActionLabel, formatTerminalContextLabel, getComposerProviderState, getRealtimeConversationControlState, hasNonZeroChangedFileStat, isAcceptedComposerImageFile, isAssistantCredentialError, isCodexReasoningEffort, isMentionNameChar, isRealtimeConversationLive, isTerminalContextExpired, legacyMentionToken, linkedMentionTextElements, mentionBindingRangesForText, mentionBindingsAfterReplacement, mentionToken, mergeOptimisticUserMessageTurnItems, messagesTimelineFingerprint, normalizeMentionBindingsForText, normalizePendingUserInputQuestion, normalizePlanMarkdownForExport, parseLinkedToolMention, parseStandaloneComposerSlashCommand, persistComposerDraftAttachments, prefillComposerState, proposedPlanTitle, readLegacyComposerDraft, renderProviderTraitsMenuContent, renderProviderTraitsPicker, replaceTextRange, resolveAssistantMessageCopyState, resolveCodexModelOption, resolveCodexReasoningEffortForModel, resolveCodexReasoningEffortOption, resolveComposerMenuActiveItemId, resolveDraftEffort, resolveDraftModel, resolvePendingUserInputAnswer, resolvePlanFollowUpSubmission, restoreComposerDraftAttachments, revokeComposerImageAttachments, scoreModelPickerSearch, searchComposerMentionTargets, searchSlashCommandItems, setPendingUserInputCustomAnswer, shouldShowWorkingRow, shouldUseCompactComposerFooter, shouldUseCompactComposerPrimaryActions, skillToken, stripDisplayedPlanMarkdown, summarizeChangedFileStats, timelineWorkEntryForTurnItem, togglePendingUserInputOptionSelection, turnItemTextForCopy, useComposerDraftStore, useComposerThreadDraft, validateComposerImageFiles, visibleTimelineWorkEntries };
7732
+ //# sourceMappingURL=chunk-NCI4MAWZ.js.map
7733
+ //# sourceMappingURL=chunk-NCI4MAWZ.js.map