Skip to content

Repository files navigation

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.

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 eight 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; until the durable-task subsystem moves, it also supplies background_tasks with a uuid id. Nothing else is read from either.

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. Six 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 takes release_dead_turn so the host can fail the job of a worker that is already gone. The runtime owns no job queue.

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.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 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

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/ 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.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages