@reticlehq/server 2.3.0 → 2.5.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/SKILL.md +702 -0
- package/dist/bridge/auth-failure-reason.d.ts +19 -0
- package/dist/bridge/auth-failure-reason.js +29 -0
- package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
- package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
- package/dist/{bridge.d.ts → bridge/bridge.d.ts} +1 -1
- package/dist/{bridge.js → bridge/bridge.js} +105 -15
- package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +6 -11
- package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +21 -9
- package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
- package/dist/capsule/capsule-store.d.ts +8 -3
- package/dist/capsule/capsule-store.js +7 -2
- package/dist/capsule/capsule.js +3 -3
- package/dist/capsule/causal-summary.d.ts +8 -0
- package/dist/capsule/causal-summary.js +22 -12
- package/dist/capsule/divergence.d.ts +9 -4
- package/dist/capsule/divergence.js +8 -8
- package/dist/capsule/predicate-to-links.js +11 -8
- package/dist/{cli-doctor.js → cli/cli-doctor.js} +9 -2
- package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
- package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
- package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
- package/dist/cli/cli-launch.js +171 -0
- package/dist/cli/cli-parse.d.ts +143 -0
- package/dist/{cli-parse.js → cli/cli-parse.js} +146 -65
- package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +15 -0
- package/dist/{cli-port.js → cli/cli-port.js} +29 -8
- package/dist/cli/cli-update-commands.d.ts +4 -0
- package/dist/cli/cli-update-commands.js +93 -0
- package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
- package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +182 -93
- package/dist/cloud/cloud-config.d.ts +0 -1
- package/dist/cloud/cloud-config.js +9 -9
- package/dist/cloud/cloud-sync.d.ts +1 -7
- package/dist/cloud/cloud-sync.js +12 -12
- package/dist/crawl/crawl-empty.d.ts +16 -0
- package/dist/crawl/crawl-empty.js +24 -0
- package/dist/crawl/crawl-tools.js +4 -1
- package/dist/crawl/crawl.js +26 -7
- package/dist/daemon/daemon-resilience.d.ts +49 -0
- package/dist/daemon/daemon-resilience.js +191 -0
- package/dist/daemon/daemon-usefulness.d.ts +61 -0
- package/dist/daemon/daemon-usefulness.js +62 -0
- package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
- package/dist/{daemon.js → daemon/daemon.js} +80 -48
- package/dist/daemon/idle-grace.d.ts +32 -0
- package/dist/daemon/idle-grace.js +41 -0
- package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +13 -0
- package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +27 -4
- package/dist/domain/domain-model.js +2 -2
- package/dist/events/body-failures.js +8 -8
- package/dist/events/contradictions.d.ts +1 -1
- package/dist/events/contradictions.js +60 -10
- package/dist/events/echo-mismatch.js +10 -10
- package/dist/events/event-filters.js +6 -6
- package/dist/events/json-salvage.d.ts +2 -1
- package/dist/events/json-salvage.js +6 -6
- package/dist/events/observed-in-window.d.ts +12 -0
- package/dist/events/observed-in-window.js +21 -0
- package/dist/events/predicate-eval.d.ts +43 -20
- package/dist/events/predicate-eval.js +159 -55
- package/dist/events/predicate.d.ts +2 -2
- package/dist/events/predicate.js +112 -35
- package/dist/events/reconcile.js +5 -5
- package/dist/events/ring-buffer.js +1 -1
- package/dist/events/stale-response.js +6 -6
- package/dist/events/testid-near-miss.d.ts +22 -0
- package/dist/events/testid-near-miss.js +33 -0
- package/dist/events/unit-mismatch.js +8 -8
- package/dist/flows/affected-tools.js +19 -4
- package/dist/flows/affected.js +1 -1
- package/dist/flows/annotate-target.d.ts +1 -0
- package/dist/flows/annotate-target.js +20 -0
- package/dist/flows/annotate-tools.js +25 -3
- package/dist/flows/annotate.js +17 -4
- package/dist/flows/assertion-integrity.d.ts +2 -1
- package/dist/flows/assertion-tiers-store.d.ts +3 -66
- package/dist/flows/assertion-tiers-store.js +2 -2
- package/dist/flows/attributed-failure.d.ts +17 -0
- package/dist/flows/attributed-failure.js +20 -0
- package/dist/flows/buddy-status.d.ts +2 -1
- package/dist/flows/buddy-status.js +2 -2
- package/dist/flows/coverage.d.ts +3 -2
- package/dist/flows/coverage.js +2 -2
- package/dist/flows/decision.d.ts +0 -6
- package/dist/flows/decision.js +64 -8
- package/dist/flows/empty-flow.d.ts +6 -0
- package/dist/flows/empty-flow.js +24 -0
- package/dist/flows/flake-store.d.ts +0 -1
- package/dist/flows/flake-store.js +1 -1
- package/dist/flows/flake.d.ts +2 -1
- package/dist/flows/flake.js +2 -2
- package/dist/flows/flow-classify.js +12 -0
- package/dist/flows/flow-replay-run.js +4 -4
- package/dist/flows/flow-replay.d.ts +5 -7
- package/dist/flows/flow-replay.js +114 -47
- package/dist/flows/flow-report.js +1 -1
- package/dist/flows/flow-scope.d.ts +1 -6
- package/dist/flows/flow-step-runners.d.ts +26 -6
- package/dist/flows/flow-step-runners.js +157 -6
- package/dist/flows/flow-success.js +20 -15
- package/dist/flows/flow-tools.js +67 -13
- package/dist/flows/flows.js +15 -11
- package/dist/flows/gate.d.ts +4 -3
- package/dist/flows/gate.js +1 -1
- package/dist/flows/heal-run.d.ts +0 -8
- package/dist/flows/heal-run.js +5 -5
- package/dist/flows/heal.js +3 -3
- package/dist/flows/predicate-to-expect.d.ts +38 -0
- package/dist/flows/predicate-to-expect.js +95 -0
- package/dist/flows/replay.d.ts +16 -1
- package/dist/flows/replay.js +58 -22
- package/dist/flows/role-anchor-nearest.d.ts +6 -0
- package/dist/flows/role-anchor-nearest.js +45 -0
- package/dist/flows/server-verify.d.ts +1 -1
- package/dist/flows/server-verify.js +5 -5
- package/dist/flows/verify-change-tools.js +32 -10
- package/dist/flows/verify-change-verdict.d.ts +15 -0
- package/dist/flows/verify-change-verdict.js +25 -0
- package/dist/flows/watch-batcher.d.ts +3 -2
- package/dist/honesty/already-true.d.ts +2 -0
- package/dist/honesty/already-true.js +31 -0
- package/dist/honesty/blind-spots.d.ts +16 -3
- package/dist/honesty/blind-spots.js +24 -12
- package/dist/honesty/honesty.d.ts +3 -2
- package/dist/honesty/honesty.js +4 -4
- package/dist/honesty/uncaptured-bodies.js +1 -1
- package/dist/honesty/unread-outcome.js +2 -2
- package/dist/honesty/verified.d.ts +22 -3
- package/dist/honesty/verified.js +48 -8
- package/dist/http-server.js +14 -7
- package/dist/hunt/hunt-report.d.ts +2 -1
- package/dist/hunt/hunt-report.js +2 -2
- package/dist/index.d.ts +8 -6
- package/dist/index.js +32 -25
- package/dist/init/agent-rules.d.ts +2 -1
- package/dist/init/agent-rules.js +45 -7
- package/dist/init/app-choice.d.ts +20 -0
- package/dist/init/app-choice.js +25 -0
- package/dist/init/astro-host.d.ts +21 -0
- package/dist/init/astro-host.js +27 -0
- package/dist/init/astro-patch.d.ts +16 -0
- package/dist/init/astro-patch.js +240 -0
- package/dist/init/capabilities.d.ts +17 -0
- package/dist/init/capabilities.js +54 -0
- package/dist/init/cra.d.ts +37 -0
- package/dist/init/cra.js +90 -0
- package/dist/init/cursor.js +39 -4
- package/dist/init/desktop-doctor.d.ts +3 -2
- package/dist/init/desktop-doctor.js +4 -4
- package/dist/init/detect.d.ts +26 -0
- package/dist/init/detect.js +78 -5
- package/dist/init/mcp-registered.d.ts +12 -0
- package/dist/init/mcp-registered.js +14 -0
- package/dist/init/mcp.d.ts +27 -2
- package/dist/init/mcp.js +40 -4
- package/dist/init/next-patch.d.ts +39 -0
- package/dist/init/next-patch.js +196 -0
- package/dist/init/node-io.js +48 -6
- package/dist/init/patch-kind.d.ts +20 -0
- package/dist/init/patch-kind.js +10 -0
- package/dist/init/plan-framework.d.ts +50 -0
- package/dist/init/plan-framework.js +341 -0
- package/dist/init/plan.d.ts +119 -6
- package/dist/init/plan.js +230 -131
- package/dist/init/project-id.d.ts +5 -9
- package/dist/init/project-id.js +10 -22
- package/dist/init/run.d.ts +22 -0
- package/dist/init/run.js +393 -28
- package/dist/init/slash-command.d.ts +27 -0
- package/dist/init/slash-command.js +61 -0
- package/dist/init/snippets.d.ts +41 -3
- package/dist/init/snippets.js +185 -10
- package/dist/init/vite-config.d.ts +4 -10
- package/dist/init/vite-config.js +15 -7
- package/dist/init/workspace-apps.d.ts +23 -0
- package/dist/init/workspace-apps.js +68 -0
- package/dist/input/driven-redaction.d.ts +15 -0
- package/dist/input/driven-redaction.js +76 -0
- package/dist/input/network-detail.d.ts +9 -3
- package/dist/input/network-detail.js +43 -23
- package/dist/input/network-mock-tools.js +2 -2
- package/dist/input/network-mock.js +4 -4
- package/dist/input/real-input.js +8 -3
- package/dist/input/scroll-find.js +2 -2
- package/dist/input/scroll-tools.d.ts +0 -5
- package/dist/input/scroll-tools.js +11 -4
- package/dist/input/viewport-tools.js +2 -2
- package/dist/journal/ambient-store.d.ts +0 -2
- package/dist/journal/ambient-store.js +1 -1
- package/dist/journal/ambient.js +1 -1
- package/dist/journal/attach-journal.d.ts +2 -1
- package/dist/journal/deviation-report.js +6 -6
- package/dist/journal/deviation-service.js +1 -1
- package/dist/journal/envelope-store.d.ts +0 -2
- package/dist/journal/envelope-store.js +1 -1
- package/dist/journal/envelope.d.ts +2 -3
- package/dist/journal/envelope.js +3 -3
- package/dist/journal/journal-query.js +1 -1
- package/dist/journal/journal-recorder.d.ts +2 -1
- package/dist/journal/journal-recorder.js +2 -2
- package/dist/journal/rollups.js +9 -9
- package/dist/journal/session-end.d.ts +2 -1
- package/dist/journal/session-journal.js +4 -4
- package/dist/license/license.d.ts +0 -14
- package/dist/license/license.js +8 -8
- package/dist/log.d.ts +10 -0
- package/dist/log.js +11 -1
- package/dist/mcp/mcp-is-error.d.ts +13 -0
- package/dist/mcp/mcp-is-error.js +18 -0
- package/dist/mcp/mcp-outage.d.ts +31 -0
- package/dist/mcp/mcp-outage.js +48 -0
- package/dist/mcp/mcp-proxy.d.ts +124 -0
- package/dist/mcp/mcp-proxy.js +697 -0
- package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
- package/dist/{mcp.js → mcp/mcp.js} +110 -35
- package/dist/mcp/proxy-handshake.d.ts +3 -0
- package/dist/mcp/proxy-handshake.js +54 -0
- package/dist/mcp/proxy-lifecycle.d.ts +64 -0
- package/dist/mcp/proxy-lifecycle.js +70 -0
- package/dist/mcp/tool-catalog-cache.d.ts +29 -0
- package/dist/mcp/tool-catalog-cache.js +55 -0
- package/dist/oracles/propose-consequences.d.ts +2 -1
- package/dist/oracles/propose-consequences.js +16 -11
- package/dist/oracles/self-instrument.d.ts +2 -1
- package/dist/oracles/self-instrument.js +1 -1
- package/dist/phenomena/phenomena.js +3 -3
- package/dist/platform.d.ts +16 -0
- package/dist/platform.js +16 -0
- package/dist/pool/playwright-launcher.d.ts +15 -2
- package/dist/pool/playwright-launcher.js +21 -2
- package/dist/project/fs-port.js +1 -1
- package/dist/project/project-tools.js +2 -2
- package/dist/runs/build-verification-run.js +1 -1
- package/dist/runs/repair-prompt.d.ts +0 -6
- package/dist/runs/repair-prompt.js +3 -3
- package/dist/runs/risk-classify.js +1 -1
- package/dist/runs/run-diff.d.ts +0 -2
- package/dist/runs/run-diff.js +3 -3
- package/dist/runs/run-tools.js +2 -2
- package/dist/runs/verification-sync.js +2 -2
- package/dist/runs/verify-http.js +1 -1
- package/dist/runs/verify-server.js +1 -1
- package/dist/session/command-timeout.d.ts +11 -3
- package/dist/session/command-timeout.js +2 -2
- package/dist/session/control-envelope.d.ts +6 -0
- package/dist/session/control-envelope.js +7 -1
- package/dist/session/dev-server-probe.d.ts +13 -0
- package/dist/session/dev-server-probe.js +52 -0
- package/dist/session/last-act.d.ts +17 -3
- package/dist/session/last-act.js +16 -4
- package/dist/session/live-control-tools.js +7 -2
- package/dist/session/live-control.js +1 -1
- package/dist/session/looks-like-dev-server.d.ts +14 -0
- package/dist/session/looks-like-dev-server.js +25 -0
- package/dist/session/no-session-diagnosis.d.ts +38 -0
- package/dist/session/no-session-diagnosis.js +70 -0
- package/dist/session/no-session-watch.d.ts +19 -0
- package/dist/session/no-session-watch.js +61 -0
- package/dist/session/observed-state.d.ts +4 -0
- package/dist/session/observed-state.js +19 -1
- package/dist/session/output-budget.js +1 -1
- package/dist/session/session-health.d.ts +8 -1
- package/dist/session/session-health.js +8 -7
- package/dist/session/session-info.d.ts +26 -7
- package/dist/session/session-info.js +42 -1
- package/dist/session/session-lease.d.ts +0 -11
- package/dist/session/session-lease.js +1 -1
- package/dist/session/session-manager.d.ts +3 -0
- package/dist/session/session-manager.js +58 -9
- package/dist/session/session-readiness.d.ts +1 -1
- package/dist/session/session-readiness.js +6 -1
- package/dist/session/session-reaper.js +1 -1
- package/dist/session/session-reconnect.d.ts +32 -0
- package/dist/session/session-reconnect.js +42 -0
- package/dist/session/session.d.ts +20 -2
- package/dist/session/session.js +76 -26
- package/dist/session/state-select.d.ts +1 -1
- package/dist/session/state-select.js +1 -1
- package/dist/status-payload.d.ts +19 -0
- package/dist/status-payload.js +11 -0
- package/dist/telemetry/argument-shape.js +10 -1
- package/dist/telemetry/browser-mode.d.ts +27 -0
- package/dist/telemetry/browser-mode.js +33 -0
- package/dist/telemetry/bug-found.d.ts +17 -21
- package/dist/telemetry/bug-found.js +120 -8
- package/dist/telemetry/cli-telemetry.d.ts +2 -12
- package/dist/telemetry/cli-telemetry.js +27 -4
- package/dist/telemetry/daemon-telemetry.d.ts +19 -0
- package/dist/telemetry/daemon-telemetry.js +12 -2
- package/dist/telemetry/dev-repo.js +4 -4
- package/dist/telemetry/error-fingerprint.js +21 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +4 -4
- package/dist/telemetry/feedback-context.d.ts +22 -0
- package/dist/telemetry/feedback-context.js +41 -1
- package/dist/telemetry/feedback-delivery.d.ts +20 -0
- package/dist/telemetry/feedback-delivery.js +30 -0
- package/dist/telemetry/feedback-outbox.d.ts +22 -0
- package/dist/telemetry/feedback-outbox.js +87 -0
- package/dist/telemetry/feedback.d.ts +22 -1
- package/dist/telemetry/feedback.js +67 -8
- package/dist/telemetry/git-facts.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +2 -0
- package/dist/telemetry/session-metrics.js +68 -6
- package/dist/telemetry/telemetry.d.ts +27 -2
- package/dist/telemetry/telemetry.js +119 -29
- package/dist/telemetry/verification-of.d.ts +22 -0
- package/dist/telemetry/verification-of.js +84 -0
- package/dist/tools/act-capsule.js +2 -2
- package/dist/tools/act-danger.d.ts +12 -0
- package/dist/tools/act-danger.js +20 -3
- package/dist/tools/act-helpers.js +4 -4
- package/dist/tools/act-tools.d.ts +0 -8
- package/dist/tools/act-tools.js +84 -115
- package/dist/tools/act-view.js +7 -7
- package/dist/tools/alias-args.d.ts +17 -0
- package/dist/tools/alias-args.js +25 -0
- package/dist/tools/assert-grade.js +9 -9
- package/dist/tools/assert-verdict.d.ts +3 -1
- package/dist/tools/assert-verdict.js +8 -5
- package/dist/tools/browser-tools.js +30 -11
- package/dist/tools/contract-tools.js +1 -1
- package/dist/tools/coverage-identity.d.ts +34 -0
- package/dist/tools/coverage-identity.js +46 -0
- package/dist/tools/coverage-tools.js +10 -14
- package/dist/tools/dynamic-tools.d.ts +2 -1
- package/dist/tools/dynamic-tools.js +90 -18
- package/dist/tools/error-recovery.d.ts +20 -2
- package/dist/tools/error-recovery.js +179 -4
- package/dist/tools/feedback-tools.d.ts +12 -1
- package/dist/tools/feedback-tools.js +28 -5
- package/dist/tools/invoke-tool.d.ts +0 -6
- package/dist/tools/invoke-tool.js +57 -32
- package/dist/tools/lease-hint.d.ts +17 -0
- package/dist/tools/lease-hint.js +24 -0
- package/dist/tools/lease-tools.js +6 -5
- package/dist/tools/merge-tools.d.ts +10 -1
- package/dist/tools/merge-tools.js +9 -3
- package/dist/tools/merged-name-redirect.d.ts +13 -0
- package/dist/tools/merged-name-redirect.js +55 -0
- package/dist/tools/navigate-result.d.ts +17 -0
- package/dist/tools/navigate-result.js +31 -0
- package/dist/tools/observe-tools.js +54 -20
- package/dist/tools/observed-nothing.d.ts +25 -0
- package/dist/tools/observed-nothing.js +33 -0
- package/dist/tools/query-paginate.js +2 -2
- package/dist/tools/query-shape.d.ts +18 -0
- package/dist/tools/query-shape.js +39 -0
- package/dist/tools/read-tools.js +85 -20
- package/dist/tools/real-input-attempt.d.ts +28 -0
- package/dist/tools/real-input-attempt.js +88 -0
- package/dist/tools/reconcile-tools.js +7 -7
- package/dist/tools/reload-result.d.ts +14 -0
- package/dist/tools/reload-result.js +29 -0
- package/dist/tools/snapshot-delta.d.ts +4 -5
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/tool-kit.d.ts +8 -0
- package/dist/tools/tool-surface.d.ts +83 -0
- package/dist/tools/tool-surface.js +204 -0
- package/dist/tools/tools-helpers.js +6 -6
- package/dist/tools/tools.d.ts +15 -0
- package/dist/tools/tools.js +53 -17
- package/dist/tools/unadvertised-help.d.ts +5 -0
- package/dist/tools/unadvertised-help.js +39 -0
- package/dist/trace.d.ts +69 -0
- package/dist/trace.js +150 -0
- package/dist/update/nudge-credit.d.ts +4 -0
- package/dist/update/nudge-credit.js +53 -0
- package/dist/update/sdk-sync.d.ts +21 -0
- package/dist/update/sdk-sync.js +42 -0
- package/dist/update/update-checker.js +3 -3
- package/dist/update/update-nudge.d.ts +63 -6
- package/dist/update/update-nudge.js +128 -15
- package/dist/update/updater.d.ts +1 -9
- package/dist/update/updater.js +13 -8
- package/dist/version/peer-announce.d.ts +4 -0
- package/dist/version/peer-announce.js +30 -0
- package/dist/{server-version.js → version/server-version.js} +5 -1
- package/dist/version/version-nudge.d.ts +28 -0
- package/dist/version/version-nudge.js +40 -0
- package/dist/version/version-skew.d.ts +66 -0
- package/dist/version/version-skew.js +71 -0
- package/dist/visual/visual-diff.js +2 -2
- package/dist/visual/visual-tools.js +4 -4
- package/docs/agent-cheatsheet.md +85 -0
- package/docs/architecture.md +113 -0
- package/docs/benchmarks.md +255 -0
- package/docs/debugging.md +102 -0
- package/docs/deploy-checks.md +69 -0
- package/docs/desktop-apps.md +256 -0
- package/docs/enterprise.md +62 -0
- package/docs/fixtures.md +28 -0
- package/docs/flows.md +166 -0
- package/docs/getting-started.md +469 -0
- package/docs/human-control.md +63 -0
- package/docs/integration-patterns.md +171 -0
- package/docs/local-registry.md +126 -0
- package/docs/mint.json +61 -0
- package/docs/multi-agent-testing.md +55 -0
- package/docs/platform-integration.md +122 -0
- package/docs/telemetry-contract.md +214 -0
- package/docs/telemetry.md +184 -0
- package/docs/testing.md +82 -0
- package/docs/token-efficiency.md +80 -0
- package/docs/usage.md +1046 -0
- package/package.json +8 -5
- package/dist/cli-launch.js +0 -112
- package/dist/cli-parse.d.ts +0 -140
- package/dist/daemon-resilience.d.ts +0 -22
- package/dist/daemon-resilience.js +0 -85
- package/dist/mcp-proxy.d.ts +0 -35
- package/dist/mcp-proxy.js +0 -190
- package/dist/tools/profiles.d.ts +0 -37
- package/dist/tools/profiles.js +0 -139
- /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
- /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
- /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
- /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
- /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
- /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
- /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The native-input attempt — everything that decides whether a pointer action is driven through a
|
|
3
|
+
* real input provider or falls back to the occlusion-honest synthetic path, and WHY.
|
|
4
|
+
*
|
|
5
|
+
* Split out of act-tools.ts along its natural seam: the act tools care only about the outcome
|
|
6
|
+
* (`result` defined = it went native), never about provider availability, box resolution,
|
|
7
|
+
* drag-target inspection or the reason taxonomy.
|
|
8
|
+
*/
|
|
9
|
+
import { ActionType, InputModeReason, ReticleCommand } from '@reticlehq/core';
|
|
10
|
+
import { isPointerAction } from '../input/real-input.js';
|
|
11
|
+
import { assertDragNotDestructive, assertNotDestructive } from './act-danger.js';
|
|
12
|
+
import { NATIVE_INPUT_ARG } from '@reticlehq/core';
|
|
13
|
+
import { asString, asRecord } from './tools-helpers.js';
|
|
14
|
+
import { commandOrThrow } from './tool-kit.js';
|
|
15
|
+
import { asBox } from './act-helpers.js';
|
|
16
|
+
/** Synthetic outcome with a diagnostic reason (provider configured but native input skipped). */
|
|
17
|
+
function synthetic(reason) {
|
|
18
|
+
return reason === undefined
|
|
19
|
+
? { result: undefined, settled: false }
|
|
20
|
+
: { result: undefined, settled: false, reason };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Attempt to drive a pointer action via native input. Returns a synthetic outcome (with a
|
|
24
|
+
* `reason` when a provider is configured) whenever the synthetic path should run — no matching
|
|
25
|
+
* page, unresolvable box, declined, etc. A throw inside the provider becomes a synthetic fallback
|
|
26
|
+
* flagged with `fellBack`. `result` is defined only on a real success.
|
|
27
|
+
*/
|
|
28
|
+
export async function tryRealInput(deps, session, ref, action, args) {
|
|
29
|
+
const provider = deps.realInput;
|
|
30
|
+
if (provider === undefined)
|
|
31
|
+
return synthetic(); // real input not configured — no diagnostic
|
|
32
|
+
if (!isPointerAction(action))
|
|
33
|
+
return synthetic(InputModeReason.NOT_POINTER); // fill/type stay synthetic
|
|
34
|
+
const inner = asRecord(args['args']);
|
|
35
|
+
// "Don't click, run the code": a click/dblclick runs the occlusion-honest SYNTHETIC path by default
|
|
36
|
+
// even with a provider configured — no coordinate gesture to be intercepted by the HUD or missed
|
|
37
|
+
// off-screen. Opt into a trusted native click with args.native:true (file pickers, clipboard,
|
|
38
|
+
// isTrusted-gated handlers). hover/drag genuinely need native pointer state, so they stay real.
|
|
39
|
+
if ((action === ActionType.CLICK || action === ActionType.DBLCLICK) &&
|
|
40
|
+
inner[NATIVE_INPUT_ARG] !== true) {
|
|
41
|
+
return synthetic(InputModeReason.SYNTHETIC_CLICK_PREFERRED);
|
|
42
|
+
}
|
|
43
|
+
if (!(await provider.isAvailableFor(session.url)))
|
|
44
|
+
return synthetic(InputModeReason.PAGE_NOT_CORRELATED);
|
|
45
|
+
const inspected = await commandOrThrow(deps, session.id, ReticleCommand.INSPECT, { ref });
|
|
46
|
+
assertNotDestructive(action, inner, inspected);
|
|
47
|
+
const box = asBox(inspected);
|
|
48
|
+
if (box === undefined)
|
|
49
|
+
return synthetic(InputModeReason.ELEMENT_NOT_LOCATABLE);
|
|
50
|
+
let toBox;
|
|
51
|
+
if (action === ActionType.DRAG) {
|
|
52
|
+
const toRef = asString(inner['toRef']);
|
|
53
|
+
if (toRef === undefined)
|
|
54
|
+
return synthetic(InputModeReason.DRAG_TARGET_UNRESOLVED);
|
|
55
|
+
const targetInspected = await commandOrThrow(deps, session.id, ReticleCommand.INSPECT, {
|
|
56
|
+
ref: toRef,
|
|
57
|
+
});
|
|
58
|
+
// A drag is judged on BOTH ends: dropping onto "Trash" is destructive however innocent the
|
|
59
|
+
// thing being dragged looks.
|
|
60
|
+
assertDragNotDestructive(inner, inspected, targetInspected);
|
|
61
|
+
toBox = asBox(targetInspected);
|
|
62
|
+
if (toBox === undefined)
|
|
63
|
+
return synthetic(InputModeReason.DRAG_TARGET_UNRESOLVED);
|
|
64
|
+
}
|
|
65
|
+
const performArgs = {};
|
|
66
|
+
const value = asString(inner['value']);
|
|
67
|
+
if (value !== undefined)
|
|
68
|
+
performArgs.value = value;
|
|
69
|
+
const text = asString(inner['text']);
|
|
70
|
+
if (text !== undefined)
|
|
71
|
+
performArgs.text = text;
|
|
72
|
+
if (toBox !== undefined)
|
|
73
|
+
performArgs.toBox = toBox;
|
|
74
|
+
try {
|
|
75
|
+
const performed = await provider.perform(session.url, action, box, performArgs);
|
|
76
|
+
if (!performed.performed)
|
|
77
|
+
return synthetic(InputModeReason.PROVIDER_DECLINED);
|
|
78
|
+
return { result: { performed: true, center: performed.center, action }, settled: true };
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return {
|
|
82
|
+
result: undefined,
|
|
83
|
+
settled: false,
|
|
84
|
+
fellBack: true,
|
|
85
|
+
reason: InputModeReason.PROVIDER_ERROR,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -28,17 +28,17 @@ async function capturedBodies(session, since, urlContains) {
|
|
|
28
28
|
for (const event of events) {
|
|
29
29
|
if (event.type !== EventType.NET_REQUEST)
|
|
30
30
|
continue;
|
|
31
|
-
const url = typeof event.data['url']
|
|
31
|
+
const url = 'string' === typeof event.data['url'] ? event.data['url'] : '';
|
|
32
32
|
if (urlContains !== undefined && !url.includes(urlContains))
|
|
33
33
|
continue;
|
|
34
34
|
total += 1;
|
|
35
35
|
const raw = event.data['responseBody'];
|
|
36
|
-
if (typeof raw !== 'string' || raw.length
|
|
36
|
+
if (typeof raw !== 'string' || 0 === raw.length)
|
|
37
37
|
continue;
|
|
38
38
|
// A capped body is not an absent one. Recover the records that closed before the cut rather than
|
|
39
39
|
// reporting nothing about the page with the most data on it.
|
|
40
40
|
const salvaged = salvageJson(raw);
|
|
41
|
-
if (salvaged.values.length
|
|
41
|
+
if (0 === salvaged.values.length)
|
|
42
42
|
continue;
|
|
43
43
|
bodies.push(...salvaged.values);
|
|
44
44
|
withBody += 1;
|
|
@@ -79,11 +79,11 @@ export const RECONCILE_TOOLS = [
|
|
|
79
79
|
const { bodies, withBody, total, truncated } = await capturedBodies(session, since, asString(args['urlContains']));
|
|
80
80
|
// An empty result over data that was never read is the exact false green this tool exists to
|
|
81
81
|
// prevent, so the two cases are reported differently and neither is silent.
|
|
82
|
-
if (bodies.length
|
|
82
|
+
if (0 === bodies.length) {
|
|
83
83
|
return withControl(session, {
|
|
84
84
|
mismatches: [],
|
|
85
85
|
compared: 0,
|
|
86
|
-
note:
|
|
86
|
+
note: 0 === total
|
|
87
87
|
? 'no responses in this window matched — nothing was compared'
|
|
88
88
|
: `${String(total)} response(s) matched but NONE carried a recorded body, so nothing was compared. Enable it where your app calls connect(): \`reticle.connect({ captureNetworkBodies: true })\`, then re-run`,
|
|
89
89
|
});
|
|
@@ -92,7 +92,7 @@ export const RECONCILE_TOOLS = [
|
|
|
92
92
|
mode: SnapshotMode.FULL,
|
|
93
93
|
});
|
|
94
94
|
const tree = snapshot.tree;
|
|
95
|
-
const mismatches = reconcile(bodies, typeof tree
|
|
95
|
+
const mismatches = reconcile(bodies, 'string' === typeof tree ? tree : '');
|
|
96
96
|
// A truncated body is declared whether or not anything was found in it: "no mismatches" over a
|
|
97
97
|
// partially-read payload is a weaker statement than over a whole one, and the difference is
|
|
98
98
|
// exactly the kind of omission this layer exists to refuse.
|
|
@@ -100,7 +100,7 @@ export const RECONCILE_TOOLS = [
|
|
|
100
100
|
? {
|
|
101
101
|
note: `${String(truncated)} of ${String(withBody)} response(s) exceeded the body cap and were read only up to the cut — records after it were not compared`,
|
|
102
102
|
}
|
|
103
|
-
: mismatches.length
|
|
103
|
+
: 0 === mismatches.length
|
|
104
104
|
? {
|
|
105
105
|
note: `compared ${String(withBody)} response(s); nothing on screen contradicts them`,
|
|
106
106
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `navigate { reload: true }` reports.
|
|
3
|
+
*
|
|
4
|
+
* It answered a bare `{ ok: true }`, while the URL branch of the same tool returns `confirmed: false`
|
|
5
|
+
* plus a note — because `ok` means the browser accepted the instruction, not that the page arrived.
|
|
6
|
+
* Identical semantics, one branch disclosing them and one not, and the silent one is the path most
|
|
7
|
+
* likely to need the caveat: a reload tears the SDK down, and a caller that acts on `ok: true` hits
|
|
8
|
+
* the window before it comes back.
|
|
9
|
+
*
|
|
10
|
+
* The permanent session loss reported alongside this is fixed separately — session-continuity.ts
|
|
11
|
+
* remembers the id in sessionStorage so a reload rejoins the SAME session instead of appearing as a
|
|
12
|
+
* new one. This is the remaining half: saying that the page is not back yet.
|
|
13
|
+
*/
|
|
14
|
+
export declare function reloadResult(reconnected?: boolean): Record<string, unknown>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `navigate { reload: true }` reports.
|
|
3
|
+
*
|
|
4
|
+
* It answered a bare `{ ok: true }`, while the URL branch of the same tool returns `confirmed: false`
|
|
5
|
+
* plus a note — because `ok` means the browser accepted the instruction, not that the page arrived.
|
|
6
|
+
* Identical semantics, one branch disclosing them and one not, and the silent one is the path most
|
|
7
|
+
* likely to need the caveat: a reload tears the SDK down, and a caller that acts on `ok: true` hits
|
|
8
|
+
* the window before it comes back.
|
|
9
|
+
*
|
|
10
|
+
* The permanent session loss reported alongside this is fixed separately — session-continuity.ts
|
|
11
|
+
* remembers the id in sessionStorage so a reload rejoins the SAME session instead of appearing as a
|
|
12
|
+
* new one. This is the remaining half: saying that the page is not back yet.
|
|
13
|
+
*/
|
|
14
|
+
/** The reload's own disclosure — the same shape and the same advice the URL branch gives. */
|
|
15
|
+
const RELOAD_NOTE = 'ok means the reload was DISPATCHED, not that the page came back — the SDK is torn down by the ' +
|
|
16
|
+
'reload itself, so nothing here can see the new document yet. Call reticle_sessions to confirm ' +
|
|
17
|
+
'the session reconnected before acting; the session id is preserved across a reload, so it will ' +
|
|
18
|
+
'be the same one.';
|
|
19
|
+
/**
|
|
20
|
+
* What a CONFIRMED reload says. The page re-announced itself under the same id before this returned,
|
|
21
|
+
* so the next call is safe — which is the whole reason the tool now waits instead of advising.
|
|
22
|
+
*/
|
|
23
|
+
const RELOAD_RECONNECTED_NOTE = 'the page came back and re-announced itself under the same session id, so this session is live ' +
|
|
24
|
+
'again — no re-selection needed. Anything captured before the reload is gone with the old document.';
|
|
25
|
+
export function reloadResult(reconnected = false) {
|
|
26
|
+
return reconnected
|
|
27
|
+
? { ok: true, confirmed: true, note: RELOAD_RECONNECTED_NOTE }
|
|
28
|
+
: { ok: true, confirmed: false, note: RELOAD_NOTE };
|
|
29
|
+
}
|
|
@@ -18,13 +18,13 @@ export declare const SnapshotDeltaMode: {
|
|
|
18
18
|
readonly UNCHANGED: "unchanged";
|
|
19
19
|
};
|
|
20
20
|
export type SnapshotDeltaMode = (typeof SnapshotDeltaMode)[keyof typeof SnapshotDeltaMode];
|
|
21
|
-
|
|
21
|
+
interface SnapshotDelta {
|
|
22
22
|
added: string[];
|
|
23
23
|
removed: string[];
|
|
24
24
|
addedCount: number;
|
|
25
25
|
removedCount: number;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
type DeltaDecision = {
|
|
28
28
|
mode: typeof SnapshotDeltaMode.FULL;
|
|
29
29
|
} | {
|
|
30
30
|
mode: typeof SnapshotDeltaMode.UNCHANGED;
|
|
@@ -43,9 +43,7 @@ export declare class SnapshotCache {
|
|
|
43
43
|
remember(key: string, route: string, tree: string): void;
|
|
44
44
|
}
|
|
45
45
|
export declare function snapshotCacheKey(sessionId: string, scope: string, mode: string): string;
|
|
46
|
-
|
|
47
|
-
export declare const CAPPED_DIFF_NOTE = "this diff covers only the first N nodes of the page (the snapshot hit its cap), so \"unchanged\" means \"unchanged in the part that was captured\" \u2014 narrow with `scope` to see the rest";
|
|
48
|
-
export interface SnapshotDeltaOpts {
|
|
46
|
+
interface SnapshotDeltaOpts {
|
|
49
47
|
sessionId: string;
|
|
50
48
|
scope: string;
|
|
51
49
|
mode: string;
|
|
@@ -58,3 +56,4 @@ export interface SnapshotDeltaOpts {
|
|
|
58
56
|
* the pure `snapshotDelta`.
|
|
59
57
|
*/
|
|
60
58
|
export declare function applySnapshotDelta(raw: unknown, opts: SnapshotDeltaOpts, cache: SnapshotCache): unknown;
|
|
59
|
+
export {};
|
|
Binary file
|
package/dist/tools/tool-kit.d.ts
CHANGED
|
@@ -35,6 +35,14 @@ export interface ToolDeps {
|
|
|
35
35
|
reticleRoot: string;
|
|
36
36
|
/** injected clock for the contract's generatedAt stamp. */
|
|
37
37
|
now: () => number;
|
|
38
|
+
/**
|
|
39
|
+
* The port this daemon's bridge listens on.
|
|
40
|
+
*
|
|
41
|
+
* Needed wherever a message has to name the OTHER half of a port mismatch — the commonest reason
|
|
42
|
+
* a leased tab loads the app and never dials in. Optional so every existing test construction of
|
|
43
|
+
* ToolDeps keeps working; absent falls back to the default port.
|
|
44
|
+
*/
|
|
45
|
+
bridgePort?: number;
|
|
38
46
|
}
|
|
39
47
|
export interface ToolDef {
|
|
40
48
|
name: string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ToolDef } from './tools.js';
|
|
2
|
+
/**
|
|
3
|
+
* There is ONE tool surface. This is not a menu.
|
|
4
|
+
*
|
|
5
|
+
* The advertised tool DEFINITIONS are re-sent to the model on every turn, so the surface is a
|
|
6
|
+
* per-turn cost that compounds across a loop, and fewer tools also makes the model wander less.
|
|
7
|
+
* What ships is the verify loop (navigate→look→act→observe→assert, with direct network + console +
|
|
8
|
+
* state) advertised directly, plus two meta-tools — `reticle_tools` to discover and `reticle_run` to
|
|
9
|
+
* invoke — that keep every other tool exactly one call away. Nothing is unreachable; the cold tail
|
|
10
|
+
* just is not re-sent every turn.
|
|
11
|
+
*
|
|
12
|
+
* Five profiles were tried. Four are gone, each for a measured reason rather than a taste:
|
|
13
|
+
*
|
|
14
|
+
* `core` was BYTE-IDENTICAL to the default — 16 tools, 18,183 bytes, the same list. One behaviour
|
|
15
|
+
* behind two names is how "I set it and nothing changed" becomes a support question with no answer.
|
|
16
|
+
*
|
|
17
|
+
* `standard` advertised 17 more tools directly for ~3,500 extra tokens EVERY TURN, buying only the
|
|
18
|
+
* removal of an occasional `reticle_run` hop. Nothing about that was characterisable as a use case.
|
|
19
|
+
*
|
|
20
|
+
* `dynamic` advertised the 2 meta-tools and nothing else. Not one harness, app or bench ever
|
|
21
|
+
* selected it, and this repo's own measurement (bench/agent-loop-and-replay.md) says a pure
|
|
22
|
+
* on-demand surface does NOT hold accuracy with a generic model: "it needs the hot-set schemas.
|
|
23
|
+
* On-demand is for the cold tail, not the hot path." An option that is unused and measured-worse is
|
|
24
|
+
* a trap, not a choice — it looks like a 4,000-token saving and costs correctness.
|
|
25
|
+
*
|
|
26
|
+
* ALL is what remains, and it is deliberately NOT a profile: it is a verification switch. It is the
|
|
27
|
+
* only mode that advertises `outputSchema`, which is what makes the MCP layer validate tool OUTPUT —
|
|
28
|
+
* the check that caught `reticle_verify_change` returning a payload its own schema rejected. It
|
|
29
|
+
* cannot be folded into the default: measured, carrying output schemas on the 16-tool surface costs
|
|
30
|
+
* 18,183 -> 41,117 bytes, 2.26x, +5,733 tokens per turn. And it cannot simply be deleted without
|
|
31
|
+
* losing that defect class. So it stays, named for what it is, and no user is asked to pick it.
|
|
32
|
+
*
|
|
33
|
+
* Sizes are NOT restated here — not as a current figure, not as a historical one. Four generations
|
|
34
|
+
* of this comment got them wrong. They live in surface-sizes.test.ts, which reads them off the real
|
|
35
|
+
* surface. (The numbers above are the two measurements that JUSTIFY a decision, which is a different
|
|
36
|
+
* job from documenting the current size; both were taken with a fresh daemon per reading.)
|
|
37
|
+
*/
|
|
38
|
+
export declare const TOOL_SURFACE: {
|
|
39
|
+
/** What every user gets: the verify loop, plus the 2 meta-tools that reach everything else. */
|
|
40
|
+
readonly DEFAULT: "default";
|
|
41
|
+
/** Every tool advertised directly, WITH output schemas. A verification switch — see above. */
|
|
42
|
+
readonly ALL: "all";
|
|
43
|
+
};
|
|
44
|
+
export type ToolSurface = (typeof TOOL_SURFACE)[keyof typeof TOOL_SURFACE];
|
|
45
|
+
/**
|
|
46
|
+
* The switch that turns on the full, output-schema-carrying surface. A boolean, not a menu.
|
|
47
|
+
*
|
|
48
|
+
* Named for what it does rather than which "profile" it selects, because the previous name invited
|
|
49
|
+
* users to shop among alternatives that did not meaningfully differ.
|
|
50
|
+
*/
|
|
51
|
+
export declare const ADVERTISE_ALL_ENV = "RETICLE_ADVERTISE_ALL_TOOLS";
|
|
52
|
+
/**
|
|
53
|
+
* The retired setting, still read so nobody's shell profile breaks.
|
|
54
|
+
*
|
|
55
|
+
* Every value it ever accepted resolves to something sensible: `full` to the ALL surface, everything
|
|
56
|
+
* else to the default. Silently honouring them would repeat the original sin, so `describeToolSurface`
|
|
57
|
+
* says the setting retired and what was used instead.
|
|
58
|
+
*/
|
|
59
|
+
export declare const TOOL_PROFILE_ENV = "RETICLE_TOOL_PROFILE";
|
|
60
|
+
export declare const CORE_TOOL_NAMES: ReadonlySet<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Which surface is live.
|
|
63
|
+
*
|
|
64
|
+
* `explicit` is the programmatic override (tests, `advertisedTools` callers). Otherwise the ALL
|
|
65
|
+
* switch decides, and the retired setting is honoured last so an old shell profile still works.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveToolSurface(explicit?: string): ToolSurface;
|
|
68
|
+
/** The live surface plus what chose it — see describeToolSurface. */
|
|
69
|
+
export interface ToolSurfaceOrigin {
|
|
70
|
+
active: ToolSurface;
|
|
71
|
+
source: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Which surface is live, and what chose it.
|
|
75
|
+
*
|
|
76
|
+
* These settings are read by the DAEMON at startup, never by the client, so exporting one in an
|
|
77
|
+
* agent's environment while a daemon is already running changes nothing at all — which is exactly
|
|
78
|
+
* the observation that produced a "standard and full advertise the same tools" report. Documenting
|
|
79
|
+
* that was not enough; the setting failing to take has to be VISIBLE, so this rides along in the
|
|
80
|
+
* reticle_tools catalog.
|
|
81
|
+
*/
|
|
82
|
+
export declare function describeToolSurface(active: ToolSurface, requested?: string): ToolSurfaceOrigin;
|
|
83
|
+
export declare function filterTools(tools: ToolDef[], surface: ToolSurface): ToolDef[];
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { ReticleTool } from './tool-names.js';
|
|
2
|
+
/**
|
|
3
|
+
* There is ONE tool surface. This is not a menu.
|
|
4
|
+
*
|
|
5
|
+
* The advertised tool DEFINITIONS are re-sent to the model on every turn, so the surface is a
|
|
6
|
+
* per-turn cost that compounds across a loop, and fewer tools also makes the model wander less.
|
|
7
|
+
* What ships is the verify loop (navigate→look→act→observe→assert, with direct network + console +
|
|
8
|
+
* state) advertised directly, plus two meta-tools — `reticle_tools` to discover and `reticle_run` to
|
|
9
|
+
* invoke — that keep every other tool exactly one call away. Nothing is unreachable; the cold tail
|
|
10
|
+
* just is not re-sent every turn.
|
|
11
|
+
*
|
|
12
|
+
* Five profiles were tried. Four are gone, each for a measured reason rather than a taste:
|
|
13
|
+
*
|
|
14
|
+
* `core` was BYTE-IDENTICAL to the default — 16 tools, 18,183 bytes, the same list. One behaviour
|
|
15
|
+
* behind two names is how "I set it and nothing changed" becomes a support question with no answer.
|
|
16
|
+
*
|
|
17
|
+
* `standard` advertised 17 more tools directly for ~3,500 extra tokens EVERY TURN, buying only the
|
|
18
|
+
* removal of an occasional `reticle_run` hop. Nothing about that was characterisable as a use case.
|
|
19
|
+
*
|
|
20
|
+
* `dynamic` advertised the 2 meta-tools and nothing else. Not one harness, app or bench ever
|
|
21
|
+
* selected it, and this repo's own measurement (bench/agent-loop-and-replay.md) says a pure
|
|
22
|
+
* on-demand surface does NOT hold accuracy with a generic model: "it needs the hot-set schemas.
|
|
23
|
+
* On-demand is for the cold tail, not the hot path." An option that is unused and measured-worse is
|
|
24
|
+
* a trap, not a choice — it looks like a 4,000-token saving and costs correctness.
|
|
25
|
+
*
|
|
26
|
+
* ALL is what remains, and it is deliberately NOT a profile: it is a verification switch. It is the
|
|
27
|
+
* only mode that advertises `outputSchema`, which is what makes the MCP layer validate tool OUTPUT —
|
|
28
|
+
* the check that caught `reticle_verify_change` returning a payload its own schema rejected. It
|
|
29
|
+
* cannot be folded into the default: measured, carrying output schemas on the 16-tool surface costs
|
|
30
|
+
* 18,183 -> 41,117 bytes, 2.26x, +5,733 tokens per turn. And it cannot simply be deleted without
|
|
31
|
+
* losing that defect class. So it stays, named for what it is, and no user is asked to pick it.
|
|
32
|
+
*
|
|
33
|
+
* Sizes are NOT restated here — not as a current figure, not as a historical one. Four generations
|
|
34
|
+
* of this comment got them wrong. They live in surface-sizes.test.ts, which reads them off the real
|
|
35
|
+
* surface. (The numbers above are the two measurements that JUSTIFY a decision, which is a different
|
|
36
|
+
* job from documenting the current size; both were taken with a fresh daemon per reading.)
|
|
37
|
+
*/
|
|
38
|
+
export const TOOL_SURFACE = {
|
|
39
|
+
/** What every user gets: the verify loop, plus the 2 meta-tools that reach everything else. */
|
|
40
|
+
DEFAULT: 'default',
|
|
41
|
+
/** Every tool advertised directly, WITH output schemas. A verification switch — see above. */
|
|
42
|
+
ALL: 'all',
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* The switch that turns on the full, output-schema-carrying surface. A boolean, not a menu.
|
|
46
|
+
*
|
|
47
|
+
* Named for what it does rather than which "profile" it selects, because the previous name invited
|
|
48
|
+
* users to shop among alternatives that did not meaningfully differ.
|
|
49
|
+
*/
|
|
50
|
+
export const ADVERTISE_ALL_ENV = 'RETICLE_ADVERTISE_ALL_TOOLS';
|
|
51
|
+
/**
|
|
52
|
+
* The retired setting, still read so nobody's shell profile breaks.
|
|
53
|
+
*
|
|
54
|
+
* Every value it ever accepted resolves to something sensible: `full` to the ALL surface, everything
|
|
55
|
+
* else to the default. Silently honouring them would repeat the original sin, so `describeToolSurface`
|
|
56
|
+
* says the setting retired and what was used instead.
|
|
57
|
+
*/
|
|
58
|
+
export const TOOL_PROFILE_ENV = 'RETICLE_TOOL_PROFILE';
|
|
59
|
+
const RETIRED_PROFILE_VALUES = {
|
|
60
|
+
full: TOOL_SURFACE.ALL,
|
|
61
|
+
hybrid: TOOL_SURFACE.DEFAULT,
|
|
62
|
+
core: TOOL_SURFACE.DEFAULT,
|
|
63
|
+
standard: TOOL_SURFACE.DEFAULT,
|
|
64
|
+
dynamic: TOOL_SURFACE.DEFAULT,
|
|
65
|
+
};
|
|
66
|
+
// The set an agent needs to verify a change end-to-end. Tool DEFINITIONS are re-sent every turn, so
|
|
67
|
+
// this set is a per-turn cost, and every name in it has to earn its place.
|
|
68
|
+
//
|
|
69
|
+
// MEASURED per-turn `tools/list` cost, off the real wire (spawn `mcp`, read tools/list, measure the
|
|
70
|
+
// serialized result), with a FRESH DAEMON per reading — the setting is read by the daemon at startup,
|
|
71
|
+
// so a loop that reuses one daemon measures the first surface every time and looks like proof that
|
|
72
|
+
// the setting does nothing. That happened while taking this very reading.
|
|
73
|
+
//
|
|
74
|
+
// default 18,183 B ~4,546 tok/turn 16 tools
|
|
75
|
+
// all 127,903 B ~31,976 tok/turn 48 tools
|
|
76
|
+
//
|
|
77
|
+
// Treat these as the SHAPE of the gap and re-measure before quoting one; counts are asserted in
|
|
78
|
+
// surface-sizes.test.ts, never from this comment.
|
|
79
|
+
//
|
|
80
|
+
// Where the cost sits on the default surface: inputSchema is 76% of the payload (parameter
|
|
81
|
+
// descriptions are half of that), tool descriptions are 12%, outputSchema ~0 because it is dropped.
|
|
82
|
+
// So the next real saving is in parameter prose, not in dropping more tools.
|
|
83
|
+
//
|
|
84
|
+
// There is a floor, though: an 8-tool cut (dropping act/navigate/wait_for/sessions) was MEASURED to
|
|
85
|
+
// regress real-agent accuracy 5/5 -> 3/5, because the model loses scaffolding and wanders on harder
|
|
86
|
+
// flows. Direct network/console stay (far more discoverable than observe-with-filters -> fewer turns,
|
|
87
|
+
// better verdicts).
|
|
88
|
+
//
|
|
89
|
+
// Evidence status: the 5/5 figure came from a single gpt-4o run and is STALE as a justification.
|
|
90
|
+
// Current-model evidence is indirect but real — the cost-delta run (bench/fix-loop/COST-DELTA.md)
|
|
91
|
+
// drove this surface on a current model and fixed 4/4 cells with ~25% FEWER tool calls than the
|
|
92
|
+
// baseline. A formal A/B against a leaner surface on a current model is still UNRUN.
|
|
93
|
+
// See bench/agent-loop-and-replay.md.
|
|
94
|
+
export const CORE_TOOL_NAMES = new Set([
|
|
95
|
+
ReticleTool.SESSIONS,
|
|
96
|
+
ReticleTool.NAVIGATE,
|
|
97
|
+
ReticleTool.SNAPSHOT,
|
|
98
|
+
ReticleTool.QUERY,
|
|
99
|
+
ReticleTool.ACT,
|
|
100
|
+
ReticleTool.ACT_AND_WAIT,
|
|
101
|
+
ReticleTool.OBSERVE,
|
|
102
|
+
ReticleTool.NETWORK,
|
|
103
|
+
ReticleTool.CONSOLE,
|
|
104
|
+
ReticleTool.WAIT_FOR,
|
|
105
|
+
ReticleTool.ASSERT,
|
|
106
|
+
ReticleTool.STATE,
|
|
107
|
+
// INSPECT is what turns a finding into an EDIT: it maps a DOM node to `src/App.tsx:104`. Finding a
|
|
108
|
+
// bug is half the job; knowing which file to open is the half that makes the agent useful, and it
|
|
109
|
+
// is the one capability here with no substitute in any other verification tool. It sat in
|
|
110
|
+
// `standard`, so under the default profile an agent had to already know it existed and reach it
|
|
111
|
+
// through reticle_run — which, observed over a drive of the whole surface, means it never gets called.
|
|
112
|
+
// The measured floor that justifies a lean core was about CUTTING to 8 (accuracy 5/5 → 3/5), not
|
|
113
|
+
// about holding at 12; one tool of schema tax to close the find→fix loop is the right trade.
|
|
114
|
+
ReticleTool.INSPECT,
|
|
115
|
+
// FEEDBACK is in every profile for the same reason INSPECT is: a tool an agent has to already know
|
|
116
|
+
// about, and reach through reticle_run, is a tool that never gets called. That is fatal here in a way
|
|
117
|
+
// it is not elsewhere — an unadvertised feedback channel collects nothing, which is indistinguishable
|
|
118
|
+
// from not having built one. It is also the cheapest tool on the surface to carry (three params) and
|
|
119
|
+
// the only one whose whole purpose is telling us which of the other fifteen are failing.
|
|
120
|
+
ReticleTool.FEEDBACK,
|
|
121
|
+
// SESSION is here because the product ORDERS the agent to call it. The session lease block is
|
|
122
|
+
// spliced onto the first result of every session ("call reticle_session {action:'yield'}"), and
|
|
123
|
+
// the pause hint is spliced onto every refusal while a human has the session paused, where
|
|
124
|
+
// {action:"resume"} is the only exit. Both were naming a tool the default surface did not
|
|
125
|
+
// advertise: an agent that obeyed got `unknown tool`, and an agent that did not left the panel
|
|
126
|
+
// reading "live" after it had stopped driving — which is the state the whole handback protocol
|
|
127
|
+
// exists to prevent.
|
|
128
|
+
//
|
|
129
|
+
// Measured cost: ~1.3 KB of prose (455 B description + ~780 B of parameter descriptions) on a
|
|
130
|
+
// surface whose prose is ~23.7 KB, so roughly +5%, a few hundred tokens a turn. The alternative —
|
|
131
|
+
// deleting the instruction from the lease and the pause hint — deletes the handback protocol,
|
|
132
|
+
// because there is nowhere else those two calls are ever named.
|
|
133
|
+
ReticleTool.SESSION,
|
|
134
|
+
]);
|
|
135
|
+
/** Is the truthy form of a boolean env var set? `1`, `true`, `yes` — anything else is off. */
|
|
136
|
+
function envFlagOn(raw) {
|
|
137
|
+
if (raw === undefined)
|
|
138
|
+
return false;
|
|
139
|
+
const value = raw.trim().toLowerCase();
|
|
140
|
+
return '1' === value || 'true' === value || 'yes' === value || 'on' === value;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Which surface is live.
|
|
144
|
+
*
|
|
145
|
+
* `explicit` is the programmatic override (tests, `advertisedTools` callers). Otherwise the ALL
|
|
146
|
+
* switch decides, and the retired setting is honoured last so an old shell profile still works.
|
|
147
|
+
*/
|
|
148
|
+
export function resolveToolSurface(explicit) {
|
|
149
|
+
if (explicit === TOOL_SURFACE.ALL)
|
|
150
|
+
return TOOL_SURFACE.ALL;
|
|
151
|
+
if (explicit === TOOL_SURFACE.DEFAULT)
|
|
152
|
+
return TOOL_SURFACE.DEFAULT;
|
|
153
|
+
const retiredExplicit = explicit === undefined ? undefined : RETIRED_PROFILE_VALUES[explicit];
|
|
154
|
+
if (retiredExplicit !== undefined)
|
|
155
|
+
return retiredExplicit;
|
|
156
|
+
if (envFlagOn(process.env[ADVERTISE_ALL_ENV]))
|
|
157
|
+
return TOOL_SURFACE.ALL;
|
|
158
|
+
const retiredEnv = RETIRED_PROFILE_VALUES[process.env[TOOL_PROFILE_ENV] ?? ''];
|
|
159
|
+
return retiredEnv ?? TOOL_SURFACE.DEFAULT;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Which surface is live, and what chose it.
|
|
163
|
+
*
|
|
164
|
+
* These settings are read by the DAEMON at startup, never by the client, so exporting one in an
|
|
165
|
+
* agent's environment while a daemon is already running changes nothing at all — which is exactly
|
|
166
|
+
* the observation that produced a "standard and full advertise the same tools" report. Documenting
|
|
167
|
+
* that was not enough; the setting failing to take has to be VISIBLE, so this rides along in the
|
|
168
|
+
* reticle_tools catalog.
|
|
169
|
+
*/
|
|
170
|
+
export function describeToolSurface(active, requested) {
|
|
171
|
+
const retired = requested ?? process.env[TOOL_PROFILE_ENV];
|
|
172
|
+
if (retired !== undefined && retired in RETIRED_PROFILE_VALUES) {
|
|
173
|
+
return {
|
|
174
|
+
active,
|
|
175
|
+
source: `${TOOL_PROFILE_ENV}=${retired} is RETIRED — there is one tool surface now; using '${active}' (set ${ADVERTISE_ALL_ENV}=1 for the full, schema-carrying surface)`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
if (retired !== undefined && 0 < retired.length) {
|
|
179
|
+
return {
|
|
180
|
+
active,
|
|
181
|
+
source: `${TOOL_PROFILE_ENV} is RETIRED and '${retired}' was never one of its values; using '${active}'`,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const flag = process.env[ADVERTISE_ALL_ENV];
|
|
185
|
+
if (envFlagOn(flag)) {
|
|
186
|
+
return { active, source: `${ADVERTISE_ALL_ENV} set in the DAEMON's environment at startup` };
|
|
187
|
+
}
|
|
188
|
+
// "unset" and "set to 0" are different facts, and only one of them means "you did not ask for it".
|
|
189
|
+
// Reporting the second as the first is how somebody spends an afternoon on a switch that IS being
|
|
190
|
+
// read and is simply off.
|
|
191
|
+
return flag === undefined || 0 === flag.length
|
|
192
|
+
? {
|
|
193
|
+
active,
|
|
194
|
+
source: `the one tool surface (${ADVERTISE_ALL_ENV} unset when the daemon started)`,
|
|
195
|
+
}
|
|
196
|
+
: { active, source: `the one tool surface (${ADVERTISE_ALL_ENV}='${flag}' is off)` };
|
|
197
|
+
}
|
|
198
|
+
export function filterTools(tools, surface) {
|
|
199
|
+
// CORE_TOOL_NAMES is what it always really was: the set advertised directly. It was never the
|
|
200
|
+
// interesting thing about the `core` PROFILE, whose only distinction was a second name for this.
|
|
201
|
+
if (surface === TOOL_SURFACE.DEFAULT)
|
|
202
|
+
return tools.filter((t) => CORE_TOOL_NAMES.has(t.name));
|
|
203
|
+
return tools;
|
|
204
|
+
}
|
|
@@ -11,13 +11,13 @@ export function parseInteractive(tree) {
|
|
|
11
11
|
return items;
|
|
12
12
|
}
|
|
13
13
|
export function asString(value) {
|
|
14
|
-
return typeof value
|
|
14
|
+
return 'string' === typeof value ? value : undefined;
|
|
15
15
|
}
|
|
16
16
|
export function asNumber(value) {
|
|
17
|
-
return typeof value
|
|
17
|
+
return 'number' === typeof value ? value : undefined;
|
|
18
18
|
}
|
|
19
19
|
export function asRecord(value) {
|
|
20
|
-
return typeof value
|
|
20
|
+
return 'object' === typeof value && value !== null ? value : {};
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* A `{ file, line }` source location off an untrusted result payload, or undefined.
|
|
@@ -27,15 +27,15 @@ export function asRecord(value) {
|
|
|
27
27
|
* worse than no location at all — it looks like an answer.
|
|
28
28
|
*/
|
|
29
29
|
export function sourceOf(value) {
|
|
30
|
-
if (
|
|
30
|
+
if (null === value || typeof value !== 'object')
|
|
31
31
|
return undefined;
|
|
32
32
|
const record = value;
|
|
33
33
|
const file = record['file'];
|
|
34
34
|
const line = record['line'];
|
|
35
|
-
if (typeof file !== 'string' || file.length
|
|
35
|
+
if (typeof file !== 'string' || 0 === file.length || typeof line !== 'number')
|
|
36
36
|
return undefined;
|
|
37
37
|
const out = { file, line };
|
|
38
|
-
if (typeof record['column']
|
|
38
|
+
if ('number' === typeof record['column'])
|
|
39
39
|
out.column = record['column'];
|
|
40
40
|
return out;
|
|
41
41
|
}
|
package/dist/tools/tools.d.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
1
|
import { type ToolDef } from './tool-kit.js';
|
|
2
|
+
import { type MergePlan } from './merge-tools.js';
|
|
2
3
|
export type { ToolDef, ToolDeps } from './tool-kit.js';
|
|
4
|
+
/**
|
|
5
|
+
* surface consolidation. Tool defs are re-sent EVERY turn, so the advertised count is a per-turn
|
|
6
|
+
* tax multiplied by loop length. Sibling families collapse into one action-dispatched tool; the member
|
|
7
|
+
* handlers stay defined above and are simply no longer advertised separately.
|
|
8
|
+
*
|
|
9
|
+
* Guardrail (from the plan): the 12-tool core hot-set keeps its EXACT names and shapes and is never
|
|
10
|
+
* merged — sessions/navigate/snapshot/query/act/act_and_wait/observe/network/console/wait_for/assert/state.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MERGE_PLANS: MergePlan[];
|
|
13
|
+
/**
|
|
14
|
+
* Retired from the MCP surface entirely (capability preserved elsewhere, per the plan):
|
|
15
|
+
* - run_record: auto-recording on flow_replay already persists run outcomes.
|
|
16
|
+
*/
|
|
17
|
+
export declare const RETIRED_FROM_SURFACE: string[];
|
|
3
18
|
export declare const TOOLS: ToolDef[];
|