@wenathlan/saddle 1.8.17 → 2.0.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/Dockerfile +1339 -0
- package/README.md +68 -22
- package/alternatives.ts +1218 -0
- package/biome.json +153 -0
- package/boards.json +1517 -0
- package/compute.ts +3144 -0
- package/cores.json +1801 -0
- package/dist/acquisition.d.ts +359 -0
- package/dist/acquisition.d.ts.map +1 -0
- package/dist/acquisition.js +629 -0
- package/dist/acquisition.js.map +1 -0
- package/dist/alternatives.d.ts +509 -0
- package/dist/alternatives.d.ts.map +1 -0
- package/dist/alternatives.js +951 -0
- package/dist/alternatives.js.map +1 -0
- package/dist/automation.d.ts +426 -0
- package/dist/automation.d.ts.map +1 -0
- package/dist/automation.js +561 -0
- package/dist/automation.js.map +1 -0
- package/dist/browser.d.ts +562 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +1057 -0
- package/dist/browser.js.map +1 -0
- package/dist/capacitor.config.d.ts +13 -0
- package/dist/capacitor.config.d.ts.map +1 -0
- package/dist/capacitor.config.js +26 -0
- package/dist/capacitor.config.js.map +1 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +111 -0
- package/dist/cli.js.map +1 -0
- package/dist/communication.d.ts +192 -0
- package/dist/communication.d.ts.map +1 -0
- package/dist/communication.js +418 -0
- package/dist/communication.js.map +1 -0
- package/dist/compute.d.ts +1161 -0
- package/dist/compute.d.ts.map +1 -0
- package/dist/compute.js +2273 -0
- package/dist/compute.js.map +1 -0
- package/dist/distribution.d.ts +529 -0
- package/dist/distribution.d.ts.map +1 -0
- package/dist/distribution.js +811 -0
- package/dist/distribution.js.map +1 -0
- package/dist/execution.d.ts +530 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +761 -0
- package/dist/execution.js.map +1 -0
- package/dist/format.d.ts +19 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +60 -0
- package/dist/format.js.map +1 -0
- package/dist/foundation.d.ts +176 -0
- package/dist/foundation.d.ts.map +1 -0
- package/dist/foundation.js +309 -0
- package/dist/foundation.js.map +1 -0
- package/dist/index.d.ts +733 -122
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1018 -122
- package/dist/index.js.map +1 -1
- package/dist/integration.d.ts +236 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +236 -0
- package/dist/integration.js.map +1 -0
- package/dist/intelligence.d.ts +94 -0
- package/dist/intelligence.d.ts.map +1 -0
- package/dist/intelligence.js +145 -0
- package/dist/intelligence.js.map +1 -0
- package/dist/isolation.d.ts +129 -0
- package/dist/isolation.d.ts.map +1 -0
- package/dist/isolation.js +96 -0
- package/dist/isolation.js.map +1 -0
- package/dist/media.d.ts +344 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +986 -0
- package/dist/media.js.map +1 -0
- package/dist/modes.d.ts +359 -0
- package/dist/modes.d.ts.map +1 -0
- package/dist/modes.js +134 -0
- package/dist/modes.js.map +1 -0
- package/dist/{library/public.d.ts → operations.d.ts} +15 -1
- package/dist/operations.d.ts.map +1 -0
- package/dist/{library/public.js → operations.js} +18 -7
- package/dist/operations.js.map +1 -0
- package/dist/orchestrator.d.ts +1339 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +4308 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/performance.d.ts +416 -0
- package/dist/performance.d.ts.map +1 -0
- package/dist/performance.js +827 -0
- package/dist/performance.js.map +1 -0
- package/dist/quantum.d.ts +810 -0
- package/dist/quantum.d.ts.map +1 -0
- package/dist/quantum.js +2073 -0
- package/dist/quantum.js.map +1 -0
- package/dist/render.d.ts +381 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +1073 -0
- package/dist/render.js.map +1 -0
- package/dist/scheduler.d.ts +596 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +1259 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/security.d.ts +501 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +1170 -0
- package/dist/security.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/{server/node.js → server.js} +16 -2
- package/dist/server.js.map +1 -0
- package/dist/tiers.d.ts +1002 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +2165 -0
- package/dist/tiers.js.map +1 -0
- package/dist/virtual.d.ts +641 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +1285 -0
- package/dist/virtual.js.map +1 -0
- package/dist/virtualcpu.d.ts +316 -0
- package/dist/virtualcpu.d.ts.map +1 -0
- package/dist/virtualcpu.js +1180 -0
- package/dist/virtualcpu.js.map +1 -0
- package/dist/virtualgpu.d.ts +345 -0
- package/dist/virtualgpu.d.ts.map +1 -0
- package/dist/virtualgpu.js +1000 -0
- package/dist/virtualgpu.js.map +1 -0
- package/dist/virtualization.d.ts +607 -0
- package/dist/virtualization.d.ts.map +1 -0
- package/dist/virtualization.js +1187 -0
- package/dist/virtualization.js.map +1 -0
- package/dist/virtualmemory.d.ts +818 -0
- package/dist/virtualmemory.d.ts.map +1 -0
- package/dist/virtualmemory.js +1796 -0
- package/dist/virtualmemory.js.map +1 -0
- package/dist/webscrape.d.ts +720 -0
- package/dist/webscrape.d.ts.map +1 -0
- package/dist/webscrape.js +2697 -0
- package/dist/webscrape.js.map +1 -0
- package/docker.config +769 -0
- package/docs/CONVERSA.txt +1523 -0
- package/docs/alternatives.md +499 -0
- package/docs/architecture-1.8.19.md +76 -0
- package/docs/architecture-1.8.19.mmd +33 -0
- package/docs/architecture-1.8.19.png +0 -0
- package/docs/architecture.md +355 -0
- package/docs/artifactavailability.md +6 -0
- package/docs/brancharchive-2026-08-18.md +18 -0
- package/docs/browser.md +7 -0
- package/docs/consolidation.md +70 -0
- package/docs/e2ugh-engine.md +528 -0
- package/{dist/examples/localjob.js → docs/example-localjob.ts} +3 -3
- package/{dist/examples/publicapi.js → docs/example-publicapi.ts} +2 -2
- package/docs/hardware.md +342 -0
- package/docs/optimization.md +126 -0
- package/docs/performance.md +499 -0
- package/docs/planning.1.8.18.md +94 -0
- package/docs/planning.1.8.19.md +49 -0
- package/docs/releasenotes-1.8.17.md +6 -0
- package/docs/releasenotes-1.8.18.md +32 -0
- package/docs/releasenotes-1.8.19.md +35 -0
- package/docs/research-1.8.18-isolation.md +43 -0
- package/docs/research-1.8.19-virtual-browser.md +27 -0
- package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
- package/docs/security.md +454 -0
- package/docs/todo-1.8.16.md +56 -1
- package/docs/todo-1.8.18.md +164 -0
- package/docs/todo-1.8.19.md +241 -0
- package/docs/viability.md +777 -0
- package/docs/virtualization.md +335 -0
- package/docs/web-duplicatecleanup.md +9 -0
- package/docs/web-ideas.md +106 -0
- package/docs/workflowimprovements-2026-08-19.md +70 -0
- package/gpumonitor.cpp +1543 -0
- package/gpus.json +2408 -0
- package/index.ts +1478 -0
- package/media.ts +1337 -0
- package/mttg.config +1549 -0
- package/orchestrator.ts +5462 -0
- package/package.json +304 -55
- package/passage.config +1331 -0
- package/performance.ts +1049 -0
- package/processors.json +2217 -0
- package/qemu.config +1062 -0
- package/qemubridge.py +1340 -0
- package/quantum.ts +2393 -0
- package/render.ts +1325 -0
- package/scheduler.ts +1600 -0
- package/security.ts +1449 -0
- package/tiers.ts +2871 -0
- package/tsconfig.json +29 -0
- package/virtualcpu.ts +1273 -0
- package/virtualgpu.ts +1181 -0
- package/virtualhardware.c +1011 -0
- package/virtualhardware.json +739 -0
- package/virtualization.ts +1628 -0
- package/virtualizationcore.cpp +4635 -0
- package/virtualmemory.ts +2303 -0
- package/vm.config.json +1910 -0
- package/{extension → web/extension}/manifest.json +1 -1
- package/web/readme.md +382 -0
- package/web/tsconfig.json +25 -0
- package/dist/adapters/forge.d.ts +0 -17
- package/dist/adapters/forge.d.ts.map +0 -1
- package/dist/adapters/forge.js +0 -19
- package/dist/adapters/forge.js.map +0 -1
- package/dist/adapters/forgejo.d.ts +0 -49
- package/dist/adapters/forgejo.d.ts.map +0 -1
- package/dist/adapters/forgejo.js +0 -8
- package/dist/adapters/forgejo.js.map +0 -1
- package/dist/adapters/github.d.ts +0 -12
- package/dist/adapters/github.d.ts.map +0 -1
- package/dist/adapters/github.js +0 -20
- package/dist/adapters/github.js.map +0 -1
- package/dist/adapters/gitlab.d.ts +0 -17
- package/dist/adapters/gitlab.d.ts.map +0 -1
- package/dist/adapters/gitlab.js +0 -10
- package/dist/adapters/gitlab.js.map +0 -1
- package/dist/adapters/huggingface.d.ts +0 -17
- package/dist/adapters/huggingface.d.ts.map +0 -1
- package/dist/adapters/huggingface.js +0 -6
- package/dist/adapters/huggingface.js.map +0 -1
- package/dist/adapters/socket.d.ts +0 -11
- package/dist/adapters/socket.d.ts.map +0 -1
- package/dist/adapters/socket.js +0 -17
- package/dist/adapters/socket.js.map +0 -1
- package/dist/adapters/transport.d.ts +0 -7
- package/dist/adapters/transport.d.ts.map +0 -1
- package/dist/adapters/transport.js +0 -36
- package/dist/adapters/transport.js.map +0 -1
- package/dist/ai/chunk.d.ts +0 -2
- package/dist/ai/chunk.d.ts.map +0 -1
- package/dist/ai/chunk.js +0 -36
- package/dist/ai/chunk.js.map +0 -1
- package/dist/ai/llmstxt.d.ts +0 -6
- package/dist/ai/llmstxt.d.ts.map +0 -1
- package/dist/ai/llmstxt.js +0 -12
- package/dist/ai/llmstxt.js.map +0 -1
- package/dist/ai/provenance.d.ts +0 -22
- package/dist/ai/provenance.d.ts.map +0 -1
- package/dist/ai/provenance.js +0 -25
- package/dist/ai/provenance.js.map +0 -1
- package/dist/ai/rag.d.ts +0 -26
- package/dist/ai/rag.d.ts.map +0 -1
- package/dist/ai/rag.js +0 -22
- package/dist/ai/rag.js.map +0 -1
- package/dist/ai/tokens.d.ts +0 -15
- package/dist/ai/tokens.d.ts.map +0 -1
- package/dist/ai/tokens.js +0 -9
- package/dist/ai/tokens.js.map +0 -1
- package/dist/api/auth.d.ts +0 -16
- package/dist/api/auth.d.ts.map +0 -1
- package/dist/api/auth.js +0 -19
- package/dist/api/auth.js.map +0 -1
- package/dist/api/contracts.d.ts +0 -28
- package/dist/api/contracts.d.ts.map +0 -1
- package/dist/api/contracts.js +0 -14
- package/dist/api/contracts.js.map +0 -1
- package/dist/api/control.d.ts +0 -10
- package/dist/api/control.d.ts.map +0 -1
- package/dist/api/control.js +0 -35
- package/dist/api/control.js.map +0 -1
- package/dist/api/http.d.ts +0 -7
- package/dist/api/http.d.ts.map +0 -1
- package/dist/api/http.js +0 -12
- package/dist/api/http.js.map +0 -1
- package/dist/api/rate.d.ts +0 -28
- package/dist/api/rate.d.ts.map +0 -1
- package/dist/api/rate.js +0 -36
- package/dist/api/rate.js.map +0 -1
- package/dist/api/security.d.ts +0 -12
- package/dist/api/security.d.ts.map +0 -1
- package/dist/api/security.js +0 -56
- package/dist/api/security.js.map +0 -1
- package/dist/api/service.d.ts +0 -5
- package/dist/api/service.d.ts.map +0 -1
- package/dist/api/service.js +0 -70
- package/dist/api/service.js.map +0 -1
- package/dist/apps/registry.d.ts +0 -33
- package/dist/apps/registry.d.ts.map +0 -1
- package/dist/apps/registry.js +0 -24
- package/dist/apps/registry.js.map +0 -1
- package/dist/binary/archive.d.ts +0 -27
- package/dist/binary/archive.d.ts.map +0 -1
- package/dist/binary/archive.js +0 -46
- package/dist/binary/archive.js.map +0 -1
- package/dist/binary/build.d.ts +0 -29
- package/dist/binary/build.d.ts.map +0 -1
- package/dist/binary/build.js +0 -17
- package/dist/binary/build.js.map +0 -1
- package/dist/binary/transform.d.ts +0 -70
- package/dist/binary/transform.d.ts.map +0 -1
- package/dist/binary/transform.js +0 -105
- package/dist/binary/transform.js.map +0 -1
- package/dist/bot/adapter.d.ts +0 -5
- package/dist/bot/adapter.d.ts.map +0 -1
- package/dist/bot/adapter.js +0 -11
- package/dist/bot/adapter.js.map +0 -1
- package/dist/bot/bot.d.ts +0 -28
- package/dist/bot/bot.d.ts.map +0 -1
- package/dist/bot/bot.js +0 -52
- package/dist/bot/bot.js.map +0 -1
- package/dist/bot/commands.d.ts +0 -8
- package/dist/bot/commands.d.ts.map +0 -1
- package/dist/bot/commands.js +0 -19
- package/dist/bot/commands.js.map +0 -1
- package/dist/bot/permissions.d.ts +0 -13
- package/dist/bot/permissions.d.ts.map +0 -1
- package/dist/bot/permissions.js +0 -16
- package/dist/bot/permissions.js.map +0 -1
- package/dist/browser/actions.d.ts +0 -33
- package/dist/browser/actions.d.ts.map +0 -1
- package/dist/browser/actions.js +0 -44
- package/dist/browser/actions.js.map +0 -1
- package/dist/browser/agent.d.ts +0 -21
- package/dist/browser/agent.d.ts.map +0 -1
- package/dist/browser/agent.js +0 -13
- package/dist/browser/agent.js.map +0 -1
- package/dist/browser/context.d.ts +0 -43
- package/dist/browser/context.d.ts.map +0 -1
- package/dist/browser/context.js +0 -54
- package/dist/browser/context.js.map +0 -1
- package/dist/browser/fingerprint.d.ts +0 -4
- package/dist/browser/fingerprint.d.ts.map +0 -1
- package/dist/browser/fingerprint.js +0 -12
- package/dist/browser/fingerprint.js.map +0 -1
- package/dist/browser/index.d.ts +0 -11
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/index.js +0 -11
- package/dist/browser/index.js.map +0 -1
- package/dist/browser/playwright.d.ts +0 -11
- package/dist/browser/playwright.d.ts.map +0 -1
- package/dist/browser/playwright.js +0 -24
- package/dist/browser/playwright.js.map +0 -1
- package/dist/browser/recorder.d.ts +0 -21
- package/dist/browser/recorder.d.ts.map +0 -1
- package/dist/browser/recorder.js +0 -58
- package/dist/browser/recorder.js.map +0 -1
- package/dist/browser/session.d.ts +0 -14
- package/dist/browser/session.d.ts.map +0 -1
- package/dist/browser/session.js +0 -21
- package/dist/browser/session.js.map +0 -1
- package/dist/browser/snapshot.d.ts +0 -69
- package/dist/browser/snapshot.d.ts.map +0 -1
- package/dist/browser/snapshot.js +0 -133
- package/dist/browser/snapshot.js.map +0 -1
- package/dist/captcha/contract.d.ts +0 -35
- package/dist/captcha/contract.d.ts.map +0 -1
- package/dist/captcha/contract.js +0 -17
- package/dist/captcha/contract.js.map +0 -1
- package/dist/captcha/evidence.d.ts +0 -10
- package/dist/captcha/evidence.d.ts.map +0 -1
- package/dist/captcha/evidence.js +0 -9
- package/dist/captcha/evidence.js.map +0 -1
- package/dist/captcha/guard.d.ts +0 -23
- package/dist/captcha/guard.d.ts.map +0 -1
- package/dist/captcha/guard.js +0 -12
- package/dist/captcha/guard.js.map +0 -1
- package/dist/cli/main.d.ts +0 -4
- package/dist/cli/main.d.ts.map +0 -1
- package/dist/cli/main.js +0 -46
- package/dist/cli/main.js.map +0 -1
- package/dist/core/errors.d.ts +0 -84
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/errors.js +0 -54
- package/dist/core/errors.js.map +0 -1
- package/dist/core/events.d.ts +0 -9
- package/dist/core/events.d.ts.map +0 -1
- package/dist/core/events.js +0 -21
- package/dist/core/events.js.map +0 -1
- package/dist/core/hash.d.ts +0 -10
- package/dist/core/hash.d.ts.map +0 -1
- package/dist/core/hash.js +0 -82
- package/dist/core/hash.js.map +0 -1
- package/dist/core/ids.d.ts +0 -10
- package/dist/core/ids.d.ts.map +0 -1
- package/dist/core/ids.js +0 -15
- package/dist/core/ids.js.map +0 -1
- package/dist/delivery/manifest.d.ts +0 -35
- package/dist/delivery/manifest.d.ts.map +0 -1
- package/dist/delivery/manifest.js +0 -68
- package/dist/delivery/manifest.js.map +0 -1
- package/dist/deploy/index.d.ts +0 -6
- package/dist/deploy/index.d.ts.map +0 -1
- package/dist/deploy/index.js +0 -6
- package/dist/deploy/index.js.map +0 -1
- package/dist/dispatch/resumable.d.ts +0 -102
- package/dist/dispatch/resumable.d.ts.map +0 -1
- package/dist/dispatch/resumable.js +0 -64
- package/dist/dispatch/resumable.js.map +0 -1
- package/dist/dispatch/workflow.d.ts +0 -6
- package/dist/dispatch/workflow.d.ts.map +0 -1
- package/dist/dispatch/workflow.js +0 -37
- package/dist/dispatch/workflow.js.map +0 -1
- package/dist/domain/artifacts.d.ts +0 -12
- package/dist/domain/artifacts.d.ts.map +0 -1
- package/dist/domain/artifacts.js +0 -14
- package/dist/domain/artifacts.js.map +0 -1
- package/dist/domain/jobs.d.ts +0 -12
- package/dist/domain/jobs.d.ts.map +0 -1
- package/dist/domain/jobs.js +0 -20
- package/dist/domain/jobs.js.map +0 -1
- package/dist/domain/providers.d.ts +0 -10
- package/dist/domain/providers.d.ts.map +0 -1
- package/dist/domain/providers.js +0 -8
- package/dist/domain/providers.js.map +0 -1
- package/dist/domain/runtime.d.ts +0 -14
- package/dist/domain/runtime.d.ts.map +0 -1
- package/dist/domain/runtime.js +0 -10
- package/dist/domain/runtime.js.map +0 -1
- package/dist/domain/sessions.d.ts +0 -12
- package/dist/domain/sessions.d.ts.map +0 -1
- package/dist/domain/sessions.js +0 -57
- package/dist/domain/sessions.js.map +0 -1
- package/dist/examples/localjob.d.ts +0 -2
- package/dist/examples/localjob.d.ts.map +0 -1
- package/dist/examples/localjob.js.map +0 -1
- package/dist/examples/publicapi.d.ts +0 -2
- package/dist/examples/publicapi.d.ts.map +0 -1
- package/dist/examples/publicapi.js.map +0 -1
- package/dist/extension/build.d.ts +0 -9
- package/dist/extension/build.d.ts.map +0 -1
- package/dist/extension/build.js +0 -85
- package/dist/extension/build.js.map +0 -1
- package/dist/extension/content.d.ts +0 -6
- package/dist/extension/content.d.ts.map +0 -1
- package/dist/extension/content.js +0 -135
- package/dist/extension/content.js.map +0 -1
- package/dist/extension/index.d.ts +0 -7
- package/dist/extension/index.d.ts.map +0 -1
- package/dist/extension/index.js +0 -7
- package/dist/extension/index.js.map +0 -1
- package/dist/extension/pagebridge.d.ts +0 -6
- package/dist/extension/pagebridge.d.ts.map +0 -1
- package/dist/extension/pagebridge.js +0 -42
- package/dist/extension/pagebridge.js.map +0 -1
- package/dist/extension/permissions.d.ts +0 -26
- package/dist/extension/permissions.d.ts.map +0 -1
- package/dist/extension/permissions.js +0 -28
- package/dist/extension/permissions.js.map +0 -1
- package/dist/extension/popup.d.ts +0 -5
- package/dist/extension/popup.d.ts.map +0 -1
- package/dist/extension/popup.js +0 -26
- package/dist/extension/popup.js.map +0 -1
- package/dist/extension/protocol.d.ts +0 -58
- package/dist/extension/protocol.d.ts.map +0 -1
- package/dist/extension/protocol.js +0 -101
- package/dist/extension/protocol.js.map +0 -1
- package/dist/extension/serviceworker.d.ts +0 -25
- package/dist/extension/serviceworker.d.ts.map +0 -1
- package/dist/extension/serviceworker.js +0 -102
- package/dist/extension/serviceworker.js.map +0 -1
- package/dist/extension/worker.d.ts +0 -28
- package/dist/extension/worker.d.ts.map +0 -1
- package/dist/extension/worker.js +0 -22
- package/dist/extension/worker.js.map +0 -1
- package/dist/format/check.d.ts +0 -8
- package/dist/format/check.d.ts.map +0 -1
- package/dist/format/check.js +0 -38
- package/dist/format/check.js.map +0 -1
- package/dist/library/public.d.ts.map +0 -1
- package/dist/library/public.js.map +0 -1
- package/dist/mcp/browser.d.ts +0 -9
- package/dist/mcp/browser.d.ts.map +0 -1
- package/dist/mcp/browser.js +0 -13
- package/dist/mcp/browser.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -35
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -40
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/transport.d.ts +0 -7
- package/dist/mcp/transport.d.ts.map +0 -1
- package/dist/mcp/transport.js +0 -17
- package/dist/mcp/transport.js.map +0 -1
- package/dist/memory/bridge.d.ts +0 -14
- package/dist/memory/bridge.d.ts.map +0 -1
- package/dist/memory/bridge.js +0 -16
- package/dist/memory/bridge.js.map +0 -1
- package/dist/memory/engine.d.ts +0 -38
- package/dist/memory/engine.d.ts.map +0 -1
- package/dist/memory/engine.js +0 -109
- package/dist/memory/engine.js.map +0 -1
- package/dist/memory/modes.d.ts +0 -43
- package/dist/memory/modes.d.ts.map +0 -1
- package/dist/memory/modes.js +0 -66
- package/dist/memory/modes.js.map +0 -1
- package/dist/memory/objects.d.ts +0 -21
- package/dist/memory/objects.d.ts.map +0 -1
- package/dist/memory/objects.js +0 -20
- package/dist/memory/objects.js.map +0 -1
- package/dist/memory/planner.d.ts +0 -66
- package/dist/memory/planner.d.ts.map +0 -1
- package/dist/memory/planner.js +0 -108
- package/dist/memory/planner.js.map +0 -1
- package/dist/memory/targets.d.ts +0 -78
- package/dist/memory/targets.d.ts.map +0 -1
- package/dist/memory/targets.js +0 -29
- package/dist/memory/targets.js.map +0 -1
- package/dist/memory/transforms.d.ts +0 -19
- package/dist/memory/transforms.d.ts.map +0 -1
- package/dist/memory/transforms.js +0 -14
- package/dist/memory/transforms.js.map +0 -1
- package/dist/modes/matrix.d.ts +0 -23
- package/dist/modes/matrix.d.ts.map +0 -1
- package/dist/modes/matrix.js +0 -18
- package/dist/modes/matrix.js.map +0 -1
- package/dist/modes/modes.d.ts +0 -33
- package/dist/modes/modes.d.ts.map +0 -1
- package/dist/modes/modes.js +0 -15
- package/dist/modes/modes.js.map +0 -1
- package/dist/modes/resolve.d.ts +0 -96
- package/dist/modes/resolve.d.ts.map +0 -1
- package/dist/modes/resolve.js +0 -48
- package/dist/modes/resolve.js.map +0 -1
- package/dist/observability/metrics.d.ts +0 -14
- package/dist/observability/metrics.d.ts.map +0 -1
- package/dist/observability/metrics.js +0 -18
- package/dist/observability/metrics.js.map +0 -1
- package/dist/packager/manifest.d.ts +0 -66
- package/dist/packager/manifest.d.ts.map +0 -1
- package/dist/packager/manifest.js +0 -94
- package/dist/packager/manifest.js.map +0 -1
- package/dist/packager/publish.d.ts +0 -51
- package/dist/packager/publish.d.ts.map +0 -1
- package/dist/packager/publish.js +0 -18
- package/dist/packager/publish.js.map +0 -1
- package/dist/packager/targetcli.d.ts +0 -7
- package/dist/packager/targetcli.d.ts.map +0 -1
- package/dist/packager/targetcli.js +0 -22
- package/dist/packager/targetcli.js.map +0 -1
- package/dist/persistence/adapter.d.ts +0 -5
- package/dist/persistence/adapter.d.ts.map +0 -1
- package/dist/persistence/adapter.js +0 -11
- package/dist/persistence/adapter.js.map +0 -1
- package/dist/persistence/drizzle.d.ts +0 -2
- package/dist/persistence/drizzle.d.ts.map +0 -1
- package/dist/persistence/drizzle.js +0 -12
- package/dist/persistence/drizzle.js.map +0 -1
- package/dist/persistence/memory.d.ts +0 -2
- package/dist/persistence/memory.d.ts.map +0 -1
- package/dist/persistence/memory.js +0 -27
- package/dist/persistence/memory.js.map +0 -1
- package/dist/persistence/migrations.d.ts +0 -19
- package/dist/persistence/migrations.d.ts.map +0 -1
- package/dist/persistence/migrations.js +0 -13
- package/dist/persistence/migrations.js.map +0 -1
- package/dist/persistence/prisma.d.ts +0 -2
- package/dist/persistence/prisma.d.ts.map +0 -1
- package/dist/persistence/prisma.js +0 -25
- package/dist/persistence/prisma.js.map +0 -1
- package/dist/persistence/schema.d.ts +0 -63
- package/dist/persistence/schema.d.ts.map +0 -1
- package/dist/persistence/schema.js +0 -28
- package/dist/persistence/schema.js.map +0 -1
- package/dist/persistence/sql.d.ts +0 -3
- package/dist/persistence/sql.d.ts.map +0 -1
- package/dist/persistence/sql.js +0 -37
- package/dist/persistence/sql.js.map +0 -1
- package/dist/protocol/blocks.d.ts +0 -10
- package/dist/protocol/blocks.d.ts.map +0 -1
- package/dist/protocol/blocks.js +0 -26
- package/dist/protocol/blocks.js.map +0 -1
- package/dist/protocol/json.d.ts +0 -6
- package/dist/protocol/json.d.ts.map +0 -1
- package/dist/protocol/json.js +0 -6
- package/dist/protocol/json.js.map +0 -1
- package/dist/protocol/ndjson.d.ts +0 -3
- package/dist/protocol/ndjson.d.ts.map +0 -1
- package/dist/protocol/ndjson.js +0 -20
- package/dist/protocol/ndjson.js.map +0 -1
- package/dist/protocol/sse.d.ts +0 -7
- package/dist/protocol/sse.d.ts.map +0 -1
- package/dist/protocol/sse.js +0 -25
- package/dist/protocol/sse.js.map +0 -1
- package/dist/proxy/pool.d.ts +0 -9
- package/dist/proxy/pool.d.ts.map +0 -1
- package/dist/proxy/pool.js +0 -27
- package/dist/proxy/pool.js.map +0 -1
- package/dist/queue/idempotency.d.ts +0 -10
- package/dist/queue/idempotency.d.ts.map +0 -1
- package/dist/queue/idempotency.js +0 -13
- package/dist/queue/idempotency.js.map +0 -1
- package/dist/queue/persistent.d.ts +0 -14
- package/dist/queue/persistent.d.ts.map +0 -1
- package/dist/queue/persistent.js +0 -66
- package/dist/queue/persistent.js.map +0 -1
- package/dist/queue/queue.d.ts +0 -7
- package/dist/queue/queue.d.ts.map +0 -1
- package/dist/queue/queue.js +0 -55
- package/dist/queue/queue.js.map +0 -1
- package/dist/queue/saga.d.ts +0 -5
- package/dist/queue/saga.d.ts.map +0 -1
- package/dist/queue/saga.js +0 -20
- package/dist/queue/saga.js.map +0 -1
- package/dist/release/assets.d.ts +0 -144
- package/dist/release/assets.d.ts.map +0 -1
- package/dist/release/assets.js +0 -157
- package/dist/release/assets.js.map +0 -1
- package/dist/release/evidence.d.ts +0 -92
- package/dist/release/evidence.d.ts.map +0 -1
- package/dist/release/evidence.js +0 -148
- package/dist/release/evidence.js.map +0 -1
- package/dist/release/verify.d.ts +0 -12
- package/dist/release/verify.d.ts.map +0 -1
- package/dist/release/verify.js +0 -112
- package/dist/release/verify.js.map +0 -1
- package/dist/runners/chain.d.ts +0 -125
- package/dist/runners/chain.d.ts.map +0 -1
- package/dist/runners/chain.js +0 -95
- package/dist/runners/chain.js.map +0 -1
- package/dist/runners/health.d.ts +0 -36
- package/dist/runners/health.d.ts.map +0 -1
- package/dist/runners/health.js +0 -26
- package/dist/runners/health.js.map +0 -1
- package/dist/runners/heartbeat.d.ts +0 -23
- package/dist/runners/heartbeat.d.ts.map +0 -1
- package/dist/runners/heartbeat.js +0 -29
- package/dist/runners/heartbeat.js.map +0 -1
- package/dist/runners/inprocess.d.ts +0 -17
- package/dist/runners/inprocess.d.ts.map +0 -1
- package/dist/runners/inprocess.js +0 -20
- package/dist/runners/inprocess.js.map +0 -1
- package/dist/runners/scheduler.d.ts +0 -5
- package/dist/runners/scheduler.d.ts.map +0 -1
- package/dist/runners/scheduler.js +0 -19
- package/dist/runners/scheduler.js.map +0 -1
- package/dist/runtime/abort.d.ts +0 -8
- package/dist/runtime/abort.d.ts.map +0 -1
- package/dist/runtime/abort.js +0 -13
- package/dist/runtime/abort.js.map +0 -1
- package/dist/runtime/compatibility.d.ts +0 -37
- package/dist/runtime/compatibility.d.ts.map +0 -1
- package/dist/runtime/compatibility.js +0 -10
- package/dist/runtime/compatibility.js.map +0 -1
- package/dist/runtime/detect.d.ts +0 -13
- package/dist/runtime/detect.d.ts.map +0 -1
- package/dist/runtime/detect.js +0 -18
- package/dist/runtime/detect.js.map +0 -1
- package/dist/runtime/engine.d.ts +0 -20
- package/dist/runtime/engine.d.ts.map +0 -1
- package/dist/runtime/engine.js +0 -61
- package/dist/runtime/engine.js.map +0 -1
- package/dist/runtime/retry.d.ts +0 -19
- package/dist/runtime/retry.d.ts.map +0 -1
- package/dist/runtime/retry.js +0 -54
- package/dist/runtime/retry.js.map +0 -1
- package/dist/runtime/worker.d.ts +0 -10
- package/dist/runtime/worker.d.ts.map +0 -1
- package/dist/runtime/worker.js +0 -25
- package/dist/runtime/worker.js.map +0 -1
- package/dist/scrape/cache.d.ts +0 -45
- package/dist/scrape/cache.d.ts.map +0 -1
- package/dist/scrape/cache.js +0 -45
- package/dist/scrape/cache.js.map +0 -1
- package/dist/scrape/crawl.d.ts +0 -47
- package/dist/scrape/crawl.d.ts.map +0 -1
- package/dist/scrape/crawl.js +0 -114
- package/dist/scrape/crawl.js.map +0 -1
- package/dist/scrape/extract.d.ts +0 -63
- package/dist/scrape/extract.d.ts.map +0 -1
- package/dist/scrape/extract.js +0 -47
- package/dist/scrape/extract.js.map +0 -1
- package/dist/scrape/normalize.d.ts +0 -52
- package/dist/scrape/normalize.d.ts.map +0 -1
- package/dist/scrape/normalize.js +0 -102
- package/dist/scrape/normalize.js.map +0 -1
- package/dist/scrape/robots.d.ts +0 -37
- package/dist/scrape/robots.d.ts.map +0 -1
- package/dist/scrape/robots.js +0 -71
- package/dist/scrape/robots.js.map +0 -1
- package/dist/scrape/schema.d.ts +0 -23
- package/dist/scrape/schema.d.ts.map +0 -1
- package/dist/scrape/schema.js +0 -92
- package/dist/scrape/schema.js.map +0 -1
- package/dist/scrape/scraper.d.ts +0 -6
- package/dist/scrape/scraper.d.ts.map +0 -1
- package/dist/scrape/scraper.js +0 -46
- package/dist/scrape/scraper.js.map +0 -1
- package/dist/scrape/semantic.d.ts +0 -25
- package/dist/scrape/semantic.d.ts.map +0 -1
- package/dist/scrape/semantic.js +0 -27
- package/dist/scrape/semantic.js.map +0 -1
- package/dist/server/node.d.ts +0 -7
- package/dist/server/node.d.ts.map +0 -1
- package/dist/server/node.js.map +0 -1
- package/dist/sessions/file.d.ts +0 -25
- package/dist/sessions/file.d.ts.map +0 -1
- package/dist/sessions/file.js +0 -13
- package/dist/sessions/file.js.map +0 -1
- package/dist/sessions/replay.d.ts +0 -9
- package/dist/sessions/replay.d.ts.map +0 -1
- package/dist/sessions/replay.js +0 -70
- package/dist/sessions/replay.js.map +0 -1
- package/dist/sessions/store.d.ts +0 -25
- package/dist/sessions/store.d.ts.map +0 -1
- package/dist/sessions/store.js +0 -13
- package/dist/sessions/store.js.map +0 -1
- package/dist/storage/adapter.d.ts +0 -5
- package/dist/storage/adapter.d.ts.map +0 -1
- package/dist/storage/adapter.js +0 -11
- package/dist/storage/adapter.js.map +0 -1
- package/dist/storage/cache.d.ts +0 -23
- package/dist/storage/cache.d.ts.map +0 -1
- package/dist/storage/cache.js +0 -79
- package/dist/storage/cache.js.map +0 -1
- package/dist/storage/checksum.d.ts +0 -3
- package/dist/storage/checksum.d.ts.map +0 -1
- package/dist/storage/checksum.js +0 -19
- package/dist/storage/checksum.js.map +0 -1
- package/dist/storage/chunked.d.ts +0 -21
- package/dist/storage/chunked.d.ts.map +0 -1
- package/dist/storage/chunked.js +0 -67
- package/dist/storage/chunked.js.map +0 -1
- package/dist/storage/content.d.ts +0 -24
- package/dist/storage/content.d.ts.map +0 -1
- package/dist/storage/content.js +0 -44
- package/dist/storage/content.js.map +0 -1
- package/dist/storage/filehosting.d.ts +0 -2
- package/dist/storage/filehosting.d.ts.map +0 -1
- package/dist/storage/filehosting.js +0 -24
- package/dist/storage/filehosting.js.map +0 -1
- package/dist/storage/githubcontents.d.ts +0 -2
- package/dist/storage/githubcontents.d.ts.map +0 -1
- package/dist/storage/githubcontents.js +0 -29
- package/dist/storage/githubcontents.js.map +0 -1
- package/dist/storage/index.d.ts +0 -12
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js +0 -12
- package/dist/storage/index.js.map +0 -1
- package/dist/storage/local.d.ts +0 -2
- package/dist/storage/local.d.ts.map +0 -1
- package/dist/storage/local.js +0 -72
- package/dist/storage/local.js.map +0 -1
- package/dist/storage/memory.d.ts +0 -6
- package/dist/storage/memory.d.ts.map +0 -1
- package/dist/storage/memory.js +0 -36
- package/dist/storage/memory.js.map +0 -1
- package/dist/storage/pool.d.ts +0 -95
- package/dist/storage/pool.d.ts.map +0 -1
- package/dist/storage/pool.js +0 -202
- package/dist/storage/pool.js.map +0 -1
- package/dist/storage/s3compatible.d.ts +0 -3
- package/dist/storage/s3compatible.d.ts.map +0 -1
- package/dist/storage/s3compatible.js +0 -70
- package/dist/storage/s3compatible.js.map +0 -1
- package/dist/storage/sync.d.ts +0 -47
- package/dist/storage/sync.d.ts.map +0 -1
- package/dist/storage/sync.js +0 -75
- package/dist/storage/sync.js.map +0 -1
- package/dist/surfaces/adapters.d.ts +0 -97
- package/dist/surfaces/adapters.d.ts.map +0 -1
- package/dist/surfaces/adapters.js +0 -50
- package/dist/surfaces/adapters.js.map +0 -1
- package/dist/surfaces/controls.d.ts +0 -18
- package/dist/surfaces/controls.d.ts.map +0 -1
- package/dist/surfaces/controls.js +0 -45
- package/dist/surfaces/controls.js.map +0 -1
- package/dist/surfaces/manifest.d.ts +0 -68
- package/dist/surfaces/manifest.d.ts.map +0 -1
- package/dist/surfaces/manifest.js +0 -42
- package/dist/surfaces/manifest.js.map +0 -1
- package/dist/surfaces/n8n.d.ts +0 -25
- package/dist/surfaces/n8n.d.ts.map +0 -1
- package/dist/surfaces/n8n.js +0 -31
- package/dist/surfaces/n8n.js.map +0 -1
- package/dist/surfaces/operations.d.ts +0 -32
- package/dist/surfaces/operations.d.ts.map +0 -1
- package/dist/surfaces/operations.js +0 -53
- package/dist/surfaces/operations.js.map +0 -1
- package/dist/surfaces/requirements.d.ts +0 -29
- package/dist/surfaces/requirements.d.ts.map +0 -1
- package/dist/surfaces/requirements.js +0 -50
- package/dist/surfaces/requirements.js.map +0 -1
- package/dist/surfaces/targets.d.ts +0 -196
- package/dist/surfaces/targets.d.ts.map +0 -1
- package/dist/surfaces/targets.js +0 -27
- package/dist/surfaces/targets.js.map +0 -1
- package/dist/webhook/delivery.d.ts +0 -18
- package/dist/webhook/delivery.d.ts.map +0 -1
- package/dist/webhook/delivery.js +0 -36
- package/dist/webhook/delivery.js.map +0 -1
- package/dist/webhook/receiver.d.ts +0 -26
- package/dist/webhook/receiver.d.ts.map +0 -1
- package/dist/webhook/receiver.js +0 -24
- package/dist/webhook/receiver.js.map +0 -1
- package/dist/webhook/signature.d.ts +0 -3
- package/dist/webhook/signature.d.ts.map +0 -1
- package/dist/webhook/signature.js +0 -7
- package/dist/webhook/signature.js.map +0 -1
- package/dist/workflow/manifest.d.ts +0 -22
- package/dist/workflow/manifest.d.ts.map +0 -1
- package/dist/workflow/manifest.js +0 -21
- package/dist/workflow/manifest.js.map +0 -1
- package/dist/workflow/registry.d.ts +0 -7
- package/dist/workflow/registry.d.ts.map +0 -1
- package/dist/workflow/registry.js +0 -18
- package/dist/workflow/registry.js.map +0 -1
- package/dist/workflow/templates.d.ts +0 -6
- package/dist/workflow/templates.d.ts.map +0 -1
- package/dist/workflow/templates.js +0 -18
- package/dist/workflow/templates.js.map +0 -1
- package/dist/workflow/triggers.d.ts +0 -64
- package/dist/workflow/triggers.d.ts.map +0 -1
- package/dist/workflow/triggers.js +0 -99
- package/dist/workflow/triggers.js.map +0 -1
- package/docs/logs/.gitkeep +0 -0
- package/docs/plans/00.index.md +0 -50
- package/docs/plans/01.architecture.md +0 -86
- package/docs/plans/02.research.computer.use.md +0 -58
- package/docs/plans/03.research.captcha.bypass.md +0 -68
- package/docs/plans/04.research.sandbox.ai.md +0 -52
- package/docs/plans/05.capture.platform.md +0 -57
- package/docs/plans/06.dependencies.md +0 -97
- package/docs/plans/07.captcha.test.page.md +0 -41
- package/docs/plans/08.production.infra.md +0 -70
- package/docs/plans/09.database.schema.md +0 -121
- package/docs/plans/10.cloudinary.storage.md +0 -57
- package/docs/plans/11.movement.logs.json.md +0 -72
- package/docs/plans/12.research.atlas.agent.browser.md +0 -79
- package/docs/plans/13.research.anti.detection.md +0 -898
- package/docs/plans/14.research.proxy.md +0 -1495
- package/docs/plans/15.research.retry.rate.limit.md +0 -1958
- package/docs/plans/16.research.crawling.md +0 -1417
- package/docs/plans/17.research.caching.md +0 -1610
- package/docs/plans/18.research.content.extraction.md +0 -1952
- package/docs/plans/19.research.errors.events.md +0 -1523
- package/docs/plans/20.research.zod.validation.md +0 -1350
- package/docs/plans/21.research.batch.concurrency.md +0 -1888
- package/docs/plans/22.research.universal.runtime.md +0 -944
- package/docs/plans/23.research.ai.integration.md +0 -1465
- package/docs/plans/24.research.memory.persistence.md +0 -1979
- package/docs/plans/25.research.server.api.md +0 -342
- package/docs/plans/26.research.compilation.md +0 -249
- package/docs/plans/27.research.html.parsing.md +0 -251
- package/docs/plans/28.action.plan.md +0 -50
- package/docs/plans/29.api.reference.md +0 -174
- package/docs/plans/30.architecture.plan.md +0 -94
- package/docs/plans/31.auditoria.dados.md +0 -163
- package/docs/plans/32.bots.automacao.computacional.md +0 -214
- package/docs/plans/33.bots.codigo.revisao.md +0 -220
- package/docs/plans/34.bots.seguranca.cicd.md +0 -366
- package/docs/plans/35.comparativo.concorrencia.md +0 -464
- package/docs/plans/36.computational.memory.md +0 -340
- package/docs/plans/37.deploystrategy.md +0 -394
- package/docs/plans/38.flow.md +0 -155
- package/docs/plans/39.multi.platform.bot.md +0 -252
- package/docs/plans/40.npm.publish.md +0 -250
- package/docs/plans/41.o.que.falta.md +0 -407
- package/docs/plans/42.pesquisa.concorrencia.md +0 -721
- package/docs/plans/43.plan.universal.architecture.md +0 -496
- package/docs/plans/44.reference.md +0 -100
- package/docs/plans/45.robotarchitecture.md +0 -237
- package/docs/plans/46.scdnintegration.md +0 -284
- package/docs/plans/47.multiforge.readme.md +0 -129
- package/docs/plans/48.theory.v4.repo.os.md +0 -152
- package/docs/plans/49.third.party.infra.md +0 -12
- package/docs/plans/50.file.as.compute.md +0 -39
- package/docs/plans/51.architecture.virtual.processor.md +0 -80
- package/docs/plans/52.manifesto.v8.md +0 -11
- package/docs/plans/58.cdn.list.md +0 -23
- package/docs/plans/59.sql.frameworks.md +0 -33
- package/docs/plans/60.sql.thirdparty.md +0 -26
- package/docs/plans/61.objective.multiforge.md +0 -63
- package/docs/plans/62.huggingface.upload.md +0 -26
- package/docs/plans/63.kaggle.upload.md +0 -24
- package/docs/plans/64.npm.storage.md +0 -30
- package/docs/plans/65.rclone.terabox.md +0 -32
- package/docs/plans/66.buckets.and.models.todo.md +0 -14
- package/docs/plans/67.database.todo.md +0 -13
- package/docs/plans/68.deploy.packages.todo.md +0 -12
- package/docs/plans/69.report.human.operator.md +0 -133
- package/docs/plans/70.report.brain2qwerty.ems.md +0 -135
- package/docs/plans/71.report.hd.infinito.vram.md +0 -155
- package/docs/plans/72.plan.hd.infinito.node.md +0 -146
- package/docs/plans/73.plan.scifi.repos.md +0 -125
- package/docs/plans/74.000.manifesto.v8.flat.2..md +0 -11
- package/docs/plans/README.md +0 -489
- package/docs/plans/aggregate_platforms.mjs +0 -146
- package/docs/plans/examplesession.json +0 -36
- package/docs/plans/missing-facts.md +0 -192
- package/docs/plans/models.md +0 -64
- package/docs/plans/organize.cjs +0 -270
- package/docs/plans/platforms.md +0 -2887
- package/docs/plans/sites.md +0 -31322
- package/docs/sources/farm.py +0 -117
- package/docs/sources/html/saddle1.html +0 -132
- package/docs/sources/html/saddle2.html +0 -157
- package/docs/sources/html/saddle3.html +0 -119
- package/docs/sources/html/saddle4.html +0 -144
- package/docs/sources/html/saddle5.html +0 -72
- package/docs/sources/html/saddle6.html +0 -171
- package/docs/sources/html/saddle7.html +0 -236
- package/docs/sources/saddle.ts +0 -74
- package/docs/sources/schema.prisma +0 -88
- package/docs/sources/script.sh +0 -64
- package/docs/sources/workflows.yml +0 -458
- package/docs/talks1/_body.txt +0 -14
- package/docs/talks1/_index.md +0 -15
- package/docs/talks1/_screenshot.png +0 -0
- package/docs/talks1/assistant-01.md +0 -5
- package/docs/talks1/assistant-02.md +0 -5
- package/docs/talks1/assistant-03.md +0 -531
- package/docs/talks1/assistant-04.md +0 -26
- package/docs/talks1/assistant-05.md +0 -774
- package/docs/talks1/assistant-06.md +0 -1718
- package/docs/talks1/scrape-share.cjs +0 -185
- package/docs/talks1/scrape-share.ts +0 -183
- package/docs/talks1/user-01.md +0 -3
- package/docs/talks1/user-02.md +0 -3
- package/docs/talks1/user-03.md +0 -88
- package/docs/talks1/user-04.md +0 -3
- package/docs/talks1/user-05.md +0 -3
- package/docs/talks1/user-06.md +0 -88
- package/docs/talks1/user-07.md +0 -88
- package/docs/talks2/_body.txt +0 -14
- package/docs/talks2/_index.md +0 -16
- package/docs/talks2/_screenshot.png +0 -0
- package/docs/talks2/assistant-01.md +0 -5
- package/docs/talks2/assistant-02.md +0 -5
- package/docs/talks2/assistant-03.md +0 -424
- package/docs/talks2/assistant-04.md +0 -598
- package/docs/talks2/assistant-05.md +0 -1280
- package/docs/talks2/assistant-06.md +0 -1227
- package/docs/talks2/assistant-07.md +0 -1252
- package/docs/talks2/user-01.md +0 -3
- package/docs/talks2/user-02.md +0 -3
- package/docs/talks2/user-03.md +0 -88
- package/docs/talks2/user-04.md +0 -88
- package/docs/talks2/user-05.md +0 -88
- package/docs/talks2/user-06.md +0 -88
- package/docs/talks2/user-07.md +0 -3
- package/docs/talks3/_body.txt +0 -467
- package/docs/talks3/_index.md +0 -10
- package/docs/talks3/_screenshot.png +0 -0
- package/docs/talks3/assistant-01.md +0 -417
- package/docs/talks3/assistant-02.md +0 -417
- package/docs/talks3/assistant-03.md +0 -29
- package/docs/talks3/assistant-04.md +0 -727
- package/docs/talks3/user-01.md +0 -88
- package/docs/talks3/user-02.md +0 -88
- package/docs/talks3/user-03.md +0 -3
- package/docs/talks3/user-04.md +0 -3
- package/docs/talks4/_body.txt +0 -14
- package/docs/talks4/_index.md +0 -12
- package/docs/talks4/_screenshot.png +0 -0
- package/docs/talks4/assistant-01.md +0 -5
- package/docs/talks4/assistant-02.md +0 -5
- package/docs/talks4/assistant-03.md +0 -35
- package/docs/talks4/assistant-04.md +0 -512
- package/docs/talks4/assistant-05.md +0 -599
- package/docs/talks4/user-01.md +0 -3
- package/docs/talks4/user-02.md +0 -3
- package/docs/talks4/user-03.md +0 -88
- package/docs/talks4/user-04.md +0 -88
- package/docs/talks4/user-05.md +0 -7
- package/docs/talks5/_body.txt +0 -14
- package/docs/talks5/_index.md +0 -13
- package/docs/talks5/_screenshot.png +0 -0
- package/docs/talks5/assistant-01.md +0 -5
- package/docs/talks5/assistant-02.md +0 -5
- package/docs/talks5/assistant-03.md +0 -690
- package/docs/talks5/assistant-04.md +0 -758
- package/docs/talks5/assistant-05.md +0 -974
- package/docs/talks5/user-01.md +0 -3
- package/docs/talks5/user-02.md +0 -3
- package/docs/talks5/user-03.md +0 -105
- package/docs/talks5/user-04.md +0 -105
- package/docs/talks5/user-05.md +0 -63
- package/docs/talks5/user-06.md +0 -105
- package/docs/talks6/_body.txt +0 -14
- package/docs/talks6/_index.md +0 -9
- package/docs/talks6/_screenshot.png +0 -0
- package/docs/talks6/assistant-01.md +0 -5
- package/docs/talks6/assistant-02.md +0 -5
- package/docs/talks6/assistant-03.md +0 -1499
- package/docs/talks6/user-01.md +0 -3
- package/docs/talks6/user-02.md +0 -3
- package/docs/talks6/user-03.md +0 -88
- package/docs/talks6/user-04.md +0 -88
- package/docs/talks7/_body.txt +0 -14
- package/docs/talks7/_index.md +0 -10
- package/docs/talks7/_screenshot.png +0 -0
- package/docs/talks7/assistant-01.md +0 -5
- package/docs/talks7/assistant-02.md +0 -5
- package/docs/talks7/assistant-03.md +0 -523
- package/docs/talks7/assistant-04.md +0 -617
- package/docs/talks7/user-01.md +0 -3
- package/docs/talks7/user-02.md +0 -3
- package/docs/talks7/user-03.md +0 -105
- package/docs/talks7/user-04.md +0 -67
- package/docs/talks8/conversa1.txt +0 -1322
- package/docs/talks8/conversa2.txt +0 -237
- package/docs/talks9/Beyond the Obvious_ 50 Plataformas Auto-Hospedadas de Forja de C/303/263digo para Al/303/251m de Gitea e GitLab.md" +0 -174
- package/docs/talks9/De NPM a Multi-Linguagem_ Uma Arquitetura T/303/251cnica para a Execu/303/247/303/243o Integrada de C/303/263digo no Ecossistema Node.js.md" +0 -59
- package/docs/talks9/De NPM a VMs Virtuais_ Uma An/303/241lise Arquitet/303/264nica para a Realiza/303/247/303/243o do Ciclo de Vida do Projeto SADDLE.md" +0 -91
- package/docs/talks9/Mapeamento da Engrenagem Computacional_ Uma Arquitetura para Execu/303/247/303/243o Isolada e Persist/303/252ncia em Ambientes Distribu/303/255dos.md" +0 -116
- package/docs/talks9/O Cen/303/241rio Pr/303/241tico do SADDLE_ Uma An/303/241lise de Viabilidade e Modelo de Ciclo de Vida Integrado.md" +0 -128
- package/docs/talks9/README (2).md +0 -489
- package/docs/talks9/README.md +0 -198
- package/docs/talks9/Viabilidade do Saddle_ Uma An/303/241lise T/303/251cnica da Transforma/303/247/303/243o de Armazenamento Remoto em Mem/303/263ria Computacional.md" +0 -80
- package/docs/talks9/conversa.txt +0 -544
- package/docs/talks9/other (2).md +0 -39
- package/docs/talks9/other.md +0 -57
- package/docs/talks9/outro.txt +0 -24
- /package/{extension/README.md → docs/extension.md} +0 -0
|
@@ -1,1465 +0,0 @@
|
|
|
1
|
-
# Pesquisa: AI/LLM Integration para Web Scraping (2026)
|
|
2
|
-
|
|
3
|
-
> Como integrar scraping web com LLMs: formatação para consumo de tokens, RAG pipelines, extração inteligente, e spec llms.txt.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1. Formatting Scraped Content for LLMs
|
|
8
|
-
|
|
9
|
-
### Markdown como ponte universal
|
|
10
|
-
|
|
11
|
-
Markdown é o formato ideal para LLMs porque:
|
|
12
|
-
|
|
13
|
-
1. **Estrutura sem overhead** — headings, lists, code blocks são compactos
|
|
14
|
-
2. **60-80% reduction de tokens** vs HTML puro
|
|
15
|
-
3. **Preserva semântica** — bold, italic, links, tabelas mantêm significado
|
|
16
|
-
4. **Fácil de parsear** — qualquer LLM entende Markdown nativamente
|
|
17
|
-
|
|
18
|
-
### Comparação de formatos
|
|
19
|
-
|
|
20
|
-
| Formato | Tokens (p/ 1KB de conteúdo) | Preservação semântica | Facilidade de parse |
|
|
21
|
-
|---------|----------------------------|----------------------|-------------------|
|
|
22
|
-
| HTML puro | ~300-400 | Alta | Alta |
|
|
23
|
-
| HTML limpo | ~200-250 | Média | Média |
|
|
24
|
-
| **Markdown** | **~80-120** | **Alta** | **Alta** |
|
|
25
|
-
| Texto puro | ~60-80 | Baixa | Baixa |
|
|
26
|
-
| JSON | ~150-200 | Alta | Alta |
|
|
27
|
-
|
|
28
|
-
### Estratégia de conversão HTML → Markdown
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import TurndownService from 'turndown';
|
|
32
|
-
|
|
33
|
-
function htmlToLLMContent(html: string, options?: {
|
|
34
|
-
preserveTables?: boolean;
|
|
35
|
-
preserveCodeBlocks?: boolean;
|
|
36
|
-
maxLineLength?: number;
|
|
37
|
-
}): string {
|
|
38
|
-
const turndown = new TurndownService({
|
|
39
|
-
headingStyle: 'atx',
|
|
40
|
-
codeBlockStyle: 'fenced',
|
|
41
|
-
bulletListMarker: '-',
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Remover elementos irrelevantes para LLMs
|
|
45
|
-
turndown.remove([
|
|
46
|
-
'script', 'style', 'noscript',
|
|
47
|
-
'nav', 'footer', 'header', // Navigation boilerplate
|
|
48
|
-
'aside', // Ads, sidebars
|
|
49
|
-
'[role="navigation"]',
|
|
50
|
-
'[role="banner"]',
|
|
51
|
-
'.ad', '.advertisement', '.sidebar',
|
|
52
|
-
'.cookie-banner', '.popup',
|
|
53
|
-
]);
|
|
54
|
-
|
|
55
|
-
// Preservar tabelas como Markdown
|
|
56
|
-
if (options?.preserveTables !== false) {
|
|
57
|
-
turndown.addRule('tables', {
|
|
58
|
-
filter: 'table',
|
|
59
|
-
replacement: (_content, node) => {
|
|
60
|
-
const table = node as HTMLTableElement;
|
|
61
|
-
const rows = Array.from(table.rows);
|
|
62
|
-
if (rows.length === 0) return '';
|
|
63
|
-
|
|
64
|
-
const header = Array.from(rows[0].cells)
|
|
65
|
-
.map(c => c.textContent?.trim() ?? '')
|
|
66
|
-
.join(' | ');
|
|
67
|
-
|
|
68
|
-
const separator = Array.from(rows[0].cells)
|
|
69
|
-
.map(() => '---')
|
|
70
|
-
.join(' | ');
|
|
71
|
-
|
|
72
|
-
const body = rows.slice(1).map(row =>
|
|
73
|
-
Array.from(row.cells)
|
|
74
|
-
.map(c => c.textContent?.trim() ?? '')
|
|
75
|
-
.join(' | ')
|
|
76
|
-
).join('\n');
|
|
77
|
-
|
|
78
|
-
return `\n\n${header}\n${separator}\n${body}\n\n`;
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let markdown = turndown.turndown(html);
|
|
84
|
-
|
|
85
|
-
// Limpar whitespace excessivo
|
|
86
|
-
markdown = markdown
|
|
87
|
-
.replace(/\n{3,}/g, '\n\n') // Max 2 newlines
|
|
88
|
-
.replace(/[ \t]+$/gm, '') // Trailing spaces
|
|
89
|
-
.trim();
|
|
90
|
-
|
|
91
|
-
// Truncar se muito longo (opcional)
|
|
92
|
-
if (options?.maxLineLength && markdown.length > options.maxLineLength) {
|
|
93
|
-
markdown = markdown.slice(0, options.maxLineLength) + '\n\n[...truncated]';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return markdown;
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Metadata para LLM context
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
interface LLMFormattedContent {
|
|
104
|
-
content: string; // Markdown limpo
|
|
105
|
-
metadata: {
|
|
106
|
-
sourceUrl: string;
|
|
107
|
-
title: string;
|
|
108
|
-
description: string;
|
|
109
|
-
scrapedAt: string;
|
|
110
|
-
contentHash: string; // SHA-256 para dedup
|
|
111
|
-
tokenEstimate: number; // Estimativa de tokens
|
|
112
|
-
headingPath: string[]; // Hierarquia de headings
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function formatForLLM(scrapeResult: ScrapeResult): LLMFormattedContent {
|
|
117
|
-
const content = htmlToLLMContent(scrapeResult.content);
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
content,
|
|
121
|
-
metadata: {
|
|
122
|
-
sourceUrl: scrapeResult.url,
|
|
123
|
-
title: scrapeResult.metadata.title,
|
|
124
|
-
description: scrapeResult.metadata.description,
|
|
125
|
-
scrapedAt: new Date().toISOString(),
|
|
126
|
-
contentHash: hashContent(content),
|
|
127
|
-
tokenEstimate: estimateTokens(content),
|
|
128
|
-
headingPath: extractHeadingPath(content),
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function hashContent(content: string): string {
|
|
134
|
-
return crypto.subtle
|
|
135
|
-
.digest('SHA-256', new TextEncoder().encode(content))
|
|
136
|
-
.then(buf => Array.from(new Uint8Array(buf))
|
|
137
|
-
.map(b => b.toString(16).padStart(2, '0'))
|
|
138
|
-
.join(''));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function estimateTokens(content: string): number {
|
|
142
|
-
// Estimativa: ~4 chars por token (média para inglês)
|
|
143
|
-
return Math.ceil(content.length / 4);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function extractHeadingPath(content: string): string[] {
|
|
147
|
-
const headings = content.match(/^#{1,6}\s+(.+)$/gm) ?? [];
|
|
148
|
-
return headings.map(h => {
|
|
149
|
-
const level = h.match(/^(#+)/)?.[1].length ?? 1;
|
|
150
|
-
const text = h.replace(/^#+\s+/, '');
|
|
151
|
-
return `${level}:${text}`;
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## 2. Token Limits e Chunking Strategies
|
|
159
|
-
|
|
160
|
-
### Limites de contexto por modelo (2026)
|
|
161
|
-
|
|
162
|
-
| Modelo | Context Window | Sweet Spot (eficiente) | Max Input Tokens |
|
|
163
|
-
|--------|---------------|----------------------|-----------------|
|
|
164
|
-
| GPT-4o | 128K | 8K-32K | ~100K |
|
|
165
|
-
| GPT-4o-mini | 128K | 4K-16K | ~100K |
|
|
166
|
-
| Claude 3.5 Sonnet | 200K | 8K-32K | ~180K |
|
|
167
|
-
| Claude 3 Opus | 200K | 8K-32K | ~180K |
|
|
168
|
-
| Gemini 1.5 Pro | 2M | 16K-128K | ~1.8M |
|
|
169
|
-
| Gemini 1.5 Flash | 1M | 8K-64K | ~900K |
|
|
170
|
-
| Llama 3.1 405B | 128K | 4K-16K | ~100K |
|
|
171
|
-
| Mistral Large | 128K | 4K-16K | ~100K |
|
|
172
|
-
|
|
173
|
-
### Sweet spot: 400-512 tokens por chunk
|
|
174
|
-
|
|
175
|
-
**Por que 400-512 tokens?**
|
|
176
|
-
|
|
177
|
-
1. **Embedding models** — a maioria treina com chunks de 512 tokens
|
|
178
|
-
2. **Retrieval quality** — chunks muito pequenos perdem contexto, muito grandes diluem
|
|
179
|
-
3. **Memory efficiency** — vetores de 512 tokens são eficientes em storage
|
|
180
|
-
4. **Overlap** — 10-20% de overlap (40-100 tokens) garante continuidade
|
|
181
|
-
|
|
182
|
-
### Estratégias de chunking
|
|
183
|
-
|
|
184
|
-
#### 2.1. Fixed-size chunks (simples, não recomendado)
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
function fixedChunk(text: string, size = 500, overlap = 50): string[] {
|
|
188
|
-
const chunks: string[] = [];
|
|
189
|
-
const words = text.split(/\s+/);
|
|
190
|
-
|
|
191
|
-
for (let i = 0; i < words.length; i += size - overlap) {
|
|
192
|
-
chunks.push(words.slice(i, i + size).join(' '));
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return chunks;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// ❌ Problema: corta no meio de frases e parágrafos
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
#### 2.2. Recursive character splitting (69% accuracy)
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
function recursiveChunk(
|
|
205
|
-
text: string,
|
|
206
|
-
maxTokens = 512,
|
|
207
|
-
overlap = 0.1
|
|
208
|
-
): string[] {
|
|
209
|
-
const separators = ['\n\n', '\n', '. ', '! ', '? ', ', ', ' '];
|
|
210
|
-
|
|
211
|
-
return chunkRecursive(text, maxTokens, overlap, separators);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function chunkRecursive(
|
|
215
|
-
text: string,
|
|
216
|
-
maxTokens: number,
|
|
217
|
-
overlap: number,
|
|
218
|
-
separators: string[]
|
|
219
|
-
): string[] {
|
|
220
|
-
if (estimateTokens(text) <= maxTokens) {
|
|
221
|
-
return [text];
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const separator = separators[0];
|
|
225
|
-
const remainingSeparators = separators.slice(1);
|
|
226
|
-
|
|
227
|
-
if (!separator) {
|
|
228
|
-
// Fallback: cortar por caracteres
|
|
229
|
-
return hardChunk(text, maxTokens);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const parts = text.split(separator);
|
|
233
|
-
const chunks: string[] = [];
|
|
234
|
-
let current = '';
|
|
235
|
-
|
|
236
|
-
for (const part of parts) {
|
|
237
|
-
const test = current ? current + separator + part : part;
|
|
238
|
-
|
|
239
|
-
if (estimateTokens(test) > maxTokens && current) {
|
|
240
|
-
chunks.push(current);
|
|
241
|
-
// Overlap: manter últimos N tokens
|
|
242
|
-
const overlapTokens = Math.floor(maxTokens * overlap);
|
|
243
|
-
current = keepLastTokens(current, overlapTokens) + separator + part;
|
|
244
|
-
} else {
|
|
245
|
-
current = test;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (current) {
|
|
250
|
-
chunks.push(current);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Recursivamente quebrar chunks que ainda são grandes
|
|
254
|
-
return chunks.flatMap(chunk =>
|
|
255
|
-
estimateTokens(chunk) > maxTokens
|
|
256
|
-
? chunkRecursive(chunk, maxTokens, overlap, remainingSeparators)
|
|
257
|
-
: [chunk]
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function hardChunk(text: string, maxTokens: number): string[] {
|
|
262
|
-
const chars = text.split('');
|
|
263
|
-
const chunks: string[] = [];
|
|
264
|
-
let current = '';
|
|
265
|
-
|
|
266
|
-
for (const char of chars) {
|
|
267
|
-
current += char;
|
|
268
|
-
if (estimateTokens(current) >= maxTokens) {
|
|
269
|
-
chunks.push(current);
|
|
270
|
-
current = '';
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (current) chunks.push(current);
|
|
275
|
-
return chunks;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
function keepLastTokens(text: string, tokens: number): string {
|
|
279
|
-
const words = text.split(/\s+/);
|
|
280
|
-
const keepWords = Math.floor(tokens * 1.3); // ~1.3 words per token
|
|
281
|
-
return words.slice(-keepWords).join(' ');
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
#### 2.3. Hierarchical parent-child (padrão production)
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
interface HierarchicalChunk {
|
|
289
|
-
id: string;
|
|
290
|
-
content: string;
|
|
291
|
-
parent?: string; // heading pai
|
|
292
|
-
children?: string[]; // sub-chunks
|
|
293
|
-
metadata: {
|
|
294
|
-
heading: string;
|
|
295
|
-
level: number;
|
|
296
|
-
tokenCount: number;
|
|
297
|
-
position: number;
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function hierarchicalChunk(markdown: string, maxTokens = 512): HierarchicalChunk[] {
|
|
302
|
-
const sections = splitByHeadings(markdown);
|
|
303
|
-
const chunks: HierarchicalChunk[] = [];
|
|
304
|
-
|
|
305
|
-
for (let i = 0; i < sections.length; i++) {
|
|
306
|
-
const section = sections[i];
|
|
307
|
-
const tokens = estimateTokens(section.content);
|
|
308
|
-
|
|
309
|
-
if (tokens <= maxTokens) {
|
|
310
|
-
// Seção cabe em um chunk
|
|
311
|
-
chunks.push({
|
|
312
|
-
id: `chunk-${i}`,
|
|
313
|
-
content: section.content,
|
|
314
|
-
parent: section.parentHeading,
|
|
315
|
-
metadata: {
|
|
316
|
-
heading: section.heading,
|
|
317
|
-
level: section.level,
|
|
318
|
-
tokenCount: tokens,
|
|
319
|
-
position: i,
|
|
320
|
-
},
|
|
321
|
-
});
|
|
322
|
-
} else {
|
|
323
|
-
// Seção é grande — subdividir
|
|
324
|
-
const subChunks = recursiveChunk(section.content, maxTokens, 0.1);
|
|
325
|
-
for (let j = 0; j < subChunks.length; j++) {
|
|
326
|
-
chunks.push({
|
|
327
|
-
id: `chunk-${i}-${j}`,
|
|
328
|
-
content: subChunks[j],
|
|
329
|
-
parent: section.heading,
|
|
330
|
-
metadata: {
|
|
331
|
-
heading: `${section.heading} (part ${j + 1})`,
|
|
332
|
-
level: section.level,
|
|
333
|
-
tokenCount: estimateTokens(subChunks[j]),
|
|
334
|
-
position: i * 100 + j,
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Link parent-child
|
|
342
|
-
for (const chunk of chunks) {
|
|
343
|
-
const parent = chunks.find(c =>
|
|
344
|
-
c.metadata.heading === chunk.parent &&
|
|
345
|
-
c.metadata.level < chunk.metadata.level
|
|
346
|
-
);
|
|
347
|
-
if (parent) {
|
|
348
|
-
if (!parent.children) parent.children = [];
|
|
349
|
-
parent.children.push(chunk.id);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
return chunks;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
interface Section {
|
|
357
|
-
heading: string;
|
|
358
|
-
level: number;
|
|
359
|
-
parentHeading: string;
|
|
360
|
-
content: string;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
function splitByHeadings(markdown: string): Section[] {
|
|
364
|
-
const lines = markdown.split('\n');
|
|
365
|
-
const sections: Section[] = [];
|
|
366
|
-
let current: Section | null = null;
|
|
367
|
-
let headingStack: { heading: string; level: number }[] = [];
|
|
368
|
-
|
|
369
|
-
for (const line of lines) {
|
|
370
|
-
const match = line.match(/^(#{1,6})\s+(.+)/);
|
|
371
|
-
if (match) {
|
|
372
|
-
const level = match[1].length;
|
|
373
|
-
const heading = match[2];
|
|
374
|
-
|
|
375
|
-
// Atualizar stack
|
|
376
|
-
while (headingStack.length > 0 && headingStack[headingStack.length - 1].level >= level) {
|
|
377
|
-
headingStack.pop();
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const parentHeading = headingStack.length > 0
|
|
381
|
-
? headingStack[headingStack.length - 1].heading
|
|
382
|
-
: '';
|
|
383
|
-
|
|
384
|
-
if (current) sections.push(current);
|
|
385
|
-
|
|
386
|
-
current = {
|
|
387
|
-
heading,
|
|
388
|
-
level,
|
|
389
|
-
parentHeading,
|
|
390
|
-
content: line + '\n',
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
headingStack.push({ heading, level });
|
|
394
|
-
} else if (current) {
|
|
395
|
-
current.content += line + '\n';
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (current) sections.push(current);
|
|
400
|
-
return sections;
|
|
401
|
-
}
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
---
|
|
405
|
-
|
|
406
|
-
## 3. RAG Pipeline Completo
|
|
407
|
-
|
|
408
|
-
### Pipeline: Fetch → Extract → Normalize → Markdown → Chunk → Embed → Store
|
|
409
|
-
|
|
410
|
-
```
|
|
411
|
-
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
412
|
-
│ Fetch │───▶│ Extract │───▶│ Normalize│───▶│ Markdown │
|
|
413
|
-
│ (fetch) │ │ (cheerio)│ │ (clean) │ │(turndown)│
|
|
414
|
-
└─────────┘ └──────────┘ └──────────┘ └──────────┘
|
|
415
|
-
│
|
|
416
|
-
▼
|
|
417
|
-
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
418
|
-
│ Store │◀───│ Embed │◀───│ Chunk │◀───│ Metadata │
|
|
419
|
-
│ (vector) │ │(embeddings│ │(hierar.) │ │ (hash) │
|
|
420
|
-
└─────────┘ └──────────┘ └──────────┘ └──────────┘
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### Implementação completa
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
// src/core/rag-pipeline.ts
|
|
427
|
-
import TurndownService from 'turndown';
|
|
428
|
-
import { createHash } from 'node:crypto';
|
|
429
|
-
|
|
430
|
-
interface RAGConfig {
|
|
431
|
-
maxChunkTokens?: number;
|
|
432
|
-
chunkOverlap?: number;
|
|
433
|
-
embeddingModel?: string;
|
|
434
|
-
vectorStore?: 'memory' | 'sqlite' | 'redis';
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
interface ProcessedDocument {
|
|
438
|
-
id: string;
|
|
439
|
-
url: string;
|
|
440
|
-
title: string;
|
|
441
|
-
content: string;
|
|
442
|
-
chunks: ProcessedChunk[];
|
|
443
|
-
metadata: DocumentMetadata;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
interface ProcessedChunk {
|
|
447
|
-
id: string;
|
|
448
|
-
documentId: string;
|
|
449
|
-
content: string;
|
|
450
|
-
embedding?: number[];
|
|
451
|
-
metadata: ChunkMetadata;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
interface DocumentMetadata {
|
|
455
|
-
url: string;
|
|
456
|
-
title: string;
|
|
457
|
-
description: string;
|
|
458
|
-
scrapedAt: string;
|
|
459
|
-
contentHash: string;
|
|
460
|
-
totalTokens: number;
|
|
461
|
-
language: string;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
interface ChunkMetadata {
|
|
465
|
-
sourceUrl: string;
|
|
466
|
-
headingPath: string[];
|
|
467
|
-
contentHash: string;
|
|
468
|
-
tokenCount: number;
|
|
469
|
-
position: number;
|
|
470
|
-
parentChunkId?: string;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
class RAGPipeline {
|
|
474
|
-
private config: RAGConfig;
|
|
475
|
-
|
|
476
|
-
constructor(config: RAGConfig = {}) {
|
|
477
|
-
this.config = {
|
|
478
|
-
maxChunkTokens: 512,
|
|
479
|
-
chunkOverlap: 0.1,
|
|
480
|
-
embeddingModel: 'text-embedding-3-small',
|
|
481
|
-
vectorStore: 'memory',
|
|
482
|
-
...config,
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// Pipeline completo: URL → Document processado
|
|
487
|
-
async processUrl(url: string): Promise<ProcessedDocument> {
|
|
488
|
-
// 1. Fetch
|
|
489
|
-
const response = await fetch(url);
|
|
490
|
-
const html = await response.text();
|
|
491
|
-
|
|
492
|
-
// 2. Extract + Normalize
|
|
493
|
-
const normalized = this.extractAndNormalize(html, url);
|
|
494
|
-
|
|
495
|
-
// 3. Convert to Markdown
|
|
496
|
-
const markdown = this.htmlToMarkdown(normalized.content);
|
|
497
|
-
|
|
498
|
-
// 4. Add metadata header
|
|
499
|
-
const fullContent = this.addMetadataHeader(markdown, normalized.metadata);
|
|
500
|
-
|
|
501
|
-
// 5. Chunk
|
|
502
|
-
const chunks = this.hierarchicalChunk(fullContent, normalized.metadata);
|
|
503
|
-
|
|
504
|
-
return {
|
|
505
|
-
id: this.generateId(url),
|
|
506
|
-
url,
|
|
507
|
-
title: normalized.metadata.title,
|
|
508
|
-
content: fullContent,
|
|
509
|
-
chunks,
|
|
510
|
-
metadata: normalized.metadata,
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// Processar múltiplas URLs com deduplicação
|
|
515
|
-
async processUrls(
|
|
516
|
-
urls: string[],
|
|
517
|
-
onProgress?: (current: number, total: number) => void
|
|
518
|
-
): Promise<ProcessedDocument[]> {
|
|
519
|
-
const documents: ProcessedDocument[] = [];
|
|
520
|
-
const seen = new Set<string>();
|
|
521
|
-
|
|
522
|
-
for (let i = 0; i < urls.length; i++) {
|
|
523
|
-
const url = urls[i];
|
|
524
|
-
|
|
525
|
-
// Deduplicação por URL
|
|
526
|
-
if (seen.has(url)) continue;
|
|
527
|
-
seen.add(url);
|
|
528
|
-
|
|
529
|
-
try {
|
|
530
|
-
const doc = await this.processUrl(url);
|
|
531
|
-
documents.push(doc);
|
|
532
|
-
onProgress?.(i + 1, urls.length);
|
|
533
|
-
} catch (error) {
|
|
534
|
-
console.error(`Failed to process ${url}:`, error);
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
return documents;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
private extractAndNormalize(html: string, url: string) {
|
|
542
|
-
// Usar cheerio para extrair conteúdo limpo
|
|
543
|
-
// Similar ao que já existe no projeto
|
|
544
|
-
const title = '';
|
|
545
|
-
const description = '';
|
|
546
|
-
const content = html;
|
|
547
|
-
|
|
548
|
-
const contentHash = createHash('sha256')
|
|
549
|
-
.update(content)
|
|
550
|
-
.digest('hex');
|
|
551
|
-
|
|
552
|
-
return {
|
|
553
|
-
content,
|
|
554
|
-
metadata: {
|
|
555
|
-
url,
|
|
556
|
-
title,
|
|
557
|
-
description,
|
|
558
|
-
scrapedAt: new Date().toISOString(),
|
|
559
|
-
contentHash,
|
|
560
|
-
totalTokens: estimateTokens(content),
|
|
561
|
-
language: 'en',
|
|
562
|
-
},
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
private htmlToMarkdown(html: string): string {
|
|
567
|
-
const turndown = new TurndownService({
|
|
568
|
-
headingStyle: 'atx',
|
|
569
|
-
codeBlockStyle: 'fenced',
|
|
570
|
-
});
|
|
571
|
-
|
|
572
|
-
turndown.remove(['script', 'style', 'nav', 'footer', 'aside']);
|
|
573
|
-
return turndown.turndown(html);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
private addMetadataHeader(content: string, metadata: DocumentMetadata): string {
|
|
577
|
-
return `---
|
|
578
|
-
source: ${metadata.url}
|
|
579
|
-
title: "${metadata.title}"
|
|
580
|
-
description: "${metadata.description}"
|
|
581
|
-
scraped_at: ${metadata.scrapedAt}
|
|
582
|
-
content_hash: ${metadata.contentHash}
|
|
583
|
-
language: ${metadata.language}
|
|
584
|
-
---
|
|
585
|
-
|
|
586
|
-
${content}`;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
private hierarchicalChunk(
|
|
590
|
-
content: string,
|
|
591
|
-
docMetadata: DocumentMetadata
|
|
592
|
-
): ProcessedChunk[] {
|
|
593
|
-
const sections = splitByHeadings(content);
|
|
594
|
-
const chunks: ProcessedChunk[] = [];
|
|
595
|
-
|
|
596
|
-
for (let i = 0; i < sections.length; i++) {
|
|
597
|
-
const section = sections[i];
|
|
598
|
-
const tokens = estimateTokens(section.content);
|
|
599
|
-
|
|
600
|
-
if (tokens <= this.config.maxChunkTokens!) {
|
|
601
|
-
chunks.push(this.createChunk(
|
|
602
|
-
section.content,
|
|
603
|
-
docMetadata,
|
|
604
|
-
i,
|
|
605
|
-
section.headingPath
|
|
606
|
-
));
|
|
607
|
-
} else {
|
|
608
|
-
const subChunks = recursiveChunk(
|
|
609
|
-
section.content,
|
|
610
|
-
this.config.maxChunkTokens!,
|
|
611
|
-
this.config.chunkOverlap!
|
|
612
|
-
);
|
|
613
|
-
for (let j = 0; j < subChunks.length; j++) {
|
|
614
|
-
chunks.push(this.createChunk(
|
|
615
|
-
subChunks[j],
|
|
616
|
-
docMetadata,
|
|
617
|
-
i * 100 + j,
|
|
618
|
-
[...section.headingPath, `${section.heading} (part ${j + 1})`]
|
|
619
|
-
));
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
return chunks;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
private createChunk(
|
|
628
|
-
content: string,
|
|
629
|
-
docMetadata: DocumentMetadata,
|
|
630
|
-
position: number,
|
|
631
|
-
headingPath: string[]
|
|
632
|
-
): ProcessedChunk {
|
|
633
|
-
const contentHash = createHash('sha256')
|
|
634
|
-
.update(content)
|
|
635
|
-
.digest('hex');
|
|
636
|
-
|
|
637
|
-
return {
|
|
638
|
-
id: `${docMetadata.contentHash.slice(0, 8)}-${position}`,
|
|
639
|
-
documentId: docMetadata.contentHash.slice(0, 16),
|
|
640
|
-
content,
|
|
641
|
-
metadata: {
|
|
642
|
-
sourceUrl: docMetadata.url,
|
|
643
|
-
headingPath,
|
|
644
|
-
contentHash,
|
|
645
|
-
tokenCount: estimateTokens(content),
|
|
646
|
-
position,
|
|
647
|
-
},
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
private generateId(url: string): string {
|
|
652
|
-
return createHash('sha256')
|
|
653
|
-
.update(url)
|
|
654
|
-
.digest('hex')
|
|
655
|
-
.slice(0, 16);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
```
|
|
659
|
-
|
|
660
|
-
---
|
|
661
|
-
|
|
662
|
-
## 4. AI-Powered Content Extraction
|
|
663
|
-
|
|
664
|
-
### Padrão: Extract Once, Scrape Millions
|
|
665
|
-
|
|
666
|
-
```typescript
|
|
667
|
-
// src/core/ai-extraction.ts
|
|
668
|
-
|
|
669
|
-
interface ExtractionSchema {
|
|
670
|
-
name: string;
|
|
671
|
-
fields: {
|
|
672
|
-
name: string;
|
|
673
|
-
type: 'string' | 'number' | 'boolean' | 'array';
|
|
674
|
-
description: string;
|
|
675
|
-
required: boolean;
|
|
676
|
-
}[];
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
interface ExtractedResult {
|
|
680
|
-
schema: string;
|
|
681
|
-
data: Record<string, unknown>;
|
|
682
|
-
confidence: number;
|
|
683
|
-
sourceUrl: string;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
// Schema para extrair produtos
|
|
687
|
-
const ProductSchema: ExtractionSchema = {
|
|
688
|
-
name: 'product',
|
|
689
|
-
fields: [
|
|
690
|
-
{ name: 'name', type: 'string', description: 'Product name', required: true },
|
|
691
|
-
{ name: 'price', type: 'number', description: 'Price in USD', required: true },
|
|
692
|
-
{ name: 'currency', type: 'string', description: 'Currency code', required: true },
|
|
693
|
-
{ name: 'description', type: 'string', description: 'Product description', required: false },
|
|
694
|
-
{ name: 'rating', type: 'number', description: 'Average rating 0-5', required: false },
|
|
695
|
-
{ name: 'reviewCount', type: 'number', description: 'Number of reviews', required: false },
|
|
696
|
-
{ name: 'inStock', type: 'boolean', description: 'Available in stock', required: true },
|
|
697
|
-
{ name: 'images', type: 'array', description: 'Image URLs', required: false },
|
|
698
|
-
],
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
async function extractWithLLM(
|
|
702
|
-
content: string,
|
|
703
|
-
schema: ExtractionSchema,
|
|
704
|
-
llmConfig: { apiKey: string; model: string; baseUrl: string }
|
|
705
|
-
): Promise<ExtractedResult> {
|
|
706
|
-
const prompt = `Extract structured data from the following content according to this schema:
|
|
707
|
-
|
|
708
|
-
Schema: ${JSON.stringify(schema, null, 2)}
|
|
709
|
-
|
|
710
|
-
Content:
|
|
711
|
-
${content}
|
|
712
|
-
|
|
713
|
-
Return ONLY valid JSON matching the schema. No explanation.`;
|
|
714
|
-
|
|
715
|
-
const response = await fetch(`${llmConfig.baseUrl}/chat/completions`, {
|
|
716
|
-
method: 'POST',
|
|
717
|
-
headers: {
|
|
718
|
-
'Content-Type': 'application/json',
|
|
719
|
-
'Authorization': `Bearer ${llmConfig.apiKey}`,
|
|
720
|
-
},
|
|
721
|
-
body: JSON.stringify({
|
|
722
|
-
model: llmConfig.model,
|
|
723
|
-
messages: [
|
|
724
|
-
{
|
|
725
|
-
role: 'system',
|
|
726
|
-
content: 'You are a data extraction assistant. Return only valid JSON.',
|
|
727
|
-
},
|
|
728
|
-
{ role: 'user', content: prompt },
|
|
729
|
-
],
|
|
730
|
-
temperature: 0,
|
|
731
|
-
response_format: { type: 'json_object' },
|
|
732
|
-
}),
|
|
733
|
-
});
|
|
734
|
-
|
|
735
|
-
const result = await response.json();
|
|
736
|
-
const data = JSON.parse(result.choices[0].message.content);
|
|
737
|
-
|
|
738
|
-
return {
|
|
739
|
-
schema: schema.name,
|
|
740
|
-
data,
|
|
741
|
-
confidence: calculateConfidence(data, schema),
|
|
742
|
-
sourceUrl: '',
|
|
743
|
-
};
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
function calculateConfidence(
|
|
747
|
-
data: Record<string, unknown>,
|
|
748
|
-
schema: ExtractionSchema
|
|
749
|
-
): number {
|
|
750
|
-
const requiredFields = schema.fields.filter(f => f.required);
|
|
751
|
-
const presentFields = requiredFields.filter(f => data[f.name] !== undefined);
|
|
752
|
-
return presentFields.length / requiredFields.length;
|
|
753
|
-
}
|
|
754
|
-
```
|
|
755
|
-
|
|
756
|
-
### Self-Healing Selectors
|
|
757
|
-
|
|
758
|
-
```typescript
|
|
759
|
-
// src/core/self-healing.ts
|
|
760
|
-
|
|
761
|
-
interface SelectorStrategy {
|
|
762
|
-
name: string;
|
|
763
|
-
priority: number;
|
|
764
|
-
test: (url: string, html: string) => Promise<boolean>;
|
|
765
|
-
extract: (html: string) => string;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
class SelfHealingExtractor {
|
|
769
|
-
private strategies: SelectorStrategy[] = [];
|
|
770
|
-
|
|
771
|
-
addStrategy(strategy: SelectorStrategy) {
|
|
772
|
-
this.strategies.push(strategy);
|
|
773
|
-
this.strategies.sort((a, b) => b.priority - a.priority);
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
async extract(url: string, html: string): Promise<string | null> {
|
|
777
|
-
for (const strategy of this.strategies) {
|
|
778
|
-
try {
|
|
779
|
-
const works = await strategy.test(url, html);
|
|
780
|
-
if (works) {
|
|
781
|
-
return strategy.extract(html);
|
|
782
|
-
}
|
|
783
|
-
} catch {
|
|
784
|
-
continue;
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
return null;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// Auto-heal: quando um selector quebra, tentar alternativas
|
|
791
|
-
async heal(
|
|
792
|
-
url: string,
|
|
793
|
-
html: string,
|
|
794
|
-
failedSelector: string
|
|
795
|
-
): Promise<string | null> {
|
|
796
|
-
// 1. Tentar variações do selector quebrado
|
|
797
|
-
const variations = this.generateSelectorVariations(failedSelector);
|
|
798
|
-
for (const variation of variations) {
|
|
799
|
-
const result = this.trySelector(html, variation);
|
|
800
|
-
if (result) return result;
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
// 2. Usar estratégias ML-based (AI extraction)
|
|
804
|
-
const aiResult = await this.extract(url, html);
|
|
805
|
-
if (aiResult) return aiResult;
|
|
806
|
-
|
|
807
|
-
// 3. Fallback: extrair todo texto
|
|
808
|
-
return this.extractAllText(html);
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
private generateSelectorVariations(selector: string): string[] {
|
|
812
|
-
const variations: string[] = [];
|
|
813
|
-
|
|
814
|
-
// Adicionar/remover classes
|
|
815
|
-
const classMatch = selector.match(/\.([a-zA-Z0-9_-]+)/);
|
|
816
|
-
if (classMatch) {
|
|
817
|
-
variations.push(selector.replace(classMatch[0], ''));
|
|
818
|
-
variations.push(selector.replace(classMatch[0], `.${classMatch[1]}-*`));
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// Tentar IDs vs classes
|
|
822
|
-
const idMatch = selector.match(/#([a-zA-Z0-9_-]+)/);
|
|
823
|
-
if (idMatch) {
|
|
824
|
-
variations.push(`[id*="${idMatch[1]}"]`);
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
// Adicionar nth-child
|
|
828
|
-
variations.push(`${selector}:nth-child(1)`);
|
|
829
|
-
|
|
830
|
-
// Usar aria-label
|
|
831
|
-
variations.push(`${selector.split('.')[0]}[aria-label]`);
|
|
832
|
-
|
|
833
|
-
return variations;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
private trySelector(html: string, selector: string): string | null {
|
|
837
|
-
// Usar cheerio
|
|
838
|
-
try {
|
|
839
|
-
const cheerio = require('cheerio');
|
|
840
|
-
const $ = cheerio.load(html);
|
|
841
|
-
const text = $(selector).text().trim();
|
|
842
|
-
return text || null;
|
|
843
|
-
} catch {
|
|
844
|
-
return null;
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
private extractAllText(html: string): string {
|
|
849
|
-
const cheerio = require('cheerio');
|
|
850
|
-
const $ = cheerio.load(html);
|
|
851
|
-
$('script, style, noscript').remove();
|
|
852
|
-
return $.text().trim();
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
```
|
|
856
|
-
|
|
857
|
-
---
|
|
858
|
-
|
|
859
|
-
## 5. llms.txt Specification
|
|
860
|
-
|
|
861
|
-
### Estrutura
|
|
862
|
-
|
|
863
|
-
```txt
|
|
864
|
-
# Site Name
|
|
865
|
-
|
|
866
|
-
> Brief description of what this site does
|
|
867
|
-
|
|
868
|
-
## Section Name
|
|
869
|
-
|
|
870
|
-
- [Page Title](https://example.com/page): Description of the page
|
|
871
|
-
- [Another Page](https://example.com/another): Another description
|
|
872
|
-
|
|
873
|
-
## API Reference
|
|
874
|
-
|
|
875
|
-
- [GET /api/users](https://api.example.com/docs/users): Returns all users
|
|
876
|
-
- [POST /api/users](https://api.example.com/docs/users-create): Create a new user
|
|
877
|
-
|
|
878
|
-
## Blog
|
|
879
|
-
|
|
880
|
-
- [Latest Post](https://blog.example.com/latest): Summary of the latest blog post
|
|
881
|
-
```
|
|
882
|
-
|
|
883
|
-
### Regras
|
|
884
|
-
|
|
885
|
-
1. **Primeira linha:** Nome do site (em `#`)
|
|
886
|
-
2. **Segunda linha:** Descrição (em `>`)
|
|
887
|
-
3. **Seções:** Organizadas por `##`
|
|
888
|
-
4. **Links:** Formato `- [Title](URL): Description`
|
|
889
|
-
5. **Máximo:** 100 links por arquivo
|
|
890
|
-
6. **Profundidade:** Máximo 2 níveis de seções
|
|
891
|
-
7. **Descrições:** Máximo 100 caracteres
|
|
892
|
-
8. **URLs:** Absolutas, com HTTPS
|
|
893
|
-
|
|
894
|
-
### Exemplo real
|
|
895
|
-
|
|
896
|
-
```txt
|
|
897
|
-
# DevThink WebScrape
|
|
898
|
-
|
|
899
|
-
> AI-powered web scraping toolkit with Playwright, multi-format serialization, and LLM-friendly output
|
|
900
|
-
|
|
901
|
-
## Getting Started
|
|
902
|
-
|
|
903
|
-
- [Installation](https://github.com/iNathlan/devthink#installation): How to install and set up
|
|
904
|
-
- [Quick Start](https://github.com/iNathlan/devthink#quick-start): Get running in 5 minutes
|
|
905
|
-
|
|
906
|
-
## API Reference
|
|
907
|
-
|
|
908
|
-
- [scrape()](https://github.com/iNathlan/devthink/blob/main/docs/API.md#scrape): Main scraping function
|
|
909
|
-
- [Agent Browser](https://github.com/iNathlan/devthink/blob/main/docs/API.md#agent-browser): Playwright-based browser automation
|
|
910
|
-
- [Serializers](https://github.com/iNathlan/devthink/blob/main/docs/API.md#serializers): Output format conversion
|
|
911
|
-
|
|
912
|
-
## Examples
|
|
913
|
-
|
|
914
|
-
- [Basic Scraping](https://github.com/iNathlan/devthink/blob/main/examples/basic.ts): Simple URL scraping
|
|
915
|
-
- [AI Agent](https://github.com/iNathlan/devthink/blob/main/examples/agent.ts): Browser agent with AI
|
|
916
|
-
```
|
|
917
|
-
|
|
918
|
-
### Adoção em 2026
|
|
919
|
-
|
|
920
|
-
- **840+ sites** já publicam llms.txt
|
|
921
|
-
- **Vercel, Anthropic, OpenAI, Stripe, Supabase** entre os adotantes
|
|
922
|
-
- **Ferramentas:** `llmstxt` CLI para gerar, validadores automáticos
|
|
923
|
-
- **Automação:** Many sites auto-generate via CI/CD
|
|
924
|
-
|
|
925
|
-
### Como consumir llms.txt
|
|
926
|
-
|
|
927
|
-
```typescript
|
|
928
|
-
async function fetchLLMsTxt(baseUrl: string): Promise<string> {
|
|
929
|
-
// Tentar llms.txt primeiro
|
|
930
|
-
const res = await fetch(`${baseUrl}/llms.txt`);
|
|
931
|
-
if (res.ok) return res.text();
|
|
932
|
-
|
|
933
|
-
// Fallback: robots.txt parseado
|
|
934
|
-
const robotsRes = await fetch(`${baseUrl}/robots.txt`);
|
|
935
|
-
if (robotsRes.ok) return parseRobotsTxt(await robotsRes.text());
|
|
936
|
-
|
|
937
|
-
return '';
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
function parseRobotsTxt(robots: string): string {
|
|
941
|
-
return robots
|
|
942
|
-
.split('\n')
|
|
943
|
-
.filter(line => line.startsWith('Allow: ') || line.startsWith('Disallow: '))
|
|
944
|
-
.map(line => line.replace(/^(Allow|Disallow): /, ''))
|
|
945
|
-
.join('\n');
|
|
946
|
-
}
|
|
947
|
-
```
|
|
948
|
-
|
|
949
|
-
---
|
|
950
|
-
|
|
951
|
-
## 6. Token Counting
|
|
952
|
-
|
|
953
|
-
### 6.1. js-tiktoken (OpenAI)
|
|
954
|
-
|
|
955
|
-
```typescript
|
|
956
|
-
import { encoding_for_model } from 'js-tiktoken';
|
|
957
|
-
|
|
958
|
-
const enc = encoding_for_model('gpt-4o');
|
|
959
|
-
|
|
960
|
-
function countTokens(text: string): number {
|
|
961
|
-
return enc.encode(text).length;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
function chunkByTokens(text: string, maxTokens: number): string[] {
|
|
965
|
-
const tokens = enc.encode(text);
|
|
966
|
-
const chunks: string[] = [];
|
|
967
|
-
|
|
968
|
-
for (let i = 0; i < tokens.length; i += maxTokens) {
|
|
969
|
-
const chunk = tokens.slice(i, i + maxTokens);
|
|
970
|
-
chunks.push(enc.decode(chunk));
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
return chunks;
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
// Cleanup
|
|
977
|
-
enc.free();
|
|
978
|
-
```
|
|
979
|
-
|
|
980
|
-
### 6.2. gpt-tokenizer (multi-model)
|
|
981
|
-
|
|
982
|
-
```typescript
|
|
983
|
-
import { encode, decode } from 'gpt-tokenizer';
|
|
984
|
-
|
|
985
|
-
function countTokensGPT(text: string): number {
|
|
986
|
-
return encode(text).length;
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
// Suporta: gpt-4, gpt-4o, gpt-3.5-turbo
|
|
990
|
-
// Mais leve que js-tiktoken
|
|
991
|
-
```
|
|
992
|
-
|
|
993
|
-
### 6.3. Claude API
|
|
994
|
-
|
|
995
|
-
```typescript
|
|
996
|
-
// Anthropic não tem lib oficial de token counting
|
|
997
|
-
// Usar estimativa: ~4 chars por token para inglês
|
|
998
|
-
// Ou usar a API de contagem
|
|
999
|
-
|
|
1000
|
-
async function countClaudeTokens(
|
|
1001
|
-
text: string,
|
|
1002
|
-
apiKey: string
|
|
1003
|
-
): Promise<number> {
|
|
1004
|
-
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
1005
|
-
method: 'POST',
|
|
1006
|
-
headers: {
|
|
1007
|
-
'Content-Type': 'application/json',
|
|
1008
|
-
'x-api-key': apiKey,
|
|
1009
|
-
'anthropic-version': '2023-06-01',
|
|
1010
|
-
},
|
|
1011
|
-
body: JSON.stringify({
|
|
1012
|
-
model: 'claude-3-5-sonnet-20241022',
|
|
1013
|
-
max_tokens: 1,
|
|
1014
|
-
messages: [{ role: 'user', content: text }],
|
|
1015
|
-
}),
|
|
1016
|
-
});
|
|
1017
|
-
|
|
1018
|
-
const result = await response.json();
|
|
1019
|
-
return result.usage?.input_tokens ?? Math.ceil(text.length / 4);
|
|
1020
|
-
}
|
|
1021
|
-
```
|
|
1022
|
-
|
|
1023
|
-
### 6.4. bpe-lite (multi-model, lightweight)
|
|
1024
|
-
|
|
1025
|
-
```typescript
|
|
1026
|
-
import { BpeTokenizer } from 'bpe-lite';
|
|
1027
|
-
|
|
1028
|
-
// Suporta múltiplos modelos
|
|
1029
|
-
const tokenizer = new BpeTokenizer('gpt-4');
|
|
1030
|
-
|
|
1031
|
-
function countTokensLite(text: string): number {
|
|
1032
|
-
return tokenizer.tokenize(text).length;
|
|
1033
|
-
}
|
|
1034
|
-
```
|
|
1035
|
-
|
|
1036
|
-
### Comparação
|
|
1037
|
-
|
|
1038
|
-
| Package | Size | Speed | Modelos | Precisão |
|
|
1039
|
-
|---------|------|-------|---------|----------|
|
|
1040
|
-
| js-tiktoken | ~5MB | Rápido | OpenAI | Alta |
|
|
1041
|
-
| gpt-tokenizer | ~1MB | Muito rápido | OpenAI | Alta |
|
|
1042
|
-
| bpe-lite | ~2MB | Rápido | Multi | Média |
|
|
1043
|
-
| Estimativa (chars/4) | 0 | Instantâneo | Qualquer | Baixa (~70%) |
|
|
1044
|
-
|
|
1045
|
-
---
|
|
1046
|
-
|
|
1047
|
-
## 7. Vector Database Formatting
|
|
1048
|
-
|
|
1049
|
-
### Metadata fields essenciais
|
|
1050
|
-
|
|
1051
|
-
```typescript
|
|
1052
|
-
interface VectorMetadata {
|
|
1053
|
-
// Identificação
|
|
1054
|
-
id: string;
|
|
1055
|
-
contentHash: string; // SHA-256 para dedup
|
|
1056
|
-
|
|
1057
|
-
// Fonte
|
|
1058
|
-
sourceUrl: string;
|
|
1059
|
-
sourceTitle: string;
|
|
1060
|
-
sourceDomain: string;
|
|
1061
|
-
|
|
1062
|
-
// Hierarquia
|
|
1063
|
-
headingPath: string[]; // ["## Section", "### Subsection"]
|
|
1064
|
-
parentChunkId?: string; // Para hierarchical retrieval
|
|
1065
|
-
|
|
1066
|
-
// Conteúdo
|
|
1067
|
-
tokenCount: number;
|
|
1068
|
-
contentType: 'text' | 'code' | 'table' | 'list';
|
|
1069
|
-
language: string;
|
|
1070
|
-
|
|
1071
|
-
// Temporal
|
|
1072
|
-
scrapedAt: string;
|
|
1073
|
-
expiresAt?: string; // Para cache TTL
|
|
1074
|
-
|
|
1075
|
-
// Embedding metadata
|
|
1076
|
-
embeddingModel: string;
|
|
1077
|
-
embeddingDimensions: number;
|
|
1078
|
-
}
|
|
1079
|
-
```
|
|
1080
|
-
|
|
1081
|
-
### Formatação para diferentes vector DBs
|
|
1082
|
-
|
|
1083
|
-
```typescript
|
|
1084
|
-
// Pinecone
|
|
1085
|
-
interface PineconeVector {
|
|
1086
|
-
id: string;
|
|
1087
|
-
values: number[];
|
|
1088
|
-
metadata: Record<string, string | number | string[]>;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
// Weaviate
|
|
1092
|
-
interface WeaviateVector {
|
|
1093
|
-
class: string;
|
|
1094
|
-
id: string;
|
|
1095
|
-
vector: number[];
|
|
1096
|
-
properties: Record<string, unknown>;
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
// Qdrant
|
|
1100
|
-
interface QdrantVector {
|
|
1101
|
-
id: string;
|
|
1102
|
-
vector: number[];
|
|
1103
|
-
payload: Record<string, unknown>;
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
// Universal format
|
|
1107
|
-
function formatForVectorDB(
|
|
1108
|
-
chunk: ProcessedChunk,
|
|
1109
|
-
embedding: number[],
|
|
1110
|
-
dbType: 'pinecone' | 'weaviate' | 'qdrant' | 'memory'
|
|
1111
|
-
): PineconeVector | WeaviateVector | QdrantVector | Record<string, unknown> {
|
|
1112
|
-
const metadata = {
|
|
1113
|
-
source_url: chunk.metadata.sourceUrl,
|
|
1114
|
-
heading_path: chunk.metadata.headingPath.join(' > '),
|
|
1115
|
-
content_hash: chunk.metadata.contentHash,
|
|
1116
|
-
token_count: chunk.metadata.tokenCount,
|
|
1117
|
-
position: chunk.metadata.position,
|
|
1118
|
-
scraped_at: new Date().toISOString(),
|
|
1119
|
-
};
|
|
1120
|
-
|
|
1121
|
-
switch (dbType) {
|
|
1122
|
-
case 'pinecone':
|
|
1123
|
-
return {
|
|
1124
|
-
id: chunk.id,
|
|
1125
|
-
values: embedding,
|
|
1126
|
-
metadata,
|
|
1127
|
-
};
|
|
1128
|
-
|
|
1129
|
-
case 'weaviate':
|
|
1130
|
-
return {
|
|
1131
|
-
class: 'DocumentChunk',
|
|
1132
|
-
id: chunk.id,
|
|
1133
|
-
vector: embedding,
|
|
1134
|
-
properties: metadata,
|
|
1135
|
-
};
|
|
1136
|
-
|
|
1137
|
-
case 'qdrant':
|
|
1138
|
-
return {
|
|
1139
|
-
id: chunk.id,
|
|
1140
|
-
vector: embedding,
|
|
1141
|
-
payload: metadata,
|
|
1142
|
-
};
|
|
1143
|
-
|
|
1144
|
-
case 'memory':
|
|
1145
|
-
default:
|
|
1146
|
-
return {
|
|
1147
|
-
id: chunk.id,
|
|
1148
|
-
vector: embedding,
|
|
1149
|
-
...metadata,
|
|
1150
|
-
};
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
```
|
|
1154
|
-
|
|
1155
|
-
---
|
|
1156
|
-
|
|
1157
|
-
## 8. npm Packages
|
|
1158
|
-
|
|
1159
|
-
### Instalação
|
|
1160
|
-
|
|
1161
|
-
```bash
|
|
1162
|
-
# Scraping
|
|
1163
|
-
npm install @mendable/firecrawl-js # Firecrawl SDK
|
|
1164
|
-
npm install llm-scraper # LLM-powered scraping
|
|
1165
|
-
|
|
1166
|
-
# Token counting
|
|
1167
|
-
npm install js-tiktoken # OpenAI tokenizer
|
|
1168
|
-
npm install gpt-tokenizer # Lightweight GPT tokenizer
|
|
1169
|
-
npm install bpe-lite # Multi-model tokenizer
|
|
1170
|
-
|
|
1171
|
-
# Processing
|
|
1172
|
-
npm install turndown # HTML → Markdown
|
|
1173
|
-
npm install cheerio # Server-side DOM
|
|
1174
|
-
npm install marked # Markdown parser
|
|
1175
|
-
|
|
1176
|
-
# Storage
|
|
1177
|
-
npm install @qdrant/js-client-rest # Qdrant vector DB
|
|
1178
|
-
npm install @pinecone-database/pinecone # Pinecone
|
|
1179
|
-
npm install ioredis # Redis client
|
|
1180
|
-
npm install better-sqlite3 # SQLite
|
|
1181
|
-
npm install keyv # Universal KV store
|
|
1182
|
-
```
|
|
1183
|
-
|
|
1184
|
-
### Uso de principais packages
|
|
1185
|
-
|
|
1186
|
-
```typescript
|
|
1187
|
-
// Firecrawl
|
|
1188
|
-
import FirecrawlApp from '@mendable/firecrawl-js';
|
|
1189
|
-
|
|
1190
|
-
const app = new FirecrawlApp({ apiKey: 'your-key' });
|
|
1191
|
-
|
|
1192
|
-
const result = await app.scrapeUrl('https://example.com', {
|
|
1193
|
-
formats: ['markdown'],
|
|
1194
|
-
onlyMainContent: true,
|
|
1195
|
-
});
|
|
1196
|
-
console.log(result.markdown);
|
|
1197
|
-
|
|
1198
|
-
// llm-scraper
|
|
1199
|
-
import { LLMScraper } from 'llm-scraper';
|
|
1200
|
-
|
|
1201
|
-
const scraper = new LLMScraper('gpt-4');
|
|
1202
|
-
const data = await scraper.scrape('https://example.com', {
|
|
1203
|
-
type: 'object',
|
|
1204
|
-
properties: {
|
|
1205
|
-
title: { type: 'string' },
|
|
1206
|
-
description: { type: 'string' },
|
|
1207
|
-
links: { type: 'array', items: { type: 'string' } },
|
|
1208
|
-
},
|
|
1209
|
-
});
|
|
1210
|
-
```
|
|
1211
|
-
|
|
1212
|
-
---
|
|
1213
|
-
|
|
1214
|
-
## 9. Content Deduplication
|
|
1215
|
-
|
|
1216
|
-
### SHA-256 hashing
|
|
1217
|
-
|
|
1218
|
-
```typescript
|
|
1219
|
-
async function contentHash(content: string): Promise<string> {
|
|
1220
|
-
const encoder = new TextEncoder();
|
|
1221
|
-
const data = encoder.encode(content);
|
|
1222
|
-
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
1223
|
-
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
1224
|
-
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
// Dedup no pipeline
|
|
1228
|
-
class ContentDeduplicator {
|
|
1229
|
-
private seen = new Map<string, string>(); // hash → url
|
|
1230
|
-
|
|
1231
|
-
async isDuplicate(content: string, url: string): Promise<boolean> {
|
|
1232
|
-
const hash = await contentHash(content);
|
|
1233
|
-
|
|
1234
|
-
if (this.seen.has(hash)) {
|
|
1235
|
-
console.log(`Duplicate detected: ${url} ≈ ${this.seen.get(hash)}`);
|
|
1236
|
-
return true;
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
this.seen.set(hash, url);
|
|
1240
|
-
return false;
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
// Dedup com tolerance para pequenas variações
|
|
1244
|
-
async isNearDuplicate(
|
|
1245
|
-
content: string,
|
|
1246
|
-
url: string,
|
|
1247
|
-
threshold = 0.95
|
|
1248
|
-
): Promise<boolean> {
|
|
1249
|
-
const hash = await contentHash(content);
|
|
1250
|
-
|
|
1251
|
-
// Check exato primeiro
|
|
1252
|
-
if (this.seen.has(hash)) return true;
|
|
1253
|
-
|
|
1254
|
-
// Check similar (minhash ou simhash — simplificado aqui)
|
|
1255
|
-
for (const [existingHash, existingUrl] of this.seen) {
|
|
1256
|
-
const similarity = this.compareHashes(hash, existingHash);
|
|
1257
|
-
if (similarity > threshold) {
|
|
1258
|
-
console.log(`Near-duplicate: ${url} ≈ ${existingUrl} (${(similarity * 100).toFixed(1)}%)`);
|
|
1259
|
-
return true;
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
this.seen.set(hash, url);
|
|
1264
|
-
return false;
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
private compareHashes(a: string, b: string): number {
|
|
1268
|
-
// SimHash simplificado
|
|
1269
|
-
let matches = 0;
|
|
1270
|
-
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
1271
|
-
if (a[i] === b[i]) matches++;
|
|
1272
|
-
}
|
|
1273
|
-
return matches / Math.max(a.length, b.length);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
```
|
|
1277
|
-
|
|
1278
|
-
---
|
|
1279
|
-
|
|
1280
|
-
## 10. Exemplos Completos
|
|
1281
|
-
|
|
1282
|
-
### 10.1. Scraping para RAG (end-to-end)
|
|
1283
|
-
|
|
1284
|
-
```typescript
|
|
1285
|
-
import TurndownService from 'turndown';
|
|
1286
|
-
|
|
1287
|
-
interface RAGScraperConfig {
|
|
1288
|
-
maxChunkTokens?: number;
|
|
1289
|
-
embeddingApiKey?: string;
|
|
1290
|
-
vectorDbUrl?: string;
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
async function scrapeForRAG(
|
|
1294
|
-
urls: string[],
|
|
1295
|
-
config: RAGScraperConfig
|
|
1296
|
-
): Promise<void> {
|
|
1297
|
-
const pipeline = new RAGPipeline({
|
|
1298
|
-
maxChunkTokens: config.maxChunkTokens ?? 512,
|
|
1299
|
-
});
|
|
1300
|
-
|
|
1301
|
-
// Process all URLs
|
|
1302
|
-
const documents = await pipeline.processUrls(urls, (current, total) => {
|
|
1303
|
-
console.log(`Processing ${current}/${total}...`);
|
|
1304
|
-
});
|
|
1305
|
-
|
|
1306
|
-
// Generate embeddings
|
|
1307
|
-
for (const doc of documents) {
|
|
1308
|
-
for (const chunk of doc.chunks) {
|
|
1309
|
-
chunk.embedding = await generateEmbedding(
|
|
1310
|
-
chunk.content,
|
|
1311
|
-
config.embeddingApiKey!
|
|
1312
|
-
);
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
// Store in vector DB
|
|
1317
|
-
for (const doc of documents) {
|
|
1318
|
-
for (const chunk of doc.chunks) {
|
|
1319
|
-
await storeVector(chunk, config.vectorDbUrl!);
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
console.log(`Processed ${documents.length} documents, ${documents.reduce((sum, d) => sum + d.chunks.length, 0)} chunks`);
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
async function generateEmbedding(
|
|
1327
|
-
text: string,
|
|
1328
|
-
apiKey: string
|
|
1329
|
-
): Promise<number[]> {
|
|
1330
|
-
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
1331
|
-
method: 'POST',
|
|
1332
|
-
headers: {
|
|
1333
|
-
'Content-Type': 'application/json',
|
|
1334
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
1335
|
-
},
|
|
1336
|
-
body: JSON.stringify({
|
|
1337
|
-
model: 'text-embedding-3-small',
|
|
1338
|
-
input: text,
|
|
1339
|
-
}),
|
|
1340
|
-
});
|
|
1341
|
-
|
|
1342
|
-
const result = await response.json();
|
|
1343
|
-
return result.data[0].embedding;
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
async function storeVector(
|
|
1347
|
-
chunk: ProcessedChunk,
|
|
1348
|
-
vectorDbUrl: string
|
|
1349
|
-
): Promise<void> {
|
|
1350
|
-
await fetch(`${vectorDbUrl}/vectors`, {
|
|
1351
|
-
method: 'PUT',
|
|
1352
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1353
|
-
body: JSON.stringify({
|
|
1354
|
-
id: chunk.id,
|
|
1355
|
-
vector: chunk.embedding,
|
|
1356
|
-
payload: {
|
|
1357
|
-
content: chunk.content,
|
|
1358
|
-
source_url: chunk.metadata.sourceUrl,
|
|
1359
|
-
heading_path: chunk.metadata.headingPath.join(' > '),
|
|
1360
|
-
token_count: chunk.metadata.tokenCount,
|
|
1361
|
-
},
|
|
1362
|
-
}),
|
|
1363
|
-
});
|
|
1364
|
-
}
|
|
1365
|
-
```
|
|
1366
|
-
|
|
1367
|
-
### 10.2. Query com RAG
|
|
1368
|
-
|
|
1369
|
-
```typescript
|
|
1370
|
-
async function queryRAG(
|
|
1371
|
-
query: string,
|
|
1372
|
-
config: RAGScraperConfig
|
|
1373
|
-
): Promise<string> {
|
|
1374
|
-
// 1. Embed query
|
|
1375
|
-
const queryEmbedding = await generateEmbedding(query, config.embeddingApiKey!);
|
|
1376
|
-
|
|
1377
|
-
// 2. Search vector DB
|
|
1378
|
-
const results = await fetch(`${config.vectorDbUrl}/vectors/search`, {
|
|
1379
|
-
method: 'POST',
|
|
1380
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1381
|
-
body: JSON.stringify({
|
|
1382
|
-
vector: queryEmbedding,
|
|
1383
|
-
limit: 5,
|
|
1384
|
-
with_payload: true,
|
|
1385
|
-
}),
|
|
1386
|
-
});
|
|
1387
|
-
|
|
1388
|
-
const matches = await results.json();
|
|
1389
|
-
|
|
1390
|
-
// 3. Build context
|
|
1391
|
-
const context = matches
|
|
1392
|
-
.map((m: { payload: { content: string; source_url: string } }) =>
|
|
1393
|
-
`Source: ${m.payload.source_url}\nContent: ${m.payload.content}`
|
|
1394
|
-
)
|
|
1395
|
-
.join('\n\n---\n\n');
|
|
1396
|
-
|
|
1397
|
-
// 4. Query LLM
|
|
1398
|
-
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
1399
|
-
method: 'POST',
|
|
1400
|
-
headers: {
|
|
1401
|
-
'Content-Type': 'application/json',
|
|
1402
|
-
'Authorization': `Bearer ${config.embeddingApiKey}`,
|
|
1403
|
-
},
|
|
1404
|
-
body: JSON.stringify({
|
|
1405
|
-
model: 'gpt-4o',
|
|
1406
|
-
messages: [
|
|
1407
|
-
{
|
|
1408
|
-
role: 'system',
|
|
1409
|
-
content: `Answer based on the context. Cite sources.\n\nContext:\n${context}`,
|
|
1410
|
-
},
|
|
1411
|
-
{ role: 'user', content: query },
|
|
1412
|
-
],
|
|
1413
|
-
}),
|
|
1414
|
-
});
|
|
1415
|
-
|
|
1416
|
-
const result = await response.json();
|
|
1417
|
-
return result.choices[0].message.content;
|
|
1418
|
-
}
|
|
1419
|
-
```
|
|
1420
|
-
|
|
1421
|
-
### 10.3. Batch processing com progress
|
|
1422
|
-
|
|
1423
|
-
```typescript
|
|
1424
|
-
async function batchScrape(urls: string[], concurrency = 5): Promise<ProcessedDocument[]> {
|
|
1425
|
-
const results: ProcessedDocument[] = [];
|
|
1426
|
-
const queue = [...urls];
|
|
1427
|
-
const processing = new Set<Promise<void>>();
|
|
1428
|
-
|
|
1429
|
-
while (queue.length > 0 || processing.size > 0) {
|
|
1430
|
-
while (processing.size < concurrency && queue.length > 0) {
|
|
1431
|
-
const url = queue.shift()!;
|
|
1432
|
-
const promise = (async () => {
|
|
1433
|
-
try {
|
|
1434
|
-
const doc = await pipeline.processUrl(url);
|
|
1435
|
-
results.push(doc);
|
|
1436
|
-
console.log(`✓ ${url} (${doc.chunks.length} chunks)`);
|
|
1437
|
-
} catch (err) {
|
|
1438
|
-
console.error(`✗ ${url}: ${err}`);
|
|
1439
|
-
}
|
|
1440
|
-
})();
|
|
1441
|
-
processing.add(promise);
|
|
1442
|
-
promise.finally(() => processing.delete(promise));
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
await Promise.race(processing);
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
return results;
|
|
1449
|
-
}
|
|
1450
|
-
```
|
|
1451
|
-
|
|
1452
|
-
---
|
|
1453
|
-
|
|
1454
|
-
## 11. Checklist
|
|
1455
|
-
|
|
1456
|
-
- [ ] Converter HTML para Markdown antes de enviar ao LLM
|
|
1457
|
-
- [ ] Usar chunks de 400-512 tokens com 10-20% overlap
|
|
1458
|
-
- [ ] Implementar RAG pipeline: Fetch → Extract → Markdown → Chunk → Embed → Store
|
|
1459
|
-
- [ ] Adicionar metadata (source_url, heading_path, content_hash) a cada chunk
|
|
1460
|
-
- [ ] Deduplicar com SHA-256 antes de armazenar
|
|
1461
|
-
- [ ] Tokenizar com js-tiktoken ou gpt-tokenizer
|
|
1462
|
-
- [ ] Formatar adequadamente para a vector DB escolhida
|
|
1463
|
-
- [ ] Suportar llms.txt para descoberta de conteúdo
|
|
1464
|
-
- [ ] Self-healing selectors para scraping resiliente
|
|
1465
|
-
- [ ] Testar extração com schemas definidos
|