gloomberb 0.16.3 → 0.16.4
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/package.json +4 -1
- package/src/api-client/askg.ts +43 -0
- package/src/api-client/auth.ts +15 -0
- package/src/api-client/beneficial-owners.ts +4 -0
- package/src/api-client/chat.ts +19 -0
- package/src/api-client/company-kpis.ts +14 -2
- package/src/api-client/data.ts +34 -16
- package/src/api-client/index.ts +12 -0
- package/src/api-client/normalizers.ts +27 -0
- package/src/api-client/paths.ts +88 -23
- package/src/api-client/request.ts +2 -1
- package/src/api-client/research-activity.ts +31 -0
- package/src/api-client/socket.ts +39 -8
- package/src/api-client/types.ts +57 -1
- package/src/api-client/upgrade-experiment.ts +90 -0
- package/src/app/global-shortcuts.ts +11 -1
- package/src/app/keybindings/actions.ts +10 -0
- package/src/app/pane-runtime/index.tsx +8 -0
- package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
- package/src/app/pane-runtime/plugin-bindings.ts +65 -25
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +18 -1
- package/src/app/runtime/desktop-deeplink.ts +5 -0
- package/src/app/star-prompt/model.ts +98 -0
- package/src/app/star-prompt/runtime.ts +41 -0
- package/src/app/star-prompt/status-line.tsx +190 -0
- package/src/app.tsx +13 -7
- package/src/architecture/core-builtin-allowlist.json +70 -0
- package/src/brokers/signed-in/adapter.ts +33 -2
- package/src/brokers/signed-in/client.ts +10 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +23 -9
- package/src/brokers/signed-in/sign-in.ts +62 -5
- package/src/capabilities/registry.ts +8 -1
- package/src/capabilities/types.ts +2 -0
- package/src/cli/commands/crypto-hints.ts +12 -4
- package/src/cli/commands/market.ts +359 -99
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +422 -0
- package/src/cli/commands/overview.ts +164 -26
- package/src/cli/commands/search.ts +29 -8
- package/src/cli/commands/system.ts +99 -19
- package/src/cli/commands/themes.ts +64 -0
- package/src/cli/commands/ticker.ts +62 -30
- package/src/cli/desktop-pane-shot.ts +97 -16
- package/src/cli/errors.ts +25 -2
- package/src/cli/freshness.ts +7 -4
- package/src/cli/fx-pair.ts +57 -0
- package/src/cli/help.ts +14 -1
- package/src/cli/index-roots.ts +51 -0
- package/src/cli/index.ts +9 -6
- package/src/cli/listing-arg.ts +211 -3
- package/src/cli/not-a-ticker.ts +37 -0
- package/src/cli/options.ts +50 -6
- package/src/cli/pane-functions/capabilities.ts +8 -2
- package/src/cli/pane-functions/catalog.ts +13 -2
- package/src/cli/pane-functions/data.ts +36 -5
- package/src/cli/pane-functions/dom.ts +21 -13
- package/src/cli/pane-functions/freshness.ts +205 -26
- package/src/cli/pane-functions/function-help.ts +67 -22
- package/src/cli/pane-functions/headless.ts +5 -4
- package/src/cli/pane-functions/index.ts +3 -0
- package/src/cli/pane-functions/market-session.ts +133 -0
- package/src/cli/pane-functions/options.ts +15 -4
- package/src/cli/pane-functions/report-notices.ts +63 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +4 -6
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +105 -23
- package/src/cli/registry.ts +2 -1
- package/src/cli/result.ts +50 -13
- package/src/cli/row-window.ts +76 -0
- package/src/cli/scroll-truncation.ts +34 -0
- package/src/components/chart/composite/composite-chart.tsx +43 -4
- package/src/components/chart/composite/legend.tsx +39 -6
- package/src/components/chart/composite/rasterizer.ts +64 -4
- package/src/components/chart/composite/series-cues.ts +71 -0
- package/src/components/chart/composite/text-renderer.ts +16 -8
- package/src/components/chart/composite/types.ts +3 -0
- package/src/components/command-bar/commands/direct/index.ts +9 -1
- package/src/components/command-bar/commands/plugin/items.ts +3 -1
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
- package/src/components/command-bar/pane-templates/workflow.ts +5 -0
- package/src/components/command-bar/routes/root/command-items.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
- package/src/components/command-bar/routes/root/results.ts +40 -10
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/root/search-providers.ts +97 -14
- package/src/components/command-bar/surface/index.tsx +18 -4
- package/src/components/command-bar/theme-picker.tsx +48 -13
- package/src/components/command-bar/workflow/ops.ts +5 -3
- package/src/components/data-table/view.tsx +28 -9
- package/src/components/layout/floating-pane.tsx +6 -2
- package/src/components/layout/market-summary.ts +23 -9
- package/src/components/layout/pane/content.tsx +46 -29
- package/src/components/layout/pane/cycle-order.ts +2 -11
- package/src/components/layout/pane/header.tsx +2 -1
- package/src/components/layout/pane/title.ts +1 -1
- package/src/components/layout/presentation.ts +22 -0
- package/src/components/layout/shell/active-drag.ts +1 -1
- package/src/components/layout/shell/drag/index.ts +4 -0
- package/src/components/layout/shell/drag/live.ts +76 -5
- package/src/components/layout/shell/drag/runtime.ts +8 -8
- package/src/components/layout/shell/index.tsx +47 -6
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +28 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +51 -10
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/pane/new-layout.ts +116 -0
- package/src/components/layout/shell/shortcuts.ts +5 -2
- package/src/components/layout/shell/visible-layout.ts +44 -1
- package/src/components/layout/status-bar.tsx +4 -1
- package/src/components/markdown-text.tsx +9 -5
- package/src/components/metric-treemap/heat-surface.tsx +27 -8
- package/src/components/metric-treemap/heat-tiles.ts +48 -17
- package/src/components/onboarding/onboarding-frame.tsx +33 -10
- package/src/components/onboarding/onboarding-wizard.tsx +49 -40
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
- package/src/components/onboarding/pro-step-layout.ts +86 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +6 -2
- package/src/components/ui/button.tsx +10 -0
- package/src/components/ui/data-table/index.tsx +38 -0
- package/src/components/ui/data-table/types.ts +8 -1
- package/src/components/ui/data-table/visible-range.ts +2 -0
- package/src/components/ui/icon.tsx +11 -2
- package/src/components/ui/index.ts +1 -1
- package/src/core/connection-health.ts +1 -1
- package/src/core/state/app/layout-reducer.ts +89 -3
- package/src/core/state/app/state.ts +8 -5
- package/src/core/state/app/types.ts +13 -2
- package/src/data/config/layout.ts +55 -21
- package/src/data/config/store/fold-panes.ts +149 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/node.ts +27 -6
- package/src/data/config/store/normalize.ts +37 -3
- package/src/i18n/es.ts +14 -1
- package/src/i18n/ja.ts +14 -1
- package/src/i18n/ko.ts +14 -1
- package/src/i18n/zh-cn.ts +14 -1
- package/src/i18n/zh-tw.ts +14 -1
- package/src/layout/desks.ts +1 -2
- package/src/layout/pane-layout-move.ts +264 -0
- package/src/layout/pane-manager/hidden-panes.ts +160 -0
- package/src/layout/pane-manager/index.ts +1 -0
- package/src/market-data/coordinator/entries.ts +7 -1
- package/src/market-data/coordinator/quotes.ts +2 -2
- package/src/market-data/market/freshness.ts +118 -18
- package/src/market-data/market/status.ts +40 -0
- package/src/market-data/options-alternatives.ts +69 -0
- package/src/market-data/quotes/contributions.ts +19 -2
- package/src/market-data/quotes/metadata.ts +16 -0
- package/src/market-data/quotes/screener-live-quotes.ts +56 -5
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +1 -0
- package/src/plugins/builtin/account-management/navigation.ts +1 -1
- package/src/plugins/builtin/account-management/pane.tsx +31 -4
- package/src/plugins/builtin/alerts/quotes.ts +3 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +3 -1
- package/src/plugins/builtin/analytics/risk-model.ts +37 -8
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -4
- package/src/plugins/builtin/backtest/pane.tsx +1 -1
- package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/broker-manager/model.ts +8 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
- package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
- package/src/plugins/builtin/broker-manager/table.ts +5 -0
- package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
- package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
- package/src/plugins/builtin/chat/channels.ts +34 -36
- package/src/plugins/builtin/chat/command-bar.ts +138 -0
- package/src/plugins/builtin/chat/composer-commands.ts +21 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
- package/src/plugins/builtin/chat/content/footer.tsx +5 -3
- package/src/plugins/builtin/chat/content/index.tsx +21 -1
- package/src/plugins/builtin/chat/content/mentions.ts +2 -1
- package/src/plugins/builtin/chat/content/user-map.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +48 -0
- package/src/plugins/builtin/chat/conversations.ts +256 -0
- package/src/plugins/builtin/chat/discord-command.ts +91 -0
- package/src/plugins/builtin/chat/edit-window.ts +12 -6
- package/src/plugins/builtin/chat/ghost-user.ts +14 -0
- package/src/plugins/builtin/chat/index.tsx +40 -2
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
- package/src/plugins/builtin/chat/message/header.tsx +24 -15
- package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
- package/src/plugins/builtin/chat/message/render-state.ts +3 -0
- package/src/plugins/builtin/chat/pane-requests.ts +60 -0
- package/src/plugins/builtin/chat/pane-state.ts +32 -2
- package/src/plugins/builtin/chat/pane.tsx +8 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +112 -4
- package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +1 -0
- package/src/plugins/builtin/cloud/askg/model.ts +129 -70
- package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
- package/src/plugins/builtin/cloud/askg/protocol.ts +40 -2
- package/src/plugins/builtin/cloud/askg/tool-display.ts +437 -0
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
- package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +360 -0
- package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
- package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
- package/src/plugins/builtin/cloud/plugin.tsx +36 -1
- package/src/plugins/builtin/cloud/starter-symbols.ts +8 -0
- package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
- package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
- package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +666 -0
- package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
- package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
- package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +234 -0
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +153 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +168 -0
- package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
- package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
- package/src/plugins/builtin/cloud/upgrade-dialog.tsx +26 -2
- package/src/plugins/builtin/cloud/upgrade-personalization.ts +57 -0
- package/src/plugins/builtin/cloud/upgrade-tickers.ts +124 -0
- package/src/plugins/builtin/comment-letters/client.ts +1 -3
- package/src/plugins/builtin/company-kpis/client.ts +23 -8
- package/src/plugins/builtin/company-kpis/headless.ts +3 -1
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
- package/src/plugins/builtin/composite-plugins.ts +107 -64
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
- package/src/plugins/builtin/credit-boards/index.tsx +21 -21
- package/src/plugins/builtin/credit-boards/model.ts +0 -1
- package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
- package/src/plugins/builtin/debt-maturities/client.ts +37 -9
- package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/data.ts +28 -7
- package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +42 -17
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/index.tsx +68 -22
- package/src/plugins/builtin/econ-statistics/headless.ts +12 -2
- package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
- package/src/plugins/builtin/econ-statistics/view.ts +17 -0
- package/src/plugins/builtin/executives/data.ts +17 -6
- package/src/plugins/builtin/executives/pane.tsx +16 -7
- package/src/plugins/builtin/filing-events/pane.tsx +22 -5
- package/src/plugins/builtin/fx-matrix/freshness.ts +65 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
- package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
- package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
- package/src/plugins/builtin/gpu/headless.ts +9 -3
- package/src/plugins/builtin/gpu/model.ts +14 -5
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/headless.ts +6 -1
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- package/src/plugins/builtin/insider/index.tsx +4 -4
- package/src/plugins/builtin/iv-history/charts.tsx +21 -7
- package/src/plugins/builtin/iv-history/client.ts +12 -2
- package/src/plugins/builtin/iv-history/format.ts +33 -2
- package/src/plugins/builtin/iv-history/headless.ts +22 -10
- package/src/plugins/builtin/iv-history/index.tsx +3 -3
- package/src/plugins/builtin/iv-history/model.ts +61 -13
- package/src/plugins/builtin/iv-history/pane.tsx +11 -3
- package/src/plugins/builtin/iv-history/screen-pane.tsx +42 -18
- package/src/plugins/builtin/jobs/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
- package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +109 -39
- package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
- package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
- package/src/plugins/builtin/layout-manager/index.tsx +9 -1
- package/src/plugins/builtin/macro-day/client.ts +24 -0
- package/src/plugins/builtin/macro-day/headless.ts +11 -8
- package/src/plugins/builtin/macro-day/index.tsx +3 -0
- package/src/plugins/builtin/macro-day/model.ts +11 -6
- package/src/plugins/builtin/macro-day/pane.tsx +12 -8
- package/src/plugins/builtin/macro-day/release-table.ts +40 -0
- package/src/plugins/builtin/macro-day/releases.ts +62 -44
- package/src/plugins/builtin/market-heatmap/data.ts +25 -5
- package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
- package/src/plugins/builtin/market-heatmap/model.ts +94 -3
- package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
- package/src/plugins/builtin/market-movers/headless.ts +31 -4
- package/src/plugins/builtin/market-movers/index.tsx +8 -1
- package/src/plugins/builtin/market-movers/model.ts +71 -17
- package/src/plugins/builtin/market-movers/table.ts +50 -23
- package/src/plugins/builtin/news/headless.ts +9 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
- package/src/plugins/builtin/openfda/client.ts +1 -1
- package/src/plugins/builtin/options/carry.ts +95 -0
- package/src/plugins/builtin/options/index.tsx +58 -5
- package/src/plugins/builtin/options/strike-window.ts +183 -0
- package/src/plugins/builtin/options/table.ts +55 -3
- package/src/plugins/builtin/options/types.ts +8 -1
- package/src/plugins/builtin/options/view.tsx +161 -12
- package/src/plugins/builtin/options-positioning/headless.ts +4 -2
- package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +73 -17
- package/src/plugins/builtin/options-scenario/headless.ts +71 -24
- package/src/plugins/builtin/options-scenario/hedge.ts +284 -0
- package/src/plugins/builtin/options-scenario/index.tsx +9 -2
- package/src/plugins/builtin/options-scenario/model.ts +33 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
- package/src/plugins/builtin/pe-band/model.ts +2 -2
- package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
- package/src/plugins/builtin/perps/equity-row.tsx +8 -5
- package/src/plugins/builtin/perps/model.ts +16 -5
- package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
- package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +344 -32
- package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
- package/src/plugins/builtin/plugin-module.ts +87 -4
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +71 -36
- package/src/plugins/builtin/portfolio-list/cli/render.ts +87 -18
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
- package/src/plugins/builtin/portfolio-list/headless.ts +38 -7
- package/src/plugins/builtin/realized-vol/headless.ts +3 -0
- package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -2
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
- package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
- package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
- package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
- package/src/plugins/builtin/risk-factors/data.ts +23 -9
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- package/src/plugins/builtin/seasonality/pane.tsx +1 -1
- package/src/plugins/builtin/sec/index.tsx +5 -5
- package/src/plugins/builtin/sectors/client.ts +10 -2
- package/src/plugins/builtin/sectors/headless.ts +35 -6
- package/src/plugins/builtin/sectors/index.tsx +18 -1
- package/src/plugins/builtin/sectors/sector-model.ts +150 -41
- package/src/plugins/builtin/shared/command-tab.ts +51 -0
- package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
- package/src/plugins/builtin/shared/members-menu.tsx +4 -4
- package/src/plugins/builtin/shared/report-freshness.ts +50 -2
- package/src/plugins/builtin/shared/ticker-request.ts +25 -1
- package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
- package/src/plugins/builtin/shared/volatility/options.ts +1 -46
- package/src/plugins/builtin/short-interest/index.tsx +19 -4
- package/src/plugins/builtin/short-interest/surface.tsx +4 -4
- package/src/plugins/builtin/short-volume/index.tsx +1 -10
- package/src/plugins/builtin/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
- package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
- package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
- package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
- package/src/plugins/builtin/treasury-auctions/headless.ts +40 -4
- package/src/plugins/builtin/treasury-auctions/index.tsx +11 -9
- package/src/plugins/builtin/treasury-auctions/model.ts +197 -30
- package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
- package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
- package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
- package/src/plugins/builtin/vol-surface/client.ts +6 -2
- package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
- package/src/plugins/builtin/vol-surface/headless.ts +124 -20
- package/src/plugins/builtin/vol-surface/model.ts +23 -11
- package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
- package/src/plugins/builtin/vol-surface/tables.ts +124 -0
- package/src/plugins/builtin/world-indices/client.ts +22 -4
- package/src/plugins/builtin/world-indices/headless.ts +54 -27
- package/src/plugins/builtin/world-indices/model.ts +4 -2
- package/src/plugins/builtin/world-indices/table.tsx +13 -2
- package/src/plugins/builtin/world-venue-map/geo-series.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +1 -1
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/builtin-editorial.ts +126 -0
- package/src/plugins/catalog-backend.ts +16 -9
- package/src/plugins/catalog-browser.ts +127 -63
- package/src/plugins/catalog-manifest.ts +73 -40
- package/src/plugins/catalog-ui.ts +26 -6
- package/src/plugins/extracted-plugins.ts +7 -1
- package/src/plugins/ownership.ts +150 -7
- package/src/plugins/plugin-functions.ts +54 -0
- package/src/plugins/plugin-off.ts +36 -0
- package/src/plugins/registry/host-actions.ts +16 -0
- package/src/plugins/registry/index.ts +84 -24
- package/src/plugins/registry/plugin-state.ts +25 -1
- package/src/plugins/runtime/context.tsx +29 -0
- package/src/react/input.ts +48 -1
- package/src/remote/app-host.tsx +5 -0
- package/src/remote/controller.ts +3 -53
- package/src/remote/matching.ts +69 -0
- package/src/remote/schema.ts +1 -1
- package/src/remote/semantic-tree.tsx +14 -0
- package/src/remote/types.ts +2 -0
- package/src/renderers/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/host/box.tsx +1 -1
- package/src/renderers/dom/host/drag-shield.ts +17 -6
- package/src/renderers/dom/host/live-frame.ts +10 -2
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +13 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
- package/src/renderers/electrobun/view/main.tsx +4 -1
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +19 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +4 -1
- package/src/sources/listing-symbols.ts +11 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/cached-routes.ts +8 -4
- package/src/sources/provider-router/financial-routes.ts +11 -5
- package/src/sources/provider-router/financials.ts +42 -15
- package/src/sources/provider-router/history.ts +27 -11
- package/src/sources/provider-router/index.ts +1 -1
- package/src/sources/provider-router/primary.ts +23 -5
- package/src/sources/sec-edgar.ts +68 -8
- package/src/sync/core-contributors.ts +4 -3
- package/src/test-support/cli-context.ts +2 -1
- package/src/test-support/data-provider.ts +34 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/series-colors.ts +46 -0
- package/src/theme/themes.ts +149 -0
- package/src/tickers/search/index.ts +22 -2
- package/src/tickers/search/ranking.ts +45 -1
- package/src/tickers/search/types.ts +3 -1
- package/src/time-series/resolve.ts +1 -14
- package/src/types/config.ts +61 -1
- package/src/types/headless.ts +11 -0
- package/src/types/instrument.ts +8 -0
- package/src/types/plugin.ts +49 -3
- package/src/ui/host.tsx +8 -4
- package/src/ui/index.tsx +2 -0
- package/src/utils/cli-output.ts +14 -1
- package/src/utils/exchanges.ts +13 -0
- package/src/utils/format.ts +2 -1
- package/src/utils/fx-market-hours.ts +34 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history.ts +39 -6
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +159 -30
- package/src/utils/sec.ts +38 -34
- package/src/utils/throttled-fetch.ts +51 -22
|
@@ -34,10 +34,42 @@ export const SCRIPT_TOOL_NAME = "run_script";
|
|
|
34
34
|
export interface ASKGCapabilities {
|
|
35
35
|
/** 1: the turn may answer by running scripts of tool calls. */
|
|
36
36
|
scripts?: 1;
|
|
37
|
+
/**
|
|
38
|
+
* 1: answers can be rated. Only the session start carries it; a turn never
|
|
39
|
+
* repeats it, and a reopened conversation says it on its own response.
|
|
40
|
+
*/
|
|
41
|
+
feedback?: 1;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
/** What this build offers at session start. */
|
|
40
|
-
export const ASKG_CLIENT_CAPABILITIES: ASKGCapabilities = { scripts: 1 };
|
|
45
|
+
export const ASKG_CLIENT_CAPABILITIES: ASKGCapabilities = { scripts: 1, feedback: 1 };
|
|
46
|
+
|
|
47
|
+
/** A thumbs up or down on one answer. */
|
|
48
|
+
export type ASKGFeedbackRating = "up" | "down";
|
|
49
|
+
|
|
50
|
+
/** Why a thumbs down, from a fixed list: a rating never carries text. */
|
|
51
|
+
export type ASKGFeedbackReason = "wrong" | "slow" | "missing_data" | "other";
|
|
52
|
+
|
|
53
|
+
/** Body of `PUT /askg/turns/:turnId/feedback`. Rating again overwrites. */
|
|
54
|
+
export interface ASKGFeedbackRequest {
|
|
55
|
+
rating: ASKGFeedbackRating;
|
|
56
|
+
/** Only with a thumbs down. */
|
|
57
|
+
reason?: ASKGFeedbackReason | null;
|
|
58
|
+
/**
|
|
59
|
+
* The person agreed to send this answer. The request carries the consent,
|
|
60
|
+
* not the text: the platform copies the question, the answer and the names
|
|
61
|
+
* of the tools that ran from its own transcript, and nothing else.
|
|
62
|
+
*/
|
|
63
|
+
share?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** A rating as stored: the route's answer, and what a reopened answer carries. */
|
|
67
|
+
export interface ASKGFeedback {
|
|
68
|
+
rating: ASKGFeedbackRating;
|
|
69
|
+
reason: ASKGFeedbackReason | null;
|
|
70
|
+
/** The answer was sent. Sending is one way: a later rating keeps it sent. */
|
|
71
|
+
shared: boolean;
|
|
72
|
+
}
|
|
41
73
|
|
|
42
74
|
/** JSON value accepted on the ASKG wire. */
|
|
43
75
|
export type JsonValue =
|
|
@@ -73,7 +105,7 @@ type ToolManifestShape = HeadlessPaneShape;
|
|
|
73
105
|
export type ToolManifestArgument = HeadlessPaneArgumentDef;
|
|
74
106
|
|
|
75
107
|
/** Serializable headless option declaration. */
|
|
76
|
-
export type ToolManifestOption = Omit<HeadlessPaneOptionDef, "settingKey" | "pluginState">;
|
|
108
|
+
export type ToolManifestOption = Omit<HeadlessPaneOptionDef, "settingKey" | "pluginState" | "normalize">;
|
|
77
109
|
|
|
78
110
|
/** Serializable headless column declaration. */
|
|
79
111
|
export type ToolManifestColumn = Omit<HeadlessPaneColumn, "format">;
|
|
@@ -254,6 +286,12 @@ interface ASKGToolExecutedEvent extends ASKGEventBase {
|
|
|
254
286
|
source: ToolManifestSource;
|
|
255
287
|
status: ToolResultStatus;
|
|
256
288
|
summary: ToolExecutionSummary;
|
|
289
|
+
/**
|
|
290
|
+
* What a tool the platform ran was asked, so its row can name the subject.
|
|
291
|
+
* Absent on an older server, on a tool this client ran, and on a call whose
|
|
292
|
+
* arguments were empty or too large to send.
|
|
293
|
+
*/
|
|
294
|
+
args?: Record<string, JsonValue>;
|
|
257
295
|
}
|
|
258
296
|
|
|
259
297
|
/** Confirms that one client tool result was accepted by the turn loop. */
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import type { ASKGToolRow } from "./model";
|
|
2
|
+
import { SCRIPT_TOOL_NAME, type JsonValue } from "./protocol";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* How a tool call reads in the timeline. A note is written for Gloom as much
|
|
6
|
+
* as for the person reading, so it can name a metadata field, paste a server
|
|
7
|
+
* error or list every symbol it skipped. The row says what happened in plain
|
|
8
|
+
* words, once: a quiet mark, what was read, how much came back, and at most
|
|
9
|
+
* one short line about what is missing. Everything else waits in the detail.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** The state a row's mark shows. `partial` reads like `ok`: it is a result. */
|
|
13
|
+
export type ToolMark = "running" | "waiting" | "ok" | "partial" | "failed" | "stopped" | "declined";
|
|
14
|
+
|
|
15
|
+
export interface ToolRowView {
|
|
16
|
+
/** What the tool is, in words: "Holdings", "Yield curve". */
|
|
17
|
+
title: string;
|
|
18
|
+
/** What it was about: a portfolio's name, a symbol, a search. Empty when nothing. */
|
|
19
|
+
subject: string;
|
|
20
|
+
/** Result size and duration, "94 rows · 1.2 s". */
|
|
21
|
+
meta: string;
|
|
22
|
+
mark: ToolMark;
|
|
23
|
+
/** At most one short line under the row: the main gap in a partial result, or why it failed. */
|
|
24
|
+
line: string | null;
|
|
25
|
+
/** The full story, for the expanded row. */
|
|
26
|
+
details: string[];
|
|
27
|
+
/** The call's arguments as readable pairs, for the expanded row. */
|
|
28
|
+
arguments: Array<{ label: string; value: string }>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ToolDisplayContext {
|
|
32
|
+
/** Display name of a portfolio or watchlist id, when the profile has it. */
|
|
33
|
+
collectionName?(id: string): string | null;
|
|
34
|
+
/** Name of the pane a client tool reads from. */
|
|
35
|
+
toolTitle?(name: string): string | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Names for the tools the platform runs. A tool missing here still reads as
|
|
40
|
+
* words: `perps.history` becomes "Perps history".
|
|
41
|
+
*/
|
|
42
|
+
const TOOL_TITLES: Record<string, string> = {
|
|
43
|
+
pf: "Holdings",
|
|
44
|
+
port: "Portfolio risk",
|
|
45
|
+
mars: "Market risk",
|
|
46
|
+
"app.get_resource": "App state",
|
|
47
|
+
"market.quotes": "Quotes",
|
|
48
|
+
"market.history": "Price history",
|
|
49
|
+
"market.search": "Instrument search",
|
|
50
|
+
"market.screener": "Market movers",
|
|
51
|
+
"market.options_chain": "Options chain",
|
|
52
|
+
"market.options_flow": "Options flow",
|
|
53
|
+
"market.short_interest": "Short interest",
|
|
54
|
+
"market.attention": "Research attention",
|
|
55
|
+
"market.hiring_movers": "Hiring movers",
|
|
56
|
+
"company.profile": "Company profile",
|
|
57
|
+
"company.statements": "Financial statements",
|
|
58
|
+
"company.financials": "Financials",
|
|
59
|
+
"company.holders": "Holders",
|
|
60
|
+
"company.analyst_research": "Analyst research",
|
|
61
|
+
"company.corporate_actions": "Corporate actions",
|
|
62
|
+
"company.awards": "Government awards",
|
|
63
|
+
"company.award_evidence": "Award evidence",
|
|
64
|
+
"company.hiring": "Hiring",
|
|
65
|
+
"sec.filings": "SEC filings",
|
|
66
|
+
"sec.insider_transactions": "Insider trades",
|
|
67
|
+
"sec.thirteenf_crowding": "13F crowding",
|
|
68
|
+
"sec.thirteenf_holders": "13F holders",
|
|
69
|
+
"macro.calendar": "Economic calendar",
|
|
70
|
+
"macro.series": "Economic data",
|
|
71
|
+
"macro.yield_curve": "Yield curve",
|
|
72
|
+
"news.stories": "News",
|
|
73
|
+
"social.ticker_posts": "Social posts",
|
|
74
|
+
"social.search_posts": "Social search",
|
|
75
|
+
"portfolio.exposure": "Scenario exposure",
|
|
76
|
+
"equity.diagnostic": "Equity diagnostic",
|
|
77
|
+
"hiring.momentum": "Hiring momentum",
|
|
78
|
+
"apps.rank_history": "App rankings",
|
|
79
|
+
"apps.attention": "App attention",
|
|
80
|
+
[SCRIPT_TOOL_NAME]: "Script",
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/** What `app.get_resource` read, in words. */
|
|
84
|
+
const RESOURCE_SUBJECTS: Record<string, string> = {
|
|
85
|
+
"app://accounts": "broker accounts",
|
|
86
|
+
"app://snapshot": "your layout",
|
|
87
|
+
"app://panes": "open panes",
|
|
88
|
+
"app://config": "settings",
|
|
89
|
+
"app://layout/current": "your layout",
|
|
90
|
+
"app://layouts": "saved layouts",
|
|
91
|
+
"app://auth": "your account",
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** Arguments that pick the subject; every other one is a detail. */
|
|
95
|
+
const SUBJECT_KEYS = ["symbol", "symbols", "text", "query", "paneId", "resource", "portfolioId", "collectionId", "ticker", "tickers"];
|
|
96
|
+
/** Options that say which view was read, worth a word next to the subject. */
|
|
97
|
+
const QUALIFIER_KEYS = ["view", "range", "period", "component", "series"];
|
|
98
|
+
|
|
99
|
+
function sentenceCase(text: string): string {
|
|
100
|
+
const spaced = text.replace(/[_.-]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/\s+/g, " ").trim();
|
|
101
|
+
if (!spaced) return "";
|
|
102
|
+
return spaced[0]!.toUpperCase() + spaced.slice(1).toLowerCase();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function toolTitle(name: string, context: ToolDisplayContext = {}): string {
|
|
106
|
+
const known = TOOL_TITLES[name];
|
|
107
|
+
if (known) return known;
|
|
108
|
+
const fromPane = context.toolTitle?.(name)?.replace(/\s+Pane$/i, "").trim();
|
|
109
|
+
if (fromPane) return fromPane;
|
|
110
|
+
// A remote operation reads as its action: "pane.show" is "Show pane".
|
|
111
|
+
const [scope, action] = name.split(".", 2);
|
|
112
|
+
if (scope && action) return sentenceCase(`${action} ${scope}`);
|
|
113
|
+
return name.length <= 5 ? name.toUpperCase() : sentenceCase(name);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function scalarText(value: JsonValue | undefined): string {
|
|
117
|
+
if (value == null) return "";
|
|
118
|
+
if (typeof value === "string") return value.trim();
|
|
119
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
120
|
+
if (Array.isArray(value)) return value.map(scalarText).filter(Boolean).join(", ");
|
|
121
|
+
return "";
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** "NVDA", "NVDA, AMD and 3 more". */
|
|
125
|
+
function symbolList(value: JsonValue | undefined): string {
|
|
126
|
+
const symbols = Array.isArray(value)
|
|
127
|
+
? value.map(scalarText).filter(Boolean)
|
|
128
|
+
: scalarText(value).split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
129
|
+
if (symbols.length <= 3) return symbols.join(", ");
|
|
130
|
+
return `${symbols.slice(0, 2).join(", ")} and ${symbols.length - 2} more`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** A broker portfolio id ("broker:ibkr-main:U1234567") as the account it names. */
|
|
134
|
+
function readableId(id: string): string {
|
|
135
|
+
const broker = /^broker:[^:]+:(.+)$/.exec(id);
|
|
136
|
+
return broker ? broker[1]! : id;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function subjectFromArgs(args: Record<string, JsonValue>, context: ToolDisplayContext): string {
|
|
140
|
+
for (const key of SUBJECT_KEYS) {
|
|
141
|
+
const value = args[key];
|
|
142
|
+
if (value == null || value === "") continue;
|
|
143
|
+
if (key === "symbol" || key === "symbols" || key === "ticker" || key === "tickers") {
|
|
144
|
+
// An empty list, which a tool's defaults fill in, leaves the next key to name the subject.
|
|
145
|
+
const symbols = symbolList(value);
|
|
146
|
+
if (symbols) return symbols;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const text = scalarText(value);
|
|
150
|
+
if (!text) continue;
|
|
151
|
+
if (key === "resource") return RESOURCE_SUBJECTS[text] ?? text.replace(/^[a-z]+:\/\//, "");
|
|
152
|
+
if (key === "query") return `"${text}"`;
|
|
153
|
+
if (key === "text" || key === "portfolioId" || key === "collectionId") {
|
|
154
|
+
return context.collectionName?.(text) ?? readableId(text);
|
|
155
|
+
}
|
|
156
|
+
return text;
|
|
157
|
+
}
|
|
158
|
+
return "";
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function qualifierFromArgs(args: Record<string, JsonValue>): string {
|
|
162
|
+
for (const key of QUALIFIER_KEYS) {
|
|
163
|
+
const text = scalarText(args[key]);
|
|
164
|
+
if (text) return text;
|
|
165
|
+
}
|
|
166
|
+
return "";
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** The options the row line leaves out, "equity shift: -10". The subject is already on the line. */
|
|
170
|
+
function argumentPairs(args: Record<string, JsonValue> | undefined) {
|
|
171
|
+
if (!args) return [];
|
|
172
|
+
const shown = new Set([...SUBJECT_KEYS, QUALIFIER_KEYS.find((key) => scalarText(args[key])) ?? ""]);
|
|
173
|
+
return Object.keys(args).sort().flatMap((key) => {
|
|
174
|
+
if (shown.has(key)) return [];
|
|
175
|
+
const value = scalarText(args[key]);
|
|
176
|
+
return value ? [{ label: sentenceCase(key).toLowerCase(), value }] : [];
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** "340 ms", "1.2 s", "1 min 4 s". */
|
|
181
|
+
function formatToolDuration(ms: number | undefined): string {
|
|
182
|
+
if (ms === undefined || !Number.isFinite(ms) || ms < 0) return "";
|
|
183
|
+
if (ms < 1_000) return `${Math.max(1, Math.round(ms / 10) * 10)} ms`;
|
|
184
|
+
if (ms < 60_000) return `${(ms / 1_000).toFixed(1)} s`;
|
|
185
|
+
const minutes = Math.floor(ms / 60_000);
|
|
186
|
+
return `${minutes} min ${Math.round((ms % 60_000) / 1_000)} s`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function countText(count: number | undefined): string {
|
|
190
|
+
if (count === undefined) return "";
|
|
191
|
+
return `${count.toLocaleString("en-US")} ${count === 1 ? "row" : "rows"}`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// --- Notes -----------------------------------------------------------------
|
|
195
|
+
|
|
196
|
+
/** Words Gloom needs and the reader does not: field paths and pointers for the model. */
|
|
197
|
+
const INTERNAL_CLAUSE = /\bmetadata\.[a-z_]+|\blists each with its reason\b|\bsee (?:the )?(?:result|payload|rows)\b/i;
|
|
198
|
+
/** A service the app already worked around. Never a warning, only a detail. */
|
|
199
|
+
const SERVICE_FAILURE = /internal server error|server error|bad gateway|service unavailable|gateway time-?out|\b(?:http|status)\s*\d{3}\b|\b50[0-9]\b|econn\w+|etimedout|fetch failed|network error|socket hang up|too many requests|rate.?limit|request failed|unexpected token|not valid json|cannot read propert|is not a function|undefined is not/i;
|
|
200
|
+
/** What the client did to fit the result through the wire. Gloom's business. */
|
|
201
|
+
const TRANSPORT_CLAUSE = /^(?:trimmed to fit|result exceeded the client payload limit|result was too large)/i;
|
|
202
|
+
/** Text that is not for people: payloads, identifiers, URIs, stack frames. */
|
|
203
|
+
const RAW_TEXT = /[{}[\]<>`]|\b[a-z]+:\/\/|\b[a-z]+_[a-z_]+\b|\b[a-z]+\.[a-z_]{2,}\b|\b[a-z]+[A-Z][a-zA-Z]+\b|\bat \S+:\d+|^\s*error:|"[a-z_.]+"/;
|
|
204
|
+
|
|
205
|
+
/** Splits a note on the separators `summarizeToolWarnings` joins with, outside parentheses. */
|
|
206
|
+
function noteClauses(note: string): string[] {
|
|
207
|
+
const clauses: string[] = [];
|
|
208
|
+
let depth = 0;
|
|
209
|
+
let current = "";
|
|
210
|
+
for (let index = 0; index < note.length; index += 1) {
|
|
211
|
+
const character = note[index]!;
|
|
212
|
+
if (character === "(") depth += 1;
|
|
213
|
+
if (character === ")") depth = Math.max(0, depth - 1);
|
|
214
|
+
if (depth === 0 && character === ";") {
|
|
215
|
+
clauses.push(current);
|
|
216
|
+
current = "";
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
current += character;
|
|
220
|
+
}
|
|
221
|
+
clauses.push(current);
|
|
222
|
+
return clauses
|
|
223
|
+
.map((clause) => clause.trim().replace(/[.\s]+$/, ""))
|
|
224
|
+
.filter((clause) => clause && !/^and \d+ more$/i.test(clause));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function listedItems(list: string): string[] {
|
|
228
|
+
return list
|
|
229
|
+
.replace(/\s+and\s+(\d+)\s+more$/i, (_match, more: string) => `, +${more}`)
|
|
230
|
+
.split(/\s*,\s*/)
|
|
231
|
+
.filter(Boolean);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function countListed(list: string): number {
|
|
235
|
+
return listedItems(list).reduce((count, item) => {
|
|
236
|
+
const more = /^\+(\d+)$/.exec(item);
|
|
237
|
+
return count + (more ? Number(more[1]) : 1);
|
|
238
|
+
}, 0);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function plural(count: number, noun: string): string {
|
|
242
|
+
return `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
interface NoteReading {
|
|
246
|
+
/** The candidate for the one line, best first. */
|
|
247
|
+
headline: string | null;
|
|
248
|
+
details: string[];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Reads one clause. Known shapes become a counted sentence; a server failure
|
|
253
|
+
* becomes "X unavailable"; anything internal is dropped; the rest is kept as
|
|
254
|
+
* written when it is plain text.
|
|
255
|
+
*/
|
|
256
|
+
function readClause(clause: string, rowCount: number | undefined): { headline?: string; detail?: string } {
|
|
257
|
+
if (INTERNAL_CLAUSE.test(clause) || TRANSPORT_CLAUSE.test(clause)) return {};
|
|
258
|
+
|
|
259
|
+
const unpriced = /^No (?:market value|price|current quote)(?: or P&L)? for (.+?)(?:,? (?:so )?totals and weights leave them out)?$/i.exec(clause);
|
|
260
|
+
if (unpriced) {
|
|
261
|
+
const count = countListed(unpriced[1]!);
|
|
262
|
+
const of = rowCount !== undefined && rowCount >= count ? ` of ${rowCount.toLocaleString("en-US")}` : "";
|
|
263
|
+
return {
|
|
264
|
+
headline: `${count}${of} positions had no price`,
|
|
265
|
+
detail: `No price for ${unpriced[1]}, so totals leave ${count === 1 ? "it" : "them"} out`,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const coverage = /^Basket covers (at most )?(\d+(?:\.\d+)?%) of market value(?: · (\d+) holdings? left out)?(?: · (.+))?$/i.exec(clause);
|
|
270
|
+
if (coverage) {
|
|
271
|
+
const share = `${coverage[1] ? "up to " : ""}${coverage[2]}`;
|
|
272
|
+
const leftOut = coverage[3] ? ` · ${plural(Number(coverage[3]), "holding")} left out` : "";
|
|
273
|
+
const sentence = `Risk covers ${share} of the portfolio's value${leftOut}`;
|
|
274
|
+
return { headline: sentence, detail: coverage[4] ? `${sentence}; ${coverage[4]}` : sentence };
|
|
275
|
+
}
|
|
276
|
+
if (/^Basket estimates unavailable/i.test(clause)) {
|
|
277
|
+
return { headline: "Too few holdings qualify for a risk estimate", detail: clause.replace(/^Basket estimates unavailable:\s*/i, "") };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const subject = /^([^:]{1,40}):\s+(.+)$/.exec(clause);
|
|
281
|
+
if (subject && SERVICE_FAILURE.test(subject[2]!)) return { detail: `${subject[1]} unavailable` };
|
|
282
|
+
if (SERVICE_FAILURE.test(clause)) return { detail: "Some data was unavailable" };
|
|
283
|
+
if (subject && /unavailable$/i.test(subject[2]!) && !RAW_TEXT.test(subject[1]!)) {
|
|
284
|
+
return { detail: `${subject[2]!.replace(/\s+unavailable$/i, "")} unavailable for ${subject[1]}` };
|
|
285
|
+
}
|
|
286
|
+
if (RAW_TEXT.test(clause)) return { detail: "Some data could not be read" };
|
|
287
|
+
|
|
288
|
+
const grouped = /^(.+?) \(([^()]+)\)$/.exec(clause);
|
|
289
|
+
if (grouped) {
|
|
290
|
+
const count = countListed(grouped[2]!);
|
|
291
|
+
return { detail: `${grouped[1]}: ${listedItems(grouped[2]!).join(", ").replace(/, \+(\d+)$/, " and $1 more")}`, ...(count > 0 ? { headline: `${grouped[1]} (${plural(count, "symbol")})` } : {}) };
|
|
292
|
+
}
|
|
293
|
+
return { headline: clause, detail: clause };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function readNote(note: string | undefined, rowCount: number | undefined): NoteReading {
|
|
297
|
+
if (!note?.trim()) return { headline: null, details: [] };
|
|
298
|
+
const headlines: string[] = [];
|
|
299
|
+
const details: string[] = [];
|
|
300
|
+
for (const clause of noteClauses(note)) {
|
|
301
|
+
// The unpriced sentence already says what totals do without them.
|
|
302
|
+
if (/^totals and weights leave (?:it|them) out$/i.test(clause)) continue;
|
|
303
|
+
// A clause in lower case finishes the one before it ("weighted at the latest close").
|
|
304
|
+
if (/^[a-z]/.test(clause) && details.length > 0 && !INTERNAL_CLAUSE.test(clause) && !RAW_TEXT.test(clause)) {
|
|
305
|
+
details[details.length - 1] = `${details[details.length - 1]}, ${clause}`;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const { headline, detail } = readClause(clause, rowCount);
|
|
309
|
+
if (headline) headlines.push(headline);
|
|
310
|
+
if (detail && !details.includes(detail)) details.push(detail);
|
|
311
|
+
}
|
|
312
|
+
// A counted gap ("3 of 94 positions had no price") says the most in the fewest words.
|
|
313
|
+
const counted = headlines.find((line) => /^\d|covers|qualify/i.test(line));
|
|
314
|
+
return { headline: counted ?? headlines[0] ?? null, details };
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** Why a call failed, in one line a person can read. */
|
|
318
|
+
function failureLine(row: ASKGToolRow): string {
|
|
319
|
+
const note = row.note?.trim() ?? "";
|
|
320
|
+
switch (row.status) {
|
|
321
|
+
case "timeout":
|
|
322
|
+
return /answered without it/i.test(note) ? "Took too long, so Gloom answered without it" : "Took too long to answer";
|
|
323
|
+
case "cancelled":
|
|
324
|
+
return "Stopped";
|
|
325
|
+
case "denied":
|
|
326
|
+
if (/declined/i.test(note)) return "You declined this";
|
|
327
|
+
if (/confirmation/i.test(note)) return "Needs your approval";
|
|
328
|
+
return "Not available in this window";
|
|
329
|
+
default: {
|
|
330
|
+
if (!note) return "Could not load this";
|
|
331
|
+
const clauses = noteClauses(note);
|
|
332
|
+
const first = clauses[0] ?? "";
|
|
333
|
+
if (/could not send this result|no longer has this tool call|too large to send/i.test(first)) return first;
|
|
334
|
+
if (SERVICE_FAILURE.test(first) || RAW_TEXT.test(first) || INTERNAL_CLAUSE.test(first) || first.length > 140) {
|
|
335
|
+
return "Could not load this";
|
|
336
|
+
}
|
|
337
|
+
return first;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function markFor(row: ASKGToolRow): ToolMark {
|
|
343
|
+
switch (row.status) {
|
|
344
|
+
case "pending":
|
|
345
|
+
case "running":
|
|
346
|
+
return "running";
|
|
347
|
+
case "awaiting-confirmation":
|
|
348
|
+
return "waiting";
|
|
349
|
+
case "ok":
|
|
350
|
+
return "ok";
|
|
351
|
+
case "partial":
|
|
352
|
+
return "partial";
|
|
353
|
+
case "cancelled":
|
|
354
|
+
return "stopped";
|
|
355
|
+
case "denied":
|
|
356
|
+
return "declined";
|
|
357
|
+
case "error":
|
|
358
|
+
case "timeout":
|
|
359
|
+
return "failed";
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function isScriptRow(row: Pick<ASKGToolRow, "name" | "origin">): boolean {
|
|
364
|
+
return row.origin === "server" && row.name === SCRIPT_TOOL_NAME;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function describeToolRow(row: ASKGToolRow, context: ToolDisplayContext = {}): ToolRowView {
|
|
368
|
+
const mark = markFor(row);
|
|
369
|
+
const args = row.args ?? {};
|
|
370
|
+
const script = isScriptRow(row);
|
|
371
|
+
// A server tool's note is a caveat about its result, not what it read, so
|
|
372
|
+
// its subject comes from its arguments. A row the platform sent none for,
|
|
373
|
+
// an older server or arguments too large to send, has no subject.
|
|
374
|
+
const subject = script ? "" : subjectFromArgs(args, context);
|
|
375
|
+
const qualifier = script ? "" : qualifierFromArgs(args);
|
|
376
|
+
const finished = mark !== "running" && mark !== "waiting";
|
|
377
|
+
// A script counts calls in its note ("3 calls, 1.2 s"), not rows.
|
|
378
|
+
const size = script || mark === "failed" || mark === "stopped" || mark === "declined" ? "" : countText(row.rowCount);
|
|
379
|
+
const meta = finished ? [size, formatToolDuration(row.elapsedMs)].filter(Boolean).join(" · ") : "";
|
|
380
|
+
|
|
381
|
+
const reading = mark === "partial" || mark === "ok" ? readNote(script ? undefined : row.note, row.rowCount) : null;
|
|
382
|
+
const line = mark === "failed" || mark === "stopped" || mark === "declined"
|
|
383
|
+
? failureLine(row)
|
|
384
|
+
: mark === "partial"
|
|
385
|
+
? reading?.headline ?? null
|
|
386
|
+
: mark === "waiting"
|
|
387
|
+
? "Waiting for your approval"
|
|
388
|
+
: null;
|
|
389
|
+
const details = reading?.details.length
|
|
390
|
+
? reading.details
|
|
391
|
+
: line && mark !== "waiting"
|
|
392
|
+
? [line]
|
|
393
|
+
: [];
|
|
394
|
+
if (row.truncated && mark !== "failed") details.push("Gloom read a shortened copy of this result");
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
title: toolTitle(row.name, context),
|
|
398
|
+
subject: [subject, qualifier].filter(Boolean).join(" · "),
|
|
399
|
+
meta,
|
|
400
|
+
mark,
|
|
401
|
+
line,
|
|
402
|
+
details,
|
|
403
|
+
// A script's argument is its code, which is not a summary of anything.
|
|
404
|
+
arguments: script ? [] : argumentPairs(row.args),
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export interface ToolGroupView {
|
|
409
|
+
/** "Holdings, Portfolio risk and 3 more". */
|
|
410
|
+
label: string;
|
|
411
|
+
/** "6 calls · 6.3 s". */
|
|
412
|
+
meta: string;
|
|
413
|
+
failed: number;
|
|
414
|
+
running: boolean;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/** One line for a turn's calls, for a turn with too many to list. */
|
|
418
|
+
export function describeToolGroup(rows: readonly ASKGToolRow[], context: ToolDisplayContext = {}): ToolGroupView {
|
|
419
|
+
const calls = rows.filter((row) => !isScriptRow(row));
|
|
420
|
+
const titles: string[] = [];
|
|
421
|
+
for (const row of calls) {
|
|
422
|
+
const title = toolTitle(row.name, context);
|
|
423
|
+
if (!titles.includes(title)) titles.push(title);
|
|
424
|
+
}
|
|
425
|
+
const named = titles.slice(0, 2).join(", ");
|
|
426
|
+
const label = titles.length > 2 ? `${named} and ${titles.length - 2} more` : named || "Tools";
|
|
427
|
+
const script = rows.find(isScriptRow);
|
|
428
|
+
const elapsed = script?.elapsedMs ?? calls.reduce((total, row) => total + (row.elapsedMs ?? 0), 0);
|
|
429
|
+
const failed = calls.filter((row) => row.status === "error" || row.status === "timeout").length;
|
|
430
|
+
const running = rows.some((row) => row.status === "pending" || row.status === "running" || row.status === "awaiting-confirmation");
|
|
431
|
+
return {
|
|
432
|
+
label,
|
|
433
|
+
meta: [plural(calls.length, "call"), formatToolDuration(elapsed || undefined)].filter(Boolean).join(" · "),
|
|
434
|
+
failed,
|
|
435
|
+
running,
|
|
436
|
+
};
|
|
437
|
+
}
|