mixdog 0.9.63 → 0.9.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/package.json +9 -2
- package/scripts/code-graph-description-contract.mjs +3 -3
- package/scripts/verify-release-assets.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +11 -14
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
- package/src/runtime/agent/orchestrator/config.mjs +19 -124
- package/src/runtime/agent/orchestrator/context/collect.mjs +6 -6
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +2 -2
- package/src/runtime/agent/orchestrator/internal-agents.mjs +2 -2
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +333 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -277
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +460 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +14 -593
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -280
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +357 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-headers.mjs +216 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +2 -188
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/file-reattach.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +17 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +18 -26
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/delivered-completions.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +260 -0
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +72 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +163 -0
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -561
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +2 -154
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/cwd-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-locks.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +2 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +519 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +5 -449
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +212 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +1 -7
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +9 -36
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +15 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +429 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +2 -395
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/mutation-planner.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/next-call-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +72 -9
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +2 -444
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +505 -0
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/backend-dispatch.mjs +20 -5
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/telegram-format.mjs +1 -1
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +4 -4
- package/src/runtime/channels/tool-defs.mjs +2 -3
- package/src/runtime/memory/index.mjs +1 -5
- package/src/runtime/memory/lib/core-memory-candidates.mjs +357 -0
- package/src/runtime/memory/lib/core-memory-store.mjs +7 -357
- package/src/runtime/memory/lib/cycle-signatures.mjs +1 -1
- package/src/runtime/memory/lib/embedding-model-config.mjs +1 -1
- package/src/runtime/memory/lib/embedding-provider.mjs +1 -5
- package/src/runtime/memory/lib/embedding-worker.mjs +1 -5
- package/src/runtime/memory/lib/ko-morph.mjs +2 -2
- package/src/runtime/memory/lib/memory-config-flags.mjs +2 -5
- package/src/runtime/memory/lib/memory-cycle-requests.mjs +3 -7
- package/src/runtime/memory/lib/memory-cycle1.mjs +4 -8
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +2 -5
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -5
- package/src/runtime/memory/lib/memory-embed.mjs +2 -6
- package/src/runtime/memory/lib/memory-log.mjs +8 -0
- package/src/runtime/memory/lib/memory-ops-policy.mjs +4 -8
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +1 -1
- package/src/runtime/memory/lib/memory-recall-store.mjs +2 -193
- package/src/runtime/memory/lib/memory-score.mjs +1 -1
- package/src/runtime/memory/lib/memory-text-utils.mjs +2 -2
- package/src/runtime/memory/lib/memory.mjs +2 -6
- package/src/runtime/memory/lib/pg/adapter.mjs +2 -6
- package/src/runtime/memory/lib/pg/process.mjs +1 -5
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -5
- package/src/runtime/memory/lib/recall-format.mjs +2 -2
- package/src/runtime/memory/lib/recall-scoring.mjs +195 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -5
- package/src/runtime/memory/lib/trace-store.mjs +2 -6
- package/src/runtime/search/lib/http-fetch.mjs +6 -6
- package/src/runtime/search/lib/web-tools.mjs +2 -2
- package/src/runtime/shared/buffered-appender.mjs +1 -1
- package/src/runtime/shared/child-guardian.mjs +1 -1
- package/src/runtime/shared/child-spawn-gate.mjs +1 -1
- package/src/runtime/shared/config.mjs +4 -4
- package/src/runtime/shared/launcher-control.mjs +9 -10
- package/src/runtime/shared/llm/index.mjs +5 -20
- package/src/runtime/shared/markdown-frontmatter.mjs +1 -1
- package/src/runtime/shared/memory-snapshot.mjs +4 -4
- package/src/runtime/shared/pristine-execution.mjs +1 -1
- package/src/runtime/shared/process-lifecycle.mjs +0 -1
- package/src/runtime/shared/process-shutdown.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +2 -2
- package/src/runtime/shared/schedule-session-run.mjs +1 -1
- package/src/runtime/shared/schedules-db.mjs +1 -1
- package/src/runtime/shared/service-discovery.mjs +2 -2
- package/src/runtime/shared/staged-update.mjs +6 -6
- package/src/runtime/shared/tool-execution-contract.mjs +1 -1
- package/src/runtime/shared/tool-primitives.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +2 -2
- package/src/runtime/shared/turn-snapshot.mjs +184 -0
- package/src/runtime/shared/update-checker.mjs +1 -1
- package/src/runtime/shared/user-cwd.mjs +3 -3
- package/src/runtime/shared/user-data-guard.mjs +4 -4
- package/src/runtime/shared/workspace-router.mjs +5 -5
- package/src/session-runtime/config-helpers.mjs +2 -3
- package/src/session-runtime/config-lifecycle.mjs +1 -1
- package/src/session-runtime/hitch-profile.mjs +1 -1
- package/src/session-runtime/lifecycle-api.mjs +6 -4
- package/src/session-runtime/model-recency.mjs +5 -5
- package/src/session-runtime/plugin-mcp.mjs +1 -1
- package/src/session-runtime/provider-request-snapshot.mjs +338 -0
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/session-text.mjs +4 -4
- package/src/session-runtime/session-turn-api.mjs +7 -0
- package/src/session-runtime/tool-catalog-schema.mjs +197 -0
- package/src/session-runtime/tool-catalog.mjs +6 -483
- package/src/session-runtime/tool-defs.mjs +1 -1
- package/src/standalone/agent-task-status.mjs +1 -1
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/channel-admin.mjs +4 -4
- package/src/standalone/explore-tool.mjs +3 -3
- package/src/standalone/hook-bus/config.mjs +1 -1
- package/src/standalone/hook-bus/constants.mjs +1 -1
- package/src/standalone/hook-bus/rules.mjs +1 -1
- package/src/standalone/projects.mjs +1 -1
- package/src/standalone/provider-admin.mjs +2 -2
- package/src/tui/App.jsx +1 -1
- package/src/tui/app/app-format.mjs +2 -2
- package/src/tui/app/clipboard.mjs +3 -3
- package/src/tui/app/input-parsers.mjs +1 -1
- package/src/tui/app/text-layout.mjs +1 -1
- package/src/tui/app/transcript-row-estimate.mjs +360 -0
- package/src/tui/app/transcript-window.mjs +5 -347
- package/src/tui/app/use-mouse-input.mjs +1 -1
- package/src/tui/app/use-prompt-handlers.mjs +1 -1
- package/src/tui/components/tool-execution/surface-detail.mjs +9 -9
- package/src/tui/components/tool-execution/text-format.mjs +2 -2
- package/src/tui/components/tool-output-format.mjs +7 -7
- package/src/tui/display-width.mjs +4 -4
- package/src/tui/dist/index.mjs +187 -99
- package/src/tui/engine/agent-envelope.mjs +5 -5
- package/src/tui/engine/live-share.mjs +100 -0
- package/src/tui/engine/notification-plan.mjs +1 -1
- package/src/tui/engine/queue-helpers.mjs +3 -3
- package/src/tui/engine/render-timing.mjs +4 -5
- package/src/tui/engine/session-api-ext.mjs +6 -3
- package/src/tui/engine/tool-result-status.mjs +5 -5
- package/src/tui/engine/tool-result-text.mjs +1 -1
- package/src/tui/engine/transcript-spill.mjs +585 -0
- package/src/tui/engine/tui-steering-persist.mjs +1 -1
- package/src/tui/engine.mjs +29 -474
- package/src/tui/lib/voice-setup.mjs +1 -1
- package/src/tui/markdown/format-token.mjs +1 -1
- package/src/tui/markdown/render-ansi.mjs +1 -1
- package/src/tui/markdown/table-layout.mjs +4 -4
- package/src/tui/paste-attachments.mjs +1 -1
- package/src/tui/prompt-history-store.mjs +3 -3
- package/src/tui/statusline-ansi-bridge.mjs +2 -2
- package/src/tui/theme.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +2 -2
- package/src/ui/ansi.mjs +0 -9
- package/src/ui/statusline-format.mjs +2 -4
- package/scripts/_bench-cwc.json +0 -20
- package/scripts/_jitter-fuzz.jsx +0 -42
- package/scripts/_jitter-fuzz2.jsx +0 -30
- package/scripts/_jitter-probe.jsx +0 -35
- package/scripts/_jp2.jsx +0 -16
- package/scripts/_smoke_wd.mjs +0 -7
- package/scripts/abort-recovery-test.mjs +0 -175
- package/scripts/agent-dispatch-abort-compose-test.mjs +0 -31
- package/scripts/agent-live-arg-guard-smoke.mjs +0 -20
- package/scripts/agent-live-path-suffix-smoke.mjs +0 -34
- package/scripts/agent-live-toolcall-args-smoke.mjs +0 -45
- package/scripts/agent-loop-policy-test.mjs +0 -37
- package/scripts/agent-model-liveness-test.mjs +0 -763
- package/scripts/agent-parallel-smoke.mjs +0 -435
- package/scripts/agent-route-batch-test.mjs +0 -40
- package/scripts/agent-tag-reuse-smoke.mjs +0 -441
- package/scripts/agent-terminal-reap-test.mjs +0 -252
- package/scripts/agent-trace-io-test.mjs +0 -133
- package/scripts/ansi-color-capability-test.mjs +0 -90
- package/scripts/anthropic-admission-retry-integration-test.mjs +0 -119
- package/scripts/anthropic-maxtokens-test.mjs +0 -119
- package/scripts/anthropic-oauth-refresh-race-test.mjs +0 -397
- package/scripts/anthropic-transport-policy-test.mjs +0 -726
- package/scripts/apply-patch-edit-smoke.mjs +0 -71
- package/scripts/arg-guard-test.mjs +0 -93
- package/scripts/async-notify-settlement-test.mjs +0 -99
- package/scripts/atomic-lock-tryonce-test.mjs +0 -125
- package/scripts/background-task-meta-smoke.mjs +0 -38
- package/scripts/bench-run.mjs +0 -508
- package/scripts/boot-smoke.mjs +0 -137
- package/scripts/build-runtime-windows.ps1 +0 -242
- package/scripts/channel-daemon-smoke.mjs +0 -1103
- package/scripts/code-graph-aggregate-cwd-test.mjs +0 -158
- package/scripts/code-graph-disk-hit-test.mjs +0 -290
- package/scripts/code-graph-dispatch-test.mjs +0 -96
- package/scripts/code-graph-root-federation-test.mjs +0 -273
- package/scripts/compact-active-turn-test.mjs +0 -68
- package/scripts/compact-file-reattach-test.mjs +0 -88
- package/scripts/compact-pressure-test.mjs +0 -788
- package/scripts/compact-prior-context-flatten-test.mjs +0 -252
- package/scripts/compact-recall-digest-test.mjs +0 -57
- package/scripts/compact-smoke.mjs +0 -1017
- package/scripts/compact-trigger-migration-smoke.mjs +0 -261
- package/scripts/compacted-placeholder-scrub-test.mjs +0 -63
- package/scripts/context-mcp-metering-test.mjs +0 -1406
- package/scripts/debounced-skills-async-save-test.mjs +0 -57
- package/scripts/deferred-tool-loading-test.mjs +0 -250
- package/scripts/desktop-session-bridge-test.mjs +0 -1013
- package/scripts/dispatch-persist-recovery-test.mjs +0 -141
- package/scripts/embedding-worker-exit-test.mjs +0 -76
- package/scripts/execution-completion-dedup-test.mjs +0 -205
- package/scripts/execution-pending-resume-kick-test.mjs +0 -151
- package/scripts/execution-resume-esc-integration-test.mjs +0 -176
- package/scripts/explore-bench-tmp.mjs +0 -36
- package/scripts/explore-bench.mjs +0 -248
- package/scripts/explore-prompt-policy-test.mjs +0 -256
- package/scripts/explore-timeout-cancel-test.mjs +0 -345
- package/scripts/find-fuzzy-hidden-test.mjs +0 -267
- package/scripts/forwarder-rebind-tail-test.mjs +0 -67
- package/scripts/freevar-smoke.mjs +0 -98
- package/scripts/gemini-provider-test.mjs +0 -1448
- package/scripts/generate-oc-icons.mjs +0 -11
- package/scripts/grok-oauth-refresh-race-test.mjs +0 -273
- package/scripts/headless-pristine-execution-test.mjs +0 -614
- package/scripts/hook-bus-test.mjs +0 -552
- package/scripts/ingest-pure-conversation-smoke.mjs +0 -175
- package/scripts/internal-comms-bench-test.mjs +0 -226
- package/scripts/internal-comms-bench.mjs +0 -853
- package/scripts/internal-comms-smoke.mjs +0 -277
- package/scripts/internal-tools-normalization-test.mjs +0 -62
- package/scripts/interrupted-turn-history-test.mjs +0 -399
- package/scripts/lead-workflow-smoke.mjs +0 -592
- package/scripts/lifecycle-api-test.mjs +0 -137
- package/scripts/live-share-test.mjs +0 -148
- package/scripts/live-worker-smoke.mjs +0 -333
- package/scripts/log-writer-guard-smoke.mjs +0 -131
- package/scripts/maintenance-default-routes-test.mjs +0 -164
- package/scripts/max-output-recovery-persist-test.mjs +0 -81
- package/scripts/max-output-recovery-test.mjs +0 -368
- package/scripts/mcp-client-normalization-test.mjs +0 -45
- package/scripts/mcp-grace-deferred-test.mjs +0 -225
- package/scripts/memory-core-input-test.mjs +0 -167
- package/scripts/memory-cycle-routing-test.mjs +0 -111
- package/scripts/memory-meta-concurrency-test.mjs +0 -20
- package/scripts/memory-pg-recovery-test.mjs +0 -59
- package/scripts/memory-rule-contract-test.mjs +0 -93
- package/scripts/model-list-sanitize-test.mjs +0 -37
- package/scripts/mouse-tracking-restore-smoke.mjs +0 -107
- package/scripts/native-edit-wire-test.mjs +0 -152
- package/scripts/notify-completion-mirror-test.mjs +0 -73
- package/scripts/openai-oauth-refresh-race-test.mjs +0 -120
- package/scripts/openai-oauth-ws-1006-retry-test.mjs +0 -954
- package/scripts/openai-ws-early-settle-test.mjs +0 -216
- package/scripts/output-style-bench.mjs +0 -292
- package/scripts/output-style-smoke.mjs +0 -145
- package/scripts/parent-abort-link-test.mjs +0 -90
- package/scripts/patch-binary-cache-test.mjs +0 -181
- package/scripts/path-suffix-test.mjs +0 -57
- package/scripts/pending-completion-drop-test.mjs +0 -239
- package/scripts/pending-messages-lock-nonblocking-test.mjs +0 -62
- package/scripts/pretool-ask-runtime-test.mjs +0 -54
- package/scripts/process-lifecycle-test.mjs +0 -461
- package/scripts/prompt-immediate-render-test.mjs +0 -89
- package/scripts/prompt-input-parity-test.mjs +0 -145
- package/scripts/provider-admission-scheduler-test.mjs +0 -681
- package/scripts/provider-contract-test.mjs +0 -632
- package/scripts/provider-stream-stall-test.mjs +0 -276
- package/scripts/provider-toolcall-test.mjs +0 -3063
- package/scripts/reactive-compact-persist-smoke.mjs +0 -203
- package/scripts/recall-bench.mjs +0 -359
- package/scripts/resource-admission-test.mjs +0 -792
- package/scripts/result-classification-test.mjs +0 -75
- package/scripts/rg-runner-test.mjs +0 -240
- package/scripts/routing-corpus-test.mjs +0 -349
- package/scripts/sanitize-tool-pairs-test.mjs +0 -260
- package/scripts/session-bench-cache-break-test.mjs +0 -102
- package/scripts/session-bench.mjs +0 -1708
- package/scripts/session-context-bench.mjs +0 -344
- package/scripts/session-heartbeat-lifecycle-test.mjs +0 -68
- package/scripts/session-ingest-compaction-smoke.mjs +0 -279
- package/scripts/session-ingest-smoke.mjs +0 -177
- package/scripts/session-orphan-sweep-test.mjs +0 -109
- package/scripts/set-effort-config-test.mjs +0 -41
- package/scripts/shell-failure-diagnostics-test.mjs +0 -280
- package/scripts/shell-hardening-test.mjs +0 -209
- package/scripts/shell-jobs-windows-hide-test.mjs +0 -164
- package/scripts/ship-mode-test.mjs +0 -98
- package/scripts/smoke-loop-failure-summary-test.mjs +0 -38
- package/scripts/smoke-loop-failure-summary.mjs +0 -16
- package/scripts/smoke-loop-report.mjs +0 -221
- package/scripts/smoke-loop.mjs +0 -202
- package/scripts/smoke-runtime-negative.ps1 +0 -106
- package/scripts/statusline-quota-hysteresis-test.mjs +0 -62
- package/scripts/steering-drain-buckets-test.mjs +0 -467
- package/scripts/steering-fold-provenance-test.mjs +0 -71
- package/scripts/streaming-tail-window-test.mjs +0 -175
- package/scripts/submit-commandbusy-race-test.mjs +0 -257
- package/scripts/task-bench.mjs +0 -205
- package/scripts/terminal-bench-isolation-guards-test.mjs +0 -102
- package/scripts/termio-input-smoke.mjs +0 -199
- package/scripts/tool-result-hook-test.mjs +0 -48
- package/scripts/tool-smoke.mjs +0 -2453
- package/scripts/tool-tui-presentation-test.mjs +0 -286
- package/scripts/toolcall-args-test.mjs +0 -239
- package/scripts/tui-ambiguous-width-test.mjs +0 -113
- package/scripts/tui-background-failure-smoke.mjs +0 -73
- package/scripts/tui-perf-run.ps1 +0 -26
- package/scripts/tui-render-smoke.mjs +0 -90
- package/scripts/tui-runtime-load-bench-entry.jsx +0 -608
- package/scripts/tui-runtime-load-bench.mjs +0 -50
- package/scripts/tui-store-frame-batch-test.mjs +0 -99
- package/scripts/tui-transcript-jitter-harness-entry.jsx +0 -383
- package/scripts/tui-transcript-perf-test.mjs +0 -934
- package/scripts/usage-metrics-epoch-smoke.mjs +0 -114
- package/scripts/verify-release-assets-test.mjs +0 -281
- package/scripts/web-fetch-routing-test.mjs +0 -158
- package/scripts/webhook-smoke.mjs +0 -201
- package/scripts/windows-hide-spawn-options-test.mjs +0 -19
- package/scripts/worker-notify-rejection-test.mjs +0 -51
- package/scripts/write-backpressure-test.mjs +0 -147
|
@@ -1,853 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// internal-comms-bench.mjs — live A/B token measurement for internal-comms rules.
|
|
3
|
-
//
|
|
4
|
-
// Variant A (verbose): prior committed blobs via `git show HEAD:src/<rule>`.
|
|
5
|
-
// Variant B (optimized): current on-disk src/ copied into a temp PLUGIN_ROOT.
|
|
6
|
-
// Only the listed rule files differ between variants; everything else matches.
|
|
7
|
-
//
|
|
8
|
-
// node scripts/internal-comms-bench.mjs
|
|
9
|
-
// node scripts/internal-comms-bench.mjs --run [--model grok] [--provider P] [--json]
|
|
10
|
-
import { execFileSync, spawnSync } from 'node:child_process';
|
|
11
|
-
import {
|
|
12
|
-
copyFileSync,
|
|
13
|
-
cpSync,
|
|
14
|
-
existsSync,
|
|
15
|
-
mkdirSync,
|
|
16
|
-
mkdtempSync,
|
|
17
|
-
readFileSync,
|
|
18
|
-
readdirSync,
|
|
19
|
-
rmSync,
|
|
20
|
-
writeFileSync,
|
|
21
|
-
} from 'node:fs';
|
|
22
|
-
import { homedir } from 'node:os';
|
|
23
|
-
import { dirname, join, resolve } from 'node:path';
|
|
24
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
25
|
-
|
|
26
|
-
const __dir = dirname(fileURLToPath(import.meta.url));
|
|
27
|
-
const REPO_ROOT = resolve(__dir, '..');
|
|
28
|
-
const PLUGIN_ROOT = join(REPO_ROOT, 'src');
|
|
29
|
-
const HEADLESS = pathToFileURL(resolve(__dir, '../src/headless-role.mjs')).href;
|
|
30
|
-
|
|
31
|
-
const RULE_FILES = [
|
|
32
|
-
'rules/agent/00-core.md',
|
|
33
|
-
'rules/agent/00-common.md',
|
|
34
|
-
'rules/agent/20-skip-protocol.md',
|
|
35
|
-
'agents/worker/AGENT.md',
|
|
36
|
-
'agents/heavy-worker/AGENT.md',
|
|
37
|
-
'agents/reviewer/AGENT.md',
|
|
38
|
-
'agents/debugger/AGENT.md',
|
|
39
|
-
'workflows/default/WORKFLOW.md',
|
|
40
|
-
'workflows/solo/WORKFLOW.md',
|
|
41
|
-
'rules/lead/01-general.md',
|
|
42
|
-
'rules/lead/02-channels.md',
|
|
43
|
-
'rules/lead/lead-tool.md',
|
|
44
|
-
'rules/lead/lead-brief.md',
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
const DEFAULT_WORKER_PROMPT =
|
|
48
|
-
'In math.js add an exported function add(a, b) that returns a + b. Keep the existing mul export unchanged. Use apply_patch only. Stop when the function exists; hand off with outcome and file:line.';
|
|
49
|
-
|
|
50
|
-
// Lead-mode task: FORCES delegation so the real internal-comms flow runs
|
|
51
|
-
// (Lead writes a brief -> worker returns a handoff -> reviewer verifies).
|
|
52
|
-
// Identical across variants A/B; only the on-disk rule files differ.
|
|
53
|
-
const DEFAULT_LEAD_PROMPT = [
|
|
54
|
-
'You are the Lead in an automation benchmark. A file named math.js already exists in your working directory.',
|
|
55
|
-
'This is the planning turn: give a concise plan only, then wait for a later explicit approval. Do not edit, mutate state, or delegate in this turn.',
|
|
56
|
-
'After approval, do NOT edit any file yourself or call apply_patch yourself. Delegate every implementation step: first a worker adds exported add(a, b) returning a + b to math.js while preserving mul, then a reviewer verifies both exports. Finally reply with a one-line outcome plus math.js:line.',
|
|
57
|
-
].join(' ');
|
|
58
|
-
export const DEFAULT_LEAD_APPROVAL_PROMPT = 'Proceed with the latest plan.';
|
|
59
|
-
export const CHILD_RESULT_START = '__INTERNAL_COMMS_BENCH_RESULT_START__';
|
|
60
|
-
export const CHILD_RESULT_END = '__INTERNAL_COMMS_BENCH_RESULT_END__';
|
|
61
|
-
|
|
62
|
-
const MODEL_ALIASES = {
|
|
63
|
-
opus: { provider: 'anthropic-oauth', model: 'claude-opus-4-8' },
|
|
64
|
-
sonnet: { provider: 'anthropic-oauth', model: 'claude-sonnet-5' },
|
|
65
|
-
gpt: { provider: 'openai-oauth', model: 'gpt-5.5' },
|
|
66
|
-
'gpt-5.5': { provider: 'openai-oauth', model: 'gpt-5.5' },
|
|
67
|
-
grok: { provider: 'grok-oauth', model: 'grok-composer-2.5-fast' },
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const AUTH_ARTIFACT_BY_PROVIDER = {
|
|
71
|
-
'grok-oauth': ['grok-oauth.json', 'grok-oauth-models.json'],
|
|
72
|
-
'anthropic-oauth': ['anthropic-oauth-credentials.json', 'anthropic-oauth-models.json'],
|
|
73
|
-
'openai-oauth': ['openai-oauth.json', 'openai-oauth-models.json'],
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const INITIAL_MATH_JS = `export function mul(a, b) {
|
|
77
|
-
return a * b;
|
|
78
|
-
}
|
|
79
|
-
`;
|
|
80
|
-
|
|
81
|
-
function argValue(name, fallback = null) {
|
|
82
|
-
const idx = process.argv.indexOf(name);
|
|
83
|
-
if (idx >= 0 && idx + 1 < process.argv.length) return process.argv[idx + 1];
|
|
84
|
-
const pref = `${name}=`;
|
|
85
|
-
const hit = process.argv.find((a) => a.startsWith(pref));
|
|
86
|
-
return hit ? hit.slice(pref.length) : fallback;
|
|
87
|
-
}
|
|
88
|
-
function hasFlag(name) { return process.argv.includes(name); }
|
|
89
|
-
|
|
90
|
-
function resolveModelOpts(modelArg, providerArg) {
|
|
91
|
-
const key = String(modelArg || '').trim().toLowerCase();
|
|
92
|
-
if (MODEL_ALIASES[key] && !providerArg) return { ...MODEL_ALIASES[key] };
|
|
93
|
-
return { provider: providerArg || null, model: modelArg || null };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function defaultUserDataDir() {
|
|
97
|
-
return process.env.MIXDOG_DATA_DIR || join(process.env.MIXDOG_HOME || join(homedir(), '.mixdog'), 'data');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function readUnifiedConfig(dataDir) {
|
|
101
|
-
try {
|
|
102
|
-
const unified = JSON.parse(readFileSync(join(dataDir, 'mixdog-config.json'), 'utf8'));
|
|
103
|
-
return unified && typeof unified === 'object' ? unified : {};
|
|
104
|
-
} catch { return {}; }
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function gitPathForRule(relFromSrc) {
|
|
108
|
-
return `src/${String(relFromSrc).replace(/\\/g, '/')}`;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function readPriorRuleBlob(relFromSrc) {
|
|
112
|
-
const gitPath = gitPathForRule(relFromSrc);
|
|
113
|
-
try {
|
|
114
|
-
return execFileSync('git', ['show', `HEAD:${gitPath}`], {
|
|
115
|
-
cwd: REPO_ROOT,
|
|
116
|
-
encoding: 'utf8',
|
|
117
|
-
maxBuffer: 8 * 1024 * 1024,
|
|
118
|
-
});
|
|
119
|
-
} catch {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function readCurrentRule(relFromSrc) {
|
|
125
|
-
return readFileSync(join(PLUGIN_ROOT, relFromSrc), 'utf8');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function ruleVariantBytes() {
|
|
129
|
-
const rows = [];
|
|
130
|
-
for (const rel of RULE_FILES) {
|
|
131
|
-
const prior = readPriorRuleBlob(rel);
|
|
132
|
-
const current = readCurrentRule(rel);
|
|
133
|
-
const aText = prior != null ? prior : current;
|
|
134
|
-
rows.push({
|
|
135
|
-
file: rel,
|
|
136
|
-
a_chars: aText.length,
|
|
137
|
-
b_chars: current.length,
|
|
138
|
-
prior_from_git: prior != null,
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
return rows;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function authArtifactNamesForSandbox(realDataDir, provider) {
|
|
145
|
-
const names = new Set();
|
|
146
|
-
for (const file of AUTH_ARTIFACT_BY_PROVIDER[provider] || []) names.add(file);
|
|
147
|
-
try {
|
|
148
|
-
for (const entry of readdirSync(realDataDir, { withFileTypes: true })) {
|
|
149
|
-
if (!entry.isFile() || !entry.name.endsWith('.json')) continue;
|
|
150
|
-
if (/oauth/i.test(entry.name) || /credentials/i.test(entry.name)) names.add(entry.name);
|
|
151
|
-
}
|
|
152
|
-
} catch { /* missing real data dir */ }
|
|
153
|
-
return [...names];
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function copyAuthArtifacts(realDataDir, sandboxDataDir, provider) {
|
|
157
|
-
const copied = [];
|
|
158
|
-
const skipped = [];
|
|
159
|
-
for (const name of authArtifactNamesForSandbox(realDataDir, provider)) {
|
|
160
|
-
const src = join(realDataDir, name);
|
|
161
|
-
const dest = join(sandboxDataDir, name);
|
|
162
|
-
if (!existsSync(src)) {
|
|
163
|
-
skipped.push(name);
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
try {
|
|
167
|
-
copyFileSync(src, dest);
|
|
168
|
-
copied.push(name);
|
|
169
|
-
} catch {
|
|
170
|
-
skipped.push(name);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return { copied, skipped };
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function materializePluginRoot(variant, sandboxRoot) {
|
|
177
|
-
const pluginRoot = join(sandboxRoot, `plugin-${variant}`);
|
|
178
|
-
cpSync(PLUGIN_ROOT, pluginRoot, { recursive: true });
|
|
179
|
-
if (variant === 'A') {
|
|
180
|
-
for (const rel of RULE_FILES) {
|
|
181
|
-
const prior = readPriorRuleBlob(rel);
|
|
182
|
-
if (prior != null) writeFileSync(join(pluginRoot, rel), prior, 'utf8');
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return pluginRoot;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function prepareDataDir(sandboxRoot, variant, realDataDir, userUnified, provider) {
|
|
189
|
-
const dataDir = join(sandboxRoot, `data-${variant}`);
|
|
190
|
-
mkdirSync(join(dataDir, 'history'), { recursive: true });
|
|
191
|
-
writeFileSync(join(dataDir, 'mixdog-config.json'), JSON.stringify(userUnified, null, 2));
|
|
192
|
-
copyAuthArtifacts(realDataDir, dataDir, provider);
|
|
193
|
-
return dataDir;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function resetTaskCwd(taskCwd) {
|
|
197
|
-
writeFileSync(join(taskCwd, 'math.js'), INITIAL_MATH_JS, 'utf8');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function prepareTaskCwd(parentDir) {
|
|
201
|
-
const taskCwd = mkdtempSync(join(parentDir, 'task-'));
|
|
202
|
-
resetTaskCwd(taskCwd);
|
|
203
|
-
return taskCwd;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function extractSessionId(text) {
|
|
207
|
-
const s = String(text || '');
|
|
208
|
-
const m = s.match(/sessionId:\s*(sess_[A-Za-z0-9_]+)/) || s.match(/\b(sess_[A-Za-z0-9_]+)/);
|
|
209
|
-
return m ? m[1] : null;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function runHeadlessWorker({ pluginRoot, dataDir, taskCwd, prompt, provider, model, effort, fast }) {
|
|
213
|
-
const driver = [
|
|
214
|
-
`import { runHeadlessRole } from ${JSON.stringify(HEADLESS)};`,
|
|
215
|
-
`const out = [];`,
|
|
216
|
-
`const code = await runHeadlessRole({`,
|
|
217
|
-
` agent: 'worker',`,
|
|
218
|
-
` message: ${JSON.stringify(prompt)},`,
|
|
219
|
-
` provider: ${JSON.stringify(provider || null)},`,
|
|
220
|
-
` model: ${JSON.stringify(model || null)},`,
|
|
221
|
-
` effort: ${JSON.stringify(effort || null)},`,
|
|
222
|
-
` fast: ${JSON.stringify(fast === true)},`,
|
|
223
|
-
` cwd: ${JSON.stringify(taskCwd)},`,
|
|
224
|
-
` write: (t) => out.push(t),`,
|
|
225
|
-
` writeErr: (t) => process.stderr.write(t),`,
|
|
226
|
-
`});`,
|
|
227
|
-
`process.stdout.write(out.join(''));`,
|
|
228
|
-
`process.exit(code);`,
|
|
229
|
-
].join('\n');
|
|
230
|
-
const started = Date.now();
|
|
231
|
-
let raw = '';
|
|
232
|
-
let ok = false;
|
|
233
|
-
try {
|
|
234
|
-
raw = execFileSync('node', ['--input-type=module', '-e', driver], {
|
|
235
|
-
encoding: 'utf8',
|
|
236
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
237
|
-
env: {
|
|
238
|
-
...process.env,
|
|
239
|
-
MIXDOG_ROOT: pluginRoot,
|
|
240
|
-
MIXDOG_DATA_DIR: dataDir,
|
|
241
|
-
},
|
|
242
|
-
});
|
|
243
|
-
ok = true;
|
|
244
|
-
} catch (e) {
|
|
245
|
-
raw = String(e.stdout || '') + String(e.stderr || '');
|
|
246
|
-
ok = false;
|
|
247
|
-
}
|
|
248
|
-
return { sessionId: extractSessionId(raw), ok, ms: Date.now() - started, raw };
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function readRows(path) {
|
|
252
|
-
if (!existsSync(path)) return [];
|
|
253
|
-
const rows = [];
|
|
254
|
-
for (const line of readFileSync(path, 'utf8').split(/\r?\n/)) {
|
|
255
|
-
if (!line) continue;
|
|
256
|
-
try {
|
|
257
|
-
rows.push(JSON.parse(line));
|
|
258
|
-
} catch { /* tail */ }
|
|
259
|
-
}
|
|
260
|
-
return rows;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function payload(row) {
|
|
264
|
-
return row?.payload && typeof row.payload === 'object' ? row.payload : {};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function field(row, name) {
|
|
268
|
-
if (row && row[name] != null) return row[name];
|
|
269
|
-
const p = payload(row);
|
|
270
|
-
return p[name] != null ? p[name] : null;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
function num(row, name) {
|
|
274
|
-
const n = Number(field(row, name));
|
|
275
|
-
return Number.isFinite(n) ? n : null;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
function sessionId(row) {
|
|
279
|
-
return String(row?.session_id || row?.sessionId || field(row, 'session_id') || '');
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function sum(values) {
|
|
283
|
-
return values.reduce((s, v) => s + (Number.isFinite(Number(v)) ? Number(v) : 0), 0);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function groupBy(rows, keyFn) {
|
|
287
|
-
const map = new Map();
|
|
288
|
-
for (const row of rows) {
|
|
289
|
-
const key = keyFn(row);
|
|
290
|
-
if (!key) continue;
|
|
291
|
-
if (!map.has(key)) map.set(key, []);
|
|
292
|
-
map.get(key).push(row);
|
|
293
|
-
}
|
|
294
|
-
return map;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function inferSessionMeta(rows) {
|
|
298
|
-
const sorted = [...rows].sort((a, b) => Number(a.ts || 0) - Number(b.ts || 0));
|
|
299
|
-
const preset = sorted.find((r) => r.kind === 'preset_assign');
|
|
300
|
-
const usage = [...sorted].reverse().find((r) => r.kind === 'usage_raw' || r.kind === 'usage');
|
|
301
|
-
const tool = sorted.find((r) => r.kind === 'tool');
|
|
302
|
-
const last = sorted[sorted.length - 1] || {};
|
|
303
|
-
const tsValues = sorted.map((r) => Number(r.ts || 0)).filter((n) => n > 0);
|
|
304
|
-
return {
|
|
305
|
-
session_id: sessionId(last),
|
|
306
|
-
parent_session_id: field(preset, 'parent_session_id') || field(preset, 'parentSessionId') || null,
|
|
307
|
-
agent: field(preset, 'agent') || field(tool, 'agent') || field(usage, 'sourceName') || field(last, 'sourceName') || null,
|
|
308
|
-
min_ts: tsValues.length ? Math.min(...tsValues) : null,
|
|
309
|
-
max_ts: tsValues.length ? Math.max(...tsValues) : null,
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function selectSessionFamily(sessionMetas, query) {
|
|
314
|
-
const selected = sessionMetas.find((m) => m.session_id === query)
|
|
315
|
-
|| sessionMetas.find((m) => m.session_id.startsWith(query));
|
|
316
|
-
if (!selected) return [];
|
|
317
|
-
const root = selected.parent_session_id
|
|
318
|
-
? sessionMetas.find((m) => m.session_id === selected.parent_session_id) || selected
|
|
319
|
-
: selected;
|
|
320
|
-
const ids = new Set([root.session_id, selected.session_id]);
|
|
321
|
-
for (const meta of sessionMetas) {
|
|
322
|
-
if (meta.parent_session_id === root.session_id) ids.add(meta.session_id);
|
|
323
|
-
}
|
|
324
|
-
return [...ids].filter(Boolean);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function sumUsageForSession(dataDir, rootSessionId) {
|
|
328
|
-
const tracePath = join(dataDir, 'history', 'agent-trace.jsonl');
|
|
329
|
-
const rows = readRows(tracePath);
|
|
330
|
-
const bySid = groupBy(rows, sessionId);
|
|
331
|
-
const sessionMetas = [...bySid.entries()].map(([, srows]) => inferSessionMeta(srows));
|
|
332
|
-
const family = selectSessionFamily(sessionMetas, rootSessionId);
|
|
333
|
-
const usageRows = rows.filter((r) => r.kind === 'usage_raw' && family.includes(sessionId(r)));
|
|
334
|
-
return {
|
|
335
|
-
tracePath,
|
|
336
|
-
session_ids: family,
|
|
337
|
-
prompt_tokens: sum(usageRows.map((r) => num(r, 'prompt_tokens'))),
|
|
338
|
-
output_tokens: sum(usageRows.map((r) => num(r, 'output_tokens'))),
|
|
339
|
-
cached_tokens: sum(usageRows.map((r) => num(r, 'cached_tokens'))),
|
|
340
|
-
usage_rows: usageRows.length,
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// ---- lead mode: multi-agent role-split token attribution -------------------
|
|
345
|
-
|
|
346
|
-
const ROLES = ['lead', 'worker', 'reviewer', 'other'];
|
|
347
|
-
|
|
348
|
-
function roleOf(agent) {
|
|
349
|
-
const a = String(agent || '').toLowerCase();
|
|
350
|
-
if (!a) return 'other';
|
|
351
|
-
if (a === 'lead' || a === 'main') return 'lead';
|
|
352
|
-
if (a.includes('review')) return 'reviewer'; // reviewer before worker (heavy-worker matches 'worker')
|
|
353
|
-
if (a.includes('worker')) return 'worker';
|
|
354
|
-
return 'other';
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function emptyRoleBucket() {
|
|
358
|
-
return { prompt_tokens: 0, output_tokens: 0, cached_tokens: 0, usage_rows: 0, total_tokens: 0 };
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Transitive closure over parent_session_id from the Lead root: collects the
|
|
362
|
-
// whole Lead+children session tree (worker/reviewer sessions link back via
|
|
363
|
-
// parent_session_id recorded on their preset_assign rows).
|
|
364
|
-
function collectSessionTree(sessionMetas, rootSessionId) {
|
|
365
|
-
const byParent = new Map();
|
|
366
|
-
for (const meta of sessionMetas) {
|
|
367
|
-
const p = meta.parent_session_id || null;
|
|
368
|
-
if (!byParent.has(p)) byParent.set(p, []);
|
|
369
|
-
byParent.get(p).push(meta);
|
|
370
|
-
}
|
|
371
|
-
const ids = new Set();
|
|
372
|
-
const queue = [rootSessionId];
|
|
373
|
-
while (queue.length) {
|
|
374
|
-
const id = queue.shift();
|
|
375
|
-
if (!id || ids.has(id)) continue;
|
|
376
|
-
ids.add(id);
|
|
377
|
-
for (const child of byParent.get(id) || []) queue.push(child.session_id);
|
|
378
|
-
}
|
|
379
|
-
return ids;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function emptyRoleSplit(dataDir) {
|
|
383
|
-
return {
|
|
384
|
-
tracePath: join(dataDir, 'history', 'agent-trace.jsonl'),
|
|
385
|
-
session_ids: [],
|
|
386
|
-
byRole: { lead: emptyRoleBucket(), worker: emptyRoleBucket(), reviewer: emptyRoleBucket(), other: emptyRoleBucket() },
|
|
387
|
-
total: { prompt_tokens: 0, output_tokens: 0, total_tokens: 0, usage_rows: 0 },
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function mathTaskCompleted(taskCwd) {
|
|
392
|
-
let source = '';
|
|
393
|
-
try {
|
|
394
|
-
source = readFileSync(join(taskCwd, 'math.js'), 'utf8');
|
|
395
|
-
} catch {
|
|
396
|
-
return false;
|
|
397
|
-
}
|
|
398
|
-
return source !== INITIAL_MATH_JS
|
|
399
|
-
&& /export\s+function\s+add\s*\(\s*a\s*,\s*b\s*\)\s*\{\s*return\s+a\s*\+\s*b\s*;?\s*\}/.test(source)
|
|
400
|
-
&& /export\s+function\s+mul\s*\(\s*a\s*,\s*b\s*\)\s*\{\s*return\s+a\s*\*\s*b\s*;?\s*\}/.test(source);
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
function splitTokensByRole(dataDir, rootSessionId) {
|
|
404
|
-
const tracePath = join(dataDir, 'history', 'agent-trace.jsonl');
|
|
405
|
-
const rows = readRows(tracePath);
|
|
406
|
-
const bySid = groupBy(rows, sessionId);
|
|
407
|
-
const sessionMetas = [...bySid.entries()].map(([sid, srows]) => ({ ...inferSessionMeta(srows), session_id: sid }));
|
|
408
|
-
const treeIds = collectSessionTree(sessionMetas, rootSessionId);
|
|
409
|
-
const roleBySession = new Map();
|
|
410
|
-
for (const meta of sessionMetas) {
|
|
411
|
-
if (treeIds.has(meta.session_id)) roleBySession.set(meta.session_id, roleOf(meta.agent));
|
|
412
|
-
}
|
|
413
|
-
// The Lead root session is created via createSession() directly (no
|
|
414
|
-
// session-builder), so it emits no preset_assign row and inferSessionMeta
|
|
415
|
-
// falls back to sourceName ('internal-comms-bench-lead') which roleOf() maps
|
|
416
|
-
// to 'other'. Pin the root to 'lead' explicitly. Worker/reviewer children go
|
|
417
|
-
// through session-builder -> traceAgentPreset, so their agent is recorded.
|
|
418
|
-
if (treeIds.has(rootSessionId)) roleBySession.set(rootSessionId, 'lead');
|
|
419
|
-
const byRole = { lead: emptyRoleBucket(), worker: emptyRoleBucket(), reviewer: emptyRoleBucket(), other: emptyRoleBucket() };
|
|
420
|
-
const usageRows = rows.filter((r) => r.kind === 'usage_raw' && treeIds.has(sessionId(r)));
|
|
421
|
-
for (const r of usageRows) {
|
|
422
|
-
const role = roleBySession.get(sessionId(r)) || 'other';
|
|
423
|
-
const bucket = byRole[role] || byRole.other;
|
|
424
|
-
bucket.prompt_tokens += num(r, 'prompt_tokens') || 0;
|
|
425
|
-
bucket.output_tokens += num(r, 'output_tokens') || 0;
|
|
426
|
-
bucket.cached_tokens += num(r, 'cached_tokens') || 0;
|
|
427
|
-
bucket.usage_rows += 1;
|
|
428
|
-
}
|
|
429
|
-
const total = { prompt_tokens: 0, output_tokens: 0, total_tokens: 0, usage_rows: 0 };
|
|
430
|
-
for (const role of ROLES) {
|
|
431
|
-
byRole[role].total_tokens = byRole[role].prompt_tokens + byRole[role].output_tokens;
|
|
432
|
-
total.prompt_tokens += byRole[role].prompt_tokens;
|
|
433
|
-
total.output_tokens += byRole[role].output_tokens;
|
|
434
|
-
total.total_tokens += byRole[role].total_tokens;
|
|
435
|
-
total.usage_rows += byRole[role].usage_rows;
|
|
436
|
-
}
|
|
437
|
-
return { tracePath, session_ids: [...treeIds], byRole, total };
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
export function validateLeadRun({ taskCwd, run, split }) {
|
|
441
|
-
const reasons = [];
|
|
442
|
-
if (!run.ok) reasons.push('child did not return a successful benchmark result');
|
|
443
|
-
if (!mathTaskCompleted(taskCwd)) reasons.push('math.js does not contain the approved add and preserved mul implementation');
|
|
444
|
-
if ((split?.byRole?.worker?.usage_rows || 0) < 1) reasons.push('worker participation/usage is missing');
|
|
445
|
-
if ((split?.byRole?.reviewer?.usage_rows || 0) < 1) reasons.push('reviewer participation/usage is missing');
|
|
446
|
-
return { valid: reasons.length === 0, reasons };
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
export function leadModeExitCode(runsMeta, perVariant) {
|
|
450
|
-
const allValid = ['A', 'B'].every((variant) => runsMeta[variant].length > 0 && runsMeta[variant].every((run) => run.valid));
|
|
451
|
-
const anyUsage = ['A', 'B'].some((variant) => perVariant[variant].some((split) => split.total.usage_rows > 0));
|
|
452
|
-
return allValid && anyUsage ? 0 : 1;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
function median(values) {
|
|
456
|
-
const arr = values.filter((v) => Number.isFinite(v)).sort((a, b) => a - b);
|
|
457
|
-
if (!arr.length) return 0;
|
|
458
|
-
const mid = Math.floor(arr.length / 2);
|
|
459
|
-
return arr.length % 2 ? arr[mid] : (arr[mid - 1] + arr[mid]) / 2;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
function mean(values) {
|
|
463
|
-
const arr = values.filter((v) => Number.isFinite(v));
|
|
464
|
-
return arr.length ? sum(arr) / arr.length : 0;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
function aggregateVariant(splits) {
|
|
468
|
-
const out = { byRole: {}, total: {} };
|
|
469
|
-
for (const role of ROLES) {
|
|
470
|
-
const totals = splits.map((s) => s.byRole[role].total_tokens);
|
|
471
|
-
out.byRole[role] = { median: median(totals), mean: mean(totals), runs: totals };
|
|
472
|
-
}
|
|
473
|
-
const grand = splits.map((s) => s.total.total_tokens);
|
|
474
|
-
out.total = { median: median(grand), mean: mean(grand), runs: grand };
|
|
475
|
-
return out;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// Drives a REAL Lead session in the variant sandbox through the public session
|
|
479
|
-
// runtime, including its deferred standalone tool surface.
|
|
480
|
-
// The variant rule files and public runtime modules take effect through the
|
|
481
|
-
// sandboxed MIXDOG_ROOT.
|
|
482
|
-
export function buildLiveLeadDriver({
|
|
483
|
-
runtimeUrl,
|
|
484
|
-
traceUrl = pathToFileURL(join(PLUGIN_ROOT, 'runtime/agent/orchestrator/agent-trace-io.mjs')).href,
|
|
485
|
-
taskCwd,
|
|
486
|
-
prompt,
|
|
487
|
-
approvalPrompt = DEFAULT_LEAD_APPROVAL_PROMPT,
|
|
488
|
-
provider,
|
|
489
|
-
model,
|
|
490
|
-
effort,
|
|
491
|
-
fast,
|
|
492
|
-
}) {
|
|
493
|
-
return [
|
|
494
|
-
`import { createMixdogSessionRuntime } from ${JSON.stringify(runtimeUrl)};`,
|
|
495
|
-
`import { drainAgentTrace } from ${JSON.stringify(traceUrl)};`,
|
|
496
|
-
`const rt = await createMixdogSessionRuntime({ provider: ${JSON.stringify(provider)}, model: ${JSON.stringify(model)},`,
|
|
497
|
-
` cwd: ${JSON.stringify(taskCwd)}, toolMode: 'full' });`,
|
|
498
|
-
effort ? `await rt.setEffort(${JSON.stringify(effort)});` : '',
|
|
499
|
-
fast !== undefined ? `await rt.setFast(${JSON.stringify(fast)});` : '',
|
|
500
|
-
`const prePromptTools = rt.toolsStatus?.()?.activeTools || [];`,
|
|
501
|
-
`if (!prePromptTools.includes('agent')) throw new Error('Lead runtime agent tool is not active');`,
|
|
502
|
-
`let busy = false; let kickDeferred = false; let wake = null;`,
|
|
503
|
-
`rt.onNotification(() => { queueMicrotask(() => { kickDeferred = true; if (!busy && wake) wake(); }); return false; });`,
|
|
504
|
-
`const askOnce = async (msg) => { busy = true; try { const { result } = await rt.ask(msg); return result; } finally { busy = false; } };`,
|
|
505
|
-
`const agentsBusy = () => { const jobs = rt.agentStatus?.()?.agentJobs || []; return jobs.some((j) => /running|pending|spawn|queued/i.test(String(j?.status || j?.state || ''))); };`,
|
|
506
|
-
`let result; let sessionId = '';`,
|
|
507
|
-
`try {`,
|
|
508
|
-
` await askOnce(${JSON.stringify(prompt)});`,
|
|
509
|
-
` result = await askOnce(${JSON.stringify(approvalPrompt)});`,
|
|
510
|
-
` const deadline = Date.now() + 30 * 60_000;`,
|
|
511
|
-
` while (Date.now() < deadline) {`,
|
|
512
|
-
` if (!kickDeferred) {`,
|
|
513
|
-
` if (!agentsBusy()) break;`,
|
|
514
|
-
` const kicked = await new Promise((resolve) => { wake = () => resolve(true); setTimeout(() => resolve(false), 10_000); });`,
|
|
515
|
-
` wake = null;`,
|
|
516
|
-
` if (!kicked && !kickDeferred && !agentsBusy()) break;`,
|
|
517
|
-
` }`,
|
|
518
|
-
` if (!kickDeferred && !agentsBusy()) break;`,
|
|
519
|
-
` kickDeferred = false; result = (await askOnce('')) || result;`,
|
|
520
|
-
` }`,
|
|
521
|
-
` sessionId = rt.sessionId || rt.id || rt.session?.id || '';`,
|
|
522
|
-
`}`,
|
|
523
|
-
`finally { try { await rt.close('internal-comms-bench-lead'); } catch {} }`,
|
|
524
|
-
`await drainAgentTrace();`,
|
|
525
|
-
`const benchResult = JSON.stringify({ text: String(result?.text || result?.content || '').trim(), sessionId });`,
|
|
526
|
-
`process.stdout.write(${JSON.stringify(CHILD_RESULT_START)} + benchResult + ${JSON.stringify(CHILD_RESULT_END)} + '\\n', () => process.exit(0));`,
|
|
527
|
-
].filter(Boolean).join('\n');
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
export function parseLiveLeadResult(stdout) {
|
|
531
|
-
const source = String(stdout || '');
|
|
532
|
-
const start = source.lastIndexOf(CHILD_RESULT_START);
|
|
533
|
-
if (start < 0) return null;
|
|
534
|
-
const jsonStart = start + CHILD_RESULT_START.length;
|
|
535
|
-
const end = source.indexOf(CHILD_RESULT_END, jsonStart);
|
|
536
|
-
if (end < 0) return null;
|
|
537
|
-
try {
|
|
538
|
-
const result = JSON.parse(source.slice(jsonStart, end));
|
|
539
|
-
return typeof result?.sessionId === 'string' && result.sessionId ? result : null;
|
|
540
|
-
} catch {
|
|
541
|
-
return null;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
export function runLiveLeadDelegation({
|
|
546
|
-
pluginRoot,
|
|
547
|
-
dataDir,
|
|
548
|
-
taskCwd,
|
|
549
|
-
prompt,
|
|
550
|
-
provider,
|
|
551
|
-
model,
|
|
552
|
-
effort,
|
|
553
|
-
fast,
|
|
554
|
-
runtimeUrls = null,
|
|
555
|
-
}) {
|
|
556
|
-
const runtimeUrl = runtimeUrls?.runtimeUrl || pathToFileURL(join(pluginRoot, 'mixdog-session-runtime.mjs')).href;
|
|
557
|
-
const traceUrl = runtimeUrls?.traceUrl || pathToFileURL(join(pluginRoot, 'runtime/agent/orchestrator/agent-trace-io.mjs')).href;
|
|
558
|
-
const driver = buildLiveLeadDriver({
|
|
559
|
-
runtimeUrl,
|
|
560
|
-
traceUrl,
|
|
561
|
-
taskCwd,
|
|
562
|
-
prompt,
|
|
563
|
-
provider,
|
|
564
|
-
model,
|
|
565
|
-
effort,
|
|
566
|
-
fast,
|
|
567
|
-
});
|
|
568
|
-
const started = Date.now();
|
|
569
|
-
const child = spawnSync(process.execPath, ['--input-type=module', '-e', driver], {
|
|
570
|
-
encoding: 'utf8',
|
|
571
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
572
|
-
env: {
|
|
573
|
-
...process.env,
|
|
574
|
-
MIXDOG_ROOT: pluginRoot,
|
|
575
|
-
MIXDOG_DATA_DIR: dataDir,
|
|
576
|
-
},
|
|
577
|
-
});
|
|
578
|
-
const stdout = String(child.stdout || '');
|
|
579
|
-
const stderr = String(child.stderr || '');
|
|
580
|
-
const result = parseLiveLeadResult(stdout);
|
|
581
|
-
return {
|
|
582
|
-
sessionId: result?.sessionId || null,
|
|
583
|
-
ms: Date.now() - started,
|
|
584
|
-
ok: child.status === 0 && !child.error && !!result,
|
|
585
|
-
raw: stdout + stderr,
|
|
586
|
-
stdout,
|
|
587
|
-
stderr,
|
|
588
|
-
exitCode: child.status,
|
|
589
|
-
signal: child.signal || null,
|
|
590
|
-
error: child.error ? String(child.error.message || child.error) : null,
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
function fmtDeltaEntry(entry) {
|
|
595
|
-
const sign = entry.delta >= 0 ? '+' : '';
|
|
596
|
-
const pct = entry.pct == null ? '' : ` (${entry.pct >= 0 ? '+' : ''}${entry.pct.toFixed(1)}%)`;
|
|
597
|
-
return `${sign}${Math.round(entry.delta)}${pct}`;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
function runLeadMode({ route, effort, fast, repeat, jsonMode, leadPrompt }) {
|
|
601
|
-
const realDataDir = defaultUserDataDir();
|
|
602
|
-
const userUnified = readUnifiedConfig(realDataDir);
|
|
603
|
-
const sandboxRoot = mkdtempSync(join(REPO_ROOT, '.tmp-internal-comms-bench-lead-'));
|
|
604
|
-
const perVariant = { A: [], B: [] };
|
|
605
|
-
const runsMeta = { A: [], B: [] };
|
|
606
|
-
let invalidRun = null;
|
|
607
|
-
try {
|
|
608
|
-
const pluginRoots = {
|
|
609
|
-
A: materializePluginRoot('A', sandboxRoot),
|
|
610
|
-
B: materializePluginRoot('B', sandboxRoot),
|
|
611
|
-
};
|
|
612
|
-
runLoop: for (let i = 0; i < repeat; i += 1) {
|
|
613
|
-
for (const variant of ['A', 'B']) {
|
|
614
|
-
const taskCwd = prepareTaskCwd(sandboxRoot);
|
|
615
|
-
const dataDir = prepareDataDir(sandboxRoot, `${variant}-r${i}`, realDataDir, userUnified, route.provider);
|
|
616
|
-
process.stderr.write(`[internal-comms-bench] lead run ${i + 1}/${repeat} variant=${variant} ${route.provider}/${route.model}\n`);
|
|
617
|
-
const run = runLiveLeadDelegation({
|
|
618
|
-
pluginRoot: pluginRoots[variant],
|
|
619
|
-
dataDir,
|
|
620
|
-
taskCwd,
|
|
621
|
-
prompt: leadPrompt,
|
|
622
|
-
provider: route.provider,
|
|
623
|
-
model: route.model,
|
|
624
|
-
effort,
|
|
625
|
-
fast,
|
|
626
|
-
});
|
|
627
|
-
const split = run.sessionId ? splitTokensByRole(dataDir, run.sessionId) : emptyRoleSplit(dataDir);
|
|
628
|
-
const validation = validateLeadRun({ taskCwd, run, split });
|
|
629
|
-
if (validation.valid) perVariant[variant].push(split);
|
|
630
|
-
const meta = {
|
|
631
|
-
ok: run.ok,
|
|
632
|
-
valid: validation.valid,
|
|
633
|
-
reasons: validation.reasons,
|
|
634
|
-
ms: run.ms,
|
|
635
|
-
sessionId: run.sessionId,
|
|
636
|
-
total: split.total.total_tokens,
|
|
637
|
-
diagnostics: {
|
|
638
|
-
stdout: run.stdout,
|
|
639
|
-
stderr: run.stderr,
|
|
640
|
-
exitCode: run.exitCode,
|
|
641
|
-
signal: run.signal,
|
|
642
|
-
error: run.error,
|
|
643
|
-
},
|
|
644
|
-
};
|
|
645
|
-
runsMeta[variant].push(meta);
|
|
646
|
-
process.stderr.write(`[internal-comms-bench] -> ${validation.valid ? 'ok' : 'FAIL'} ${Math.round(run.ms / 1000)}s session=${run.sessionId || '(none)'} total=${split.total.total_tokens} lead=${split.byRole.lead.total_tokens} worker=${split.byRole.worker.total_tokens} reviewer=${split.byRole.reviewer.total_tokens} other=${split.byRole.other.total_tokens}${validation.valid ? '' : ` reasons=${validation.reasons.join('; ')}`}\n`);
|
|
647
|
-
if (!validation.valid && (run.stdout || run.stderr || run.error)) {
|
|
648
|
-
process.stderr.write(`[internal-comms-bench] child diagnostics variant=${variant} stdout=${JSON.stringify(run.stdout)} stderr=${JSON.stringify(run.stderr)} error=${JSON.stringify(run.error)}\n`);
|
|
649
|
-
}
|
|
650
|
-
if (!validation.valid) {
|
|
651
|
-
invalidRun = { variant, index: i, reasons: validation.reasons };
|
|
652
|
-
break runLoop;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
} finally {
|
|
657
|
-
rmSync(sandboxRoot, { recursive: true, force: true });
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
if (invalidRun) {
|
|
661
|
-
process.stderr.write(`[internal-comms-bench] aborting before aggregation: invalid variant=${invalidRun.variant} run=${invalidRun.index + 1} reasons=${invalidRun.reasons.join('; ')}\n`);
|
|
662
|
-
process.exit(1);
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
const aggA = aggregateVariant(perVariant.A);
|
|
667
|
-
const aggB = aggregateVariant(perVariant.B);
|
|
668
|
-
const deltaMedian = {};
|
|
669
|
-
const deltaMean = {};
|
|
670
|
-
for (const role of [...ROLES, 'total']) {
|
|
671
|
-
const aM = role === 'total' ? aggA.total.median : aggA.byRole[role].median;
|
|
672
|
-
const bM = role === 'total' ? aggB.total.median : aggB.byRole[role].median;
|
|
673
|
-
const aAvg = role === 'total' ? aggA.total.mean : aggA.byRole[role].mean;
|
|
674
|
-
const bAvg = role === 'total' ? aggB.total.mean : aggB.byRole[role].mean;
|
|
675
|
-
deltaMedian[role] = { delta: bM - aM, pct: pctChange(bM, aM) };
|
|
676
|
-
deltaMean[role] = { delta: bAvg - aAvg, pct: pctChange(bAvg, aAvg) };
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
if (jsonMode) {
|
|
680
|
-
console.log(JSON.stringify({
|
|
681
|
-
mode: 'lead',
|
|
682
|
-
route,
|
|
683
|
-
repeat,
|
|
684
|
-
prompt: leadPrompt,
|
|
685
|
-
runs: runsMeta,
|
|
686
|
-
variants: { A: { label: 'prior_verbose@HEAD', ...aggA }, B: { label: 'optimized_on_disk', ...aggB } },
|
|
687
|
-
delta_B_vs_A: { median: deltaMedian, mean: deltaMean },
|
|
688
|
-
note: 'single runs are noise-dominated; median+mean over --repeat N reduce run-to-run noise.',
|
|
689
|
-
}, null, 2));
|
|
690
|
-
} else {
|
|
691
|
-
console.log(`lead-mode multi-agent ${route.provider}/${route.model} repeat=${repeat}`);
|
|
692
|
-
console.log('NOTE: single runs are noise-dominated; use --repeat N to stabilize (median+mean shown).');
|
|
693
|
-
for (const [id, agg] of [['A', aggA], ['B', aggB]]) {
|
|
694
|
-
console.log(`variant ${id} (${id === 'A' ? 'prior_verbose@HEAD' : 'optimized_on_disk'}) per-role tokens median/mean over ${repeat} run(s):`);
|
|
695
|
-
for (const role of ROLES) {
|
|
696
|
-
const r = agg.byRole[role];
|
|
697
|
-
console.log(` ${role.padEnd(9)} med=${Math.round(r.median)} mean=${Math.round(r.mean)}`);
|
|
698
|
-
}
|
|
699
|
-
console.log(` ${'total'.padEnd(9)} med=${Math.round(agg.total.median)} mean=${Math.round(agg.total.mean)}`);
|
|
700
|
-
}
|
|
701
|
-
console.log('delta B-vs-A (median): ' + [...ROLES, 'total'].map((r) => `${r}=${fmtDeltaEntry(deltaMedian[r])}`).join(' '));
|
|
702
|
-
console.log('delta B-vs-A (mean): ' + [...ROLES, 'total'].map((r) => `${r}=${fmtDeltaEntry(deltaMean[r])}`).join(' '));
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
process.exit(leadModeExitCode(runsMeta, perVariant));
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
function pctChange(b, a) {
|
|
709
|
-
if (!Number.isFinite(a) || a === 0) return null;
|
|
710
|
-
return ((b - a) / a) * 100;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
function printUsage() {
|
|
714
|
-
process.stdout.write(`internal-comms-bench — live A/B token effect (internal-comms rules).
|
|
715
|
-
|
|
716
|
-
Variant A = prior verbose rules from git: git show HEAD:src/<rule> (fallback: current file).
|
|
717
|
-
Variant B = optimized rules: current on-disk src/ copied to temp PLUGIN_ROOT.
|
|
718
|
-
|
|
719
|
-
Modes:
|
|
720
|
-
--mode worker (default) — single worker task via runHeadlessRole (bench-run child pattern).
|
|
721
|
-
--mode lead — REAL internal-comms flow: a live Lead session is forced to delegate
|
|
722
|
-
one small task to a worker and then a reviewer (via the agent tool).
|
|
723
|
-
Tokens are split BY ROLE (lead/worker/reviewer/other) across the whole
|
|
724
|
-
Lead+children session tree, parsed from the sandbox agent-trace.jsonl.
|
|
725
|
-
|
|
726
|
-
Usage:
|
|
727
|
-
node scripts/internal-comms-bench.mjs [--json]
|
|
728
|
-
node scripts/internal-comms-bench.mjs --run [--model grok] [--provider P] [--effort E] [--fast] [--prompt "..."] [--json]
|
|
729
|
-
node scripts/internal-comms-bench.mjs --run --mode lead [--repeat N] [--model grok] [--provider P] [--effort E] [--fast] [--prompt "..."] [--json]
|
|
730
|
-
|
|
731
|
-
--run required for live model calls. Sandboxes temp PLUGIN_ROOT + MIXDOG_DATA_DIR; copies OAuth JSON read-only from your real data dir.
|
|
732
|
-
--mode lead measures the optimization the worker mode cannot (Lead brief + agent handoff tokens).
|
|
733
|
-
--repeat N (default 1) runs the A/B N times and reports per-role median AND mean; single runs are noise-dominated.
|
|
734
|
-
`);
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
function main() {
|
|
738
|
-
const jsonMode = hasFlag('--json');
|
|
739
|
-
const doRun = hasFlag('--run');
|
|
740
|
-
const mode = String(argValue('--mode', 'worker') || 'worker').trim().toLowerCase();
|
|
741
|
-
const repeat = Math.max(1, Number.parseInt(argValue('--repeat', '1'), 10) || 1);
|
|
742
|
-
const prompt = argValue('--prompt', mode === 'lead' ? DEFAULT_LEAD_PROMPT : DEFAULT_WORKER_PROMPT);
|
|
743
|
-
const cli = resolveModelOpts(argValue('--model', doRun ? 'grok' : null), argValue('--provider', null));
|
|
744
|
-
const effort = argValue('--effort', null);
|
|
745
|
-
const fast = hasFlag('--fast');
|
|
746
|
-
|
|
747
|
-
if (!doRun) {
|
|
748
|
-
printUsage();
|
|
749
|
-
const ruleStats = ruleVariantBytes();
|
|
750
|
-
const aSum = sum(ruleStats.map((r) => r.a_chars));
|
|
751
|
-
const bSum = sum(ruleStats.map((r) => r.b_chars));
|
|
752
|
-
if (jsonMode) {
|
|
753
|
-
console.log(JSON.stringify({
|
|
754
|
-
mode: 'usage',
|
|
755
|
-
run_mode: mode,
|
|
756
|
-
repeat,
|
|
757
|
-
rule_files: RULE_FILES,
|
|
758
|
-
rule_stats: ruleStats,
|
|
759
|
-
rule_chars: { A: aSum, B: bSum },
|
|
760
|
-
liveCommand: 'node scripts/internal-comms-bench.mjs --run --model grok',
|
|
761
|
-
liveLeadCommand: 'node scripts/internal-comms-bench.mjs --run --mode lead --repeat 3 --model grok',
|
|
762
|
-
}, null, 2));
|
|
763
|
-
} else {
|
|
764
|
-
process.stdout.write(`[internal-comms-bench] rule chars A(prior@HEAD)=${aSum} B(on-disk)=${bSum} (${RULE_FILES.length} files); mode=${mode} repeat=${repeat}\n`);
|
|
765
|
-
}
|
|
766
|
-
process.exit(0);
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
const realDataDir = defaultUserDataDir();
|
|
770
|
-
const userUnified = readUnifiedConfig(realDataDir);
|
|
771
|
-
const route = {
|
|
772
|
-
provider: cli.provider || MODEL_ALIASES.grok.provider,
|
|
773
|
-
model: cli.model || MODEL_ALIASES.grok.model,
|
|
774
|
-
};
|
|
775
|
-
|
|
776
|
-
if (mode === 'lead') {
|
|
777
|
-
runLeadMode({ route, effort, fast, repeat, jsonMode, leadPrompt: prompt });
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
const sandboxRoot = mkdtempSync(join(REPO_ROOT, '.tmp-internal-comms-bench-'));
|
|
782
|
-
const results = {};
|
|
783
|
-
try {
|
|
784
|
-
const taskCwd = prepareTaskCwd(sandboxRoot);
|
|
785
|
-
for (const variant of ['A', 'B']) {
|
|
786
|
-
resetTaskCwd(taskCwd);
|
|
787
|
-
const pluginRoot = materializePluginRoot(variant, sandboxRoot);
|
|
788
|
-
const dataDir = prepareDataDir(sandboxRoot, variant, realDataDir, userUnified, route.provider);
|
|
789
|
-
process.stderr.write(`[internal-comms-bench] variant=${variant} ${route.provider}/${route.model}\n`);
|
|
790
|
-
const run = runHeadlessWorker({
|
|
791
|
-
pluginRoot,
|
|
792
|
-
dataDir,
|
|
793
|
-
taskCwd,
|
|
794
|
-
prompt,
|
|
795
|
-
provider: route.provider,
|
|
796
|
-
model: route.model,
|
|
797
|
-
effort,
|
|
798
|
-
fast,
|
|
799
|
-
});
|
|
800
|
-
const usage = run.sessionId
|
|
801
|
-
? sumUsageForSession(dataDir, run.sessionId)
|
|
802
|
-
: {
|
|
803
|
-
session_ids: [],
|
|
804
|
-
prompt_tokens: 0,
|
|
805
|
-
output_tokens: 0,
|
|
806
|
-
cached_tokens: 0,
|
|
807
|
-
usage_rows: 0,
|
|
808
|
-
tracePath: join(dataDir, 'history', 'agent-trace.jsonl'),
|
|
809
|
-
};
|
|
810
|
-
usage.total_tokens = usage.prompt_tokens + usage.output_tokens;
|
|
811
|
-
results[variant] = { ...run, usage };
|
|
812
|
-
process.stderr.write(`[internal-comms-bench] -> ${run.ok ? 'ok' : 'FAIL'} ${Math.round(run.ms / 1000)}s session=${run.sessionId || '(none)'} tokens=${usage.total_tokens}\n`);
|
|
813
|
-
}
|
|
814
|
-
} finally {
|
|
815
|
-
rmSync(sandboxRoot, { recursive: true, force: true });
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
const a = results.A?.usage || {};
|
|
819
|
-
const b = results.B?.usage || {};
|
|
820
|
-
const delta = {
|
|
821
|
-
prompt_tokens: (b.prompt_tokens || 0) - (a.prompt_tokens || 0),
|
|
822
|
-
output_tokens: (b.output_tokens || 0) - (a.output_tokens || 0),
|
|
823
|
-
total_tokens: (b.total_tokens || 0) - (a.total_tokens || 0),
|
|
824
|
-
pct_total_B_vs_A: pctChange(b.total_tokens || 0, a.total_tokens || 0),
|
|
825
|
-
};
|
|
826
|
-
|
|
827
|
-
if (jsonMode) {
|
|
828
|
-
console.log(JSON.stringify({
|
|
829
|
-
mode: 'live',
|
|
830
|
-
route,
|
|
831
|
-
prompt,
|
|
832
|
-
variants: {
|
|
833
|
-
A: { label: 'prior_verbose@HEAD', run: { ok: results.A.ok, ms: results.A.ms, sessionId: results.A.sessionId }, usage: a },
|
|
834
|
-
B: { label: 'optimized_on_disk', run: { ok: results.B.ok, ms: results.B.ms, sessionId: results.B.sessionId }, usage: b },
|
|
835
|
-
},
|
|
836
|
-
delta_B_vs_A: delta,
|
|
837
|
-
}, null, 2));
|
|
838
|
-
} else {
|
|
839
|
-
console.log(`live worker ${route.provider}/${route.model}`);
|
|
840
|
-
for (const id of ['A', 'B']) {
|
|
841
|
-
const u = results[id].usage;
|
|
842
|
-
console.log(`variant ${id}: ${results[id].ok ? 'ok' : 'FAIL'} prompt=${u.prompt_tokens} output=${u.output_tokens} total=${u.total_tokens} sessions=${(u.session_ids || []).length}`);
|
|
843
|
-
}
|
|
844
|
-
const pct = delta.pct_total_B_vs_A;
|
|
845
|
-
const pctStr = pct == null ? 'n/a' : `${pct >= 0 ? '+' : ''}${pct.toFixed(1)}%`;
|
|
846
|
-
console.log(`delta B-vs-A: prompt=${delta.prompt_tokens >= 0 ? '+' : ''}${delta.prompt_tokens} output=${delta.output_tokens >= 0 ? '+' : ''}${delta.output_tokens} total=${delta.total_tokens >= 0 ? '+' : ''}${delta.total_tokens} (${pctStr})`);
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
const ok = results.A?.ok && results.B?.ok && (a.usage_rows > 0 || b.usage_rows > 0);
|
|
850
|
-
process.exit(ok ? 0 : 1);
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) main();
|