@vibesdotdev/docs 0.0.0-stage → 1.0.0-rc.2
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/LICENSE +18 -0
- package/README.md +74 -2
- package/dist/cli/cli.plugin.d.ts +14 -0
- package/dist/cli/cli.plugin.d.ts.map +1 -0
- package/dist/cli/cli.plugin.js +57 -0
- package/dist/cli/cli.plugin.js.map +1 -0
- package/dist/cli/commands/docs.list.command.descriptor.d.ts +33 -0
- package/dist/cli/commands/docs.list.command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/docs.list.command.descriptor.js +34 -0
- package/dist/cli/commands/docs.list.command.descriptor.js.map +1 -0
- package/dist/cli/commands/docs.list.command.impl.d.ts +25 -0
- package/dist/cli/commands/docs.list.command.impl.d.ts.map +1 -0
- package/dist/cli/commands/docs.list.command.impl.js +87 -0
- package/dist/cli/commands/docs.list.command.impl.js.map +1 -0
- package/dist/cli/commands/docs.show.command.descriptor.d.ts +44 -0
- package/dist/cli/commands/docs.show.command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/docs.show.command.descriptor.js +48 -0
- package/dist/cli/commands/docs.show.command.descriptor.js.map +1 -0
- package/dist/cli/commands/docs.show.command.impl.d.ts +26 -0
- package/dist/cli/commands/docs.show.command.impl.d.ts.map +1 -0
- package/dist/cli/commands/docs.show.command.impl.js +82 -0
- package/dist/cli/commands/docs.show.command.impl.js.map +1 -0
- package/dist/cli/commands/generate/docs.generate.cli-command.descriptor.d.ts +4 -0
- package/dist/cli/commands/generate/docs.generate.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/generate/docs.generate.cli-command.descriptor.js +58 -0
- package/dist/cli/commands/generate/docs.generate.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/generate/docs.generate.cli-command.impl.d.ts +24 -0
- package/dist/cli/commands/generate/docs.generate.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/generate/docs.generate.cli-command.impl.js +283 -0
- package/dist/cli/commands/generate/docs.generate.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/man/man.cli-command.descriptor.d.ts +4 -0
- package/dist/cli/commands/man/man.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/man/man.cli-command.descriptor.js +32 -0
- package/dist/cli/commands/man/man.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/man/man.cli-command.impl.d.ts +23 -0
- package/dist/cli/commands/man/man.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/man/man.cli-command.impl.js +22 -0
- package/dist/cli/commands/man/man.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/open/docs.open.cli-command.descriptor.d.ts +4 -0
- package/dist/cli/commands/open/docs.open.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/open/docs.open.cli-command.descriptor.js +18 -0
- package/dist/cli/commands/open/docs.open.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/open/docs.open.cli-command.impl.d.ts +14 -0
- package/dist/cli/commands/open/docs.open.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/open/docs.open.cli-command.impl.js +52 -0
- package/dist/cli/commands/open/docs.open.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/search.command.descriptor.d.ts +36 -0
- package/dist/cli/commands/search.command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/search.command.descriptor.js +35 -0
- package/dist/cli/commands/search.command.descriptor.js.map +1 -0
- package/dist/cli/commands/search.command.impl.d.ts +25 -0
- package/dist/cli/commands/search.command.impl.d.ts.map +1 -0
- package/dist/cli/commands/search.command.impl.js +113 -0
- package/dist/cli/commands/search.command.impl.js.map +1 -0
- package/dist/cli/directives/card.d.ts +11 -0
- package/dist/cli/directives/card.d.ts.map +1 -0
- package/dist/cli/directives/card.js +18 -0
- package/dist/cli/directives/card.js.map +1 -0
- package/dist/cli/directives/descriptor.d.ts +11 -0
- package/dist/cli/directives/descriptor.d.ts.map +1 -0
- package/dist/cli/directives/descriptor.js +20 -0
- package/dist/cli/directives/descriptor.js.map +1 -0
- package/dist/cli/directives/endpoint.d.ts +8 -0
- package/dist/cli/directives/endpoint.d.ts.map +1 -0
- package/dist/cli/directives/endpoint.js +31 -0
- package/dist/cli/directives/endpoint.js.map +1 -0
- package/dist/cli/directives/index.d.ts +9 -0
- package/dist/cli/directives/index.d.ts.map +1 -0
- package/dist/cli/directives/index.js +37 -0
- package/dist/cli/directives/index.js.map +1 -0
- package/dist/cli/directives/install.d.ts +12 -0
- package/dist/cli/directives/install.d.ts.map +1 -0
- package/dist/cli/directives/install.js +27 -0
- package/dist/cli/directives/install.js.map +1 -0
- package/dist/cli/directives/shell.d.ts +10 -0
- package/dist/cli/directives/shell.d.ts.map +1 -0
- package/dist/cli/directives/shell.js +16 -0
- package/dist/cli/directives/shell.js.map +1 -0
- package/dist/cli/directives/usage.d.ts +9 -0
- package/dist/cli/directives/usage.d.ts.map +1 -0
- package/dist/cli/directives/usage.js +13 -0
- package/dist/cli/directives/usage.js.map +1 -0
- package/dist/cli/docs/docs.cli.docs.descriptor.d.ts +22 -0
- package/dist/cli/docs/docs.cli.docs.descriptor.d.ts.map +1 -0
- package/dist/cli/docs/docs.cli.docs.descriptor.js +92 -0
- package/dist/cli/docs/docs.cli.docs.descriptor.js.map +1 -0
- package/dist/cli/docs.cli-group.descriptor.d.ts +4 -0
- package/dist/cli/docs.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/docs.cli-group.descriptor.js +11 -0
- package/dist/cli/docs.cli-group.descriptor.js.map +1 -0
- package/dist/client/citations.d.ts +11 -0
- package/dist/client/citations.d.ts.map +1 -0
- package/dist/client/citations.js +197 -0
- package/dist/client/citations.js.map +1 -0
- package/dist/client/docs-client.d.ts +51 -0
- package/dist/client/docs-client.d.ts.map +1 -0
- package/dist/client/docs-client.js +298 -0
- package/dist/client/docs-client.js.map +1 -0
- package/dist/client/index.d.ts +12 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +13 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/types.d.ts +26 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/config/docs.svelte.config.descriptor.d.ts +50 -0
- package/dist/config/docs.svelte.config.descriptor.d.ts.map +1 -0
- package/dist/config/docs.svelte.config.descriptor.js +46 -0
- package/dist/config/docs.svelte.config.descriptor.js.map +1 -0
- package/dist/config/documents.source-refresh.config.descriptor.d.ts +41 -0
- package/dist/config/documents.source-refresh.config.descriptor.d.ts.map +1 -0
- package/dist/config/documents.source-refresh.config.descriptor.js +39 -0
- package/dist/config/documents.source-refresh.config.descriptor.js.map +1 -0
- package/dist/directives/index.d.ts +4 -0
- package/dist/directives/index.d.ts.map +1 -0
- package/dist/directives/index.js +3 -0
- package/dist/directives/index.js.map +1 -0
- package/dist/directives/registry.d.ts +31 -0
- package/dist/directives/registry.d.ts.map +1 -0
- package/dist/directives/registry.js +65 -0
- package/dist/directives/registry.js.map +1 -0
- package/dist/directives/types.d.ts +33 -0
- package/dist/directives/types.d.ts.map +1 -0
- package/dist/directives/types.js +2 -0
- package/dist/directives/types.js.map +1 -0
- package/dist/docs/agent-voice.docs.descriptor.d.ts +30 -0
- package/dist/docs/agent-voice.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/agent-voice.docs.descriptor.js +107 -0
- package/dist/docs/agent-voice.docs.descriptor.js.map +1 -0
- package/dist/docs/charts.usage.docs.descriptor.d.ts +27 -0
- package/dist/docs/charts.usage.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/charts.usage.docs.descriptor.js +90 -0
- package/dist/docs/charts.usage.docs.descriptor.js.map +1 -0
- package/dist/docs/command-palette.actions.docs.descriptor.d.ts +25 -0
- package/dist/docs/command-palette.actions.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/command-palette.actions.docs.descriptor.js +80 -0
- package/dist/docs/command-palette.actions.docs.descriptor.js.map +1 -0
- package/dist/docs/docs.directives.docs.descriptor.d.ts +22 -0
- package/dist/docs/docs.directives.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/docs.directives.docs.descriptor.js +104 -0
- package/dist/docs/docs.directives.docs.descriptor.js.map +1 -0
- package/dist/docs/docs.topics.docs.descriptor.d.ts +22 -0
- package/dist/docs/docs.topics.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/docs.topics.docs.descriptor.js +90 -0
- package/dist/docs/docs.topics.docs.descriptor.js.map +1 -0
- package/dist/docs/fleet-pairing-direct.docs.descriptor.d.ts +30 -0
- package/dist/docs/fleet-pairing-direct.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/fleet-pairing-direct.docs.descriptor.js +93 -0
- package/dist/docs/fleet-pairing-direct.docs.descriptor.js.map +1 -0
- package/dist/docs/fleet-pairing-mdns.docs.descriptor.d.ts +30 -0
- package/dist/docs/fleet-pairing-mdns.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/fleet-pairing-mdns.docs.descriptor.js +88 -0
- package/dist/docs/fleet-pairing-mdns.docs.descriptor.js.map +1 -0
- package/dist/docs/fleet-pairing-platform.docs.descriptor.d.ts +30 -0
- package/dist/docs/fleet-pairing-platform.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/fleet-pairing-platform.docs.descriptor.js +101 -0
- package/dist/docs/fleet-pairing-platform.docs.descriptor.js.map +1 -0
- package/dist/docs/fleet-pairing.docs.descriptor.d.ts +28 -0
- package/dist/docs/fleet-pairing.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/fleet-pairing.docs.descriptor.js +89 -0
- package/dist/docs/fleet-pairing.docs.descriptor.js.map +1 -0
- package/dist/docs/getting-started-cli.docs.descriptor.d.ts +4 -0
- package/dist/docs/getting-started-cli.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/getting-started-cli.docs.descriptor.js +141 -0
- package/dist/docs/getting-started-cli.docs.descriptor.js.map +1 -0
- package/dist/docs/getting-started.concepts.docs.descriptor.d.ts +4 -0
- package/dist/docs/getting-started.concepts.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/getting-started.concepts.docs.descriptor.js +100 -0
- package/dist/docs/getting-started.concepts.docs.descriptor.js.map +1 -0
- package/dist/docs/getting-started.docs.descriptor.d.ts +4 -0
- package/dist/docs/getting-started.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/getting-started.docs.descriptor.js +63 -0
- package/dist/docs/getting-started.docs.descriptor.js.map +1 -0
- package/dist/docs/getting-started.first-query.docs.descriptor.d.ts +4 -0
- package/dist/docs/getting-started.first-query.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/getting-started.first-query.docs.descriptor.js +95 -0
- package/dist/docs/getting-started.first-query.docs.descriptor.js.map +1 -0
- package/dist/docs/guided-flows.flows.docs.descriptor.d.ts +22 -0
- package/dist/docs/guided-flows.flows.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/guided-flows.flows.docs.descriptor.js +114 -0
- package/dist/docs/guided-flows.flows.docs.descriptor.js.map +1 -0
- package/dist/docs/runtime-rpc-relay.docs.descriptor.d.ts +19 -0
- package/dist/docs/runtime-rpc-relay.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/runtime-rpc-relay.docs.descriptor.js +140 -0
- package/dist/docs/runtime-rpc-relay.docs.descriptor.js.map +1 -0
- package/dist/docs/tutorials.ai-text-generation.docs.descriptor.d.ts +4 -0
- package/dist/docs/tutorials.ai-text-generation.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/tutorials.ai-text-generation.docs.descriptor.js +115 -0
- package/dist/docs/tutorials.ai-text-generation.docs.descriptor.js.map +1 -0
- package/dist/docs/tutorials.build-an-app.docs.descriptor.d.ts +4 -0
- package/dist/docs/tutorials.build-an-app.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/tutorials.build-an-app.docs.descriptor.js +172 -0
- package/dist/docs/tutorials.build-an-app.docs.descriptor.js.map +1 -0
- package/dist/docs/tutorials.crud-collection.docs.descriptor.d.ts +4 -0
- package/dist/docs/tutorials.crud-collection.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/tutorials.crud-collection.docs.descriptor.js +142 -0
- package/dist/docs/tutorials.crud-collection.docs.descriptor.js.map +1 -0
- package/dist/docs/tutorials.docs.descriptor.d.ts +4 -0
- package/dist/docs/tutorials.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/tutorials.docs.descriptor.js +52 -0
- package/dist/docs/tutorials.docs.descriptor.js.map +1 -0
- package/dist/docs/tutorials.runtime-plugin.docs.descriptor.d.ts +4 -0
- package/dist/docs/tutorials.runtime-plugin.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/tutorials.runtime-plugin.docs.descriptor.js +121 -0
- package/dist/docs/tutorials.runtime-plugin.docs.descriptor.js.map +1 -0
- package/dist/docs.plugin.d.ts +12 -0
- package/dist/docs.plugin.d.ts.map +1 -0
- package/dist/docs.plugin.js +118 -0
- package/dist/docs.plugin.js.map +1 -0
- package/dist/documents/documents.cloud.plugin.d.ts +3 -0
- package/dist/documents/documents.cloud.plugin.d.ts.map +1 -0
- package/dist/documents/documents.cloud.plugin.js +26 -0
- package/dist/documents/documents.cloud.plugin.js.map +1 -0
- package/dist/documents/documents.consumer.plugin.d.ts +3 -0
- package/dist/documents/documents.consumer.plugin.d.ts.map +1 -0
- package/dist/documents/documents.consumer.plugin.js +26 -0
- package/dist/documents/documents.consumer.plugin.js.map +1 -0
- package/dist/documents/documents.plugin.d.ts +3 -0
- package/dist/documents/documents.plugin.d.ts.map +1 -0
- package/dist/documents/documents.plugin.js +33 -0
- package/dist/documents/documents.plugin.js.map +1 -0
- package/dist/documents/docx/client.d.ts +56 -0
- package/dist/documents/docx/client.d.ts.map +1 -0
- package/dist/documents/docx/client.js +90 -0
- package/dist/documents/docx/client.js.map +1 -0
- package/dist/documents/docx/extract.d.ts +12 -0
- package/dist/documents/docx/extract.d.ts.map +1 -0
- package/dist/documents/docx/extract.js +62 -0
- package/dist/documents/docx/extract.js.map +1 -0
- package/dist/documents/docx/generator.d.ts +49 -0
- package/dist/documents/docx/generator.d.ts.map +1 -0
- package/dist/documents/docx/generator.js +101 -0
- package/dist/documents/docx/generator.js.map +1 -0
- package/dist/documents/docx/index.d.ts +19 -0
- package/dist/documents/docx/index.d.ts.map +1 -0
- package/dist/documents/docx/index.js +16 -0
- package/dist/documents/docx/index.js.map +1 -0
- package/dist/documents/docx/kinds.d.ts +10 -0
- package/dist/documents/docx/kinds.d.ts.map +1 -0
- package/dist/documents/docx/kinds.js +11 -0
- package/dist/documents/docx/kinds.js.map +1 -0
- package/dist/documents/docx/plugin/docx.plugin.d.ts +9 -0
- package/dist/documents/docx/plugin/docx.plugin.d.ts.map +1 -0
- package/dist/documents/docx/plugin/docx.plugin.js +35 -0
- package/dist/documents/docx/plugin/docx.plugin.js.map +1 -0
- package/dist/documents/docx/schemas/generator.d.ts +10 -0
- package/dist/documents/docx/schemas/generator.d.ts.map +1 -0
- package/dist/documents/docx/schemas/generator.js +2 -0
- package/dist/documents/docx/schemas/generator.js.map +1 -0
- package/dist/documents/docx/schemas/index.d.ts +4 -0
- package/dist/documents/docx/schemas/index.d.ts.map +1 -0
- package/dist/documents/docx/schemas/index.js +2 -0
- package/dist/documents/docx/schemas/index.js.map +1 -0
- package/dist/documents/docx/schemas/runtime.d.ts +68 -0
- package/dist/documents/docx/schemas/runtime.d.ts.map +1 -0
- package/dist/documents/docx/schemas/runtime.js +30 -0
- package/dist/documents/docx/schemas/runtime.js.map +1 -0
- package/dist/documents/docx/schemas/template-registry.d.ts +21 -0
- package/dist/documents/docx/schemas/template-registry.d.ts.map +1 -0
- package/dist/documents/docx/schemas/template-registry.js +2 -0
- package/dist/documents/docx/schemas/template-registry.js.map +1 -0
- package/dist/documents/docx/templates/index.d.ts +3 -0
- package/dist/documents/docx/templates/index.d.ts.map +1 -0
- package/dist/documents/docx/templates/index.js +2 -0
- package/dist/documents/docx/templates/index.js.map +1 -0
- package/dist/documents/docx/templates/loader.d.ts +20 -0
- package/dist/documents/docx/templates/loader.d.ts.map +1 -0
- package/dist/documents/docx/templates/loader.js +36 -0
- package/dist/documents/docx/templates/loader.js.map +1 -0
- package/dist/documents/docx/templates/types.d.ts +2 -0
- package/dist/documents/docx/templates/types.d.ts.map +1 -0
- package/dist/documents/docx/templates/types.js +2 -0
- package/dist/documents/docx/templates/types.js.map +1 -0
- package/dist/documents/index.d.ts +4 -0
- package/dist/documents/index.d.ts.map +1 -0
- package/dist/documents/index.js +4 -0
- package/dist/documents/index.js.map +1 -0
- package/dist/documents/outline/parse-outline.d.ts +132 -0
- package/dist/documents/outline/parse-outline.d.ts.map +1 -0
- package/dist/documents/outline/parse-outline.js +246 -0
- package/dist/documents/outline/parse-outline.js.map +1 -0
- package/dist/documents/plugin.d.ts +3 -0
- package/dist/documents/plugin.d.ts.map +1 -0
- package/dist/documents/plugin.js +13 -0
- package/dist/documents/plugin.js.map +1 -0
- package/dist/documents/presentations/capabilities/index.d.ts +3 -0
- package/dist/documents/presentations/capabilities/index.d.ts.map +1 -0
- package/dist/documents/presentations/capabilities/index.js +3 -0
- package/dist/documents/presentations/capabilities/index.js.map +1 -0
- package/dist/documents/presentations/capabilities/presentations.directory.impl.consumer.worker.d.ts +333 -0
- package/dist/documents/presentations/capabilities/presentations.directory.impl.consumer.worker.d.ts.map +1 -0
- package/dist/documents/presentations/capabilities/presentations.directory.impl.consumer.worker.js +101 -0
- package/dist/documents/presentations/capabilities/presentations.directory.impl.consumer.worker.js.map +1 -0
- package/dist/documents/presentations/capabilities/presentations.directory.kind.d.ts +65 -0
- package/dist/documents/presentations/capabilities/presentations.directory.kind.d.ts.map +1 -0
- package/dist/documents/presentations/capabilities/presentations.directory.kind.js +152 -0
- package/dist/documents/presentations/capabilities/presentations.directory.kind.js.map +1 -0
- package/dist/documents/presentations/capabilities/presentations.surface.kind.d.ts +68 -0
- package/dist/documents/presentations/capabilities/presentations.surface.kind.d.ts.map +1 -0
- package/dist/documents/presentations/capabilities/presentations.surface.kind.js +100 -0
- package/dist/documents/presentations/capabilities/presentations.surface.kind.js.map +1 -0
- package/dist/documents/presentations/client/contracts.d.ts +20 -0
- package/dist/documents/presentations/client/contracts.d.ts.map +1 -0
- package/dist/documents/presentations/client/contracts.js +2 -0
- package/dist/documents/presentations/client/contracts.js.map +1 -0
- package/dist/documents/presentations/client/index.d.ts +5 -0
- package/dist/documents/presentations/client/index.d.ts.map +1 -0
- package/dist/documents/presentations/client/index.js +5 -0
- package/dist/documents/presentations/client/index.js.map +1 -0
- package/dist/documents/presentations/client/presentations.runtime-client.descriptor.d.ts +4 -0
- package/dist/documents/presentations/client/presentations.runtime-client.descriptor.d.ts.map +1 -0
- package/dist/documents/presentations/client/presentations.runtime-client.descriptor.js +13 -0
- package/dist/documents/presentations/client/presentations.runtime-client.descriptor.js.map +1 -0
- package/dist/documents/presentations/client/presentations.runtime-client.impl.d.ts +711 -0
- package/dist/documents/presentations/client/presentations.runtime-client.impl.d.ts.map +1 -0
- package/dist/documents/presentations/client/presentations.runtime-client.impl.js +72 -0
- package/dist/documents/presentations/client/presentations.runtime-client.impl.js.map +1 -0
- package/dist/documents/presentations/docs/presentations.docs.descriptor.d.ts +4 -0
- package/dist/documents/presentations/docs/presentations.docs.descriptor.d.ts.map +1 -0
- package/dist/documents/presentations/docs/presentations.docs.descriptor.js +54 -0
- package/dist/documents/presentations/docs/presentations.docs.descriptor.js.map +1 -0
- package/dist/documents/presentations/index.d.ts +8 -0
- package/dist/documents/presentations/index.d.ts.map +1 -0
- package/dist/documents/presentations/index.js +8 -0
- package/dist/documents/presentations/index.js.map +1 -0
- package/dist/documents/presentations/presentations.consumer.plugin.d.ts +4 -0
- package/dist/documents/presentations/presentations.consumer.plugin.d.ts.map +1 -0
- package/dist/documents/presentations/presentations.consumer.plugin.js +16 -0
- package/dist/documents/presentations/presentations.consumer.plugin.js.map +1 -0
- package/dist/documents/presentations/presentations.plugin.d.ts +3 -0
- package/dist/documents/presentations/presentations.plugin.d.ts.map +1 -0
- package/dist/documents/presentations/presentations.plugin.js +48 -0
- package/dist/documents/presentations/presentations.plugin.js.map +1 -0
- package/dist/documents/presentations/review-read-authority.d.ts +117 -0
- package/dist/documents/presentations/review-read-authority.d.ts.map +1 -0
- package/dist/documents/presentations/review-read-authority.js +74 -0
- package/dist/documents/presentations/review-read-authority.js.map +1 -0
- package/dist/documents/presentations/schemas/index.d.ts +5 -0
- package/dist/documents/presentations/schemas/index.d.ts.map +1 -0
- package/dist/documents/presentations/schemas/index.js +5 -0
- package/dist/documents/presentations/schemas/index.js.map +1 -0
- package/dist/documents/presentations/schemas/owner.d.ts +28 -0
- package/dist/documents/presentations/schemas/owner.d.ts.map +1 -0
- package/dist/documents/presentations/schemas/owner.js +18 -0
- package/dist/documents/presentations/schemas/owner.js.map +1 -0
- package/dist/documents/presentations/schemas/request.d.ts +325 -0
- package/dist/documents/presentations/schemas/request.d.ts.map +1 -0
- package/dist/documents/presentations/schemas/request.js +169 -0
- package/dist/documents/presentations/schemas/request.js.map +1 -0
- package/dist/documents/presentations/schemas/review.d.ts +154 -0
- package/dist/documents/presentations/schemas/review.d.ts.map +1 -0
- package/dist/documents/presentations/schemas/review.js +83 -0
- package/dist/documents/presentations/schemas/review.js.map +1 -0
- package/dist/documents/presentations/schemas/surface.d.ts +315 -0
- package/dist/documents/presentations/schemas/surface.d.ts.map +1 -0
- package/dist/documents/presentations/schemas/surface.js +125 -0
- package/dist/documents/presentations/schemas/surface.js.map +1 -0
- package/dist/documents/presentations/state-machine.d.ts +36 -0
- package/dist/documents/presentations/state-machine.d.ts.map +1 -0
- package/dist/documents/presentations/state-machine.js +158 -0
- package/dist/documents/presentations/state-machine.js.map +1 -0
- package/dist/documents/presentations/storage/index.d.ts +3 -0
- package/dist/documents/presentations/storage/index.d.ts.map +1 -0
- package/dist/documents/presentations/storage/index.js +3 -0
- package/dist/documents/presentations/storage/index.js.map +1 -0
- package/dist/documents/presentations/storage/owner-app.d.ts +12 -0
- package/dist/documents/presentations/storage/owner-app.d.ts.map +1 -0
- package/dist/documents/presentations/storage/owner-app.js +43 -0
- package/dist/documents/presentations/storage/owner-app.js.map +1 -0
- package/dist/documents/presentations/storage/owner-transforms.d.ts +476 -0
- package/dist/documents/presentations/storage/owner-transforms.d.ts.map +1 -0
- package/dist/documents/presentations/storage/owner-transforms.js +77 -0
- package/dist/documents/presentations/storage/owner-transforms.js.map +1 -0
- package/dist/documents/presentations/storage/records.d.ts +227 -0
- package/dist/documents/presentations/storage/records.d.ts.map +1 -0
- package/dist/documents/presentations/storage/records.js +145 -0
- package/dist/documents/presentations/storage/records.js.map +1 -0
- package/dist/documents/presentations/tools/presentations.tool.descriptor.d.ts +543 -0
- package/dist/documents/presentations/tools/presentations.tool.descriptor.d.ts.map +1 -0
- package/dist/documents/presentations/tools/presentations.tool.descriptor.js +47 -0
- package/dist/documents/presentations/tools/presentations.tool.descriptor.js.map +1 -0
- package/dist/documents/presentations/tools/presentations.tool.impl.consumer.d.ts +8 -0
- package/dist/documents/presentations/tools/presentations.tool.impl.consumer.d.ts.map +1 -0
- package/dist/documents/presentations/tools/presentations.tool.impl.consumer.js +68 -0
- package/dist/documents/presentations/tools/presentations.tool.impl.consumer.js.map +1 -0
- package/dist/documents/presentations/tools/presentations.tool.schemas.d.ts +504 -0
- package/dist/documents/presentations/tools/presentations.tool.schemas.d.ts.map +1 -0
- package/dist/documents/presentations/tools/presentations.tool.schemas.js +76 -0
- package/dist/documents/presentations/tools/presentations.tool.schemas.js.map +1 -0
- package/dist/documents/render/grid.d.ts +96 -0
- package/dist/documents/render/grid.d.ts.map +1 -0
- package/dist/documents/render/grid.js +115 -0
- package/dist/documents/render/grid.js.map +1 -0
- package/dist/documents/render/index.d.ts +2 -0
- package/dist/documents/render/index.d.ts.map +1 -0
- package/dist/documents/render/index.js +2 -0
- package/dist/documents/render/index.js.map +1 -0
- package/dist/documents/render/render.impl.cloud.d.ts +25 -0
- package/dist/documents/render/render.impl.cloud.d.ts.map +1 -0
- package/dist/documents/render/render.impl.cloud.js +245 -0
- package/dist/documents/render/render.impl.cloud.js.map +1 -0
- package/dist/documents/render/render.impl.consumer.d.ts +35 -0
- package/dist/documents/render/render.impl.consumer.d.ts.map +1 -0
- package/dist/documents/render/render.impl.consumer.js +104 -0
- package/dist/documents/render/render.impl.consumer.js.map +1 -0
- package/dist/documents/render/render.interface.d.ts +147 -0
- package/dist/documents/render/render.interface.d.ts.map +1 -0
- package/dist/documents/render/render.interface.js +90 -0
- package/dist/documents/render/render.interface.js.map +1 -0
- package/dist/documents/schemas/ai-service-binding.schema.d.ts +11 -0
- package/dist/documents/schemas/ai-service-binding.schema.d.ts.map +1 -0
- package/dist/documents/schemas/ai-service-binding.schema.js +8 -0
- package/dist/documents/schemas/ai-service-binding.schema.js.map +1 -0
- package/dist/documents/schemas/document-read.schema.d.ts +107 -0
- package/dist/documents/schemas/document-read.schema.d.ts.map +1 -0
- package/dist/documents/schemas/document-read.schema.js +124 -0
- package/dist/documents/schemas/document-read.schema.js.map +1 -0
- package/dist/documents/schemas/document-view.schema.d.ts +74 -0
- package/dist/documents/schemas/document-view.schema.d.ts.map +1 -0
- package/dist/documents/schemas/document-view.schema.js +66 -0
- package/dist/documents/schemas/document-view.schema.js.map +1 -0
- package/dist/documents/schemas/index.d.ts +3 -0
- package/dist/documents/schemas/index.d.ts.map +1 -0
- package/dist/documents/schemas/index.js +3 -0
- package/dist/documents/schemas/index.js.map +1 -0
- package/dist/documents/schemas/page-cache.schema.d.ts +29 -0
- package/dist/documents/schemas/page-cache.schema.d.ts.map +1 -0
- package/dist/documents/schemas/page-cache.schema.js +50 -0
- package/dist/documents/schemas/page-cache.schema.js.map +1 -0
- package/dist/documents/storage/index.d.ts +3 -0
- package/dist/documents/storage/index.d.ts.map +1 -0
- package/dist/documents/storage/index.js +2 -0
- package/dist/documents/storage/index.js.map +1 -0
- package/dist/documents/storage/page-cache.descriptor.d.ts +17 -0
- package/dist/documents/storage/page-cache.descriptor.d.ts.map +1 -0
- package/dist/documents/storage/page-cache.descriptor.js +45 -0
- package/dist/documents/storage/page-cache.descriptor.js.map +1 -0
- package/dist/documents/tools/descriptors.d.ts +248 -0
- package/dist/documents/tools/descriptors.d.ts.map +1 -0
- package/dist/documents/tools/descriptors.js +78 -0
- package/dist/documents/tools/descriptors.js.map +1 -0
- package/dist/documents/tools/document-read-loop-guard.d.ts +61 -0
- package/dist/documents/tools/document-read-loop-guard.d.ts.map +1 -0
- package/dist/documents/tools/document-read-loop-guard.js +314 -0
- package/dist/documents/tools/document-read-loop-guard.js.map +1 -0
- package/dist/documents/tools/document-read.impl.d.ts +77 -0
- package/dist/documents/tools/document-read.impl.d.ts.map +1 -0
- package/dist/documents/tools/document-read.impl.js +1139 -0
- package/dist/documents/tools/document-read.impl.js.map +1 -0
- package/dist/documents/tools/document-view.impl.d.ts +45 -0
- package/dist/documents/tools/document-view.impl.d.ts.map +1 -0
- package/dist/documents/tools/document-view.impl.js +168 -0
- package/dist/documents/tools/document-view.impl.js.map +1 -0
- package/dist/documents/tools/index.d.ts +3 -0
- package/dist/documents/tools/index.d.ts.map +1 -0
- package/dist/documents/tools/index.js +6 -0
- package/dist/documents/tools/index.js.map +1 -0
- package/dist/documents/tools/source-refresh.d.ts +33 -0
- package/dist/documents/tools/source-refresh.d.ts.map +1 -0
- package/dist/documents/tools/source-refresh.js +127 -0
- package/dist/documents/tools/source-refresh.js.map +1 -0
- package/dist/documents/tools/unavailable.impl.d.ts +5 -0
- package/dist/documents/tools/unavailable.impl.d.ts.map +1 -0
- package/dist/documents/tools/unavailable.impl.js +12 -0
- package/dist/documents/tools/unavailable.impl.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/descriptors/vibes-platform.prompt.descriptor.d.ts +113 -0
- package/dist/prompts/descriptors/vibes-platform.prompt.descriptor.d.ts.map +1 -0
- package/dist/prompts/descriptors/vibes-platform.prompt.descriptor.js +35 -0
- package/dist/prompts/descriptors/vibes-platform.prompt.descriptor.js.map +1 -0
- package/dist/render/ansi.d.ts +86 -0
- package/dist/render/ansi.d.ts.map +1 -0
- package/dist/render/ansi.js +125 -0
- package/dist/render/ansi.js.map +1 -0
- package/dist/render/frontmatter.d.ts +21 -0
- package/dist/render/frontmatter.d.ts.map +1 -0
- package/dist/render/frontmatter.js +57 -0
- package/dist/render/frontmatter.js.map +1 -0
- package/dist/render/index.d.ts +10 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +6 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/parse.d.ts +29 -0
- package/dist/render/parse.d.ts.map +1 -0
- package/dist/render/parse.js +145 -0
- package/dist/render/parse.js.map +1 -0
- package/dist/render/sections.d.ts +24 -0
- package/dist/render/sections.d.ts.map +1 -0
- package/dist/render/sections.js +76 -0
- package/dist/render/sections.js.map +1 -0
- package/dist/render/terminal.d.ts +15 -0
- package/dist/render/terminal.d.ts.map +1 -0
- package/dist/render/terminal.js +293 -0
- package/dist/render/terminal.js.map +1 -0
- package/dist/runbooks/index.d.ts +4 -0
- package/dist/runbooks/index.d.ts.map +1 -0
- package/dist/runbooks/index.js +3 -0
- package/dist/runbooks/index.js.map +1 -0
- package/dist/runbooks/runbooks.plugin.d.ts +3 -0
- package/dist/runbooks/runbooks.plugin.d.ts.map +1 -0
- package/dist/runbooks/runbooks.plugin.js +3 -0
- package/dist/runbooks/runbooks.plugin.js.map +1 -0
- package/dist/schemas/citations.schema.d.ts +21 -0
- package/dist/schemas/citations.schema.d.ts.map +1 -0
- package/dist/schemas/citations.schema.js +17 -0
- package/dist/schemas/citations.schema.js.map +1 -0
- package/dist/schemas/index.d.ts +4 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +3 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/topic.schema.d.ts +179 -0
- package/dist/schemas/topic.schema.d.ts.map +1 -0
- package/dist/schemas/topic.schema.js +15 -0
- package/dist/schemas/topic.schema.js.map +1 -0
- package/dist/svelte/build/highlight.d.ts +33 -0
- package/dist/svelte/build/highlight.d.ts.map +1 -0
- package/dist/svelte/build/highlight.js +95 -0
- package/dist/svelte/build/topic-index.d.ts +96 -0
- package/dist/svelte/build/topic-index.d.ts.map +1 -0
- package/dist/svelte/build/topic-index.js +247 -0
- package/dist/svelte/context.d.ts +12 -0
- package/dist/svelte/context.d.ts.map +1 -0
- package/dist/svelte/context.js +16 -0
- package/dist/svelte/docs-origin.d.ts +14 -0
- package/dist/svelte/docs-origin.d.ts.map +1 -0
- package/dist/svelte/docs-origin.js +49 -0
- package/dist/svelte/docs-svelte.plugin.d.ts +121 -0
- package/dist/svelte/docs-svelte.plugin.d.ts.map +1 -0
- package/dist/svelte/docs-svelte.plugin.js +35 -0
- package/dist/svelte/documents/presentations/components/PresentationMonitor.svelte +261 -0
- package/dist/svelte/documents/presentations/components/PresentationMonitor.svelte.d.ts +16 -0
- package/dist/svelte/documents/presentations/components/PresentationMonitor.svelte.d.ts.map +1 -0
- package/dist/svelte/documents/presentations/index.d.ts +3 -0
- package/dist/svelte/documents/presentations/index.d.ts.map +1 -0
- package/dist/svelte/documents/presentations/index.js +2 -0
- package/dist/svelte/documents/presentations/monitor-state.d.ts +17 -0
- package/dist/svelte/documents/presentations/monitor-state.d.ts.map +1 -0
- package/dist/svelte/documents/presentations/monitor-state.js +38 -0
- package/dist/svelte/index.d.ts +20 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +16 -0
- package/dist/svelte/loaders.d.ts +57 -0
- package/dist/svelte/loaders.d.ts.map +1 -0
- package/dist/svelte/loaders.js +74 -0
- package/dist/svelte/state.svelte.d.ts +366 -0
- package/dist/svelte/state.svelte.d.ts.map +1 -0
- package/dist/svelte/state.svelte.js +155 -0
- package/dist/svelte/styles.css +8 -0
- package/dist/svelte/tool-widgets/DocsToolCard.svelte +41 -0
- package/dist/svelte/tool-widgets/DocsToolCard.svelte.d.ts +5 -0
- package/dist/svelte/tool-widgets/DocsToolCard.svelte.d.ts.map +1 -0
- package/dist/svelte/tool-widgets/DocumentReadToolCard.svelte +28 -0
- package/dist/svelte/tool-widgets/DocumentReadToolCard.svelte.d.ts +8 -0
- package/dist/svelte/tool-widgets/DocumentReadToolCard.svelte.d.ts.map +1 -0
- package/dist/svelte/tool-widgets/PresentationsToolCard.svelte +25 -0
- package/dist/svelte/tool-widgets/PresentationsToolCard.svelte.d.ts +8 -0
- package/dist/svelte/tool-widgets/PresentationsToolCard.svelte.d.ts.map +1 -0
- package/dist/svelte/tool-widgets/RunbookToolCard.svelte +29 -0
- package/dist/svelte/tool-widgets/RunbookToolCard.svelte.d.ts +8 -0
- package/dist/svelte/tool-widgets/RunbookToolCard.svelte.d.ts.map +1 -0
- package/dist/svelte/tool-widgets/index.d.ts +7 -0
- package/dist/svelte/tool-widgets/index.d.ts.map +1 -0
- package/dist/svelte/tool-widgets/index.js +5 -0
- package/dist/svelte/tool-widgets/models.d.ts +47 -0
- package/dist/svelte/tool-widgets/models.d.ts.map +1 -0
- package/dist/svelte/tool-widgets/models.js +112 -0
- package/dist/svelte/ui/DocViewer.svelte +122 -0
- package/dist/svelte/ui/DocViewer.svelte.d.ts +17 -0
- package/dist/svelte/ui/DocViewer.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/DocsLoader.svelte +37 -0
- package/dist/svelte/ui/DocsLoader.svelte.d.ts +21 -0
- package/dist/svelte/ui/DocsLoader.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/DocsSearch.svelte +129 -0
- package/dist/svelte/ui/DocsSearch.svelte.d.ts +15 -0
- package/dist/svelte/ui/DocsSearch.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/directives/Card.svelte +61 -0
- package/dist/svelte/ui/directives/Card.svelte.d.ts +8 -0
- package/dist/svelte/ui/directives/Card.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/directives/Descriptor.svelte +73 -0
- package/dist/svelte/ui/directives/Descriptor.svelte.d.ts +8 -0
- package/dist/svelte/ui/directives/Descriptor.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/directives/DirectiveDispatch.svelte +45 -0
- package/dist/svelte/ui/directives/DirectiveDispatch.svelte.d.ts +8 -0
- package/dist/svelte/ui/directives/DirectiveDispatch.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/directives/Endpoint.svelte +68 -0
- package/dist/svelte/ui/directives/Endpoint.svelte.d.ts +8 -0
- package/dist/svelte/ui/directives/Endpoint.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/directives/Install.svelte +112 -0
- package/dist/svelte/ui/directives/Install.svelte.d.ts +8 -0
- package/dist/svelte/ui/directives/Install.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/directives/Shell.svelte +32 -0
- package/dist/svelte/ui/directives/Shell.svelte.d.ts +8 -0
- package/dist/svelte/ui/directives/Shell.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/directives/Usage.svelte +14 -0
- package/dist/svelte/ui/directives/Usage.svelte.d.ts +8 -0
- package/dist/svelte/ui/directives/Usage.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/help/HelpDialog.svelte +210 -0
- package/dist/svelte/ui/help/HelpDialog.svelte.d.ts +11 -0
- package/dist/svelte/ui/help/HelpDialog.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/help/HelpIcon.svelte +83 -0
- package/dist/svelte/ui/help/HelpIcon.svelte.d.ts +16 -0
- package/dist/svelte/ui/help/HelpIcon.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/markdown/CodeBlock.svelte +125 -0
- package/dist/svelte/ui/markdown/CodeBlock.svelte.d.ts +8 -0
- package/dist/svelte/ui/markdown/CodeBlock.svelte.d.ts.map +1 -0
- package/dist/svelte/ui/markdown/MarkdownView.svelte +319 -0
- package/dist/svelte/ui/markdown/MarkdownView.svelte.d.ts +9 -0
- package/dist/svelte/ui/markdown/MarkdownView.svelte.d.ts.map +1 -0
- package/dist/tools/docs.descriptor.d.ts +48 -0
- package/dist/tools/docs.descriptor.d.ts.map +1 -0
- package/dist/tools/docs.descriptor.js +23 -0
- package/dist/tools/docs.descriptor.js.map +1 -0
- package/dist/tools/docs.impl.d.ts +7 -0
- package/dist/tools/docs.impl.d.ts.map +1 -0
- package/dist/tools/docs.impl.js +67 -0
- package/dist/tools/docs.impl.js.map +1 -0
- package/dist/tools/schemas.d.ts +43 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +30 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tui/docs-tui.plugin.d.ts +3 -0
- package/dist/tui/docs-tui.plugin.d.ts.map +1 -0
- package/dist/tui/docs-tui.plugin.js +18 -0
- package/dist/tui/docs-tui.plugin.js.map +1 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +2 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/tui/docs-explorer.impl.consumer.d.ts +38 -0
- package/dist/tui/tui/docs-explorer.impl.consumer.d.ts.map +1 -0
- package/dist/tui/tui/docs-explorer.impl.consumer.js +334 -0
- package/dist/tui/tui/docs-explorer.impl.consumer.js.map +1 -0
- package/dist/tui/tui/docs-explorer.tui.descriptor.d.ts +13 -0
- package/dist/tui/tui/docs-explorer.tui.descriptor.d.ts.map +1 -0
- package/dist/tui/tui/docs-explorer.tui.descriptor.js +29 -0
- package/dist/tui/tui/docs-explorer.tui.descriptor.js.map +1 -0
- package/package.json +450 -4
|
@@ -0,0 +1,1139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* document.read tool implementation.
|
|
3
|
+
*
|
|
4
|
+
* Cache-first orchestration for document reading:
|
|
5
|
+
* 1. Build a cache key from (ref, page, renderProfile, promptVersion)
|
|
6
|
+
* 2. Look up in the documents.page-cache manifest
|
|
7
|
+
* 3. Cache hit → return stored markdown (+ cached rows when a schema read)
|
|
8
|
+
* 4. Cache miss → render the page PNG once via the scope-injected renderer
|
|
9
|
+
* → POST ai-web /api/internal/ocr (VISION OCR on the PNG) → markdown
|
|
10
|
+
* → when input.schema is set, ALSO POST ai-web
|
|
11
|
+
* /api/internal/document-extract (VISION extract on the SAME
|
|
12
|
+
* PNG) → rows
|
|
13
|
+
* → write markdown (+ rows) to the cache
|
|
14
|
+
*
|
|
15
|
+
* The rendered PNG is produced ONCE per page and fed to BOTH internal calls —
|
|
16
|
+
* extract is a vision read on the page image, not a re-parse of the OCR markdown.
|
|
17
|
+
*
|
|
18
|
+
* HTTP contracts (reconciled to the LIVE ai-web routes):
|
|
19
|
+
*
|
|
20
|
+
* OCR endpoint — VISION OCR on a rasterized page image:
|
|
21
|
+
* POST ${aiOrigin}/api/internal/ocr
|
|
22
|
+
* Headers: Authorization: Bearer ${VIBES_INTERNAL_SERVICE_TOKEN}
|
|
23
|
+
* Content-Type: application/json
|
|
24
|
+
* Body: { image: string (raw base64 PNG), mimeType?, category?,
|
|
25
|
+
* modelId?, modelName?, prompt? }
|
|
26
|
+
* Response: { text: string, markdown: string, metadata: Record<string, unknown> }
|
|
27
|
+
* (Source: apps/ai-web/src/routes/api/internal/ocr/+server.ts)
|
|
28
|
+
*
|
|
29
|
+
* Extract endpoint — schema-driven VISION extract on the SAME page image:
|
|
30
|
+
* POST ${aiOrigin}/api/internal/document-extract
|
|
31
|
+
* Headers: Authorization: Bearer ${VIBES_INTERNAL_SERVICE_TOKEN}
|
|
32
|
+
* Content-Type: application/json
|
|
33
|
+
* Body: { image: string (raw base64 PNG), mimeType?, schema (REQUIRED),
|
|
34
|
+
* vocabulary?: string[], rowContainerKeys?: string[], promptHint?: string, modelId?, modelName? }
|
|
35
|
+
* Response: { rows: unknown[], raw: string, diagnostics: Record<string, unknown> }
|
|
36
|
+
* (Source: apps/ai-web/src/routes/api/internal/document-extract/+server.ts)
|
|
37
|
+
*
|
|
38
|
+
* NOTE: there is no markdown-analyzer endpoint. When input.question is set WITHOUT
|
|
39
|
+
* input.schema, the impl returns the markdown path — the calling agent reads the
|
|
40
|
+
* page markdown to answer the question. A schema is required to get structured rows.
|
|
41
|
+
*
|
|
42
|
+
* A ref's `sourceRefreshUrl` is admitted against the declared destinations before
|
|
43
|
+
* the internal service credential goes to it (`./source-refresh.ts`).
|
|
44
|
+
*
|
|
45
|
+
* TODO(WS0): Wire VIBES_PDF_RENDER_ORIGIN for the consumer-scope renderer.
|
|
46
|
+
* TODO(WS0): Wire the platform CRUD endpoint /api/documents/page-cache (cloud-api adapter).
|
|
47
|
+
*/
|
|
48
|
+
import * as z from 'zod/v4';
|
|
49
|
+
import { CapabilityError, isCapabilityError, valueFreeFailure, settle, settleNow } from '@vibesdotdev/kernel';
|
|
50
|
+
import { getLogger } from '@vibesdotdev/logging';
|
|
51
|
+
import { JsonObjectSchema, JsonValueSchema } from '@vibesdotdev/kernel/schemas/json';
|
|
52
|
+
import { StorageManifest } from '@vibesdotdev/storage';
|
|
53
|
+
import { readTrustedRunContext } from '@vibesdotdev/tools/agents/trusted-context';
|
|
54
|
+
import { serviceOrigin } from '@vibesdotdev/infra-core/service';
|
|
55
|
+
import { PDF_OCR_FOVEATE_PAGE_JOB_ID, PDF_OCR_QUEUE_ID } from '@vibesdotdev/ai/generation/pdf-ocr';
|
|
56
|
+
import { DocumentReadInputSchema } from "../schemas/document-read.schema.js";
|
|
57
|
+
import { DocumentPageCacheRecordSchema } from "../schemas/page-cache.schema.js";
|
|
58
|
+
import { planFoveationGrid, enumerateGridCells, cellsAreAdjacent, FOVEATE_DEFAULT_OVERLAP, FOVEATE_MAX_CELLS, FOVEATE_MIN_LONGEST_EDGE_PX } from "../render/grid.js";
|
|
59
|
+
import { resolveFreshSourceUrl, resolveInternalServiceToken } from "./source-refresh.js";
|
|
60
|
+
import { AIServiceBindingSchema } from "../schemas/ai-service-binding.schema.js";
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Cache key
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
/**
|
|
65
|
+
* Build a stable cache key for a (ref, page, renderProfile, promptVersion)
|
|
66
|
+
* tuple. Used to look up and write records in the documents.page-cache manifest.
|
|
67
|
+
*/
|
|
68
|
+
export function buildCacheKey(ref, page, renderProfile, promptVersion) {
|
|
69
|
+
const stableExternalId = ref.documentId ? `document:${ref.documentId}` : ref.url ?? '';
|
|
70
|
+
const refPart = [ref.providerId ?? '', ref.path ?? '', stableExternalId].join('|');
|
|
71
|
+
return `${refPart}::p${page}::${renderProfile}::${promptVersion}`;
|
|
72
|
+
}
|
|
73
|
+
async function sha256Hex(input) {
|
|
74
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));
|
|
75
|
+
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
76
|
+
}
|
|
77
|
+
export async function buildFoveatedPageJobId(storageCacheKey) {
|
|
78
|
+
return `pdf-ocr-foveate:${await sha256Hex(storageCacheKey)}`;
|
|
79
|
+
}
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Prompt folding
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
/**
|
|
84
|
+
* The live OCR endpoint exposes a SINGLE `prompt` field (no separate
|
|
85
|
+
* instructions / visionFocusHint / vocabulary fields). Fold the focus hint and
|
|
86
|
+
* freeform instructions into one prompt string, or undefined when neither is set.
|
|
87
|
+
*/
|
|
88
|
+
function foldOcrPrompt(input) {
|
|
89
|
+
const parts = [];
|
|
90
|
+
if (input.visionFocusHint)
|
|
91
|
+
parts.push(`[focus] ${input.visionFocusHint}`);
|
|
92
|
+
if (input.instructions)
|
|
93
|
+
parts.push(input.instructions);
|
|
94
|
+
return parts.length > 0 ? parts.join('\n') : undefined;
|
|
95
|
+
}
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Internal HTTP helpers — reconciled to the live ai-web route schemas.
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
/** Live /api/internal/ocr response shape. */
|
|
100
|
+
const OcrResponseSchema = z.object({
|
|
101
|
+
text: z.string(),
|
|
102
|
+
markdown: z.string(),
|
|
103
|
+
metadata: z.record(z.string(), JsonValueSchema).default({})
|
|
104
|
+
});
|
|
105
|
+
/** Live /api/internal/document-extract response shape. */
|
|
106
|
+
const ExtractResponseSchema = z.object({
|
|
107
|
+
rows: z.array(JsonValueSchema).default([]),
|
|
108
|
+
raw: z.string().default(''),
|
|
109
|
+
diagnostics: z.record(z.string(), JsonValueSchema).default({})
|
|
110
|
+
});
|
|
111
|
+
/**
|
|
112
|
+
* The ai-web origin that serves /api/internal/ocr + /api/internal/document-extract:
|
|
113
|
+
* the declared `ai` service's internal origin. document.read runs on ai-web or on
|
|
114
|
+
* any app loading the documents plugin; both select the same service catalog, so
|
|
115
|
+
* there is no self-origin special case.
|
|
116
|
+
*/
|
|
117
|
+
async function resolveAiInternalOrigin(runtime) {
|
|
118
|
+
return (await serviceOrigin(runtime, 'ai', 'internal')).replace(/\/$/, '');
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Fetch the ai-web internal endpoints WITHOUT going through the public edge.
|
|
122
|
+
*
|
|
123
|
+
* document.read runs ON ai-web, so calling `fetch('https://ai.vibes.dev/...')`
|
|
124
|
+
* is a self-loopback over the Cloudflare edge — which times the OCR subrequest
|
|
125
|
+
* out and returns a 522 (the same "never self-fetch a public hostname" trap that
|
|
126
|
+
* broke cron). When the `AI_INTERNAL` service binding (a worker-to-self Fetcher
|
|
127
|
+
* declared in ai-web's deployment.config) is present we route through it instead:
|
|
128
|
+
* the request goes worker→worker with no edge hop, so a slow vision-OCR call
|
|
129
|
+
* completes within the tool budget instead of hitting the edge timeout. The URL
|
|
130
|
+
* host is ignored by the service binding (it routes to vibes-ai); only the path
|
|
131
|
+
* matters. Falls back to the global fetch for any app consuming ai-web remotely.
|
|
132
|
+
*/
|
|
133
|
+
function internalFetch(runtime, url, init) {
|
|
134
|
+
const binding = runtime.getBinding('AI_INTERNAL', AIServiceBindingSchema);
|
|
135
|
+
if (binding)
|
|
136
|
+
return binding.fetch(url, init);
|
|
137
|
+
return fetch(url, init);
|
|
138
|
+
}
|
|
139
|
+
async function callOcr(runtime, aiOrigin, token, body) {
|
|
140
|
+
const response = await internalFetch(runtime, `${aiOrigin}/api/internal/ocr`, {
|
|
141
|
+
method: 'POST',
|
|
142
|
+
headers: {
|
|
143
|
+
Authorization: `Bearer ${token}`,
|
|
144
|
+
'Content-Type': 'application/json'
|
|
145
|
+
},
|
|
146
|
+
body: JSON.stringify(body)
|
|
147
|
+
});
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
throw new CapabilityError('Document OCR request refused.', 'UNAVAILABLE', { reason: 'document-ocr-failed', details: { status: response.status } });
|
|
150
|
+
}
|
|
151
|
+
return OcrResponseSchema.parse(await response.json());
|
|
152
|
+
}
|
|
153
|
+
async function callExtract(runtime, aiOrigin, token, body) {
|
|
154
|
+
const response = await internalFetch(runtime, `${aiOrigin}/api/internal/document-extract`, {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
headers: {
|
|
157
|
+
Authorization: `Bearer ${token}`,
|
|
158
|
+
'Content-Type': 'application/json'
|
|
159
|
+
},
|
|
160
|
+
body: JSON.stringify(body)
|
|
161
|
+
});
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
throw new CapabilityError('Document extraction request refused.', 'UNAVAILABLE', { reason: 'document-extract-failed', details: { status: response.status } });
|
|
164
|
+
}
|
|
165
|
+
return ExtractResponseSchema.parse(await response.json());
|
|
166
|
+
}
|
|
167
|
+
/** The page cache manifest of `runtime`, the runtime the tool call was handed. */
|
|
168
|
+
function getPageCache(runtime) {
|
|
169
|
+
return StorageManifest.fromId('documents.page-cache', runtime);
|
|
170
|
+
}
|
|
171
|
+
function readString(value) {
|
|
172
|
+
const parsed = z.string().safeParse(value);
|
|
173
|
+
if (!parsed.success)
|
|
174
|
+
return undefined;
|
|
175
|
+
const trimmed = parsed.data.trim();
|
|
176
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
177
|
+
}
|
|
178
|
+
function resolveRequestOwner(runtime, ctx) {
|
|
179
|
+
// Identity is per invocation: the active invocation's actor (rc01 §2.1).
|
|
180
|
+
const principal = runtime.scope.actor;
|
|
181
|
+
const metadata = readTrustedRunContext(ctx);
|
|
182
|
+
const userId = readString(metadata.userId) ?? principal?.userId;
|
|
183
|
+
if (!userId)
|
|
184
|
+
return null;
|
|
185
|
+
const organizationId = readString(metadata.orgId) ?? principal?.orgId;
|
|
186
|
+
const owner = { userId };
|
|
187
|
+
if (organizationId)
|
|
188
|
+
owner.organizationId = organizationId;
|
|
189
|
+
return owner;
|
|
190
|
+
}
|
|
191
|
+
async function tryResolvePlatformOrigin(runtime) {
|
|
192
|
+
return settle(async () => (await serviceOrigin(runtime, 'platform', 'internal')).replace(/\/$/, ''));
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* The declared `platform` service's internal origin for the page cache, or
|
|
196
|
+
* `null` when this host declares no `platform` service for its service environment (`service-undeclared`:
|
|
197
|
+
* the page cache is an optimisation and stays off). Any other failure throws.
|
|
198
|
+
*/
|
|
199
|
+
async function resolvePlatformOrigin(runtime) {
|
|
200
|
+
const res = await tryResolvePlatformOrigin(runtime);
|
|
201
|
+
if (res.ok)
|
|
202
|
+
return res.value;
|
|
203
|
+
if (res.cause instanceof Error && isCapabilityError(res.cause) && res.cause.reason === 'service-undeclared') {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
throw res.cause;
|
|
207
|
+
}
|
|
208
|
+
const PageCacheLookupResponseSchema = z.object({
|
|
209
|
+
result: JsonValueSchema.optional()
|
|
210
|
+
});
|
|
211
|
+
async function createInternalPageCacheClient(runtime, ctx, token) {
|
|
212
|
+
const owner = resolveRequestOwner(runtime, ctx);
|
|
213
|
+
const platformOrigin = await resolvePlatformOrigin(runtime);
|
|
214
|
+
if (!owner || !platformOrigin)
|
|
215
|
+
return null;
|
|
216
|
+
const headers = () => {
|
|
217
|
+
const h = {
|
|
218
|
+
authorization: `Bearer ${token}`,
|
|
219
|
+
'x-vibes-user-id': owner.userId,
|
|
220
|
+
'content-type': 'application/json',
|
|
221
|
+
origin: platformOrigin
|
|
222
|
+
};
|
|
223
|
+
if (owner.organizationId) {
|
|
224
|
+
h['x-vibes-organization-id'] = owner.organizationId;
|
|
225
|
+
}
|
|
226
|
+
return h;
|
|
227
|
+
};
|
|
228
|
+
const ownerType = owner.organizationId ? 'organization' : 'user';
|
|
229
|
+
const ownerId = owner.organizationId ?? owner.userId;
|
|
230
|
+
const storageKey = (cacheKey) => `${ownerType}:${encodeURIComponent(ownerId)}:${cacheKey}`;
|
|
231
|
+
return {
|
|
232
|
+
async lookup(cacheKey) {
|
|
233
|
+
const key = storageKey(cacheKey);
|
|
234
|
+
const response = await fetch(`${platformOrigin}/api/internal/documents/page-cache/${encodeURIComponent(key)}`, { headers: headers() });
|
|
235
|
+
if (response.status === 404)
|
|
236
|
+
return null;
|
|
237
|
+
if (!response.ok)
|
|
238
|
+
throw new Error(`page-cache lookup failed (${response.status})`);
|
|
239
|
+
const data = PageCacheLookupResponseSchema.safeParse(await response.json());
|
|
240
|
+
const parsed = data.success && data.data.result ? DocumentPageCacheRecordSchema.safeParse(data.data.result) : null;
|
|
241
|
+
return parsed?.success ? parsed.data : null;
|
|
242
|
+
},
|
|
243
|
+
async write(record) {
|
|
244
|
+
const stored = { ...record, id: storageKey(record.id) };
|
|
245
|
+
const response = await fetch(`${platformOrigin}/api/internal/documents/page-cache/${encodeURIComponent(stored.id)}`, {
|
|
246
|
+
method: 'PUT',
|
|
247
|
+
headers: headers(),
|
|
248
|
+
body: JSON.stringify(stored)
|
|
249
|
+
});
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
throw new CapabilityError('Document page-cache write refused.', 'UNAVAILABLE', { reason: 'document-cache-write-failed', details: { status: response.status } });
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
storageKey
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
async function safeLoadCacheRecords(cache) {
|
|
258
|
+
return settle(async () => (await cache.load()) ?? []);
|
|
259
|
+
}
|
|
260
|
+
function createManifestPageCacheClient(cache, runtime) {
|
|
261
|
+
return {
|
|
262
|
+
async lookup(cacheKey) {
|
|
263
|
+
const res = await safeLoadCacheRecords(cache);
|
|
264
|
+
if (res.ok) {
|
|
265
|
+
return res.value.find((r) => r.id === cacheKey) ?? null;
|
|
266
|
+
}
|
|
267
|
+
const diagnostic = settleNow(() => getLogger('documents.read', runtime).warn('page-cache manifest lookup failed; treating as a miss', {
|
|
268
|
+
cacheKey,
|
|
269
|
+
error: valueFreeFailure(res.cause)
|
|
270
|
+
}));
|
|
271
|
+
if (!diagnostic.ok)
|
|
272
|
+
settleNow(() => runtime.diagnostics.error('Document diagnostic failed', { scope: 'docs', plugin: 'documents.read', error: new AggregateError([res.cause, diagnostic.cause], 'Primary failure and diagnostic failed.', { cause: res.cause }) }));
|
|
273
|
+
return null;
|
|
274
|
+
},
|
|
275
|
+
async write(record) {
|
|
276
|
+
const res = await safeLoadCacheRecords(cache);
|
|
277
|
+
const records = res.ok ? res.value : [];
|
|
278
|
+
const idx = records.findIndex((r) => r.id === record.id);
|
|
279
|
+
if (idx >= 0) {
|
|
280
|
+
records[idx] = record;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
records.push(record);
|
|
284
|
+
}
|
|
285
|
+
await cache.save(records);
|
|
286
|
+
},
|
|
287
|
+
storageKey(cacheKey) {
|
|
288
|
+
return cacheKey;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
async function tryCreateInternalPageCacheClient(runtime, ctx, token) {
|
|
293
|
+
return settle(() => createInternalPageCacheClient(runtime, ctx, token));
|
|
294
|
+
}
|
|
295
|
+
async function resolvePageCacheClient(runtime, ctx, token) {
|
|
296
|
+
const res = await tryCreateInternalPageCacheClient(runtime, ctx, token);
|
|
297
|
+
if (res.ok && res.value)
|
|
298
|
+
return res.value;
|
|
299
|
+
if (!res.ok) {
|
|
300
|
+
const diagnostic = settleNow(() => getLogger('documents.read', runtime).warn('internal page-cache client unavailable; using the manifest adapter', {
|
|
301
|
+
error: valueFreeFailure(res.cause)
|
|
302
|
+
}));
|
|
303
|
+
if (!diagnostic.ok)
|
|
304
|
+
settleNow(() => runtime.diagnostics.error('Document diagnostic failed', { scope: 'docs', plugin: 'documents.read', error: new AggregateError([res.cause, diagnostic.cause], 'Primary failure and diagnostic failed.', { cause: res.cause }) }));
|
|
305
|
+
}
|
|
306
|
+
return createManifestPageCacheClient(getPageCache(runtime), runtime);
|
|
307
|
+
}
|
|
308
|
+
async function tryLookupCache(cache, cacheKey) {
|
|
309
|
+
return settle(() => cache.lookup(cacheKey));
|
|
310
|
+
}
|
|
311
|
+
async function lookupCache(cache, cacheKey, runtime) {
|
|
312
|
+
const res = await tryLookupCache(cache, cacheKey);
|
|
313
|
+
if (res.ok)
|
|
314
|
+
return res.value;
|
|
315
|
+
const diagnostic = settleNow(() => getLogger('documents.read', runtime).warn('page-cache lookup failed; treating as a miss', {
|
|
316
|
+
cacheKey,
|
|
317
|
+
error: valueFreeFailure(res.cause)
|
|
318
|
+
}));
|
|
319
|
+
if (!diagnostic.ok)
|
|
320
|
+
settleNow(() => runtime.diagnostics.error('Document diagnostic failed', { scope: 'docs', plugin: 'documents.read', error: new AggregateError([res.cause, diagnostic.cause], 'Primary failure and diagnostic failed.', { cause: res.cause }) }));
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
async function writeCache(cache, record) {
|
|
324
|
+
await cache.write(record);
|
|
325
|
+
}
|
|
326
|
+
// ---------------------------------------------------------------------------
|
|
327
|
+
// Core per-page logic
|
|
328
|
+
// ---------------------------------------------------------------------------
|
|
329
|
+
const DEFAULT_RENDER_PROFILE = 'page-150dpi';
|
|
330
|
+
// CACHE-BUST: the page cache keys on (ref, page, renderProfile, promptVersion) — NOT on the
|
|
331
|
+
// extraction-schema descriptor version or the preamble text. So ANY change to the casework
|
|
332
|
+
// estimator preamble / cabinet schema (the drawing-literacy, quantity-semantics, non-casework
|
|
333
|
+
// rules) MUST bump this token, or a previously-cached page is re-served with the STALE prompt
|
|
334
|
+
// and the fix silently never applies. Bump on every prompt/schema change. (v2 = reconciliation
|
|
335
|
+
// fixes: quantity≠N-units, non-casework describe-not-counter, multi-view transcription.)
|
|
336
|
+
const DEFAULT_PROMPT_VERSION = 'v4-describe-foveate';
|
|
337
|
+
const ASYNC_PROCESSING_MESSAGE = 'foveated read queued — re-read this page to retrieve the transcription once processing completes.';
|
|
338
|
+
const ASYNC_ERROR_MESSAGE = 'foveated read failed in the background — re-read this page in a few minutes to retry it.';
|
|
339
|
+
const PROCESSING_MARKER_STALE_MS = 30 * 60 * 1000;
|
|
340
|
+
/**
|
|
341
|
+
* Cool-off before a cached FAILURE marker becomes retryable. Within the
|
|
342
|
+
* window the error is served as-is (so an agent loop cannot hot-requeue a
|
|
343
|
+
* failing page); after it, a re-read falls through to a fresh render +
|
|
344
|
+
* re-enqueue with a FRESH source URL — background failures (expired
|
|
345
|
+
* SharePoint tempauth, transient model outages, capacity) must never be
|
|
346
|
+
* permanent just because they were cached.
|
|
347
|
+
*/
|
|
348
|
+
const ERROR_MARKER_RETRY_MS = 5 * 60 * 1000;
|
|
349
|
+
export function isProcessingCacheRecord(record) {
|
|
350
|
+
return (record.quality?.asyncStatus === 'processing' ||
|
|
351
|
+
record.ocrMarkdown.includes(ASYNC_PROCESSING_MESSAGE));
|
|
352
|
+
}
|
|
353
|
+
export function isStaleProcessingCacheRecord(record, nowMs = Date.now()) {
|
|
354
|
+
if (!isProcessingCacheRecord(record))
|
|
355
|
+
return false;
|
|
356
|
+
const queuedAt = readString(record.quality?.queuedAt);
|
|
357
|
+
if (!queuedAt)
|
|
358
|
+
return false;
|
|
359
|
+
const queuedAtMs = Date.parse(queuedAt);
|
|
360
|
+
if (!Number.isFinite(queuedAtMs))
|
|
361
|
+
return false;
|
|
362
|
+
return nowMs - queuedAtMs > PROCESSING_MARKER_STALE_MS;
|
|
363
|
+
}
|
|
364
|
+
function isErrorCacheRecord(record) {
|
|
365
|
+
return record.quality?.asyncStatus === 'error';
|
|
366
|
+
}
|
|
367
|
+
/** A failure marker older than the cool-off (or missing/garbled failedAt —
|
|
368
|
+
* legacy rows) is retryable: the read path re-renders + re-enqueues. */
|
|
369
|
+
export function isRetryableErrorCacheRecord(record, nowMs = Date.now()) {
|
|
370
|
+
if (!isErrorCacheRecord(record))
|
|
371
|
+
return false;
|
|
372
|
+
const failedAt = readString(record.quality?.failedAt);
|
|
373
|
+
if (!failedAt)
|
|
374
|
+
return true;
|
|
375
|
+
const failedAtMs = Date.parse(failedAt);
|
|
376
|
+
if (!Number.isFinite(failedAtMs))
|
|
377
|
+
return true;
|
|
378
|
+
return nowMs - failedAtMs > ERROR_MARKER_RETRY_MS;
|
|
379
|
+
}
|
|
380
|
+
function processingPage(page, cacheKey, jobId) {
|
|
381
|
+
const res = {
|
|
382
|
+
index: page,
|
|
383
|
+
text: ASYNC_PROCESSING_MESSAGE,
|
|
384
|
+
cacheHit: false,
|
|
385
|
+
status: 'processing',
|
|
386
|
+
cacheKey,
|
|
387
|
+
message: ASYNC_PROCESSING_MESSAGE
|
|
388
|
+
};
|
|
389
|
+
if (jobId)
|
|
390
|
+
res.jobId = jobId;
|
|
391
|
+
return res;
|
|
392
|
+
}
|
|
393
|
+
function errorPage(page, cacheKey, record) {
|
|
394
|
+
const message = readString(record.quality?.message) ?? ASYNC_ERROR_MESSAGE;
|
|
395
|
+
const jobId = readString(record.quality?.jobId);
|
|
396
|
+
const res = {
|
|
397
|
+
index: page,
|
|
398
|
+
text: record.ocrMarkdown || message,
|
|
399
|
+
cacheHit: true,
|
|
400
|
+
status: 'error',
|
|
401
|
+
cacheKey,
|
|
402
|
+
message
|
|
403
|
+
};
|
|
404
|
+
if (jobId)
|
|
405
|
+
res.jobId = jobId;
|
|
406
|
+
return res;
|
|
407
|
+
}
|
|
408
|
+
function asyncFoveationEnabled(runtime, input) {
|
|
409
|
+
if (input.schema)
|
|
410
|
+
return false;
|
|
411
|
+
const forceSync = runtime.getEnv('VIBES_DOCUMENT_READ_SYNC_FOVEATION');
|
|
412
|
+
if (forceSync === '1' || forceSync === 'true' || forceSync === 'TRUE')
|
|
413
|
+
return false;
|
|
414
|
+
const disabled = runtime.getEnv('VIBES_DOCUMENT_READ_ASYNC_FOVEATION');
|
|
415
|
+
return !(disabled === '0' || disabled === 'false' || disabled === 'FALSE');
|
|
416
|
+
}
|
|
417
|
+
async function resolvePdfOcrQueue(runtime) {
|
|
418
|
+
const res = await settle(async () => {
|
|
419
|
+
const adapter = await runtime
|
|
420
|
+
.query('workers/adapter')
|
|
421
|
+
.withId('worker-adapter.kafka')
|
|
422
|
+
.resolve();
|
|
423
|
+
if (!adapter?.getQueueAdapter) {
|
|
424
|
+
throw new Error('Adapter worker-adapter.kafka missing getQueueAdapter');
|
|
425
|
+
}
|
|
426
|
+
if (adapter.isConnected && !adapter.isConnected()) {
|
|
427
|
+
await adapter.connect?.(runtime);
|
|
428
|
+
}
|
|
429
|
+
const queue = adapter.getQueueAdapter(PDF_OCR_QUEUE_ID);
|
|
430
|
+
await queue.connect?.();
|
|
431
|
+
return queue;
|
|
432
|
+
});
|
|
433
|
+
if (!res.ok) {
|
|
434
|
+
const diagnostic = settleNow(() => getLogger('documents.read', runtime).warn('pdf-ocr queue unavailable; falling back to synchronous foveation', {
|
|
435
|
+
error: valueFreeFailure(res.cause)
|
|
436
|
+
}));
|
|
437
|
+
if (!diagnostic.ok)
|
|
438
|
+
settleNow(() => runtime.diagnostics.error('Document diagnostic failed', { scope: 'docs', plugin: 'documents.read', error: new AggregateError([res.cause, diagnostic.cause], 'Primary failure and diagnostic failed.', { cause: res.cause }) }));
|
|
439
|
+
}
|
|
440
|
+
return res;
|
|
441
|
+
}
|
|
442
|
+
async function writeProcessingMarker(args) {
|
|
443
|
+
const quality = {
|
|
444
|
+
asyncStatus: 'processing',
|
|
445
|
+
cacheKey: args.cacheKey,
|
|
446
|
+
queuedAt: new Date().toISOString()
|
|
447
|
+
};
|
|
448
|
+
if (args.jobId)
|
|
449
|
+
quality.jobId = args.jobId;
|
|
450
|
+
await writeCache(args.cache, {
|
|
451
|
+
id: args.cacheKey,
|
|
452
|
+
ref: args.input.ref,
|
|
453
|
+
page: args.page,
|
|
454
|
+
renderProfile: args.renderProfile,
|
|
455
|
+
promptVersion: args.promptVersion,
|
|
456
|
+
ocrMarkdown: ASYNC_PROCESSING_MESSAGE,
|
|
457
|
+
quality,
|
|
458
|
+
sourceHash: `processing:${args.jobId ?? args.cacheKey}`,
|
|
459
|
+
renderedAt: new Date().toISOString()
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
async function tryWriteProcessingMarker(args) {
|
|
463
|
+
return settle(async () => {
|
|
464
|
+
await writeProcessingMarker(args);
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
async function enqueueFoveatedPage(args) {
|
|
468
|
+
const owner = resolveRequestOwner(args.runtime, args.ctx);
|
|
469
|
+
if (!owner)
|
|
470
|
+
return null;
|
|
471
|
+
const platformOrigin = await resolvePlatformOrigin(args.runtime);
|
|
472
|
+
if (!platformOrigin)
|
|
473
|
+
return null;
|
|
474
|
+
const queueRes = await resolvePdfOcrQueue(args.runtime);
|
|
475
|
+
if (!queueRes.ok)
|
|
476
|
+
return null;
|
|
477
|
+
const queue = queueRes.value;
|
|
478
|
+
const storageCacheKey = args.cache.storageKey(args.cacheKey);
|
|
479
|
+
const jobId = await buildFoveatedPageJobId(storageCacheKey);
|
|
480
|
+
// Job data is persisted, so it carries no credential: the job resolves the
|
|
481
|
+
// internal service credential through its own runtime when it runs.
|
|
482
|
+
const jobInput = {
|
|
483
|
+
requestId: jobId,
|
|
484
|
+
userId: owner.userId,
|
|
485
|
+
sourceUrl: args.sourceUrl,
|
|
486
|
+
page: args.page,
|
|
487
|
+
pageWidthPx: Math.max(1, Math.floor(args.pageWidthPx)),
|
|
488
|
+
pageHeightPx: Math.max(1, Math.floor(args.pageHeightPx)),
|
|
489
|
+
ref: args.input.ref,
|
|
490
|
+
cacheKey: storageCacheKey,
|
|
491
|
+
renderProfile: args.renderProfile,
|
|
492
|
+
promptVersion: args.promptVersion,
|
|
493
|
+
aiOrigin: args.aiOrigin,
|
|
494
|
+
platformOrigin
|
|
495
|
+
};
|
|
496
|
+
if (owner.organizationId)
|
|
497
|
+
jobInput.organizationId = owner.organizationId;
|
|
498
|
+
// Admitted when this read resolved its source (`resolveFreshSourceUrl`).
|
|
499
|
+
if (args.input.ref.sourceRefreshUrl)
|
|
500
|
+
jobInput.sourceRefreshUrl = args.input.ref.sourceRefreshUrl;
|
|
501
|
+
if (args.input.ref.documentId)
|
|
502
|
+
jobInput.documentId = args.input.ref.documentId;
|
|
503
|
+
if (args.input.instructions)
|
|
504
|
+
jobInput.instructions = args.input.instructions;
|
|
505
|
+
if (args.input.visionFocusHint)
|
|
506
|
+
jobInput.visionFocusHint = args.input.visionFocusHint;
|
|
507
|
+
if (args.input.modelName)
|
|
508
|
+
jobInput.modelName = args.input.modelName;
|
|
509
|
+
const metadata = {
|
|
510
|
+
type: PDF_OCR_FOVEATE_PAGE_JOB_ID,
|
|
511
|
+
maxAttempts: 2,
|
|
512
|
+
billingUserId: owner.userId
|
|
513
|
+
};
|
|
514
|
+
if (owner.organizationId)
|
|
515
|
+
metadata.billingOrganizationId = owner.organizationId;
|
|
516
|
+
return queue.enqueue(jobInput, {
|
|
517
|
+
jobId,
|
|
518
|
+
jobName: PDF_OCR_FOVEATE_PAGE_JOB_ID,
|
|
519
|
+
attempts: 2,
|
|
520
|
+
metadata
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
/** Lowercased string value of the first matching field, or '' when absent. */
|
|
524
|
+
function fieldStr(row, keys) {
|
|
525
|
+
const parsed = JsonObjectSchema.safeParse(row);
|
|
526
|
+
if (!parsed.success)
|
|
527
|
+
return '';
|
|
528
|
+
const rec = parsed.data;
|
|
529
|
+
for (const [k, v] of Object.entries(rec)) {
|
|
530
|
+
if (keys.includes(k.toLowerCase())) {
|
|
531
|
+
const str = z.string().safeParse(v);
|
|
532
|
+
if (str.success)
|
|
533
|
+
return str.data.trim().toLowerCase();
|
|
534
|
+
const num = z.number().safeParse(v);
|
|
535
|
+
if (num.success)
|
|
536
|
+
return String(num.data);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return '';
|
|
540
|
+
}
|
|
541
|
+
/** Best-effort title/tag of a row (schema-agnostic — tries common field names). */
|
|
542
|
+
function rowTitle(row) {
|
|
543
|
+
return fieldStr(row, ['title', 'tag', 'label', 'name', 'mark', 'id', 'type']);
|
|
544
|
+
}
|
|
545
|
+
/** Best-effort dimension signature of a row (schema-agnostic). */
|
|
546
|
+
function rowDims(row) {
|
|
547
|
+
const direct = fieldStr(row, ['dimensions', 'dims', 'size', 'dimension']);
|
|
548
|
+
if (direct)
|
|
549
|
+
return direct;
|
|
550
|
+
// Fall back to width×height×depth components when present.
|
|
551
|
+
const w = fieldStr(row, ['width', 'w']);
|
|
552
|
+
const h = fieldStr(row, ['height', 'h']);
|
|
553
|
+
const d = fieldStr(row, ['depth', 'd']);
|
|
554
|
+
const combined = [w, h, d].filter(Boolean).join('x');
|
|
555
|
+
return combined;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Merge per-cell rows for the foveated path.
|
|
559
|
+
*
|
|
560
|
+
* NEVER auto-dedups: two genuinely identical cabinets are valid, and silent
|
|
561
|
+
* dedup under-counts → an unsafe bid. Instead we keep ALL rows and emit a
|
|
562
|
+
* diagnostic that (a) records each row's cell provenance and (b) flags pairs of
|
|
563
|
+
* rows from ADJACENT/overlapping cells that share an identical title AND
|
|
564
|
+
* identical dimensions as a *possible* cross-cell duplicate (flag only).
|
|
565
|
+
*/
|
|
566
|
+
function mergeFoveatedRows(cellRows) {
|
|
567
|
+
const rows = cellRows.map((cr) => cr.row);
|
|
568
|
+
const provenance = cellRows.map((cr, index) => ({
|
|
569
|
+
index,
|
|
570
|
+
cell: `r${cr.cell.row}c${cr.cell.col}`
|
|
571
|
+
}));
|
|
572
|
+
const possibleDuplicates = [];
|
|
573
|
+
for (let i = 0; i < cellRows.length; i++) {
|
|
574
|
+
for (let j = i + 1; j < cellRows.length; j++) {
|
|
575
|
+
const A = cellRows[i];
|
|
576
|
+
const B = cellRows[j];
|
|
577
|
+
if (A.cell === B.cell)
|
|
578
|
+
continue; // same cell → not a seam duplicate
|
|
579
|
+
if (!cellsAreAdjacent(A.cell, B.cell))
|
|
580
|
+
continue;
|
|
581
|
+
const titleA = rowTitle(A.row);
|
|
582
|
+
const titleB = rowTitle(B.row);
|
|
583
|
+
const dimsA = rowDims(A.row);
|
|
584
|
+
const dimsB = rowDims(B.row);
|
|
585
|
+
if (titleA && titleA === titleB && dimsA && dimsA === dimsB) {
|
|
586
|
+
possibleDuplicates.push({ a: i, b: j, title: titleA, dims: dimsA });
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return { rows, provenance, possibleDuplicates };
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Foveated SCHEMA read: render the page as a grid of HIGH-DPI cells and extract
|
|
594
|
+
* each, merging rows with provenance + duplicate flags. Returns the merged rows,
|
|
595
|
+
* a diagnostics blob, and a short markdown note. Cost is bounded: the grid is
|
|
596
|
+
* capped at FOVEATE_MAX_CELLS cells, and the sweep aborts early if the first few
|
|
597
|
+
* cells all return zero rows (a blank/text page won't benefit from tiling).
|
|
598
|
+
*/
|
|
599
|
+
async function foveatedExtract(runtime, page, sourceUrl, pageWidthPx, pageHeightPx, input, renderer, aiOrigin, token) {
|
|
600
|
+
const grid = planFoveationGrid(pageWidthPx, pageHeightPx, FOVEATE_MAX_CELLS);
|
|
601
|
+
const cells = enumerateGridCells(grid, FOVEATE_DEFAULT_OVERLAP);
|
|
602
|
+
// schema present → structured EXTRACT per cell; absent → faithful TRANSCRIBE per
|
|
603
|
+
// cell (DESCRIBE mode). Describe keeps document.read a generic doc-intelligence tool:
|
|
604
|
+
// the vision model transcribes what's drawn (titles, dimension strings, callouts,
|
|
605
|
+
// detail tags) and the CALLER (e.g. the casework agent) interprets it — so a detail
|
|
606
|
+
// or section sheet with no titled "rows" still yields its dimensions instead of blank.
|
|
607
|
+
const wantsExtract = Boolean(input.schema);
|
|
608
|
+
const cellRows = [];
|
|
609
|
+
const cellTexts = [];
|
|
610
|
+
const perCellCounts = [];
|
|
611
|
+
const cellFailures = [];
|
|
612
|
+
// RENDER every cell from a SINGLE source fetch (a SharePoint pre-auth token is
|
|
613
|
+
// rejected — 401 — when fetched per cell / concurrently). The vision EXTRACT then
|
|
614
|
+
// runs per cell; extract POSTs the cell image to ai-web (no source fetch), so the
|
|
615
|
+
// extracts go CONCURRENTLY (batched, to not hammer the vision model) — each cell
|
|
616
|
+
// is ~15-25s and running them sequentially would blow the tool budget (the async
|
|
617
|
+
// rail timeout document.read exists to escape).
|
|
618
|
+
const rendered = await renderer.renderGridCells({ sourceUrl, page, cells });
|
|
619
|
+
const byKey = new Map(cells.map((c) => [`${c.row}:${c.col}`, c]));
|
|
620
|
+
const CONCURRENCY = 4;
|
|
621
|
+
const extractCell = async (rc) => {
|
|
622
|
+
const fallbackCell = {
|
|
623
|
+
col: rc.col,
|
|
624
|
+
row: rc.row,
|
|
625
|
+
cols: grid.cols,
|
|
626
|
+
rows: grid.rows,
|
|
627
|
+
overlap: FOVEATE_DEFAULT_OVERLAP
|
|
628
|
+
};
|
|
629
|
+
const cell = byKey.get(`${rc.row}:${rc.col}`) ?? fallbackCell;
|
|
630
|
+
return settle(async () => {
|
|
631
|
+
if (wantsExtract) {
|
|
632
|
+
const extractBody = {
|
|
633
|
+
image: rc.pngBase64,
|
|
634
|
+
schema: JsonObjectSchema.parse(input.schema),
|
|
635
|
+
vocabulary: input.vocabulary,
|
|
636
|
+
promptHint: input.instructions
|
|
637
|
+
};
|
|
638
|
+
if (input.rowContainerKeys)
|
|
639
|
+
extractBody.rowContainerKeys = input.rowContainerKeys;
|
|
640
|
+
if (input.modelName)
|
|
641
|
+
extractBody.modelName = input.modelName;
|
|
642
|
+
const extracted = await callExtract(runtime, aiOrigin, token, extractBody);
|
|
643
|
+
return {
|
|
644
|
+
cell,
|
|
645
|
+
rows: extracted.rows,
|
|
646
|
+
text: extracted.raw
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
// DESCRIBE mode: transcribe this legible cell faithfully (no schema).
|
|
650
|
+
const ocrBody = {
|
|
651
|
+
image: rc.pngBase64,
|
|
652
|
+
prompt: foldOcrPrompt(input)
|
|
653
|
+
};
|
|
654
|
+
if (input.modelName)
|
|
655
|
+
ocrBody.modelName = input.modelName;
|
|
656
|
+
const ocr = await callOcr(runtime, aiOrigin, token, ocrBody);
|
|
657
|
+
return { cell, rows: [], text: ocr.markdown || ocr.text || '' };
|
|
658
|
+
});
|
|
659
|
+
};
|
|
660
|
+
let cellsRun = 0;
|
|
661
|
+
for (let i = 0; i < rendered.length; i += CONCURRENCY) {
|
|
662
|
+
const batch = rendered.slice(i, i + CONCURRENCY);
|
|
663
|
+
const results = await Promise.all(batch.map(extractCell));
|
|
664
|
+
for (let bIdx = 0; bIdx < batch.length; bIdx++) {
|
|
665
|
+
const res = results[bIdx];
|
|
666
|
+
const rc = batch[bIdx];
|
|
667
|
+
if (!res || !rc)
|
|
668
|
+
continue;
|
|
669
|
+
if (!res.ok) {
|
|
670
|
+
const err = 'Document cell extraction failed.';
|
|
671
|
+
cellFailures.push({ cell: `r${rc.row}c${rc.col}`, error: err });
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
const { cell, rows, text } = res.value;
|
|
675
|
+
cellsRun += 1;
|
|
676
|
+
perCellCounts.push({ cell: `r${cell.row}c${cell.col}`, rows: rows.length });
|
|
677
|
+
for (const row of rows)
|
|
678
|
+
cellRows.push({ row, cell });
|
|
679
|
+
if (text && text.trim())
|
|
680
|
+
cellTexts.push({ cell, text: text.trim() });
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (cellFailures.length === rendered.length && rendered.length > 0) {
|
|
684
|
+
throw new Error(`foveated read failed in every cell (${cellFailures.length}/${rendered.length})`);
|
|
685
|
+
}
|
|
686
|
+
const merged = mergeFoveatedRows(cellRows);
|
|
687
|
+
const diagnostics = {
|
|
688
|
+
foveated: true,
|
|
689
|
+
grid: { cols: grid.cols, rows: grid.rows },
|
|
690
|
+
cellsPlanned: cells.length,
|
|
691
|
+
cellsRun,
|
|
692
|
+
perCellRowCounts: perCellCounts,
|
|
693
|
+
provenance: merged.provenance
|
|
694
|
+
};
|
|
695
|
+
if (cellFailures.length > 0)
|
|
696
|
+
diagnostics.cellFailures = cellFailures;
|
|
697
|
+
if (merged.possibleDuplicates.length > 0) {
|
|
698
|
+
diagnostics.possibleCrossCellDuplicates = merged.possibleDuplicates;
|
|
699
|
+
}
|
|
700
|
+
// DESCRIBE mode → the markdown IS the deliverable: a spatially-labelled transcription
|
|
701
|
+
// of the whole sheet (top→bottom, left→right) the caller reads + interprets. EXTRACT
|
|
702
|
+
// mode → a short provenance summary (the rows are the deliverable).
|
|
703
|
+
const markdown = wantsExtract
|
|
704
|
+
? `foveated ${cellsRun}-cell read (${grid.cols}×${grid.rows} grid, ${merged.rows.length} rows${merged.possibleDuplicates.length > 0
|
|
705
|
+
? `, ${merged.possibleDuplicates.length} possible cross-cell duplicate(s) flagged`
|
|
706
|
+
: ''})`
|
|
707
|
+
: cellTexts
|
|
708
|
+
.slice()
|
|
709
|
+
.sort((a, b) => a.cell.row - b.cell.row || a.cell.col - b.cell.col)
|
|
710
|
+
.map(({ cell, text }) => `### sheet region — row ${cell.row + 1}/${grid.rows}, col ${cell.col + 1}/${grid.cols}\n${text}`)
|
|
711
|
+
.join('\n\n') || '(no legible text found on this sheet)';
|
|
712
|
+
return { rows: merged.rows, diagnostics, markdown };
|
|
713
|
+
}
|
|
714
|
+
async function tryFoveatedExtract(runtime, page, sourceUrl, pageWidthPx, pageHeightPx, input, renderer, aiOrigin, token) {
|
|
715
|
+
return settle(() => foveatedExtract(runtime, page, sourceUrl, pageWidthPx, pageHeightPx, input, renderer, aiOrigin, token));
|
|
716
|
+
}
|
|
717
|
+
async function tryWriteCache(cache, record) {
|
|
718
|
+
return settle(async () => {
|
|
719
|
+
await writeCache(cache, record);
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
async function processPage(page, input, renderer, aiOrigin, token, cache, runtime, ctx) {
|
|
723
|
+
const renderProfile = DEFAULT_RENDER_PROFILE;
|
|
724
|
+
const promptVersion = input.promptVersion ?? DEFAULT_PROMPT_VERSION;
|
|
725
|
+
const cacheKey = buildCacheKey(input.ref, page, renderProfile, promptVersion);
|
|
726
|
+
const wantsExtract = Boolean(input.schema);
|
|
727
|
+
// 1. Cache lookup. A cached record satisfies the markdown path always; it
|
|
728
|
+
// satisfies the extract path too only when it already carries extractRows.
|
|
729
|
+
const cached = await lookupCache(cache, cacheKey, runtime);
|
|
730
|
+
if (cached && isProcessingCacheRecord(cached)) {
|
|
731
|
+
if (!isStaleProcessingCacheRecord(cached)) {
|
|
732
|
+
return { page: processingPage(page, cacheKey, readString(cached.quality?.jobId)) };
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (cached && isErrorCacheRecord(cached)) {
|
|
736
|
+
// Not terminal: after the cool-off a re-read falls THROUGH to a fresh
|
|
737
|
+
// render + re-enqueue (fresh source URL), which overwrites this marker
|
|
738
|
+
// with a processing one. Within the cool-off, serve the error so a tight
|
|
739
|
+
// agent loop cannot hot-requeue the same failing page.
|
|
740
|
+
if (!isRetryableErrorCacheRecord(cached)) {
|
|
741
|
+
return { page: errorPage(page, cacheKey, cached) };
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
else if (cached && (!wantsExtract || cached.extractRows !== undefined)) {
|
|
745
|
+
const cachedResult = {
|
|
746
|
+
page: { index: page, text: cached.ocrMarkdown, cacheHit: true, status: 'ready', cacheKey }
|
|
747
|
+
};
|
|
748
|
+
if (wantsExtract) {
|
|
749
|
+
cachedResult.rows = cached.extractRows ?? [];
|
|
750
|
+
}
|
|
751
|
+
return cachedResult;
|
|
752
|
+
}
|
|
753
|
+
// 2. Render the page PNG ONCE — fed to both the OCR and (optional) extract call.
|
|
754
|
+
const sourceUrl = await resolveFreshSourceUrl(runtime, input.ref, `document-read:p${page}:${cacheKey}`);
|
|
755
|
+
const rendered = await renderer.renderPageClip({ sourceUrl, page, dpi: 150 });
|
|
756
|
+
// 3+4. ONE vision call per page. Each vision call on a rendered sheet is the
|
|
757
|
+
// dominant cost (tens of seconds); doing BOTH an OCR pass AND a schema
|
|
758
|
+
// extract on the same image doubled the latency and pushed a structured read
|
|
759
|
+
// past the tool budget for no added value — the extract reads the SAME image
|
|
760
|
+
// and its raw text serves as the page markdown. So:
|
|
761
|
+
// - schema read → extract ONLY (rows + raw text as markdown)
|
|
762
|
+
// - markdown read → OCR ONLY
|
|
763
|
+
let ocrMarkdown = '';
|
|
764
|
+
let ocrModelId;
|
|
765
|
+
let extractRows;
|
|
766
|
+
let diagnostics;
|
|
767
|
+
let quality;
|
|
768
|
+
// A large/dense architectural sheet downscaled to ONE full-page image makes small
|
|
769
|
+
// detail text illegible → a full-page read returns near-nothing for ~20s of wasted
|
|
770
|
+
// vision time. So for a LARGE (downscale-capped) page we FOVEATE: render a few HIGH-DPI
|
|
771
|
+
// cells from one source fetch and read each — with a schema → EXTRACT rows per cell;
|
|
772
|
+
// without → DESCRIBE (transcribe) each cell. Foveation now runs for BOTH modes so the
|
|
773
|
+
// describe-then-interpret path reads big sheets legibly, not only schema reads. A SMALL
|
|
774
|
+
// page is read in a single full-page pass (no tiling needed).
|
|
775
|
+
const longestEdge = Math.max(rendered.width ?? 0, rendered.height ?? 0);
|
|
776
|
+
let foveated = null;
|
|
777
|
+
if (longestEdge >= FOVEATE_MIN_LONGEST_EDGE_PX) {
|
|
778
|
+
if (asyncFoveationEnabled(runtime, input)) {
|
|
779
|
+
const jobId = await enqueueFoveatedPage({
|
|
780
|
+
runtime,
|
|
781
|
+
ctx,
|
|
782
|
+
input,
|
|
783
|
+
page,
|
|
784
|
+
sourceUrl,
|
|
785
|
+
pageWidthPx: rendered.width ?? 0,
|
|
786
|
+
pageHeightPx: rendered.height ?? 0,
|
|
787
|
+
cacheKey,
|
|
788
|
+
cache,
|
|
789
|
+
renderProfile,
|
|
790
|
+
promptVersion,
|
|
791
|
+
aiOrigin
|
|
792
|
+
});
|
|
793
|
+
if (jobId) {
|
|
794
|
+
const markerRes = await tryWriteProcessingMarker({
|
|
795
|
+
cache,
|
|
796
|
+
input,
|
|
797
|
+
page,
|
|
798
|
+
cacheKey,
|
|
799
|
+
renderProfile,
|
|
800
|
+
promptVersion,
|
|
801
|
+
jobId
|
|
802
|
+
});
|
|
803
|
+
if (!markerRes.ok) {
|
|
804
|
+
// Declared-optional: the queued job writes the final cache record.
|
|
805
|
+
const diagnostic = settleNow(() => getLogger('documents.read', runtime).warn('processing marker write failed', {
|
|
806
|
+
cacheKey,
|
|
807
|
+
error: valueFreeFailure(markerRes.cause)
|
|
808
|
+
}));
|
|
809
|
+
if (!diagnostic.ok)
|
|
810
|
+
settleNow(() => runtime.diagnostics.error('Document diagnostic failed', { scope: 'docs', plugin: 'documents.read', error: new AggregateError([markerRes.cause, diagnostic.cause], 'Primary failure and diagnostic failed.', { cause: markerRes.cause }) }));
|
|
811
|
+
}
|
|
812
|
+
return {
|
|
813
|
+
page: processingPage(page, cacheKey, jobId),
|
|
814
|
+
diagnostics: {
|
|
815
|
+
asyncStatus: 'processing',
|
|
816
|
+
cacheKey,
|
|
817
|
+
jobId,
|
|
818
|
+
message: ASYNC_PROCESSING_MESSAGE
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const foveatedRes = await tryFoveatedExtract(runtime, page, sourceUrl, rendered.width ?? 0, rendered.height ?? 0, input, renderer, aiOrigin, token);
|
|
824
|
+
if (foveatedRes.ok) {
|
|
825
|
+
foveated = foveatedRes.value;
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
foveated = null;
|
|
829
|
+
diagnostics = {
|
|
830
|
+
foveationError: valueFreeFailure(foveatedRes.cause)
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
if (foveated) {
|
|
835
|
+
if (wantsExtract)
|
|
836
|
+
extractRows = foveated.rows;
|
|
837
|
+
diagnostics = foveated.diagnostics;
|
|
838
|
+
ocrMarkdown = foveated.markdown;
|
|
839
|
+
quality = foveated.diagnostics;
|
|
840
|
+
}
|
|
841
|
+
else if (wantsExtract) {
|
|
842
|
+
// Small page, OR foveation didn't run/failed → one full-page extract.
|
|
843
|
+
const extractBody = {
|
|
844
|
+
image: rendered.pngBase64,
|
|
845
|
+
schema: JsonObjectSchema.parse(input.schema),
|
|
846
|
+
promptHint: input.instructions
|
|
847
|
+
};
|
|
848
|
+
if (input.vocabulary)
|
|
849
|
+
extractBody.vocabulary = input.vocabulary;
|
|
850
|
+
if (input.rowContainerKeys)
|
|
851
|
+
extractBody.rowContainerKeys = input.rowContainerKeys;
|
|
852
|
+
if (input.modelName)
|
|
853
|
+
extractBody.modelName = input.modelName;
|
|
854
|
+
const extracted = await callExtract(runtime, aiOrigin, token, extractBody);
|
|
855
|
+
extractRows = extracted.rows;
|
|
856
|
+
const nextDiagnostics = {};
|
|
857
|
+
if (diagnostics)
|
|
858
|
+
Object.assign(nextDiagnostics, diagnostics);
|
|
859
|
+
Object.assign(nextDiagnostics, extracted.diagnostics);
|
|
860
|
+
diagnostics = nextDiagnostics;
|
|
861
|
+
ocrMarkdown = extracted.raw ?? '';
|
|
862
|
+
quality = extracted.diagnostics;
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
// Small page (or foveation failed), DESCRIBE mode → a single VISION OCR pass.
|
|
866
|
+
const ocrBody = {
|
|
867
|
+
image: rendered.pngBase64,
|
|
868
|
+
prompt: foldOcrPrompt(input)
|
|
869
|
+
};
|
|
870
|
+
if (input.modelName)
|
|
871
|
+
ocrBody.modelName = input.modelName;
|
|
872
|
+
const ocr = await callOcr(runtime, aiOrigin, token, ocrBody);
|
|
873
|
+
ocrMarkdown = ocr.markdown || ocr.text;
|
|
874
|
+
ocrModelId = readString(ocr.metadata?.modelId);
|
|
875
|
+
quality = ocr.metadata;
|
|
876
|
+
}
|
|
877
|
+
// 5. Write to cache (markdown always; extractRows when computed).
|
|
878
|
+
// Simple hash: length of pngBase64 + first 32 chars (deterministic, lightweight)
|
|
879
|
+
const sourceHash = `${rendered.pngBase64.length}:${rendered.pngBase64.slice(0, 32)}`;
|
|
880
|
+
const cacheRecord = {
|
|
881
|
+
id: cacheKey,
|
|
882
|
+
ref: input.ref,
|
|
883
|
+
page,
|
|
884
|
+
renderProfile,
|
|
885
|
+
promptVersion,
|
|
886
|
+
ocrMarkdown,
|
|
887
|
+
quality,
|
|
888
|
+
sourceHash,
|
|
889
|
+
renderedAt: new Date().toISOString()
|
|
890
|
+
};
|
|
891
|
+
if (extractRows !== undefined)
|
|
892
|
+
cacheRecord.extractRows = extractRows;
|
|
893
|
+
if (ocrModelId)
|
|
894
|
+
cacheRecord.ocrModelId = ocrModelId;
|
|
895
|
+
// Best-effort cache write — a persistence failure (cloud-api adapter not in
|
|
896
|
+
// scope, platform-web /api/documents/page-cache down) must NOT discard the
|
|
897
|
+
// freshly-computed OCR/extract result the caller needs. Next read re-renders.
|
|
898
|
+
const writeRes = await tryWriteCache(cache, cacheRecord);
|
|
899
|
+
if (!writeRes.ok) {
|
|
900
|
+
// Declared-optional: the page result is returned regardless.
|
|
901
|
+
const diagnostic = settleNow(() => getLogger('documents.read', runtime).warn('page-cache write failed; result returned uncached', {
|
|
902
|
+
cacheKey,
|
|
903
|
+
error: valueFreeFailure(writeRes.cause)
|
|
904
|
+
}));
|
|
905
|
+
if (!diagnostic.ok)
|
|
906
|
+
settleNow(() => runtime.diagnostics.error('Document diagnostic failed', { scope: 'docs', plugin: 'documents.read', error: new AggregateError([writeRes.cause, diagnostic.cause], 'Primary failure and diagnostic failed.', { cause: writeRes.cause }) }));
|
|
907
|
+
}
|
|
908
|
+
const pageReadResult = {
|
|
909
|
+
page: { index: page, text: ocrMarkdown, cacheHit: false, status: 'ready', cacheKey }
|
|
910
|
+
};
|
|
911
|
+
if (wantsExtract)
|
|
912
|
+
pageReadResult.rows = extractRows ?? [];
|
|
913
|
+
if (diagnostics)
|
|
914
|
+
pageReadResult.diagnostics = diagnostics;
|
|
915
|
+
return pageReadResult;
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Render a text-layer sheet index as agent-facing markdown — the document STRUCTURE
|
|
919
|
+
* (page → sheet number → title), domain-neutral. Which sheets matter for a given takeoff is
|
|
920
|
+
* the model's call, steered by the consuming surface's prompt; this index deliberately does
|
|
921
|
+
* NOT pre-filter or label a trade (e.g. "casework") so the same tool serves any discipline.
|
|
922
|
+
*/
|
|
923
|
+
function formatOutlineMarkdown(outline) {
|
|
924
|
+
const sizeNote = outline.pageWidthIn && outline.pageHeightIn
|
|
925
|
+
? `${outline.pageWidthIn}×${outline.pageHeightIn}" sheets`
|
|
926
|
+
: 'sheets';
|
|
927
|
+
const entry = (s) => `- p${s.page}${s.number ? ` — ${s.number}` : ''}${s.title ? ` — ${s.title}` : ''}`;
|
|
928
|
+
const lines = [`# Sheet index — ${outline.pageCount} pages, ${sizeNote}`, ''];
|
|
929
|
+
// When the text layer is garbled (a custom CAD font encoding pdftotext can't decode — real
|
|
930
|
+
// on some architects' sets) the titles are junk: tell the agent to classify by VISION.
|
|
931
|
+
if (outline.textLayerReliable === false) {
|
|
932
|
+
const garbledPages = outline.sheets.filter((s) => s.garbled).map((s) => s.page);
|
|
933
|
+
lines.push('## ⚠️ Text layer unreliable — classify sheets by VISION, not these titles', `This drawing set has a garbled/unreadable text layer (a custom font encoding), so the sheet ` +
|
|
934
|
+
`titles below are NOT trustworthy${garbledPages.length ? ` (affected pages: ${garbledPages.join(', ')})` : ''}. Open the candidate sheets directly with document.view / document.read to SEE and ` +
|
|
935
|
+
'classify each one, rather than trusting this index.', '');
|
|
936
|
+
}
|
|
937
|
+
lines.push('## Sheets (page — number — title):');
|
|
938
|
+
for (const s of outline.sheets)
|
|
939
|
+
lines.push(entry(s));
|
|
940
|
+
return lines.join('\n');
|
|
941
|
+
}
|
|
942
|
+
function tryResolveExtractionSchemaDescriptor(runtime, schemaId) {
|
|
943
|
+
return settleNow(() => runtime
|
|
944
|
+
.query('ai/extraction-schema')
|
|
945
|
+
.withId(schemaId)
|
|
946
|
+
.firstDescriptor());
|
|
947
|
+
}
|
|
948
|
+
async function safeFetchOutline(renderer, sourceUrl) {
|
|
949
|
+
return settle(() => renderer.outline({ sourceUrl }));
|
|
950
|
+
}
|
|
951
|
+
// ---------------------------------------------------------------------------
|
|
952
|
+
// ToolImplementation
|
|
953
|
+
// ---------------------------------------------------------------------------
|
|
954
|
+
export class DocumentReadImplementation {
|
|
955
|
+
/** Builds the renderer for each call's runtime (the plugin selects it by scope). */
|
|
956
|
+
rendererFor;
|
|
957
|
+
constructor(rendererFor) {
|
|
958
|
+
this.rendererFor = rendererFor;
|
|
959
|
+
}
|
|
960
|
+
async execute(rawInput, runtime, ctx) {
|
|
961
|
+
const renderer = this.rendererFor(runtime);
|
|
962
|
+
const parsed = DocumentReadInputSchema.parse(rawInput);
|
|
963
|
+
// Resolve schemaId → inline schema when `schema` is absent.
|
|
964
|
+
// Inline `schema` always takes precedence over `schemaId`.
|
|
965
|
+
// The descriptor ALSO carries an optional domain prompt preamble + vocabulary
|
|
966
|
+
// (PLAN F1): a casework cabinet schema delivers its drawing-literacy estimator
|
|
967
|
+
// prompt as DATA so the GENERIC kernel stays domain-agnostic. We fold those into
|
|
968
|
+
// `input.instructions` / `input.vocabulary` so they ride callExtract → the
|
|
969
|
+
// /api/internal/document-extract `promptHint` / `vocabulary` → extractStructured.
|
|
970
|
+
let resolvedSchema = parsed.schema;
|
|
971
|
+
let schemaPreamble;
|
|
972
|
+
let schemaVocabulary;
|
|
973
|
+
let schemaRowContainerKeys;
|
|
974
|
+
let schemaModelName;
|
|
975
|
+
if (!resolvedSchema && parsed.schemaId) {
|
|
976
|
+
const schemaRes = tryResolveExtractionSchemaDescriptor(runtime, parsed.schemaId);
|
|
977
|
+
if (schemaRes.ok) {
|
|
978
|
+
const descriptor = schemaRes.value;
|
|
979
|
+
if (descriptor?.jsonSchema) {
|
|
980
|
+
resolvedSchema = descriptor.jsonSchema;
|
|
981
|
+
if (descriptor.promptPreamble)
|
|
982
|
+
schemaPreamble = descriptor.promptPreamble;
|
|
983
|
+
if (descriptor.vocabulary)
|
|
984
|
+
schemaVocabulary = descriptor.vocabulary;
|
|
985
|
+
if (descriptor.rowContainerKeys)
|
|
986
|
+
schemaRowContainerKeys = descriptor.rowContainerKeys;
|
|
987
|
+
if (descriptor.preferredModelName)
|
|
988
|
+
schemaModelName = descriptor.preferredModelName;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
else {
|
|
992
|
+
const diagnostic = settleNow(() => getLogger('documents.read', runtime).warn('extraction schema descriptor lookup failed; reading as markdown', {
|
|
993
|
+
schemaId: parsed.schemaId,
|
|
994
|
+
error: valueFreeFailure(schemaRes.cause)
|
|
995
|
+
}));
|
|
996
|
+
if (!diagnostic.ok)
|
|
997
|
+
settleNow(() => runtime.diagnostics.error('Document diagnostic failed', { scope: 'docs', plugin: 'documents.read', error: new AggregateError([schemaRes.cause, diagnostic.cause], 'Primary failure and diagnostic failed.', { cause: schemaRes.cause }) }));
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
// Rebuild input with the resolved schema (+ domain preamble/vocabulary) so
|
|
1001
|
+
// processPage / execute below see a consistent DocumentReadInput. The descriptor
|
|
1002
|
+
// preamble leads; any caller-supplied instructions follow it. Caller-supplied
|
|
1003
|
+
// vocabulary takes precedence over the descriptor default.
|
|
1004
|
+
const foldedInstructions = [schemaPreamble, parsed.instructions].filter(Boolean).join('\n\n') || undefined;
|
|
1005
|
+
// Caller-supplied modelName wins; otherwise the descriptor declares the model.
|
|
1006
|
+
const resolvedModelName = parsed.modelName ?? schemaModelName;
|
|
1007
|
+
const needsRebuild = resolvedSchema !== parsed.schema ||
|
|
1008
|
+
foldedInstructions !== parsed.instructions ||
|
|
1009
|
+
(schemaVocabulary !== undefined && parsed.vocabulary === undefined) ||
|
|
1010
|
+
(schemaRowContainerKeys !== undefined && parsed.rowContainerKeys === undefined) ||
|
|
1011
|
+
(resolvedModelName !== undefined && parsed.modelName === undefined);
|
|
1012
|
+
let input = parsed;
|
|
1013
|
+
if (needsRebuild) {
|
|
1014
|
+
input = { ...parsed, schema: resolvedSchema };
|
|
1015
|
+
if (foldedInstructions !== undefined)
|
|
1016
|
+
input.instructions = foldedInstructions;
|
|
1017
|
+
if (parsed.vocabulary === undefined && schemaVocabulary !== undefined) {
|
|
1018
|
+
input.vocabulary = schemaVocabulary;
|
|
1019
|
+
}
|
|
1020
|
+
if (parsed.rowContainerKeys === undefined && schemaRowContainerKeys !== undefined) {
|
|
1021
|
+
input.rowContainerKeys = schemaRowContainerKeys;
|
|
1022
|
+
}
|
|
1023
|
+
if (parsed.modelName === undefined && resolvedModelName !== undefined) {
|
|
1024
|
+
input.modelName = resolvedModelName;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
// The ai-web origin that hosts the internal OCR + extract endpoints: the
|
|
1028
|
+
// declared `ai` service (NOT_FOUND when this host declares none).
|
|
1029
|
+
const aiOrigin = await resolveAiInternalOrigin(runtime);
|
|
1030
|
+
const token = await resolveInternalServiceToken(runtime);
|
|
1031
|
+
const cache = await resolvePageCacheClient(runtime, ctx, token);
|
|
1032
|
+
// Determine pages to read
|
|
1033
|
+
const pagesToRead = input.pages ?? [];
|
|
1034
|
+
if (pagesToRead.length === 0) {
|
|
1035
|
+
// No pages specified — return the document STRUCTURE so the agent can
|
|
1036
|
+
// target the right pages. Prefer the FREE text-layer sheet index (pdfinfo +
|
|
1037
|
+
// pdftotext, no vision, ~instant): it lists every sheet's number/title and
|
|
1038
|
+
// flags the casework sheets. Fall back to a vision OCR of page 1 only when
|
|
1039
|
+
// the PDF has no text layer (a scanned set).
|
|
1040
|
+
const sourceUrl = await resolveFreshSourceUrl(runtime, input.ref, 'document-read:outline');
|
|
1041
|
+
const outlineRes = await safeFetchOutline(renderer, sourceUrl);
|
|
1042
|
+
if (outlineRes.ok) {
|
|
1043
|
+
if (outlineRes.value.sheets.length > 0) {
|
|
1044
|
+
return {
|
|
1045
|
+
kind: 'markdown',
|
|
1046
|
+
pages: [
|
|
1047
|
+
{
|
|
1048
|
+
index: 0,
|
|
1049
|
+
text: formatOutlineMarkdown(outlineRes.value),
|
|
1050
|
+
cacheHit: false,
|
|
1051
|
+
title: 'Sheet index'
|
|
1052
|
+
}
|
|
1053
|
+
]
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
else {
|
|
1058
|
+
const diagnostic = settleNow(() => getLogger('documents.read', runtime).warn('document outline unavailable; using vision overview', {
|
|
1059
|
+
error: valueFreeFailure(outlineRes.cause)
|
|
1060
|
+
}));
|
|
1061
|
+
if (!diagnostic.ok)
|
|
1062
|
+
settleNow(() => runtime.diagnostics.error('Document diagnostic failed', { scope: 'docs', plugin: 'documents.read', error: new AggregateError([outlineRes.cause, diagnostic.cause], 'Primary failure and diagnostic failed.', { cause: outlineRes.cause }) }));
|
|
1063
|
+
}
|
|
1064
|
+
const overview = await renderer.renderOverview({ sourceUrl, dpi: 72 });
|
|
1065
|
+
const ocrResult = await callOcr(runtime, aiOrigin, token, {
|
|
1066
|
+
image: overview.pngBase64,
|
|
1067
|
+
prompt: foldOcrPrompt({
|
|
1068
|
+
visionFocusHint: input.visionFocusHint ?? 'overview',
|
|
1069
|
+
instructions: input.instructions ??
|
|
1070
|
+
'Extract the table of contents, sheet list, or document structure.'
|
|
1071
|
+
})
|
|
1072
|
+
});
|
|
1073
|
+
return {
|
|
1074
|
+
kind: 'markdown',
|
|
1075
|
+
pages: [
|
|
1076
|
+
{
|
|
1077
|
+
index: 0,
|
|
1078
|
+
title: 'Overview / TOC',
|
|
1079
|
+
text: ocrResult.markdown || ocrResult.text,
|
|
1080
|
+
cacheHit: false
|
|
1081
|
+
}
|
|
1082
|
+
]
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
// Read requested pages (in parallel, capped at 10 concurrent).
|
|
1086
|
+
const CONCURRENCY = 10;
|
|
1087
|
+
const pageReads = [];
|
|
1088
|
+
for (let i = 0; i < pagesToRead.length; i += CONCURRENCY) {
|
|
1089
|
+
const batch = pagesToRead.slice(i, i + CONCURRENCY);
|
|
1090
|
+
const settled = await Promise.all(batch.map((page) => processPage(page, input, renderer, aiOrigin, token, cache, runtime, ctx)));
|
|
1091
|
+
pageReads.push(...settled);
|
|
1092
|
+
}
|
|
1093
|
+
// Sort by page index
|
|
1094
|
+
pageReads.sort((a, b) => a.page.index - b.page.index);
|
|
1095
|
+
// Structured path: a schema produces aggregated rows across all pages.
|
|
1096
|
+
// (Each page was extracted from its own rendered PNG inside processPage.)
|
|
1097
|
+
if (input.schema) {
|
|
1098
|
+
const rows = [];
|
|
1099
|
+
const perPageDiagnostics = {};
|
|
1100
|
+
for (const read of pageReads) {
|
|
1101
|
+
if (read.rows)
|
|
1102
|
+
rows.push(...read.rows);
|
|
1103
|
+
if (read.diagnostics) {
|
|
1104
|
+
perPageDiagnostics[`page-${read.page.index}`] = read.diagnostics;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
// Completeness gate (EMPIRICAL-VERIFIED.md §completeness gate): a STRUCTURED
|
|
1108
|
+
// (schema) read that yields ZERO rows from the requested pages is an UNDER-READ,
|
|
1109
|
+
// not an empty document. Surface it as a diagnostic so the caller never persists
|
|
1110
|
+
// a casework-flagged sheet as "takeoff-ready, no cabinets" — a silent dropped /
|
|
1111
|
+
// under-bid. The agent should re-read at higher DPI / a tighter crop, or report
|
|
1112
|
+
// the sheet unreadable, rather than treat zero rows as authoritative.
|
|
1113
|
+
if (rows.length === 0) {
|
|
1114
|
+
perPageDiagnostics.completeness = {
|
|
1115
|
+
status: 'under_read',
|
|
1116
|
+
message: 'Structured read returned zero rows from the requested page(s) — likely an under-read ' +
|
|
1117
|
+
'(illegible render or a vision miss), not a sheet with no casework. Re-read at a higher ' +
|
|
1118
|
+
'DPI / tighter crop, or report the sheet as unreadable; do NOT treat zero rows as authoritative.'
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
const structuredResult = {
|
|
1122
|
+
kind: 'structured',
|
|
1123
|
+
rows
|
|
1124
|
+
};
|
|
1125
|
+
if (Object.keys(perPageDiagnostics).length > 0) {
|
|
1126
|
+
structuredResult.diagnostics = perPageDiagnostics;
|
|
1127
|
+
}
|
|
1128
|
+
return structuredResult;
|
|
1129
|
+
}
|
|
1130
|
+
// Markdown path: no schema. When input.question is set, the calling agent
|
|
1131
|
+
// reads the returned page markdown to answer it — there is no
|
|
1132
|
+
// markdown-analyzer endpoint, so question alone does NOT trigger extract.
|
|
1133
|
+
return { kind: 'markdown', pages: pageReads.map((r) => r.page) };
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
export function createDocumentReadTool(rendererFor) {
|
|
1137
|
+
return new DocumentReadImplementation(rendererFor);
|
|
1138
|
+
}
|
|
1139
|
+
//# sourceMappingURL=document-read.impl.js.map
|