@polderlabs/bizar 6.2.5 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +15 -0
- package/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
- package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
- package/.claude/agents/_shared/SKILLS.md +109 -0
- package/.claude/agents/agent-browser.md +80 -0
- package/.claude/agents/baldr.md +49 -0
- package/.claude/agents/forseti.md +51 -0
- package/.claude/agents/frigg.md +42 -0
- package/.claude/agents/heimdall.md +33 -0
- package/.claude/agents/hermod.md +53 -0
- package/.claude/agents/mimir.md +49 -0
- package/.claude/agents/odin.md +287 -0
- package/.claude/agents/quick.md +34 -0
- package/.claude/agents/semble-search.md +50 -0
- package/.claude/agents/thor.md +53 -0
- package/.claude/agents/tyr.md +56 -0
- package/.claude/agents/vidarr.md +54 -0
- package/.claude/agents/vor.md +53 -0
- package/.claude/commands/audit.md +25 -0
- package/.claude/commands/bizar.md +22 -0
- package/.claude/commands/explain.md +17 -0
- package/.claude/commands/init.md +29 -0
- package/.claude/commands/learn.md +44 -0
- package/.claude/commands/plan.md +35 -0
- package/.claude/commands/plow-through.md +50 -0
- package/.claude/commands/pr-review.md +49 -0
- package/.claude/commands/setup-provider.md +96 -0
- package/.claude/commands/tailscale-serve.md +100 -0
- package/.claude/commands/team.md +132 -0
- package/.claude/commands/test.md +62 -0
- package/.claude/commands/validate.md +68 -0
- package/.claude/commands/visual-plan.md +24 -0
- package/.claude/hooks/README.md +92 -0
- package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
- package/.claude/hooks/pretooluse-bash.mjs +81 -0
- package/.claude/hooks/pretooluse-editwrite.mjs +139 -0
- package/.claude/hooks/sessionend-recall.mjs +74 -0
- package/.claude/hooks/sessionstart-prime.mjs +80 -0
- package/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
- package/.claude/hooks/worker-suggest.mjs +110 -0
- package/.claude/settings.json +125 -0
- package/.claude/skills/9router/SKILL.md +80 -0
- package/.claude/skills/9router-chat/SKILL.md +73 -0
- package/.claude/skills/9router-embeddings/SKILL.md +69 -0
- package/.claude/skills/9router-image/SKILL.md +86 -0
- package/.claude/skills/9router-stt/SKILL.md +79 -0
- package/.claude/skills/9router-tts/SKILL.md +80 -0
- package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
- package/.claude/skills/9router-web-search/SKILL.md +91 -0
- package/.claude/skills/bizar/README.md +9 -0
- package/.claude/skills/bizar/SKILL.md +450 -0
- package/.claude/skills/cpp-coding-standards/README.md +28 -0
- package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
- package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
- package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
- package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
- package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
- package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
- package/.claude/skills/cpp-testing/README.md +28 -0
- package/.claude/skills/cpp-testing/SKILL.md +304 -0
- package/.claude/skills/cpp-testing/references/coverage.md +370 -0
- package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
- package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
- package/.claude/skills/cpp-testing/references/mocking.md +364 -0
- package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
- package/.claude/skills/cubesandbox/SKILL.md +148 -0
- package/.claude/skills/embedded-esp-idf/README.md +41 -0
- package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
- package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
- package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
- package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
- package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
- package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
- package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
- package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
- package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
- package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
- package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
- package/.claude/skills/glyph/SKILL.md +163 -0
- package/.claude/skills/harness-engineering/SKILL.md +143 -0
- package/.claude/skills/lightrag/SKILL.md +81 -0
- package/.claude/skills/memory-protocol/SKILL.md +105 -0
- package/.claude/skills/obsidian/SKILL.md +306 -0
- package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
- package/.claude/skills/self-improvement/SKILL.md +64 -0
- package/README.md +87 -59
- package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-CW6fWKds.js} +3 -3
- package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
- package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
- package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
- package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
- package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
- package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
- package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
- package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
- package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
- package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
- package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
- package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
- package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
- package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
- package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
- package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-w2bDDkAH.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
- package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DXYCA0hC.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
- package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
- package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
- package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
- package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
- package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
- package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
- package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
- package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
- package/bizar-dash/dist/index.html +12 -10
- package/bizar-dash/dist/mobile.html +7 -4
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/api.mjs +15 -4
- package/bizar-dash/src/server/background-store.mjs +15 -16
- package/bizar-dash/src/server/bg-poller.mjs +25 -35
- package/bizar-dash/src/server/bg-retry.mjs +66 -194
- package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
- package/bizar-dash/src/server/claude-info.mjs +412 -0
- package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
- package/bizar-dash/src/server/claude-sdk.mjs +191 -0
- package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
- package/bizar-dash/src/server/memory-distillation.mjs +296 -0
- package/bizar-dash/src/server/providers-store.mjs +22 -49
- package/bizar-dash/src/server/routes/background.mjs +24 -20
- package/bizar-dash/src/server/routes/chat.mjs +223 -326
- package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
- package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
- package/bizar-dash/src/server/routes/distill.mjs +129 -0
- package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
- package/bizar-dash/src/server/routes/tasks.mjs +20 -28
- package/bizar-dash/src/server/task-delegator.mjs +76 -77
- package/bizar-dash/src/web/App.tsx +4 -0
- package/bizar-dash/src/web/components/Tag.tsx +18 -5
- package/bizar-dash/src/web/components/Topbar.tsx +3 -0
- package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
- package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
- package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
- package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
- package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
- package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
- package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
- package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
- package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
- package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
- package/bizar-dash/src/web/lib/types.ts +25 -0
- package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
- package/bizar-dash/src/web/styles/main.css +251 -0
- package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
- package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
- package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
- package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
- package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
- package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
- package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
- package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
- package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
- package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
- package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
- package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
- package/bizar-dash/src/web/ui/controls/controls.css +454 -0
- package/bizar-dash/src/web/ui/controls/index.ts +33 -0
- package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
- package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
- package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
- package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
- package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
- package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
- package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
- package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
- package/bizar-dash/src/web/ui/data/data.css +535 -0
- package/bizar-dash/src/web/ui/data/index.ts +31 -0
- package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
- package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
- package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
- package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
- package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
- package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
- package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
- package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
- package/bizar-dash/src/web/ui/index.ts +56 -0
- package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
- package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
- package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
- package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
- package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
- package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
- package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
- package/bizar-dash/src/web/ui/layout/index.ts +33 -0
- package/bizar-dash/src/web/ui/layout/layout.css +413 -0
- package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
- package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
- package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
- package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
- package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
- package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
- package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
- package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
- package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
- package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
- package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
- package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
- package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
- package/bizar-dash/src/web/ui/styles/globals.css +86 -0
- package/bizar-dash/src/web/ui/styles/reset.css +125 -0
- package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
- package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
- package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
- package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
- package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
- package/bizar-dash/src/web/views/Agents.tsx +506 -266
- package/bizar-dash/src/web/views/Chat.tsx +8 -8
- package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
- package/bizar-dash/src/web/views/Overview.tsx +996 -448
- package/bizar-dash/src/web/views/Tasks.tsx +277 -273
- package/bizar-dash/tests/communication-log.test.tsx +67 -0
- package/bizar-dash/tests/dep-graph.test.tsx +40 -0
- package/bizar-dash/tests/event-log.test.tsx +61 -0
- package/bizar-dash/tests/goal-input.test.tsx +72 -0
- package/bizar-dash/tests/goap-planner.test.ts +68 -0
- package/bizar-dash/tests/quality-gates.test.tsx +59 -0
- package/bizar-dash/tests/setup.ts +31 -1
- package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
- package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
- package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
- package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
- package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
- package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
- package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
- package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
- package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
- package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
- package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
- package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
- package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
- package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
- package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
- package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
- package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
- package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
- package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
- package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
- package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
- package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
- package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
- package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
- package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
- package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
- package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
- package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
- package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
- package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
- package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
- package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
- package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
- package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
- package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
- package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
- package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
- package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
- package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
- package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
- package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
- package/bizar-dash/tests/views/Agents.test.tsx +359 -0
- package/bizar-dash/tests/views/Overview.test.tsx +413 -0
- package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
- package/bizar-dash/vitest.config.ts +3 -1
- package/cli/__tests__/cost-gate.test.mjs +301 -0
- package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
- package/cli/bin.mjs +55 -18
- package/cli/commands/claim.mjs +282 -0
- package/cli/commands/claude-cmd.mjs +348 -0
- package/cli/commands/cost.mjs +279 -0
- package/cli/commands/install.mjs +12 -11
- package/cli/commands/validate.mjs +252 -325
- package/cli/cost-gate.mjs +501 -0
- package/cli/dev-link.test.mjs +11 -11
- package/cli/doctor.mjs +131 -213
- package/cli/feature-list-bridge.mjs +400 -0
- package/cli/install.mjs +33 -37
- package/cli/install.test.mjs +9 -9
- package/cli/memory-constants.mjs +17 -0
- package/cli/provision-claude.mjs +893 -0
- package/cli/provision.mjs +224 -227
- package/cli/utils.mjs +72 -58
- package/cli/worker-dispatcher.mjs +259 -0
- package/cli/worker-dispatcher.test.mjs +204 -0
- package/config/AGENTS.md +28 -28
- package/config/trigger-patterns.json +186 -0
- package/install.sh +66 -44
- package/package.json +19 -11
- package/packages/sdk/ARCHITECTURE.md +40 -36
- package/packages/sdk/package.json +15 -5
- package/packages/sdk/src/agent-registry.ts +304 -0
- package/packages/sdk/src/consensus/byzantine.ts +587 -0
- package/packages/sdk/src/consensus/index.ts +147 -0
- package/packages/sdk/src/consensus/queen.ts +173 -0
- package/packages/sdk/src/consensus/types.ts +199 -0
- package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
- package/packages/sdk/src/federation/audit.ts +156 -0
- package/packages/sdk/src/federation/budget.ts +269 -0
- package/packages/sdk/src/federation/envelope.ts +144 -0
- package/packages/sdk/src/federation/hmac.ts +160 -0
- package/packages/sdk/src/federation/index.ts +443 -0
- package/packages/sdk/src/federation/pii.ts +241 -0
- package/packages/sdk/src/federation/policy.ts +112 -0
- package/packages/sdk/src/federation/trust.ts +146 -0
- package/packages/sdk/src/fingerprint.ts +0 -0
- package/packages/sdk/src/index.ts +101 -69
- package/packages/sdk/src/mcp/bin.ts +51 -0
- package/packages/sdk/src/mcp/server.ts +848 -0
- package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
- package/packages/sdk/src/router/codemod-intent.ts +125 -0
- package/packages/sdk/src/router/index.ts +247 -0
- package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
- package/packages/sdk/src/router/memory-distillation.ts +249 -0
- package/packages/sdk/src/router/model-router.ts +235 -0
- package/packages/sdk/src/router/q-learning-router.ts +304 -0
- package/packages/sdk/src/swarm-topology.ts +279 -0
- package/packages/sdk/tests/agent-registry.test.ts +285 -0
- package/packages/sdk/tests/consensus.test.ts +376 -0
- package/packages/sdk/tests/federation/audit.test.ts +164 -0
- package/packages/sdk/tests/federation/budget.test.ts +189 -0
- package/packages/sdk/tests/federation/envelope.test.ts +120 -0
- package/packages/sdk/tests/federation/hmac.test.ts +194 -0
- package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
- package/packages/sdk/tests/federation/pii.test.ts +106 -0
- package/packages/sdk/tests/federation/policy.test.ts +140 -0
- package/packages/sdk/tests/federation/trust.test.ts +124 -0
- package/packages/sdk/tests/mcp-tools.test.ts +204 -0
- package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
- package/packages/sdk/tests/model-router.test.mjs +108 -0
- package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
- package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
- package/packages/sdk/tests/router.test.mjs +91 -0
- package/packages/sdk/tests/sdk.test.mjs +172 -0
- package/packages/sdk/tests/swarm-topology.test.ts +258 -0
- package/packages/sdk/vitest.config.ts +1 -1
- package/scripts/bh-full-e2e.mjs +167 -368
- package/scripts/check-deps.mjs +28 -46
- package/scripts/mirror-claude-md.sh +78 -0
- package/scripts/test-in-container.sh +31 -9
- package/templates/clean-state-checklist.md +3 -3
- package/templates/sprint-contract.md +2 -2
- package/bizar-dash/.bizar/activity.log +0 -3
- package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
- package/bizar-dash/.omx/state/session.json +0 -10
- package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
- package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
- package/bizar-dash/bizar-design/canvas.html +0 -281
- package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/components.css +0 -1665
- package/bizar-dash/bizar-design/components.html +0 -557
- package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/agents.html +0 -74
- package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/memory.html +0 -75
- package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
- package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/overview.html +0 -95
- package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/desktop/settings.html +0 -70
- package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/icons.svg +0 -44
- package/bizar-dash/bizar-design/index.html +0 -192
- package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/agents.html +0 -29
- package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/memory.html +0 -28
- package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
- package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/overview.html +0 -33
- package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/mobile/settings.html +0 -28
- package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
- package/bizar-dash/bizar-design/prototype.js +0 -114
- package/bizar-dash/bizar-design/tokens.css +0 -106
- package/bizar-dash/dist/assets/MobileChat-BnKN_Ks_.js +0 -1
- package/bizar-dash/dist/assets/MobileSettings-DjCPxC-Q.js +0 -1
- package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
- package/bizar-dash/dist/assets/main-DYiZqMrn.js +0 -18
- package/bizar-dash/dist/assets/main-DYiZqMrn.js.map +0 -1
- package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
- package/bizar-dash/dist/assets/markdown-C6mXtQxD.js +0 -1
- package/bizar-dash/dist/assets/mobile-CMHqtLV2.js +0 -1
- package/bizar-dash/dist/assets/mobile-layout-3jIhHX_p.js +0 -2
- package/bizar-dash/dist/assets/mobile-layout-3jIhHX_p.js.map +0 -1
- package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
- package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
- package/bizar-dash/dist/assets/useSlashCommands-DtITw8Xv.js +0 -2
- package/bizar-dash/dist/assets/useSlashCommands-DtITw8Xv.js.map +0 -1
- package/bizar-dash/dist/assets/vendor-CeHGtduv.js +0 -29
- package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
- package/bizar-dash/node_modules/.package-lock.json +0 -6
- package/bizar-dash/package-lock.json +0 -6
- package/bizar-dash/src/server/cline-sdk.mjs +0 -132
- package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
- package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
- package/cli/commands/cline-cmd.mjs +0 -289
- package/cli/commands/validate.test.mjs +0 -379
- package/cli/doctor.test.mjs +0 -350
- package/config/cline.json.template +0 -342
- package/packages/sdk/src/client.ts +0 -188
- package/packages/sdk/src/cline-events.ts +0 -134
- package/packages/sdk/src/cline-types.ts +0 -66
- package/packages/sdk/src/cline.ts +0 -339
- package/packages/sdk/src/errors.ts +0 -129
- package/packages/sdk/src/events.ts +0 -153
- package/packages/sdk/src/types.ts +0 -176
- package/packages/sdk/tests/client.test.ts +0 -217
- package/packages/sdk/tests/errors.test.ts +0 -108
- package/packages/sdk/tests/events.test.ts +0 -139
- package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
- package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
- package/plugins/bizar/ARCHITECTURE.md +0 -142
- package/plugins/bizar/CONSTRAINTS.md +0 -67
- package/plugins/bizar/LICENSE +0 -21
- package/plugins/bizar/README.md +0 -448
- package/plugins/bizar/index.ts +0 -925
- package/plugins/bizar/package.json +0 -39
- package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
- package/plugins/bizar/src/background-state.ts +0 -641
- package/plugins/bizar/src/background.ts +0 -1806
- package/plugins/bizar/src/cline-runner.ts +0 -203
- package/plugins/bizar/src/clineruntime.ts +0 -227
- package/plugins/bizar/src/commands-impl.ts +0 -151
- package/plugins/bizar/src/commands.ts +0 -1799
- package/plugins/bizar/src/compaction.d.mts +0 -48
- package/plugins/bizar/src/compaction.mjs +0 -192
- package/plugins/bizar/src/dashboard-client.ts +0 -233
- package/plugins/bizar/src/event-stream.ts +0 -606
- package/plugins/bizar/src/fingerprint.ts +0 -120
- package/plugins/bizar/src/handoff.ts +0 -79
- package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
- package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
- package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
- package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
- package/plugins/bizar/src/http-client.ts +0 -467
- package/plugins/bizar/src/key-rotation.ts +0 -218
- package/plugins/bizar/src/logger.ts +0 -144
- package/plugins/bizar/src/loop-engineering.ts +0 -241
- package/plugins/bizar/src/loop.ts +0 -176
- package/plugins/bizar/src/mistake-recovery.ts +0 -98
- package/plugins/bizar/src/odin.ts +0 -227
- package/plugins/bizar/src/options.ts +0 -470
- package/plugins/bizar/src/plan-fs.ts +0 -323
- package/plugins/bizar/src/reasoning-clean.ts +0 -454
- package/plugins/bizar/src/report.ts +0 -178
- package/plugins/bizar/src/research-prompt.ts +0 -35
- package/plugins/bizar/src/serve-info.ts +0 -228
- package/plugins/bizar/src/serve.ts +0 -496
- package/plugins/bizar/src/settings.ts +0 -349
- package/plugins/bizar/src/state.ts +0 -298
- package/plugins/bizar/src/tool-discipline.ts +0 -105
- package/plugins/bizar/src/tools/agent-browser.ts +0 -315
- package/plugins/bizar/src/tools/bg-collect.ts +0 -131
- package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
- package/plugins/bizar/src/tools/bg-kill.ts +0 -116
- package/plugins/bizar/src/tools/bg-pause.ts +0 -99
- package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
- package/plugins/bizar/src/tools/bg-resume.ts +0 -94
- package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
- package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
- package/plugins/bizar/src/tools/bg-status.ts +0 -130
- package/plugins/bizar/src/tools/graph-query.ts +0 -278
- package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
- package/plugins/bizar/src/tools/memory-list.ts +0 -43
- package/plugins/bizar/src/tools/memory-read.ts +0 -69
- package/plugins/bizar/src/tools/memory-search.ts +0 -47
- package/plugins/bizar/src/tools/memory-write.ts +0 -54
- package/plugins/bizar/src/tools/open-kb.ts +0 -198
- package/plugins/bizar/src/tools/plan-action.ts +0 -785
- package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
- package/plugins/bizar/src/tools/sandbox.ts +0 -232
- package/plugins/bizar/src/tools/team-spawn.ts +0 -73
- package/plugins/bizar/src/tools/team-status.ts +0 -76
- package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
- package/plugins/bizar/src/trajectory.ts +0 -104
- package/plugins/bizar/tests/README.md +0 -99
- package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
- package/plugins/bizar/tests/background-state.test.ts +0 -277
- package/plugins/bizar/tests/background.test.ts +0 -402
- package/plugins/bizar/tests/block.test.ts +0 -195
- package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
- package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
- package/plugins/bizar/tests/commands-impl.test.ts +0 -316
- package/plugins/bizar/tests/commands.test.ts +0 -584
- package/plugins/bizar/tests/compaction.test.ts +0 -264
- package/plugins/bizar/tests/config.test.ts +0 -128
- package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
- package/plugins/bizar/tests/dispose.test.ts +0 -336
- package/plugins/bizar/tests/event-stream.test.ts +0 -409
- package/plugins/bizar/tests/event.test.ts +0 -262
- package/plugins/bizar/tests/fingerprint.test.ts +0 -190
- package/plugins/bizar/tests/http-client.test.ts +0 -404
- package/plugins/bizar/tests/init-helpers.test.ts +0 -203
- package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
- package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
- package/plugins/bizar/tests/key-rotation.test.ts +0 -396
- package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
- package/plugins/bizar/tests/loop.test.ts +0 -397
- package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
- package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
- package/plugins/bizar/tests/odin.test.ts +0 -125
- package/plugins/bizar/tests/options.test.ts +0 -329
- package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
- package/plugins/bizar/tests/safety.test.ts +0 -281
- package/plugins/bizar/tests/serve.test.ts +0 -339
- package/plugins/bizar/tests/settings.test.ts +0 -351
- package/plugins/bizar/tests/stall-think.test.ts +0 -750
- package/plugins/bizar/tests/state.test.ts +0 -276
- package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
- package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
- package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
- package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
- package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
- package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
- package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
- package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
- package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
- package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
- package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
- package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
- package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
- package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
- package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
- package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
- package/plugins/bizar/tests/tools/sandbox.test.ts +0 -117
- package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
- package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
- package/plugins/bizar/tsconfig.json +0 -29
- package/scripts/mirror-agents-md.sh +0 -69
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp-tools.test.ts — exercises the 4 new MCP tools (F-032) by calling
|
|
3
|
+
* each tool's `handler` directly and asserting the return shape.
|
|
4
|
+
*
|
|
5
|
+
* The tools live in `packages/sdk/src/mcp/server.ts`; we import the
|
|
6
|
+
* compiled `BIZAR_TOOLS` array and walk it to find each tool by name.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, test, expect, beforeEach } from "vitest";
|
|
10
|
+
import { BIZAR_TOOLS, type SdkMcpToolDef } from "../src/mcp/server.js";
|
|
11
|
+
import { bizarAgentRegistry } from "../src/agent-registry.js";
|
|
12
|
+
import { swarmTopologyRegistry } from "../src/swarm-topology.js";
|
|
13
|
+
|
|
14
|
+
function findTool(name: string): SdkMcpToolDef {
|
|
15
|
+
const t = BIZAR_TOOLS.find((x) => x.name === name);
|
|
16
|
+
if (!t) throw new Error(`tool not found: ${name}`);
|
|
17
|
+
return t;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function call(toolName: string, args: unknown): Promise<unknown> {
|
|
21
|
+
const tool = findTool(toolName);
|
|
22
|
+
const res = await tool.handler(args, {});
|
|
23
|
+
// Standard MCP shape: { content: [{ type: 'text', text: '...' }] }
|
|
24
|
+
if (!Array.isArray(res.content) || res.content.length !== 1) {
|
|
25
|
+
throw new Error(`unexpected response shape from ${toolName}`);
|
|
26
|
+
}
|
|
27
|
+
const block = res.content[0];
|
|
28
|
+
if (block.type !== "text") throw new Error(`unexpected block type: ${block.type}`);
|
|
29
|
+
try { return JSON.parse(block.text); }
|
|
30
|
+
catch { return block.text; }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe("MCP tools — F-032 swarm/agent lifecycle", () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
// Each test starts from a clean slate so list assertions are deterministic.
|
|
36
|
+
bizarAgentRegistry.reset();
|
|
37
|
+
swarmTopologyRegistry.reset();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("BIZAR_TOOLS includes the 4 new tools (total ≥ 17)", () => {
|
|
41
|
+
const names = new Set(BIZAR_TOOLS.map((t) => t.name));
|
|
42
|
+
expect(names.has("agent_spawn")).toBe(true);
|
|
43
|
+
expect(names.has("agent_list")).toBe(true);
|
|
44
|
+
expect(names.has("agent_terminate")).toBe(true);
|
|
45
|
+
expect(names.has("swarm_init")).toBe(true);
|
|
46
|
+
expect(BIZAR_TOOLS.length).toBeGreaterThanOrEqual(17);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("each new tool has the expected inputSchema", () => {
|
|
50
|
+
const spawn = findTool("agent_spawn");
|
|
51
|
+
expect(spawn.inputSchema).toMatchObject({
|
|
52
|
+
type: "string", name: "string", priority: "string", metadata: "string",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const list = findTool("agent_list");
|
|
56
|
+
expect(list.inputSchema).toMatchObject({
|
|
57
|
+
status: "string", type: "string", limit: "number", offset: "number",
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const term = findTool("agent_terminate");
|
|
61
|
+
expect(term.inputSchema).toMatchObject({
|
|
62
|
+
agentId: "string", graceful: "boolean", reason: "string",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const swarm = findTool("swarm_init");
|
|
66
|
+
expect(swarm.inputSchema).toMatchObject({
|
|
67
|
+
topology: "string", maxAgents: "number", metadata: "string",
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("agent_spawn returns { agentId, status }", async () => {
|
|
72
|
+
const r = await call("agent_spawn", { type: "coder", name: "ada" });
|
|
73
|
+
expect(r).toMatchObject({ status: "active" });
|
|
74
|
+
expect((r as { agentId: string }).agentId).toMatch(/^agent-/);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("agent_spawn parses metadata JSON when supplied", async () => {
|
|
78
|
+
const r = await call("agent_spawn", {
|
|
79
|
+
type: "coder",
|
|
80
|
+
metadata: JSON.stringify({ region: "us", priority: "high" }),
|
|
81
|
+
});
|
|
82
|
+
const id = (r as { agentId: string }).agentId;
|
|
83
|
+
const got = bizarAgentRegistry.getAgent(id);
|
|
84
|
+
expect(got?.metadata).toEqual({ region: "us", priority: "high" });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("agent_spawn returns a structured error when metadata is not valid JSON", async () => {
|
|
88
|
+
const tool = findTool("agent_spawn");
|
|
89
|
+
const res = await tool.handler({ type: "coder", metadata: "not-json" }, {});
|
|
90
|
+
const text = (res.content[0] as { text: string }).text;
|
|
91
|
+
expect(text).toMatch(/^error:/);
|
|
92
|
+
expect(text).toMatch(/JSON/);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("agent_spawn rejects types outside the AGENT_TYPES allowlist", async () => {
|
|
96
|
+
const tool = findTool("agent_spawn");
|
|
97
|
+
const res = await tool.handler({ type: "lawyer" }, {});
|
|
98
|
+
const text = (res.content[0] as { text: string }).text;
|
|
99
|
+
expect(text).toMatch(/^error:/);
|
|
100
|
+
expect(text).toMatch(/must be one of/);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("agent_list returns active agents by default", async () => {
|
|
104
|
+
await call("agent_spawn", { type: "coder" });
|
|
105
|
+
await call("agent_spawn", { type: "reviewer" });
|
|
106
|
+
const r = await call("agent_list", {});
|
|
107
|
+
expect(r).toMatchObject({ total: 2 });
|
|
108
|
+
expect((r as { agents: unknown[] }).agents).toHaveLength(2);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("agent_list filters by status", async () => {
|
|
112
|
+
const a = await call("agent_spawn", { type: "coder" }) as { agentId: string };
|
|
113
|
+
await call("agent_spawn", { type: "coder" });
|
|
114
|
+
await call("agent_terminate", { agentId: a.agentId, reason: "test" });
|
|
115
|
+
const terminated = await call("agent_list", { status: "terminated" });
|
|
116
|
+
expect(terminated).toMatchObject({ total: 1 });
|
|
117
|
+
const active = await call("agent_list", { status: "active" });
|
|
118
|
+
expect(active).toMatchObject({ total: 1 });
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("agent_list defaults status to 'all' for unrecognized values", async () => {
|
|
122
|
+
await call("agent_spawn", { type: "coder" });
|
|
123
|
+
const r = await call("agent_list", { status: "bogus" });
|
|
124
|
+
expect(r).toMatchObject({ total: 1 });
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("agent_terminate returns { agentId, status, terminatedAt }", async () => {
|
|
128
|
+
const spawned = await call("agent_spawn", { type: "coder" }) as { agentId: string };
|
|
129
|
+
const r = await call("agent_terminate", { agentId: spawned.agentId, reason: "done" });
|
|
130
|
+
expect(r).toMatchObject({
|
|
131
|
+
agentId: spawned.agentId,
|
|
132
|
+
status: "terminated",
|
|
133
|
+
});
|
|
134
|
+
expect(typeof (r as { terminatedAt: string }).terminatedAt).toBe("string");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("agent_terminate surfaces a structured error for unknown agent", async () => {
|
|
138
|
+
const tool = findTool("agent_terminate");
|
|
139
|
+
const res = await tool.handler({ agentId: "agent-nope" }, {});
|
|
140
|
+
const text = (res.content[0] as { text: string }).text;
|
|
141
|
+
expect(text).toMatch(/^error:/);
|
|
142
|
+
expect(text).toMatch(/not found/);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("swarm_init creates a swarm with defaults", async () => {
|
|
146
|
+
const r = await call("swarm_init", {}) as {
|
|
147
|
+
swarmId: string; topology: string; maxAgents: number; createdAt: string;
|
|
148
|
+
};
|
|
149
|
+
expect(r.swarmId).toMatch(/^swarm-\d+$/);
|
|
150
|
+
expect(r.topology).toBe("hierarchical-mesh");
|
|
151
|
+
expect(r.maxAgents).toBe(15);
|
|
152
|
+
expect(typeof r.createdAt).toBe("string");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("swarm_init respects topology and maxAgents", async () => {
|
|
156
|
+
const r = await call("swarm_init", {
|
|
157
|
+
topology: "mesh",
|
|
158
|
+
maxAgents: 42,
|
|
159
|
+
metadata: JSON.stringify({ owner: "F-032" }),
|
|
160
|
+
}) as { topology: string; maxAgents: number; metadata?: Record<string, unknown> };
|
|
161
|
+
expect(r.topology).toBe("mesh");
|
|
162
|
+
expect(r.maxAgents).toBe(42);
|
|
163
|
+
expect(r.metadata).toEqual({ owner: "F-032" });
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("swarm_init clamps maxAgents to [1, 1000]", async () => {
|
|
167
|
+
const lo = await call("swarm_init", { maxAgents: 0 }) as { maxAgents: number };
|
|
168
|
+
const hi = await call("swarm_init", { maxAgents: 99999 }) as { maxAgents: number };
|
|
169
|
+
expect(lo.maxAgents).toBe(1);
|
|
170
|
+
expect(hi.maxAgents).toBe(1000);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("swarm_init returns an error for invalid JSON metadata", async () => {
|
|
174
|
+
const tool = findTool("swarm_init");
|
|
175
|
+
const res = await tool.handler({ metadata: "{not-json" }, {});
|
|
176
|
+
const text = (res.content[0] as { text: string }).text;
|
|
177
|
+
expect(text).toMatch(/^error:/);
|
|
178
|
+
expect(text).toMatch(/JSON/);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("end-to-end: spawn → list → terminate → list shows 1 active + 1 terminated", async () => {
|
|
182
|
+
const spawned = await call("agent_spawn", { type: "coder", name: "ada" }) as {
|
|
183
|
+
agentId: string;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const allAfterSpawn = await call("agent_list", { status: "all" }) as {
|
|
187
|
+
total: number; agents: { agentId: string; status: string }[];
|
|
188
|
+
};
|
|
189
|
+
expect(allAfterSpawn.total).toBe(1);
|
|
190
|
+
expect(allAfterSpawn.agents[0]?.status).toBe("active");
|
|
191
|
+
expect(allAfterSpawn.agents[0]?.agentId).toBe(spawned.agentId);
|
|
192
|
+
|
|
193
|
+
await call("agent_terminate", { agentId: spawned.agentId, reason: "smoke" });
|
|
194
|
+
|
|
195
|
+
const allAfterTerm = await call("agent_list", { status: "all" }) as {
|
|
196
|
+
total: number; agents: { status: string }[];
|
|
197
|
+
};
|
|
198
|
+
expect(allAfterTerm.total).toBe(1);
|
|
199
|
+
expect(allAfterTerm.agents[0]?.status).toBe("terminated");
|
|
200
|
+
|
|
201
|
+
// Sanity: the registry returns the same record (proves state lives in BizarAgentRegistry).
|
|
202
|
+
expect(bizarAgentRegistry.getAgent(spawned.agentId)?.status).toBe("terminated");
|
|
203
|
+
});
|
|
204
|
+
});
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the RETRIEVE → JUDGE → DISTILL → CONSOLIDATE pipeline (F-033 / ADR-174).
|
|
3
|
+
*
|
|
4
|
+
* Roundtrip: write 3 memory entries of kind `coding_convention`,
|
|
5
|
+
* run the distiller, assert ≥1 promoted pattern with
|
|
6
|
+
* `provenance_tier` set.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, test, expect } from "vitest";
|
|
10
|
+
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import {
|
|
14
|
+
runDistillation,
|
|
15
|
+
retrieve,
|
|
16
|
+
judge,
|
|
17
|
+
PROVENANCE_TIERS,
|
|
18
|
+
} from "../src/router/memory-distillation.js";
|
|
19
|
+
import { writeNote } from "../dist/memory/index.js";
|
|
20
|
+
|
|
21
|
+
function makeEntry(body, opts = {}) {
|
|
22
|
+
return {
|
|
23
|
+
memory_id: opts.id ?? `note-${Math.random().toString(36).slice(2, 8)}`,
|
|
24
|
+
frontmatter: {
|
|
25
|
+
kind: opts.kind ?? "coding_convention",
|
|
26
|
+
createdAt: opts.createdAt ?? new Date().toISOString(),
|
|
27
|
+
...opts.frontmatter,
|
|
28
|
+
},
|
|
29
|
+
body,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe("memory-distillation — RETRIEVE", () => {
|
|
34
|
+
test("short body without code block is 'simple'", () => {
|
|
35
|
+
const r = retrieve(makeEntry("Use const for module exports.", { kind: "coding_convention" }));
|
|
36
|
+
expect(r.complexity).toBe("simple");
|
|
37
|
+
expect(r.hasCodeBlock).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("body with a fenced code block is 'complex'", () => {
|
|
41
|
+
const r = retrieve(makeEntry("Pattern:\n```ts\nconst a = 1;\n```"));
|
|
42
|
+
expect(r.complexity).toBe("complex");
|
|
43
|
+
expect(r.hasCodeBlock).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("frontmatter tag `test-exec` flips testExec=true", () => {
|
|
47
|
+
const r = retrieve(makeEntry("x", { frontmatter: { tags: ["test-exec"] } }));
|
|
48
|
+
expect(r.testExec).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("frontmatter `kind: feedback` flips testExec=true", () => {
|
|
52
|
+
const r = retrieve(makeEntry("x", { frontmatter: { kind: "feedback" } }));
|
|
53
|
+
expect(r.testExec).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("memory-distillation — JUDGE / provenance_tier", () => {
|
|
58
|
+
test("testExec=true → oracle:test-exec", () => {
|
|
59
|
+
const r = retrieve(makeEntry("x", { frontmatter: { tags: ["test-exec"] } }));
|
|
60
|
+
expect(judge(makeEntry("x"), r)).toBe("oracle:test-exec");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("testExec=false → proxy:structural", () => {
|
|
64
|
+
const r = retrieve(makeEntry("x", { kind: "coding_convention" }));
|
|
65
|
+
expect(judge(makeEntry("x"), r)).toBe("proxy:structural");
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe("memory-distillation — RUN (4-step pipeline)", () => {
|
|
70
|
+
test("3 coding_convention entries → ≥1 promoted pattern with provenance_tier", () => {
|
|
71
|
+
const entries = [
|
|
72
|
+
makeEntry("Always use const for module-level exports.", { kind: "coding_convention" }),
|
|
73
|
+
makeEntry("Prefer async/await over raw promise chains.", { kind: "coding_convention" }),
|
|
74
|
+
makeEntry(
|
|
75
|
+
"Document every exported function with a JSDoc block.",
|
|
76
|
+
{ kind: "coding_convention", frontmatter: { kind: "coding_convention", tags: ["test-exec"] } },
|
|
77
|
+
),
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const result = runDistillation(entries);
|
|
81
|
+
expect(result.patterns.length).toBeGreaterThan(0);
|
|
82
|
+
// The third entry carries the `test-exec` tag → oracle tier →
|
|
83
|
+
// eligible for promotion.
|
|
84
|
+
const promoted = result.promoted;
|
|
85
|
+
expect(promoted.length).toBeGreaterThanOrEqual(1);
|
|
86
|
+
expect(promoted[0].provenance_tier).toBe("oracle:test-exec");
|
|
87
|
+
expect(promoted[0].promoted).toBe(true);
|
|
88
|
+
expect(result.byTier["oracle:test-exec"]).toBeGreaterThanOrEqual(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("all-proxy input still produces patterns, but none promoted", () => {
|
|
92
|
+
const entries = [
|
|
93
|
+
makeEntry("Pattern: keep imports sorted.", { kind: "task_summary" }),
|
|
94
|
+
makeEntry("Use: lint before commit.", { kind: "task_summary" }),
|
|
95
|
+
];
|
|
96
|
+
const result = runDistillation(entries);
|
|
97
|
+
expect(result.patterns.length).toBeGreaterThan(0);
|
|
98
|
+
expect(result.promoted.length).toBe(0);
|
|
99
|
+
expect(result.byTier["proxy:structural"]).toBeGreaterThan(0);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("empty input → empty result with zero counts", () => {
|
|
103
|
+
const result = runDistillation([]);
|
|
104
|
+
expect(result.patterns).toEqual([]);
|
|
105
|
+
expect(result.promoted).toEqual([]);
|
|
106
|
+
for (const tier of PROVENANCE_TIERS) {
|
|
107
|
+
expect(result.byTier[tier]).toBe(0);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("non-pattern kinds (e.g. user_preference) are not distilled", () => {
|
|
112
|
+
const entries = [
|
|
113
|
+
makeEntry("I prefer dark mode.", { kind: "user_preference" }),
|
|
114
|
+
makeEntry("I prefer tabs.", { kind: "user_preference" }),
|
|
115
|
+
];
|
|
116
|
+
const result = runDistillation(entries);
|
|
117
|
+
expect(result.patterns.length).toBe(0);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("run is idempotent (same input → same patterns)", () => {
|
|
121
|
+
const entries = [
|
|
122
|
+
makeEntry("Use const for top-level exports.", { kind: "coding_convention", id: "a" }),
|
|
123
|
+
makeEntry(
|
|
124
|
+
"Use const for top-level exports in TypeScript modules.",
|
|
125
|
+
{ kind: "coding_convention", frontmatter: { tags: ["test-exec"] }, id: "b" },
|
|
126
|
+
),
|
|
127
|
+
];
|
|
128
|
+
const r1 = runDistillation(entries);
|
|
129
|
+
const r2 = runDistillation(entries);
|
|
130
|
+
expect(r2.patterns.length).toBe(r1.patterns.length);
|
|
131
|
+
expect(r2.promoted.map((p) => p.id).sort()).toEqual(r1.promoted.map((p) => p.id).sort());
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe("memory-distillation — roundtrip via in-process vault", () => {
|
|
136
|
+
test("write 3 coding_convention notes → run distiller → promoted pattern exists", async () => {
|
|
137
|
+
const vault = mkdtempSync(join(tmpdir(), "bizar-f033-"));
|
|
138
|
+
try {
|
|
139
|
+
// 1. Seed: write 3 coding_convention notes — one of them is
|
|
140
|
+
// marked `test-exec` to drive the oracle tier.
|
|
141
|
+
writeNote(vault, "conv-1.md", {
|
|
142
|
+
title: "Always use const for module-level exports",
|
|
143
|
+
kind: "coding_convention",
|
|
144
|
+
createdAt: new Date().toISOString(),
|
|
145
|
+
}, "Always use `const` for module-level exports.");
|
|
146
|
+
writeNote(vault, "conv-2.md", {
|
|
147
|
+
title: "Prefer async/await over raw promise chains",
|
|
148
|
+
kind: "coding_convention",
|
|
149
|
+
createdAt: new Date().toISOString(),
|
|
150
|
+
}, "Prefer `async`/`await` over raw `.then()` chains.");
|
|
151
|
+
writeNote(vault, "conv-3.md", {
|
|
152
|
+
title: "Document exported functions",
|
|
153
|
+
kind: "coding_convention",
|
|
154
|
+
createdAt: new Date().toISOString(),
|
|
155
|
+
tags: ["test-exec"],
|
|
156
|
+
}, "Document every exported function with a JSDoc block.");
|
|
157
|
+
|
|
158
|
+
// 2. Read them back via the SDK in-process vault helpers.
|
|
159
|
+
const vaultModule = await import("../dist/memory/index.js");
|
|
160
|
+
const notes = vaultModule.listNotes(vault, "", 100);
|
|
161
|
+
expect(notes.length).toBe(3);
|
|
162
|
+
|
|
163
|
+
// 3. Translate to the distiller's input shape.
|
|
164
|
+
const entries = notes.map((n) => ({
|
|
165
|
+
memory_id: n.relPath,
|
|
166
|
+
relPath: n.relPath,
|
|
167
|
+
frontmatter: n.frontmatter ?? {},
|
|
168
|
+
body: n.body ?? "",
|
|
169
|
+
kind: n.frontmatter?.kind ?? n.frontmatter?.type,
|
|
170
|
+
createdAt: n.frontmatter?.createdAt,
|
|
171
|
+
}));
|
|
172
|
+
|
|
173
|
+
// 4. Run the distiller and assert the promoted pattern.
|
|
174
|
+
const result = runDistillation(entries);
|
|
175
|
+
expect(result.patterns.length).toBeGreaterThanOrEqual(1);
|
|
176
|
+
const promoted = result.promoted;
|
|
177
|
+
expect(promoted.length).toBeGreaterThanOrEqual(1);
|
|
178
|
+
expect(promoted[0].provenance_tier).toBe("oracle:test-exec");
|
|
179
|
+
expect(promoted[0].promoted).toBe(true);
|
|
180
|
+
// Provenance tier is one of the allowed ADR-174 values.
|
|
181
|
+
expect(PROVENANCE_TIERS).toContain(promoted[0].provenance_tier);
|
|
182
|
+
} finally {
|
|
183
|
+
rmSync(vault, { recursive: true, force: true });
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the Thompson-sampling bandit model router (F-033).
|
|
3
|
+
*
|
|
4
|
+
* - Codemod short-circuit returns `{tier: 'flash', codemodIntent}`.
|
|
5
|
+
* - Default priors make `flash` the most-likely pick.
|
|
6
|
+
* - recordOutcome() shifts the Beta(α, β) priors.
|
|
7
|
+
* - recordOutcome with seed gives deterministic picks.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, test, expect } from "vitest";
|
|
11
|
+
import { ModelRouter } from "../src/router/model-router.js";
|
|
12
|
+
|
|
13
|
+
describe("ModelRouter — codemod short-circuit", () => {
|
|
14
|
+
test("var-to-const short-circuits to flash with codemodIntent", () => {
|
|
15
|
+
const r = new ModelRouter({ seed: 42 });
|
|
16
|
+
const d = r.route("convert var to const");
|
|
17
|
+
expect(d.tier).toBe("flash");
|
|
18
|
+
expect(d.codemodIntent).toBe("var-to-const");
|
|
19
|
+
expect(d.confidence).toBe(1.0);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("remove-console short-circuits to flash with codemodIntent", () => {
|
|
23
|
+
const r = new ModelRouter({ seed: 42 });
|
|
24
|
+
const d = r.route("strip console.log statements");
|
|
25
|
+
expect(d.tier).toBe("flash");
|
|
26
|
+
expect(d.codemodIntent).toBe("remove-console");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("add-logging short-circuits to flash with codemodIntent", () => {
|
|
30
|
+
const r = new ModelRouter({ seed: 42 });
|
|
31
|
+
const d = r.route("add logging to the handler");
|
|
32
|
+
expect(d.tier).toBe("flash");
|
|
33
|
+
expect(d.codemodIntent).toBe("add-logging");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("ModelRouter — Thompson sampling", () => {
|
|
38
|
+
test("non-codemod prompt returns a valid tier", () => {
|
|
39
|
+
const r = new ModelRouter({ seed: 42 });
|
|
40
|
+
const d = r.route("design a database schema for inventory");
|
|
41
|
+
expect(["flash", "mid", "expensive"]).toContain(d.tier);
|
|
42
|
+
expect(d.confidence).toBeGreaterThanOrEqual(0);
|
|
43
|
+
expect(d.confidence).toBeLessThanOrEqual(1);
|
|
44
|
+
expect(d.codemodIntent).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("default priors favor flash (alpha=2, beta=1)", () => {
|
|
48
|
+
const r = new ModelRouter({ seed: 1 });
|
|
49
|
+
const priors = r.getPriors();
|
|
50
|
+
// The default-prior math (matches ADR-026 §BANDIT_REWARDS note).
|
|
51
|
+
expect(priors.flash.alpha).toBe(2);
|
|
52
|
+
expect(priors.flash.beta).toBe(1);
|
|
53
|
+
expect(priors.mid.alpha).toBe(1);
|
|
54
|
+
expect(priors.mid.beta).toBe(1);
|
|
55
|
+
expect(priors.expensive.alpha).toBe(1);
|
|
56
|
+
expect(priors.expensive.beta).toBe(2);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("many flash successes shift priors toward flash", () => {
|
|
60
|
+
const r = new ModelRouter({ seed: 42 });
|
|
61
|
+
for (let i = 0; i < 30; i++) r.recordOutcome("flash", true);
|
|
62
|
+
const priors = r.getPriors();
|
|
63
|
+
expect(priors.flash.alpha).toBeGreaterThan(2);
|
|
64
|
+
expect(priors.flash.beta).toBe(1);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("flash failures increment β", () => {
|
|
68
|
+
const r = new ModelRouter({ seed: 42 });
|
|
69
|
+
for (let i = 0; i < 5; i++) r.recordOutcome("flash", false);
|
|
70
|
+
const priors = r.getPriors();
|
|
71
|
+
expect(priors.flash.alpha).toBe(2);
|
|
72
|
+
expect(priors.flash.beta).toBe(1 + 5);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("seeded RNG produces deterministic pick", () => {
|
|
76
|
+
const a = new ModelRouter({ seed: 7 });
|
|
77
|
+
const b = new ModelRouter({ seed: 7 });
|
|
78
|
+
const prompt = "explain what this function does";
|
|
79
|
+
// Run several samples; at least one must agree (probabilistically
|
|
80
|
+
// very near 1.0).
|
|
81
|
+
let matches = 0;
|
|
82
|
+
for (let i = 0; i < 20; i++) {
|
|
83
|
+
const da = a.route(prompt);
|
|
84
|
+
const db = b.route(prompt);
|
|
85
|
+
if (da.tier === db.tier) matches += 1;
|
|
86
|
+
}
|
|
87
|
+
expect(matches).toBeGreaterThanOrEqual(18);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("expensive success is devalued (alpha += 0.4)", () => {
|
|
91
|
+
const r = new ModelRouter({ seed: 42 });
|
|
92
|
+
r.recordOutcome("expensive", true);
|
|
93
|
+
const priors = r.getPriors();
|
|
94
|
+
expect(priors.expensive.alpha).toBeCloseTo(1.4);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("ModelRouter — overrides", () => {
|
|
99
|
+
test("priors override applies per-tier", () => {
|
|
100
|
+
const r = new ModelRouter({
|
|
101
|
+
priors: { expensive: { alpha: 100, beta: 1 } },
|
|
102
|
+
seed: 1,
|
|
103
|
+
});
|
|
104
|
+
const priors = r.getPriors();
|
|
105
|
+
expect(priors.expensive.alpha).toBe(100);
|
|
106
|
+
expect(priors.flash.alpha).toBe(2); // default still in place
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the Q-learning agent router (F-033).
|
|
3
|
+
*
|
|
4
|
+
* - selectAgent() returns one of the 8 hard-coded Bizar agent names.
|
|
5
|
+
* - Codemod prompts route to heimdall (the routine-implementation agent).
|
|
6
|
+
* - recordOutcome() updates the Q-table (snapshot mean shifts).
|
|
7
|
+
* - LRU caching: repeated tasks return the same pick without burning
|
|
8
|
+
* exploration budget.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, test, expect } from "vitest";
|
|
12
|
+
import { QLearningRouter, AGENT_ACTIONS } from "../src/router/q-learning-router.js";
|
|
13
|
+
|
|
14
|
+
describe("QLearningRouter — action set", () => {
|
|
15
|
+
test("AGENT_ACTIONS lists 8 Bizar agents", () => {
|
|
16
|
+
expect(AGENT_ACTIONS.length).toBe(8);
|
|
17
|
+
expect(AGENT_ACTIONS).toContain("odin");
|
|
18
|
+
expect(AGENT_ACTIONS).toContain("heimdall");
|
|
19
|
+
expect(AGENT_ACTIONS).toContain("forseti");
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("QLearningRouter — codemod short-circuit", () => {
|
|
24
|
+
test("var-to-const picks heimdall", () => {
|
|
25
|
+
const r = new QLearningRouter({ seed: 42, epsilon: 0 });
|
|
26
|
+
expect(r.selectAgent("convert var to const").agent).toBe("heimdall");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("remove-console picks heimdall", () => {
|
|
30
|
+
const r = new QLearningRouter({ seed: 42, epsilon: 0 });
|
|
31
|
+
expect(r.selectAgent("remove console.log calls").agent).toBe("heimdall");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("add-logging picks heimdall", () => {
|
|
35
|
+
const r = new QLearningRouter({ seed: 42, epsilon: 0 });
|
|
36
|
+
expect(r.selectAgent("add logging to the handler").agent).toBe("heimdall");
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("QLearningRouter — bandit behavior", () => {
|
|
41
|
+
test("non-codemod task returns a valid agent", () => {
|
|
42
|
+
const r = new QLearningRouter({ seed: 42, epsilon: 0.5 });
|
|
43
|
+
const d = r.selectAgent("explain the architecture of this codebase");
|
|
44
|
+
expect(AGENT_ACTIONS).toContain(d.agent);
|
|
45
|
+
expect(d.confidence).toBeGreaterThanOrEqual(0);
|
|
46
|
+
expect(d.confidence).toBeLessThanOrEqual(1);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("epsilon=0 deterministic given seeded RNG", () => {
|
|
50
|
+
const a = new QLearningRouter({ seed: 99, epsilon: 0 });
|
|
51
|
+
const b = new QLearningRouter({ seed: 99, epsilon: 0 });
|
|
52
|
+
const task = "implement a new cache layer for the storage engine";
|
|
53
|
+
// Different RNG state path; the LRU cache for the first call
|
|
54
|
+
// should fire identically. Subsequent calls fall back to bandit.
|
|
55
|
+
expect(a.selectAgent(task).agent).toBe(b.selectAgent(task).agent);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("recordOutcome shifts the Q snapshot toward the rewarded agent", () => {
|
|
59
|
+
const r = new QLearningRouter({ seed: 7, epsilon: 0 });
|
|
60
|
+
const before = r.snapshot().find((s) => s.agent === "thor")?.qMean ?? 0.5;
|
|
61
|
+
for (let i = 0; i < 50; i++) r.recordOutcome("thor", true);
|
|
62
|
+
const after = r.snapshot().find((s) => s.agent === "thor")?.qMean ?? 0.5;
|
|
63
|
+
expect(after).toBeGreaterThan(before);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("failures shift the Q mean downward", () => {
|
|
67
|
+
const r = new QLearningRouter({ seed: 7, epsilon: 0 });
|
|
68
|
+
for (let i = 0; i < 50; i++) r.recordOutcome("frigg", false);
|
|
69
|
+
const after = r.snapshot().find((s) => s.agent === "frigg")?.qMean ?? 0.5;
|
|
70
|
+
expect(after).toBeLessThan(0.5);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("recordOutcome is a no-op for unknown agents", () => {
|
|
74
|
+
const r = new QLearningRouter({ seed: 7, epsilon: 0 });
|
|
75
|
+
const before = r.snapshot();
|
|
76
|
+
r.recordOutcome("not-a-real-agent", true);
|
|
77
|
+
const after = r.snapshot();
|
|
78
|
+
expect(after).toEqual(before);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("QLearningRouter — LRU cache", () => {
|
|
83
|
+
test("repeated task returns the cached decision", () => {
|
|
84
|
+
const r = new QLearningRouter({ seed: 11, epsilon: 0 });
|
|
85
|
+
const task = "review this PR for security concerns";
|
|
86
|
+
const first = r.selectAgent(task);
|
|
87
|
+
const second = r.selectAgent(task);
|
|
88
|
+
// The LRU returns the exact stored object — same agent, same confidence.
|
|
89
|
+
expect(second.agent).toBe(first.agent);
|
|
90
|
+
expect(second.confidence).toBe(first.confidence);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("QLearningRouter — empty input safety", () => {
|
|
95
|
+
test("null task returns the safe odin fallback", () => {
|
|
96
|
+
const r = new QLearningRouter({ seed: 7 });
|
|
97
|
+
const d = r.selectAgent("");
|
|
98
|
+
expect(d.agent).toBe("odin");
|
|
99
|
+
});
|
|
100
|
+
});
|