cartethyia 2.4.4 → 2.4.6
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/.env.example +4 -1
- package/README.md +18 -0
- package/dist/dashboard/assets/AccountCooldown-ChpdzxRH.js.gz +0 -0
- package/dist/dashboard/assets/{BannedPage-TDue2X0p.js → BannedPage-QhvbJB9o.js} +1 -1
- package/dist/dashboard/assets/BannedPage-QhvbJB9o.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-qaHXuiI5.js → CliToolDetailPage-Bcy150Jo.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-Bcy150Jo.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BFuQBKez.js → CliToolsPage-DyNXefph.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DyNXefph.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-Cak0ljnO.js +1 -0
- package/dist/dashboard/assets/CombosPage-Cak0ljnO.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CATpAEOz.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-CATpAEOz.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-BhglcqyR.js → CustomizationPage-D6jEU7nL.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-D6jEU7nL.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CZkpn0a7.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-CZkpn0a7.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-CeqROJrT.js → LoginPage-BJlMVN4U.js} +1 -1
- package/dist/dashboard/assets/LoginPage-BJlMVN4U.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-Br3CXEau.js +1 -0
- package/dist/dashboard/assets/ModelPicker-Br3CXEau.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-CRXSAITY.js → OverviewPage-CQxXbo2g.js} +1 -1
- package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CXiumA53.js +7 -0
- package/dist/dashboard/assets/ProxyPage-CXiumA53.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js +1 -0
- package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-YxRml8AT.js → SettingsPage-BHW4Zt06.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-BHW4Zt06.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-VOYC_lIa.js +1 -0
- package/dist/dashboard/assets/SetupPage-VOYC_lIa.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-DpOTnGuH.js +1 -0
- package/dist/dashboard/assets/SortableList-DpOTnGuH.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-BNIDLiU6.js +31 -0
- package/dist/dashboard/assets/StudioPage-BNIDLiU6.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-B6LA4ewF.js → UsagePage-BAFaSDQV.js} +14 -14
- package/dist/dashboard/assets/UsagePage-BAFaSDQV.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BETfaMYZ.js +1 -0
- package/dist/dashboard/assets/api-keys-BETfaMYZ.js.gz +0 -0
- package/dist/dashboard/assets/app-BLCvGdzb.css +2 -0
- package/dist/dashboard/assets/app-BLCvGdzb.css.gz +0 -0
- package/dist/dashboard/assets/{app-BDJWMThu.js → app-Cjq7nrwu.js} +3 -3
- package/dist/dashboard/assets/app-Cjq7nrwu.js.gz +0 -0
- package/dist/dashboard/assets/arrow-left-CpBxkoxI.js.gz +0 -0
- package/dist/dashboard/assets/arrow-right-Dl5yKnp8.js.gz +0 -0
- package/dist/dashboard/assets/{assert-Bwh6DJTK.js → assert-7J6_LVD3.js} +1 -1
- package/dist/dashboard/assets/assert-7J6_LVD3.js.gz +0 -0
- package/dist/dashboard/assets/backup-file-gdKIlg8U.js.gz +0 -0
- package/dist/dashboard/assets/{badge-BwmwEOgA.js → badge-BTyGk_DL.js} +1 -1
- package/dist/dashboard/assets/badge-BTyGk_DL.js.gz +0 -0
- package/dist/dashboard/assets/{banner-BKBfKTqn.js → banner-bujTWYM4.js} +1 -1
- package/dist/dashboard/assets/banner-bujTWYM4.js.gz +0 -0
- package/dist/dashboard/assets/brain-Cwed_72z.js.gz +0 -0
- package/dist/dashboard/assets/{card-BTdbRFFg.js → card-B0Bnx5CA.js} +1 -1
- package/dist/dashboard/assets/card-B0Bnx5CA.js.gz +0 -0
- package/dist/dashboard/assets/check-D69FzdvC.js.gz +0 -0
- package/dist/dashboard/assets/chevron-right-BXIy5l3h.js.gz +0 -0
- package/dist/dashboard/assets/circle-alert-CntYHV5v.js.gz +0 -0
- package/dist/dashboard/assets/circle-check-BU3v_mFW.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-DE2ug812.js +1 -0
- package/dist/dashboard/assets/cli-tools-DE2ug812.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-R_rArH8S.js +1 -0
- package/dist/dashboard/assets/clipboard-button-R_rArH8S.js.gz +0 -0
- package/dist/dashboard/assets/cog-CdWhsajs.js.gz +0 -0
- package/dist/dashboard/assets/copy-ngmQ9zcZ.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-iocKA3jr.js → dialog-BWIP_EvW.js} +1 -1
- package/dist/dashboard/assets/dialog-BWIP_EvW.js.gz +0 -0
- package/dist/dashboard/assets/dialog-actions-B1axpEg7.js.gz +0 -0
- package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
- package/dist/dashboard/assets/download-dRFo5_Wu.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CDKOTZdY.js → drawer-BKcgVugF.js} +1 -1
- package/dist/dashboard/assets/drawer-BKcgVugF.js.gz +0 -0
- package/dist/dashboard/assets/entry-7dpgvpJ3.js +4 -0
- package/dist/dashboard/assets/entry-7dpgvpJ3.js.gz +0 -0
- package/dist/dashboard/assets/entry-CcWkGR4a.js +1 -0
- package/dist/dashboard/assets/entry-CcWkGR4a.js.gz +0 -0
- package/dist/dashboard/assets/entry-kTiTFrvh.js +1 -0
- package/dist/dashboard/assets/entry-kTiTFrvh.js.gz +0 -0
- package/dist/dashboard/assets/eye-C_hawfH4.js.gz +0 -0
- package/dist/dashboard/assets/eye-off-Bk5g2luF.js.gz +0 -0
- package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
- package/dist/dashboard/assets/gauge-BbIMy7MB.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-Booc5mNe.js +1 -0
- package/dist/dashboard/assets/github-badge-Booc5mNe.js.gz +0 -0
- package/dist/dashboard/assets/image-BPaouViG.js.gz +0 -0
- package/dist/dashboard/assets/{index-BA_ni9Ix.js → index-D70pChfn.js} +2 -2
- package/dist/dashboard/assets/index-D70pChfn.js.gz +0 -0
- package/dist/dashboard/assets/{inline-DCejSLlA.js → inline-D1TCqM2D.js} +1 -1
- package/dist/dashboard/assets/inline-D1TCqM2D.js.gz +0 -0
- package/dist/dashboard/assets/{input-Bn4_kNav.js → input-B9oyU93y.js} +1 -1
- package/dist/dashboard/assets/input-B9oyU93y.js.gz +0 -0
- package/dist/dashboard/assets/jsx-runtime-CXUMngI_.js.gz +0 -0
- package/dist/dashboard/assets/key-round-UkavsGxp.js.gz +0 -0
- package/dist/dashboard/assets/layers-2-glBbjl.js.gz +0 -0
- package/dist/dashboard/assets/{layout-Bv-NxqZ5.js → layout-BArzXirQ.js} +1 -1
- package/dist/dashboard/assets/layout-BArzXirQ.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BLA0sldD.js → list-row-BVZzaoHF.js} +1 -1
- package/dist/dashboard/assets/list-row-BVZzaoHF.js.gz +0 -0
- package/dist/dashboard/assets/{live-YlifPYox.js → live-EmuIayqp.js} +1 -1
- package/dist/dashboard/assets/live-EmuIayqp.js.gz +0 -0
- package/dist/dashboard/assets/log-in-BmRjy60c.js.gz +0 -0
- package/dist/dashboard/assets/message-circle-CCxGwRvv.js.gz +0 -0
- package/dist/dashboard/assets/{model-bans-CVvHZ-qz.js → model-bans-CSPQ9xB0.js} +1 -1
- package/dist/dashboard/assets/model-bans-CSPQ9xB0.js.gz +0 -0
- package/dist/dashboard/assets/mutation-BkoLM5Ba.js +1 -0
- package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CFL4_Dqc.js.gz +0 -0
- package/dist/dashboard/assets/pencil-768ysRAr.js.gz +0 -0
- package/dist/dashboard/assets/plus-DIdX_g-x.js.gz +0 -0
- package/dist/dashboard/assets/power-off-Yjw9GMJh.js +1 -0
- package/dist/dashboard/assets/power-off-Yjw9GMJh.js.gz +0 -0
- package/dist/dashboard/assets/privacy-mode-GM8bej85.js +1 -0
- package/dist/dashboard/assets/privacy-mode-GM8bej85.js.gz +0 -0
- package/dist/dashboard/assets/providers/agentrouter.svg.gz +0 -0
- package/dist/dashboard/assets/providers/aihubmix.svg.gz +0 -0
- package/dist/dashboard/assets/providers/alibaba-coding-plan.svg.gz +0 -0
- package/dist/dashboard/assets/providers/alibaba.svg.gz +0 -0
- package/dist/dashboard/assets/providers/antigravity.svg.gz +0 -0
- package/dist/dashboard/assets/providers/bai.svg.gz +0 -0
- package/dist/dashboard/assets/providers/blackbox.svg.gz +0 -0
- package/dist/dashboard/assets/providers/claude-code.svg.gz +0 -0
- package/dist/dashboard/assets/providers/exa.svg.gz +0 -0
- package/dist/dashboard/assets/providers/gmi-cloud.svg.gz +0 -0
- package/dist/dashboard/assets/providers/inferhub.svg.gz +0 -0
- package/dist/dashboard/assets/providers/muse.svg.gz +0 -0
- package/dist/dashboard/assets/providers/nous-research.svg.gz +0 -0
- package/dist/dashboard/assets/providers/openai-light.svg.gz +0 -0
- package/dist/dashboard/assets/providers/parallel.svg.gz +0 -0
- package/dist/dashboard/assets/providers/tokenharbor.svg.gz +0 -0
- package/dist/dashboard/assets/providers/zai-coding-plan.svg.gz +0 -0
- package/dist/dashboard/assets/{query-keys-ROf-g1Wi.js → query-keys-D7wX2vM5.js} +1 -1
- package/dist/dashboard/assets/query-keys-D7wX2vM5.js.gz +0 -0
- package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
- package/dist/dashboard/assets/refresh-cw-BqJFk4sU.js.gz +0 -0
- package/dist/dashboard/assets/rotate-ccw-CufcqITi.js.gz +0 -0
- package/dist/dashboard/assets/route-CNSNj9Zm.js.gz +0 -0
- package/dist/dashboard/assets/{routing-jntw9-Ui.js → routing-BExgxxBU.js} +1 -1
- package/dist/dashboard/assets/routing-BExgxxBU.js.gz +0 -0
- package/dist/dashboard/assets/scaling-nWE4Cx8f.js.gz +0 -0
- package/dist/dashboard/assets/search-JOKus9rb.js.gz +0 -0
- package/dist/dashboard/assets/{select-CGUuTQmj.js → select-C9mMoEpJ.js} +1 -1
- package/dist/dashboard/assets/select-C9mMoEpJ.js.gz +0 -0
- package/dist/dashboard/assets/settings-C4_Gn_wq.js +1 -0
- package/dist/dashboard/assets/settings-C4_Gn_wq.js.gz +0 -0
- package/dist/dashboard/assets/shield-check-DVS0Foqh.js.gz +0 -0
- package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js.gz +0 -0
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
- package/dist/dashboard/assets/{stack-C1kTcOmP.js → stack-Ca5HxI5i.js} +1 -1
- package/dist/dashboard/assets/stack-Ca5HxI5i.js.gz +0 -0
- package/dist/dashboard/assets/{state-DHKdg-pm.js → state-CzUPfLXo.js} +1 -1
- package/dist/dashboard/assets/state-CzUPfLXo.js.gz +0 -0
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
- package/dist/dashboard/assets/{switch-DIDeAiz9.js → switch-DOUIky_i.js} +1 -1
- package/dist/dashboard/assets/switch-DOUIky_i.js.gz +0 -0
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js +1 -0
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
- package/dist/dashboard/assets/toast-C76WrMhc.js +2 -0
- package/dist/dashboard/assets/toast-C76WrMhc.js.gz +0 -0
- package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
- package/dist/dashboard/assets/trash-Cppn5c3R.js.gz +0 -0
- package/dist/dashboard/assets/use-clipboard-B0Sy03fE.js.gz +0 -0
- package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
- package/dist/dashboard/assets/use-reduced-motion-C4B0R6Sz.js.gz +0 -0
- package/dist/dashboard/assets/use-timeout-BwcBBRrT.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-DVmwOKU-.js → useMutation-D87FZwH0.js} +1 -1
- package/dist/dashboard/assets/useMutation-D87FZwH0.js.gz +0 -0
- package/dist/dashboard/assets/wrench-B6E1oEuY.js.gz +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +123 -0
- package/migrations/full-postgres/0013_add_providers_tenant_id_index.sql +22 -0
- package/migrations/full-postgres/0014_add_provider_accounts_tenant_id_index.sql +21 -0
- package/migrations/lite-sqlite3/0000_baseline.sql +4 -2
- package/migrations/lite-sqlite3/0013_add_providers_tenant_id_index.sql +4 -0
- package/migrations/lite-sqlite3/0014_add_provider_accounts_tenant_id_index.sql +4 -0
- package/package.json +25 -30
- package/scripts/cli/{carte-launcher.cjs → bin/carte.cjs} +8 -8
- package/scripts/cli/{cli-launcher.cjs → bin/cartethyia.cjs} +167 -134
- package/scripts/cli/command/admin.ts +65 -0
- package/scripts/cli/command/console-menu.ts +227 -0
- package/scripts/cli/{doctor.ts → command/doctor.ts} +257 -258
- package/scripts/cli/{setup.ts → command/setup.ts} +8 -12
- package/scripts/cli/command/start.ts +13 -0
- package/scripts/cli/command/tray.ts +165 -0
- package/scripts/cli/command/update.ts +23 -0
- package/scripts/cli/{runtime-state.ts → gateway/drain-token.ts} +78 -78
- package/scripts/cli/gateway/spawn.ts +101 -0
- package/scripts/cli/gateway/stop.ts +51 -0
- package/scripts/cli/main.ts +94 -0
- package/scripts/cli/support/bun.ts +27 -0
- package/scripts/cli/support/env.ts +99 -0
- package/scripts/cli/support/platform.ts +64 -0
- package/scripts/cli/support/services.ts +88 -0
- package/scripts/cli/support/startup-signal.ts +23 -0
- package/scripts/cli/support/version.ts +37 -0
- package/scripts/cli/tray/hidden-window.vbs +28 -0
- package/scripts/cli/{tray.ts → tray/index.ts} +3 -3
- package/scripts/cli/{tray.ps1 → tray/windows.ps1} +107 -98
- package/scripts/cli/ui/background.ts +49 -0
- package/src/boot/app.ts +3 -1
- package/src/boot/dependencies.ts +36 -13
- package/src/config/providers.ts +27 -1
- package/src/config/spec.ts +11 -0
- package/src/console/backup/routes.ts +8 -0
- package/src/console/cli-tools/contracts.ts +6 -6
- package/src/console/console-router.ts +5 -3
- package/src/console/dashboard-assets.ts +81 -11
- package/src/console/observability/contracts.ts +54 -22
- package/src/console/observability/routes.ts +31 -6
- package/src/console/observability/store.ts +68 -28
- package/src/console/providers/catalog/public-model-store.ts +91 -60
- package/src/console/providers/catalog/store.ts +5 -1
- package/src/console/quota/account-quota-tenant.ts +9 -6
- package/src/console/response-compression.ts +69 -2
- package/src/console/routing/pools/probe-verdict.ts +72 -0
- package/src/console/share/share-router.ts +7 -4
- package/src/console/share/share-stats.ts +12 -5
- package/src/console/shared/read-through-cache.ts +133 -7
- package/src/console/updates/repository-updates.ts +39 -34
- package/src/network/outbound-fetch.ts +113 -25
- package/src/network/tls/bun-client-hello.ts +112 -0
- package/src/observability/event-log.ts +29 -8
- package/src/observability/metrics.ts +40 -13
- package/src/observability/runtime-metrics.ts +7 -0
- package/src/persistence/schema.ts +40 -2
- package/src/protocol/response/codex.ts +9 -75
- package/src/protocol/tool-identity.ts +43 -9
- package/src/providers/authentication/jwt-validator.ts +130 -187
- package/src/providers/authentication/oauth-flow-store.ts +16 -9
- package/src/providers/default-registry.ts +4 -0
- package/src/providers/discovery/catalog/catalog-format.ts +20 -0
- package/src/providers/discovery/models-dev-catalog.ts +39 -22
- package/src/providers/discovery/probe-wire.ts +29 -5
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +3 -2
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +88 -0
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +4 -0
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +33 -1
- package/src/providers/integrations/buddy/buddy-identity.ts +46 -0
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +37 -1
- package/src/providers/integrations/buddy/buddy-usage-store.ts +40 -5
- package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -2
- package/src/providers/integrations/buddy/codebuddy/shared.ts +106 -73
- package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +5 -2
- package/src/providers/integrations/buddy/workbuddy/quota.ts +172 -159
- package/src/providers/integrations/buddy/workbuddy/shared.ts +200 -171
- package/src/providers/integrations/codex/codex.ts +5 -8
- package/src/providers/integrations/factory/factory-oauth.ts +7 -11
- package/src/providers/integrations/opencode/opencode-go-quota.ts +130 -0
- package/src/providers/integrations/opencode/provider.ts +42 -3
- package/src/providers/integrations/qoder/qoder-oauth.ts +3 -9
- package/src/providers/integrations/shared/install-id.ts +29 -2
- package/src/providers/operations/client-versions.ts +11 -1
- package/src/providers/operations/model-catalog-cache.ts +18 -3
- package/src/providers/operations/provider-catalog-service.ts +76 -0
- package/src/transport/dispatch/attempt-finalize.ts +7 -1
- package/src/transport/dispatch/attempt-loop.ts +9 -7
- package/src/transport/dispatch/empty-stream.ts +17 -26
- package/src/transport/failure-policy.ts +20 -0
- package/src/transport/routing/route-catalog.ts +42 -3
- package/src/transport/surface/chat/encode.ts +18 -31
- package/src/transport/surface/messages/stream.ts +3 -2
- package/src/transport/translation/tool-repair.ts +37 -16
- package/src/workers/account-identity-sweep.ts +14 -12
- package/src/workers/daily-checkin.ts +62 -0
- package/src/workers/quota-refresh-sweep.ts +27 -2
- package/dist/dashboard/assets/CombosPage-B7ETkfVH.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-vkZBxMVo.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-DDkHfwpV.js +0 -1
- package/dist/dashboard/assets/ModelPicker-CAiPR5Vd.js +0 -1
- package/dist/dashboard/assets/ProviderDetailPage-cNAD_6uN.js +0 -3
- package/dist/dashboard/assets/ProvidersPage-Cv5tdxlx.js +0 -1
- package/dist/dashboard/assets/ProxyPage-CWvMfzjj.js +0 -7
- package/dist/dashboard/assets/QuotaPage-IYQOOHR4.js +0 -1
- package/dist/dashboard/assets/SetupPage-BPDNo3Ek.js +0 -1
- package/dist/dashboard/assets/SortableList-Bol1ASmI.js +0 -1
- package/dist/dashboard/assets/StudioPage-BE5DJONZ.js +0 -31
- package/dist/dashboard/assets/api-keys-CjIGQhe7.js +0 -1
- package/dist/dashboard/assets/app-Cjgo4-Lf.css +0 -2
- package/dist/dashboard/assets/cli-tools-DccaOfhX.js +0 -1
- package/dist/dashboard/assets/clipboard-button-DQmMikNQ.js +0 -1
- package/dist/dashboard/assets/entry-DTiWhIY-.js +0 -4
- package/dist/dashboard/assets/entry-Dm3PpDCO.js +0 -1
- package/dist/dashboard/assets/entry-keNDZ_Wz.js +0 -1
- package/dist/dashboard/assets/github-badge-BuAJr8oU.js +0 -1
- package/dist/dashboard/assets/mutation-BIizFZav.js +0 -1
- package/dist/dashboard/assets/privacy-mode-CQjbZ3xk.js +0 -1
- package/dist/dashboard/assets/settings-BAS6QbmJ.js +0 -1
- package/dist/dashboard/assets/terminal-C9mZ4Ugm.js +0 -1
- package/dist/dashboard/assets/toast-DKAdP2mo.js +0 -2
- package/scripts/cli/cli.ts +0 -766
- package/scripts/cli/version.ts +0 -66
- package/scripts/operations/probe-egress.ts +0 -335
- package/scripts/operations/restart.ts +0 -120
- package/scripts/shared/env.ts +0 -269
- /package/{tray-assets → scripts/cli/tray/assets}/cartethyia.ico +0 -0
- /package/{tray-assets → scripts/cli/tray/assets}/cartethyia.png +0 -0
- /package/scripts/cli/{menu.ts → ui/prompt.ts} +0 -0
- /package/scripts/cli/{wordmark.ts → ui/wordmark.ts} +0 -0
|
@@ -169,10 +169,11 @@ interface HistogramSeries {
|
|
|
169
169
|
class Histogram implements HistogramMetric {
|
|
170
170
|
private readonly series = new Map<string, HistogramSeries>();
|
|
171
171
|
/**
|
|
172
|
-
* The label names this histogram emits
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
172
|
+
* The label names this histogram emits. Declared at registration when the
|
|
173
|
+
* caller passes them to `histogram()`, otherwise fixed by the first LABELLED
|
|
174
|
+
* observation. A Prometheus metric family must expose one consistent label
|
|
175
|
+
* set, so a later observation carrying different keys is normalized against
|
|
176
|
+
* this set rather than creating a second, incompatible series.
|
|
176
177
|
*/
|
|
177
178
|
private labelNames: readonly string[] = [];
|
|
178
179
|
|
|
@@ -180,12 +181,18 @@ class Histogram implements HistogramMetric {
|
|
|
180
181
|
readonly name: string,
|
|
181
182
|
readonly help: string,
|
|
182
183
|
readonly buckets: readonly number[],
|
|
183
|
-
|
|
184
|
+
labelNames: readonly string[] = [],
|
|
185
|
+
) {
|
|
186
|
+
// A declared set is stable across runs and workers, so the exposition is
|
|
187
|
+
// deterministic even before the first observation arrives. Sorting keeps
|
|
188
|
+
// the order fixed either way.
|
|
189
|
+
this.labelNames = [...labelNames].sort();
|
|
190
|
+
}
|
|
184
191
|
|
|
185
192
|
observe(value: number, labels?: MetricLabels): void {
|
|
193
|
+
// Fall back to inferring the set from the first labelled observation when
|
|
194
|
+
// the metric was registered without declaring one.
|
|
186
195
|
if (this.labelNames.length === 0 && labels !== undefined) {
|
|
187
|
-
// Sorting makes the exposition order deterministic, so two runs of the same
|
|
188
|
-
// code produce byte-identical output.
|
|
189
196
|
this.labelNames = Object.keys(labels).sort();
|
|
190
197
|
}
|
|
191
198
|
const normalized = normalizeLabels(labels, this.labelNames);
|
|
@@ -271,7 +278,8 @@ export class PrometheusRegistry {
|
|
|
271
278
|
readonly cartethyia_routing_roundrobin_entries: GaugeMetric;
|
|
272
279
|
readonly cartethyia_ip_abuse_keys: GaugeMetric;
|
|
273
280
|
readonly cartethyia_quota_cache_entries: GaugeMetric;
|
|
274
|
-
readonly
|
|
281
|
+
readonly cartethyia_model_catalog_entries: GaugeMetric;
|
|
282
|
+
readonly cartethyia_proxy_dial_proxy_resolved_total: CounterMetric;
|
|
275
283
|
readonly proxy_provider_adapter_load_ms: HistogramMetric;
|
|
276
284
|
readonly pool_cooldown_record_failed: CounterMetric;
|
|
277
285
|
readonly quota_cache_invalidate_failed: CounterMetric;
|
|
@@ -348,9 +356,13 @@ export class PrometheusRegistry {
|
|
|
348
356
|
"cartethyia_quota_cache_entries",
|
|
349
357
|
"Entries in the in-process provider quota cache",
|
|
350
358
|
);
|
|
351
|
-
this.
|
|
352
|
-
"
|
|
353
|
-
"
|
|
359
|
+
this.cartethyia_model_catalog_entries = this.gauge(
|
|
360
|
+
"cartethyia_model_catalog_entries",
|
|
361
|
+
"Entries in the per-provider model catalog cache (at the cap means eviction churn)",
|
|
362
|
+
);
|
|
363
|
+
this.cartethyia_proxy_dial_proxy_resolved_total = this.counter(
|
|
364
|
+
"cartethyia_proxy_dial_proxy_resolved_total",
|
|
365
|
+
"Pool/relay-bound dials whose target is resolved by the proxy or relay rather than by the local resolver, so local DNS for the target is advisory only",
|
|
354
366
|
);
|
|
355
367
|
this.proxy_provider_adapter_load_ms = this.histogram(
|
|
356
368
|
"proxy_provider_adapter_load_ms",
|
|
@@ -379,8 +391,23 @@ export class PrometheusRegistry {
|
|
|
379
391
|
return metric;
|
|
380
392
|
}
|
|
381
393
|
|
|
382
|
-
|
|
383
|
-
|
|
394
|
+
/**
|
|
395
|
+
* Registers a histogram.
|
|
396
|
+
*
|
|
397
|
+
* `labelNames` declares the label set up front. It is optional because a
|
|
398
|
+
* histogram observed without labels still has to render, but passing it is
|
|
399
|
+
* the correct call: a declared set is stable across runs and workers, so the
|
|
400
|
+
* exposition is deterministic even before the first observation, and an
|
|
401
|
+
* observation carrying undeclared keys cannot create a second, incompatible
|
|
402
|
+
* series.
|
|
403
|
+
*/
|
|
404
|
+
histogram(
|
|
405
|
+
name: string,
|
|
406
|
+
help: string,
|
|
407
|
+
buckets: readonly number[],
|
|
408
|
+
labelNames: readonly string[] = [],
|
|
409
|
+
): HistogramMetric {
|
|
410
|
+
const metric = new Histogram(name, help, buckets, labelNames);
|
|
384
411
|
this.all.push(metric);
|
|
385
412
|
return metric;
|
|
386
413
|
}
|
|
@@ -24,6 +24,12 @@ export interface RuntimeMetricSources {
|
|
|
24
24
|
readonly ipAbuseKeys: () => number;
|
|
25
25
|
/** Tracked keys in the in-process quota cache tier (0 when Redis-only paths are idle). */
|
|
26
26
|
readonly quotaCacheEntries: () => number;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Entries in the per-provider model-catalog cache. Bounded, but a count that
|
|
30
|
+
* sits at the cap means every rebuild is evicting something it needs.
|
|
31
|
+
*/
|
|
32
|
+
readonly modelCatalogEntries: () => number;
|
|
27
33
|
/**
|
|
28
34
|
* Live in-flight request count. Zero means the gateway is idle, so a
|
|
29
35
|
* synchronous full collection is safe (no request to stall).
|
|
@@ -129,6 +135,7 @@ export class RuntimeMetricsSampler {
|
|
|
129
135
|
metrics.cartethyia_routing_roundrobin_entries.set(roundRobin.provider, { scope: "provider" });
|
|
130
136
|
metrics.cartethyia_ip_abuse_keys.set(this.sources.ipAbuseKeys());
|
|
131
137
|
metrics.cartethyia_quota_cache_entries.set(this.sources.quotaCacheEntries());
|
|
138
|
+
metrics.cartethyia_model_catalog_entries.set(this.sources.modelCatalogEntries());
|
|
132
139
|
|
|
133
140
|
this.checkPressure(memory.rss);
|
|
134
141
|
this.checkIdleReclaim(memory.rss);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Canonical Drizzle schema: every persistence table, enum, index, and shared type. */
|
|
2
|
-
import { sql } from "drizzle-orm";
|
|
2
|
+
import { desc, sql } from "drizzle-orm";
|
|
3
3
|
import {
|
|
4
4
|
bigint, boolean, check, customType, index, integer, jsonb, numeric, pgEnum, pgTable,
|
|
5
5
|
primaryKey, text, timestamp, uniqueIndex, uuid, type AnyPgColumn,
|
|
@@ -168,6 +168,14 @@ export const providers = pgTable(
|
|
|
168
168
|
// see `src/transport/routing/route-catalog.ts`.
|
|
169
169
|
requiresAccount: boolean("requires_account").notNull().default(true),
|
|
170
170
|
},
|
|
171
|
+
(table) => [
|
|
172
|
+
// `globalOrOwnedBy(providers.tenantId, …)` is the predicate behind
|
|
173
|
+
// `listModelsForTenant` and `/quota/overview`, and it is a bare
|
|
174
|
+
// `tenant_id IS NULL OR tenant_id = ?` — which no other index here can
|
|
175
|
+
// serve, so both reads scanned the whole provider list. Cheap to keep:
|
|
176
|
+
// providers are few and written rarely.
|
|
177
|
+
index("providers_tenant_id_idx").on(table.tenantId),
|
|
178
|
+
],
|
|
171
179
|
);
|
|
172
180
|
|
|
173
181
|
// Upstream account credentials plus the full health state machine.
|
|
@@ -262,6 +270,12 @@ export const providerAccounts = pgTable("provider_accounts", {
|
|
|
262
270
|
),
|
|
263
271
|
index("provider_accounts_status_cooldown_idx").on(table.status, table.cooldownUntil),
|
|
264
272
|
index("provider_accounts_provider_tenant_idx").on(table.providerId, table.tenantId),
|
|
273
|
+
// The bare `tenant_id IS NULL OR tenant_id = ?` that `listAllAccounts`
|
|
274
|
+
// uses is served by neither index above: `(status, cooldown_until)` leads
|
|
275
|
+
// with the wrong column, and `(provider_id, tenant_id)` cannot serve a
|
|
276
|
+
// predicate that does not constrain `provider_id`. This one matches the
|
|
277
|
+
// hot listing path.
|
|
278
|
+
index("provider_accounts_tenant_id_idx").on(table.tenantId),
|
|
265
279
|
],
|
|
266
280
|
);
|
|
267
281
|
|
|
@@ -473,7 +487,16 @@ export const healthEvents = pgTable(
|
|
|
473
487
|
},
|
|
474
488
|
(table) => [
|
|
475
489
|
index("health_events_account_id_created_at_idx").on(table.accountId, table.createdAt),
|
|
476
|
-
|
|
490
|
+
// Descending `created_at` is deliberate: health history is always read
|
|
491
|
+
// newest-first. The SQLite baseline drops the direction (see
|
|
492
|
+
// `scripts/generate/sqlite-ddl.ts` — SQLite scans an index either way),
|
|
493
|
+
// so this is a Postgres-only access-path choice, not a cross-backend
|
|
494
|
+
// disagreement.
|
|
495
|
+
index("health_events_account_model_created_idx").on(
|
|
496
|
+
table.accountId,
|
|
497
|
+
table.modelId,
|
|
498
|
+
desc(table.createdAt),
|
|
499
|
+
),
|
|
477
500
|
index("health_events_network_pool_id_created_at_idx").on(table.networkPoolId, table.createdAt),
|
|
478
501
|
check(
|
|
479
502
|
"health_events_entity_reference_check",
|
|
@@ -723,6 +746,21 @@ export const apiKeys = pgTable(
|
|
|
723
746
|
},
|
|
724
747
|
(table) => [
|
|
725
748
|
uniqueIndex("api_keys_key_hash_idx").on(table.keyHash),
|
|
749
|
+
/**
|
|
750
|
+
* One *live* default key per tenant, enforced by the database.
|
|
751
|
+
*
|
|
752
|
+
* The baseline SQL has always created this; the schema never declared it,
|
|
753
|
+
* so the two descriptions disagreed and nothing noticed. It is the only
|
|
754
|
+
* database-level guarantee behind `isDefault`, and
|
|
755
|
+
* `test/persistence/sqlite-baseline.test.ts` pins it by name — so the
|
|
756
|
+
* schema was the incomplete side, not the migration.
|
|
757
|
+
*
|
|
758
|
+
* Partial on `revoked_at IS NULL` so a tenant can rotate its default key
|
|
759
|
+
* without the old, revoked row blocking the new one.
|
|
760
|
+
*/
|
|
761
|
+
uniqueIndex("api_keys_one_default_per_tenant_uidx")
|
|
762
|
+
.on(table.tenantId)
|
|
763
|
+
.where(sql`${table.isDefault} = true AND ${table.revokedAt} IS NULL`),
|
|
726
764
|
index("api_keys_tenant_id_idx").on(table.tenantId),
|
|
727
765
|
index("api_keys_enabled_tenant_idx").on(table.tenantId).where(sql`${table.enabled} = true`),
|
|
728
766
|
index("api_keys_parent_key_id_idx").on(table.parentKeyId),
|
|
@@ -281,9 +281,7 @@ export class CodexStreamFrameProcessor {
|
|
|
281
281
|
// output_index routing + `output_item.added` registration.
|
|
282
282
|
readonly #openItems = new Map<string, OpenItemEntry>();
|
|
283
283
|
readonly #openItemsByOutputIndex = new Map<number, OpenItemEntry>();
|
|
284
|
-
|
|
285
|
-
// future reconciliation of streamed arguments against authoritative ones.
|
|
286
|
-
readonly #toolCallArgs = new Map<string, string[]>();
|
|
284
|
+
|
|
287
285
|
// Whitespace-loop guard: a model stuck emitting only whitespace tool-call
|
|
288
286
|
// argument deltas would otherwise hang the dispatch loop forever.
|
|
289
287
|
readonly #whitespaceDeltaTracking = new Map<
|
|
@@ -427,9 +425,6 @@ export class CodexStreamFrameProcessor {
|
|
|
427
425
|
: undefined;
|
|
428
426
|
const key = itemId ?? callId;
|
|
429
427
|
this.#checkWhitespaceLoopGuard(key, json["delta"] as string);
|
|
430
|
-
const chunks = this.#toolCallArgs.get(key) ?? [];
|
|
431
|
-
chunks.push(json["delta"] as string);
|
|
432
|
-
this.#toolCallArgs.set(key, chunks);
|
|
433
428
|
events.push({
|
|
434
429
|
type: "tool_call_delta",
|
|
435
430
|
sequence_number: this.#seq++,
|
|
@@ -443,14 +438,7 @@ export class CodexStreamFrameProcessor {
|
|
|
443
438
|
typeof json["delta"] === "string"
|
|
444
439
|
) {
|
|
445
440
|
const { callId, name } = this.#resolveToolIdentity(json);
|
|
446
|
-
|
|
447
|
-
typeof json["item_id"] === "string"
|
|
448
|
-
? (json["item_id"] as string)
|
|
449
|
-
: undefined;
|
|
450
|
-
const key = itemId ?? callId;
|
|
451
|
-
const chunks = this.#toolCallArgs.get(key) ?? [];
|
|
452
|
-
chunks.push(json["delta"] as string);
|
|
453
|
-
this.#toolCallArgs.set(key, chunks);
|
|
441
|
+
|
|
454
442
|
events.push({
|
|
455
443
|
type: "tool_call_delta",
|
|
456
444
|
sequence_number: this.#seq++,
|
|
@@ -505,37 +493,13 @@ export class CodexStreamFrameProcessor {
|
|
|
505
493
|
},
|
|
506
494
|
});
|
|
507
495
|
} else if (t === "response.function_call_arguments.done") {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const itemId =
|
|
512
|
-
typeof json["item_id"] === "string"
|
|
513
|
-
? (json["item_id"] as string)
|
|
514
|
-
: undefined;
|
|
515
|
-
let key: string | undefined;
|
|
516
|
-
if (itemId !== undefined) key = itemId;
|
|
517
|
-
else if (rawCallId !== undefined) key = decodeCodexToolCallId(rawCallId);
|
|
518
|
-
else {
|
|
519
|
-
const outputIndex = readOutputIndex(json);
|
|
520
|
-
if (outputIndex !== undefined) key = `idx_${outputIndex}`;
|
|
521
|
-
}
|
|
522
|
-
const finalArgs = (json as Record<string, unknown>)["arguments"];
|
|
523
|
-
if (typeof finalArgs === "string" && key !== undefined) {
|
|
524
|
-
this.#toolCallArgs.set(key, [finalArgs]);
|
|
525
|
-
}
|
|
496
|
+
// The arguments themselves are emitted by the delta events above; the
|
|
497
|
+
// `.done` event only marks the call complete.
|
|
498
|
+
|
|
526
499
|
this.hasToolCall = true;
|
|
527
500
|
} else if (t === "response.custom_tool_call_input.done") {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
? (json["item_id"] as string)
|
|
531
|
-
: undefined;
|
|
532
|
-
const rawCallId = (json["call_id"] as string | undefined) ?? itemId;
|
|
533
|
-
let key: string | undefined;
|
|
534
|
-
if (itemId !== undefined) key = itemId;
|
|
535
|
-
else if (rawCallId !== undefined) key = decodeCodexToolCallId(rawCallId);
|
|
536
|
-
const finalInput = (json as Record<string, unknown>)["input"];
|
|
537
|
-
if (typeof finalInput === "string" && key !== undefined)
|
|
538
|
-
this.#toolCallArgs.set(key, [finalInput]);
|
|
501
|
+
// As above: the input arrives as deltas, so `.done` only completes it.
|
|
502
|
+
|
|
539
503
|
this.hasToolCall = true;
|
|
540
504
|
} else if (t === "response.output_item.done") {
|
|
541
505
|
const item = json["item"];
|
|
@@ -598,43 +562,13 @@ export class CodexStreamFrameProcessor {
|
|
|
598
562
|
}
|
|
599
563
|
if (outputItem["type"] === "function_call") {
|
|
600
564
|
this.hasToolCall = true;
|
|
601
|
-
|
|
602
|
-
typeof outputItem["call_id"] === "string"
|
|
603
|
-
? (outputItem["call_id"] as string)
|
|
604
|
-
: undefined;
|
|
605
|
-
const decodedCallId =
|
|
606
|
-
callIdRaw !== undefined
|
|
607
|
-
? decodeCodexToolCallId(callIdRaw)
|
|
608
|
-
: undefined;
|
|
609
|
-
const authoritative =
|
|
610
|
-
typeof outputItem["arguments"] === "string"
|
|
611
|
-
? (outputItem["arguments"] as string)
|
|
612
|
-
: undefined;
|
|
613
|
-
if (authoritative !== undefined && decodedCallId !== undefined) {
|
|
614
|
-
const key = outputItemId ?? decodedCallId;
|
|
615
|
-
this.#toolCallArgs.set(key, [authoritative]);
|
|
616
|
-
}
|
|
565
|
+
|
|
617
566
|
if (outputItemId !== undefined) this.#openItems.delete(outputItemId);
|
|
618
567
|
if (outputIndex !== undefined)
|
|
619
568
|
this.#openItemsByOutputIndex.delete(outputIndex);
|
|
620
569
|
} else if (outputItem["type"] === "custom_tool_call") {
|
|
621
570
|
this.hasToolCall = true;
|
|
622
|
-
|
|
623
|
-
typeof outputItem["call_id"] === "string"
|
|
624
|
-
? (outputItem["call_id"] as string)
|
|
625
|
-
: undefined;
|
|
626
|
-
const decodedCallId =
|
|
627
|
-
callIdRaw !== undefined
|
|
628
|
-
? decodeCodexToolCallId(callIdRaw)
|
|
629
|
-
: undefined;
|
|
630
|
-
const authoritative =
|
|
631
|
-
typeof outputItem["input"] === "string"
|
|
632
|
-
? (outputItem["input"] as string)
|
|
633
|
-
: undefined;
|
|
634
|
-
if (authoritative !== undefined && decodedCallId !== undefined) {
|
|
635
|
-
const key = outputItemId ?? decodedCallId;
|
|
636
|
-
this.#toolCallArgs.set(key, [authoritative]);
|
|
637
|
-
}
|
|
571
|
+
|
|
638
572
|
if (outputItemId !== undefined) this.#openItems.delete(outputItemId);
|
|
639
573
|
if (outputIndex !== undefined)
|
|
640
574
|
this.#openItemsByOutputIndex.delete(outputIndex);
|
|
@@ -7,12 +7,33 @@ export interface ToolCallState {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Per-state argument fragments
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* Per-state argument fragments and their joined snapshot.
|
|
11
|
+
*
|
|
12
|
+
* The snapshot is cached on the CHUNK ARRAY, not on the state, because the
|
|
13
|
+
* array is deliberately handed forward from a superseded state to its
|
|
14
|
+
* replacement and mutated in place — so a reader holding the older
|
|
15
|
+
* `ToolCallState` still observes the newest total. Caching per state would
|
|
16
|
+
* freeze each state at the value it had when created and silently break that
|
|
17
|
+
* invariant (pinned by test/protocol/tool-identity.test.ts).
|
|
18
|
+
*
|
|
19
|
+
* The cache is dropped on push, so N deltas cost O(N) total: without it each
|
|
20
|
+
* read re-joined the whole array, and a reader that slices the string per
|
|
21
|
+
* delta — as the Messages stream does — re-joined and re-sliced once per
|
|
22
|
+
* fragment, which is O(n²) over a large tool argument.
|
|
14
23
|
*/
|
|
15
24
|
const argumentChunks = new WeakMap<ToolCallState, string[]>();
|
|
25
|
+
const argumentJoined = new WeakMap<string[], string>();
|
|
26
|
+
|
|
27
|
+
/** The accumulated arguments, joining only when a fragment has been added. */
|
|
28
|
+
function joinedArguments(state: ToolCallState): string {
|
|
29
|
+
const chunks = argumentChunks.get(state);
|
|
30
|
+
if (chunks === undefined) return "";
|
|
31
|
+
const cached = argumentJoined.get(chunks);
|
|
32
|
+
if (cached !== undefined) return cached;
|
|
33
|
+
const value = chunks.join("");
|
|
34
|
+
argumentJoined.set(chunks, value);
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
16
37
|
|
|
17
38
|
/**
|
|
18
39
|
* Single tool-call tracking home: id/index/arguments-accumulation keyed by
|
|
@@ -60,17 +81,17 @@ export function trackToolCall(
|
|
|
60
81
|
tracker.nextIndex = Math.max(tracker.nextIndex, index + 1);
|
|
61
82
|
const prior = tracker.states.get(tool.id);
|
|
62
83
|
const name = tool.name ?? prior?.name;
|
|
63
|
-
// Append the fragment in O(1) amortized
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// along one call id (superseded states are never read after replacement).
|
|
84
|
+
// Append the fragment in O(1) amortized. The chunk array is shared forward
|
|
85
|
+
// along one call id, so the joined cache is keyed on the array and dropped
|
|
86
|
+
// here: the next read re-joins once and re-caches.
|
|
67
87
|
const chunks =
|
|
68
88
|
prior !== undefined ? (argumentChunks.get(prior) ?? [prior.arguments]) : [];
|
|
69
89
|
chunks.push(tool.args ?? "");
|
|
90
|
+
argumentJoined.delete(chunks);
|
|
70
91
|
const state: ToolCallState = {
|
|
71
92
|
id: tool.id || prior?.id || "",
|
|
72
93
|
get arguments() {
|
|
73
|
-
return
|
|
94
|
+
return joinedArguments(state);
|
|
74
95
|
},
|
|
75
96
|
index,
|
|
76
97
|
};
|
|
@@ -80,6 +101,19 @@ export function trackToolCall(
|
|
|
80
101
|
return { index, isFirst: prior === undefined, state };
|
|
81
102
|
}
|
|
82
103
|
|
|
104
|
+
/**
|
|
105
|
+
* The not-yet-emitted tail of a call's arguments, from `offset`.
|
|
106
|
+
*
|
|
107
|
+
* Reads the cached joined string rather than re-joining the chunk array, so a
|
|
108
|
+
* caller that asks once per delta — as the Messages stream does — stays
|
|
109
|
+
* linear in the total argument length instead of quadratic. The `slice` itself
|
|
110
|
+
* is unavoidable: the caller needs the tail, and its own length is the output.
|
|
111
|
+
*/
|
|
112
|
+
export function argumentsFrom(state: ToolCallState, offset: number): string {
|
|
113
|
+
const all = joinedArguments(state);
|
|
114
|
+
return offset <= 0 ? all : all.slice(offset);
|
|
115
|
+
}
|
|
116
|
+
|
|
83
117
|
// ===== Emission ledger =====
|
|
84
118
|
|
|
85
119
|
/**
|