@miragon/mcp-toolkit-ui 2.7.0 → 2.8.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 +7 -4
- package/dist/app/adapt-data-widget.d.ts +1 -22
- package/dist/app/adapt-data-widget.d.ts.map +1 -1
- package/dist/app/adapt-data-widget.js +1 -35
- package/dist/app/adapt-data-widget.js.map +1 -1
- package/dist/app/builder/BuilderBanners.js +1 -1
- package/dist/app/builder/BuilderBanners.js.map +1 -1
- package/dist/app/builder/CanvasRow.d.ts +4 -2
- package/dist/app/builder/CanvasRow.d.ts.map +1 -1
- package/dist/app/builder/CanvasRow.js +21 -7
- package/dist/app/builder/CanvasRow.js.map +1 -1
- package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
- package/dist/app/builder/CatalogueSheet.js +11 -4
- package/dist/app/builder/CatalogueSheet.js.map +1 -1
- package/dist/app/builder/CellPropsSheet.d.ts +7 -3
- package/dist/app/builder/CellPropsSheet.d.ts.map +1 -1
- package/dist/app/builder/CellPropsSheet.js +10 -3
- package/dist/app/builder/CellPropsSheet.js.map +1 -1
- package/dist/app/builder/DiscardDialog.d.ts +18 -0
- package/dist/app/builder/DiscardDialog.d.ts.map +1 -0
- package/dist/app/builder/DiscardDialog.js +18 -0
- package/dist/app/builder/DiscardDialog.js.map +1 -0
- package/dist/app/builder/LayoutSurface.d.ts +33 -9
- package/dist/app/builder/LayoutSurface.d.ts.map +1 -1
- package/dist/app/builder/LayoutSurface.js +74 -23
- package/dist/app/builder/LayoutSurface.js.map +1 -1
- package/dist/app/builder/PipelineStrip.d.ts +2 -1
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
- package/dist/app/builder/PipelineStrip.js +26 -13
- package/dist/app/builder/PipelineStrip.js.map +1 -1
- package/dist/app/builder/SaveDialog.d.ts +9 -1
- package/dist/app/builder/SaveDialog.d.ts.map +1 -1
- package/dist/app/builder/SaveDialog.js +8 -2
- package/dist/app/builder/SaveDialog.js.map +1 -1
- package/dist/app/builder/Toolbar.d.ts +12 -4
- package/dist/app/builder/Toolbar.d.ts.map +1 -1
- package/dist/app/builder/Toolbar.js +18 -7
- package/dist/app/builder/Toolbar.js.map +1 -1
- package/dist/app/builder/Workspace.d.ts +23 -3
- package/dist/app/builder/Workspace.d.ts.map +1 -1
- package/dist/app/builder/Workspace.js +58 -8
- package/dist/app/builder/Workspace.js.map +1 -1
- package/dist/app/builder/builder-model.d.ts +143 -1
- package/dist/app/builder/builder-model.d.ts.map +1 -1
- package/dist/app/builder/builder-model.js +191 -1
- package/dist/app/builder/builder-model.js.map +1 -1
- package/dist/app/builder/reveal.d.ts +10 -0
- package/dist/app/builder/reveal.d.ts.map +1 -0
- package/dist/app/builder/reveal.js +10 -0
- package/dist/app/builder/reveal.js.map +1 -0
- package/dist/app/builder/use-builder-catalogue.d.ts +4 -1
- package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
- package/dist/app/builder/use-builder-catalogue.js +44 -17
- package/dist/app/builder/use-builder-catalogue.js.map +1 -1
- package/dist/app/builder/use-builder-session.d.ts +30 -0
- package/dist/app/builder/use-builder-session.d.ts.map +1 -0
- package/dist/app/builder/use-builder-session.js +58 -0
- package/dist/app/builder/use-builder-session.js.map +1 -0
- package/dist/app/builder/use-display-resolver.d.ts +17 -0
- package/dist/app/builder/use-display-resolver.d.ts.map +1 -0
- package/dist/app/builder/use-display-resolver.js +16 -0
- package/dist/app/builder/use-display-resolver.js.map +1 -0
- package/dist/app/index.d.ts +8 -3
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +8 -2
- package/dist/app/index.js.map +1 -1
- package/dist/app/layout-builder.d.ts +13 -25
- package/dist/app/layout-builder.d.ts.map +1 -1
- package/dist/app/layout-builder.js +75 -81
- package/dist/app/layout-builder.js.map +1 -1
- package/dist/app/mcp-app-view-chrome.d.ts +12 -3
- package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
- package/dist/app/mcp-app-view-chrome.js +21 -5
- package/dist/app/mcp-app-view-chrome.js.map +1 -1
- package/dist/app/mcp-app-view-states.d.ts +11 -3
- package/dist/app/mcp-app-view-states.d.ts.map +1 -1
- package/dist/app/mcp-app-view-states.js +29 -8
- package/dist/app/mcp-app-view-states.js.map +1 -1
- package/dist/app/mcp-app-view.d.ts +33 -1
- package/dist/app/mcp-app-view.d.ts.map +1 -1
- package/dist/app/mcp-app-view.js +181 -127
- package/dist/app/mcp-app-view.js.map +1 -1
- package/dist/app/mcp-toolkit-app.d.ts +6 -1
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
- package/dist/app/mcp-toolkit-app.js +8 -1
- package/dist/app/mcp-toolkit-app.js.map +1 -1
- package/dist/app/mcp-use-host-bridge.d.ts +15 -6
- package/dist/app/mcp-use-host-bridge.d.ts.map +1 -1
- package/dist/app/mcp-use-host-bridge.js +51 -22
- package/dist/app/mcp-use-host-bridge.js.map +1 -1
- package/dist/app/model-context.d.ts +71 -0
- package/dist/app/model-context.d.ts.map +1 -0
- package/dist/app/model-context.js +101 -0
- package/dist/app/model-context.js.map +1 -0
- package/dist/app/use-build-mode-focus.d.ts +33 -0
- package/dist/app/use-build-mode-focus.d.ts.map +1 -0
- package/dist/app/use-build-mode-focus.js +59 -0
- package/dist/app/use-build-mode-focus.js.map +1 -0
- package/dist/app/use-view-actions.d.ts +31 -0
- package/dist/app/use-view-actions.d.ts.map +1 -0
- package/dist/app/use-view-actions.js +81 -0
- package/dist/app/use-view-actions.js.map +1 -0
- package/dist/app/use-view-lifecycle.d.ts +4 -0
- package/dist/app/use-view-lifecycle.d.ts.map +1 -1
- package/dist/app/use-view-lifecycle.js +2 -0
- package/dist/app/use-view-lifecycle.js.map +1 -1
- package/dist/app/view-lifecycle.d.ts +80 -4
- package/dist/app/view-lifecycle.d.ts.map +1 -1
- package/dist/app/view-lifecycle.js +90 -3
- package/dist/app/view-lifecycle.js.map +1 -1
- package/dist/app/widget-fixture.d.ts +10 -3
- package/dist/app/widget-fixture.d.ts.map +1 -1
- package/dist/app/widget-fixture.js +21 -8
- package/dist/app/widget-fixture.js.map +1 -1
- package/dist/app/widget-props-sheet.d.ts +3 -1
- package/dist/app/widget-props-sheet.d.ts.map +1 -1
- package/dist/app/widget-props-sheet.js +22 -10
- package/dist/app/widget-props-sheet.js.map +1 -1
- package/dist/app/widget-renderer.js +1 -1
- package/dist/app/widget-renderer.js.map +1 -1
- package/dist/components/DrillButton.d.ts +9 -6
- package/dist/components/DrillButton.d.ts.map +1 -1
- package/dist/components/DrillButton.js +8 -6
- package/dist/components/DrillButton.js.map +1 -1
- package/dist/components/EmptyState.d.ts.map +1 -1
- package/dist/components/EmptyState.js +4 -2
- package/dist/components/EmptyState.js.map +1 -1
- package/dist/components/ErrorState.d.ts +5 -2
- package/dist/components/ErrorState.d.ts.map +1 -1
- package/dist/components/ErrorState.js +25 -8
- package/dist/components/ErrorState.js.map +1 -1
- package/dist/components/FilterBar.d.ts +15 -4
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +11 -6
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/KpiGrid.d.ts +66 -21
- package/dist/components/KpiGrid.d.ts.map +1 -1
- package/dist/components/KpiGrid.js +101 -34
- package/dist/components/KpiGrid.js.map +1 -1
- package/dist/components/ListFooter.d.ts +31 -4
- package/dist/components/ListFooter.d.ts.map +1 -1
- package/dist/components/ListFooter.js +30 -11
- package/dist/components/ListFooter.js.map +1 -1
- package/dist/components/PagedListFooter.d.ts +57 -0
- package/dist/components/PagedListFooter.d.ts.map +1 -0
- package/dist/components/PagedListFooter.js +27 -0
- package/dist/components/PagedListFooter.js.map +1 -0
- package/dist/components/Pills.d.ts +27 -7
- package/dist/components/Pills.d.ts.map +1 -1
- package/dist/components/Pills.js +21 -6
- package/dist/components/Pills.js.map +1 -1
- package/dist/components/SectionHeading.d.ts +3 -1
- package/dist/components/SectionHeading.d.ts.map +1 -1
- package/dist/components/SectionHeading.js +6 -2
- package/dist/components/SectionHeading.js.map +1 -1
- package/dist/components/Toast.d.ts +9 -3
- package/dist/components/Toast.d.ts.map +1 -1
- package/dist/components/Toast.js +31 -16
- package/dist/components/Toast.js.map +1 -1
- package/dist/components/WidgetHeader.d.ts +34 -10
- package/dist/components/WidgetHeader.d.ts.map +1 -1
- package/dist/components/WidgetHeader.js +11 -6
- package/dist/components/WidgetHeader.js.map +1 -1
- package/dist/hooks/index.d.ts +4 -4
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/tool-result-recovery-model.d.ts +155 -0
- package/dist/hooks/tool-result-recovery-model.d.ts.map +1 -0
- package/dist/hooks/tool-result-recovery-model.js +273 -0
- package/dist/hooks/tool-result-recovery-model.js.map +1 -0
- package/dist/hooks/use-tool-query.d.ts +56 -14
- package/dist/hooks/use-tool-query.d.ts.map +1 -1
- package/dist/hooks/use-tool-query.js +102 -25
- package/dist/hooks/use-tool-query.js.map +1 -1
- package/dist/hooks/use-tool-result-recovery.d.ts +47 -52
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
- package/dist/hooks/use-tool-result-recovery.js +58 -120
- package/dist/hooks/use-tool-result-recovery.js.map +1 -1
- package/dist/hooks/use-view-data.d.ts +52 -10
- package/dist/hooks/use-view-data.d.ts.map +1 -1
- package/dist/hooks/use-view-data.js +81 -16
- package/dist/hooks/use-view-data.js.map +1 -1
- package/dist/hooks/use-view-tool-query.d.ts +12 -7
- package/dist/hooks/use-view-tool-query.d.ts.map +1 -1
- package/dist/hooks/use-view-tool-query.js +15 -14
- package/dist/hooks/use-view-tool-query.js.map +1 -1
- package/dist/index.d.ts +17 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/focus-return.d.ts +61 -0
- package/dist/lib/focus-return.d.ts.map +1 -0
- package/dist/lib/focus-return.js +46 -0
- package/dist/lib/focus-return.js.map +1 -0
- package/dist/lib/parse-tool-result.d.ts +23 -1
- package/dist/lib/parse-tool-result.d.ts.map +1 -1
- package/dist/lib/parse-tool-result.js +38 -2
- package/dist/lib/parse-tool-result.js.map +1 -1
- package/dist/lib/toast-model.d.ts +41 -1
- package/dist/lib/toast-model.d.ts.map +1 -1
- package/dist/lib/toast-model.js +67 -1
- package/dist/lib/toast-model.js.map +1 -1
- package/dist/lib/tone-utils.d.ts +58 -6
- package/dist/lib/tone-utils.d.ts.map +1 -1
- package/dist/lib/tone-utils.js +66 -4
- package/dist/lib/tone-utils.js.map +1 -1
- package/dist/lib/tool-query.d.ts +107 -0
- package/dist/lib/tool-query.d.ts.map +1 -0
- package/dist/lib/tool-query.js +182 -0
- package/dist/lib/tool-query.js.map +1 -0
- package/dist/lib/tool-result-observer.d.ts +108 -0
- package/dist/lib/tool-result-observer.d.ts.map +1 -0
- package/dist/lib/tool-result-observer.js +158 -0
- package/dist/lib/tool-result-observer.js.map +1 -0
- package/dist/lib/typography.d.ts +37 -0
- package/dist/lib/typography.d.ts.map +1 -0
- package/dist/lib/typography.js +41 -0
- package/dist/lib/typography.js.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +11 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/locale/index.d.ts +1 -1
- package/dist/locale/index.d.ts.map +1 -1
- package/dist/locale/message-types.d.ts +117 -4
- package/dist/locale/message-types.d.ts.map +1 -1
- package/dist/locale/messages-de.d.ts.map +1 -1
- package/dist/locale/messages-de.js +44 -10
- package/dist/locale/messages-de.js.map +1 -1
- package/dist/locale/messages-en.d.ts.map +1 -1
- package/dist/locale/messages-en.js +44 -10
- package/dist/locale/messages-en.js.map +1 -1
- package/dist/locale/toolkit-messages.d.ts +19 -1
- package/dist/locale/toolkit-messages.d.ts.map +1 -1
- package/dist/locale/toolkit-messages.js +54 -1
- package/dist/locale/toolkit-messages.js.map +1 -1
- package/dist/primitives/alert.d.ts +1 -1
- package/dist/primitives/alert.d.ts.map +1 -1
- package/dist/primitives/alert.js +2 -0
- package/dist/primitives/alert.js.map +1 -1
- package/dist/primitives/badge.d.ts +1 -1
- package/dist/primitives/badge.d.ts.map +1 -1
- package/dist/primitives/badge.js +9 -4
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.d.ts +1 -1
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/button.js.map +1 -1
- package/dist/primitives/dialog.d.ts +1 -1
- package/dist/primitives/dialog.d.ts.map +1 -1
- package/dist/primitives/dialog.js +10 -3
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/select.js +1 -1
- package/dist/primitives/select.js.map +1 -1
- package/dist/primitives/sheet.d.ts +1 -1
- package/dist/primitives/sheet.d.ts.map +1 -1
- package/dist/primitives/sheet.js +6 -2
- package/dist/primitives/sheet.js.map +1 -1
- package/dist/providers/query-provider.d.ts +32 -1
- package/dist/providers/query-provider.d.ts.map +1 -1
- package/dist/providers/query-provider.js +53 -4
- package/dist/providers/query-provider.js.map +1 -1
- package/dist/render-cases-primitives.js +1 -1
- package/dist/render-cases-primitives.js.map +1 -1
- package/dist/render-cases.d.ts.map +1 -1
- package/dist/render-cases.js +30 -6
- package/dist/render-cases.js.map +1 -1
- package/dist/render-effects.d.ts +42 -0
- package/dist/render-effects.d.ts.map +1 -0
- package/dist/render-effects.js +81 -0
- package/dist/render-effects.js.map +1 -0
- package/dist/theme/create-theme.d.ts +19 -1
- package/dist/theme/create-theme.d.ts.map +1 -1
- package/dist/theme/create-theme.js +15 -0
- package/dist/theme/create-theme.js.map +1 -1
- package/package.json +5 -4
- package/src/app/adapt-data-widget.tsx +2 -42
- package/src/app/builder/BuilderBanners.tsx +1 -1
- package/src/app/builder/CanvasRow.tsx +63 -17
- package/src/app/builder/CatalogueSheet.tsx +50 -29
- package/src/app/builder/CellPropsSheet.tsx +17 -2
- package/src/app/builder/DiscardDialog.tsx +59 -0
- package/src/app/builder/LayoutSurface.tsx +206 -66
- package/src/app/builder/PipelineStrip.tsx +253 -153
- package/src/app/builder/SaveDialog.tsx +14 -2
- package/src/app/builder/Toolbar.tsx +144 -59
- package/src/app/builder/Workspace.tsx +226 -58
- package/src/app/builder/builder-model.ts +341 -2
- package/src/app/builder/builder-model.ux.test.ts +456 -0
- package/src/app/builder/builder-ux.test.tsx +844 -0
- package/src/app/builder/reveal.ts +10 -0
- package/src/app/builder/use-builder-catalogue.ts +56 -19
- package/src/app/builder/use-builder-session.ts +68 -0
- package/src/app/builder/use-display-resolver.ts +24 -0
- package/src/app/index.ts +12 -2
- package/src/app/layout-builder.tsx +178 -191
- package/src/app/mcp-app-view-chrome.test.tsx +141 -1
- package/src/app/mcp-app-view-chrome.tsx +56 -6
- package/src/app/mcp-app-view-states.tsx +51 -11
- package/src/app/mcp-app-view.effects.test.tsx +292 -0
- package/src/app/mcp-app-view.test.tsx +222 -2
- package/src/app/mcp-app-view.tsx +267 -117
- package/src/app/mcp-toolkit-app.test.tsx +40 -0
- package/src/app/mcp-toolkit-app.tsx +8 -1
- package/src/app/mcp-use-host-bridge.test.tsx +180 -0
- package/src/app/mcp-use-host-bridge.tsx +67 -24
- package/src/app/model-context.test.tsx +116 -0
- package/src/app/model-context.tsx +125 -0
- package/src/app/use-build-mode-focus.ts +62 -0
- package/src/app/use-view-actions.ts +89 -0
- package/src/app/use-view-lifecycle.ts +6 -0
- package/src/app/view-lifecycle.test.ts +216 -0
- package/src/app/view-lifecycle.ts +165 -5
- package/src/app/widget-fixture.effects.test.tsx +51 -0
- package/src/app/widget-fixture.render.test.tsx +81 -0
- package/src/app/widget-fixture.tsx +34 -11
- package/src/app/widget-props-sheet.tsx +57 -16
- package/src/app/widget-renderer.tsx +1 -1
- package/src/components/DrillButton.tsx +23 -10
- package/src/components/EmptyState.tsx +6 -4
- package/src/components/ErrorState.tsx +31 -9
- package/src/components/FilterBar.test.tsx +82 -0
- package/src/components/FilterBar.tsx +52 -26
- package/src/components/KpiGrid.test.tsx +279 -0
- package/src/components/KpiGrid.tsx +297 -90
- package/src/components/ListFooter.test.tsx +116 -0
- package/src/components/ListFooter.tsx +102 -15
- package/src/components/PagedListFooter.test.tsx +140 -0
- package/src/components/PagedListFooter.tsx +107 -0
- package/src/components/Pills.test.tsx +77 -0
- package/src/components/Pills.tsx +63 -10
- package/src/components/SectionHeading.tsx +9 -3
- package/src/components/Toast.tsx +37 -19
- package/src/components/WidgetHeader.test.tsx +78 -0
- package/src/components/WidgetHeader.tsx +63 -16
- package/src/components/feedback-states.test.tsx +98 -9
- package/src/components/tone-figures.test.tsx +8 -4
- package/src/hooks/index.ts +6 -3
- package/src/hooks/tool-result-recovery-model.test.ts +744 -0
- package/src/hooks/tool-result-recovery-model.ts +418 -0
- package/src/hooks/use-tool-query.effects.test.tsx +205 -0
- package/src/hooks/use-tool-query.ts +156 -33
- package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
- package/src/hooks/use-tool-result-recovery.test.ts +3 -4
- package/src/hooks/use-tool-result-recovery.ts +84 -142
- package/src/hooks/use-view-data.test.tsx +118 -9
- package/src/hooks/use-view-data.ts +128 -18
- package/src/hooks/use-view-tool-query.ts +25 -19
- package/src/i18n-coverage.test.tsx +104 -2
- package/src/index.ts +48 -11
- package/src/lib/focus-return.test.ts +288 -0
- package/src/lib/focus-return.ts +96 -0
- package/src/lib/parse-tool-result.test.ts +46 -1
- package/src/lib/parse-tool-result.ts +40 -2
- package/src/lib/toast-model.test.ts +166 -1
- package/src/lib/toast-model.ts +104 -2
- package/src/lib/tone-utils.test.ts +86 -10
- package/src/lib/tone-utils.ts +89 -8
- package/src/lib/tool-query.test.ts +569 -0
- package/src/lib/tool-query.ts +253 -0
- package/src/lib/tool-result-observer.test.ts +296 -0
- package/src/lib/tool-result-observer.ts +211 -0
- package/src/lib/typography.test.ts +45 -0
- package/src/lib/typography.ts +47 -0
- package/src/lib/utils.ts +12 -1
- package/src/locale/index.ts +1 -0
- package/src/locale/message-types.ts +118 -2
- package/src/locale/messages-de.ts +49 -10
- package/src/locale/messages-en.ts +49 -10
- package/src/locale/toolkit-messages.test.ts +133 -0
- package/src/locale/toolkit-messages.ts +63 -2
- package/src/primitives/alert.tsx +3 -0
- package/src/primitives/badge.tsx +9 -4
- package/src/primitives/button.tsx +1 -1
- package/src/primitives/dialog.tsx +10 -1
- package/src/primitives/select.tsx +1 -1
- package/src/primitives/sheet.tsx +7 -0
- package/src/providers/query-provider.test.tsx +154 -0
- package/src/providers/query-provider.tsx +66 -5
- package/src/render-cases-primitives.tsx +1 -1
- package/src/render-cases.tsx +38 -6
- package/src/render-effects.tsx +96 -0
- package/src/theme/cd-tokens.test.ts +3 -1
- package/src/theme/create-theme.test.ts +10 -0
- package/src/theme/create-theme.ts +28 -0
- package/src/theme/theme-css.test.ts +51 -0
- package/src/theme.css +31 -1
- package/ui-catalog.json +448 -41
|
@@ -1,48 +1,49 @@
|
|
|
1
|
+
import { type ToolResultObserver } from "../lib/tool-result-observer.js";
|
|
2
|
+
import { type RecoveryPolicy, type ToolResultRecoveryState } from "./tool-result-recovery-model.js";
|
|
3
|
+
export { decodeRecoveredResult } from "./tool-result-recovery-model.js";
|
|
4
|
+
export type { RecoveryBlockReason, RecoveryPolicy, ToolResultRecoveryState, ToolSafety, } from "./tool-result-recovery-model.js";
|
|
1
5
|
/**
|
|
2
6
|
* Recovery for hosts that deliver the `ui/notifications/tool-result`
|
|
3
7
|
* notification without `structuredContent` (observed on claude.ai and Claude
|
|
4
|
-
* Desktop, which forward only the model-facing `content` blocks).
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* forever and the shell would idle on its loading skeleton.
|
|
8
|
+
* Desktop, which forward only the model-facing `content` blocks). mcp-use
|
|
9
|
+
* 2.x's `useToolContext` latch ignores such a content-only result, so its
|
|
10
|
+
* status stays `"pending"` forever and the shell would idle on its skeleton.
|
|
8
11
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* result has latched within
|
|
13
|
-
* {@link ToolResultRecoveryOptions.assumeStrippedAfterMs}, the result is
|
|
14
|
-
* assumed delivered-but-stripped. Either way the hook re-executes the
|
|
15
|
-
* originating tool once via the host bridge's official `callTool` — tool-call
|
|
16
|
-
* RESPONSES carry `structuredContent` intact on those hosts — and exposes the
|
|
17
|
-
* decoded payload. Spec-conforming hosts (e.g. the mcp-use inspector) deliver
|
|
18
|
-
* a valid payload up front, so the recovery never fires there.
|
|
12
|
+
* The hook re-executes the originating tool once via the host bridge's
|
|
13
|
+
* `callTool` — tool-call RESPONSES carry `structuredContent` intact on those
|
|
14
|
+
* hosts — and exposes the decoded payload. When it does so (toolkit#176):
|
|
19
15
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
16
|
+
* - **Only when the host stripped the result.** A passive observer of the
|
|
17
|
+
* host's lifecycle notifications (`installToolResultObserver`) sees the
|
|
18
|
+
* content-only result itself, so the recovery fires as it arrives, and a
|
|
19
|
+
* slow tool on a compliant host is never re-run (K13): no result has
|
|
20
|
+
* arrived because none was sent. Where the observer cannot vouch for that
|
|
21
|
+
* (no browser frame, or installed after the handshake), the 2.x grace timer
|
|
22
|
+
* ({@link ToolResultRecoveryOptions.assumeStrippedAfterMs}) still infers a
|
|
23
|
+
* stripped result, once the call's arguments arrived.
|
|
24
|
+
* - **With the call's complete arguments** (N21): the observer's complete
|
|
25
|
+
* `tool-input`, never a partial stream; an equal re-delivery is the same run.
|
|
26
|
+
* - **Never for a cancelled or failed call:** re-running repeats the failure
|
|
27
|
+
* or overrides the user's stop; the shell renders that state and offers an
|
|
28
|
+
* explicit retry.
|
|
29
|
+
* - **Only for a tool the policy allows** ({@link ToolResultRecoveryOptions.policy}):
|
|
30
|
+
* by default never one the host reports as writing (`readOnlyHint: false`
|
|
31
|
+
* or `destructiveHint: true` in `hostContext.toolInfo.tool.annotations`).
|
|
32
|
+
* A blocked recovery is reported (`blocked`) so the view can show its error.
|
|
27
33
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* repeat, and may rarely run concurrently with the original invocation when
|
|
31
|
-
* the grace timer beats a slow but conforming host.
|
|
34
|
+
* The decision and its timer live in `createRecoveryController`; this hook
|
|
35
|
+
* only binds it to React.
|
|
32
36
|
*/
|
|
33
37
|
/**
|
|
34
|
-
* Default grace period before a silent latch counts as a stripped result
|
|
35
|
-
*
|
|
36
|
-
* short enough that users on stripping hosts are not left staring at the
|
|
37
|
-
* skeleton noticeably.
|
|
38
|
+
* Default grace period before a silent latch counts as a stripped result —
|
|
39
|
+
* used only where the transport observer cannot vouch that nothing arrived.
|
|
38
40
|
*/
|
|
39
41
|
export declare const DEFAULT_ASSUME_STRIPPED_AFTER_MS = 2500;
|
|
40
42
|
export interface ToolResultRecoveryOptions {
|
|
41
43
|
/**
|
|
42
44
|
* The latch fired (`useToolContext().status !== "pending"`) — a structured
|
|
43
45
|
* result, a tool error, or a host cancellation arrived. On hosts that strip
|
|
44
|
-
* `structuredContent` this never turns true
|
|
45
|
-
* that case.
|
|
46
|
+
* `structuredContent` this never turns true.
|
|
46
47
|
*/
|
|
47
48
|
resultReady: boolean;
|
|
48
49
|
/**
|
|
@@ -61,10 +62,7 @@ export interface ToolResultRecoveryOptions {
|
|
|
61
62
|
errored?: boolean;
|
|
62
63
|
/** The payload the host delivered (`useToolContext().toolOutput`). */
|
|
63
64
|
props: unknown;
|
|
64
|
-
/**
|
|
65
|
-
* Validates a candidate payload. MUST be referentially stable (module-level
|
|
66
|
-
* function or memoised) — it is an effect dependency.
|
|
67
|
-
*/
|
|
65
|
+
/** Validates a candidate payload. */
|
|
68
66
|
isValid: (value: unknown) => boolean;
|
|
69
67
|
/** The tool arguments from `ui/notifications/tool-input` (`useToolContext().toolInput`). */
|
|
70
68
|
toolInput: Record<string, unknown> | null | undefined;
|
|
@@ -74,18 +72,19 @@ export interface ToolResultRecoveryOptions {
|
|
|
74
72
|
callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
75
73
|
/**
|
|
76
74
|
* Grace period in ms after which a silent latch counts as a stripped
|
|
77
|
-
* result.
|
|
78
|
-
*
|
|
79
|
-
* arguments mean the invocation may not have finished yet. Defaults to
|
|
75
|
+
* result. Applies only where the transport observer cannot vouch that no
|
|
76
|
+
* result arrived (see above); restarts for new arguments. Defaults to
|
|
80
77
|
* {@link DEFAULT_ASSUME_STRIPPED_AFTER_MS}.
|
|
81
78
|
*/
|
|
82
79
|
assumeStrippedAfterMs?: number;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
/** Which tools may be re-executed on their own. Default `"auto"`. */
|
|
81
|
+
policy?: RecoveryPolicy;
|
|
82
|
+
/**
|
|
83
|
+
* The transport observer. Defaults to the document's
|
|
84
|
+
* (`installToolResultObserver()`); `null` disables it, leaving the grace
|
|
85
|
+
* timer to decide alone (the 2.x behaviour).
|
|
86
|
+
*/
|
|
87
|
+
observer?: ToolResultObserver | null;
|
|
89
88
|
}
|
|
90
89
|
/**
|
|
91
90
|
* Resolves the originating tool name from the host context's `toolInfo`.
|
|
@@ -94,14 +93,10 @@ export interface ToolResultRecoveryState<T> {
|
|
|
94
93
|
*/
|
|
95
94
|
export declare function resolveRecoveryToolName(hostContext: unknown): string | undefined;
|
|
96
95
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Whether the recovery may fire: the result latched (or is assumed stripped)
|
|
103
|
-
* and the call was neither cancelled nor failed. Exported for tests — this is
|
|
104
|
-
* the #176 rule "never recover on an error status".
|
|
96
|
+
* Whether a latched or assumed-stripped result may be recovered at all: the
|
|
97
|
+
* call was neither cancelled nor failed. Kept for existing imports; the full
|
|
98
|
+
* rule (observer, policy, arguments) is `decideRecovery`.
|
|
99
|
+
* @deprecated Use `decideRecovery` from the recovery model.
|
|
105
100
|
*/
|
|
106
101
|
export declare function isRecoveryReady(state: {
|
|
107
102
|
resultReady: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-tool-result-recovery.d.ts","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-tool-result-recovery.d.ts","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,KAAK,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnG,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC7B,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AACvE,YAAY,EACV,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,UAAU,GACX,MAAM,iCAAiC,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;GAGG;AACH,eAAO,MAAM,gCAAgC,OAAO,CAAA;AAEpD,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,WAAW,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sEAAsE;IACtE,KAAK,EAAE,OAAO,CAAA;IACd,qCAAqC;IACrC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;IACpC,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IACrD,gGAAgG;IAChG,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IACvD,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3E;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,qEAAqE;IACrE,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAA;CACrC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAehF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,WAAW,EAAE,OAAO,CAAA;IACpB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;CACjB,GAAG,OAAO,CAGV;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,yBAAyB,GACjC,uBAAuB,CAAC,CAAC,CAAC,CAyC5B"}
|
|
@@ -1,45 +1,44 @@
|
|
|
1
|
-
import { useEffect,
|
|
2
|
-
import {
|
|
1
|
+
import { useEffect, useState, useSyncExternalStore } from "react";
|
|
2
|
+
import { installToolResultObserver } from "../lib/tool-result-observer.js";
|
|
3
|
+
import { createRecoveryController, } from "./tool-result-recovery-model.js";
|
|
4
|
+
export { decodeRecoveredResult } from "./tool-result-recovery-model.js";
|
|
3
5
|
/**
|
|
4
6
|
* Recovery for hosts that deliver the `ui/notifications/tool-result`
|
|
5
7
|
* notification without `structuredContent` (observed on claude.ai and Claude
|
|
6
|
-
* Desktop, which forward only the model-facing `content` blocks).
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* forever and the shell would idle on its loading skeleton.
|
|
8
|
+
* Desktop, which forward only the model-facing `content` blocks). mcp-use
|
|
9
|
+
* 2.x's `useToolContext` latch ignores such a content-only result, so its
|
|
10
|
+
* status stays `"pending"` forever and the shell would idle on its skeleton.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* result has latched within
|
|
15
|
-
* {@link ToolResultRecoveryOptions.assumeStrippedAfterMs}, the result is
|
|
16
|
-
* assumed delivered-but-stripped. Either way the hook re-executes the
|
|
17
|
-
* originating tool once via the host bridge's official `callTool` — tool-call
|
|
18
|
-
* RESPONSES carry `structuredContent` intact on those hosts — and exposes the
|
|
19
|
-
* decoded payload. Spec-conforming hosts (e.g. the mcp-use inspector) deliver
|
|
20
|
-
* a valid payload up front, so the recovery never fires there.
|
|
12
|
+
* The hook re-executes the originating tool once via the host bridge's
|
|
13
|
+
* `callTool` — tool-call RESPONSES carry `structuredContent` intact on those
|
|
14
|
+
* hosts — and exposes the decoded payload. When it does so (toolkit#176):
|
|
21
15
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
16
|
+
* - **Only when the host stripped the result.** A passive observer of the
|
|
17
|
+
* host's lifecycle notifications (`installToolResultObserver`) sees the
|
|
18
|
+
* content-only result itself, so the recovery fires as it arrives, and a
|
|
19
|
+
* slow tool on a compliant host is never re-run (K13): no result has
|
|
20
|
+
* arrived because none was sent. Where the observer cannot vouch for that
|
|
21
|
+
* (no browser frame, or installed after the handshake), the 2.x grace timer
|
|
22
|
+
* ({@link ToolResultRecoveryOptions.assumeStrippedAfterMs}) still infers a
|
|
23
|
+
* stripped result, once the call's arguments arrived.
|
|
24
|
+
* - **With the call's complete arguments** (N21): the observer's complete
|
|
25
|
+
* `tool-input`, never a partial stream; an equal re-delivery is the same run.
|
|
26
|
+
* - **Never for a cancelled or failed call:** re-running repeats the failure
|
|
27
|
+
* or overrides the user's stop; the shell renders that state and offers an
|
|
28
|
+
* explicit retry.
|
|
29
|
+
* - **Only for a tool the policy allows** ({@link ToolResultRecoveryOptions.policy}):
|
|
30
|
+
* by default never one the host reports as writing (`readOnlyHint: false`
|
|
31
|
+
* or `destructiveHint: true` in `hostContext.toolInfo.tool.annotations`).
|
|
32
|
+
* A blocked recovery is reported (`blocked`) so the view can show its error.
|
|
29
33
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* repeat, and may rarely run concurrently with the original invocation when
|
|
33
|
-
* the grace timer beats a slow but conforming host.
|
|
34
|
+
* The decision and its timer live in `createRecoveryController`; this hook
|
|
35
|
+
* only binds it to React.
|
|
34
36
|
*/
|
|
35
37
|
/**
|
|
36
|
-
* Default grace period before a silent latch counts as a stripped result
|
|
37
|
-
*
|
|
38
|
-
* short enough that users on stripping hosts are not left staring at the
|
|
39
|
-
* skeleton noticeably.
|
|
38
|
+
* Default grace period before a silent latch counts as a stripped result —
|
|
39
|
+
* used only where the transport observer cannot vouch that nothing arrived.
|
|
40
40
|
*/
|
|
41
41
|
export const DEFAULT_ASSUME_STRIPPED_AFTER_MS = 2500;
|
|
42
|
-
const IDLE = { data: null, failed: false };
|
|
43
42
|
/**
|
|
44
43
|
* Resolves the originating tool name from the host context's `toolInfo`.
|
|
45
44
|
* Reads the SEP-1865 shape first (`toolInfo.tool.name`), then the flattened
|
|
@@ -65,23 +64,10 @@ export function resolveRecoveryToolName(hostContext) {
|
|
|
65
64
|
return undefined;
|
|
66
65
|
}
|
|
67
66
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
let decoded;
|
|
73
|
-
try {
|
|
74
|
-
decoded = parseToolResult(result);
|
|
75
|
-
}
|
|
76
|
-
catch {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
return decoded !== null && isValid(decoded) ? decoded : null;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Whether the recovery may fire: the result latched (or is assumed stripped)
|
|
83
|
-
* and the call was neither cancelled nor failed. Exported for tests — this is
|
|
84
|
-
* the #176 rule "never recover on an error status".
|
|
67
|
+
* Whether a latched or assumed-stripped result may be recovered at all: the
|
|
68
|
+
* call was neither cancelled nor failed. Kept for existing imports; the full
|
|
69
|
+
* rule (observer, policy, arguments) is `decideRecovery`.
|
|
70
|
+
* @deprecated Use `decideRecovery` from the recovery model.
|
|
85
71
|
*/
|
|
86
72
|
export function isRecoveryReady(state) {
|
|
87
73
|
if (state.cancelled || state.errored)
|
|
@@ -89,79 +75,31 @@ export function isRecoveryReady(state) {
|
|
|
89
75
|
return state.resultReady || state.assumedReady;
|
|
90
76
|
}
|
|
91
77
|
export function useToolResultRecovery(options) {
|
|
92
|
-
const { resultReady, cancelled = false, errored = false, props, isValid, toolInput, hostContext, callTool, assumeStrippedAfterMs = DEFAULT_ASSUME_STRIPPED_AFTER_MS, } = options;
|
|
93
|
-
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const flightInputRef = useRef(null);
|
|
99
|
-
const toolName = resolveRecoveryToolName(hostContext);
|
|
100
|
-
// A stripped result is unobservable (the 2.x latch ignores content-only
|
|
101
|
-
// results), so infer it: once a recovery could fire but the latch has been
|
|
102
|
-
// silent for the grace period, treat the result as delivered-but-stripped.
|
|
103
|
-
// Re-armed on every toolInput identity change — streaming arguments mean
|
|
104
|
-
// the invocation may still be running, so the grace period starts over.
|
|
105
|
-
// The re-arm is a render-phase reset (not an effect) so the cascading-
|
|
106
|
-
// render lint stays satisfied; the timer effect below restarts anyway
|
|
107
|
-
// because toolInput is one of its dependencies.
|
|
108
|
-
const [assumedReady, setAssumedReady] = useState(false);
|
|
109
|
-
const [prevTimerInput, setPrevTimerInput] = useState(toolInput);
|
|
110
|
-
if (prevTimerInput !== toolInput) {
|
|
111
|
-
setPrevTimerInput(toolInput);
|
|
112
|
-
if (assumedReady)
|
|
113
|
-
setAssumedReady(false);
|
|
114
|
-
}
|
|
115
|
-
const suppressed = cancelled || errored;
|
|
78
|
+
const { resultReady, cancelled = false, errored = false, props, isValid, toolInput, hostContext, callTool, assumeStrippedAfterMs = DEFAULT_ASSUME_STRIPPED_AFTER_MS, policy = "auto", observer, } = options;
|
|
79
|
+
// One controller per mount; it survives StrictMode's effect re-run, so an
|
|
80
|
+
// in-flight call is never fired twice.
|
|
81
|
+
const [controller] = useState(() => createRecoveryController({
|
|
82
|
+
observer: observer === undefined ? installToolResultObserver() : observer,
|
|
83
|
+
}));
|
|
116
84
|
useEffect(() => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return () => clearTimeout(timer);
|
|
121
|
-
}, [resultReady, suppressed, toolName, toolInput, assumeStrippedAfterMs]);
|
|
122
|
-
// A cancelled or failed call never counts as ready, so the effect below
|
|
123
|
-
// invalidates any in-flight attempt the same way it does for a superseded run.
|
|
124
|
-
const ready = isRecoveryReady({ resultReady, assumedReady, cancelled, errored });
|
|
85
|
+
controller.start();
|
|
86
|
+
return () => controller.stop();
|
|
87
|
+
}, [controller]);
|
|
125
88
|
useEffect(() => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
flightRef.current = (async () => {
|
|
139
|
-
try {
|
|
140
|
-
const result = await callTool(toolName, toolInput ?? {});
|
|
141
|
-
const data = decodeRecoveredResult(result, isValid);
|
|
142
|
-
if (data !== null)
|
|
143
|
-
return { data, failed: false };
|
|
144
|
-
console.warn(`[mcp-toolkit] tool-result recovery: re-executing "${toolName}" returned no usable payload`);
|
|
145
|
-
return { data: null, failed: true };
|
|
146
|
-
}
|
|
147
|
-
catch (err) {
|
|
148
|
-
console.warn(`[mcp-toolkit] tool-result recovery for "${toolName}" failed:`, err);
|
|
149
|
-
return { data: null, failed: true };
|
|
150
|
-
}
|
|
151
|
-
})();
|
|
152
|
-
}
|
|
153
|
-
const flight = flightRef.current;
|
|
154
|
-
let stale = false;
|
|
155
|
-
void flight.then((outcome) => {
|
|
156
|
-
// Drop the outcome when this subscription was superseded or the flight
|
|
157
|
-
// was invalidated by a newer tool run.
|
|
158
|
-
if (!stale && flightRef.current === flight)
|
|
159
|
-
setState(outcome);
|
|
89
|
+
controller.update({
|
|
90
|
+
resultReady,
|
|
91
|
+
cancelled,
|
|
92
|
+
errored,
|
|
93
|
+
props,
|
|
94
|
+
isValid,
|
|
95
|
+
toolInput,
|
|
96
|
+
hostContext,
|
|
97
|
+
callTool,
|
|
98
|
+
policy,
|
|
99
|
+
graceMs: assumeStrippedAfterMs,
|
|
100
|
+
resolveToolName: resolveRecoveryToolName,
|
|
160
101
|
});
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
};
|
|
164
|
-
}, [ready, props, isValid, toolName, toolInput, callTool]);
|
|
165
|
-
return state;
|
|
102
|
+
});
|
|
103
|
+
return useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
|
|
166
104
|
}
|
|
167
105
|
//# sourceMappingURL=use-tool-result-recovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-tool-result-recovery.js","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"use-tool-result-recovery.js","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,yBAAyB,EAA2B,MAAM,gCAAgC,CAAA;AACnG,OAAO,EACL,wBAAwB,GAGzB,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAQvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,IAAI,CAAA;AAkDpD;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAAoB;IAC1D,IAAI,CAAC,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IACrE,MAAM,IAAI,GAAI,WAAuC,CAAC,QAAQ,CAAA;IAC9D,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IACvD,MAAM,GAAG,GAAG,IAA+B,CAAA;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAA;IACrB,MAAM,UAAU,GAAG;QACjB,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAgC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACrF,GAAG,CAAC,IAAI;QACR,GAAG,CAAC,QAAQ;KACb,CAAA;IACD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;IAC7E,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAK/B;IACC,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IAClD,OAAO,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,YAAY,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAAkC;IAElC,MAAM,EACJ,WAAW,EACX,SAAS,GAAG,KAAK,EACjB,OAAO,GAAG,KAAK,EACf,KAAK,EACL,OAAO,EACP,SAAS,EACT,WAAW,EACX,QAAQ,EACR,qBAAqB,GAAG,gCAAgC,EACxD,MAAM,GAAG,MAAM,EACf,QAAQ,GACT,GAAG,OAAO,CAAA;IACX,0EAA0E;IAC1E,uCAAuC;IACvC,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CACjC,wBAAwB,CAAI;QAC1B,QAAQ,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,yBAAyB,EAAE,CAAC,CAAC,CAAC,QAAQ;KAC1E,CAAC,CACH,CAAA;IACD,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,KAAK,EAAE,CAAA;QAClB,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,CAAA;IAChC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAChB,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,MAAM,CAAC;YAChB,WAAW;YACX,SAAS;YACT,OAAO;YACP,KAAK;YACL,OAAO;YACP,SAAS;YACT,WAAW;YACX,QAAQ;YACR,MAAM;YACN,OAAO,EAAE,qBAAqB;YAC9B,eAAe,EAAE,uBAAuB;SACzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,OAAO,oBAAoB,CAAC,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;AAC7F,CAAC"}
|
|
@@ -1,25 +1,67 @@
|
|
|
1
|
+
import { type UseToolQueryOptions } from "../lib/tool-query.js";
|
|
1
2
|
export interface ViewDataResult<T> {
|
|
2
3
|
data: T | null;
|
|
3
4
|
/** True while self-fetching with no data yet — the first paint of a cockpit cell. */
|
|
4
5
|
loading: boolean;
|
|
5
6
|
error: Error | null;
|
|
6
7
|
/**
|
|
7
|
-
* Fetch `tool` again: the retry of an error state
|
|
8
|
-
* (`<ErrorState onRetry={refetch} … />`)
|
|
9
|
-
*
|
|
8
|
+
* Fetch `tool` again now: the retry of an error state
|
|
9
|
+
* (`<ErrorState onRetry={refetch} … />`) or a manual refresh — a new read
|
|
10
|
+
* even while a failed fetch still waits on its retry backoff. In `"static"`
|
|
11
|
+
* mode host-pushed data, when present, stays what `data` returns.
|
|
10
12
|
*/
|
|
11
13
|
refetch: () => void;
|
|
14
|
+
/** Failed attempts of the current fetch (0 once it succeeds). */
|
|
15
|
+
failureCount: number;
|
|
16
|
+
/**
|
|
17
|
+
* The current fetch's last failed attempt — set from the first failure on,
|
|
18
|
+
* while the query still retries (`error` waits for the last retry).
|
|
19
|
+
*/
|
|
20
|
+
failureReason: Error | null;
|
|
21
|
+
/** A fetch is in flight (the first one or a refetch). */
|
|
22
|
+
isFetching: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* `data` is a placeholder (`placeholderData`, e.g. `keepPreviousData`):
|
|
25
|
+
* the previous args' answer while the current args' fetch runs or failed.
|
|
26
|
+
*/
|
|
27
|
+
isPlaceholderData: boolean;
|
|
12
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* How {@link useViewData} treats host-pushed `initialData`.
|
|
31
|
+
*
|
|
32
|
+
* - `"static"` (default): returned verbatim; the feed query stays off while
|
|
33
|
+
* it is present.
|
|
34
|
+
* - `"seed"`: it becomes the feed query's cached answer, and the query stays
|
|
35
|
+
* live (once `ready`): an invalidation after a write, a `refetch` or a
|
|
36
|
+
* retry re-reads the feed. A fresh seed is not refetched on mount (it is
|
|
37
|
+
* younger than `staleTime`); a payload delivered anew (content not seeded
|
|
38
|
+
* for the key before) replaces the cached answer, while a re-rendered or
|
|
39
|
+
* remounted old one never rolls a refetched answer back.
|
|
40
|
+
*/
|
|
41
|
+
export type ViewDataMode = "static" | "seed";
|
|
42
|
+
/**
|
|
43
|
+
* Options of {@link useViewData}: TanStack's query options for the feed
|
|
44
|
+
* (`retry`, `retryDelay`, `staleTime`, `placeholderData` /
|
|
45
|
+
* `keepPreviousData`, `enabled` as an extra gate next to `ready`, …),
|
|
46
|
+
* plus how host data seeds it.
|
|
47
|
+
*/
|
|
48
|
+
export type UseViewDataOptions<T> = Omit<UseToolQueryOptions<T>, "initialData" | "select"> & {
|
|
49
|
+
initialDataMode?: ViewDataMode;
|
|
50
|
+
};
|
|
13
51
|
/**
|
|
14
52
|
* The seam that lets one widget component serve both modes without a duplicate UI.
|
|
15
53
|
*
|
|
16
54
|
* Standalone (a `*_show_*` widget) the agent's tool result is handed in via
|
|
17
|
-
* `initialData` (from the view's stepData, e.g. through `adaptDataWidget`)
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
55
|
+
* `initialData` (from the view's stepData, e.g. through `adaptDataWidget`).
|
|
56
|
+
* Embedded in a self-fetching cockpit only scope params are passed, so the
|
|
57
|
+
* component fetches `tool` with `args` under `key`, gated on `ready` (i.e.
|
|
58
|
+
* the required id/key is present). Sibling widgets sharing `key` and `args`
|
|
59
|
+
* dedupe to a single call, so a composed view of N widgets over one data
|
|
60
|
+
* feed fetches once.
|
|
61
|
+
*
|
|
62
|
+
* By default host data is returned verbatim and switches the query off;
|
|
63
|
+
* `initialDataMode: "seed"` keeps the query live over it instead (see
|
|
64
|
+
* {@link ViewDataMode}). `options` passes TanStack's query options through.
|
|
23
65
|
*/
|
|
24
|
-
export declare function useViewData<T>(initialData: T | null | undefined, key: ReadonlyArray<unknown>, tool: string, args: Record<string, unknown>, ready: boolean): ViewDataResult<T>;
|
|
66
|
+
export declare function useViewData<T>(initialData: T | null | undefined, key: ReadonlyArray<unknown>, tool: string, args: Record<string, unknown>, ready: boolean, options?: UseViewDataOptions<T>): ViewDataResult<T>;
|
|
25
67
|
//# sourceMappingURL=use-view-data.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-view-data.d.ts","sourceRoot":"","sources":["../../src/hooks/use-view-data.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-view-data.d.ts","sourceRoot":"","sources":["../../src/hooks/use-view-data.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAG9E,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,qFAAqF;IACrF,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,aAAa,EAAE,KAAK,GAAG,IAAI,CAAA;IAC3B,yDAAyD;IACzD,UAAU,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG,QAAQ,CAAC,GAAG;IAC3F,eAAe,CAAC,EAAE,YAAY,CAAA;CAC/B,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EACjC,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,EAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,cAAc,CAAC,CAAC,CAAC,CA0BnB"}
|
|
@@ -1,23 +1,88 @@
|
|
|
1
|
-
import { useCallback } from "react";
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
import { hashKey, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { seedToolQuery } from "../lib/tool-query.js";
|
|
4
|
+
import { useToolQuery, useToolQueryKey } from "./use-tool-query.js";
|
|
3
5
|
/**
|
|
4
6
|
* The seam that lets one widget component serve both modes without a duplicate UI.
|
|
5
7
|
*
|
|
6
8
|
* Standalone (a `*_show_*` widget) the agent's tool result is handed in via
|
|
7
|
-
* `initialData` (from the view's stepData, e.g. through `adaptDataWidget`)
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* `initialData` (from the view's stepData, e.g. through `adaptDataWidget`).
|
|
10
|
+
* Embedded in a self-fetching cockpit only scope params are passed, so the
|
|
11
|
+
* component fetches `tool` with `args` under `key`, gated on `ready` (i.e.
|
|
12
|
+
* the required id/key is present). Sibling widgets sharing `key` and `args`
|
|
13
|
+
* dedupe to a single call, so a composed view of N widgets over one data
|
|
14
|
+
* feed fetches once.
|
|
15
|
+
*
|
|
16
|
+
* By default host data is returned verbatim and switches the query off;
|
|
17
|
+
* `initialDataMode: "seed"` keeps the query live over it instead (see
|
|
18
|
+
* {@link ViewDataMode}). `options` passes TanStack's query options through.
|
|
19
|
+
*/
|
|
20
|
+
export function useViewData(initialData, key, tool, args, ready, options) {
|
|
21
|
+
const { initialDataMode = "static", enabled, ...queryOptions } = options ?? {};
|
|
22
|
+
const seeding = initialDataMode === "seed";
|
|
23
|
+
const cacheKey = useStableKey(useToolQueryKey(key, tool, args));
|
|
24
|
+
useSeed(seeding ? initialData : null, cacheKey, queryOptions.initialDataUpdatedAt);
|
|
25
|
+
const active = ready && enabled !== false;
|
|
26
|
+
const fetches = active && (seeding || !initialData);
|
|
27
|
+
const query = useToolQuery([...key], tool, args, {
|
|
28
|
+
...queryOptions,
|
|
29
|
+
enabled: typeof enabled === "function" ? (q) => fetches && enabled(q) : fetches,
|
|
30
|
+
});
|
|
31
|
+
const data = seeding ? (query.data ?? initialData) : (initialData ?? query.data);
|
|
32
|
+
const refetch = useFreshRefetch(cacheKey, query.refetch);
|
|
33
|
+
return {
|
|
34
|
+
data: data ?? null,
|
|
35
|
+
// The query's own verdict: a function `enabled` that returns false idles
|
|
36
|
+
// like `enabled: false`, never an endless skeleton.
|
|
37
|
+
loading: !data && query.isEnabled && !query.isError,
|
|
38
|
+
error: query.error,
|
|
39
|
+
refetch,
|
|
40
|
+
failureCount: query.failureCount,
|
|
41
|
+
failureReason: query.failureReason,
|
|
42
|
+
isFetching: query.isFetching,
|
|
43
|
+
isPlaceholderData: query.isPlaceholderData,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** `key`, kept by content: callers build `key`/`args` anew every render. */
|
|
47
|
+
function useStableKey(key) {
|
|
48
|
+
const id = hashKey(key);
|
|
49
|
+
const [stable, setStable] = useState({ id, key });
|
|
50
|
+
if (stable.id !== id)
|
|
51
|
+
setStable({ id, key });
|
|
52
|
+
return stable.id === id ? stable.key : key;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `"seed"` mode: write the host's payload into the feed's cache entry in the
|
|
56
|
+
* render phase, before the query's observer reads the cache — what TanStack's
|
|
57
|
+
* own `initialData` does (see {@link seedToolQuery} for when it wins over a
|
|
58
|
+
* cached answer). The last processed seed skips the content check while the
|
|
59
|
+
* same object comes in render after render.
|
|
60
|
+
*/
|
|
61
|
+
function useSeed(seed, cacheKey, updatedAt) {
|
|
62
|
+
const client = useQueryClient();
|
|
63
|
+
const keyId = hashKey(cacheKey);
|
|
64
|
+
const [seen, setSeen] = useState(null);
|
|
65
|
+
if (seed == null || (seen?.seed === seed && seen.keyId === keyId))
|
|
66
|
+
return;
|
|
67
|
+
const at = typeof updatedAt === "function" ? updatedAt() : updatedAt;
|
|
68
|
+
const written = seedToolQuery(client, cacheKey, seed, at);
|
|
69
|
+
// Only a real change re-renders: an equal new object per render must not loop.
|
|
70
|
+
if (written || seen?.keyId !== keyId)
|
|
71
|
+
setSeen({ seed, keyId });
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A refetch that reads anew at once. TanStack restarts an in-flight fetch only
|
|
75
|
+
* over data (`cancelRefetch`); a key without data joins the running retry
|
|
76
|
+
* chain and waits out its backoff. So cancel that chain first, then read.
|
|
13
77
|
*/
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
78
|
+
function useFreshRefetch(cacheKey, refetchQuery) {
|
|
79
|
+
const client = useQueryClient();
|
|
80
|
+
return useCallback(() => {
|
|
81
|
+
if (client.getQueryData(cacheKey) !== undefined) {
|
|
82
|
+
void refetchQuery();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
void client.cancelQueries({ queryKey: cacheKey, exact: true }).then(() => refetchQuery());
|
|
86
|
+
}, [client, cacheKey, refetchQuery]);
|
|
22
87
|
}
|
|
23
88
|
//# sourceMappingURL=use-view-data.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-view-data.js","sourceRoot":"","sources":["../../src/hooks/use-view-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"use-view-data.js","sourceRoot":"","sources":["../../src/hooks/use-view-data.ts"],"names":[],"mappings":"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"}
|