Skip to content

Add tasks to the store: create a session and start its first run in one transaction - #215

Merged
jinxi97 merged 1 commit into
mainfrom
jinxi97/new-task-api
Oct 27, 2026
Merged

jinxi97 merged 1 commit into
mainfrom
jinxi97/new-task-api

Conversation

@jinxi97

@jinxi97 jinxi97 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

First of two stacked PRs for the task API. This one is the core schema, the Store port and the pg adapter. The api routes (POST /v1/tasks, GET /v1/tasks/:id, POST /v1/tasks/:id/cancel) follow in a PR based on this one.

What a task is

A task is work handed to an agent config: its content becomes the first message of a new session. Today that is "create a session, then send it a message", but as one transaction. The current two calls can fail between them and leave an empty session behind.

A task is its own row, not an alias for its session. Deferral will let a task wait before it starts, and a task cancelled while waiting never gets a session. In this PR every task starts the moment it is created, so sessionId is always set.

Changes

  • core: TaskRef, CreateTaskRequest (namespace, agentConfigId, agentConfigVersion?, content, metadata?), Task.
  • Store port: createTask and getTask.
  • pg adapter:
    • createTask does everything in one transaction: check the config, pin its version, insert the session, log the content, ready the first inference item, insert the task.
    • createSession's body and intake's "start a run" branch become helpers (insertSession, startRun) that all three methods share, so the archive lock and the run start aren't copied.
  • Migration 20261027225858_add_tasks: the new tasks table, with foreign keys to the pinned config version and to the session. The test pins the migration's hash.

Decisions

  • The version is pinned when the task is created. The session pins the same one.
  • content is stored on the task as well as in the session log. A task that waits to start will need it before any session exists, and adding it later would leave the earlier tasks without it.
  • metadata stays on the task. The session gets none.
  • The task's session is an ordinary session: follow-ups, cancel and archive work as on any other.
  • No cancelledAt and no deferral columns yet. They come with deferral, when a task can actually be waiting.

Tests

  • New conformance tests:
    • round trip, with absent metadata left absent and JSON-null metadata kept
    • the first entry and one ready, claimable inference item
    • a follow-up message queues behind the task's run
    • the latest version or an explicit version is pinned
    • an archived config throws ArchivedError; unknown or foreign configs and versions are "unknown"; an invalid request is rejected. None of these leaves a session behind
    • namespace stamping, and getTask returning undefined for an unknown or foreign task
  • pnpm typecheck, pnpm format:check and pnpm test pass.
  • The conformance suite also passes against a real postgres:16 container (pg-postgres.test.ts, 103/103).

🤖 Generated with Claude Code

…ne transaction

A task is work handed to an agent config: its content becomes the first
message of a new session. createTask pins the agent version, creates the
session, logs the content and readies the first inference item in one
transaction, so a failure never leaves an empty session behind. The task
is its own row (new tasks table, new migration) pointing at the session it
started, so deferral can later add tasks that wait before they start.

createSession and intake's started branch become shared helpers
(insertSession, startRun), so createTask reuses their checks and locks
instead of copying them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@jinxi97
jinxi97 merged commit b1be3c2 into main Oct 27, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant