zidane-ui 9.1.13 → 9.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/index.d.ts +2 -2
- package/dist/adapters/index.js +2 -2
- package/dist/adapters/live.d.ts +29 -3
- package/dist/adapters/live.js +9 -1
- package/dist/adapters/server-composer-host.js +17 -2
- package/dist/adapters/server-extensions-host.d.ts +0 -1
- package/dist/adapters/server-extensions-host.js +5 -16
- package/dist/adapters/server-git-host.js +7 -16
- package/dist/adapters/server-host.js +181 -43
- package/dist/adapters/server-machines-host.d.ts +2 -0
- package/dist/adapters/server-machines-host.js +24 -25
- package/dist/adapters/server-onboarding-host.d.ts +1 -1
- package/dist/adapters/server-onboarding-host.js +3 -4
- package/dist/adapters/server-session-host.js +22 -3
- package/dist/adapters/server-settings-accounts.js +2 -2
- package/dist/adapters/server-settings-host.js +3 -3
- package/dist/adapters/server-settings-performance.js +7 -9
- package/dist/adapters/server-settings-sections.js +13 -14
- package/dist/adapters/server-sidebar-host.js +2 -2
- package/dist/adapters/sse-host.js +68 -3
- package/dist/adapters/sse-protocol.d.ts +12 -2
- package/dist/adapters/sse-protocol.js +4 -2
- package/dist/app/AppHostProvider.js +4 -3
- package/dist/app/ModalProvider.d.ts +13 -3
- package/dist/app/ModalProvider.js +103 -24
- package/dist/app/NoticeStack.d.ts +33 -0
- package/dist/app/NoticeStack.js +90 -0
- package/dist/app/index.d.ts +3 -2
- package/dist/app/index.js +3 -2
- package/dist/appearance/AppearanceProvider.js +2 -2
- package/dist/appearance/headless/index.js +1 -1
- package/dist/approvals/headless/index.js +2 -2
- package/dist/chat/SessionFilterMenu.d.ts +1 -1
- package/dist/chat/SessionFilterMenu.js +2 -1
- package/dist/chat/Transcript.js +1 -1
- package/dist/chat/composer/Composer.js +9 -6
- package/dist/chat/composer/ComposerEditor.js +1 -1
- package/dist/chat/composer/ConversationBadges.js +1 -1
- package/dist/chat/composer/ModelChainList.js +17 -8
- package/dist/chat/composer/ModelChainTooltip.js +5 -2
- package/dist/chat/composer/use-composer-stores.js +1 -1
- package/dist/chat/composer/use-draft-target.d.ts +20 -1
- package/dist/chat/composer/use-draft-target.js +122 -6
- package/dist/chat/composer/use-new-session-defaults.d.ts +5 -1
- package/dist/chat/composer/use-new-session-defaults.js +17 -4
- package/dist/chat/composer/use-run-meter.js +1 -1
- package/dist/chat/composer/use-send-prompt.js +1 -1
- package/dist/chat/headless/chip-labels.d.ts +1 -0
- package/dist/chat/headless/chip-labels.js +1 -0
- package/dist/chat/headless/composer/index.js +2 -2
- package/dist/chat/headless/draft-target.d.ts +21 -1
- package/dist/chat/headless/fixture-host.js +17 -2
- package/dist/chat/headless/host.d.ts +3 -3
- package/dist/chat/headless/index.d.ts +9 -9
- package/dist/chat/headless/index.js +15 -15
- package/dist/chat/headless/labels.d.ts +13 -4
- package/dist/chat/headless/labels.js +8 -5
- package/dist/chat/headless/session-list.d.ts +20 -6
- package/dist/chat/headless/session-list.js +1 -0
- package/dist/chat/headless/sidebar/directory.d.ts +56 -14
- package/dist/chat/headless/sidebar/directory.js +149 -70
- package/dist/chat/headless/sidebar/index.d.ts +3 -3
- package/dist/chat/headless/sidebar/index.js +3 -3
- package/dist/chat/headless/sidebar/labels.d.ts +15 -6
- package/dist/chat/headless/sidebar/types.d.ts +3 -1
- package/dist/chat/headless/sidebar/view.d.ts +13 -5
- package/dist/chat/headless/sidebar/view.js +31 -11
- package/dist/chat/headless/streams/actions.d.ts +5 -3
- package/dist/chat/headless/streams/actions.js +3 -2
- package/dist/chat/headless/streams/index.d.ts +3 -3
- package/dist/chat/headless/streams/merge.d.ts +6 -10
- package/dist/chat/headless/streams/merge.js +7 -21
- package/dist/chat/headless/streams/session-streams.d.ts +29 -4
- package/dist/chat/headless/streams/session-streams.js +86 -0
- package/dist/chat/headless/streams/store.d.ts +162 -16
- package/dist/chat/headless/streams/store.js +334 -38
- package/dist/chat/headless/streams/types.d.ts +10 -7
- package/dist/chat/headless/transcript-labels.d.ts +1 -0
- package/dist/chat/interactions/PlanCard.js +10 -3
- package/dist/chat/interactions/QuestionForm.js +7 -3
- package/dist/chat/interactions/card-ui.d.ts +5 -3
- package/dist/chat/interactions/card-ui.js +9 -7
- package/dist/chat/sidebar/SessionSidebar.js +5 -5
- package/dist/chat/sidebar/SidebarFilterMenu.js +3 -1
- package/dist/chat/sidebar/SidebarFrame.d.ts +4 -0
- package/dist/chat/sidebar/SidebarFrame.js +27 -9
- package/dist/chat/sidebar/SidebarGroupHeader.js +1 -1
- package/dist/chat/sidebar/SidebarHostProvider.d.ts +8 -5
- package/dist/chat/sidebar/SidebarHostProvider.js +13 -9
- package/dist/chat/sidebar/SidebarToggleButton.js +7 -3
- package/dist/chat/sidebar/index.d.ts +2 -2
- package/dist/chat/sidebar/session-menu.js +4 -4
- package/dist/chat/sidebar/useSaveViewAsSpace.js +2 -2
- package/dist/chat/testing/contract.js +2 -2
- package/dist/chat/transcript/AuthFailureCard.js +11 -8
- package/dist/chat/transcript/BadgeMenu.js +13 -2
- package/dist/chat/transcript/MermaidDiagram.js +7 -3
- package/dist/chat/transcript/fold.d.ts +4 -0
- package/dist/chat/transcript/fold.js +53 -22
- package/dist/chat/transcript/script-input.d.ts +1 -1
- package/dist/chat/transcript/shell-block.js +8 -4
- package/dist/chat/transcript/useStickToBottom.js +12 -0
- package/dist/components/BrowserSignIn.js +23 -21
- package/dist/components/Form.d.ts +6 -4
- package/dist/components/Form.js +16 -8
- package/dist/components/LoadError.d.ts +4 -2
- package/dist/components/LoadError.js +13 -9
- package/dist/components/Notice.d.ts +29 -0
- package/dist/components/Notice.js +63 -0
- package/dist/components/PanelEmpty.d.ts +1 -1
- package/dist/components/PanelEmpty.js +4 -2
- package/dist/components/Restricted.d.ts +1 -1
- package/dist/components/palette/PaletteList.js +8 -1
- package/dist/components/palette/PalettePanel.js +14 -6
- package/dist/core.css +24 -5
- package/dist/dist/{index-Bq87OcGy.d.ts → index-C6rzc-tt.d.ts} +28 -3
- package/dist/dist/index.d.ts +2 -2
- package/dist/dist/{timeout-B5pO5I5a.d.ts → timeout-Cz9dRF8Q.d.ts} +1 -1
- package/dist/extensions/ExtensionSettingsPage.js +2 -5
- package/dist/extensions/ExtensionSettingsSection.js +5 -4
- package/dist/extensions/ExtensionSettingsSidebar.js +3 -7
- package/dist/extensions/SettingsWireForm.d.ts +1 -7
- package/dist/extensions/SettingsWireForm.js +7 -5
- package/dist/extensions/headless/fixture-host.d.ts +1 -5
- package/dist/extensions/headless/fixture-host.js +2 -5
- package/dist/extensions/headless/host.d.ts +1 -11
- package/dist/extensions/headless/index.d.ts +3 -3
- package/dist/extensions/headless/index.js +6 -6
- package/dist/extensions/headless/select.d.ts +1 -11
- package/dist/extensions/headless/select.js +1 -18
- package/dist/extensions/hooks.js +1 -1
- package/dist/files/EditorColumn.js +13 -2
- package/dist/files/MediaDiff.js +1 -1
- package/dist/files/TreeColumn.js +13 -20
- package/dist/files/useEntryActions.js +1 -1
- package/dist/files/useOpenFiles.js +3 -1
- package/dist/git/BranchMenu.js +6 -4
- package/dist/git/ImportRepoDialog.js +18 -9
- package/dist/git/MoveSessionDialog.js +16 -8
- package/dist/git/RemoteFolderPicker.js +35 -17
- package/dist/git/SyncChip.js +17 -17
- package/dist/git/WherePicker.d.ts +16 -1
- package/dist/git/WherePicker.js +81 -37
- package/dist/git/headless/environment.d.ts +33 -3
- package/dist/git/headless/environment.js +33 -5
- package/dist/git/headless/index.d.ts +2 -2
- package/dist/git/headless/index.js +2 -2
- package/dist/git/headless/labels.d.ts +15 -2
- package/dist/git/headless/labels.js +17 -4
- package/dist/git/useEnvironmentChoices.d.ts +3 -1
- package/dist/git/useEnvironmentChoices.js +7 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/keybindings/KeyCommands.js +1 -1
- package/dist/keybindings/KeybindingsProvider.js +1 -1
- package/dist/keybindings/headless/index.js +2 -2
- package/dist/keybindings/headless/overrides.js +1 -1
- package/dist/labels.d.ts +5 -0
- package/dist/labels.js +5 -0
- package/dist/machines/AddMachineDialog.d.ts +34 -0
- package/dist/machines/AddMachineDialog.js +464 -0
- package/dist/machines/Banners.d.ts +33 -4
- package/dist/machines/Banners.js +64 -3
- package/dist/machines/DaemonMenu.js +27 -4
- package/dist/machines/HostCapabilities.d.ts +1 -3
- package/dist/machines/HostCapabilities.js +24 -45
- package/dist/machines/HostSyncPanel.js +124 -130
- package/dist/machines/HostsSection.d.ts +4 -1
- package/dist/machines/HostsSection.js +30 -7
- package/dist/machines/MachinesExplainer.d.ts +17 -0
- package/dist/machines/MachinesExplainer.js +71 -0
- package/dist/machines/MachinesProvider.d.ts +14 -2
- package/dist/machines/MachinesProvider.js +35 -1
- package/dist/machines/ServerAddedCard.d.ts +31 -0
- package/dist/machines/ServerAddedCard.js +72 -0
- package/dist/machines/ServerCard.js +91 -215
- package/dist/machines/ServerMachinesPanel.d.ts +2 -2
- package/dist/machines/ServerMachinesPanel.js +184 -323
- package/dist/machines/ServerUpdatePanel.js +51 -40
- package/dist/machines/ShareThisComputerForm.d.ts +19 -0
- package/dist/machines/ShareThisComputerForm.js +133 -0
- package/dist/machines/SyncOutcomeBadge.js +1 -1
- package/dist/machines/TokensPanel.d.ts +5 -3
- package/dist/machines/TokensPanel.js +98 -78
- package/dist/machines/headless/fixture-host.d.ts +19 -3
- package/dist/machines/headless/fixture-host.js +43 -6
- package/dist/machines/headless/fixtures.js +4 -6
- package/dist/machines/headless/host.d.ts +40 -19
- package/dist/machines/headless/index.d.ts +3 -3
- package/dist/machines/headless/index.js +3 -3
- package/dist/machines/headless/labels.d.ts +63 -20
- package/dist/machines/headless/labels.js +88 -25
- package/dist/machines/headless/messages.js +8 -0
- package/dist/machines/headless/stores.d.ts +9 -2
- package/dist/machines/headless/stores.js +28 -1
- package/dist/machines/index.d.ts +7 -3
- package/dist/machines/index.js +8 -4
- package/dist/machines/testing/contract.d.ts +15 -3
- package/dist/machines/testing/contract.js +68 -14
- package/dist/motion/grow.d.ts +8 -1
- package/dist/motion/grow.js +10 -4
- package/dist/onboarding/headless/labels.d.ts +13 -0
- package/dist/onboarding/headless/labels.js +8 -0
- package/dist/onboarding/sources/SourceBrowser.js +11 -7
- package/dist/onboarding/steps/ImportStep.js +4 -1
- package/dist/onboarding/steps/ReadyStep.js +9 -2
- package/dist/onboarding/steps/connect/KeyForm.js +6 -2
- package/dist/onboarding/steps/connect/ProviderPanel.js +6 -2
- package/dist/onboarding/steps/connect/ProviderReady.js +25 -20
- package/dist/onboarding/steps/tasks.js +17 -14
- package/dist/palette/app-sources.js +1 -1
- package/dist/server/sse-handler.js +141 -19
- package/dist/session/ArtifactsPanel.js +40 -18
- package/dist/session/PlanTracker.js +13 -8
- package/dist/session/ProjectHome.js +13 -11
- package/dist/session/RemindersPanel.js +35 -17
- package/dist/session/RunningWorkDialog.js +6 -2
- package/dist/session/SecretsPanel.js +29 -10
- package/dist/session/SessionDetailsDialog.d.ts +1 -1
- package/dist/session/SessionDetailsDialog.js +18 -10
- package/dist/session/SideChat.js +10 -7
- package/dist/session/TurnDetailsDialog.js +19 -5
- package/dist/session/UsagePanel.js +10 -4
- package/dist/session/headless/host.d.ts +2 -0
- package/dist/session/headless/index.js +2 -2
- package/dist/session/headless/labels.d.ts +19 -1
- package/dist/session/headless/labels.js +15 -1
- package/dist/session/headless/queue.js +2 -1
- package/dist/session/headless/reminder-labels.d.ts +4 -0
- package/dist/session/headless/reminder-labels.js +4 -0
- package/dist/settings/SettingsRestricted.d.ts +1 -1
- package/dist/settings/SettingsRestricted.js +4 -4
- package/dist/settings/SettingsShell.d.ts +7 -0
- package/dist/settings/SettingsShell.js +6 -1
- package/dist/settings/headless/fixture-performance.d.ts +1 -1
- package/dist/settings/headless/host.d.ts +2 -2
- package/dist/settings/headless/index.js +1 -1
- package/dist/settings/headless/labels.d.ts +3 -3
- package/dist/settings/headless/labels.js +3 -3
- package/dist/settings/headless/performance.d.ts +3 -4
- package/dist/settings/headless/search.d.ts +1 -1
- package/dist/settings/index.d.ts +2 -1
- package/dist/settings/index.js +2 -1
- package/dist/settings/sections/appearance/AppearanceSection.js +2 -2
- package/dist/settings/sections/claude-import/ClaudeImportDialog.js +1 -1
- package/dist/settings/sections/editor/EditorSection.js +8 -5
- package/dist/settings/sections/editor/labels.d.ts +1 -0
- package/dist/settings/sections/editor/labels.js +1 -0
- package/dist/settings/sections/environments/EnvironmentsSection.js +21 -14
- package/dist/settings/sections/environments/labels.d.ts +1 -0
- package/dist/settings/sections/environments/labels.js +2 -1
- package/dist/settings/sections/extensions/ChangeOriginDialog.js +1 -1
- package/dist/settings/sections/extensions/CreateExtensionDialog.js +1 -1
- package/dist/settings/sections/extensions/ExtensionConfigRows.d.ts +1 -3
- package/dist/settings/sections/extensions/ExtensionConfigRows.js +20 -19
- package/dist/settings/sections/extensions/ExtensionOptionsSection.js +2 -1
- package/dist/settings/sections/extensions/ExtensionsSection.js +1 -1
- package/dist/settings/sections/extensions/options-labels.d.ts +2 -1
- package/dist/settings/sections/extensions/options-labels.js +2 -1
- package/dist/settings/sections/host-catalog/HostCatalogSection.js +1 -1
- package/dist/settings/sections/index.d.ts +2 -1
- package/dist/settings/sections/index.js +2 -1
- package/dist/settings/sections/instructions/InstructionsSection.js +1 -1
- package/dist/settings/sections/logs/LogsSection.d.ts +2 -2
- package/dist/settings/sections/logs/LogsSection.js +2 -2
- package/dist/settings/sections/mcp/McpSection.d.ts +1 -1
- package/dist/settings/sections/mcp/McpSection.js +13 -7
- package/dist/settings/sections/mcp/McpServerRow.js +21 -14
- package/dist/settings/sections/mcp/labels.d.ts +8 -2
- package/dist/settings/sections/mcp/labels.js +8 -2
- package/dist/settings/sections/models/ModelRows.js +1 -1
- package/dist/settings/sections/models/NewChatPlaceRow.d.ts +26 -0
- package/dist/settings/sections/models/NewChatPlaceRow.js +78 -0
- package/dist/settings/sections/models/SpacesDefaultsSection.js +15 -3
- package/dist/settings/sections/models/labels.d.ts +7 -0
- package/dist/settings/sections/models/labels.js +7 -0
- package/dist/settings/sections/models/model-test.js +7 -4
- package/dist/settings/sections/performance/PerformanceSection.js +16 -6
- package/dist/settings/sections/performance/labels.d.ts +1 -1
- package/dist/settings/sections/performance/labels.js +1 -1
- package/dist/settings/sections/providers/ProvidersSection.d.ts +1 -1
- package/dist/settings/sections/providers/ProvidersSection.js +15 -8
- package/dist/settings/sections/providers/ServerProvidersSection.d.ts +1 -1
- package/dist/settings/sections/providers/ServerProvidersSection.js +12 -6
- package/dist/settings/sections/providers/labels.d.ts +2 -2
- package/dist/settings/sections/providers/labels.js +2 -2
- package/dist/settings/sections/shared/catalog.js +1 -1
- package/dist/settings/sections/skills/SkillsSection.js +1 -1
- package/dist/settings/testing/performance.contract.js +8 -12
- package/dist/styles.css +32 -3
- package/dist/terminal/HostTerminalSurface.js +17 -7
- package/dist/terminal/TerminalPanel.js +30 -17
- package/dist/terminal/TerminalSurface.js +11 -4
- package/dist/terminal/headless/labels.d.ts +5 -0
- package/dist/terminal/headless/labels.js +5 -0
- package/dist/terminal/headless/store.d.ts +1 -1
- package/dist/terminal/headless/store.js +6 -3
- package/dist/workspace/LayoutBudget.d.ts +5 -1
- package/dist/workspace/LayoutBudget.js +14 -1
- package/dist/workspace/PanelContentView.d.ts +1 -1
- package/dist/workspace/PanelContentView.js +17 -6
- package/dist/workspace/WorkspaceProvider.js +4 -3
- package/dist/workspace/extension-tabs.js +1 -1
- package/dist/workspace/headless/index.js +1 -1
- package/dist/workspace/headless/labels.d.ts +1 -0
- package/dist/workspace/headless/labels.js +1 -0
- package/package.json +3 -3
- package/src/styles/motion.css +8 -0
- package/src/styles/primitives.css +7 -0
|
@@ -3,9 +3,11 @@ import { inheritRowIdentity } from "../transcript/collapse.js";
|
|
|
3
3
|
import { mergeLiveTail } from "./merge.js";
|
|
4
4
|
import { mergePromptPreviews, missingPreviewData } from "./prompt-previews.js";
|
|
5
5
|
import { defaultFrameScheduler } from "./scheduler.js";
|
|
6
|
-
import { discardThinking, finalizeStreamingMarkdownForOwner,
|
|
6
|
+
import { applyHistoryOp, applyHistorySince, discardThinking, finalizeStreamingMarkdownForOwner, readFreshness, reconcileEvents } from "zidane/chat/pure";
|
|
7
7
|
//#region src/chat/headless/streams/store.ts
|
|
8
8
|
const PARENT_OWNER = "parent";
|
|
9
|
+
/** Numberings a window remembers leaving (`_retiredHistoryIds`). */
|
|
10
|
+
const RETIRED_HISTORY_IDS = 8;
|
|
9
11
|
/**
|
|
10
12
|
* Module-level stable empty array — returned by `getEventsSnapshot` when
|
|
11
13
|
* the session has no entry yet. Keeping this reference identical across
|
|
@@ -13,12 +15,39 @@ const PARENT_OWNER = "parent";
|
|
|
13
15
|
* consumer mounts before its session hydrates.
|
|
14
16
|
*/
|
|
15
17
|
const EMPTY_EVENTS = Object.freeze([]);
|
|
18
|
+
/**
|
|
19
|
+
* Finds the pending entry an echo answers. It is the entry with the echo's
|
|
20
|
+
* message id (its `clientMessageId`, else `origin.messageId`). Else it is
|
|
21
|
+
* the first entry with the echo's text and no message id of its own. If the
|
|
22
|
+
* echo carries no message id, the first entry with its text matches. Returns
|
|
23
|
+
* -1 for a genuine remote send.
|
|
24
|
+
*/
|
|
25
|
+
function pendingEchoIndex(pending, echo) {
|
|
26
|
+
const messageId = echo.clientMessageId ?? echo.origin?.messageId;
|
|
27
|
+
if (messageId !== void 0) {
|
|
28
|
+
const byId = pending.findIndex((p) => p.clientMessageId === messageId);
|
|
29
|
+
if (byId !== -1) return byId;
|
|
30
|
+
return pending.findIndex((p) => p.clientMessageId === void 0 && p.text === echo.text);
|
|
31
|
+
}
|
|
32
|
+
return pending.findIndex((p) => p.text === echo.text);
|
|
33
|
+
}
|
|
16
34
|
/** Page-state snapshot for a session with no hydrated page — stable identity. */
|
|
17
35
|
const NO_PAGE = Object.freeze({
|
|
18
36
|
firstSeq: 0,
|
|
19
37
|
hasMore: false,
|
|
20
38
|
loadingEarlier: false
|
|
21
39
|
});
|
|
40
|
+
/** Builds a window's page state from a page it took. It holds the cursor and the history position of the cursor (the page's, else `fallback`). */
|
|
41
|
+
function pageState(page, loadingEarlier, fallback) {
|
|
42
|
+
const at = page.pos !== void 0 ? page : fallback;
|
|
43
|
+
return {
|
|
44
|
+
firstSeq: page.firstSeq,
|
|
45
|
+
hasMore: page.hasMore,
|
|
46
|
+
loadingEarlier,
|
|
47
|
+
...at?.pos !== void 0 ? { pos: at.pos } : {},
|
|
48
|
+
...at?.pos !== void 0 && at.historyId !== void 0 ? { historyId: at.historyId } : {}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
22
51
|
/**
|
|
23
52
|
* Markdown merge options by default. No 64 KB segmenting: a reloaded
|
|
24
53
|
* transcript shows each message whole (the renderer chunks long text
|
|
@@ -95,15 +124,17 @@ var SessionStreamStore = class {
|
|
|
95
124
|
_runSeq = /* @__PURE__ */ new Map();
|
|
96
125
|
_pages = /* @__PURE__ */ new Map();
|
|
97
126
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
127
|
+
* User prompts THIS window appended optimistically that still await their
|
|
128
|
+
* host echo. The host stamps `echo: true` on the broadcast of the sender's
|
|
129
|
+
* own prompt (send / steer paths) for EVERY peer. It cannot know which
|
|
130
|
+
* window sent the prompt, so the dedupe lives here. One pending entry
|
|
131
|
+
* consumes one echo and keeps the local copy, which carries refs and
|
|
132
|
+
* attachments that the canonical event does not.
|
|
104
133
|
* Echo-tagged prompts with NO pending match are genuine remote sends
|
|
105
134
|
* (another window, a daemon-drained queued prompt) and must render.
|
|
106
|
-
*
|
|
135
|
+
* The echo matches by the sender's message id when both carry one, else
|
|
136
|
+
* by text, and gives the local row its turn id. Leftovers (failed sends)
|
|
137
|
+
* are cleared at `run:end`.
|
|
107
138
|
*/
|
|
108
139
|
_pendingEcho = /* @__PURE__ */ new Map();
|
|
109
140
|
/**
|
|
@@ -111,6 +142,39 @@ var SessionStreamStore = class {
|
|
|
111
142
|
* the prompt shows up in the transcript (see `prompt-previews.ts`).
|
|
112
143
|
*/
|
|
113
144
|
_promptPreviews = /* @__PURE__ */ new Map();
|
|
145
|
+
/** The history position each window applied last (`applyHistory`). It is the window's bookmark in the session's history. */
|
|
146
|
+
_historyPos = /* @__PURE__ */ new Map();
|
|
147
|
+
/** The numbering of each window's `_historyPos` (`HistoryPosition.historyId`), when known. */
|
|
148
|
+
_historyId = /* @__PURE__ */ new Map();
|
|
149
|
+
/** Windows to fetch again when their run ends (`takeRefetchDue`, `markRefetchDue`). */
|
|
150
|
+
_refetchDue = /* @__PURE__ */ new Set();
|
|
151
|
+
/**
|
|
152
|
+
* Windows whose rows are behind their history position. A write asked for a
|
|
153
|
+
* tail read that has not landed yet (in flight, failed, or waiting for the
|
|
154
|
+
* run's end). The position stays the newest write seen, so a read older than
|
|
155
|
+
* it is stale. But it is not a bookmark. The reconnect ladder reads the tail,
|
|
156
|
+
* and a later write also reads the tail instead of applying in place.
|
|
157
|
+
*/
|
|
158
|
+
_tailDue = /* @__PURE__ */ new Set();
|
|
159
|
+
/** Per window, the numberings it left for another numbering. A read in one of them is older than the window. */
|
|
160
|
+
_retiredHistoryIds = /* @__PURE__ */ new Map();
|
|
161
|
+
/**
|
|
162
|
+
* Windows that saw their current run start (`run:start`, live or replayed).
|
|
163
|
+
* If a run ends in a hydrated window that never saw it start, the window
|
|
164
|
+
* missed the run's first rows. This happens after a drop that main could not
|
|
165
|
+
* replay, or when the window opened mid-run. The rows it read meanwhile also
|
|
166
|
+
* sit below the rows it streamed since. So it reads its tail at the run's
|
|
167
|
+
* end (`takeRefetchDue`).
|
|
168
|
+
*/
|
|
169
|
+
_runStarted = /* @__PURE__ */ new Set();
|
|
170
|
+
/**
|
|
171
|
+
* Windows that streamed rows since their last run boundary (a run's start or
|
|
172
|
+
* end, a page read). With `_running`, it tells a run whose start went by
|
|
173
|
+
* apart from a send that the host refused before it started. A refused send
|
|
174
|
+
* streams nothing, and its error row lives only in this store. Reading the
|
|
175
|
+
* tail drops that row.
|
|
176
|
+
*/
|
|
177
|
+
_runActivity = /* @__PURE__ */ new Set();
|
|
114
178
|
_listenersBySession = /* @__PURE__ */ new Map();
|
|
115
179
|
_listenersForHas = /* @__PURE__ */ new Set();
|
|
116
180
|
/**
|
|
@@ -242,27 +306,178 @@ var SessionStreamStore = class {
|
|
|
242
306
|
return this._pages.get(sessionId) ?? NO_PAGE;
|
|
243
307
|
}
|
|
244
308
|
/**
|
|
245
|
-
* Hydrate one replay page as the session's full window
|
|
246
|
-
* `loadEvents`
|
|
247
|
-
* swap and the page-state swap.
|
|
309
|
+
* Hydrate one replay page as the session's full window (the
|
|
310
|
+
* `loadEvents` tail page path). One notify covers both the events
|
|
311
|
+
* swap and the page-state swap. Returns `false` and changes nothing
|
|
312
|
+
* when the page is older than a write the window applied since.
|
|
248
313
|
*
|
|
249
314
|
* @param sessionId - The session.
|
|
250
315
|
* @param page - The persisted page.
|
|
251
316
|
*/
|
|
252
317
|
setEventsPage(sessionId, page) {
|
|
318
|
+
if (this._freshness(sessionId, page) === "stale") return false;
|
|
319
|
+
if (page.pos !== void 0) this._setHistoryPos(sessionId, page.pos, page.historyId);
|
|
320
|
+
this._tailDue.delete(sessionId);
|
|
253
321
|
const had = this._events.has(sessionId);
|
|
254
322
|
const wasHydrated = this._pages.has(sessionId);
|
|
255
323
|
const prior = this._events.get(sessionId) ?? [];
|
|
256
|
-
const next = wasHydrated ? reconcileEvents(prior, page.events) : mergeLiveTail(prior, page.events);
|
|
324
|
+
const next = wasHydrated ? reconcileEvents(prior, page.events) : mergeLiveTail(this._withoutSavedLocalPrompts(sessionId, prior, page.events), page.events);
|
|
257
325
|
inheritRowIdentity(prior, next);
|
|
258
326
|
this._events.set(sessionId, next);
|
|
259
|
-
this._pages.set(sessionId,
|
|
260
|
-
|
|
261
|
-
hasMore: page.hasMore,
|
|
262
|
-
loadingEarlier: false
|
|
263
|
-
});
|
|
327
|
+
this._pages.set(sessionId, pageState(page, false));
|
|
328
|
+
this._runActivity.delete(sessionId);
|
|
264
329
|
this._notifySession(sessionId);
|
|
265
330
|
if (!had || !wasHydrated) this._notifyHas();
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Applies one history write (`history:changed`) to the session's window.
|
|
335
|
+
* It uses the shared rule (`applyHistoryOp`, `zidane/chat/pure`). A
|
|
336
|
+
* streamed append changes nothing. An append that never streamed adds the
|
|
337
|
+
* rows it carries. A rewrite or a missed write asks for a fetch.
|
|
338
|
+
*
|
|
339
|
+
* Returns `true` when the caller must fetch the session's tail now and
|
|
340
|
+
* replace the window with it (`setEventsPage`). A window whose run streams
|
|
341
|
+
* fetches at the run's end instead (`takeRefetchDue`), and a window never
|
|
342
|
+
* hydrated is left to its first read.
|
|
343
|
+
*
|
|
344
|
+
* @param sessionId - The session.
|
|
345
|
+
* @param change - The write, as the signal carries it.
|
|
346
|
+
*/
|
|
347
|
+
applyHistory(sessionId, change) {
|
|
348
|
+
const events = this._events.get(sessionId) ?? [];
|
|
349
|
+
const context = this._historyContext(sessionId);
|
|
350
|
+
const result = applyHistoryOp(events, change, context);
|
|
351
|
+
return this._applyHistoryResult(sessionId, events, result, context);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Applies a shared history rule's answer to the window. Its position moves
|
|
355
|
+
* first. Then its rows change, or it asks for a tail read. It returns `true`
|
|
356
|
+
* for a read now. While the run streams, the read waits for the run's end.
|
|
357
|
+
* A window whose rows are behind (`_tailDue`) reads its tail on any write
|
|
358
|
+
* that moves it. It does not apply the write to rows that miss the earlier one.
|
|
359
|
+
*/
|
|
360
|
+
_applyHistoryResult(sessionId, events, result, context) {
|
|
361
|
+
this._setHistoryPos(sessionId, result.pos, result.historyId);
|
|
362
|
+
if (!this._pages.has(sessionId)) return false;
|
|
363
|
+
const moved = result.pos !== context.pos || result.historyId !== context.historyId;
|
|
364
|
+
if ("refetch" in result || moved && this._tailDue.has(sessionId)) {
|
|
365
|
+
this._tailDue.add(sessionId);
|
|
366
|
+
if (!this._running.get(sessionId)) return true;
|
|
367
|
+
this._refetchDue.add(sessionId);
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
if (result.rows !== events) {
|
|
371
|
+
this._events.set(sessionId, result.rows);
|
|
372
|
+
this._notifySession(sessionId);
|
|
373
|
+
}
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Applies the reconnect ladder's second step to the session's window. That
|
|
378
|
+
* step brings the rows of the turns appended after its position
|
|
379
|
+
* (`sessions.historySince`, the shared `applyHistorySince`). Returns `true`
|
|
380
|
+
* when the caller must fetch the tail now (as {@link applyHistory} does).
|
|
381
|
+
*
|
|
382
|
+
* @param sessionId - The session.
|
|
383
|
+
* @param since - The rows and the position they bring the window to.
|
|
384
|
+
*/
|
|
385
|
+
applyHistorySince(sessionId, since) {
|
|
386
|
+
const events = this._events.get(sessionId) ?? [];
|
|
387
|
+
const context = this._historyContext(sessionId);
|
|
388
|
+
const result = applyHistorySince(events, since, context);
|
|
389
|
+
return this._applyHistoryResult(sessionId, events, result, context);
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Moves the window to `pos` after an adapter's own hydrate replaced it with
|
|
393
|
+
* a tail read at `pos`. Returns `stale` if the read is older than a write
|
|
394
|
+
* the window applied since. The adapter then reads it again.
|
|
395
|
+
*
|
|
396
|
+
* @param sessionId - The session.
|
|
397
|
+
* @param pos - The read's position, when the host named one.
|
|
398
|
+
* @param historyId - The numbering `pos` counts in, when the host named one.
|
|
399
|
+
*/
|
|
400
|
+
adoptHistoryPos(sessionId, pos, historyId) {
|
|
401
|
+
const read = {
|
|
402
|
+
...pos !== void 0 ? { pos } : {},
|
|
403
|
+
...historyId !== void 0 ? { historyId } : {}
|
|
404
|
+
};
|
|
405
|
+
if (this._freshness(sessionId, read) === "stale") return "stale";
|
|
406
|
+
if (pos !== void 0) this._setHistoryPos(sessionId, pos, historyId);
|
|
407
|
+
this._tailDue.delete(sessionId);
|
|
408
|
+
return "fresh";
|
|
409
|
+
}
|
|
410
|
+
/** `readFreshness` against what the window applied, and the numberings it left. */
|
|
411
|
+
_freshness(sessionId, read) {
|
|
412
|
+
return readFreshness(read, this._historyPos.get(sessionId), this._historyId.get(sessionId), this._retiredHistoryIds.get(sessionId));
|
|
413
|
+
}
|
|
414
|
+
/** What the window applied last, for the shared history rules. */
|
|
415
|
+
_historyContext(sessionId) {
|
|
416
|
+
const pos = this._historyPos.get(sessionId);
|
|
417
|
+
const historyId = this._historyId.get(sessionId);
|
|
418
|
+
return {
|
|
419
|
+
...pos !== void 0 ? { pos } : {},
|
|
420
|
+
...historyId !== void 0 ? { historyId } : {}
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
/** Sets the window at `pos` of numbering `historyId`. If the numbering is unknown, none is kept. */
|
|
424
|
+
_setHistoryPos(sessionId, pos, historyId) {
|
|
425
|
+
this._historyPos.set(sessionId, pos);
|
|
426
|
+
const left = this._historyId.get(sessionId);
|
|
427
|
+
if (left !== void 0 && historyId !== void 0 && historyId !== left) {
|
|
428
|
+
const retired = this._retiredHistoryIds.get(sessionId) ?? /* @__PURE__ */ new Set();
|
|
429
|
+
retired.delete(historyId);
|
|
430
|
+
retired.add(left);
|
|
431
|
+
if (retired.size > RETIRED_HISTORY_IDS) retired.delete(retired.values().next().value);
|
|
432
|
+
this._retiredHistoryIds.set(sessionId, retired);
|
|
433
|
+
}
|
|
434
|
+
if (historyId !== void 0) this._historyId.set(sessionId, historyId);
|
|
435
|
+
else this._historyId.delete(sessionId);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Whether the session's window must be fetched again now that its run ended
|
|
439
|
+
* (see `applyHistory`, `markRefetchDue`). Clears the flag.
|
|
440
|
+
*
|
|
441
|
+
* @param sessionId - The session.
|
|
442
|
+
*/
|
|
443
|
+
takeRefetchDue(sessionId) {
|
|
444
|
+
if (this._running.get(sessionId)) return false;
|
|
445
|
+
return this._refetchDue.delete(sessionId);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Asks for the session's window to be read again at its run's end (`takeRefetchDue`). It is for a read dropped
|
|
449
|
+
* because a run streamed when it came back, or for a read that kept coming back older than the window.
|
|
450
|
+
*
|
|
451
|
+
* @param sessionId - The session.
|
|
452
|
+
*/
|
|
453
|
+
markRefetchDue(sessionId) {
|
|
454
|
+
this._refetchDue.add(sessionId);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Whether the session's rows are behind its history position. This is so
|
|
458
|
+
* when a write asked for a tail read that has not landed (in flight, failed,
|
|
459
|
+
* or waiting for the run's end). The reconnect ladder then reads the tail.
|
|
460
|
+
*
|
|
461
|
+
* @param sessionId - The session.
|
|
462
|
+
*/
|
|
463
|
+
isTailDue(sessionId) {
|
|
464
|
+
return this._tailDue.has(sessionId);
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* The history position the session's window applied last. It is `undefined` before its first `history:changed` or positioned page.
|
|
468
|
+
*
|
|
469
|
+
* @param sessionId - The session.
|
|
470
|
+
*/
|
|
471
|
+
getHistoryPosSnapshot(sessionId) {
|
|
472
|
+
return this._historyPos.get(sessionId);
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* The numbering of {@link getHistoryPosSnapshot}'s position, when known.
|
|
476
|
+
*
|
|
477
|
+
* @param sessionId - The session.
|
|
478
|
+
*/
|
|
479
|
+
getHistoryIdSnapshot(sessionId) {
|
|
480
|
+
return this._historyId.get(sessionId);
|
|
266
481
|
}
|
|
267
482
|
/**
|
|
268
483
|
* Splice an OLDER page in front of the hydrated window (lazy scrollback).
|
|
@@ -274,11 +489,7 @@ var SessionStreamStore = class {
|
|
|
274
489
|
const existing = this._events.get(sessionId) ?? [];
|
|
275
490
|
const wasHydrated = this._pages.has(sessionId);
|
|
276
491
|
this._events.set(sessionId, [...page.events, ...existing]);
|
|
277
|
-
this._pages.set(sessionId,
|
|
278
|
-
firstSeq: page.firstSeq,
|
|
279
|
-
hasMore: page.hasMore,
|
|
280
|
-
loadingEarlier: false
|
|
281
|
-
});
|
|
492
|
+
this._pages.set(sessionId, pageState(page, false, this._pages.get(sessionId)));
|
|
282
493
|
this._notifySession(sessionId);
|
|
283
494
|
if (!wasHydrated) this._notifyHas();
|
|
284
495
|
}
|
|
@@ -356,6 +567,13 @@ var SessionStreamStore = class {
|
|
|
356
567
|
this._retry.clear();
|
|
357
568
|
this._systemMd.clear();
|
|
358
569
|
this._pages.clear();
|
|
570
|
+
this._historyPos.clear();
|
|
571
|
+
this._historyId.clear();
|
|
572
|
+
this._refetchDue.clear();
|
|
573
|
+
this._tailDue.clear();
|
|
574
|
+
this._retiredHistoryIds.clear();
|
|
575
|
+
this._runStarted.clear();
|
|
576
|
+
this._runActivity.clear();
|
|
359
577
|
this._pendingEcho.clear();
|
|
360
578
|
for (const sessionId of sessionIds) this._notifySession(sessionId);
|
|
361
579
|
if (had) this._notifyHas();
|
|
@@ -374,6 +592,13 @@ var SessionStreamStore = class {
|
|
|
374
592
|
this._retry.delete(sessionId);
|
|
375
593
|
this._systemMd.delete(sessionId);
|
|
376
594
|
this._pages.delete(sessionId);
|
|
595
|
+
this._historyPos.delete(sessionId);
|
|
596
|
+
this._historyId.delete(sessionId);
|
|
597
|
+
this._refetchDue.delete(sessionId);
|
|
598
|
+
this._tailDue.delete(sessionId);
|
|
599
|
+
this._retiredHistoryIds.delete(sessionId);
|
|
600
|
+
this._runStarted.delete(sessionId);
|
|
601
|
+
this._runActivity.delete(sessionId);
|
|
377
602
|
this._notifySession(sessionId);
|
|
378
603
|
if (!had || wasHydrated) this._notifyHas();
|
|
379
604
|
}
|
|
@@ -403,6 +628,13 @@ var SessionStreamStore = class {
|
|
|
403
628
|
this._fallback.delete(sessionId);
|
|
404
629
|
this._retry.delete(sessionId);
|
|
405
630
|
this._pages.delete(sessionId);
|
|
631
|
+
this._historyPos.delete(sessionId);
|
|
632
|
+
this._historyId.delete(sessionId);
|
|
633
|
+
this._refetchDue.delete(sessionId);
|
|
634
|
+
this._tailDue.delete(sessionId);
|
|
635
|
+
this._retiredHistoryIds.delete(sessionId);
|
|
636
|
+
this._runStarted.delete(sessionId);
|
|
637
|
+
this._runActivity.delete(sessionId);
|
|
406
638
|
this._notifySession(sessionId);
|
|
407
639
|
dropped = true;
|
|
408
640
|
}
|
|
@@ -425,6 +657,13 @@ var SessionStreamStore = class {
|
|
|
425
657
|
this._pages.delete(sessionId);
|
|
426
658
|
this._pendingEcho.delete(sessionId);
|
|
427
659
|
this._promptPreviews.delete(sessionId);
|
|
660
|
+
this._historyPos.delete(sessionId);
|
|
661
|
+
this._historyId.delete(sessionId);
|
|
662
|
+
this._refetchDue.delete(sessionId);
|
|
663
|
+
this._tailDue.delete(sessionId);
|
|
664
|
+
this._retiredHistoryIds.delete(sessionId);
|
|
665
|
+
this._runStarted.delete(sessionId);
|
|
666
|
+
this._runActivity.delete(sessionId);
|
|
428
667
|
if (had) {
|
|
429
668
|
this._notifySession(sessionId);
|
|
430
669
|
this._notifyHas();
|
|
@@ -493,8 +732,9 @@ var SessionStreamStore = class {
|
|
|
493
732
|
* @param text - The prompt text.
|
|
494
733
|
* @param refs - The completions the prompt used (skills, files), for its chips.
|
|
495
734
|
* @param rawAttachments - The prompt's attachments. Omitted for a pushed queued prompt, which takes the previews this client remembered for it.
|
|
735
|
+
* @param clientMessageId - The id the send gave the message (`SendOptions.clientMessageId`). The store matches the echo by it.
|
|
496
736
|
*/
|
|
497
|
-
appendUserPrompt(sessionId, text, refs, rawAttachments) {
|
|
737
|
+
appendUserPrompt(sessionId, text, refs, rawAttachments, clientMessageId) {
|
|
498
738
|
const had = this._events.has(sessionId);
|
|
499
739
|
const events = this._events.get(sessionId)?.slice() ?? [];
|
|
500
740
|
const attachments = rawAttachments === void 0 || missingPreviewData(rawAttachments) ? mergePromptPreviews(rawAttachments, this.takePromptPreviews(sessionId, text)) : rawAttachments;
|
|
@@ -506,7 +746,11 @@ var SessionStreamStore = class {
|
|
|
506
746
|
};
|
|
507
747
|
events.push(event);
|
|
508
748
|
const pending = this._pendingEcho.get(sessionId) ?? [];
|
|
509
|
-
pending.push(
|
|
749
|
+
pending.push({
|
|
750
|
+
text,
|
|
751
|
+
...clientMessageId !== void 0 ? { clientMessageId } : {},
|
|
752
|
+
event
|
|
753
|
+
});
|
|
510
754
|
this._pendingEcho.set(sessionId, pending);
|
|
511
755
|
this._events.set(sessionId, events);
|
|
512
756
|
this._notifySession(sessionId);
|
|
@@ -522,7 +766,7 @@ var SessionStreamStore = class {
|
|
|
522
766
|
*/
|
|
523
767
|
dropPendingEcho(sessionId, text) {
|
|
524
768
|
const pending = this._pendingEcho.get(sessionId);
|
|
525
|
-
const index = pending?.
|
|
769
|
+
const index = pending?.findIndex((p) => p.text === text) ?? -1;
|
|
526
770
|
if (pending && index !== -1) pending.splice(index, 1);
|
|
527
771
|
}
|
|
528
772
|
/**
|
|
@@ -592,6 +836,8 @@ var SessionStreamStore = class {
|
|
|
592
836
|
this._notifyHas();
|
|
593
837
|
}
|
|
594
838
|
this._running.set(signal.sessionId, true);
|
|
839
|
+
this._runStarted.add(signal.sessionId);
|
|
840
|
+
this._runActivity.delete(signal.sessionId);
|
|
595
841
|
this._runSeq.set(signal.sessionId, (this._runSeq.get(signal.sessionId) ?? 0) + 1);
|
|
596
842
|
this._fallback.delete(signal.sessionId);
|
|
597
843
|
this._notifySession(signal.sessionId);
|
|
@@ -606,8 +852,12 @@ var SessionStreamStore = class {
|
|
|
606
852
|
...signal.detail ? { detail: signal.detail } : {}
|
|
607
853
|
}];
|
|
608
854
|
const had = this._events.has(signal.sessionId);
|
|
855
|
+
const wasRunning = this._running.get(signal.sessionId) === true;
|
|
609
856
|
this._events.set(signal.sessionId, next);
|
|
610
857
|
this._running.set(signal.sessionId, false);
|
|
858
|
+
const sawStart = this._runStarted.delete(signal.sessionId);
|
|
859
|
+
const streamed = this._runActivity.delete(signal.sessionId);
|
|
860
|
+
if (!sawStart && (wasRunning || streamed) && this._pages.has(signal.sessionId)) this._refetchDue.add(signal.sessionId);
|
|
611
861
|
this._retry.delete(signal.sessionId);
|
|
612
862
|
this._pendingEcho.delete(signal.sessionId);
|
|
613
863
|
this._notifySession(signal.sessionId);
|
|
@@ -624,11 +874,13 @@ var SessionStreamStore = class {
|
|
|
624
874
|
return;
|
|
625
875
|
}
|
|
626
876
|
case "event": {
|
|
877
|
+
if (signal.event.kind === "separator" && signal.echo && this._separateLocalPrompt(signal.sessionId)) return;
|
|
627
878
|
if (signal.event.kind === "user-prompt" && signal.echo) {
|
|
628
879
|
const pending = this._pendingEcho.get(signal.sessionId);
|
|
629
|
-
const index = pending
|
|
880
|
+
const index = pending ? pendingEchoIndex(pending, signal.event) : -1;
|
|
630
881
|
if (pending && index !== -1) {
|
|
631
|
-
pending.splice(index, 1);
|
|
882
|
+
const [local] = pending.splice(index, 1);
|
|
883
|
+
if (signal.event.turnId !== void 0) this._bindLocalPrompt(signal.sessionId, local.event, signal.event.turnId);
|
|
632
884
|
return;
|
|
633
885
|
}
|
|
634
886
|
}
|
|
@@ -643,6 +895,7 @@ var SessionStreamStore = class {
|
|
|
643
895
|
const had = this._events.has(signal.sessionId);
|
|
644
896
|
const prior = this._events.get(signal.sessionId) ?? [];
|
|
645
897
|
this._events.set(signal.sessionId, this._append(prior, event));
|
|
898
|
+
this._runActivity.add(signal.sessionId);
|
|
646
899
|
if (this._batch) this._notifySoon(signal.sessionId);
|
|
647
900
|
else this._notifySession(signal.sessionId);
|
|
648
901
|
if (!had) this._notifyHas();
|
|
@@ -662,17 +915,6 @@ var SessionStreamStore = class {
|
|
|
662
915
|
if (signal.discardTurnId) this._discardThinking(signal.sessionId, signal.source, signal.discardTurnId);
|
|
663
916
|
this._notifySession(signal.sessionId);
|
|
664
917
|
return;
|
|
665
|
-
case "prompt-turns": {
|
|
666
|
-
const events = this._events.get(signal.sessionId);
|
|
667
|
-
if (!events || events.length === 0) return;
|
|
668
|
-
const next = retagUserPromptEventsFromRefs(events, signal.refs);
|
|
669
|
-
if (next !== events) {
|
|
670
|
-
inheritRowIdentity(events, next);
|
|
671
|
-
this._events.set(signal.sessionId, next);
|
|
672
|
-
this._notifySession(signal.sessionId);
|
|
673
|
-
}
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
918
|
case "stream:retry:cleared":
|
|
677
919
|
if (this._retry.get(signal.sessionId)?.source === signal.source) {
|
|
678
920
|
this._retry.delete(signal.sessionId);
|
|
@@ -742,6 +984,60 @@ var SessionStreamStore = class {
|
|
|
742
984
|
this._pendingNotify.clear();
|
|
743
985
|
for (const id of ids) this._notifySession(id);
|
|
744
986
|
}
|
|
987
|
+
/**
|
|
988
|
+
* Returns `live` without the prompts that this client appended and that the
|
|
989
|
+
* page already holds. These prompts still await their echo. They match by the
|
|
990
|
+
* send's message id, which the saved prompt carries (`origin.messageId`).
|
|
991
|
+
* Their pending entries stay, so the echo is still consumed. It binds
|
|
992
|
+
* nothing, because the row is gone.
|
|
993
|
+
*/
|
|
994
|
+
_withoutSavedLocalPrompts(sessionId, live, page) {
|
|
995
|
+
const pending = this._pendingEcho.get(sessionId);
|
|
996
|
+
if (!pending?.length) return live;
|
|
997
|
+
const saved = /* @__PURE__ */ new Set();
|
|
998
|
+
for (const event of page) {
|
|
999
|
+
const messageId = event.kind === "user-prompt" ? event.clientMessageId ?? event.origin?.messageId : void 0;
|
|
1000
|
+
if (messageId !== void 0) saved.add(messageId);
|
|
1001
|
+
}
|
|
1002
|
+
const superseded = new Set(pending.flatMap((p) => p.clientMessageId !== void 0 && saved.has(p.clientMessageId) ? [p.event] : []));
|
|
1003
|
+
return superseded.size === 0 ? live : live.filter((event) => !superseded.has(event));
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Puts the host's exchange separator before the oldest prompt that this
|
|
1007
|
+
* client appended and whose echo has not come yet (`appendUserPrompt`).
|
|
1008
|
+
* Returns false when no such prompt is on show. The separator then appends
|
|
1009
|
+
* like any event.
|
|
1010
|
+
*/
|
|
1011
|
+
_separateLocalPrompt(sessionId) {
|
|
1012
|
+
const local = this._pendingEcho.get(sessionId)?.[0]?.event;
|
|
1013
|
+
const events = this._events.get(sessionId);
|
|
1014
|
+
const at = local && events ? events.indexOf(local) : -1;
|
|
1015
|
+
if (!events || at === -1) return false;
|
|
1016
|
+
if (events[at - 1]?.kind !== "separator") {
|
|
1017
|
+
const next = events.slice();
|
|
1018
|
+
next.splice(at, 0, {
|
|
1019
|
+
kind: "separator",
|
|
1020
|
+
text: ""
|
|
1021
|
+
});
|
|
1022
|
+
this._events.set(sessionId, next);
|
|
1023
|
+
this._notifySession(sessionId);
|
|
1024
|
+
}
|
|
1025
|
+
return true;
|
|
1026
|
+
}
|
|
1027
|
+
/** Gives this client's optimistic prompt row the turn id its echo carries. A row that a reload replaced is left alone. */
|
|
1028
|
+
_bindLocalPrompt(sessionId, local, turnId) {
|
|
1029
|
+
const events = this._events.get(sessionId);
|
|
1030
|
+
const at = events?.indexOf(local) ?? -1;
|
|
1031
|
+
if (!events || at === -1) return;
|
|
1032
|
+
const next = events.slice();
|
|
1033
|
+
next[at] = {
|
|
1034
|
+
...local,
|
|
1035
|
+
turnId
|
|
1036
|
+
};
|
|
1037
|
+
inheritRowIdentity(events, next);
|
|
1038
|
+
this._events.set(sessionId, next);
|
|
1039
|
+
this._notifySession(sessionId);
|
|
1040
|
+
}
|
|
745
1041
|
/** Drop a stalled attempt's reasoning lane: the retry (or next model) streams its own, and the saved turn never holds it. */
|
|
746
1042
|
_discardThinking(sessionId, source, turnId) {
|
|
747
1043
|
const events = this._events.get(sessionId);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ChatEvent } from "../host.js";
|
|
2
|
-
import { PromptTurnRef } from "zidane/chat/pure";
|
|
3
2
|
import { StreamEvent, SystemMdFile } from "zidane/chat";
|
|
4
3
|
//#region src/chat/headless/streams/types.d.ts
|
|
5
4
|
/** The model serving a run after it fell back from the one picked. */
|
|
@@ -31,6 +30,10 @@ interface SessionPageState {
|
|
|
31
30
|
hasMore: boolean;
|
|
32
31
|
/** Whether a fetch of the previous page is in flight. */
|
|
33
32
|
loadingEarlier: boolean;
|
|
33
|
+
/** The history position at which the cursor (`firstSeq`) was taken. An older page whose `floor` is past it is of another history. */
|
|
34
|
+
pos?: number;
|
|
35
|
+
/** The numbering `pos` counts in. An older page of another numbering is of another history. */
|
|
36
|
+
historyId?: string;
|
|
34
37
|
}
|
|
35
38
|
/** One page of a session's persisted transcript (the tail, or the page before a sequence number). */
|
|
36
39
|
interface SessionStreamPage {
|
|
@@ -40,6 +43,12 @@ interface SessionStreamPage {
|
|
|
40
43
|
firstSeq: number;
|
|
41
44
|
/** Whether older turns exist before the page. */
|
|
42
45
|
hasMore: boolean;
|
|
46
|
+
/** The history position the page was read at (`SessionEventsPage.pos`), when the host named one. */
|
|
47
|
+
pos?: number;
|
|
48
|
+
/** The session's floor when the page was read (set with `pos`). */
|
|
49
|
+
floor?: number;
|
|
50
|
+
/** The numbering `pos` counts in (`HistoryPosition.historyId`). */
|
|
51
|
+
historyId?: string;
|
|
43
52
|
}
|
|
44
53
|
/**
|
|
45
54
|
* The live signals the session stream store reduces: zidane's host signals
|
|
@@ -101,12 +110,6 @@ type SessionStreamSignal<K extends string = string> =
|
|
|
101
110
|
sessionId: K;
|
|
102
111
|
source: string;
|
|
103
112
|
} |
|
|
104
|
-
/** Prompt turns just persisted: binds them to their live `user-prompt` rows. */
|
|
105
|
-
{
|
|
106
|
-
kind: 'prompt-turns';
|
|
107
|
-
sessionId: K;
|
|
108
|
-
refs: readonly PromptTurnRef[];
|
|
109
|
-
} |
|
|
110
113
|
/** The `SYSTEM.md` override the session's prompt was composed with, or `null`. */
|
|
111
114
|
{
|
|
112
115
|
kind: 'system-md';
|
|
@@ -32,6 +32,7 @@ declare const TRANSCRIPT_LABELS: {
|
|
|
32
32
|
interactionAnsweredBy: (who: string) => string;
|
|
33
33
|
badgePathUnavailable: string;
|
|
34
34
|
badgeNoComposer: string;
|
|
35
|
+
badgeActionFailed: string;
|
|
35
36
|
badgeCopied: string;
|
|
36
37
|
badgeOpenIn: (app: string) => string;
|
|
37
38
|
badgeOpenInBrowserPane: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorMessage } from "../../components/report-error.js";
|
|
1
2
|
import { useChatLabels } from "../useChatLabels.js";
|
|
2
3
|
import { useTranscriptRenderers } from "../transcript/renderers.js";
|
|
3
4
|
import { BTN, BTN_DANGER, BTN_PRIMARY, CardError, INPUT, useAutoFocus } from "./card-ui.js";
|
|
@@ -43,7 +44,7 @@ function PlanCard({ request, autoFocus = false, onAnswer, Markdown, className, s
|
|
|
43
44
|
...comment.trim() ? { comment: comment.trim() } : {}
|
|
44
45
|
});
|
|
45
46
|
} catch (err) {
|
|
46
|
-
setError(
|
|
47
|
+
setError(errorMessage(err));
|
|
47
48
|
setBusy(false);
|
|
48
49
|
}
|
|
49
50
|
};
|
|
@@ -82,7 +83,10 @@ function PlanCard({ request, autoFocus = false, onAnswer, Markdown, className, s
|
|
|
82
83
|
className: BTN,
|
|
83
84
|
children: labels.back
|
|
84
85
|
}),
|
|
85
|
-
/* @__PURE__ */ jsx(CardError, {
|
|
86
|
+
/* @__PURE__ */ jsx(CardError, {
|
|
87
|
+
error: error && labels.answerSendFailed,
|
|
88
|
+
detail: error
|
|
89
|
+
}),
|
|
86
90
|
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
87
91
|
/* @__PURE__ */ jsx("button", {
|
|
88
92
|
type: "button",
|
|
@@ -110,7 +114,10 @@ function PlanCard({ request, autoFocus = false, onAnswer, Markdown, className, s
|
|
|
110
114
|
className: BTN_DANGER,
|
|
111
115
|
children: labels.planReject
|
|
112
116
|
}),
|
|
113
|
-
/* @__PURE__ */ jsx(CardError, {
|
|
117
|
+
/* @__PURE__ */ jsx(CardError, {
|
|
118
|
+
error: error && labels.answerSendFailed,
|
|
119
|
+
detail: error
|
|
120
|
+
}),
|
|
114
121
|
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
115
122
|
/* @__PURE__ */ jsx("button", {
|
|
116
123
|
type: "button",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorMessage } from "../../components/report-error.js";
|
|
1
2
|
import { useChatLabels } from "../useChatLabels.js";
|
|
2
3
|
import { useTranscriptRenderers } from "../transcript/renderers.js";
|
|
3
4
|
import { BTN_GHOST_LEADING, BTN_PRIMARY, CardError, INPUT, useAutoFocus } from "./card-ui.js";
|
|
@@ -71,7 +72,7 @@ function QuestionForm({ request, autoFocus = false, onAnswer, onDismiss, Markdow
|
|
|
71
72
|
...instructions.trim() ? { instructions: instructions.trim() } : {}
|
|
72
73
|
});
|
|
73
74
|
} catch (err) {
|
|
74
|
-
setError(
|
|
75
|
+
setError(errorMessage(err));
|
|
75
76
|
setBusy(false);
|
|
76
77
|
}
|
|
77
78
|
};
|
|
@@ -99,7 +100,7 @@ function QuestionForm({ request, autoFocus = false, onAnswer, onDismiss, Markdow
|
|
|
99
100
|
try {
|
|
100
101
|
await onDismiss();
|
|
101
102
|
} catch (err) {
|
|
102
|
-
setError(
|
|
103
|
+
setError(errorMessage(err));
|
|
103
104
|
setBusy(false);
|
|
104
105
|
}
|
|
105
106
|
};
|
|
@@ -172,7 +173,10 @@ function QuestionForm({ request, autoFocus = false, onAnswer, onDismiss, Markdow
|
|
|
172
173
|
className: BTN_GHOST_LEADING,
|
|
173
174
|
children: labels.dismiss
|
|
174
175
|
}),
|
|
175
|
-
/* @__PURE__ */ jsx(CardError, {
|
|
176
|
+
/* @__PURE__ */ jsx(CardError, {
|
|
177
|
+
error: error && labels.answerSendFailed,
|
|
178
|
+
detail: error
|
|
179
|
+
}),
|
|
176
180
|
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
177
181
|
/* @__PURE__ */ jsx("button", {
|
|
178
182
|
type: "button",
|
|
@@ -16,8 +16,10 @@ declare const FIELD = "zg-well text-zg-ui px-2.5";
|
|
|
16
16
|
declare const INPUT = "zg-well text-zg-ui px-2.5 w-full placeholder:text-[var(--zg-text-subtle)]";
|
|
17
17
|
/** Props for {@link CardError}. */
|
|
18
18
|
interface CardErrorProps {
|
|
19
|
-
/** The message to show, or `null` to render nothing. */
|
|
19
|
+
/** The message to show, worded for people, or `null` to render nothing. */
|
|
20
20
|
error: string | null;
|
|
21
|
+
/** The raw words behind it (an exception's message): folded under Details. */
|
|
22
|
+
detail?: string | null;
|
|
21
23
|
/** Extra classes on the root element. */
|
|
22
24
|
className?: string;
|
|
23
25
|
/** Inline styles on the root element, merged after the component's own. */
|
|
@@ -26,9 +28,9 @@ interface CardErrorProps {
|
|
|
26
28
|
/**
|
|
27
29
|
* Renders an inline error message, or nothing when there is none.
|
|
28
30
|
*
|
|
29
|
-
* @param props - Component props: the `error`
|
|
31
|
+
* @param props - Component props: the `error` message and its raw `detail`.
|
|
30
32
|
*/
|
|
31
|
-
declare function CardError({ error, className, style }: CardErrorProps): import("react").JSX.Element | null;
|
|
33
|
+
declare function CardError({ error, detail, className, style }: CardErrorProps): import("react").JSX.Element | null;
|
|
32
34
|
/**
|
|
33
35
|
* Move keyboard focus to the card's first focusable control when asked
|
|
34
36
|
* (the card became the head, or the user came through "Open inbox").
|