Assistant Platform Knowledge Bundle
Bundle OKF 0.2 · 4 conceitos · VEuPathDB/ai-assistant-platform
Open source Repository Open in the app JSON README (API)
About
# Assistant Platform Knowledge Bundle
Durable knowledge about the three distributions in this repository, in
[Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
v0.2. Plain markdown with YAML frontmatter and no tooling: if you can `cat` a
file you can read it.
This is not a replacement for `README.md` (what the packages are and how they
are gated) or for code comments (why one line is the way it is). It holds what
neither can: the choices that had a real alternative, and what is still
outstanding.
## Decisions
- [Decisions](decisions/) - choices made deliberately, with the alternative that was rejected
## Conventions
- [Conventions](conventions/) - how work here is verified
## Backlog
- [Backlog](backlog/) - everything known to be outstanding, ranked
## History
- [log.md](log.md) - dated record of significant changes to this bundle
Details
- Kind
- OKF bundles
- Topic
- Files & documents
- Publisher
- veupathdb
- Origin
- okf_github
- Category
- dados
- Version
- 0.2
- Last push
- 2026-09-10T09:55:24Z
- Repository state
- ativo
- Language
- Python
- Added
- 2026-09-10 16:06:11
- Updated
- 2026-09-10 16:06:11
- Origin id
VEuPathDB/ai-assistant-platform:docs/knowledge/index.md
README
# assistant-platform Three distributions and the wire between them. Nothing here knows about genes, strategies or VEuPathDB: an assistant built on this runtime brings its own science. | folder | distribution | import name | | --- | --- | --- | | `packages/assistant-core/` | `assistant-core` | `assistant_core` | | `packages/assistant-client-ts/` | `@veupathdb/assistant-client` | - | | `packages/mcp-conformance/` | `veupathdb-mcp-conformance` | `mcp_conformance` | ## The `screening` extra `assistant-core[screening]` adds the ONNX runtime and the tokenizer that `assistant_core.capabilities.input_screening` needs. A host that screens user text before an agent reads it declares the extra and tells the scanner which directory holds the model; an assistant that screens nothing declares plain `assistant-core` and carries neither wheel. ## One Yarn project, one lock This folder is its own Yarn project: `package.json` declares `packages/assistant-client-ts` as its only workspace, pins the Yarn release, and `yarn.lock` here is what the client resolves against. `yarn install --immutable` is the first step of the client's CI lane, so the suite runs against the versions the lock names rather than whatever a fresh install picks. A consuming application names this repository, the workspace and one release tag (`"@veupathdb/assistant-client": "git+https://github.com/VEuPathDB/ai-assistant-platform.git#workspace=@veupathdb/assistant-client&tag=v<version>"`). Yarn clones the repository, installs it with its own lock, runs `prepack` and packs `dist`, so the consumer compiles the built output and needs no install here. From `ai` 6.0.250 a resumed stream is seeded from empty state instead of from the assistant message the client already holds, so the client rebuilds the message the tail continues. `DurableChatTransport` therefore resumes a message a turn left open from a cursor before that message's own `start`, drops what the tail delivers before it, and opens the next tail itself where the host ended one at a `done`. That is what section 6.1 of `PROTOCOL.md` asks of a turn suspended on a durable task: the gap's `data-task-progress` and `data-task-completed` chunks belong to the suspended turn's message, and a host serves them on a second tail. The cursor a replay names comes from the store, which the snapshot seeds from its `openMessage`, so a reload never tails from `0`. The peer range is `>=6.0.250 <8`, the releases that seed a resume that way; `tests/conformance/replayedMessage.test.ts` is the gate, and it fails on `ai` 6.0.154. ## The runtime carries its own migration chain `assistant-core` owns `conversations`, `messages`, `conversation_events`, `memory_tombstones`, `chat_turn_cancellations`, `monthly_usage`, `scratchpad_notes` and `scratchpad_compactions`, and ships the alembic history that creates them under `src/assistant_core/alembic/`, recording its position in `alembic_version_assistant_core`. A host application's chain uses its own version table, so the two share a database without touching each other. ```bash uv run python -m assistant_core.migrate # bring the runtime's tables to head ``` The runtime does not migrate at start. A host that embeds this package as a library runs `assistant_core.migrate.upgrade_head(connection)` on its own connection, after its own chain, because the runtime's tables name host tables in foreign keys. A database whose host chain already created the tables a revision would build needs no `alembic stamp`: each revision asks the inspector first and records the position without rebuilding anything. A database holding some of one revision's tables is refused, naming which are present and which are missing. `assistant_core.migrate.OWNED_TABLES` is the ten names, and `assistant_core.migrate.include_object` is the alembic filter that keeps them. A host whose own `env.py` maps its tables on the same declarative base uses that filter's complement, so neither chain autogenerates a revision for the other's tables. A revision names the tables it created in its own `CREATES`, which does not move when the distribution grows; a test holds the union of those to `OWNED_TABLES`. The runtime declares one host table it does not own. A host supplies `users` with a uuid `id`. Nothing else is read from it. ## What a host supplies to the runtime The runtime holds the rules that read its own rows and hands back the decisions a product makes. These seams carry that split. `assistant_core.quota` counts spend into `monthly_usage` per user per application, and `get_current(session, user_id, limit_usd=...)` takes the budget as an argument: the runtime stores no limit and reads no user record. What a caller at a hundred percent is told is the host's. `assistant_core.conversation.cancellation` writes the stop row a running worker polls, and fails the job of a worker that is already gone through `assistant_core.tasks.maintenance`. `assistant_core.conversation.authz` answers ownership over a `ConversationLookup`, a protocol whose one member is `get_by_id`. A host passes the thread store it already holds and inherits nothing from the runtime. `assistant_core.scratchpad.rendering.render_scratchpad` draws a thread's note index and appends a `ScratchpadGuidance`, three strings the host writes: what to start noting on an empty scratchpad, what to do before the turn ends on a filled one, and what is worth promoting to long-term memory. `build_scratchpad_toolset(guidance=...)` is a value a host puts in an agent's `toolsets`; the runtime names no agent, and the third string lands on the `promote_to_memory` tool description, which is what the model reads when it decides to promote. `assistant_core.scratchpad.compactor.compact_scratchpad` takes a factory that builds the compactor agent, so the model and the rewriting instructions are the host's, and a host builds one only when a ceiling is passed. The runtime owns the gate, the token trim, the cost and the write-back. `assistant_core.tasks` runs durable tools on a queue the host opens. `install_task_app(app)` gives the runtime the procrastinate application and its schema; `install_worker_context(build)` builds the turn context a durable body reads; `install_completion_turn(run)` drives the turn a finished task opens; `install_durable_job_context(ctx)` carries state a worker cannot re-derive, so the runtime names no product's credential. Each of those has a `reset_*` in the same module. A host subclasses `DurableJobState` and types every credential `CarriedSecret`, and `register_durable_jobs` scrubs the carried state out of the queue's own log lines, so no host filter matches on a product's key name. `declare_durable_tool` names a tool once, and the decorator, the procrastinate job and the worker body all read that value. `assistant_core.tasks.heartbeat.HeartbeatThread` writes the beat that `worker_dead_heartbeat_seconds` reads, and the settings refuse a beat too slow for that window. `assistant_core.tasks.names` holds the queues and the job names a host wires, and `assistant_core.tasks.chat_turn` states the two fields the stalled-job sweep reads out of a host's chat-turn payload. `assistant_core.registry.install_assistant_registry` serves the assistants to work that carries no request, such as the turn a finished durable task opens. `assistant_core.errors.AssistantCoreError` is the base of every refusal the runtime raises across that surface (`ConversationNotFoundError`, `ConversationForbiddenError`, `TurnStillRunningError`). None of them names an HTTP status; a host maps them onto its own transport. ## PROTOCOL.md is the contract [`PROTOCOL.md`](packages/assistant-core/src/assistant_core/PROTOCOL.md) is the wire an `assistant-core` deployment serves and the TypeScript client reads: the frame grammar, cursor semantics, the snapshot and tail contract, the turn shape, the chunk vocabulary and the reduction rules. It is versioned and additive only. Both sides are pinned to it. `assistant-core`'s `tests/integration/conversation/test_protocol_document.py` compares the document against the chunks the runtime actually emits, so a new chunk kind fails there. The client's suite is the **consumer-side gate**: `yarn sync:protocol` reads the document into `src/protocol/captured.json`, and `tests/conformance/` fails when the capture and the document disagree. The sync is an authoring step; the gate is the suite that reads the capture back. A change to `PROTOCOL.md` that neither side implements fails both. The document ships inside the runtime package, so an installed consumer reads it at `Path(assistant_core.__file__).parent / "PROTOCOL.md"`, the same bytes the deployment serves. `tests/packaging` builds the wheel and reads it back. ## mcp-conformance is an admission gate `mcp_conformance` is the suite an MCP tool server passes before a deployment admits it. It runs against a served endpoint (`pytest --pyargs mcp_conformance --mcp-endpoint <url> --mcp-bearer <token>`) and produces an admission record. It ships apart from the runtime because a deployment reads a server it did not build. ## Gates ```bash yarn install --immutable cd packages/assistant-core && uv sync --frozen && uv run ruff check src tests && uv run ruff format --check src tests && uv run mypy --strict src && uv run pytest && uv run pytest tests/packaging -m wheel --override-ini addopts='' cd packages/assistant-client-ts && yarn typecheck && yarn lint && yarn format:check && yarn test && yarn build cd packages/mcp-conformance && uv sync --frozen && uv run ruff check src tests && uv run mypy --strict src && uv run pytest node scripts/check-knowledge.mjs && node --test scripts/check-knowledge.test.mjs ``` Those four lanes are what `.github/workflows/ci.yml` runs, command for command. `.pre-commit-config.yaml` carries the same checks as hooks, and leaves the wheel check and the integration half of the runtime suite to CI. `assistant-core`'s suite runs with **no** application installed; that is what makes the boundary an installation fact rather than a lint rule. ## docs/knowledge is the durable record [`docs/knowledge/`](docs/knowledge/index.md) holds the choices behind this repository, in Open Knowledge Format v0.2. `scripts/check-knowledge.mjs` is its gate: every page carries a `type`, every relative link resolves, and every page is linked from its directory's index.