@ashlr/hub 3.4.0 → 3.5.1
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/CHANGELOG.md +107 -1
- package/README.md +3 -0
- package/dist/build-identity.json +2 -2
- package/dist/cli/index.js +11 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/local-runtime.js +40 -9
- package/dist/cli/local-runtime.js.map +1 -1
- package/dist/core/fleet/external-skill-audit.js +1 -1
- package/dist/core/fleet/external-skill-audit.js.map +1 -1
- package/dist/core/local-eval/classify.d.ts +57 -0
- package/dist/core/local-eval/classify.js +121 -0
- package/dist/core/local-eval/classify.js.map +1 -0
- package/dist/core/local-eval/configuration.d.ts +37 -0
- package/dist/core/local-eval/configuration.js +171 -0
- package/dist/core/local-eval/configuration.js.map +1 -0
- package/dist/core/local-eval/index.d.ts +15 -0
- package/dist/core/local-eval/index.js +16 -0
- package/dist/core/local-eval/index.js.map +1 -0
- package/dist/core/local-eval/main.d.ts +31 -0
- package/dist/core/local-eval/main.js +174 -0
- package/dist/core/local-eval/main.js.map +1 -0
- package/dist/core/local-eval/report.d.ts +25 -0
- package/dist/core/local-eval/report.js +157 -0
- package/dist/core/local-eval/report.js.map +1 -0
- package/dist/core/local-eval/runner.d.ts +55 -0
- package/dist/core/local-eval/runner.js +290 -0
- package/dist/core/local-eval/runner.js.map +1 -0
- package/dist/core/local-eval/tasks.d.ts +22 -0
- package/dist/core/local-eval/tasks.js +303 -0
- package/dist/core/local-eval/tasks.js.map +1 -0
- package/dist/core/local-eval/trace.d.ts +67 -0
- package/dist/core/local-eval/trace.js +309 -0
- package/dist/core/local-eval/trace.js.map +1 -0
- package/dist/core/local-eval/types.d.ts +262 -0
- package/dist/core/local-eval/types.js +23 -0
- package/dist/core/local-eval/types.js.map +1 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-host.d.ts +68 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-host.js +120 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-host.js.map +1 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-process.d.ts +15 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-process.js +21 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-process.js.map +1 -0
- package/dist/core/local-runtime/llama/anthropic-proxy.d.ts +2 -1
- package/dist/core/local-runtime/llama/anthropic-proxy.js +14 -6
- package/dist/core/local-runtime/llama/anthropic-proxy.js.map +1 -1
- package/dist/core/local-runtime/llama/anthropic-shim.d.ts +33 -0
- package/dist/core/local-runtime/llama/anthropic-shim.js +59 -0
- package/dist/core/local-runtime/llama/anthropic-shim.js.map +1 -1
- package/dist/core/local-runtime/llama/config.d.ts +123 -6
- package/dist/core/local-runtime/llama/config.js +196 -6
- package/dist/core/local-runtime/llama/config.js.map +1 -1
- package/dist/core/local-runtime/llama/index.d.ts +15 -0
- package/dist/core/local-runtime/llama/index.js +13 -0
- package/dist/core/local-runtime/llama/index.js.map +1 -1
- package/dist/core/local-runtime/llama/paths.d.ts +17 -0
- package/dist/core/local-runtime/llama/paths.js +25 -0
- package/dist/core/local-runtime/llama/paths.js.map +1 -1
- package/dist/core/local-runtime/llama/proxy-invocation.d.ts +101 -0
- package/dist/core/local-runtime/llama/proxy-invocation.js +134 -0
- package/dist/core/local-runtime/llama/proxy-invocation.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-launchd.d.ts +83 -0
- package/dist/core/local-runtime/llama/proxy-launchd.js +216 -0
- package/dist/core/local-runtime/llama/proxy-launchd.js.map +1 -0
- package/dist/core/local-runtime/llama/shapes.d.ts +2 -1
- package/dist/core/local-runtime/llama/shapes.js +2 -1
- package/dist/core/local-runtime/llama/shapes.js.map +1 -1
- package/dist/core/verse/adapters/claude.js +16 -0
- package/dist/core/verse/adapters/claude.js.map +1 -1
- package/dist/core/verse/adapters/codex.js +60 -2
- package/dist/core/verse/adapters/codex.js.map +1 -1
- package/dist/core/verse/adapters/grok.js +13 -0
- package/dist/core/verse/adapters/grok.js.map +1 -1
- package/dist/core/verse/control-api.d.ts +8 -9
- package/dist/core/verse/control-api.js +14 -114
- package/dist/core/verse/control-api.js.map +1 -1
- package/dist/core/verse/github-api.d.ts +50 -0
- package/dist/core/verse/github-api.js +211 -0
- package/dist/core/verse/github-api.js.map +1 -0
- package/dist/core/verse/github-proposal.d.ts +64 -0
- package/dist/core/verse/github-proposal.js +186 -0
- package/dist/core/verse/github-proposal.js.map +1 -0
- package/dist/core/verse/github-repo.d.ts +104 -0
- package/dist/core/verse/github-repo.js +476 -0
- package/dist/core/verse/github-repo.js.map +1 -0
- package/dist/core/verse/github-types.d.ts +174 -0
- package/dist/core/verse/github-types.js +31 -0
- package/dist/core/verse/github-types.js.map +1 -0
- package/dist/core/verse/mcp-cli-health.d.ts +149 -0
- package/dist/core/verse/mcp-cli-health.js +227 -0
- package/dist/core/verse/mcp-cli-health.js.map +1 -0
- package/dist/core/verse/mcp-control-api.d.ts +68 -0
- package/dist/core/verse/mcp-control-api.js +322 -0
- package/dist/core/verse/mcp-control-api.js.map +1 -0
- package/dist/core/verse/mcp-mutation.d.ts +187 -0
- package/dist/core/verse/mcp-mutation.js +471 -0
- package/dist/core/verse/mcp-mutation.js.map +1 -0
- package/dist/core/verse/mcp-scope.d.ts +114 -0
- package/dist/core/verse/mcp-scope.js +149 -0
- package/dist/core/verse/mcp-scope.js.map +1 -0
- package/dist/core/verse/mcp-seat-view.d.ts +197 -0
- package/dist/core/verse/mcp-seat-view.js +322 -0
- package/dist/core/verse/mcp-seat-view.js.map +1 -0
- package/dist/core/verse/path-guard.d.ts +115 -0
- package/dist/core/verse/path-guard.js +171 -0
- package/dist/core/verse/path-guard.js.map +1 -0
- package/dist/core/verse/seats.js +30 -2
- package/dist/core/verse/seats.js.map +1 -1
- package/dist/core/verse/session-engine.js +60 -1
- package/dist/core/verse/session-engine.js.map +1 -1
- package/dist/core/verse/session-store.js +20 -0
- package/dist/core/verse/session-store.js.map +1 -1
- package/dist/core/verse/types.d.ts +225 -1
- package/dist/core/verse/types.js +26 -0
- package/dist/core/verse/types.js.map +1 -1
- package/dist/core/verse/verse-api.d.ts +16 -1
- package/dist/core/verse/verse-api.js +338 -16
- package/dist/core/verse/verse-api.js.map +1 -1
- package/dist/core/verse/workspaces.d.ts +130 -0
- package/dist/core/verse/workspaces.js +501 -0
- package/dist/core/verse/workspaces.js.map +1 -0
- package/dist/core/web/api.js +23 -0
- package/dist/core/web/api.js.map +1 -1
- package/dist/core/web/public/next/assets/App-BbVoUCIi.js +7 -0
- package/dist/core/web/public/next/assets/App-BbVoUCIi.js.map +1 -0
- package/dist/core/web/public/next/assets/App-Cgi6j1Gk.css +1 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-BW9iVjUa.js +2 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-BW9iVjUa.js.map +1 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-Su-NUTis.css +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-CRqHUhED.js +2 -0
- package/dist/core/web/public/next/assets/AutonomySection-CRqHUhED.js.map +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-Cpk_oEhc.css +1 -0
- package/dist/core/web/public/next/assets/ChatSection-5irrh6Jw.js +80 -0
- package/dist/core/web/public/next/assets/ChatSection-5irrh6Jw.js.map +1 -0
- package/dist/core/web/public/next/assets/ChatSection-LQiAn6Eu.css +1 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-CXevY3Au.js +2 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-CXevY3Au.js.map +1 -0
- package/dist/core/web/public/next/assets/{ConfirmDialog-cYuivhCX.css → ConfirmDialog-Dx15x0Ho.css} +1 -1
- package/dist/core/web/public/next/assets/Dialog-Bn0CgEGz.js +2 -0
- package/dist/core/web/public/next/assets/Dialog-Bn0CgEGz.js.map +1 -0
- package/dist/core/web/public/next/assets/Dialog-tQ8kFulD.css +1 -0
- package/dist/core/web/public/next/assets/DiffViewer-C8HHTnVE.css +1 -0
- package/dist/core/web/public/next/assets/DiffViewer-QKyisN2L.js +7 -0
- package/dist/core/web/public/next/assets/DiffViewer-QKyisN2L.js.map +1 -0
- package/dist/core/web/public/next/assets/{MutationTokenDialog-jWLLCxWn.css → MutationTokenDialog-CrfJ0PdD.css} +1 -1
- package/dist/core/web/public/next/assets/MutationTokenDialog-DbSHPy3w.js +2 -0
- package/dist/core/web/public/next/assets/MutationTokenDialog-DbSHPy3w.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-C-PCgCzo.js +7 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-C-PCgCzo.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-CM_8pJs6.css +1 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-Dw8ZjmkS.js +2 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-Dw8ZjmkS.js.map +1 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-ekyMXAK8.css +1 -0
- package/dist/core/web/public/next/assets/SettingsSection-BII7TTSD.css +1 -0
- package/dist/core/web/public/next/assets/SettingsSection-CWxtTNlD.js +2 -0
- package/dist/core/web/public/next/assets/SettingsSection-CWxtTNlD.js.map +1 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Bk5HipM0.js +2 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Bk5HipM0.js.map +1 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Dh7A-hLD.css +1 -0
- package/dist/core/web/public/next/assets/UniverseView-Bqa8DH57.css +1 -0
- package/dist/core/web/public/next/assets/UniverseView-D8k9q0ce.js +9 -0
- package/dist/core/web/public/next/assets/UniverseView-D8k9q0ce.js.map +1 -0
- package/dist/core/web/public/next/assets/UsageSection-B2E06ZH1.js +2 -0
- package/dist/core/web/public/next/assets/UsageSection-B2E06ZH1.js.map +1 -0
- package/dist/core/web/public/next/assets/UsageSection-DwgNOYvi.css +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CRfZUV-T.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CRfZUV-T.js.map +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-D2E3mU9a.css +1 -0
- package/dist/core/web/public/next/assets/charts-CsrtT4rk.css +1 -0
- package/dist/core/web/public/next/assets/charts-DSUpczxG.js +2 -0
- package/dist/core/web/public/next/assets/charts-DSUpczxG.js.map +1 -0
- package/dist/core/web/public/next/assets/fleet-model-ClBbQ0Uj.js +2 -0
- package/dist/core/web/public/next/assets/fleet-model-ClBbQ0Uj.js.map +1 -0
- package/dist/core/web/public/next/assets/format-BNYWGJat.js +2 -0
- package/dist/core/web/public/next/assets/format-BNYWGJat.js.map +1 -0
- package/dist/core/web/public/next/assets/global-C4jfYHrj.js +2 -0
- package/dist/core/web/public/next/assets/global-C4jfYHrj.js.map +1 -0
- package/dist/core/web/public/next/assets/global-D463gG1X.css +1 -0
- package/dist/core/web/public/next/assets/icons-BxOX8-XB.js +2 -0
- package/dist/core/web/public/next/assets/icons-BxOX8-XB.js.map +1 -0
- package/dist/core/web/public/next/assets/index-BMRIET7F.js +11 -0
- package/dist/core/web/public/next/assets/index-BMRIET7F.js.map +1 -0
- package/dist/core/web/public/next/assets/queries-AxnVa02h.js +2 -0
- package/dist/core/web/public/next/assets/queries-AxnVa02h.js.map +1 -0
- package/dist/core/web/public/next/assets/use-guarded-action-BO6c94Wp.js +2 -0
- package/dist/core/web/public/next/assets/use-guarded-action-BO6c94Wp.js.map +1 -0
- package/dist/core/web/public/next/assets/verse-model-CvtK6vP6.js +2 -0
- package/dist/core/web/public/next/assets/verse-model-CvtK6vP6.js.map +1 -0
- package/dist/core/web/public/next/assets/workspace-model-cE4LkKpE.js +2 -0
- package/dist/core/web/public/next/assets/workspace-model-cE4LkKpE.js.map +1 -0
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/docs/README.md +4 -0
- package/node_modules/marked/README.md +8 -0
- package/node_modules/marked/bin/main.js +12 -11
- package/node_modules/marked/lib/marked.d.ts +88 -25
- package/node_modules/marked/lib/marked.esm.js +50 -44
- package/node_modules/marked/lib/marked.esm.js.map +3 -3
- package/node_modules/marked/lib/marked.umd.js +50 -44
- package/node_modules/marked/lib/marked.umd.js.map +3 -3
- package/node_modules/marked/man/marked.1 +1 -1
- package/node_modules/marked/package.json +21 -21
- package/package.json +13 -8
- package/dist/cli/activation.d.ts +0 -41
- package/dist/cli/activation.js +0 -485
- package/dist/cli/activation.js.map +0 -1
- package/dist/core/fleet/generated-repair-resolution.d.ts +0 -36
- package/dist/core/fleet/generated-repair-resolution.js +0 -245
- package/dist/core/fleet/generated-repair-resolution.js.map +0 -1
- package/dist/core/local-runtime/llama/port.d.ts +0 -17
- package/dist/core/local-runtime/llama/port.js +0 -47
- package/dist/core/local-runtime/llama/port.js.map +0 -1
- package/dist/core/local-runtime/llama/proxy-host.d.ts +0 -54
- package/dist/core/local-runtime/llama/proxy-host.js +0 -159
- package/dist/core/local-runtime/llama/proxy-host.js.map +0 -1
- package/dist/core/local-runtime/llama/proxy-process.d.ts +0 -148
- package/dist/core/local-runtime/llama/proxy-process.js +0 -250
- package/dist/core/local-runtime/llama/proxy-process.js.map +0 -1
- package/dist/core/local-runtime/llama/proxy-record.d.ts +0 -40
- package/dist/core/local-runtime/llama/proxy-record.js +0 -133
- package/dist/core/local-runtime/llama/proxy-record.js.map +0 -1
- package/dist/core/local-runtime/llama/proxy-supervisor.d.ts +0 -118
- package/dist/core/local-runtime/llama/proxy-supervisor.js +0 -511
- package/dist/core/local-runtime/llama/proxy-supervisor.js.map +0 -1
- package/dist/core/web/public/next/assets/App-BCKqSppK.css +0 -1
- package/dist/core/web/public/next/assets/App-LuILXjWG.js +0 -16
- package/dist/core/web/public/next/assets/App-LuILXjWG.js.map +0 -1
- package/dist/core/web/public/next/assets/ApprovalsSection-B_Xor8JH.js +0 -2
- package/dist/core/web/public/next/assets/ApprovalsSection-B_Xor8JH.js.map +0 -1
- package/dist/core/web/public/next/assets/ApprovalsSection-CRP59wSb.css +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-BB8RD-tv.css +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-BEwITtPJ.js +0 -2
- package/dist/core/web/public/next/assets/AutonomySection-BEwITtPJ.js.map +0 -1
- package/dist/core/web/public/next/assets/ChatSection-DrxqhBPK.css +0 -1
- package/dist/core/web/public/next/assets/ChatSection-bRAzlMth.js +0 -77
- package/dist/core/web/public/next/assets/ChatSection-bRAzlMth.js.map +0 -1
- package/dist/core/web/public/next/assets/ConfirmDialog-BqkZdPs_.js +0 -2
- package/dist/core/web/public/next/assets/ConfirmDialog-BqkZdPs_.js.map +0 -1
- package/dist/core/web/public/next/assets/Dialog-CPmedg4S.js +0 -2
- package/dist/core/web/public/next/assets/Dialog-CPmedg4S.js.map +0 -1
- package/dist/core/web/public/next/assets/Dialog-DxN7RgB5.css +0 -1
- package/dist/core/web/public/next/assets/DiffViewer-DmPJbeM_.js +0 -7
- package/dist/core/web/public/next/assets/DiffViewer-DmPJbeM_.js.map +0 -1
- package/dist/core/web/public/next/assets/DiffViewer-hN7X6wGT.css +0 -1
- package/dist/core/web/public/next/assets/Epistemic-DiyMyeaN.css +0 -1
- package/dist/core/web/public/next/assets/Epistemic-M3SxLHjq.js +0 -2
- package/dist/core/web/public/next/assets/Epistemic-M3SxLHjq.js.map +0 -1
- package/dist/core/web/public/next/assets/Meter-CGBsbXUX.css +0 -1
- package/dist/core/web/public/next/assets/Meter-D_X7c9U3.js +0 -2
- package/dist/core/web/public/next/assets/Meter-D_X7c9U3.js.map +0 -1
- package/dist/core/web/public/next/assets/MutationTokenDialog-Ba5ZHu-8.js +0 -2
- package/dist/core/web/public/next/assets/MutationTokenDialog-Ba5ZHu-8.js.map +0 -1
- package/dist/core/web/public/next/assets/RefreshIndicator-O7jUBOmX.css +0 -1
- package/dist/core/web/public/next/assets/RefreshIndicator-vHGpmyzb.js +0 -2
- package/dist/core/web/public/next/assets/RefreshIndicator-vHGpmyzb.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-B5g6JEVk.js +0 -7
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-B5g6JEVk.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-DLl4DbGG.css +0 -1
- package/dist/core/web/public/next/assets/RouteErrorBoundary-BIpdnxp-.css +0 -1
- package/dist/core/web/public/next/assets/RouteErrorBoundary-CroxuKoi.js +0 -2
- package/dist/core/web/public/next/assets/RouteErrorBoundary-CroxuKoi.js.map +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-DGJMdUh2.css +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-p-7FCGfn.js +0 -2
- package/dist/core/web/public/next/assets/SettingsSection-p-7FCGfn.js.map +0 -1
- package/dist/core/web/public/next/assets/Skeleton-4qq4HuJO.js +0 -2
- package/dist/core/web/public/next/assets/Skeleton-4qq4HuJO.js.map +0 -1
- package/dist/core/web/public/next/assets/Skeleton-D2JaTXyv.css +0 -1
- package/dist/core/web/public/next/assets/StatusBadge-BbEdqEGn.js +0 -2
- package/dist/core/web/public/next/assets/StatusBadge-BbEdqEGn.js.map +0 -1
- package/dist/core/web/public/next/assets/StatusBadge-TpDqZf6K.css +0 -1
- package/dist/core/web/public/next/assets/TableView-R6Yeztp1.css +0 -1
- package/dist/core/web/public/next/assets/TableView-nyYs7Sv1.js +0 -2
- package/dist/core/web/public/next/assets/TableView-nyYs7Sv1.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-CiZZxRPV.css +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-DjTpQUrA.js +0 -2
- package/dist/core/web/public/next/assets/UniverseConsoleApp-DjTpQUrA.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseView-BtApwayT.js +0 -9
- package/dist/core/web/public/next/assets/UniverseView-BtApwayT.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseView-gBxl6yum.css +0 -1
- package/dist/core/web/public/next/assets/UsageSection-Db99N6ao.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-Db99N6ao.js.map +0 -1
- package/dist/core/web/public/next/assets/UsageSection-UUYDidOg.css +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-COa3J2dO.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-COa3J2dO.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-mOAXvWa6.css +0 -1
- package/dist/core/web/public/next/assets/fleet-model-DXCfVtNW.js +0 -2
- package/dist/core/web/public/next/assets/fleet-model-DXCfVtNW.js.map +0 -1
- package/dist/core/web/public/next/assets/format-fggwu_Rs.js +0 -2
- package/dist/core/web/public/next/assets/format-fggwu_Rs.js.map +0 -1
- package/dist/core/web/public/next/assets/global-BeRYd1Bu.css +0 -1
- package/dist/core/web/public/next/assets/global-CNVapoV1.js +0 -2
- package/dist/core/web/public/next/assets/global-CNVapoV1.js.map +0 -1
- package/dist/core/web/public/next/assets/index-BkUlX2Se.js +0 -51
- package/dist/core/web/public/next/assets/index-BkUlX2Se.js.map +0 -1
- package/dist/core/web/public/next/assets/index-YNTgDG2b.js +0 -2
- package/dist/core/web/public/next/assets/index-YNTgDG2b.js.map +0 -1
- package/dist/core/web/public/next/assets/queries-C9XS4SYq.js +0 -2
- package/dist/core/web/public/next/assets/queries-C9XS4SYq.js.map +0 -1
- package/dist/core/web/public/next/assets/use-guarded-action-Bqa2v0a-.css +0 -1
- package/dist/core/web/public/next/assets/use-guarded-action-Bql1nA-z.js +0 -2
- package/dist/core/web/public/next/assets/use-guarded-action-Bql1nA-z.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-model-IrNQKtER.js +0 -2
- package/dist/core/web/public/next/assets/verse-model-IrNQKtER.js.map +0 -1
- package/node_modules/which/CHANGELOG.md +0 -166
- /package/node_modules/marked/{LICENSE.md → LICENSE} +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture the configuration a result is only meaningful against.
|
|
3
|
+
*
|
|
4
|
+
* "Four agents completed 4/4" is not a fact anyone can act on. "Four agents
|
|
5
|
+
* completed 4/4 on qwen3.8:27b-q8_0 at 4 slots x 65,536 context, temp 1.0,
|
|
6
|
+
* through the normalising proxy" is. The difference is whether the next person
|
|
7
|
+
* to change a setting can tell if they improved anything.
|
|
8
|
+
*
|
|
9
|
+
* READ, DO NOT ASK. Every field here is observed from the running system —
|
|
10
|
+
* llama-server's own `/props`, the process's real argv, Ollama's manifest —
|
|
11
|
+
* rather than accepted from a caller or a config file. A hand-maintained record
|
|
12
|
+
* of "what we were running" is the first thing to go stale, and a stale
|
|
13
|
+
* configuration silently invalidates every comparison made against it. The
|
|
14
|
+
* whole module is therefore best-effort and NEVER THROWS: an unknown field is
|
|
15
|
+
* recorded as unknown, which is honest, while a crashed capture would cost a
|
|
16
|
+
* whole benchmark run.
|
|
17
|
+
*/
|
|
18
|
+
import type { HarnessConfiguration } from './types.js';
|
|
19
|
+
export interface CaptureOptions {
|
|
20
|
+
/** Base URL the agent will be pointed at, e.g. `http://127.0.0.1:8090`. */
|
|
21
|
+
readonly baseUrl: string;
|
|
22
|
+
/** Origin llama-server itself is on, used for `/props`. */
|
|
23
|
+
readonly upstreamOrigin: string;
|
|
24
|
+
readonly agentCli: string;
|
|
25
|
+
/** Whether the run inserted the tracing proxy in front of `baseUrl`. */
|
|
26
|
+
readonly tracing: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Observe the live runtime. Best effort throughout; never throws.
|
|
30
|
+
*
|
|
31
|
+
* NOTE ON `contextPerSlot`. llama-server's `-c` is the TOTAL context, divided
|
|
32
|
+
* across `--parallel` slots. The number that bounds any single agent is the
|
|
33
|
+
* quotient, and `/props.n_ctx` already reports it per slot — so it is taken from
|
|
34
|
+
* there rather than recomputed, and both are recorded because confusing the two
|
|
35
|
+
* is how a 262,144 headline number gets attached to a 65,536 reality.
|
|
36
|
+
*/
|
|
37
|
+
export declare function captureConfiguration(opts: CaptureOptions): Promise<HarnessConfiguration>;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture the configuration a result is only meaningful against.
|
|
3
|
+
*
|
|
4
|
+
* "Four agents completed 4/4" is not a fact anyone can act on. "Four agents
|
|
5
|
+
* completed 4/4 on qwen3.8:27b-q8_0 at 4 slots x 65,536 context, temp 1.0,
|
|
6
|
+
* through the normalising proxy" is. The difference is whether the next person
|
|
7
|
+
* to change a setting can tell if they improved anything.
|
|
8
|
+
*
|
|
9
|
+
* READ, DO NOT ASK. Every field here is observed from the running system —
|
|
10
|
+
* llama-server's own `/props`, the process's real argv, Ollama's manifest —
|
|
11
|
+
* rather than accepted from a caller or a config file. A hand-maintained record
|
|
12
|
+
* of "what we were running" is the first thing to go stale, and a stale
|
|
13
|
+
* configuration silently invalidates every comparison made against it. The
|
|
14
|
+
* whole module is therefore best-effort and NEVER THROWS: an unknown field is
|
|
15
|
+
* recorded as unknown, which is honest, while a crashed capture would cost a
|
|
16
|
+
* whole benchmark run.
|
|
17
|
+
*/
|
|
18
|
+
import { execFile } from 'node:child_process';
|
|
19
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
20
|
+
import { homedir } from 'node:os';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { promisify } from 'node:util';
|
|
23
|
+
const execFileAsync = promisify(execFile);
|
|
24
|
+
/** Sampling parameters worth recording. The rest of `/props` is noise here. */
|
|
25
|
+
const SAMPLING_KEYS = [
|
|
26
|
+
'temperature',
|
|
27
|
+
'top_k',
|
|
28
|
+
'top_p',
|
|
29
|
+
'min_p',
|
|
30
|
+
'typical_p',
|
|
31
|
+
'repeat_penalty',
|
|
32
|
+
'repeat_last_n',
|
|
33
|
+
'presence_penalty',
|
|
34
|
+
'frequency_penalty',
|
|
35
|
+
'mirostat',
|
|
36
|
+
'seed',
|
|
37
|
+
];
|
|
38
|
+
const UNKNOWN = 'unknown';
|
|
39
|
+
async function fetchJson(url, timeoutMs = 5_000) {
|
|
40
|
+
try {
|
|
41
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
42
|
+
if (!res.ok)
|
|
43
|
+
return null;
|
|
44
|
+
return (await res.json());
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** The argv of whatever is listening on `port`, via lsof then ps. */
|
|
51
|
+
async function argvOnPort(port) {
|
|
52
|
+
try {
|
|
53
|
+
const { stdout } = await execFileAsync('lsof', ['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-t']);
|
|
54
|
+
const pid = stdout.trim().split('\n')[0];
|
|
55
|
+
if (!pid)
|
|
56
|
+
return [];
|
|
57
|
+
const { stdout: cmd } = await execFileAsync('ps', ['-o', 'command=', '-p', pid]);
|
|
58
|
+
return cmd.trim().split(/\s+/).filter(Boolean);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Reverse a content-addressed blob path back to the model reference a human
|
|
66
|
+
* would recognise.
|
|
67
|
+
*
|
|
68
|
+
* llama-server reports the blob it loaded, which is a sha256 and tells nobody
|
|
69
|
+
* anything. Ollama's manifest tree is the only mapping from that back to
|
|
70
|
+
* `qwen3.8:27b-q8_0`, so it is walked rather than the name being assumed from
|
|
71
|
+
* whatever someone last said in a status update.
|
|
72
|
+
*/
|
|
73
|
+
async function resolveModelRef(modelPath) {
|
|
74
|
+
const digest = /sha256-([0-9a-f]{64})/.exec(modelPath)?.[1];
|
|
75
|
+
if (!digest)
|
|
76
|
+
return UNKNOWN;
|
|
77
|
+
const root = join(process.env['OLLAMA_MODELS'] ?? join(homedir(), '.ollama', 'models'), 'manifests');
|
|
78
|
+
const walk = async (dir, depth = 0) => {
|
|
79
|
+
if (depth > 6)
|
|
80
|
+
return null;
|
|
81
|
+
let entries;
|
|
82
|
+
try {
|
|
83
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
const full = join(dir, entry.name);
|
|
90
|
+
if (entry.isDirectory()) {
|
|
91
|
+
const found = await walk(full, depth + 1);
|
|
92
|
+
if (found)
|
|
93
|
+
return found;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
if ((await stat(full)).size > 256_000)
|
|
98
|
+
continue;
|
|
99
|
+
if (!(await readFile(full, 'utf8')).includes(digest))
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// .../manifests/<registry>/<namespace>/<model>/<tag> -> model:tag
|
|
106
|
+
const parts = full.slice(root.length + 1).split('/');
|
|
107
|
+
if (parts.length >= 2)
|
|
108
|
+
return `${parts[parts.length - 2]}:${parts[parts.length - 1]}`;
|
|
109
|
+
return parts.join('/');
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
};
|
|
113
|
+
return (await walk(root)) ?? UNKNOWN;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Observe the live runtime. Best effort throughout; never throws.
|
|
117
|
+
*
|
|
118
|
+
* NOTE ON `contextPerSlot`. llama-server's `-c` is the TOTAL context, divided
|
|
119
|
+
* across `--parallel` slots. The number that bounds any single agent is the
|
|
120
|
+
* quotient, and `/props.n_ctx` already reports it per slot — so it is taken from
|
|
121
|
+
* there rather than recomputed, and both are recorded because confusing the two
|
|
122
|
+
* is how a 262,144 headline number gets attached to a 65,536 reality.
|
|
123
|
+
*/
|
|
124
|
+
export async function captureConfiguration(opts) {
|
|
125
|
+
const props = await fetchJson(`${opts.upstreamOrigin}/props`);
|
|
126
|
+
const defaults = (props?.['default_generation_settings'] ?? {});
|
|
127
|
+
const params = (defaults['params'] ?? {});
|
|
128
|
+
const modelPath = typeof props?.['model_path'] === 'string' ? props['model_path'] : UNKNOWN;
|
|
129
|
+
const contextPerSlot = typeof defaults['n_ctx'] === 'number' ? defaults['n_ctx'] : 0;
|
|
130
|
+
const slots = typeof props?.['total_slots'] === 'number' ? props['total_slots'] : 0;
|
|
131
|
+
const sampling = {};
|
|
132
|
+
for (const key of SAMPLING_KEYS) {
|
|
133
|
+
if (key in params)
|
|
134
|
+
sampling[key] = params[key];
|
|
135
|
+
}
|
|
136
|
+
const upstreamPort = Number(new URL(opts.upstreamOrigin).port || 80);
|
|
137
|
+
const baseUrlPort = Number(new URL(opts.baseUrl).port || 80);
|
|
138
|
+
const llamaArgv = await argvOnPort(upstreamPort);
|
|
139
|
+
// `-c` is authoritative for the total; fall back to slots x per-slot.
|
|
140
|
+
const cFlag = llamaArgv.indexOf('-c');
|
|
141
|
+
const contextTotal = cFlag >= 0 && llamaArgv[cFlag + 1]
|
|
142
|
+
? Number(llamaArgv[cFlag + 1])
|
|
143
|
+
: contextPerSlot * (slots || 1);
|
|
144
|
+
const proxyOn = baseUrlPort !== upstreamPort;
|
|
145
|
+
const proxyArgv = proxyOn ? await argvOnPort(baseUrlPort) : [];
|
|
146
|
+
let agentCli = UNKNOWN;
|
|
147
|
+
try {
|
|
148
|
+
const { stdout } = await execFileAsync(opts.agentCli, ['--version']);
|
|
149
|
+
agentCli = `${opts.agentCli} ${stdout.trim()}`;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
agentCli = opts.agentCli;
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
model: await resolveModelRef(modelPath),
|
|
156
|
+
modelPath,
|
|
157
|
+
quantization: typeof props?.['model_ftype'] === 'string' ? props['model_ftype'] : UNKNOWN,
|
|
158
|
+
slots,
|
|
159
|
+
contextPerSlot,
|
|
160
|
+
contextTotal: Number.isFinite(contextTotal) ? contextTotal : 0,
|
|
161
|
+
samplingParams: sampling,
|
|
162
|
+
baseUrl: opts.baseUrl,
|
|
163
|
+
proxy: proxyOn ? 'on' : 'off',
|
|
164
|
+
tracing: opts.tracing ? 'on' : 'off',
|
|
165
|
+
proxyImplementation: proxyOn ? (proxyArgv.join(' ') || UNKNOWN) : 'none (direct to llama-server)',
|
|
166
|
+
agentCli,
|
|
167
|
+
llamaServerArgv: llamaArgv,
|
|
168
|
+
capturedAt: new Date().toISOString(),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=configuration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configuration.js","sourceRoot":"","sources":["../../../src/core/local-eval/configuration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,+EAA+E;AAC/E,MAAM,aAAa,GAAsB;IACvC,aAAa;IACb,OAAO;IACP,OAAO;IACP,OAAO;IACP,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,kBAAkB;IAClB,mBAAmB;IACnB,UAAU;IACV,MAAM;CACP,CAAC;AAEF,MAAM,OAAO,GAAG,SAAS,CAAC;AAE1B,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,SAAS,GAAG,KAAK;IACrD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,qEAAqE;AACrE,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/F,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QACjF,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,eAAe,CAAC,SAAiB;IAC9C,MAAM,MAAM,GAAG,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAC;IAErG,MAAM,IAAI,GAAG,KAAK,EAAE,GAAW,EAAE,KAAK,GAAG,CAAC,EAA0B,EAAE;QACpE,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3B,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACnC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;gBAC1C,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBACxB,SAAS;YACX,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO;oBAAE,SAAS;gBAChD,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,SAAS;YACjE,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,oEAAoE;YACpE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACrD,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;gBAAE,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;YACtF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC;AACvC,CAAC;AAYD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAoB;IAC7D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,cAAc,QAAQ,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,CAAC,6BAA6B,CAAC,IAAI,EAAE,CAA4B,CAAC;IAC3F,MAAM,MAAM,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;IAErE,MAAM,SAAS,GAAG,OAAO,KAAK,EAAE,CAAC,YAAY,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC5F,MAAM,cAAc,GAAG,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,KAAK,GAAG,OAAO,KAAK,EAAE,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpF,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,IAAI,GAAG,IAAI,MAAM;YAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACrE,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC;IAEjD,sEAAsE;IACtE,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,YAAY,GAAG,KAAK,IAAI,CAAC,IAAI,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC;QACrD,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC9B,CAAC,CAAC,cAAc,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;IAElC,MAAM,OAAO,GAAG,WAAW,KAAK,YAAY,CAAC;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/D,IAAI,QAAQ,GAAG,OAAO,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QACrE,QAAQ,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC3B,CAAC;IAED,OAAO;QACL,KAAK,EAAE,MAAM,eAAe,CAAC,SAAS,CAAC;QACvC,SAAS;QACT,YAAY,EAAE,OAAO,KAAK,EAAE,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO;QACzF,KAAK;QACL,cAAc;QACd,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9D,cAAc,EAAE,QAAQ;QACxB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;QAC7B,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;QACpC,mBAAmB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,+BAA+B;QACjG,QAAQ;QACR,eAAe,EAAE,SAAS;QAC1B,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local-agent evaluation harness.
|
|
3
|
+
*
|
|
4
|
+
* Answers one question with a number: did a change to the local-model harness
|
|
5
|
+
* make agents better, worse, or neither? See `types.ts` for the three
|
|
6
|
+
* commitments the design rests on.
|
|
7
|
+
*/
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
export { TASKS } from './tasks.js';
|
|
10
|
+
export { classifyTrial, type TrialEvidence, type TrialVerdict } from './classify.js';
|
|
11
|
+
export { captureConfiguration, type CaptureOptions } from './configuration.js';
|
|
12
|
+
export { countChanges, parseAgentResult, runTrial, type RunTrialOptions } from './runner.js';
|
|
13
|
+
export { buildReport, renderReport, summariseTask } from './report.js';
|
|
14
|
+
export { diagnoseTimeout, startTrace, type StartTraceOptions, type TraceHandle } from './trace.js';
|
|
15
|
+
export { parseArgs, pool } from './main.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local-agent evaluation harness.
|
|
3
|
+
*
|
|
4
|
+
* Answers one question with a number: did a change to the local-model harness
|
|
5
|
+
* make agents better, worse, or neither? See `types.ts` for the three
|
|
6
|
+
* commitments the design rests on.
|
|
7
|
+
*/
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
export { TASKS } from './tasks.js';
|
|
10
|
+
export { classifyTrial } from './classify.js';
|
|
11
|
+
export { captureConfiguration } from './configuration.js';
|
|
12
|
+
export { countChanges, parseAgentResult, runTrial } from './runner.js';
|
|
13
|
+
export { buildReport, renderReport, summariseTask } from './report.js';
|
|
14
|
+
export { diagnoseTimeout, startTrace } from './trace.js';
|
|
15
|
+
export { parseArgs, pool } from './main.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/local-eval/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,aAAa,EAAyC,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAuB,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,UAAU,EAA4C,MAAM,YAAY,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry point: run the task set N times and print a comparable number.
|
|
3
|
+
*
|
|
4
|
+
* npx tsx src/core/local-eval/main.ts [--trials N] [--concurrency N]
|
|
5
|
+
* [--base-url URL] [--upstream URL]
|
|
6
|
+
* [--model REF] [--timeout-ms N]
|
|
7
|
+
* [--task ID] [--out FILE] [--no-trace]
|
|
8
|
+
*
|
|
9
|
+
* CONCURRENCY DEFAULTS TO 2, NOT TO THE SLOT COUNT. The runtime is shared with
|
|
10
|
+
* whatever else is using this machine. Saturating all four slots would make the
|
|
11
|
+
* harness's own timings a measurement of contention, and would degrade everyone
|
|
12
|
+
* else's turns while it ran. Raise it deliberately, and only on an idle box —
|
|
13
|
+
* and note that timings taken at different concurrencies are not comparable.
|
|
14
|
+
*/
|
|
15
|
+
interface Args {
|
|
16
|
+
trials: number;
|
|
17
|
+
concurrency: number;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
upstream: string;
|
|
20
|
+
model: string;
|
|
21
|
+
agentCli: string;
|
|
22
|
+
timeoutMs: number;
|
|
23
|
+
taskFilter: string | null;
|
|
24
|
+
out: string | null;
|
|
25
|
+
/** Insert the tracing proxy. On by default; `--no-trace` turns it off. */
|
|
26
|
+
trace: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare function parseArgs(argv: readonly string[]): Args;
|
|
29
|
+
/** Run `jobs` with at most `limit` in flight, preserving result order. */
|
|
30
|
+
export declare function pool<T>(jobs: readonly (() => Promise<T>)[], limit: number): Promise<T[]>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry point: run the task set N times and print a comparable number.
|
|
3
|
+
*
|
|
4
|
+
* npx tsx src/core/local-eval/main.ts [--trials N] [--concurrency N]
|
|
5
|
+
* [--base-url URL] [--upstream URL]
|
|
6
|
+
* [--model REF] [--timeout-ms N]
|
|
7
|
+
* [--task ID] [--out FILE] [--no-trace]
|
|
8
|
+
*
|
|
9
|
+
* CONCURRENCY DEFAULTS TO 2, NOT TO THE SLOT COUNT. The runtime is shared with
|
|
10
|
+
* whatever else is using this machine. Saturating all four slots would make the
|
|
11
|
+
* harness's own timings a measurement of contention, and would degrade everyone
|
|
12
|
+
* else's turns while it ran. Raise it deliberately, and only on an idle box —
|
|
13
|
+
* and note that timings taken at different concurrencies are not comparable.
|
|
14
|
+
*/
|
|
15
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
16
|
+
import { tmpdir } from 'node:os';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { pathToFileURL } from 'node:url';
|
|
19
|
+
import { captureConfiguration } from './configuration.js';
|
|
20
|
+
import { DEFAULT_ANTHROPIC_PROXY_PORT, DEFAULT_LLAMA_HOST, DEFAULT_LLAMA_PORT, } from '../local-runtime/llama/config.js';
|
|
21
|
+
import { buildReport, renderReport, summariseTask } from './report.js';
|
|
22
|
+
import { runTrial } from './runner.js';
|
|
23
|
+
import { TASKS } from './tasks.js';
|
|
24
|
+
export function parseArgs(argv) {
|
|
25
|
+
const args = {
|
|
26
|
+
trials: 3,
|
|
27
|
+
concurrency: 2,
|
|
28
|
+
// These DEFAULT TO THE SHIPPING PORTS, derived from config.ts rather than
|
|
29
|
+
// written out, and that is the whole point. The previous default was
|
|
30
|
+
// `http://127.0.0.1:8090`, which is not a port anything in this repository
|
|
31
|
+
// ever binds — it was a hand-started scratch script outside the tree. A
|
|
32
|
+
// baseline measured against it therefore could not be reproduced from a
|
|
33
|
+
// clean checkout: the harness pointed at a port that, for anyone but the
|
|
34
|
+
// one machine the script was running on, had nothing behind it. Deriving
|
|
35
|
+
// both from the constants keeps the harness aimed at the lane the product
|
|
36
|
+
// actually serves.
|
|
37
|
+
baseUrl: process.env['ASHLR_EVAL_BASE_URL']
|
|
38
|
+
?? `http://${DEFAULT_LLAMA_HOST}:${DEFAULT_ANTHROPIC_PROXY_PORT}`,
|
|
39
|
+
upstream: process.env['ASHLR_EVAL_UPSTREAM'] ?? `http://${DEFAULT_LLAMA_HOST}:${DEFAULT_LLAMA_PORT}`,
|
|
40
|
+
// llama-server serves whatever is loaded and ignores this, but the CLI
|
|
41
|
+
// stamps it into the result JSON, so it is the label the run is filed under.
|
|
42
|
+
model: process.env['ASHLR_EVAL_MODEL'] ?? 'qwen3.8',
|
|
43
|
+
agentCli: process.env['ASHLR_EVAL_AGENT'] ?? 'claude',
|
|
44
|
+
timeoutMs: 900_000,
|
|
45
|
+
taskFilter: null,
|
|
46
|
+
out: null,
|
|
47
|
+
trace: true,
|
|
48
|
+
};
|
|
49
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
50
|
+
const flag = argv[i];
|
|
51
|
+
const value = argv[i + 1];
|
|
52
|
+
switch (flag) {
|
|
53
|
+
case '--trials':
|
|
54
|
+
args.trials = Number(value);
|
|
55
|
+
i += 1;
|
|
56
|
+
break;
|
|
57
|
+
case '--concurrency':
|
|
58
|
+
args.concurrency = Number(value);
|
|
59
|
+
i += 1;
|
|
60
|
+
break;
|
|
61
|
+
case '--base-url':
|
|
62
|
+
args.baseUrl = String(value);
|
|
63
|
+
i += 1;
|
|
64
|
+
break;
|
|
65
|
+
case '--upstream':
|
|
66
|
+
args.upstream = String(value);
|
|
67
|
+
i += 1;
|
|
68
|
+
break;
|
|
69
|
+
case '--model':
|
|
70
|
+
args.model = String(value);
|
|
71
|
+
i += 1;
|
|
72
|
+
break;
|
|
73
|
+
case '--agent':
|
|
74
|
+
args.agentCli = String(value);
|
|
75
|
+
i += 1;
|
|
76
|
+
break;
|
|
77
|
+
case '--timeout-ms':
|
|
78
|
+
args.timeoutMs = Number(value);
|
|
79
|
+
i += 1;
|
|
80
|
+
break;
|
|
81
|
+
case '--task':
|
|
82
|
+
args.taskFilter = String(value);
|
|
83
|
+
i += 1;
|
|
84
|
+
break;
|
|
85
|
+
case '--out':
|
|
86
|
+
args.out = String(value);
|
|
87
|
+
i += 1;
|
|
88
|
+
break;
|
|
89
|
+
case '--no-trace':
|
|
90
|
+
args.trace = false;
|
|
91
|
+
break;
|
|
92
|
+
case '--trace':
|
|
93
|
+
args.trace = true;
|
|
94
|
+
break;
|
|
95
|
+
default: break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return args;
|
|
99
|
+
}
|
|
100
|
+
/** Run `jobs` with at most `limit` in flight, preserving result order. */
|
|
101
|
+
export async function pool(jobs, limit) {
|
|
102
|
+
const results = new Array(jobs.length);
|
|
103
|
+
let next = 0;
|
|
104
|
+
const workers = Array.from({ length: Math.max(1, Math.min(limit, jobs.length)) }, async () => {
|
|
105
|
+
for (;;) {
|
|
106
|
+
const index = next;
|
|
107
|
+
next += 1;
|
|
108
|
+
if (index >= jobs.length)
|
|
109
|
+
return;
|
|
110
|
+
results[index] = await jobs[index]();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
await Promise.all(workers);
|
|
114
|
+
return results;
|
|
115
|
+
}
|
|
116
|
+
async function main() {
|
|
117
|
+
const args = parseArgs(process.argv.slice(2));
|
|
118
|
+
const tasks = args.taskFilter ? TASKS.filter((t) => t.id === args.taskFilter) : TASKS;
|
|
119
|
+
if (tasks.length === 0) {
|
|
120
|
+
console.error(`no task matched ${args.taskFilter}`);
|
|
121
|
+
process.exitCode = 2;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const configuration = await captureConfiguration({
|
|
125
|
+
baseUrl: args.baseUrl,
|
|
126
|
+
upstreamOrigin: args.upstream,
|
|
127
|
+
agentCli: args.agentCli,
|
|
128
|
+
tracing: args.trace,
|
|
129
|
+
});
|
|
130
|
+
const root = join(tmpdir(), `ashlr-local-eval-${Date.now()}`);
|
|
131
|
+
await mkdir(root, { recursive: true });
|
|
132
|
+
console.error(`[local-eval] ${tasks.length} task(s) x ${args.trials} trial(s), `
|
|
133
|
+
+ `concurrency ${args.concurrency}, artifacts in ${root}`);
|
|
134
|
+
const startedAt = Date.now();
|
|
135
|
+
const jobs = [];
|
|
136
|
+
for (const task of tasks) {
|
|
137
|
+
for (let trial = 1; trial <= args.trials; trial += 1) {
|
|
138
|
+
jobs.push(async () => {
|
|
139
|
+
const result = await runTrial({
|
|
140
|
+
task,
|
|
141
|
+
trial,
|
|
142
|
+
trialDir: join(root, `${task.id}-${trial}`),
|
|
143
|
+
baseUrl: args.baseUrl,
|
|
144
|
+
model: args.model,
|
|
145
|
+
agentCli: args.agentCli,
|
|
146
|
+
timeoutMs: args.timeoutMs,
|
|
147
|
+
trace: args.trace,
|
|
148
|
+
});
|
|
149
|
+
console.error(`[local-eval] ${task.id}#${trial} ${result.mode} `
|
|
150
|
+
+ `(${(result.wallMs / 1000).toFixed(0)}s)`
|
|
151
|
+
+ (result.timeoutDiagnosis ? ` — ${result.timeoutDiagnosis.kind}` : ''));
|
|
152
|
+
return result;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const all = await pool(jobs, args.concurrency);
|
|
157
|
+
const finishedAt = Date.now();
|
|
158
|
+
const outcomes = tasks.map((task) => summariseTask(task, all.filter((r) => r.taskId === task.id)));
|
|
159
|
+
const report = buildReport({
|
|
160
|
+
configuration, outcomes,
|
|
161
|
+
trialsPerTask: args.trials,
|
|
162
|
+
concurrency: args.concurrency,
|
|
163
|
+
startedAt, finishedAt,
|
|
164
|
+
});
|
|
165
|
+
const target = args.out ?? join(root, 'report.json');
|
|
166
|
+
await writeFile(target, JSON.stringify(report, null, 2), 'utf8');
|
|
167
|
+
console.log(renderReport(report));
|
|
168
|
+
console.error(`\n[local-eval] report written to ${target}`);
|
|
169
|
+
}
|
|
170
|
+
// Only run when invoked directly, so the module stays importable by tests.
|
|
171
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
172
|
+
void main();
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/core/local-eval/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning trials into the number the harness exists to produce.
|
|
3
|
+
*
|
|
4
|
+
* MEDIAN, NOT JUST MEAN. Turn times on this hardware vary by tens of seconds,
|
|
5
|
+
* and a single slow trial drags a mean far enough to invent a regression that
|
|
6
|
+
* is not there. Both are reported, because a large gap between them is itself
|
|
7
|
+
* the signal that a run was contended and its timings should not be compared.
|
|
8
|
+
*
|
|
9
|
+
* FAILURE MODES ARE RANKED. The most common mode is printed first, because the
|
|
10
|
+
* question after "did this help?" is always "what is still broken?", and a
|
|
11
|
+
* ranked list answers it without opening a single log.
|
|
12
|
+
*/
|
|
13
|
+
import type { EvalReport, HarnessConfiguration, TaskOutcome, TaskSpec, TrialResult } from './types.js';
|
|
14
|
+
/** Aggregate every trial of one task. */
|
|
15
|
+
export declare function summariseTask(task: TaskSpec, trials: readonly TrialResult[]): TaskOutcome;
|
|
16
|
+
export declare function buildReport(args: {
|
|
17
|
+
readonly configuration: HarnessConfiguration;
|
|
18
|
+
readonly outcomes: readonly TaskOutcome[];
|
|
19
|
+
readonly trialsPerTask: number;
|
|
20
|
+
readonly concurrency: number;
|
|
21
|
+
readonly startedAt: number;
|
|
22
|
+
readonly finishedAt: number;
|
|
23
|
+
}): EvalReport;
|
|
24
|
+
/** Render a report for a terminal. Configuration first — it frames everything. */
|
|
25
|
+
export declare function renderReport(report: EvalReport): string;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning trials into the number the harness exists to produce.
|
|
3
|
+
*
|
|
4
|
+
* MEDIAN, NOT JUST MEAN. Turn times on this hardware vary by tens of seconds,
|
|
5
|
+
* and a single slow trial drags a mean far enough to invent a regression that
|
|
6
|
+
* is not there. Both are reported, because a large gap between them is itself
|
|
7
|
+
* the signal that a run was contended and its timings should not be compared.
|
|
8
|
+
*
|
|
9
|
+
* FAILURE MODES ARE RANKED. The most common mode is printed first, because the
|
|
10
|
+
* question after "did this help?" is always "what is still broken?", and a
|
|
11
|
+
* ranked list answers it without opening a single log.
|
|
12
|
+
*/
|
|
13
|
+
function median(values) {
|
|
14
|
+
if (values.length === 0)
|
|
15
|
+
return 0;
|
|
16
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
17
|
+
const mid = Math.floor(sorted.length / 2);
|
|
18
|
+
return sorted.length % 2 === 0 ? Math.round((sorted[mid - 1] + sorted[mid]) / 2) : sorted[mid];
|
|
19
|
+
}
|
|
20
|
+
function mean(values) {
|
|
21
|
+
if (values.length === 0)
|
|
22
|
+
return 0;
|
|
23
|
+
return Math.round(values.reduce((a, b) => a + b, 0) / values.length);
|
|
24
|
+
}
|
|
25
|
+
/** Aggregate every trial of one task. */
|
|
26
|
+
export function summariseTask(task, trials) {
|
|
27
|
+
const passes = trials.filter((t) => t.passed).length;
|
|
28
|
+
const counts = new Map();
|
|
29
|
+
for (const trial of trials) {
|
|
30
|
+
if (trial.passed)
|
|
31
|
+
continue;
|
|
32
|
+
counts.set(trial.mode, (counts.get(trial.mode) ?? 0) + 1);
|
|
33
|
+
}
|
|
34
|
+
const wall = trials.map((t) => t.wallMs);
|
|
35
|
+
return {
|
|
36
|
+
taskId: task.id,
|
|
37
|
+
why: task.why,
|
|
38
|
+
expectation: task.expectation,
|
|
39
|
+
trials,
|
|
40
|
+
passes,
|
|
41
|
+
total: trials.length,
|
|
42
|
+
passRate: trials.length === 0 ? 0 : passes / trials.length,
|
|
43
|
+
medianWallMs: median(wall),
|
|
44
|
+
meanWallMs: mean(wall),
|
|
45
|
+
modes: [...counts.entries()]
|
|
46
|
+
.map(([mode, count]) => ({ mode, count }))
|
|
47
|
+
.sort((a, b) => b.count - a.count || a.mode.localeCompare(b.mode)),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function buildReport(args) {
|
|
51
|
+
const totalTrials = args.outcomes.reduce((n, o) => n + o.total, 0);
|
|
52
|
+
const totalPasses = args.outcomes.reduce((n, o) => n + o.passes, 0);
|
|
53
|
+
return {
|
|
54
|
+
configuration: args.configuration,
|
|
55
|
+
trialsPerTask: args.trialsPerTask,
|
|
56
|
+
concurrency: args.concurrency,
|
|
57
|
+
outcomes: args.outcomes,
|
|
58
|
+
overallPassRate: totalTrials === 0 ? 0 : totalPasses / totalTrials,
|
|
59
|
+
totalPasses,
|
|
60
|
+
totalTrials,
|
|
61
|
+
startedAt: new Date(args.startedAt).toISOString(),
|
|
62
|
+
finishedAt: new Date(args.finishedAt).toISOString(),
|
|
63
|
+
wallMs: args.finishedAt - args.startedAt,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const pct = (n) => `${(n * 100).toFixed(0)}%`;
|
|
67
|
+
const secs = (ms) => `${(ms / 1000).toFixed(0)}s`;
|
|
68
|
+
/** Render a report for a terminal. Configuration first — it frames everything. */
|
|
69
|
+
export function renderReport(report) {
|
|
70
|
+
const c = report.configuration;
|
|
71
|
+
const lines = [];
|
|
72
|
+
lines.push('CONFIGURATION');
|
|
73
|
+
lines.push(` model ${c.model} (${c.quantization})`);
|
|
74
|
+
lines.push(` slots ${c.slots}`);
|
|
75
|
+
lines.push(` context/slot ${c.contextPerSlot.toLocaleString()} (total ${c.contextTotal.toLocaleString()})`);
|
|
76
|
+
lines.push(` sampling ${JSON.stringify(c.samplingParams)}`);
|
|
77
|
+
// Baselines recorded before tracing existed have no such field, and printing
|
|
78
|
+
// `undefined` at them would read as a run that chose to turn it off.
|
|
79
|
+
const tracing = c.tracing ?? 'unknown (recorded before tracing existed)';
|
|
80
|
+
lines.push(` base url ${c.baseUrl} (proxy ${c.proxy}, tracing ${tracing})`);
|
|
81
|
+
lines.push(` proxy impl ${c.proxyImplementation}`);
|
|
82
|
+
lines.push(` agent cli ${c.agentCli}`);
|
|
83
|
+
lines.push(` concurrency ${report.concurrency} trial(s) at a time`);
|
|
84
|
+
lines.push('');
|
|
85
|
+
lines.push(`RESULT ${report.totalPasses}/${report.totalTrials} = ${pct(report.overallPassRate)} pass rate`
|
|
86
|
+
+ ` (${report.trialsPerTask} trials/task, ${secs(report.wallMs)} wall)`);
|
|
87
|
+
lines.push('');
|
|
88
|
+
const pad = (s, n) => s.padEnd(n);
|
|
89
|
+
lines.push(` ${pad('task', 24)} ${pad('pass', 8)} ${pad('median', 8)} ${pad('mean', 8)} failure modes`);
|
|
90
|
+
for (const o of report.outcomes) {
|
|
91
|
+
const modes = o.modes.length === 0
|
|
92
|
+
? '-'
|
|
93
|
+
: o.modes.map((m) => `${m.mode} x${m.count}`).join(', ');
|
|
94
|
+
lines.push(` ${pad(o.taskId, 24)} ${pad(`${o.passes}/${o.total}`, 8)} `
|
|
95
|
+
+ `${pad(secs(o.medianWallMs), 8)} ${pad(secs(o.meanWallMs), 8)} ${modes}`);
|
|
96
|
+
}
|
|
97
|
+
lines.push('');
|
|
98
|
+
// Reported separately and never folded into the pass rate. An
|
|
99
|
+
// `unsupported-claim` reading is a prompt to go and read one transcript, not
|
|
100
|
+
// a verdict: the shared classifier fires on change verbs wherever they
|
|
101
|
+
// appear, including in a refusal that merely MENTIONS refactoring. Treat a
|
|
102
|
+
// flag on a passing trial as a question, and a flag on a failing one as the
|
|
103
|
+
// most likely explanation.
|
|
104
|
+
const flagged = report.outcomes.flatMap((o) => o.trials
|
|
105
|
+
.filter((t) => t.integrity === 'unsupported-claim')
|
|
106
|
+
.map((t) => `${o.taskId}#${t.trial} (${t.passed ? 'passed the check' : t.mode})`));
|
|
107
|
+
lines.push(`INTEGRITY FLAGS ${flagged.length === 0 ? 'none' : flagged.join(', ')}`);
|
|
108
|
+
lines.push(' claimed a change while the tree did not move — read the transcript before believing either side');
|
|
109
|
+
lines.push('');
|
|
110
|
+
// A timeout used to be the end of the story: the CLI emits its result JSON
|
|
111
|
+
// once, at the end, so a killed trial recorded zero tokens, zero turns and no
|
|
112
|
+
// transcript. An outcome nobody can act on is the same failure as a false
|
|
113
|
+
// success, which is what this harness exists to catch — so every timeout now
|
|
114
|
+
// reports what the wire was doing when the clock ran out.
|
|
115
|
+
const timedOut = report.outcomes.flatMap((o) => o.trials.filter((t) => t.mode === 'timeout').map((t) => ({ task: o.taskId, trial: t })));
|
|
116
|
+
if (timedOut.length > 0) {
|
|
117
|
+
lines.push('TIMEOUTS, DIAGNOSED');
|
|
118
|
+
for (const { task, trial } of timedOut) {
|
|
119
|
+
const d = trial.timeoutDiagnosis;
|
|
120
|
+
lines.push(` ${pad(`${task}#${trial.trial}`, 26)} `
|
|
121
|
+
+ (d ? d.kind : 'UNDIAGNOSED — this run was not traced, so why it timed out is unrecoverable'));
|
|
122
|
+
if (d)
|
|
123
|
+
lines.push(` ${' '.repeat(26)} ${d.detail}`);
|
|
124
|
+
if (trial.trace) {
|
|
125
|
+
// Turns the SERVER finished. The CLI's connectivity probe and token
|
|
126
|
+
// counts are not SSE streams at all, and a turn the agent hung up on
|
|
127
|
+
// is not evidence about the runtime — counting either would report a
|
|
128
|
+
// terminator failure on every timeout.
|
|
129
|
+
const turns = trial.trace.streams.filter((x) => (x.events['message_start'] ?? 0) > 0 && x.ended === 'upstream-end');
|
|
130
|
+
const unterminated = turns.filter((x) => !x.sawTerminator && x.ended === 'upstream-end').length;
|
|
131
|
+
lines.push(` ${' '.repeat(26)} ${turns.length} completed turn(s), `
|
|
132
|
+
+ `${unterminated} ended without a terminator; raw capture in ${trial.trace.captureDir}`);
|
|
133
|
+
// Where the budget actually went. A single enormous turn and a long
|
|
134
|
+
// series of ordinary ones are different problems with different fixes,
|
|
135
|
+
// and the totals alone cannot tell them apart.
|
|
136
|
+
if (turns.length > 0) {
|
|
137
|
+
const longest = turns.reduce((a, b) => (a.durationMs >= b.durationMs ? a : b));
|
|
138
|
+
const spent = turns.reduce((n, t) => n + t.durationMs, 0);
|
|
139
|
+
lines.push(` ${' '.repeat(26)} longest completed turn ${secs(longest.durationMs)} `
|
|
140
|
+
+ `(#${longest.seq}), ${secs(spent)} across all completed turns`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
lines.push('');
|
|
145
|
+
}
|
|
146
|
+
lines.push('TOKENS PER TRIAL (input / output / cache-read)');
|
|
147
|
+
for (const o of report.outcomes) {
|
|
148
|
+
for (const t of o.trials) {
|
|
149
|
+
lines.push(` ${pad(`${o.taskId}#${t.trial}`, 26)} `
|
|
150
|
+
+ `${pad(String(t.tokens.input), 8)} ${pad(String(t.tokens.output), 8)} `
|
|
151
|
+
+ `${pad(String(t.tokens.cacheRead), 10)} ${pad(t.mode, 26)} `
|
|
152
|
+
+ `${t.changedFiles ?? '?'} file(s), ${t.turns ?? '?'} turns${t.note ? ` — ${t.note}` : ''}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return lines.join('\n');
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=report.js.map
|