talos-code 0.0.1 → 0.2.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/CHANGELOG.md +87 -0
- package/LICENSE +661 -0
- package/README.md +116 -3
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/archive/zip.js +73 -0
- package/dist/args.js +100 -0
- package/dist/automations/history-store.js +34 -0
- package/dist/automations/policy-store.js +43 -0
- package/dist/automations/runner.js +107 -0
- package/dist/automations/schedule.js +85 -0
- package/dist/automations/windows-task.js +53 -0
- package/dist/commands/advanced-cli.js +233 -0
- package/dist/commands/checkpoint-cli.js +45 -0
- package/dist/commands/config-cli.js +107 -0
- package/dist/commands/context.js +17 -0
- package/dist/commands/extensions-cli.js +207 -0
- package/dist/commands/project-cli.js +74 -0
- package/dist/commands/project-commands.js +143 -0
- package/dist/commands/provider-cli.js +244 -0
- package/dist/commands/services-cli.js +248 -0
- package/dist/commands/session-cli.js +171 -0
- package/dist/commands/system-cli.js +405 -0
- package/dist/config/commands.js +60 -0
- package/dist/config/load.js +382 -0
- package/dist/config/migrations.js +48 -0
- package/dist/config/types.js +11 -0
- package/dist/diagnostics/development-log.js +154 -0
- package/dist/diagnostics/doctor.js +104 -0
- package/dist/diagnostics/redact.js +80 -0
- package/dist/diagnostics/zip.js +52 -0
- package/dist/errors.js +156 -0
- package/dist/events/bridge.js +130 -0
- package/dist/extensions/installer.js +178 -0
- package/dist/extensions/package-schema.js +24 -0
- package/dist/headless/result.js +84 -0
- package/dist/headless/run.js +230 -0
- package/dist/i18n/en/approval.js +46 -0
- package/dist/i18n/en/common.js +9 -0
- package/dist/i18n/en/credentials.js +92 -0
- package/dist/i18n/en/errors.js +267 -0
- package/dist/i18n/en/firstrun.js +101 -0
- package/dist/i18n/en/providers.js +37 -0
- package/dist/i18n/en/screen.js +774 -0
- package/dist/i18n/en/tools.js +127 -0
- package/dist/i18n/en.js +14 -0
- package/dist/i18n/error-view.js +307 -0
- package/dist/i18n/index.js +19 -0
- package/dist/i18n/kernel-map.js +139 -0
- package/dist/io.js +45 -0
- package/dist/main.js +331 -0
- package/dist/paths.js +41 -0
- package/dist/protocol/v2/codec.js +9 -0
- package/dist/protocol/v2/events.js +555 -0
- package/dist/protocol/v2/index.js +4 -0
- package/dist/protocol/v2/replay.js +28 -0
- package/dist/protocol/v2/types.js +1 -0
- package/dist/provider/control-plane.js +135 -0
- package/dist/provider/environment-keys.js +275 -0
- package/dist/provider/health.js +110 -0
- package/dist/provider/missing-key.js +48 -0
- package/dist/provider/model-catalog.js +168 -0
- package/dist/provider/openrouter-login.js +172 -0
- package/dist/provider/provider-text.js +13 -0
- package/dist/provider/store.js +95 -0
- package/dist/provider/system-keyring.js +214 -0
- package/dist/runtime/active-run.js +63 -0
- package/dist/runtime/agent-tree.js +74 -0
- package/dist/runtime/attachments.js +84 -0
- package/dist/runtime/brokered-executor.js +395 -0
- package/dist/runtime/context-archive.js +69 -0
- package/dist/runtime/context-status.js +76 -0
- package/dist/runtime/create-runtime.js +111 -0
- package/dist/runtime/model-profile.js +361 -0
- package/dist/runtime/output-store.js +137 -0
- package/dist/runtime/provider-attempts.js +185 -0
- package/dist/runtime/replay-buffer.js +153 -0
- package/dist/runtime/repo.js +95 -0
- package/dist/runtime/session-facade.js +135 -0
- package/dist/runtime/session-summary.js +125 -0
- package/dist/runtime/supervisor.js +265 -0
- package/dist/runtime/talos-composition.js +1011 -0
- package/dist/runtime/types.js +5 -0
- package/dist/runtime/usage-snapshot.js +82 -0
- package/dist/security/auto-classifier.js +38 -0
- package/dist/security/credential-free-environment.js +54 -0
- package/dist/security/evaluate.js +243 -0
- package/dist/security/execution-backends.js +236 -0
- package/dist/security/execution-broker.js +102 -0
- package/dist/security/forge-scan.js +74 -0
- package/dist/security/from-approval.js +39 -0
- package/dist/security/mxc-execution-backend.js +281 -0
- package/dist/security/permission-engine.js +138 -0
- package/dist/security/permission-explanation.js +54 -0
- package/dist/security/persist.js +179 -0
- package/dist/security/plugin-guard.js +230 -0
- package/dist/security/process-tree-evidence-store.js +74 -0
- package/dist/security/process-tree-probe.js +554 -0
- package/dist/security/project-resource-inventory.js +186 -0
- package/dist/security/project-trust-gate.js +38 -0
- package/dist/security/project-trust.js +367 -0
- package/dist/security/rule-parser.js +201 -0
- package/dist/security/shell-segmentation.js +68 -0
- package/dist/security/trust-authority.js +324 -0
- package/dist/security/types.js +1 -0
- package/dist/security/workspace-identity.js +102 -0
- package/dist/services/automation-facade.js +59 -0
- package/dist/services/forge-facade.js +77 -0
- package/dist/services/hook-facade.js +240 -0
- package/dist/services/index.js +16 -0
- package/dist/services/library-facade.js +174 -0
- package/dist/services/mcp-facade.js +348 -0
- package/dist/services/memory-facade.js +126 -0
- package/dist/services/notes-facade.js +157 -0
- package/dist/services/plugin-facade.js +308 -0
- package/dist/services/research-facade.js +110 -0
- package/dist/services/task-board-facade.js +236 -0
- package/dist/services/workflow-catalog.js +246 -0
- package/dist/sessions/export-format.js +98 -0
- package/dist/sessions/metadata-store.js +160 -0
- package/dist/sessions/share.js +122 -0
- package/dist/sessions/transfer.js +16 -0
- package/dist/subcommands.js +62 -0
- package/dist/tui/agent-roster.js +36 -0
- package/dist/tui/agent-view.js +51 -0
- package/dist/tui/app.js +4098 -0
- package/dist/tui/approval.js +36 -0
- package/dist/tui/boot/boot-sequence.js +76 -0
- package/dist/tui/boot/cinematic.js +243 -0
- package/dist/tui/boot/desktop-logo.js +82 -0
- package/dist/tui/boot.js +3 -0
- package/dist/tui/busy-input.js +58 -0
- package/dist/tui/catalog-service.js +560 -0
- package/dist/tui/components/assistant-stream.js +1 -0
- package/dist/tui/components/command-menu.js +68 -0
- package/dist/tui/components/composer.js +219 -0
- package/dist/tui/components/diff.js +35 -0
- package/dist/tui/components/footer.js +48 -0
- package/dist/tui/components/header.js +6 -0
- package/dist/tui/components/markdown.js +305 -0
- package/dist/tui/components/status-indicator.js +38 -0
- package/dist/tui/components/terminal-shell.js +214 -0
- package/dist/tui/components/thinking-row.js +19 -0
- package/dist/tui/components/tool-row.js +97 -0
- package/dist/tui/components/transcript-virtualizer.js +165 -0
- package/dist/tui/components/transcript.js +43 -0
- package/dist/tui/descendant-approvals.js +104 -0
- package/dist/tui/diff-model.js +77 -0
- package/dist/tui/editor-history.js +21 -0
- package/dist/tui/editor.js +210 -0
- package/dist/tui/event-adapter.js +436 -0
- package/dist/tui/exit-output.js +58 -0
- package/dist/tui/external-editor.js +53 -0
- package/dist/tui/file-completion.js +89 -0
- package/dist/tui/focus-manager.js +5 -0
- package/dist/tui/highlight.js +30 -0
- package/dist/tui/input-router.js +18 -0
- package/dist/tui/interrupt.js +99 -0
- package/dist/tui/keybindings.js +194 -0
- package/dist/tui/keymap-resolver.js +91 -0
- package/dist/tui/launch-state.js +148 -0
- package/dist/tui/line-diff.js +57 -0
- package/dist/tui/live-activity.js +56 -0
- package/dist/tui/metrics.js +123 -0
- package/dist/tui/onboarding.js +36 -0
- package/dist/tui/overlays/agent-tree.js +43 -0
- package/dist/tui/overlays/approval-dialog.js +642 -0
- package/dist/tui/overlays/automation-center.js +51 -0
- package/dist/tui/overlays/checkpoint-picker.js +47 -0
- package/dist/tui/overlays/context-inspector.js +36 -0
- package/dist/tui/overlays/effort-line.js +110 -0
- package/dist/tui/overlays/forge-center.js +46 -0
- package/dist/tui/overlays/help-dialog.js +16 -0
- package/dist/tui/overlays/history-picker.js +37 -0
- package/dist/tui/overlays/hook-center.js +70 -0
- package/dist/tui/overlays/library-center.js +55 -0
- package/dist/tui/overlays/mcp-center.js +60 -0
- package/dist/tui/overlays/memory-center.js +63 -0
- package/dist/tui/overlays/model-picker.js +77 -0
- package/dist/tui/overlays/notes-center.js +53 -0
- package/dist/tui/overlays/overlay-host.js +8 -0
- package/dist/tui/overlays/plugin-center.js +76 -0
- package/dist/tui/overlays/provider-picker.js +171 -0
- package/dist/tui/overlays/queue-editor.js +32 -0
- package/dist/tui/overlays/research-center.js +59 -0
- package/dist/tui/overlays/scroll-window.js +234 -0
- package/dist/tui/overlays/session-picker.js +115 -0
- package/dist/tui/overlays/tasks-center.js +83 -0
- package/dist/tui/overlays/theme-picker.js +21 -0
- package/dist/tui/overlays/transcript-search.js +58 -0
- package/dist/tui/overlays/trust-center.js +29 -0
- package/dist/tui/overlays/workflow-center.js +46 -0
- package/dist/tui/project-file-index.js +214 -0
- package/dist/tui/project-references.js +85 -0
- package/dist/tui/project-trust-prompt.js +289 -0
- package/dist/tui/prompt-history-store.js +116 -0
- package/dist/tui/queue-store.js +110 -0
- package/dist/tui/regions/budget.js +59 -0
- package/dist/tui/regions/views.js +96 -0
- package/dist/tui/render-coordinator.js +148 -0
- package/dist/tui/render-scheduler.js +4 -0
- package/dist/tui/run.js +69 -0
- package/dist/tui/selection-list.js +29 -0
- package/dist/tui/session-controller.js +791 -0
- package/dist/tui/session-export.js +54 -0
- package/dist/tui/setup-wizard.js +46 -0
- package/dist/tui/shell-input.js +35 -0
- package/dist/tui/shell-layout.js +48 -0
- package/dist/tui/shell-model.js +98 -0
- package/dist/tui/slash-commands.js +82 -0
- package/dist/tui/state.js +151 -0
- package/dist/tui/status-bar.js +125 -0
- package/dist/tui/status-view.js +40 -0
- package/dist/tui/terminal-capabilities.js +9 -0
- package/dist/tui/terminal-session.js +11 -0
- package/dist/tui/text-width.js +66 -0
- package/dist/tui/theme-catalog.js +27 -0
- package/dist/tui/theme-store.js +23 -0
- package/dist/tui/theme.js +23 -0
- package/dist/tui/tool-display.js +135 -0
- package/dist/tui/tool-facts.js +1 -0
- package/dist/tui/tools/bash-renderer.js +32 -0
- package/dist/tui/tools/change.js +61 -0
- package/dist/tui/tools/edit-renderer.js +17 -0
- package/dist/tui/tools/generic-renderer.js +13 -0
- package/dist/tui/tools/list-renderer.js +14 -0
- package/dist/tui/tools/read-renderer.js +13 -0
- package/dist/tui/tools/registry.js +20 -0
- package/dist/tui/tools/row-format.js +187 -0
- package/dist/tui/tools/search-renderer.js +38 -0
- package/dist/tui/tools/shared.js +97 -0
- package/dist/tui/tools/write-renderer.js +15 -0
- package/dist/tui/transcript-model.js +441 -0
- package/dist/tui/ui-preferences.js +79 -0
- package/dist/tui/usage-view.js +77 -0
- package/dist/tui/vim-mode.js +99 -0
- package/dist/update/check.js +15 -0
- package/dist/update/npm.js +51 -0
- package/dist/update/run.js +129 -0
- package/dist/version.js +2 -0
- package/dist/workspace/checkpoint-store.js +210 -0
- package/dist/workspace/checkpoint.js +413 -0
- package/dist/workspace/restore.js +232 -0
- package/package.json +64 -5
- package/vendor/context-engine/package.json +11 -0
- package/vendor/context-engine/src/compaction-planner.mjs +57 -0
- package/vendor/context-engine/src/contracts.mjs +48 -0
- package/vendor/context-engine/src/engine.mjs +445 -0
- package/vendor/context-engine/src/node/context-export.mjs +164 -0
- package/vendor/context-engine/src/node/legacy-import.mjs +92 -0
- package/vendor/context-engine/src/node/migrations/001-context.sql +126 -0
- package/vendor/context-engine/src/node/sqlite-store.mjs +85 -0
- package/vendor/context-engine/src/node/sqlite-worker.mjs +559 -0
- package/vendor/context-engine/src/profiles.mjs +10 -0
- package/vendor/context-engine/src/retrieval.mjs +104 -0
- package/vendor/context-engine/src/summary.mjs +97 -0
- package/vendor/context-engine/src/usage.mjs +34 -0
- package/vendor/harness-ui/package.json +38 -0
- package/vendor/harness-ui/src/acp-agent.mjs +350 -0
- package/vendor/harness-ui/src/agent-service.mjs +2188 -0
- package/vendor/harness-ui/src/agui-events.mjs +452 -0
- package/vendor/harness-ui/src/ambiente-solo-server.mjs +121 -0
- package/vendor/harness-ui/src/artifact-store.mjs +39 -0
- package/vendor/harness-ui/src/assistenza.mjs +123 -0
- package/vendor/harness-ui/src/automation-scheduler.mjs +69 -0
- package/vendor/harness-ui/src/automation-store.mjs +145 -0
- package/vendor/harness-ui/src/browser-annota.mjs +639 -0
- package/vendor/harness-ui/src/browser-frame.mjs +211 -0
- package/vendor/harness-ui/src/browser-proxy-universale.mjs +519 -0
- package/vendor/harness-ui/src/browser-proxy.mjs +87 -0
- package/vendor/harness-ui/src/browser-sessione-viva.mjs +329 -0
- package/vendor/harness-ui/src/browser-stream.mjs +445 -0
- package/vendor/harness-ui/src/browser-vivo.mjs +694 -0
- package/vendor/harness-ui/src/chat-image-attachments.mjs +72 -0
- package/vendor/harness-ui/src/config.mjs +697 -0
- package/vendor/harness-ui/src/contesto-del-progetto.mjs +385 -0
- package/vendor/harness-ui/src/context-asset-adapter.mjs +72 -0
- package/vendor/harness-ui/src/context-desktop-service.mjs +253 -0
- package/vendor/harness-ui/src/context-embedding-runtime.mjs +252 -0
- package/vendor/harness-ui/src/context-inference-scheduler.mjs +81 -0
- package/vendor/harness-ui/src/context-native-compaction.mjs +75 -0
- package/vendor/harness-ui/src/context-provider-adapter.mjs +141 -0
- package/vendor/harness-ui/src/context-runtime.mjs +118 -0
- package/vendor/harness-ui/src/context-token-counters.mjs +184 -0
- package/vendor/harness-ui/src/context-tool-catalog.mjs +86 -0
- package/vendor/harness-ui/src/context-tool-output.mjs +72 -0
- package/vendor/harness-ui/src/costo-elenco.mjs +252 -0
- package/vendor/harness-ui/src/custom-task.mjs +171 -0
- package/vendor/harness-ui/src/doctor.mjs +142 -0
- package/vendor/harness-ui/src/document-filename.mjs +97 -0
- package/vendor/harness-ui/src/document-generator.mjs +493 -0
- package/vendor/harness-ui/src/document-report.mjs +331 -0
- package/vendor/harness-ui/src/duckduckgo-search.mjs +155 -0
- package/vendor/harness-ui/src/elenco-profondo.mjs +337 -0
- package/vendor/harness-ui/src/favicon-proxy.mjs +113 -0
- package/vendor/harness-ui/src/forge-contract.mjs +221 -0
- package/vendor/harness-ui/src/frequent-dirs.mjs +134 -0
- package/vendor/harness-ui/src/generated-image-store.mjs +147 -0
- package/vendor/harness-ui/src/generation-idle.mjs +332 -0
- package/vendor/harness-ui/src/gguf-header.mjs +207 -0
- package/vendor/harness-ui/src/git-service.mjs +626 -0
- package/vendor/harness-ui/src/gitignore-elenco.mjs +604 -0
- package/vendor/harness-ui/src/harness-receipt-keypair.mjs +207 -0
- package/vendor/harness-ui/src/hf-direct-transfer.mjs +170 -0
- package/vendor/harness-ui/src/hf-hub-client.mjs +106 -0
- package/vendor/harness-ui/src/hf-image-proxy.mjs +105 -0
- package/vendor/harness-ui/src/hf-model-transfer.mjs +245 -0
- package/vendor/harness-ui/src/hook-registry.mjs +186 -0
- package/vendor/harness-ui/src/http-app.mjs +6259 -0
- package/vendor/harness-ui/src/http-lifecycle.mjs +132 -0
- package/vendor/harness-ui/src/id-archivio.mjs +27 -0
- package/vendor/harness-ui/src/image-generator.mjs +143 -0
- package/vendor/harness-ui/src/istruzioni-di-progetto.mjs +234 -0
- package/vendor/harness-ui/src/kernel/dist/kernelPerIlBanco.js +518 -0
- package/vendor/harness-ui/src/kernel/talosHarness.mjs +10437 -0
- package/vendor/harness-ui/src/library-policy-store.mjs +175 -0
- package/vendor/harness-ui/src/library-store.mjs +652 -0
- package/vendor/harness-ui/src/llama-server-supervisor.mjs +629 -0
- package/vendor/harness-ui/src/local-model-store.mjs +339 -0
- package/vendor/harness-ui/src/local-runtime-contract.mjs +66 -0
- package/vendor/harness-ui/src/local-runtime-events.mjs +44 -0
- package/vendor/harness-ui/src/local-runtime-llama-server.mjs +244 -0
- package/vendor/harness-ui/src/local-runtime-probe.mjs +401 -0
- package/vendor/harness-ui/src/machine-capacity.mjs +66 -0
- package/vendor/harness-ui/src/mappa-cartelle.mjs +491 -0
- package/vendor/harness-ui/src/mcp-client.mjs +98 -0
- package/vendor/harness-ui/src/mcp-registry.mjs +157 -0
- package/vendor/harness-ui/src/mcp-session.mjs +177 -0
- package/vendor/harness-ui/src/memory-store.mjs +227 -0
- package/vendor/harness-ui/src/model-catalog-models-dev.mjs +276 -0
- package/vendor/harness-ui/src/model-catalog.mjs +129 -0
- package/vendor/harness-ui/src/model-destination.mjs +189 -0
- package/vendor/harness-ui/src/modifica-ancorata.mjs +177 -0
- package/vendor/harness-ui/src/native-provider-adapter.mjs +205 -0
- package/vendor/harness-ui/src/notes-store.mjs +250 -0
- package/vendor/harness-ui/src/openai-compatible-runtime.mjs +428 -0
- package/vendor/harness-ui/src/openrouter-oauth.mjs +339 -0
- package/vendor/harness-ui/src/path-policy.mjs +442 -0
- package/vendor/harness-ui/src/plugin-registry.mjs +780 -0
- package/vendor/harness-ui/src/plugin-session.mjs +180 -0
- package/vendor/harness-ui/src/process-policy.mjs +345 -0
- package/vendor/harness-ui/src/prompt-enhancer-provider.mjs +94 -0
- package/vendor/harness-ui/src/provider-auth-cloud.mjs +95 -0
- package/vendor/harness-ui/src/provider-credential-store.mjs +541 -0
- package/vendor/harness-ui/src/provider-probe.mjs +582 -0
- package/vendor/harness-ui/src/provider-registry.mjs +1633 -0
- package/vendor/harness-ui/src/pty-terminal.mjs +312 -0
- package/vendor/harness-ui/src/public-problem.mjs +109 -0
- package/vendor/harness-ui/src/research/card.mjs +235 -0
- package/vendor/harness-ui/src/research/citations.mjs +142 -0
- package/vendor/harness-ui/src/research/collector.mjs +275 -0
- package/vendor/harness-ui/src/research/deposito-a-pezzi.mjs +139 -0
- package/vendor/harness-ui/src/research/dossier.mjs +114 -0
- package/vendor/harness-ui/src/research/esportazioni.mjs +560 -0
- package/vendor/harness-ui/src/research/fetch-cache.mjs +465 -0
- package/vendor/harness-ui/src/research/fidelity.mjs +122 -0
- package/vendor/harness-ui/src/research/independence.mjs +159 -0
- package/vendor/harness-ui/src/research/ledger.mjs +166 -0
- package/vendor/harness-ui/src/research/markdown-server.mjs +565 -0
- package/vendor/harness-ui/src/research/narration.mjs +181 -0
- package/vendor/harness-ui/src/research/open-cards.mjs +131 -0
- package/vendor/harness-ui/src/research/opposing.mjs +305 -0
- package/vendor/harness-ui/src/research/outline.mjs +111 -0
- package/vendor/harness-ui/src/research/page-budget.mjs +209 -0
- package/vendor/harness-ui/src/research/pdf.mjs +291 -0
- package/vendor/harness-ui/src/research/plan.mjs +301 -0
- package/vendor/harness-ui/src/research/raccolta-viva.mjs +452 -0
- package/vendor/harness-ui/src/research/recheck-document.mjs +69 -0
- package/vendor/harness-ui/src/research/recheck-history.mjs +192 -0
- package/vendor/harness-ui/src/research/recheck.mjs +194 -0
- package/vendor/harness-ui/src/research/report.mjs +203 -0
- package/vendor/harness-ui/src/research/run.mjs +527 -0
- package/vendor/harness-ui/src/research/synthesis.mjs +318 -0
- package/vendor/harness-ui/src/research/verification.mjs +572 -0
- package/vendor/harness-ui/src/research-orchestrator.mjs +2679 -0
- package/vendor/harness-ui/src/research-store.mjs +1133 -0
- package/vendor/harness-ui/src/runtime-build-manifest.mjs +26 -0
- package/vendor/harness-ui/src/runtime-contract.mjs +59 -0
- package/vendor/harness-ui/src/runtime-owner-adapter.mjs +1348 -0
- package/vendor/harness-ui/src/runtime-owner-contract.mjs +32 -0
- package/vendor/harness-ui/src/scheda-di-lavoro.mjs +249 -0
- package/vendor/harness-ui/src/search-source-store.mjs +172 -0
- package/vendor/harness-ui/src/session-registry.mjs +6095 -0
- package/vendor/harness-ui/src/session-store.mjs +220 -0
- package/vendor/harness-ui/src/sessione-pronta.mjs +73 -0
- package/vendor/harness-ui/src/setup-stato.mjs +31 -0
- package/vendor/harness-ui/src/sezioni-istruzioni.mjs +204 -0
- package/vendor/harness-ui/src/skill-registry.mjs +120 -0
- package/vendor/harness-ui/src/sse-replay-coalescente.mjs +0 -0
- package/vendor/harness-ui/src/static-files.mjs +96 -0
- package/vendor/harness-ui/src/stream-partition.mjs +123 -0
- package/vendor/harness-ui/src/subagent-orchestrator.mjs +453 -0
- package/vendor/harness-ui/src/task-catalog.mjs +65 -0
- package/vendor/harness-ui/src/tasks-store.mjs +220 -0
- package/vendor/harness-ui/src/terminal-registry.mjs +312 -0
- package/vendor/harness-ui/src/terminal-ws.mjs +170 -0
- package/vendor/harness-ui/src/tool-forge-store.mjs +299 -0
- package/vendor/harness-ui/src/tool-schema-normalize.mjs +100 -0
- package/vendor/harness-ui/src/usage-cache.mjs +315 -0
- package/vendor/harness-ui/src/workspace-browser.mjs +213 -0
- package/vendor/harness-ui/src/workspace-context.mjs +124 -0
- package/vendor/harness-ui/src/workspace-disk.mjs +62 -0
- package/vendor/harness-ui/src/workspace-files.mjs +589 -0
- package/vendor/harness-ui/src/workspace-info.mjs +189 -0
- package/vendor/harness-ui/src/workspace-launch-store.mjs +150 -0
- package/vendor/harness-ui/src/workspace-tree.mjs +67 -0
- package/vendor/harness-ui/src/workspace-watcher.mjs +161 -0
- package/vendor/manifest.json +170 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* L6 — LA CACHE DEI RISULTATI WEB, DENTRO LA CORSA.
|
|
3
|
+
*
|
|
4
|
+
* ## Il difetto che chiude, col numero
|
|
5
|
+
*
|
|
6
|
+
* Baseline vera del desktop, corsa `deep` (sessione `d2a453a8` del 4174,
|
|
7
|
+
* 11/09/2026): 484.171 token in ingresso, `cached_tokens: 0`, 9 ricerche e 14
|
|
8
|
+
* navigazioni. Le linee d'indagine di una ricerca profonda partono dalla stessa
|
|
9
|
+
* domanda: cercano le stesse cose e aprono le stesse pagine, e oggi ognuna paga
|
|
10
|
+
* per conto suo. È l'UNICO punto in cui Hermes — l'obiettivo da battere — è
|
|
11
|
+
* avanti a noi E al mobile (§4.2 del disegno, righe C21/C22).
|
|
12
|
+
*
|
|
13
|
+
* ## Che cosa questa cache risparmia, e che cosa NO
|
|
14
|
+
*
|
|
15
|
+
* ⛔ Va detto con precisione, perché confonderlo farebbe promettere il numero
|
|
16
|
+
* sbagliato:
|
|
17
|
+
*
|
|
18
|
+
* - risparmia CHIAMATE DI RETE e attese: la stessa pagina si apre una volta;
|
|
19
|
+
* - risparmia GIRI: un attrezzo in meno è un giro in meno, e in una
|
|
20
|
+
* conversazione che cresce ogni giro rispedisce TUTTO il prefisso — quindi
|
|
21
|
+
* il risparmio in token è più che proporzionale al risultato evitato;
|
|
22
|
+
* - NON risparmia da sola i token della sintesi: il testo di una pagina entra
|
|
23
|
+
* nel prompt anche quando arriva dalla cache. Quelli li tagliano il budget
|
|
24
|
+
* per pagina (`page-budget.mjs`) e la cache del PROMPT del fornitore, che è
|
|
25
|
+
* un'altra cosa e sta altrove.
|
|
26
|
+
*
|
|
27
|
+
* ⇒ `cached_tokens: 0` è un guasto della cache del PROMPT (prefisso esatto);
|
|
28
|
+
* questa cache attacca il numeratore — 484.171 — riducendo i giri. Le due si
|
|
29
|
+
* moltiplicano, e per moltiplicarsi vogliono la stessa cosa: che una chiamata
|
|
30
|
+
* identica produca byte IDENTICI. Per questo un risultato servito dalla cache
|
|
31
|
+
* torna uguale all'originale, e il fatto che venisse dalla cache si scrive nel
|
|
32
|
+
* registro — mai dentro il testo che legge il modello.
|
|
33
|
+
*
|
|
34
|
+
* ## Le regole, e da dove vengono
|
|
35
|
+
*
|
|
36
|
+
* Fonte primaria: `website/docs/user-guide/features/web-search.md:65-80` del
|
|
37
|
+
* clone `%LOCALAPPDATA%\Temp\talos-competitor\hermes-agent-v21` (Hermes v0.21
|
|
38
|
+
* «Pantheon»), letta l'11/09/2026 — «Result caching»:
|
|
39
|
+
*
|
|
40
|
+
* - `web_search`: stessa query (insensibile a maiuscole e spazi), stesso
|
|
41
|
+
* fornitore; i limiti richiesti sono raggruppati a 10/20/50/100 «so
|
|
42
|
+
* near-identical requests share one entry, with each caller receiving its
|
|
43
|
+
* requested count»;
|
|
44
|
+
* - `web_extract`: stesso URL, stesso formato, stesso fornitore;
|
|
45
|
+
* - ricerche identiche CONCORRENTI «are coalesced into a single backend
|
|
46
|
+
* request — the first caller pays; the rest share the response»;
|
|
47
|
+
* - «Only successful responses are cached. Failures always retry the backend»;
|
|
48
|
+
* - mai in cache gli indirizzi locali: «dev servers, hot-reload builds … a
|
|
49
|
+
* cached copy would show you a stale build».
|
|
50
|
+
*
|
|
51
|
+
* ⛔ Quest'ultima per noi non è un'ipotesi di comodo: il 4174 è `localhost`, e
|
|
52
|
+
* una copia vecchia di una pagina del nostro stesso prodotto è esattamente il
|
|
53
|
+
* genere di bugia che costa una giornata.
|
|
54
|
+
*
|
|
55
|
+
* ## Perché la scadenza, di default, è LA CORSA
|
|
56
|
+
*
|
|
57
|
+
* Hermes tiene 20 minuti. Noi no, e per una ragione che riguarda il prodotto:
|
|
58
|
+
* un dossier dev'essere COERENTE. Due rami che citano la stessa pagina con due
|
|
59
|
+
* testi diversi perché in mezzo è passata mezz'ora producono un rapporto che si
|
|
60
|
+
* contraddice da solo, e la contraddizione non sarebbe nemmeno visibile. La
|
|
61
|
+
* freschezza è il mestiere di `recheck.mjs`, che rilegge apposta e dice cos'è
|
|
62
|
+
* cambiato. ⇒ dentro una corsa la pagina è quella; `ttlMs` resta configurabile
|
|
63
|
+
* per chi vuole il comportamento di Hermes.
|
|
64
|
+
*
|
|
65
|
+
* ## Vive per corsa e sopravvive alla pausa
|
|
66
|
+
*
|
|
67
|
+
* Questo modulo NON scrive su disco: la persistenza è dell'orchestratore, che
|
|
68
|
+
* salva accanto al giornale. Qui si dichiara solo il contratto —
|
|
69
|
+
* `snapshot()`/`restore()` su un oggetto JSON-serializzabile — perché una
|
|
70
|
+
* ripresa che ripaga ciò che era già stato pagato è il difetto che il giornale
|
|
71
|
+
* esiste per impedire.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
import { TALOS_RESEARCH_KEPT_CAP } from './page-budget.mjs';
|
|
75
|
+
|
|
76
|
+
/** La versione dell'istantanea. Un numero diverso si ignora invece di indovinare. */
|
|
77
|
+
export const TALOS_RESEARCH_CACHE_SNAPSHOT_VERSION = 1;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* I gruppi dei limiti di ricerca, da Hermes: `limit=5` e `limit=8` condividono
|
|
81
|
+
* una voce, e ognuno riceve il numero che aveva chiesto.
|
|
82
|
+
*/
|
|
83
|
+
export const TALOS_RESEARCH_LIMIT_BUCKETS = [10, 20, 50, 100];
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* L'indirizzo ridotto a ciò che identifica la PAGINA.
|
|
87
|
+
*
|
|
88
|
+
* Schema e host minuscoli, porta di default via, frammento via (`#sezione` è un
|
|
89
|
+
* punto della stessa pagina), query ORDINATA per chiave — `?b=2&a=1` e
|
|
90
|
+
* `?a=1&b=2` sono la stessa richiesta — ma MAI tolta: su moltissimi siti `?id=12`
|
|
91
|
+
* e `?id=13` sono due articoli diversi, e fonderli sarebbe peggio di un doppione.
|
|
92
|
+
*
|
|
93
|
+
* ⛔ La barra finale si toglie per stare d'accordo con `chiaveDi` in
|
|
94
|
+
* `synthesis.mjs:124-133`, che deduplica le fonti allo stesso modo: due
|
|
95
|
+
* identità diverse per la stessa pagina farebbero cadere la cache proprio dove
|
|
96
|
+
* la sintesi ha già deciso che si tratta di una pagina sola.
|
|
97
|
+
*
|
|
98
|
+
* Un indirizzo illeggibile resta sé stesso, ripulito: meglio un doppione che
|
|
99
|
+
* un'eccezione in mezzo a una raccolta.
|
|
100
|
+
*
|
|
101
|
+
* @param {string} grezzo
|
|
102
|
+
* @returns {string}
|
|
103
|
+
*/
|
|
104
|
+
export function talosResearchNormalizeUrl(grezzo) {
|
|
105
|
+
const testo = String(grezzo ?? '').trim();
|
|
106
|
+
let letto;
|
|
107
|
+
try {
|
|
108
|
+
letto = new URL(testo);
|
|
109
|
+
} catch {
|
|
110
|
+
return testo;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
letto.hash = '';
|
|
114
|
+
letto.protocol = letto.protocol.toLowerCase();
|
|
115
|
+
letto.hostname = letto.hostname.toLowerCase();
|
|
116
|
+
if ((letto.protocol === 'http:' && letto.port === '80') || (letto.protocol === 'https:' && letto.port === '443')) {
|
|
117
|
+
letto.port = '';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const coppie = [...letto.searchParams.entries()].sort((a, b) => (
|
|
121
|
+
a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0
|
|
122
|
+
));
|
|
123
|
+
letto.search = '';
|
|
124
|
+
for (const [chiave, valore] of coppie) letto.searchParams.append(chiave, valore);
|
|
125
|
+
|
|
126
|
+
const finale = letto.toString();
|
|
127
|
+
return finale.endsWith('/') && !letto.search ? finale.slice(0, -1) : finale;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* La query ridotta a ciò che la identifica: spazi compattati, maiuscole via.
|
|
132
|
+
* «Insensibile a maiuscole e spazi», come Hermes.
|
|
133
|
+
*
|
|
134
|
+
* @param {string} grezza
|
|
135
|
+
* @returns {string}
|
|
136
|
+
*/
|
|
137
|
+
export function talosResearchNormalizeQuery(grezza) {
|
|
138
|
+
return String(grezza ?? '').replace(/\s+/g, ' ').trim().toLowerCase();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Il gruppo di appartenenza di un limite richiesto.
|
|
143
|
+
* @param {number} quanti
|
|
144
|
+
* @returns {number}
|
|
145
|
+
*/
|
|
146
|
+
export function talosResearchLimitBucket(quanti) {
|
|
147
|
+
const n = Number(quanti);
|
|
148
|
+
if (!Number.isFinite(n) || n <= 0) return TALOS_RESEARCH_LIMIT_BUCKETS[0];
|
|
149
|
+
for (const gruppo of TALOS_RESEARCH_LIMIT_BUCKETS) if (n <= gruppo) return gruppo;
|
|
150
|
+
return TALOS_RESEARCH_LIMIT_BUCKETS[TALOS_RESEARCH_LIMIT_BUCKETS.length - 1];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @typedef {object} TalosResearchFetchDescriptor
|
|
155
|
+
* @property {'search' | 'extract'} kind
|
|
156
|
+
* @property {string} [url] Per `extract`.
|
|
157
|
+
* @property {string} [query] Per `search`.
|
|
158
|
+
* @property {number} [limit] Per `search`: raggruppato, non usato alla lettera.
|
|
159
|
+
* @property {string} [provider] Chi risponde. Due fornitori non danno la stessa pagina.
|
|
160
|
+
* @property {string} [format] Il formato chiesto a chi estrae, quando ne ha più d'uno.
|
|
161
|
+
*/
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* La chiave.
|
|
165
|
+
*
|
|
166
|
+
* ⛔ Le parti a vocabolario chiuso (tipo, fornitore, formato, gruppo) stanno
|
|
167
|
+
* PRIMA e non contengono mai il separatore; la parte libera — URL o query — sta
|
|
168
|
+
* ULTIMA. Così un `|` dentro una query non può fingersi un confine: non c'è
|
|
169
|
+
* nessun campo dopo di lei da confondere.
|
|
170
|
+
*
|
|
171
|
+
* @param {TalosResearchFetchDescriptor} descrittore
|
|
172
|
+
* @returns {string}
|
|
173
|
+
*/
|
|
174
|
+
export function talosResearchFetchKey(descrittore) {
|
|
175
|
+
const tipo = descrittore.kind === 'search' ? 'search' : 'extract';
|
|
176
|
+
const fornitore = String(descrittore.provider ?? '').replace(/\|/g, '').trim().toLowerCase() || '-';
|
|
177
|
+
const formato = String(descrittore.format ?? '').replace(/\|/g, '').trim().toLowerCase() || '-';
|
|
178
|
+
return tipo === 'search'
|
|
179
|
+
? `search|${fornitore}|${talosResearchLimitBucket(descrittore.limit ?? 0)}|${talosResearchNormalizeQuery(descrittore.query ?? '')}`
|
|
180
|
+
: `extract|${fornitore}|${formato}|${talosResearchNormalizeUrl(descrittore.url ?? '')}`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const IPV4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Gli indirizzi che non si mettono MAI in cache: locali, di rete privata, o
|
|
187
|
+
* senza punti (un nome a etichetta sola è un host di LAN).
|
|
188
|
+
*
|
|
189
|
+
* ⛔ Il 4174 cade qui dentro, ed è voluto: una pagina del nostro prodotto
|
|
190
|
+
* servita da una copia vecchia è il modo più efficiente di perdere una giornata.
|
|
191
|
+
*
|
|
192
|
+
* @param {string} grezzo
|
|
193
|
+
* @returns {boolean}
|
|
194
|
+
*/
|
|
195
|
+
export function talosResearchNeverCached(grezzo) {
|
|
196
|
+
let host;
|
|
197
|
+
try {
|
|
198
|
+
host = new URL(String(grezzo ?? '')).hostname.toLowerCase();
|
|
199
|
+
} catch {
|
|
200
|
+
// Un indirizzo che non si legge non si può nemmeno giudicare pubblico.
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
if (!host) return true;
|
|
204
|
+
|
|
205
|
+
const nudo = host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host;
|
|
206
|
+
if (nudo === 'localhost' || nudo === '::1' || nudo.endsWith('.localhost')) return true;
|
|
207
|
+
if (nudo.endsWith('.local') || nudo.endsWith('.internal') || nudo.endsWith('.home.arpa')) return true;
|
|
208
|
+
if (!nudo.includes('.') && !nudo.includes(':')) return true;
|
|
209
|
+
|
|
210
|
+
const quattro = IPV4.exec(nudo);
|
|
211
|
+
if (quattro) {
|
|
212
|
+
const [a, b] = [Number(quattro[1]), Number(quattro[2])];
|
|
213
|
+
if (a === 127 || a === 10 || a === 0) return true;
|
|
214
|
+
if (a === 192 && b === 168) return true;
|
|
215
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
216
|
+
if (a === 169 && b === 254) return true;
|
|
217
|
+
}
|
|
218
|
+
if (nudo.startsWith('fe80:') || nudo.startsWith('fc') || nudo.startsWith('fd')) return true;
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @typedef {object} TalosResearchCacheStats
|
|
224
|
+
* @property {number} calls Quante volte è stata chiesta una cosa. `calls === fetched + served + coalesced`.
|
|
225
|
+
* @property {number} fetched Quante volte si è dovuto chiamare davvero il produttore.
|
|
226
|
+
* @property {number} served Quante volte ha risposto la cache.
|
|
227
|
+
* @property {number} coalesced Quante si sono accodate a una chiamata identica già in volo.
|
|
228
|
+
* @property {number} skipped Indirizzi mai da mettere in cache (sottoinsieme di `fetched`).
|
|
229
|
+
* @property {number} failed Produttori che hanno lanciato o non hanno prodotto: nulla è stato conservato.
|
|
230
|
+
* @property {number} oversize Risposte troppo grandi per essere conservate.
|
|
231
|
+
* @property {number} evicted Voci sfrattate per fare posto.
|
|
232
|
+
* @property {number} entries Voci vive adesso.
|
|
233
|
+
* @property {number} chars Caratteri conservati adesso.
|
|
234
|
+
*/
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @typedef {object} TalosResearchCacheSnapshot
|
|
238
|
+
* @property {number} version
|
|
239
|
+
* @property {number | null} savedAt
|
|
240
|
+
* @property {readonly {key: string, storedAt: number, chars: number, value: unknown}[]} entries
|
|
241
|
+
*/
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Quanto pesa una risposta. `JSON.stringify` invece di indovinare dal campo
|
|
245
|
+
* `text`: una risposta di ricerca è un elenco, e il peso vero è tutto l'oggetto.
|
|
246
|
+
*
|
|
247
|
+
* @param {unknown} valore
|
|
248
|
+
* @returns {number}
|
|
249
|
+
*/
|
|
250
|
+
function pesa(valore) {
|
|
251
|
+
try {
|
|
252
|
+
return JSON.stringify(valore)?.length ?? 0;
|
|
253
|
+
} catch {
|
|
254
|
+
// Un valore non serializzabile non è conservabile: peso infinito lo esclude
|
|
255
|
+
// dalla conservazione senza un ramo speciale.
|
|
256
|
+
return Number.POSITIVE_INFINITY;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* ⛔ Il tipo è il RITORNO della fabbrica, non un'interfaccia scritta due volte:
|
|
262
|
+
* `harness-ui/` non ha un `tsconfig.json`, quindi un `@typedef` copiato a mano
|
|
263
|
+
* che si scosta dal codice non farebbe rosso nessun test — e diventerebbe una
|
|
264
|
+
* bugia silenziosa esattamente nel punto in cui gli altri file lo leggono.
|
|
265
|
+
*
|
|
266
|
+
* @typedef {ReturnType<typeof talosResearchFetchCache>} TalosResearchFetchCache
|
|
267
|
+
*/
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* La cache di una corsa.
|
|
271
|
+
*
|
|
272
|
+
* @param {{now?: () => number, ttlMs?: number | null, maxEntries?: number, maxChars?: number, entryMaxChars?: number}} [opzioni]
|
|
273
|
+
*/
|
|
274
|
+
export function talosResearchFetchCache(opzioni = {}) {
|
|
275
|
+
const adesso = opzioni.now ?? (() => Date.now());
|
|
276
|
+
const ttlMs = opzioni.ttlMs ?? null;
|
|
277
|
+
const maxVoci = Math.max(1, Math.trunc(opzioni.maxEntries ?? 500));
|
|
278
|
+
const maxCaratteri = Math.max(1, Math.trunc(opzioni.maxChars ?? 64 * 1024 * 1024));
|
|
279
|
+
const maxPerVoce = Math.max(1, Math.trunc(opzioni.entryMaxChars ?? TALOS_RESEARCH_KEPT_CAP));
|
|
280
|
+
|
|
281
|
+
/** @type {Map<string, {storedAt: number, chars: number, value: unknown}>} */
|
|
282
|
+
const voci = new Map();
|
|
283
|
+
/** @type {Map<string, Promise<unknown>>} */
|
|
284
|
+
const inVolo = new Map();
|
|
285
|
+
let caratteri = 0;
|
|
286
|
+
|
|
287
|
+
const conto = { calls: 0, fetched: 0, served: 0, coalesced: 0, skipped: 0, failed: 0, oversize: 0, evicted: 0 };
|
|
288
|
+
|
|
289
|
+
/** @param {string} chiave */
|
|
290
|
+
function scaduta(chiave) {
|
|
291
|
+
if (ttlMs === null) return false;
|
|
292
|
+
const voce = voci.get(chiave);
|
|
293
|
+
return voce ? adesso() - voce.storedAt >= ttlMs : false;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** @param {string} chiave */
|
|
297
|
+
function togli(chiave) {
|
|
298
|
+
const voce = voci.get(chiave);
|
|
299
|
+
if (!voce) return;
|
|
300
|
+
caratteri -= voce.chars;
|
|
301
|
+
voci.delete(chiave);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function sfratta() {
|
|
305
|
+
// La `Map` conserva l'ordine di inserimento e ogni lettura ri-inserisce in
|
|
306
|
+
// fondo: la prima chiave è la meno usata di recente.
|
|
307
|
+
while ((voci.size > maxVoci || caratteri > maxCaratteri) && voci.size > 0) {
|
|
308
|
+
const primo = voci.keys().next().value;
|
|
309
|
+
togli(primo);
|
|
310
|
+
conto.evicted += 1;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* @param {string} chiave
|
|
316
|
+
* @param {unknown} valore
|
|
317
|
+
*/
|
|
318
|
+
function conserva(chiave, valore) {
|
|
319
|
+
const peso = pesa(valore);
|
|
320
|
+
if (peso > maxPerVoce) {
|
|
321
|
+
conto.oversize += 1;
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
togli(chiave);
|
|
325
|
+
voci.set(chiave, { storedAt: adesso(), chars: peso, value: valore });
|
|
326
|
+
caratteri += peso;
|
|
327
|
+
sfratta();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
/** @param {TalosResearchFetchDescriptor} descrittore */
|
|
332
|
+
key: (descrittore) => talosResearchFetchKey(descrittore),
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Il solo modo di passare di qui: si chiede il valore, e la cache decide se
|
|
336
|
+
* chiamare il produttore, servire quello che ha, o accodarsi a una chiamata
|
|
337
|
+
* identica già in volo.
|
|
338
|
+
*
|
|
339
|
+
* ⛔ `fromCache` NON deve finire nel testo che legge il modello: due giri
|
|
340
|
+
* identici devono produrre gli stessi byte, o la cache del prompt del
|
|
341
|
+
* fornitore (prefisso esatto) si azzera proprio mentre la stiamo cercando.
|
|
342
|
+
* Va nel registro.
|
|
343
|
+
*
|
|
344
|
+
* @template T
|
|
345
|
+
* @param {TalosResearchFetchDescriptor} descrittore
|
|
346
|
+
* @param {() => Promise<T>} produttore
|
|
347
|
+
* @returns {Promise<{value: T, fromCache: boolean, key: string}>}
|
|
348
|
+
*/
|
|
349
|
+
async around(descrittore, produttore) {
|
|
350
|
+
conto.calls += 1;
|
|
351
|
+
const chiave = talosResearchFetchKey(descrittore);
|
|
352
|
+
|
|
353
|
+
const mai = descrittore.kind === 'extract' && talosResearchNeverCached(descrittore.url ?? '');
|
|
354
|
+
if (mai) {
|
|
355
|
+
conto.fetched += 1;
|
|
356
|
+
conto.skipped += 1;
|
|
357
|
+
try {
|
|
358
|
+
return { value: await produttore(), fromCache: false, key: chiave };
|
|
359
|
+
} catch (rotto) {
|
|
360
|
+
conto.failed += 1;
|
|
361
|
+
throw rotto;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (scaduta(chiave)) togli(chiave);
|
|
366
|
+
|
|
367
|
+
if (voci.has(chiave)) {
|
|
368
|
+
const voce = voci.get(chiave);
|
|
369
|
+
// Ri-inserita in fondo: è la mossa che rende l'ordine una LRU.
|
|
370
|
+
voci.delete(chiave);
|
|
371
|
+
voci.set(chiave, voce);
|
|
372
|
+
conto.served += 1;
|
|
373
|
+
return { value: /** @type {T} */ (voce.value), fromCache: true, key: chiave };
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const giaInVolo = inVolo.get(chiave);
|
|
377
|
+
if (giaInVolo) {
|
|
378
|
+
conto.coalesced += 1;
|
|
379
|
+
// Il primo paga, gli altri condividono la risposta. Se il primo fallisce
|
|
380
|
+
// falliscono anche loro: è la stessa chiamata, e fingere il contrario
|
|
381
|
+
// vorrebbe dire chiamare di nuovo un fornitore che ha appena detto di no.
|
|
382
|
+
return { value: /** @type {T} */ (await giaInVolo), fromCache: true, key: chiave };
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
conto.fetched += 1;
|
|
386
|
+
const promessa = (async () => produttore())();
|
|
387
|
+
inVolo.set(chiave, promessa);
|
|
388
|
+
try {
|
|
389
|
+
const valore = await promessa;
|
|
390
|
+
// Solo le risposte riuscite si conservano, come Hermes. `null`/`undefined`
|
|
391
|
+
// è «non si è potuto leggere»: un fallimento si ritenta, non si incide.
|
|
392
|
+
if (valore === null || valore === undefined) conto.failed += 1;
|
|
393
|
+
else conserva(chiave, valore);
|
|
394
|
+
return { value: /** @type {T} */ (valore), fromCache: false, key: chiave };
|
|
395
|
+
} catch (rotto) {
|
|
396
|
+
conto.failed += 1;
|
|
397
|
+
throw rotto;
|
|
398
|
+
} finally {
|
|
399
|
+
inVolo.delete(chiave);
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
|
|
403
|
+
/** @returns {TalosResearchCacheStats} */
|
|
404
|
+
stats() {
|
|
405
|
+
return { ...conto, entries: voci.size, chars: caratteri };
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Il contratto per chi persiste: un oggetto JSON-serializzabile, che
|
|
410
|
+
* l'orchestratore salva accanto al giornale. ⛔ Questo modulo non scrive
|
|
411
|
+
* niente su disco.
|
|
412
|
+
*
|
|
413
|
+
* @returns {TalosResearchCacheSnapshot}
|
|
414
|
+
*/
|
|
415
|
+
snapshot() {
|
|
416
|
+
return {
|
|
417
|
+
version: TALOS_RESEARCH_CACHE_SNAPSHOT_VERSION,
|
|
418
|
+
savedAt: adesso(),
|
|
419
|
+
entries: [...voci.entries()].map(([key, voce]) => ({
|
|
420
|
+
key,
|
|
421
|
+
storedAt: voce.storedAt,
|
|
422
|
+
chars: voce.chars,
|
|
423
|
+
value: voce.value,
|
|
424
|
+
})),
|
|
425
|
+
};
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Rimette dentro ciò che una corsa in pausa aveva già pagato.
|
|
430
|
+
*
|
|
431
|
+
* ⛔ Tollerante in lettura, come il giornale: una versione che non conosce
|
|
432
|
+
* si ignora, una voce malformata si salta. Un formato più nuovo non deve
|
|
433
|
+
* impedire a una ricerca di RIPARTIRE — al massimo la fa ripagare.
|
|
434
|
+
*
|
|
435
|
+
* @param {TalosResearchCacheSnapshot | null | undefined} istantanea
|
|
436
|
+
* @returns {number} quante voci sono rientrate
|
|
437
|
+
*/
|
|
438
|
+
restore(istantanea) {
|
|
439
|
+
if (!istantanea || istantanea.version !== TALOS_RESEARCH_CACHE_SNAPSHOT_VERSION) return 0;
|
|
440
|
+
if (!Array.isArray(istantanea.entries)) return 0;
|
|
441
|
+
let rientrate = 0;
|
|
442
|
+
for (const voce of istantanea.entries) {
|
|
443
|
+
if (!voce || typeof voce.key !== 'string') continue;
|
|
444
|
+
if (voce.value === null || voce.value === undefined) continue;
|
|
445
|
+
const peso = typeof voce.chars === 'number' && voce.chars >= 0 ? voce.chars : pesa(voce.value);
|
|
446
|
+
if (peso > maxPerVoce) { conto.oversize += 1; continue; }
|
|
447
|
+
togli(voce.key);
|
|
448
|
+
voci.set(voce.key, {
|
|
449
|
+
storedAt: typeof voce.storedAt === 'number' ? voce.storedAt : adesso(),
|
|
450
|
+
chars: peso,
|
|
451
|
+
value: voce.value,
|
|
452
|
+
});
|
|
453
|
+
caratteri += peso;
|
|
454
|
+
rientrate += 1;
|
|
455
|
+
}
|
|
456
|
+
sfratta();
|
|
457
|
+
return rientrate;
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
clear() {
|
|
461
|
+
voci.clear();
|
|
462
|
+
caratteri = 0;
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { talosResearchIndependentSources } from './independence.mjs'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* PORTO FEDELE di AVM/mobile/src/lib/research/researchFidelity.ts (115 righe, 11/09/2026).
|
|
5
|
+
*
|
|
6
|
+
* ⛔ Di `verification.mjs` (porto di `researchVerification.ts`, altra sessione)
|
|
7
|
+
* servono qui solo i TIPI: in JSDoc non producono import a runtime, quindi
|
|
8
|
+
* questo file gira anche prima che quello esista.
|
|
9
|
+
*
|
|
10
|
+
* ⛔⛔ FEDELTA-05 — le quattro misure, e il divieto di darne una quando non c'è.
|
|
11
|
+
*
|
|
12
|
+
* ## Da dove vengono, misurato il 2026-08-20
|
|
13
|
+
*
|
|
14
|
+
* Ricerca sui benchmark 2026 per gli agenti di ricerca profonda — DeepResearch
|
|
15
|
+
* Bench, TRACE, e il lavoro sull'attribuzione delle fonti. Le dimensioni su cui
|
|
16
|
+
* si giudica un rapporto sono **copertura**, **fedeltà delle citazioni**,
|
|
17
|
+
* **ancoraggio delle affermazioni**, e quante **prove distinte** ci sono
|
|
18
|
+
* davvero — che conta quanto le altre tre, e nessuno la mostra.
|
|
19
|
+
*
|
|
20
|
+
* ⛔ La stessa ricerca dice perché una misura del genere invecchia: la metrica
|
|
21
|
+
* FACT è considerata inaffidabile per la riproducibilità **perché le pagine
|
|
22
|
+
* citate diventano irraggiungibili nel tempo**. Da qui due conseguenze che
|
|
23
|
+
* stanno nel codice e non in un commento: ogni punteggio esce con la sua
|
|
24
|
+
* **data**, e accanto a queste misure ci vuole la tenuta nel tempo.
|
|
25
|
+
*
|
|
26
|
+
* ## ⛔ La regola che conta più delle formule
|
|
27
|
+
*
|
|
28
|
+
* Un numero su cui nessuno ha giudicato non è un numero basso: **non è un
|
|
29
|
+
* numero**. Una ricerca senza giudice non produce «40%», produce «non
|
|
30
|
+
* verificata» — perché un 40% viene letto come una misura, e sarebbe una
|
|
31
|
+
* misura di niente. Per questo ogni quota è `number | null`, e il `null` non è
|
|
32
|
+
* un valore mancante: è l'unica risposta onesta.
|
|
33
|
+
*
|
|
34
|
+
* ⛔ Il conteggio delle fonti indipendenti fa eccezione, e la ragione è che non
|
|
35
|
+
* dipende dal giudice: si vede dagli indirizzi. Una ricerca non verificata può
|
|
36
|
+
* comunque dire quante prove distinte ha raccolto.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @import { TalosResearchVerifiedClaim } from './verification.mjs'
|
|
41
|
+
* @import { TalosResearchSourceOrigin } from './independence.mjs'
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {object} TalosResearchFidelityInput
|
|
46
|
+
* @property {readonly TalosResearchVerifiedClaim[]} claims
|
|
47
|
+
* @property {readonly TalosResearchSourceOrigin[]} sources
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @typedef {object} TalosResearchFidelity
|
|
52
|
+
* @property {boolean} verified Falso quando nessuno ha giudicato: allora le quote sono tutte `null`.
|
|
53
|
+
* @property {number | null} coverage Quota di affermazioni su cui un giudizio è arrivato.
|
|
54
|
+
* @property {number | null} citationFaithfulness Quota di affermazioni il cui passaggio è stato ritrovato nella pagina.
|
|
55
|
+
* @property {number | null} claimGroundedness Quanto le affermazioni giudicate reggono davvero: piena 1, parziale 0,5.
|
|
56
|
+
* @property {number} independentSources Prove distinte, non URL. Si conta anche senza giudice.
|
|
57
|
+
* @property {string | null} measuredAt ⛔ Quando: un punteggio senza data è una promessa che scade in silenzio.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* ⛔ Una parziale vale MEZZA, e non è una convenzione arbitraria.
|
|
62
|
+
*
|
|
63
|
+
* Contarla come una sostenuta gonfierebbe il rapporto proprio dove è più
|
|
64
|
+
* fragile; contarla come zero cancellerebbe una verifica che è riuscita a metà,
|
|
65
|
+
* e spingerebbe a non usare mai «parziale» — cioè a perdere la distinzione più
|
|
66
|
+
* utile che abbiamo.
|
|
67
|
+
*
|
|
68
|
+
* @type {Record<string, number>}
|
|
69
|
+
*/
|
|
70
|
+
const PESO = { yes: 1, partial: 0.5, no: 0, unchecked: 0 }
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {TalosResearchFidelityInput} input
|
|
74
|
+
* @returns {TalosResearchFidelity}
|
|
75
|
+
*/
|
|
76
|
+
export function talosResearchFidelity(input) {
|
|
77
|
+
const indipendenti = talosResearchIndependentSources(input.sources)
|
|
78
|
+
const totali = input.claims.length
|
|
79
|
+
const giudicate = input.claims.filter((entry) => entry.checks.judge !== null)
|
|
80
|
+
|
|
81
|
+
if (totali === 0 || giudicate.length === 0) {
|
|
82
|
+
return {
|
|
83
|
+
verified: false,
|
|
84
|
+
coverage: null,
|
|
85
|
+
citationFaithfulness: null,
|
|
86
|
+
claimGroundedness: null,
|
|
87
|
+
independentSources: indipendenti.independent,
|
|
88
|
+
measuredAt: null,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ⛔ Il passaggio conta come citazione solo se è stato ritrovato NELLA
|
|
93
|
+
// pagina: uno preso da uno snippet di ricerca non è la fonte, è il modo in
|
|
94
|
+
// cui il motore l'ha riassunta, e un `missing` non è una citazione affatto.
|
|
95
|
+
const conPassaggio = input.claims.filter(
|
|
96
|
+
(entry) => entry.checks.resolved === 'page' && entry.checks.quotePresent,
|
|
97
|
+
).length
|
|
98
|
+
|
|
99
|
+
const peso = giudicate.reduce(
|
|
100
|
+
(somma, entry) => somma + (PESO[entry.checks.claimSupported] ?? 0),
|
|
101
|
+
0,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
* La data è la PIÙ RECENTE fra i giudizi: è il momento in cui questo
|
|
106
|
+
* punteggio ha smesso di essere aggiornato, ed è quello che serve sapere
|
|
107
|
+
* per decidere se rileggerlo.
|
|
108
|
+
*/
|
|
109
|
+
const date = giudicate
|
|
110
|
+
.map((entry) => entry.checks.judgedAt)
|
|
111
|
+
.filter((quando) => typeof quando === 'string' && quando.length > 0)
|
|
112
|
+
.sort()
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
verified: true,
|
|
116
|
+
coverage: giudicate.length / totali,
|
|
117
|
+
citationFaithfulness: conPassaggio / totali,
|
|
118
|
+
claimGroundedness: peso / giudicate.length,
|
|
119
|
+
independentSources: indipendenti.independent,
|
|
120
|
+
measuredAt: date.at(-1) ?? null,
|
|
121
|
+
}
|
|
122
|
+
}
|