mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-11-03 22:32:27 +08:00
61 lines
3.4 KiB
Markdown
61 lines
3.4 KiB
Markdown
# Shared runtime source candidate (SDK >=0.7.4)
|
|
|
|
This source declares `sharedRuntime: shared-runtime-v1` and `componentModel: stateless-v1`.
|
|
It is source-reviewed for the multi-tenant contract; it is **not certified** and makes no
|
|
claim of live tenant acceptance.
|
|
|
|
- Configuration (`enable_vision`, `vision_llm_model_uuid`) is read per invocation through
|
|
`self.get_config()`. Nothing from tenant config is copied onto the plugin, the Parser
|
|
component or module globals, so a shared worker is never initialized with another
|
|
installation's settings.
|
|
- The installation binding is resolved per invocation with
|
|
`self.get_installation_binding()` and only used to derive a cache key; the binding
|
|
object is not retained after the call.
|
|
|
|
## Binding-keyed state
|
|
|
|
- Parser telemetry (filenames, MIME types, extensions, durations, parse errors) is tenant
|
|
data. It is no longer a process-global singleton: `TelemetryRegistry` keeps one
|
|
`ParserTelemetry` per full installation scope
|
|
`(instance_uuid, workspace_uuid, installation_uuid)`.
|
|
- `runtime_revision` is deliberately excluded from the scope so a worker upgrade keeps the
|
|
same bucket.
|
|
- `GeneralParsersPlugin.on_installation_revoked(binding)` calls `release_telemetry(binding)`,
|
|
dropping that installation's store on uninstall/disable/workspace-removal/upgrade.
|
|
|
|
## PDF execution boundary
|
|
|
|
- PyMuPDF is not thread safe and its table finder keeps module-level page state
|
|
(`EDGES` / `CHARS` in `pymupdf.table`, unchanged across the supported 1.x line). Parsing
|
|
it from the shared worker's thread pool let concurrent installations re-enter those
|
|
globals and could return another installation's page text or crash the shared process.
|
|
- Every PDF parse therefore runs in a dedicated short-lived interpreter process
|
|
(`components/general_parsers/isolated_process.py` + `process_worker.py`) that owns the
|
|
complete lifecycle: open document -> font/header/footer pass -> `find_tables()` ->
|
|
table extraction -> text/image extraction -> close document.
|
|
- The boundary is released only after that process has exited. A hard timeout
|
|
(`DEFAULT_TIMEOUT_SECONDS`, 300 s), a cancellation or a crash terminates and reaps the
|
|
worker before the caller resumes, so no dependency work can keep running into a later
|
|
request. PyMuPDF module state only ever exists inside the per-parse worker; the shared
|
|
process never imports it.
|
|
- Supported dependency range: `PyMuPDF>=1.24.0,<2.0.0` (see `requirements.txt`). The
|
|
process boundary is what makes the shared runtime safe on this whole range; the range is
|
|
bounded to the 1.x line this implementation is verified against.
|
|
|
|
## Page scoping
|
|
|
|
`PageRequest` carries no binding. `ParserObservabilityPage` resolves the current
|
|
installation from the task-local SDK binding (`self.get_installation_binding()`), which the
|
|
Host sets from the page request's installation context. `/snapshot` and `/clear` therefore
|
|
act only on the calling installation's store and never expose another installation's
|
|
filenames or errors. When no binding is active (direct, non-invocation use; unit tests) an
|
|
isolated "unscoped" store is used — it never receives records from a bound invocation.
|
|
|
|
## Known limits
|
|
|
|
- Telemetry is in-memory, per worker. It is not aggregated across workers and is lost on
|
|
worker restart.
|
|
- The unscoped store is never merged into a tenant view; it exists only for direct use.
|
|
- No claim of certification; independent review and two-Workspace invocation acceptance are
|
|
still required.
|