@teaflask/assistant 0.6.0 → 0.7.0
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/README.md +1 -1
- package/custom-elements.json +264 -0
- package/dist/appearance/theme.d.ts +138 -0
- package/dist/components/approval-card.js +3 -3
- package/dist/components/approval-context.d.ts +20 -0
- package/dist/components/assistant-companion.d.ts +15 -0
- package/dist/components/assistant-page.d.ts +61 -0
- package/dist/components/assistant-palette.d.ts +12 -0
- package/dist/components/assistant-palette.js +2 -2
- package/dist/components/child-transcript.js +1 -1
- package/dist/components/companion-header-disclosure.js +1 -1
- package/dist/components/companion-history-menu.js +1 -1
- package/dist/components/composer.js +11 -65
- package/dist/components/conversation-context.d.ts +6 -0
- package/dist/components/conversation-gate-card.js +1 -1
- package/dist/components/conversation-view.d.ts +11 -0
- package/dist/components/elicitation-context.d.ts +39 -0
- package/dist/components/model-picker-chip.js +4 -2
- package/dist/components/primitives/button.js +25 -17
- package/dist/components/primitives/floating-panel.js +1 -1
- package/dist/components/provider-chip.js +8 -1
- package/dist/components/question-panel-footer.js +1 -1
- package/dist/components/react-tool-view.d.ts +7 -0
- package/dist/components/subagent-count-pill.js +2 -2
- package/dist/components/subagent-group-row.js +1 -26
- package/dist/components/subagent-preview-popover.js +1 -1
- package/dist/components/subscription-connect-arms.js +6 -4
- package/dist/components/subscription-connect-flow.js +30 -45
- package/dist/components/subscription-connected-standing.js +9 -6
- package/dist/components/subscription-plan-notice.js +4 -2
- package/dist/components/teaflask-assistant-provider.d.ts +99 -0
- package/dist/components/teaflask-assistant.d.ts +33 -0
- package/dist/components/tool-views/action-view.js +1 -1
- package/dist/components/tool-views/parts-classes.d.ts +5 -5
- package/dist/components/tool-views/parts-classes.js +5 -5
- package/dist/components/tool-views/parts.d.ts +44 -0
- package/dist/components/tool-views/questions-view.js +2 -2
- package/dist/components/tool-views/view-dom.d.ts +76 -0
- package/dist/components/transcript.js +2 -2
- package/dist/components/use-assistant-activity.d.ts +5 -0
- package/dist/components/use-assistant-conversation.d.ts +99 -2
- package/dist/components/use-store-cell.d.ts +5 -0
- package/dist/components/use-thread-dispatches.js +8 -366
- package/dist/components/use-transcript-folds.js +2 -1
- package/dist/components/use-transcript.d.ts +55 -2
- package/dist/components/use-transcript.js +7 -2
- package/dist/contract/actions-adapter.d.ts +78 -0
- package/dist/contract/errors.d.ts +6 -1
- package/dist/contract/events.d.ts +1 -3
- package/dist/contract/identity.d.ts +1 -1
- package/dist/contract/subscriptions.d.ts +2 -2
- package/dist/contract/subscriptions.js +1 -1
- package/dist/contract/telemetry.d.ts +45 -0
- package/dist/contract/threads.d.ts +5 -1
- package/dist/core/activity.d.ts +44 -0
- package/dist/core/approval-inbox.d.ts +69 -0
- package/dist/core/assistant-session-registry.js +15 -0
- package/dist/core/composer-attachments.js +82 -0
- package/dist/core/composer-input-state.js +1 -0
- package/dist/core/composer-policy.d.ts +20 -0
- package/dist/core/connection-epoch.d.ts +65 -2
- package/dist/core/conversation-adoption.js +3 -0
- package/dist/core/conversation-contract.d.ts +112 -1
- package/dist/core/conversation-publish.js +1 -0
- package/dist/core/conversation-store.d.ts +3 -0
- package/dist/core/conversation-store.js +7 -0
- package/dist/core/dispatch-poll.js +81 -0
- package/dist/core/elicitation-answers.js +12 -0
- package/dist/core/elicitation-cards.d.ts +14 -0
- package/dist/core/elicitation-pickers.d.ts +16 -0
- package/dist/core/memory-provenance-anchors.d.ts +16 -0
- package/dist/core/observable-cell.d.ts +12 -0
- package/dist/core/pending-decision-gap.d.ts +9 -0
- package/dist/core/question-drafts.d.ts +59 -0
- package/dist/core/receipt-anchors.d.ts +9 -0
- package/dist/core/segment-timing.d.ts +23 -0
- package/dist/core/subagent-delivery-anchors.d.ts +7 -0
- package/dist/core/subagent-ledger-join.js +176 -0
- package/dist/core/subagent-rows.d.ts +68 -0
- package/dist/core/thread-dispatch-ledger.js +303 -0
- package/dist/core/tool-call-display.d.ts +71 -0
- package/dist/core/tool-call-presentation.d.ts +34 -1
- package/dist/core/tool-call-presentation.js +0 -1
- package/dist/core/tool-schema-anchors.d.ts +6 -0
- package/dist/core/tool-view.d.ts +174 -1
- package/dist/core/transcript-rows.d.ts +138 -3
- package/dist/core/turn-failed-anchors.d.ts +4 -0
- package/dist/core/user-turn-ledger.d.ts +3 -0
- package/dist/generated/models/apiErrorCode.d.ts +1 -0
- package/dist/generated/models/apiErrorCode.js +1 -0
- package/dist/generated/models/assistantTurnStatus.d.ts +16 -0
- package/dist/generated/models/servingAssistantThreadResponse.d.ts +23 -0
- package/dist/generated/models/servingAttachmentResponse.d.ts +29 -0
- package/dist/generated/models/servingErrorCode.d.ts +18 -0
- package/dist/generated/models/servingTurnAttachmentResponse.d.ts +12 -0
- package/dist/generated/models/siteTheme.d.ts +1 -0
- package/dist/generated/models/thinkingEffort.d.ts +10 -0
- package/dist/generated/models/threadModelPickResponse.d.ts +12 -0
- package/dist/headless.d.ts +9 -4
- package/dist/index.d.ts +2 -6
- package/dist/index.js +0 -3
- package/dist/persistence/stored-thread.d.ts +5 -0
- package/dist/styles.css +1 -1
- package/dist/transport/serving-error.d.ts +21 -0
- package/package.json +6 -25
- package/dist/affordances/highlight.d.ts +0 -3
- package/dist/affordances/prefill.d.ts +0 -14
- package/dist/components/activity-rail.d.ts +0 -12
- package/dist/components/activity-shelf.d.ts +0 -7
- package/dist/components/agent-identity-mark.d.ts +0 -7
- package/dist/components/appearance-context.d.ts +0 -14
- package/dist/components/approval-card.d.ts +0 -7
- package/dist/components/assistant-palette-body.d.ts +0 -3
- package/dist/components/assistant-transcript.d.ts +0 -47
- package/dist/components/attachment-chips.d.ts +0 -4
- package/dist/components/child-transcript.d.ts +0 -22
- package/dist/components/companion-drawer-body.d.ts +0 -1
- package/dist/components/companion-drawer.d.ts +0 -10
- package/dist/components/companion-header-disclosure.d.ts +0 -20
- package/dist/components/companion-history-menu.d.ts +0 -15
- package/dist/components/companion-mark-image.d.ts +0 -3
- package/dist/components/companion-mark-image.js +0 -18
- package/dist/components/companion-mark.d.ts +0 -1
- package/dist/components/companion-mode-menu.d.ts +0 -15
- package/dist/components/composer-attachment-chip.d.ts +0 -7
- package/dist/components/composer-banner.d.ts +0 -4
- package/dist/components/composer.d.ts +0 -4
- package/dist/components/conversation-gate-card.d.ts +0 -8
- package/dist/components/conversation-surfaces-provider.d.ts +0 -6
- package/dist/components/copy-text-button.d.ts +0 -5
- package/dist/components/elicitation-receipt-row.d.ts +0 -4
- package/dist/components/human-file-size.d.ts +0 -1
- package/dist/components/icons.d.ts +0 -15
- package/dist/components/lazy-body.d.ts +0 -4
- package/dist/components/markdown/assistant-markdown.d.ts +0 -3
- package/dist/components/markdown/code-block.d.ts +0 -4
- package/dist/components/markdown/highlight.d.ts +0 -1
- package/dist/components/markdown/markdown-structure.d.ts +0 -16
- package/dist/components/markdown/memoized-blocks.d.ts +0 -6
- package/dist/components/markdown/paced-assistant-markdown.d.ts +0 -4
- package/dist/components/markdown/reveal-pacer.d.ts +0 -20
- package/dist/components/markdown/shiki-highlighter.d.ts +0 -1
- package/dist/components/markdown/streaming-repair.d.ts +0 -1
- package/dist/components/markdown/use-highlighted-html.d.ts +0 -1
- package/dist/components/markdown/use-paced-reveal.d.ts +0 -5
- package/dist/components/memory-updated-footer.d.ts +0 -4
- package/dist/components/message-list-row.d.ts +0 -13
- package/dist/components/message-list-slots.d.ts +0 -25
- package/dist/components/message-list-slots.js +0 -1
- package/dist/components/message-list.d.ts +0 -23
- package/dist/components/model-picker-chip.d.ts +0 -1
- package/dist/components/model-picker-effort.d.ts +0 -4
- package/dist/components/model-picker-panels.d.ts +0 -22
- package/dist/components/notice-banner.d.ts +0 -8
- package/dist/components/operation-icons.d.ts +0 -19
- package/dist/components/pretty-print.d.ts +0 -1
- package/dist/components/primitives/autofocus.d.ts +0 -1
- package/dist/components/primitives/button.d.ts +0 -10
- package/dist/components/primitives/cx.d.ts +0 -1
- package/dist/components/primitives/dialog.d.ts +0 -7
- package/dist/components/primitives/disclosure.d.ts +0 -22
- package/dist/components/primitives/file-input.d.ts +0 -5
- package/dist/components/primitives/floating-panel.d.ts +0 -15
- package/dist/components/primitives/kbd.d.ts +0 -2
- package/dist/components/primitives/sheet.d.ts +0 -11
- package/dist/components/primitives/sheet.js +0 -18
- package/dist/components/primitives/textarea.d.ts +0 -7
- package/dist/components/primitives/use-dock-reflow.d.ts +0 -2
- package/dist/components/primitives/use-swipe-dismiss.d.ts +0 -17
- package/dist/components/provider-chip.d.ts +0 -8
- package/dist/components/question-panel-answers.d.ts +0 -29
- package/dist/components/question-panel-footer.d.ts +0 -9
- package/dist/components/question-panel.d.ts +0 -4
- package/dist/components/reasoning-row.d.ts +0 -4
- package/dist/components/receipt-rows.d.ts +0 -3
- package/dist/components/run-status-announcer.d.ts +0 -5
- package/dist/components/scroll-follow-guards.d.ts +0 -1
- package/dist/components/served-suggestions.d.ts +0 -3
- package/dist/components/slot-boundary.d.ts +0 -11
- package/dist/components/standing-poll.d.ts +0 -1
- package/dist/components/streaming-states.d.ts +0 -12
- package/dist/components/subagent-count-pill.d.ts +0 -8
- package/dist/components/subagent-current-work.d.ts +0 -6
- package/dist/components/subagent-delegation-surface.d.ts +0 -9
- package/dist/components/subagent-delivery-divider.d.ts +0 -5
- package/dist/components/subagent-drill-in.d.ts +0 -8
- package/dist/components/subagent-execution-work.d.ts +0 -3
- package/dist/components/subagent-group-row.d.ts +0 -26
- package/dist/components/subagent-preview-popover.d.ts +0 -8
- package/dist/components/subscription-connect-arms.d.ts +0 -25
- package/dist/components/subscription-connect-flow.d.ts +0 -60
- package/dist/components/subscription-connected-standing.d.ts +0 -16
- package/dist/components/subscription-plan-notice.d.ts +0 -1
- package/dist/components/subscription-recheck.d.ts +0 -10
- package/dist/components/surface-boundary.d.ts +0 -8
- package/dist/components/suspension-surfaces.d.ts +0 -3
- package/dist/components/thread-list.d.ts +0 -16
- package/dist/components/tool-arguments-summary.d.ts +0 -2
- package/dist/components/tool-call-rows.d.ts +0 -10
- package/dist/components/tool-row.d.ts +0 -7
- package/dist/components/tool-view-registry-context.d.ts +0 -3
- package/dist/components/tool-view-slot.d.ts +0 -11
- package/dist/components/tool-views/action-view.d.ts +0 -1
- package/dist/components/tool-views/command-view.d.ts +0 -1
- package/dist/components/tool-views/docs-search-view.d.ts +0 -10
- package/dist/components/tool-views/file-edit-view.d.ts +0 -1
- package/dist/components/tool-views/questions-view.d.ts +0 -1
- package/dist/components/transcript.d.ts +0 -3
- package/dist/components/use-agent-subscriber.d.ts +0 -3
- package/dist/components/use-agent-subscriber.js +0 -13
- package/dist/components/use-answer-list-fold.d.ts +0 -6
- package/dist/components/use-assistant-surface-presence.d.ts +0 -2
- package/dist/components/use-child-replay-stream.d.ts +0 -20
- package/dist/components/use-latest-ref.d.ts +0 -2
- package/dist/components/use-member-toggle-outrank.d.ts +0 -6
- package/dist/components/use-perch-clearance.d.ts +0 -2
- package/dist/components/use-question-panel-keys.d.ts +0 -32
- package/dist/components/use-register-assistant-surface.d.ts +0 -2
- package/dist/components/use-resolved-theme-mode.d.ts +0 -3
- package/dist/components/use-roster-disclosure.d.ts +0 -20
- package/dist/components/use-roster-preview.d.ts +0 -24
- package/dist/components/use-thread-dispatches.d.ts +0 -8
- package/dist/components/use-transcript-folds.d.ts +0 -26
- package/dist/components/user-message.d.ts +0 -6
- package/dist/contract/actions-adapter.js +0 -1
- package/dist/contract/assistant-config.js +0 -1
- package/dist/contract/dispatches.d.ts +0 -15
- package/dist/contract/errors.js +0 -1
- package/dist/contract/identity.js +0 -1
- package/dist/core/activity-title.d.ts +0 -1
- package/dist/core/agent-identity.d.ts +0 -2
- package/dist/core/approval-decision.d.ts +0 -6
- package/dist/core/approval-resolved.d.ts +0 -7
- package/dist/core/assistant-prose.d.ts +0 -2
- package/dist/core/assistant-session-registry.d.ts +0 -51
- package/dist/core/attachment-uploads.d.ts +0 -5
- package/dist/core/block-timing-anchors.d.ts +0 -5
- package/dist/core/companion-drawer-flag.d.ts +0 -4
- package/dist/core/companion-presence.d.ts +0 -7
- package/dist/core/composer-input-state.d.ts +0 -8
- package/dist/core/connection-driver.d.ts +0 -3
- package/dist/core/conversation-adoption.d.ts +0 -13
- package/dist/core/conversation-contract.js +0 -1
- package/dist/core/conversation-publish.d.ts +0 -8
- package/dist/core/conversation-refresh.d.ts +0 -4
- package/dist/core/conversation-send.d.ts +0 -6
- package/dist/core/disposable-subscriber.d.ts +0 -6
- package/dist/core/disposable-subscriber.js +0 -18
- package/dist/core/dock-reflow.d.ts +0 -5
- package/dist/core/elicitation-answers.d.ts +0 -7
- package/dist/core/epoch-sync.d.ts +0 -12
- package/dist/core/error-copy.d.ts +0 -3
- package/dist/core/execution-driver.d.ts +0 -37
- package/dist/core/host-fill.d.ts +0 -1
- package/dist/core/hotkey.d.ts +0 -18
- package/dist/core/identity-pair.d.ts +0 -14
- package/dist/core/idle-recheck.d.ts +0 -3
- package/dist/core/messages-cell.d.ts +0 -11
- package/dist/core/perch-clearance.d.ts +0 -19
- package/dist/core/question-receipt.d.ts +0 -11
- package/dist/core/reasoning-copy.d.ts +0 -2
- package/dist/core/run-folds.d.ts +0 -43
- package/dist/core/run-status.d.ts +0 -4
- package/dist/core/settle-refresh.d.ts +0 -9
- package/dist/core/step-caption.d.ts +0 -2
- package/dist/core/stop-copy.d.ts +0 -1
- package/dist/core/stop-settle.d.ts +0 -5
- package/dist/core/stream-trouble.d.ts +0 -5
- package/dist/core/subagent-brief.d.ts +0 -3
- package/dist/core/subagent-presence.d.ts +0 -10
- package/dist/core/subagent-roster.d.ts +0 -35
- package/dist/core/surface-registry.d.ts +0 -16
- package/dist/core/suspension-queue.d.ts +0 -14
- package/dist/core/tail-slot-pool.d.ts +0 -13
- package/dist/core/time-labels.d.ts +0 -7
- package/dist/core/tool-call-display-anchors.d.ts +0 -11
- package/dist/core/tool-cancel-anchors.d.ts +0 -5
- package/dist/core/tool-decision-anchors.d.ts +0 -6
- package/dist/core/tool-error-anchors.d.ts +0 -5
- package/dist/core/tool-flag-anchors.d.ts +0 -9
- package/dist/core/tool-offload-anchors.d.ts +0 -5
- package/dist/core/tool-outcome.d.ts +0 -9
- package/dist/core/tool-refusal-anchors.d.ts +0 -5
- package/dist/core/tool-result-envelope.d.ts +0 -3
- package/dist/core/tool-sentence-anchors.d.ts +0 -11
- package/dist/core/transcript-lease.d.ts +0 -2
- package/dist/core/turn-failure-copy.d.ts +0 -4
- package/dist/core/turns-backfill.d.ts +0 -14
- package/dist/core/wire-sentence-cap.d.ts +0 -1
- package/dist/generated/serving.d.ts +0 -38
- package/dist/markdown.d.ts +0 -4
- package/dist/markdown.js +0 -4
- package/dist/persistence/execution-ledger.d.ts +0 -7
- package/dist/persistence/panel-mode.d.ts +0 -6
- package/dist/persistence/plan-notice.d.ts +0 -3
- package/dist/reader/accessible-name.d.ts +0 -3
- package/dist/reader/interactivity.d.ts +0 -11
- package/dist/reader/layout-probe.d.ts +0 -29
- package/dist/reader/line-diff.d.ts +0 -1
- package/dist/reader/read-page.d.ts +0 -12
- package/dist/reader/redaction.d.ts +0 -3
- package/dist/reader/render.d.ts +0 -3
- package/dist/reader/roles.d.ts +0 -8
- package/dist/reader/snapshot-compaction.d.ts +0 -5
- package/dist/reader/snapshot-node.d.ts +0 -4
- package/dist/reader/snapshot-root.d.ts +0 -15
- package/dist/reader/snapshot.d.ts +0 -60
- package/dist/reader/visibility.d.ts +0 -8
- package/dist/scroll.d.ts +0 -1
- package/dist/scroll.js +0 -1
- package/dist/transcript-ui.d.ts +0 -15
- package/dist/transcript-ui.js +0 -8
- package/dist/transcript.d.ts +0 -43
- package/dist/transcript.js +0 -38
- package/dist/transport/actions-adapter.d.ts +0 -4
- package/dist/transport/door-budget.d.ts +0 -4
- package/dist/transport/serving-api.d.ts +0 -33
- package/dist/transport/serving-fetch.d.ts +0 -11
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { AgentSubscriber } from "@ag-ui/client";
|
|
2
|
+
/**
|
|
3
|
+
* Notice sentences attached to one message, split by whether they are shown
|
|
4
|
+
* before or after it.
|
|
5
|
+
*/
|
|
2
6
|
export interface AnchoredReceipts {
|
|
7
|
+
/**
|
|
8
|
+
* Sentences shown before the message. The package places failure notices
|
|
9
|
+
* after the message, so this is normally empty.
|
|
10
|
+
*/
|
|
3
11
|
before: string[];
|
|
12
|
+
/** Sentences shown after the message. */
|
|
4
13
|
after: string[];
|
|
5
14
|
}
|
|
6
15
|
export declare function receiptOf(value: unknown): string | null;
|
|
@@ -1,13 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When a message or tool call started and ended, by the server's clock in
|
|
3
|
+
* milliseconds since the Unix epoch.
|
|
4
|
+
*/
|
|
1
5
|
export interface BlockTiming {
|
|
6
|
+
/** The earliest server timestamp seen for it, or null when unknown. */
|
|
2
7
|
startedAtMs: number | null;
|
|
8
|
+
/**
|
|
9
|
+
* The latest server timestamp seen for it, or null when unknown. Equals
|
|
10
|
+
* startedAtMs until its end arrives.
|
|
11
|
+
*/
|
|
3
12
|
settledAtMs: number | null;
|
|
4
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* A duration that is either unknown (hide it) or measured in milliseconds;
|
|
16
|
+
* render a measured value under 1000 as "<1s" rather than "0s".
|
|
17
|
+
*/
|
|
5
18
|
export type SegmentDuration = {
|
|
6
19
|
kind: "unknown";
|
|
7
20
|
} | {
|
|
8
21
|
kind: "measured";
|
|
9
22
|
durationMs: number;
|
|
10
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* How long the given blocks took together, from the earliest to the latest
|
|
26
|
+
* server timestamp among them, or unknown when none has a timestamp.
|
|
27
|
+
*/
|
|
11
28
|
export declare function settledFoldDurationOf(members: readonly BlockTiming[]): SegmentDuration;
|
|
12
29
|
export declare function durationLabelOf(durationMs: number): string;
|
|
30
|
+
/**
|
|
31
|
+
* Time elapsed from the earliest server timestamp among the given blocks to
|
|
32
|
+
* `nowMs` (milliseconds since the Unix epoch), or unknown when none has a
|
|
33
|
+
* timestamp. Passing Date.now() includes any difference between the device
|
|
34
|
+
* clock and the server clock.
|
|
35
|
+
*/
|
|
13
36
|
export declare function activeFoldElapsedOf(members: readonly BlockTiming[], nowMs: number): SegmentDuration;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { AgentSubscriber } from "@ag-ui/client";
|
|
2
|
+
/** One finished sub-agent whose result a turn reports. */
|
|
2
3
|
export interface DeliveredResult {
|
|
4
|
+
/**
|
|
5
|
+
* The sub-agent's number within the conversation, matching
|
|
6
|
+
* DispatchReceipt.ordinal of its dispatch.
|
|
7
|
+
*/
|
|
3
8
|
ordinal: number;
|
|
9
|
+
/** A short excerpt of the task the sub-agent was given. */
|
|
4
10
|
label: string;
|
|
11
|
+
/** True when the sub-agent succeeded, false when it failed. */
|
|
5
12
|
succeeded: boolean;
|
|
6
13
|
}
|
|
7
14
|
export declare const EMPTY_SUBAGENT_DELIVERY_ANCHORS: ReadonlyMap<string, DeliveredResult[]>;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { dispatchFailed, dispatchIsPaused, dispatchIsRunning, } from "../contract/dispatches.js";
|
|
2
|
+
import { subagentIdentityTokenOf } from "./agent-identity.js";
|
|
3
|
+
import { DISPATCH_SUBAGENT_TOOL_NAME, dispatchReceiptOf, withSubagentGroups, } from "./subagent-rows.js";
|
|
4
|
+
export function resolvedSubagentEntryOf(entry, byOrdinal) {
|
|
5
|
+
const ledger = entry.receipt != null ? byOrdinal.get(entry.receipt.ordinal) : undefined;
|
|
6
|
+
const ledgerLabel = ledger !== undefined && ledger.label !== "" ? ledger.label : null;
|
|
7
|
+
const childSessionId = ledger !== undefined && entry.receipt?.childSessionId != null
|
|
8
|
+
? entry.receipt.childSessionId
|
|
9
|
+
: null;
|
|
10
|
+
const running = ledger !== undefined ? dispatchIsRunning(ledger) : entry.running;
|
|
11
|
+
const failed = ledger !== undefined ? dispatchFailed(ledger) : entry.failed;
|
|
12
|
+
return {
|
|
13
|
+
toolCallId: entry.toolCallId,
|
|
14
|
+
label: ledgerLabel ?? entry.label,
|
|
15
|
+
running,
|
|
16
|
+
failed,
|
|
17
|
+
cancelled: entry.cancelled,
|
|
18
|
+
note: (ledger !== undefined && dispatchFailed(ledger) ? ledger.error : null) ??
|
|
19
|
+
entry.note,
|
|
20
|
+
childSessionId,
|
|
21
|
+
identityToken: childSessionId !== null ? subagentIdentityTokenOf(childSessionId) : null,
|
|
22
|
+
ordinal: entry.receipt?.ordinal ?? null,
|
|
23
|
+
paused: ledger !== undefined && dispatchIsPaused(ledger),
|
|
24
|
+
startedAt: ledger !== undefined ? ledger.created_at : null,
|
|
25
|
+
settledAt: ledger !== undefined && !running ? ledger.updated_at : null,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export const RESUME_SUBAGENT_TOOL_NAME = "resume_subagent";
|
|
29
|
+
export function demandInputOfRows(rows) {
|
|
30
|
+
const entries = [];
|
|
31
|
+
const resumeResults = [];
|
|
32
|
+
const deliveredOrdinals = [];
|
|
33
|
+
for (const row of rows) {
|
|
34
|
+
if (row.kind === "subagent-group") {
|
|
35
|
+
entries.push(...row.entries);
|
|
36
|
+
}
|
|
37
|
+
else if (row.kind === "tool-call" &&
|
|
38
|
+
row.toolName === RESUME_SUBAGENT_TOOL_NAME) {
|
|
39
|
+
resumeResults.push(row.result);
|
|
40
|
+
}
|
|
41
|
+
else if (row.kind === "subagent-delivery") {
|
|
42
|
+
deliveredOrdinals.push(...row.results.map((result) => result.ordinal));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { entries, resumeResults, deliveredOrdinals };
|
|
46
|
+
}
|
|
47
|
+
export function demandInputOfMessages(messages, anchors) {
|
|
48
|
+
const results = new Map();
|
|
49
|
+
for (const message of messages) {
|
|
50
|
+
if (message.role === "tool" && typeof message.content === "string") {
|
|
51
|
+
results.set(message.toolCallId, message.content);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const calls = [];
|
|
55
|
+
const resumeResults = [];
|
|
56
|
+
for (const message of messages) {
|
|
57
|
+
if (message.role !== "assistant") {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
for (const toolCall of message.toolCalls ?? []) {
|
|
61
|
+
const id = toolCall.id;
|
|
62
|
+
if (toolCall.function.name === RESUME_SUBAGENT_TOOL_NAME) {
|
|
63
|
+
resumeResults.push(results.get(id));
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (toolCall.function.name !== DISPATCH_SUBAGENT_TOOL_NAME) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const failed = anchors.toolErrorAnchors.has(id);
|
|
70
|
+
const denied = !failed && (anchors.toolDenialAnchors?.has(id) ?? false);
|
|
71
|
+
const cancelled = !failed && !denied && anchors.toolCancelAnchors.has(id);
|
|
72
|
+
const refused = !failed && !denied && !cancelled && anchors.toolRefusalAnchors.has(id);
|
|
73
|
+
if (denied || refused) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const result = results.get(id);
|
|
77
|
+
calls.push({
|
|
78
|
+
toolCallId: id,
|
|
79
|
+
settled: failed || cancelled || result !== undefined,
|
|
80
|
+
failed,
|
|
81
|
+
cancelled,
|
|
82
|
+
result,
|
|
83
|
+
errorText: undefined,
|
|
84
|
+
argsText: toolCall.function.arguments,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const entries = withSubagentGroups(calls, (call) => call, (call) => call.toolCallId).flatMap((row) => ("entries" in row ? row.entries : []));
|
|
89
|
+
const deliveredOrdinals = [];
|
|
90
|
+
for (const delivered of anchors.subagentDeliveryAnchors.values()) {
|
|
91
|
+
deliveredOrdinals.push(...delivered.map((result) => result.ordinal));
|
|
92
|
+
}
|
|
93
|
+
return { entries, resumeResults, deliveredOrdinals };
|
|
94
|
+
}
|
|
95
|
+
function aResumeAwaitsLedgerTruth(resumeResults, ledger) {
|
|
96
|
+
return resumeResults.some((result) => {
|
|
97
|
+
const receipt = dispatchReceiptOf(result);
|
|
98
|
+
if (receipt === null || receipt.outcome === "already_settled") {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const dispatched = ledger.get(receipt.ordinal);
|
|
102
|
+
return dispatched === undefined || dispatchIsRunning(dispatched);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function anySubagentStillRunning(entries, ledger) {
|
|
106
|
+
return entries.some((entry) => entry.receipt != null && resolvedSubagentEntryOf(entry, ledger).running);
|
|
107
|
+
}
|
|
108
|
+
export function dispatchDemandOf(input, byOrdinal) {
|
|
109
|
+
return {
|
|
110
|
+
delegated: input.entries.length > 0 ||
|
|
111
|
+
aResumeAwaitsLedgerTruth(input.resumeResults, EMPTY_BY_ORDINAL),
|
|
112
|
+
stillMoving: anySubagentStillRunning(input.entries, byOrdinal) ||
|
|
113
|
+
aResumeAwaitsLedgerTruth(input.resumeResults, byOrdinal),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const EMPTY_BY_ORDINAL = new Map();
|
|
117
|
+
export function dispatchJoinKeyOf(input) {
|
|
118
|
+
const ordinals = new Set();
|
|
119
|
+
for (const entry of input.entries) {
|
|
120
|
+
if (entry.receipt !== null) {
|
|
121
|
+
ordinals.add(entry.receipt.ordinal);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (const result of input.resumeResults) {
|
|
125
|
+
const receipt = dispatchReceiptOf(result);
|
|
126
|
+
if (receipt !== null) {
|
|
127
|
+
ordinals.add(receipt.ordinal);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return [...ordinals].sort((a, b) => a - b).join(",");
|
|
131
|
+
}
|
|
132
|
+
export function staleDeliveredOrdinalsKeyOf(input, byOrdinal) {
|
|
133
|
+
return [...new Set(input.deliveredOrdinals)]
|
|
134
|
+
.filter((ordinal) => {
|
|
135
|
+
const ledgerRow = byOrdinal.get(ordinal);
|
|
136
|
+
return ledgerRow !== undefined && dispatchIsRunning(ledgerRow);
|
|
137
|
+
})
|
|
138
|
+
.sort((a, b) => a - b)
|
|
139
|
+
.join(",");
|
|
140
|
+
}
|
|
141
|
+
export function withDispatchLedger(rows, byOrdinal) {
|
|
142
|
+
if (byOrdinal.size === 0) {
|
|
143
|
+
return rows;
|
|
144
|
+
}
|
|
145
|
+
let out = null;
|
|
146
|
+
for (const [index, row] of rows.entries()) {
|
|
147
|
+
if (row.kind !== "subagent-group") {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const joined = _joinedGroupRowOf(row, byOrdinal);
|
|
151
|
+
if (joined !== row) {
|
|
152
|
+
out ??= [...rows];
|
|
153
|
+
out[index] = joined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return out ?? rows;
|
|
157
|
+
}
|
|
158
|
+
function _joinedGroupRowOf(row, byOrdinal) {
|
|
159
|
+
let entries = null;
|
|
160
|
+
for (const [index, entry] of row.entries.entries()) {
|
|
161
|
+
const resolved = resolvedSubagentEntryOf(entry, byOrdinal);
|
|
162
|
+
if (resolved.running === entry.running &&
|
|
163
|
+
resolved.failed === entry.failed &&
|
|
164
|
+
resolved.note === entry.note) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
entries ??= [...row.entries];
|
|
168
|
+
entries[index] = {
|
|
169
|
+
...entry,
|
|
170
|
+
running: resolved.running,
|
|
171
|
+
failed: resolved.failed,
|
|
172
|
+
note: resolved.note,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return entries === null ? row : { ...row, entries };
|
|
176
|
+
}
|
|
@@ -8,28 +8,96 @@ export interface DispatchCall {
|
|
|
8
8
|
errorText: string | undefined;
|
|
9
9
|
argsText: string;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* The sub-agent tool's immediate reply confirming a dispatch, parsed. It is not
|
|
13
|
+
* the sub-agent's result, which arrives later in its own turn.
|
|
14
|
+
*/
|
|
11
15
|
export interface DispatchReceipt {
|
|
16
|
+
/**
|
|
17
|
+
* launched means a new sub-agent was started, attached means the same task
|
|
18
|
+
* was re-issued and joined the sub-agent already working on it, and
|
|
19
|
+
* already_settled means that sub-agent had already finished, with its
|
|
20
|
+
* outcome in `settled`.
|
|
21
|
+
*/
|
|
12
22
|
outcome: "launched" | "attached" | "already_settled";
|
|
23
|
+
/**
|
|
24
|
+
* The sub-agent's number within the conversation, counting from 0; the same
|
|
25
|
+
* number identifies it in DeliveredResult.ordinal.
|
|
26
|
+
*/
|
|
13
27
|
ordinal: number;
|
|
28
|
+
/**
|
|
29
|
+
* A short excerpt of the task given to the sub-agent. Can be empty when the
|
|
30
|
+
* stored reply was cut short.
|
|
31
|
+
*/
|
|
14
32
|
label: string;
|
|
33
|
+
/**
|
|
34
|
+
* The id of the sub-agent's own session. Null when the stored reply was cut
|
|
35
|
+
* short.
|
|
36
|
+
*/
|
|
15
37
|
childSessionId: string | null;
|
|
38
|
+
/**
|
|
39
|
+
* The finished sub-agent's outcome (whether it failed, plus an optional
|
|
40
|
+
* note) when outcome is already_settled; null otherwise.
|
|
41
|
+
*/
|
|
16
42
|
settled: {
|
|
17
43
|
failed: boolean;
|
|
18
44
|
note: string | null;
|
|
19
45
|
} | null;
|
|
20
46
|
}
|
|
47
|
+
/** One sub-agent in a group of dispatches. */
|
|
21
48
|
export interface SubagentGroupEntry {
|
|
49
|
+
/** The id of the tool call that dispatched this sub-agent. */
|
|
22
50
|
toolCallId: string;
|
|
51
|
+
/**
|
|
52
|
+
* The dispatch's confirmation. Null until it arrives, or when the dispatch
|
|
53
|
+
* failed.
|
|
54
|
+
*/
|
|
23
55
|
receipt: DispatchReceipt | null;
|
|
56
|
+
/**
|
|
57
|
+
* A short excerpt of the sub-agent's task, read from the confirmation or,
|
|
58
|
+
* before it arrives, from the task text still streaming. Null when nothing
|
|
59
|
+
* readable is available yet.
|
|
60
|
+
*/
|
|
24
61
|
label: string | null;
|
|
62
|
+
/**
|
|
63
|
+
* True while the sub-agent is still working as of the package's latest
|
|
64
|
+
* successful check, and false once a check has seen it finish, whether or
|
|
65
|
+
* not the built-in transcript is on screen; before any check lands, or for
|
|
66
|
+
* a sub-agent whose confirmation never arrived, it reads as the dispatch
|
|
67
|
+
* reply last showed it. The package re-checks the conversation's sub-agents
|
|
68
|
+
* while any is unfinished and the checks keep succeeding; a
|
|
69
|
+
* subagent-delivery row then reports the result.
|
|
70
|
+
*/
|
|
25
71
|
running: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* True when the dispatch failed, or when the dispatch's confirmation or the
|
|
74
|
+
* package's latest successful check reports that the sub-agent failed; a
|
|
75
|
+
* failure no check has seen yet reads false.
|
|
76
|
+
*/
|
|
26
77
|
failed: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* True when the dispatch was cancelled or abandoned by a retry; the
|
|
80
|
+
* built-in UI labels this "interrupted".
|
|
81
|
+
*/
|
|
27
82
|
cancelled: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* An explanation to show beside the entry: why the dispatch failed, why the
|
|
85
|
+
* sub-agent failed, or the note its confirmation carried for a sub-agent
|
|
86
|
+
* that had already finished. Null when there is none; a sub-agent that
|
|
87
|
+
* finishes successfully while you watch leaves it null.
|
|
88
|
+
*/
|
|
28
89
|
note: string | null;
|
|
29
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Consecutive sub-agent dispatches shown as one group, such as "Running 3
|
|
93
|
+
* subagents".
|
|
94
|
+
*/
|
|
30
95
|
export interface SubagentGroupRow {
|
|
96
|
+
/** Identifies a sub-agent group row. */
|
|
31
97
|
kind: "subagent-group";
|
|
98
|
+
/** Stable unique key for this row, suitable as a React list key. */
|
|
32
99
|
key: string;
|
|
100
|
+
/** The dispatched sub-agents, in the order they were dispatched. */
|
|
33
101
|
entries: SubagentGroupEntry[];
|
|
34
102
|
}
|
|
35
103
|
export interface SubagentOutcomeCounts {
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { dispatchIsPaused, dispatchIsRunning, } from "../contract/dispatches.js";
|
|
2
|
+
import { listThreadDispatches } from "../transport/serving-api.js";
|
|
3
|
+
import { ObservableCell } from "./observable-cell.js";
|
|
4
|
+
const POLL_INTERVAL_MS = 10_000;
|
|
5
|
+
const MAX_CONSECUTIVE_READ_FAILURES = 3;
|
|
6
|
+
const READ_BOUND_MS = 2 * POLL_INTERVAL_MS;
|
|
7
|
+
export const EMPTY_THREAD_DISPATCHES = new Map();
|
|
8
|
+
export function newestRowForSession(map, childSessionId) {
|
|
9
|
+
let newest;
|
|
10
|
+
for (const dispatch of map.values()) {
|
|
11
|
+
if (dispatch.child_session_id !== childSessionId) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
if (newest === undefined || dispatch.ordinal > newest.ordinal) {
|
|
15
|
+
newest = dispatch;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return newest;
|
|
19
|
+
}
|
|
20
|
+
export class ThreadDispatchLedger {
|
|
21
|
+
session;
|
|
22
|
+
cell = new ObservableCell(null);
|
|
23
|
+
demands = new Map();
|
|
24
|
+
timer = null;
|
|
25
|
+
timerThreadId = null;
|
|
26
|
+
busy = false;
|
|
27
|
+
readThreadId = null;
|
|
28
|
+
pendingThreadId = null;
|
|
29
|
+
failedThreadId = null;
|
|
30
|
+
consecutiveFailures = 0;
|
|
31
|
+
constructor(session) {
|
|
32
|
+
this.session = session;
|
|
33
|
+
}
|
|
34
|
+
settleListeners = new Map();
|
|
35
|
+
setSettleListener(token, listener) {
|
|
36
|
+
if (listener === null) {
|
|
37
|
+
this.settleListeners.delete(token);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.settleListeners.set(token, listener);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
pauseListeners = new Map();
|
|
44
|
+
setPauseListener(token, listener) {
|
|
45
|
+
if (listener === null) {
|
|
46
|
+
this.pauseListeners.delete(token);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.pauseListeners.set(token, listener);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
setDemand(token, demand) {
|
|
53
|
+
const held = this.demands.get(token);
|
|
54
|
+
if (demand === null) {
|
|
55
|
+
if (held === undefined) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.demands.delete(token);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
if (held?.threadId === demand.threadId &&
|
|
62
|
+
held.delegated === demand.delegated &&
|
|
63
|
+
held.stillMoving === demand.stillMoving &&
|
|
64
|
+
held.joinKey === demand.joinKey) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
this.demands.set(token, demand);
|
|
68
|
+
}
|
|
69
|
+
this._reconcile();
|
|
70
|
+
}
|
|
71
|
+
noteThreadAnswered(threadId) {
|
|
72
|
+
if (this.failedThreadId !== threadId || this.consecutiveFailures === 0) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this.failedThreadId = null;
|
|
76
|
+
this.consecutiveFailures = 0;
|
|
77
|
+
this._reconcile();
|
|
78
|
+
}
|
|
79
|
+
refresh(threadId) {
|
|
80
|
+
if (!this.busy) {
|
|
81
|
+
return this._readOnce(threadId);
|
|
82
|
+
}
|
|
83
|
+
if (this.followUp === null || this.followUpThreadId !== threadId) {
|
|
84
|
+
this.followUpThreadId = threadId;
|
|
85
|
+
this.followUp = (this.flight ?? Promise.resolve()).then(() => {
|
|
86
|
+
this.followUp = null;
|
|
87
|
+
this.followUpThreadId = null;
|
|
88
|
+
return this._readOnce(threadId);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return this.followUp;
|
|
92
|
+
}
|
|
93
|
+
followUp = null;
|
|
94
|
+
followUpThreadId = null;
|
|
95
|
+
_reconcile() {
|
|
96
|
+
let threadId = null;
|
|
97
|
+
let delegated = false;
|
|
98
|
+
let stillMoving = false;
|
|
99
|
+
for (const demand of this.demands.values()) {
|
|
100
|
+
threadId ??= demand.threadId;
|
|
101
|
+
delegated ||= demand.delegated;
|
|
102
|
+
stillMoving ||= demand.stillMoving;
|
|
103
|
+
}
|
|
104
|
+
if (this.pendingThreadId !== null && this.pendingThreadId !== threadId) {
|
|
105
|
+
this.pendingThreadId = null;
|
|
106
|
+
}
|
|
107
|
+
if (threadId === null || !delegated) {
|
|
108
|
+
this._stopTimer();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (this.readThreadId !== threadId) {
|
|
112
|
+
void this._readOnce(threadId);
|
|
113
|
+
}
|
|
114
|
+
if (!stillMoving) {
|
|
115
|
+
this._stopTimer();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (this.timer === null || this.timerThreadId !== threadId) {
|
|
119
|
+
this._stopTimer();
|
|
120
|
+
void this._readOnce(threadId);
|
|
121
|
+
this.timerThreadId = threadId;
|
|
122
|
+
this.timer = setInterval(() => {
|
|
123
|
+
void this._readOnce(threadId);
|
|
124
|
+
}, POLL_INTERVAL_MS);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
_sameAsCurrent(next) {
|
|
128
|
+
const current = this.cell.get();
|
|
129
|
+
if (current?.threadId !== next.threadId) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
if (current.map.size !== next.map.size) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
for (const [ordinal, dispatch] of next.map) {
|
|
136
|
+
const held = current.map.get(ordinal);
|
|
137
|
+
if (held?.status !== dispatch.status ||
|
|
138
|
+
held.error !== dispatch.error ||
|
|
139
|
+
held.updated_at !== dispatch.updated_at) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
_stopTimer() {
|
|
146
|
+
if (this.timer !== null) {
|
|
147
|
+
clearInterval(this.timer);
|
|
148
|
+
this.timer = null;
|
|
149
|
+
this.timerThreadId = null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
_readOnce(threadId) {
|
|
153
|
+
if (this.busy) {
|
|
154
|
+
if (threadId !== this.readThreadId) {
|
|
155
|
+
this.pendingThreadId = threadId;
|
|
156
|
+
}
|
|
157
|
+
return this.flight ?? Promise.resolve();
|
|
158
|
+
}
|
|
159
|
+
this.busy = true;
|
|
160
|
+
this.readThreadId = threadId;
|
|
161
|
+
this.generation += 1;
|
|
162
|
+
const generation = this.generation;
|
|
163
|
+
let settleFlight;
|
|
164
|
+
const flight = new Promise((resolve) => {
|
|
165
|
+
settleFlight = resolve;
|
|
166
|
+
});
|
|
167
|
+
this.flight = flight;
|
|
168
|
+
setTimeout(() => {
|
|
169
|
+
this._releaseBoundedOutRead(threadId, generation);
|
|
170
|
+
settleFlight();
|
|
171
|
+
}, READ_BOUND_MS);
|
|
172
|
+
void this._read(threadId, generation, settleFlight);
|
|
173
|
+
return flight;
|
|
174
|
+
}
|
|
175
|
+
flight = null;
|
|
176
|
+
generation = 0;
|
|
177
|
+
_releaseBoundedOutRead(threadId, generation) {
|
|
178
|
+
if (generation !== this.generation || !this.busy) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
this.generation += 1;
|
|
182
|
+
this.busy = false;
|
|
183
|
+
this.flight = null;
|
|
184
|
+
this._noteReadFailure(threadId);
|
|
185
|
+
this._replayParkedSwitch();
|
|
186
|
+
}
|
|
187
|
+
_noteReadFailure(threadId) {
|
|
188
|
+
this.consecutiveFailures =
|
|
189
|
+
this.failedThreadId === threadId ? this.consecutiveFailures + 1 : 1;
|
|
190
|
+
this.failedThreadId = threadId;
|
|
191
|
+
if (this.consecutiveFailures >= MAX_CONSECUTIVE_READ_FAILURES &&
|
|
192
|
+
this.timerThreadId === threadId) {
|
|
193
|
+
this._stopTimer();
|
|
194
|
+
}
|
|
195
|
+
if (this.cell.get()?.threadId !== threadId) {
|
|
196
|
+
this.readThreadId = null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
_replayParkedSwitch() {
|
|
200
|
+
const pending = this.pendingThreadId;
|
|
201
|
+
this.pendingThreadId = null;
|
|
202
|
+
if (pending !== null && pending !== this.readThreadId) {
|
|
203
|
+
void this._readOnce(pending);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
adoptedThrough = 0;
|
|
207
|
+
async _read(threadId, generation, settleFlight) {
|
|
208
|
+
const live = () => generation === this.generation;
|
|
209
|
+
try {
|
|
210
|
+
const dispatches = await listThreadDispatches(this.session, threadId);
|
|
211
|
+
const adopts = live() ||
|
|
212
|
+
(generation > this.adoptedThrough &&
|
|
213
|
+
(this.readThreadId === threadId || this.readThreadId === null));
|
|
214
|
+
if (!adopts) {
|
|
215
|
+
if (this.failedThreadId === threadId) {
|
|
216
|
+
this.failedThreadId = null;
|
|
217
|
+
this.consecutiveFailures = 0;
|
|
218
|
+
}
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
this.readThreadId ??= threadId;
|
|
222
|
+
this.adoptedThrough = generation;
|
|
223
|
+
const previous = this.cell.get();
|
|
224
|
+
const next = {
|
|
225
|
+
threadId,
|
|
226
|
+
map: new Map(dispatches.map((dispatch) => [dispatch.ordinal, dispatch])),
|
|
227
|
+
};
|
|
228
|
+
if (!this._sameAsCurrent(next)) {
|
|
229
|
+
this.cell.set(next);
|
|
230
|
+
}
|
|
231
|
+
this.failedThreadId = null;
|
|
232
|
+
this.consecutiveFailures = 0;
|
|
233
|
+
if (_observedASettle(previous, next)) {
|
|
234
|
+
_fireEach(this.settleListeners);
|
|
235
|
+
}
|
|
236
|
+
if (_observedAPause(previous, next)) {
|
|
237
|
+
_fireEach(this.pauseListeners);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
if (!live()) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
this._noteReadFailure(threadId);
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
if (live()) {
|
|
248
|
+
this.busy = false;
|
|
249
|
+
this.flight = null;
|
|
250
|
+
settleFlight();
|
|
251
|
+
this._replayParkedSwitch();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function _fireEach(listeners) {
|
|
257
|
+
for (const listener of new Set(listeners.values())) {
|
|
258
|
+
try {
|
|
259
|
+
listener();
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function _observedAPause(previous, next) {
|
|
266
|
+
const comparable = previous?.threadId === next.threadId ? previous : null;
|
|
267
|
+
for (const [ordinal, dispatch] of next.map) {
|
|
268
|
+
if (!dispatchIsPaused(dispatch)) {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
const held = comparable?.map.get(ordinal);
|
|
272
|
+
if (held === undefined ||
|
|
273
|
+
!dispatchIsPaused(held) ||
|
|
274
|
+
held.updated_at !== dispatch.updated_at) {
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
function _observedASettle(previous, next) {
|
|
281
|
+
if (previous?.threadId !== next.threadId) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
for (const [ordinal, dispatch] of next.map) {
|
|
285
|
+
if (dispatchIsRunning(dispatch)) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
const held = previous.map.get(ordinal);
|
|
289
|
+
if (held === undefined || dispatchIsRunning(held)) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
const _ledgers = new WeakMap();
|
|
296
|
+
export function threadDispatchLedgerFor(session) {
|
|
297
|
+
let ledger = _ledgers.get(session);
|
|
298
|
+
if (ledger === undefined) {
|
|
299
|
+
ledger = new ThreadDispatchLedger(session);
|
|
300
|
+
_ledgers.set(session, ledger);
|
|
301
|
+
}
|
|
302
|
+
return ledger;
|
|
303
|
+
}
|