ConusAI vendor v0.1.0-beta.114
ci / gate (push) Waiting to run

This commit is contained in:
ConusAI vendor v0.1.0-beta.114
2026-11-14 09:56:45 +00:00
commit 1ce8d23c35
867 changed files with 122104 additions and 0 deletions
+173
View File
@@ -0,0 +1,173 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// Real pg-boss claims for Agent tests, including local engine/provider tests.
import { buildRegistry, Container, defineModule, type JobContext, newId, type ProjectScope } from "@conusai-kit/core"
import { systemActor } from "@conusai-kit/core/worker"
import { type DataSource, entitiesOf } from "@conusai-kit/data"
import { connectKyselyDataSourceFromEnv, type KyselyDataSource } from "@conusai-kit/data-kysely"
import {
createPgBoss,
createPgBossClaimGuard,
createPgBossJobQueue,
createWorker,
fromKyselyTransaction,
withJobTransaction,
} from "@conusai-kit/jobs-pgboss"
import { Pool, type PoolClient } from "pg"
import { afterAll, beforeAll } from "vitest"
import { z } from "zod"
import { runJob } from "../adapters/procedures.js"
import { RUN_JOB } from "../contract/index.js"
import { AGENT_SCOPE } from "../core/ports.js"
import { grantPgBoss, migrate, type Postgres, startPostgres } from "./claimed-postgres.js"
import { workerRegistry } from "./worker-fixture.js"
let postgres: Postgres
let boss: ReturnType<typeof createPgBoss>
let guard: ReturnType<typeof createPgBossClaimGuard>
let sql: Pool
let ownedClient: PoolClient
/** Terminate only the client acquired from this test's dedicated guard pool. */
export async function terminateClaimSession() {
const {
rows: [{ pid }],
} = await ownedClient.query("select pg_backend_pid() as pid")
await sql.query("select pg_terminate_backend($1)", [pid])
}
export type ClaimChange = "cancel" | "reclaim" | "delete" | "scope" | "actor" | "owner"
const workers: ReturnType<typeof createWorker>[] = []
const pending = new Map<
string,
{
container: Container
extra: Partial<JobContext>
change?: ClaimChange
resolve: () => void
reject: (error: unknown) => void
}
>()
let domainData: KyselyDataSource | undefined
/** Queue and domain tables share the actual database, as in the supported host. */
export async function claimedDataSource(): Promise<KyselyDataSource> {
if (!domainData) {
const entities = entitiesOf(workerRegistry, "postgres")
await migrate(postgres, entities)
// Migrations grant access to public tables; queue objects remain owned by pg-boss.
domainData = await connectKyselyDataSourceFromEnv(
{ POSTGRES_URL: postgres.runtimeUrl, POSTGRES_READER_URL: postgres.readerUrl },
{ entities, transactionContext: (trx, run) => withJobTransaction(fromKyselyTransaction(trx), run) },
)
}
return domainData
}
let currentData: DataSource
const registry = buildRegistry([
defineModule({
id: "agent",
version: "1.0.0",
kit: "^0.1.0",
jobs: {
[RUN_JOB]: {
payload: z.object({ runId: z.string(), delivery: z.string() }),
async handler(payload, ctx) {
const target = pending.get(payload.delivery)
if (!target) throw new Error("unregistered test delivery")
try {
if (!ctx.execution) throw new Error("supported adapter did not supply execution")
const id = ctx.execution.id
if (target.change === "delete") await sql.query("delete from pgboss.job where id = $1", [id])
if (target.change === "cancel")
await sql.query("update pgboss.job set state = 'cancelled' where id = $1", [id])
if (target.change === "reclaim")
await sql.query("update pgboss.job set retry_count = retry_count + 1 where id = $1", [id])
if (target.change === "scope")
await sql.query(
"update pgboss.job set data = jsonb_set(data, '{scope,projectId}', to_jsonb($2::text)) where id = $1",
[id, newId()],
)
if (target.change === "actor")
await sql.query(
"update pgboss.job set data = jsonb_set(data, '{onBehalfOf}', to_jsonb($2::text)) where id = $1",
[id, newId()],
)
await runJob.handler(
{ runId: payload.runId },
{ ...ctx, ...target.extra, execution: ctx.execution, container: target.container },
)
target.resolve()
} catch (error) {
target.reject(error)
} finally {
pending.delete(payload.delivery)
}
},
},
},
}),
])
beforeAll(async () => {
postgres = await startPostgres()
boss = createPgBoss({ connectionString: postgres.ownerUrl })
await boss.start()
await boss.createQueue(RUN_JOB)
await grantPgBoss(postgres)
sql = new Pool({ connectionString: postgres.runtimeUrl, max: 2 })
const guardPool = new Pool({ connectionString: postgres.runtimeUrl, max: 2 })
guardPool.on("acquire", (client) => {
ownedClient = client
})
guard = createPgBossClaimGuard(guardPool)
}, 300_000)
afterAll(async () => {
for (const worker of workers) await worker.stop()
await guard?.close()
await sql?.end()
await boss?.stop({ graceful: true })
await domainData?.close()
await postgres?.stop()
})
let started = false
export async function claimedDelivery(
data: DataSource,
container: Container,
scope: ProjectScope,
runId: string,
extra: Partial<JobContext> = {},
change?: ClaimChange,
) {
currentData = data
if (!started) {
// Source forwarding is needed because a file exercises several independent tenancy fixtures.
const source = new Proxy({} as DataSource, {
get(_target, property) {
const value = Reflect.get(currentData, property)
return typeof value === "function" ? value.bind(currentData) : value
},
})
workers.length = 0
const worker = createWorker({
registry,
boss,
claimGuard: guard,
dataSource: source,
container: new Container(),
relay: { enabled: false },
})
workers.push(worker)
await worker.start()
started = true
}
// Mirror the actual adapter scope into the app's independently bound scope port.
const base = extra.container ?? container
const child = base.child()
child.value(AGENT_SCOPE, { ...base.resolve(AGENT_SCOPE), actor: systemActor(RUN_JOB) })
const delivery = newId()
const settled = new Promise<void>((resolve, reject) =>
pending.set(delivery, { container: child, extra, ...(change ? { change } : {}), resolve, reject }),
)
await createPgBossJobQueue({ boss }).enqueue(
change === "owner" ? { ...scope, actor: { userId: newId() } } : scope,
RUN_JOB,
{ runId, delivery },
)
return settled
}
+103
View File
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// Disposable local PostgreSQL for the app's actual claim tests. No SDK-private test code.
import { execFileSync } from "node:child_process"
import type { AnyEntityDef } from "@conusai-kit/data"
import { readerMigration, runMigrationsFromEnv, schemaMigration } from "@conusai-kit/data-kysely"
import { Pool } from "pg"
export interface Postgres {
ownerUrl: string
runtimeUrl: string
readerUrl: string
stop(): Promise<void>
}
const docker = (...args: string[]) =>
execFileSync("docker", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim()
export async function startPostgres(): Promise<Postgres> {
const name = `agent-claim-${crypto.randomUUID()}`
const container = docker(
"run",
"--detach",
"--rm",
"--name",
name,
"--label",
"conusai.test=app-agent-claim",
"--publish",
"127.0.0.1::5432",
"--env",
"POSTGRES_USER=owner",
"--env",
"POSTGRES_PASSWORD=owner",
"--env",
"POSTGRES_DB=agent",
"pgvector/pgvector:pg18",
)
const stop = async () => {
docker("rm", "--force", "--volumes", container)
}
let owner: Pool | undefined
try {
// Docker Desktop can return before the random published port is visible. An empty
// port makes pg silently use 5432, so wait for the actual mapping before connecting.
const mappingDeadline = Date.now() + 10_000
let port = ""
while (!/^[1-9][0-9]*$/.test(port)) {
port = docker("port", container, "5432/tcp").split(":").at(-1) ?? ""
if (/^[1-9][0-9]*$/.test(port)) break
if (Date.now() >= mappingDeadline) throw new Error("Postgres test port was not published")
await new Promise((resolve) => setTimeout(resolve, 100))
}
const ownerUrl = `postgresql://owner:owner@127.0.0.1:${port}/agent`
owner = new Pool({ connectionString: ownerUrl, max: 1, connectionTimeoutMillis: 1000 })
const deadline = Date.now() + 60_000
while (true) {
try {
await owner.query("select 1")
break
} catch (error) {
if (Date.now() >= deadline) throw error
await new Promise((resolve) => setTimeout(resolve, 100))
}
}
await owner.query("create role app_runtime login password 'runtime' nosuperuser nobypassrls")
await owner.query("create role app_reader login password 'reader' nosuperuser nobypassrls")
return {
ownerUrl,
runtimeUrl: ownerUrl.replace("owner:owner@", "app_runtime:runtime@"),
readerUrl: ownerUrl.replace("owner:owner@", "app_reader:reader@"),
stop,
}
} catch (error) {
await stop()
throw error
} finally {
await owner?.end()
}
}
export async function migrate(postgres: Postgres, entities: readonly AnyEntityDef[]) {
await runMigrationsFromEnv({ POSTGRES_MIGRATE_URL: postgres.ownerUrl }, [
schemaMigration(entities),
readerMigration("app_reader", []),
])
const owner = new Pool({ connectionString: postgres.ownerUrl, max: 1 })
try {
await owner.query("grant usage on schema public to app_runtime, app_reader")
await owner.query("grant select, insert, update, delete on all tables in schema public to app_runtime")
} finally {
await owner.end()
}
}
export async function grantPgBoss(postgres: Postgres) {
const owner = new Pool({ connectionString: postgres.ownerUrl, max: 1 })
try {
await owner.query("grant usage on schema pgboss to app_runtime")
await owner.query("grant select, insert, update, delete on all tables in schema pgboss to app_runtime")
await owner.query("grant execute on all functions in schema pgboss to app_runtime")
} finally {
await owner.end()
}
}
+23
View File
@@ -0,0 +1,23 @@
// The module's messages: en and lt declare the same keys, or a page in one language breaks.
import { buildRegistry } from "@conusai-kit/core"
import { tenancyModule } from "@conusai-kit/tenancy"
import { describe, expect, it } from "vitest"
import { agentModule } from "../index.js"
describe("the agent module's messages", () => {
const catalogues = buildRegistry([tenancyModule, agentModule]).catalogues
it("declares en and lt, and every en key resolves in lt", () => {
const en = catalogues.en?.agent ?? {}
const lt = catalogues.lt?.agent ?? {}
const flatten = (tree: Record<string, unknown>, prefix = ""): string[] =>
Object.entries(tree).flatMap(([key, value]) =>
typeof value === "string" ? [`${prefix}${key}`] : flatten(value as Record<string, unknown>, `${prefix}${key}.`),
)
const enKeys = flatten(en)
const ltKeys = new Set(flatten(lt))
expect(enKeys.length).toBeGreaterThan(0)
for (const key of enKeys) expect(ltKeys.has(key), `agent.${key} has no Lithuanian message`).toBe(true)
})
})
+51
View File
@@ -0,0 +1,51 @@
// What the generated tenant-isolation suite needs of this module: seeds and one fixture per
// tenant-scoped procedure, built from the OTHER tenant's ids.
import type { TransportCaller } from "@conusai-kit/core"
import type { IsolationFixture, IsolationTenant } from "@conusai-kit/testing"
export interface ModuleIsolation {
seed(
call: TransportCaller,
inProject: { org: string; workspace: string; project: string },
): Promise<Record<string, string>>
fixtures: Record<string, IsolationFixture>
}
const NOWHERE = "00000000-0000-0000-0000-000000000000"
const inWorkspaceOf = (t: IsolationTenant) => ({ org: t.orgSlug, workspace: t.workspaceSlug })
const inProjectOf = (t: IsolationTenant) => ({ ...inWorkspaceOf(t), project: t.projectSlug })
const runOf = (t: IsolationTenant) => t.extra.agentRunId ?? NOWHERE
const PLAN = [{ key: "read", label: "Read", tool: "documents.read", args: {} }]
export const isolation: ModuleIsolation = {
async seed(call, inProject) {
const started = (await call.callByName("agent.run.start", { ...inProject, goal: "Seed run", plan: PLAN })) as {
runId: string
}
return { agentRunId: started.runId }
},
fixtures: {
"agent.run.start": { input: (t) => ({ ...inProjectOf(t), goal: "Intruder", plan: PLAN }) },
"agent.run.status": { input: (t) => ({ ...inProjectOf(t), runId: runOf(t) }) },
"agent.run.events": { input: (t) => ({ ...inProjectOf(t), runId: runOf(t) }) },
"agent.run.cancel": { input: (t) => ({ ...inProjectOf(t), runId: runOf(t) }) },
"agent.run.list": { input: (t) => inProjectOf(t) },
// The live collection's read-back: another tenant's run id answers nothing.
"agent.run.getMany": { input: (t) => ({ ...inProjectOf(t), ids: [runOf(t)] }) },
"agent.approval.list": { input: (t) => inProjectOf(t) },
"agent.approval.review": {
input: (t) => ({ ...inProjectOf(t), runId: runOf(t), stepKey: "read", decision: "approve" }),
},
// The conversation behind the Agent in the right panel (kit-agent's assistant module, mounted by this one).
"assistant.turn.send": { input: (t) => ({ ...inProjectOf(t), turnId: NOWHERE, message: "Intruder" }) },
"assistant.conversation.list": { input: (t) => inProjectOf(t) },
"assistant.rootAction.reconcile": { input: (t) => ({ ...inProjectOf(t), conversationId: NOWHERE }) },
"assistant.conversation.get": { input: (t) => ({ ...inProjectOf(t), conversationId: NOWHERE }) },
"assistant.receipt.list": { input: (t) => inProjectOf(t) },
// The Agent's own workspace reads, offered to a turn with no project open.
"assistant.workspace.projects": { input: (t) => inWorkspaceOf(t) },
"assistant.workspace.openProject": { input: (t) => ({ ...inWorkspaceOf(t), slug: t.projectSlug }) },
},
}
+215
View File
@@ -0,0 +1,215 @@
// The run page's live island: what it shows from the server's seed before the first event, and
// from the run's AG-UI events (the projection `agent.run.events` serves, folded by the TanStack AI
// client's reducer) after it — step states, a parked approval, the completed run's answer with its
// Art. 50 disclosure, and a lost stream. Server-rendered, the island is exactly the seed.
import type { AgentRunRecord, AgentStepRecord } from "@conusai-kit/agent"
import { runEventsOf } from "@conusai-kit/agent/agui"
import { type AgUiChunk, initialAgentRunView, reduceAgentRunEvent } from "@conusai-kit/agent/client"
import { buildRegistry } from "@conusai-kit/core"
import { createI18n } from "@conusai-kit/i18n"
import { createDataClient, DataProvider } from "@conusai-kit/ui/data"
import { renderToStaticMarkup } from "react-dom/server"
import { describe, expect, it } from "vitest"
import { appModules } from "../../index.js"
import type { RunView } from "../contract/index.js"
import { LiveRun } from "../ui/live-run.js"
import { liveRunState } from "../ui/live-run-state.js"
const RUN = "01a19940-0000-7000-0000-000000000001"
const PLAN = [
{ key: "read", label: "Read", tool: "documents.read", args: {} },
{ key: "order", label: "Order", tool: "orders.create", args: { total: 4200 }, needsApproval: true },
]
const seed: RunView = {
runId: RUN,
goal: "Order the parts",
status: "queued",
failureCode: null,
failureDetail: null,
plan: PLAN.map((step) => ({
...step,
needsApproval: step.needsApproval === true,
status: "pending" as const,
attempts: 0,
error: null,
})),
usageCostMicrocents: 0,
usageSteps: 0,
percent: 0,
cancelRequested: false,
answer: null,
answerProvenance: null,
actorId: "user-1",
createdAt: "2026-11-02T10:00:00.000Z",
startedAt: null,
finishedAt: null,
}
const record = (status: AgentRunRecord["status"]): AgentRunRecord => ({
id: RUN,
version: 1,
status,
failureCode: null,
failureDetail: null,
goal: seed.goal,
plan: PLAN,
actorId: "user-1",
budget: { maxCostMicrocents: 1_000_000, maxSteps: 10, maxDurationSeconds: 600 },
usageCostMicrocents: 0,
usageSteps: 0,
cancelRequestedAt: null,
startedAt: "2026-11-02T10:00:01.000Z",
finishedAt: null,
createdAt: seed.createdAt,
answerProvenance: null,
})
const step = (
index: number,
status: AgentStepRecord["status"],
approval: AgentStepRecord["approval"] = null,
): AgentStepRecord => ({
id: `s-${index}`,
runId: RUN,
key: PLAN[index]?.key ?? "missing",
index,
label: PLAN[index]?.label ?? "missing",
status,
attempts: 1,
usageCostMicrocents: 0,
usageTokens: 0,
error: null,
externalEffect: false,
artifacts: [],
result: null,
approval,
startedAt: null,
finishedAt: null,
})
const parked = {
actionId: null,
tool: "orders.create",
arguments: { total: 4200 },
reviewUrl: null,
interrupt: { id: "approval_c-1", runId: `${RUN}.chat` },
decision: null,
}
const fold = (events: readonly unknown[]) =>
(events as AgUiChunk[]).reduce(reduceAgentRunEvent, initialAgentRunView(RUN))
describe("the live run state", () => {
it("is the seed until the first event", () => {
const state = liveRunState(seed, initialAgentRunView(RUN))
expect(state.status).toBe("queued")
expect(state.steps.map((s) => s.status)).toEqual(["pending", "pending"])
expect(state.answer).toBeNull()
})
it("follows the run's events: a committed step, then a parked approval", () => {
const view = fold(runEventsOf(record("awaiting_approval"), [step(0, "committed"), step(1, "pending", parked)]))
const state = liveRunState(seed, view)
expect(state.status).toBe("awaiting_approval")
expect(state.steps.map((s) => s.status)).toEqual(["committed", "pending"])
expect(state.percent).toBe(0.5)
})
it("shows a completed run's answer and a failed run's code", () => {
const done = fold(
runEventsOf(
record("completed"),
[step(0, "committed"), step(1, "committed", { ...parked, decision: "approved" })],
"Ordered.",
),
)
expect(liveRunState(seed, done)).toMatchObject({ status: "completed", percent: 1, answer: "Ordered." })
const failed = fold(
runEventsOf(
{ ...record("failed"), failureCode: "budget_exhausted", failureDetail: "the run reached its budget" },
[step(0, "committed")],
),
)
expect(liveRunState(seed, failed)).toMatchObject({
status: "failed",
failureCode: "budget_exhausted",
answer: null,
})
})
it("names a lost stream and keeps the last state it knew", () => {
const view = {
...fold(runEventsOf(record("running"), [step(0, "committed")])),
error: { source: "transport" as const, code: "reconnect_limit", message: "gone", status: null },
}
const state = liveRunState(seed, view)
expect(state.streamError).toBe("reconnect_limit")
expect(state.steps[0]?.status).toBe("committed")
})
})
describe("the live run island", () => {
const catalogues = buildRegistry([...appModules]).catalogues
const i18n = createI18n("en", { en: { agent: catalogues.en?.agent ?? {} } })
const t = (key: string) => i18n.message(`agent.${key}`)
const labels = {
status: t("runs.status"),
progress: t("runs.progress"),
plan: t("runs.plan"),
step: t("runs.step"),
tool: t("runs.tool"),
needsApproval: t("runs.needsApproval"),
answer: t("runs.answer"),
answerDisclosure: t("runs.answerDisclosure"),
streamLost: t("runs.streamLost"),
statuses: {
queued: t("runs.statusQueued"),
running: t("runs.statusRunning"),
awaiting_approval: t("runs.statusAwaitingApproval"),
completed: t("runs.statusCompleted"),
failed: t("runs.statusFailed"),
cancelled: t("runs.statusCancelled"),
uncertain: t("runs.statusUncertain"),
},
stepStatuses: {
pending: t("runs.stepPending"),
committed: t("runs.stepCommitted"),
failed: t("runs.stepFailed"),
cancelled: t("runs.stepCancelled"),
uncertain: t("runs.stepUncertain"),
},
controls: {
cancel: t("runs.cancel"),
cancelling: t("runs.cancelling"),
failedHint: t("recovery.failedHint"),
cancelledHint: t("recovery.cancelledHint"),
uncertainHint: t("recovery.uncertainHint"),
budgetExhausted: t("recovery.budgetExhausted"),
approvalUnavailable: t("recovery.approvalUnavailable"),
toolError: t("recovery.toolError"),
planRefused: t("recovery.planRefused"),
internal: t("recovery.internal"),
},
}
const render = (run: RunView) =>
renderToStaticMarkup(
<DataProvider client={createDataClient({ fetch: async () => new Response(null, { status: 501 }) })}>
<LiveRun slugs={{ org: "acme", workspace: "ws", project: "p" }} seed={run} labels={labels} />
</DataProvider>,
)
it("renders the seed on the server, the approval mark on a gated step, and no answer yet", () => {
const html = render(seed)
expect(html).toContain(labels.statuses.queued)
expect(html).toContain(labels.needsApproval)
expect(html).not.toContain(labels.answer)
})
it("renders a completed run's answer with the AI disclosure", () => {
const html = render({ ...seed, status: "completed", answer: "Ordered the parts." })
expect(html).toContain("Ordered the parts.")
expect(html).toContain(labels.answerDisclosure.replaceAll("'", "&#x27;"))
})
})
+59
View File
@@ -0,0 +1,59 @@
// The module's migrations are its own files, each exactly `schemaStatements()` over the entities it
// added (decision AT-D20: the entity definition is the one source of a column). Forward-only: the
// first file stays the run and step tables as first shipped; the second adds the step's recorded
// tool result and the run's conversation table (`agent_thread`, TanStack AI's message store); the
// third adds the run answer's provenance (EU AI Act Art. 50(2)).
import { readFileSync } from "node:fs"
import { AGENT_ENTITIES, agentRuns, agentSteps, agentThreads } from "@conusai-kit/agent"
import { schemaStatements } from "@conusai-kit/data-kysely"
import { describe, expect, it } from "vitest"
import { agentModule } from "../index.js"
function tablesOf(entities: Parameters<typeof schemaStatements>[0]): string {
const kernel = schemaStatements([]).length
return `${schemaStatements(entities)
.slice(kernel)
.map((statement) => `${statement};`)
.join("\n\n")}\n`
}
const migration = (name: string) => readFileSync(new URL(`../migrations/${name}`, import.meta.url), "utf8")
const HEADER = "-- SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0\n"
describe("the migrations of the agent module", () => {
it("are the run and step tables as first shipped, then the step's result column", () => {
const added = ',\n "result" jsonb\n'
const provenance = ',\n "answer_provenance" jsonb\n'
const generated = tablesOf([agentRuns, agentSteps])
expect(generated).toContain(added)
expect(generated).toContain(provenance)
expect(`${HEADER}${generated.replace(added, "\n").replace(provenance, "\n")}`).toBe(migration("0001_agent.sql"))
expect(migration("0002_agent_thread.sql")).toContain(
`${HEADER}alter table "agent_step" add column "result" jsonb;\n\n`,
)
})
it("add the run's conversation table in the second file, exactly its table", async () => {
await expect(
`${HEADER}alter table "agent_step" add column "result" jsonb;\n\n${tablesOf([agentThreads])}`,
).toMatchFileSnapshot("../migrations/0002_agent_thread.sql")
expect(AGENT_ENTITIES).toEqual([agentRuns, agentSteps, agentThreads])
})
it("add the run answer's provenance column in the third file, exactly that column", () => {
expect(tablesOf([agentRuns])).toContain(',\n "answer_provenance" jsonb\n')
expect(migration("0003_agent_answer_provenance.sql")).toBe(
`${HEADER}alter table "agent_run" add column "answer_provenance" jsonb;\n`,
)
})
it("are declared by the manifest, and every table is row-level secured", () => {
expect(agentModule.migrations).toEqual({ postgres: "migrations" })
const sql = migration("0001_agent.sql") + migration("0002_agent_thread.sql")
for (const table of ["agent_run", "agent_step", "agent_thread"]) {
expect(sql).toContain(`create table "${table}"`)
expect(sql).toContain(`alter table "${table}" force row level security`)
}
})
})
+156
View File
@@ -0,0 +1,156 @@
// The agent page on F10: its loader reads through the caller and returns plain data with every label
// translated, and its view renders what reached the browser, the run page's first paint being the seed of
// the live island. A path that is not one run is the kernel's 404, which is what the shell answers.
import { AppError, buildRegistry, Container, forbidden, type TransportCaller } from "@conusai-kit/core"
import { builtInCatalogues, createI18n, uiLabels } from "@conusai-kit/i18n"
import { createDataClient, DataProvider } from "@conusai-kit/ui/data"
import { UiLabelsProvider } from "@conusai-kit/ui/primitives"
import { renderToStaticMarkup as renderMarkup } from "react-dom/server"
import { describe, expect, it, vi } from "vitest"
import { appModules } from "../../index.js"
import { modulePages } from "../../pages.js"
import type { ApprovalView, RunView } from "../contract/index.js"
import { agentPage } from "../ui/pages.js"
const kitStrings = uiLabels(createI18n("en", builtInCatalogues))
const renderToStaticMarkup = (node: React.ReactNode) =>
renderMarkup(<UiLabelsProvider labels={kitStrings}>{node}</UiLabelsProvider>)
const catalogues = buildRegistry([...appModules]).catalogues
const i18n = createI18n("en", {
en: { agent: catalogues.en?.agent ?? {}, app: { failed: "That did not work: {detail}" } },
})
const slugs = { org: "acme", workspace: "ws", project: "p" }
const run: RunView = {
runId: "01a19940-0000-7000-0000-000000000001",
goal: "Order the parts",
status: "running",
failureCode: null,
failureDetail: null,
plan: [
{
key: "read",
label: "Read",
tool: "documents.read",
args: {},
needsApproval: false,
status: "pending",
attempts: 0,
error: null,
},
],
usageCostMicrocents: 120,
usageSteps: 3,
percent: 0.5,
cancelRequested: false,
answer: null,
answerProvenance: null,
actorId: "user-1",
createdAt: "2026-11-02T10:00:00.000Z",
startedAt: "2026-11-02T10:00:01.000Z",
finishedAt: null,
}
const approval: ApprovalView = {
runId: run.runId,
stepKey: "read",
goal: run.goal,
tool: "orders.create",
arguments: { total: 4200 },
reviewUrl: null,
createdAt: "2026-11-02T10:00:00.000Z",
}
const callerOf = (answers: Record<string, unknown>, asked: string[] = []): TransportCaller =>
({
call: async (contract: { name: string }) => {
asked.push(contract.name)
const answer = answers[contract.name]
if (answer instanceof Error) throw answer
return answer
},
}) as unknown as TransportCaller
const load = (segments: string[], answers: Record<string, unknown>, asked?: string[]) =>
agentPage.load({ slugs, segments, search: {}, caller: callerOf(answers, asked), i18n, container: new Container() })
/** The page as the shell renders it: the loader's data through JSON, as the browser receives it, then the view. */
const render = async (segments: string[], answers: Record<string, unknown>) => {
const data = await load(segments, answers)
expect(JSON.parse(JSON.stringify(data))).toStrictEqual(data)
const { View } = agentPage
return renderToStaticMarkup(
<DataProvider client={createDataClient({ fetch: async () => new Response(null, { status: 501 }) })}>
<View slugs={slugs} segments={segments} locale="en" data={JSON.parse(JSON.stringify(data))} />
</DataProvider>,
)
}
const lists = { "agent.run.list": { runs: [run] }, "agent.approval.list": { approvals: [approval] } }
describe("the agent page", () => {
it("is listed for the shell", async () => {
await expect(modulePages.agent?.()).resolves.toBe(agentPage)
})
it("lists the runs, each with its status in words, its progress and a link to it", async () => {
const html = await render([], lists)
const link = html.match(/<a\b[^>]*>Order the parts<\/a>/)?.[0] ?? ""
expect(link.match(/class="([^"]*)"/)?.[1]?.split(/\s+/)).toContain("kit-row-link")
expect(link).toContain(`href="/acme/ws/p/agent/${run.runId}"`)
expect(link).toContain('data-slot="row-link"')
expect(html).toContain('<progress value="0.5" max="1">50%</progress>')
expect(html).toContain("user-1")
expect(html).toContain("orders.create")
})
it("says when there is no run", async () => {
const data = await load([], { "agent.run.list": { runs: [] }, "agent.approval.list": { approvals: [] } })
if (data.kind !== "list") throw new Error("not the list")
expect(data.runs).toEqual([])
expect(await render([], { ...lists, "agent.run.list": { runs: [] } })).toContain(data.runLabels.empty)
})
it("renders one run from its status, the seed of the live island", async () => {
const asked: string[] = []
const html = await render([run.runId], { "agent.run.status": run })
await load([run.runId], { "agent.run.status": run }, asked)
expect(asked).toEqual(["agent.run.status"])
expect(html).toContain(">Order the parts</h1>")
expect(html).toContain('href="/acme/ws/p/agent"')
expect(html).toContain("<dt>Usage</dt><dd>3 steps, 120 microcents</dd>")
expect(html).toContain('data-live="agent.run"')
})
it("answers a path that is not one run with the kernel's 404, without reading", async () => {
const asked: string[] = []
const refused = load([run.runId, "extra"], lists, asked)
await expect(refused).rejects.toBeInstanceOf(AppError)
await expect(refused).rejects.toMatchObject({ status: 404 })
expect(asked).toEqual([])
})
it("hands a procedure's refusal on, as the AppError the shell answers", async () => {
const call = vi.fn(async () => {
throw forbidden("this page needs agent.run.read")
})
await expect(
agentPage.load({
slugs,
segments: [],
search: {},
caller: { call } as unknown as TransportCaller,
i18n,
container: new Container(),
}),
).rejects.toMatchObject({ status: 403 })
})
})
// This journey requires explicit optional-module admission.
vi.mock("../../inclusion.js", async (importOriginal) => ({
...(await importOriginal<typeof import("../../inclusion.js")>()),
...(await import("../../../test/support/native-readiness.js")).selectedModules(["agent"]),
}))
+35
View File
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// Follow the offered step using a public gateway adapter with an in-process transport.
// No network/provider call and no SDK-private or transitive TanStack testing import.
import { conusaiText } from "@conusai-sdk/ai/tanstack"
export function planFollower() {
return conusaiText("scripted-agent-test", {
apiUrl: "https://gateway.example.invalid/api",
token: "synthetic-test-token",
maxRetries: 0,
fetch: async (_input, init) => {
const body = JSON.parse(String(init?.body ?? "{}")) as { tool_choice?: { function?: { name?: string } } }
const step = body.tool_choice?.function?.name
const delta =
step === undefined
? { role: "assistant", content: "Done." }
: {
role: "assistant",
tool_calls: [
{ index: 0, id: `call-${step}`, type: "function", function: { name: step, arguments: "{}" } },
],
}
const chunk = {
id: "synthetic-completion",
object: "chat.completion.chunk",
created: 1,
model: "scripted-agent-test",
choices: [{ index: 0, delta, finish_reason: step === undefined ? "stop" : "tool_calls" }],
}
return new Response(`data: ${JSON.stringify(chunk)}\n\ndata: [DONE]\n\n`, {
headers: { "content-type": "text/event-stream" },
})
},
})
}
+135
View File
@@ -0,0 +1,135 @@
// The run retention sweep of the agent module (G3j): the hourly job deletes a terminal run past the
// retention with its steps and conversation, in each project the app serves, and keeps a run still going,
// a fresher one and another organization's. The job is the module's own (adapters/procedures.ts), so it runs
// on whatever data source the worker binds; this test uses the in-memory one.
import { AGENT_ENTITIES, agentRuns, agentSteps, agentThreads, threadIdOf } from "@conusai-kit/agent"
import { Container, type TenantScope } from "@conusai-kit/core"
import { createMemoryDataSource, DATA_SOURCE, type DataSource } from "@conusai-kit/data"
import { afterEach, describe, expect, it, vi } from "vitest"
import { RUN_EXPIRE_JOB } from "../contract/constants.js"
import { AGENT_SCOPE } from "../core/ports.js"
import { AGENT_JOBS, agentSchedules } from "../index.js"
const DAY = 86_400_000
const NOW = Date.parse("2026-11-02T12:00:00.000Z")
const USER = "01900000-0000-7000-0000-000000000009"
const ORG_A = "01900000-0000-7000-0000-000000000001"
const ORG_B = "01900000-0000-7000-0000-00000000000b"
const WORKSPACE = "01900000-0000-7000-0000-000000000002"
const PROJECT = "01900000-0000-7000-0000-000000000003"
const scopeOf = (orgId: string): TenantScope & { workspaceId: string; projectId: string } => ({
level: "project",
actor: { userId: USER as never, system: true },
orgId,
workspaceId: WORKSPACE,
projectId: PROJECT,
})
const daysAgo = (days: number): string => new Date(NOW - days * DAY).toISOString()
async function seed(data: DataSource, orgId: string, status: string, finishedDaysAgo: number | null): Promise<string> {
const repos = data.forScope(scopeOf(orgId))
const run = await repos.of(agentRuns).insert({
goal: "Review the contract",
plan: [{ key: "read", label: "Read", tool: "documents.read", args: {} }],
status,
failureCode: null,
failureDetail: null,
actorId: USER,
budgetCostMicrocents: 1_000_000,
budgetSteps: 10,
budgetSeconds: 300,
usageCostMicrocents: 0,
usageSteps: 0,
cancelRequestedAt: null,
startedAt: daysAgo((finishedDaysAgo ?? 1) + 1),
finishedAt: finishedDaysAgo === null ? null : daysAgo(finishedDaysAgo),
} as never)
await repos.of(agentSteps).insert({
runId: run.id,
key: "read",
index: 0,
label: "Read",
status: "committed",
attempts: 1,
usageCostMicrocents: 0,
usageTokens: 0,
error: null,
externalEffect: false,
artifacts: [],
approval: null,
startedAt: null,
finishedAt: null,
result: null,
} as never)
await repos.of(agentThreads).insert({ threadId: threadIdOf(run.id), messages: [] } as never)
return run.id
}
/** The retention job, as the module registers it. */
function expireJob() {
const job = AGENT_JOBS[RUN_EXPIRE_JOB]
if (!job) throw new Error("the agent module registers no run retention job")
return job
}
const runIdsOf = async (data: DataSource, orgId: string): Promise<string[]> =>
(await data.forScope(scopeOf(orgId)).of(agentRuns).list({})).items.map((run) => run.id).sort()
/** The job as the worker runs it: its container binds the data source and the project scope it runs in. */
function containerFor(data: DataSource, orgId: string): Container {
const container = new Container()
container.value(DATA_SOURCE, data)
container.value(AGENT_SCOPE, scopeOf(orgId))
return container
}
afterEach(() => vi.restoreAllMocks())
describe("the agent run retention job", () => {
it("deletes a terminal run past the retention with its steps and conversation, and keeps the rest", async () => {
vi.spyOn(Date, "now").mockReturnValue(NOW)
const data = createMemoryDataSource({ entities: [...AGENT_ENTITIES] })
await seed(data, ORG_A, "completed", 100)
await seed(data, ORG_A, "failed", 91)
const fresh = await seed(data, ORG_A, "completed", 89)
const running = await seed(data, ORG_A, "running", null)
const otherOrg = await seed(data, ORG_B, "completed", 400)
await expireJob().handler(
{ retentionDays: 90 },
{ container: containerFor(data, ORG_A), correlationId: "t", attempt: 1 },
)
expect(await runIdsOf(data, ORG_A)).toEqual([fresh, running].sort())
expect((await data.forScope(scopeOf(ORG_A)).of(agentSteps).list({})).items.map((s) => s.runId).sort()).toEqual(
[fresh, running].sort(),
)
expect((await data.forScope(scopeOf(ORG_A)).of(agentThreads).list({})).items.map((t) => t.threadId).sort()).toEqual(
[fresh, running].map(threadIdOf).sort(),
)
// Negative control: another organization's run, past the same retention, is untouched in its own project.
expect(await runIdsOf(data, ORG_B)).toEqual([otherOrg])
})
it("takes its retention from the schedule's payload, which accepts only whole days from 1 to 3650", () => {
const payload = expireJob().payload
expect(payload.safeParse({ retentionDays: 90 }).success).toBe(true)
expect(payload.safeParse({ retentionDays: 0 }).success).toBe(false)
expect(payload.safeParse({ retentionDays: 3651 }).success).toBe(false)
expect(payload.safeParse({ retentionDays: 2.5 }).success).toBe(false)
})
it("is scheduled hourly, once per project, with the retention it was given", () => {
expect(agentSchedules(90)).toEqual([
{
job: RUN_EXPIRE_JOB,
cron: "0 * * * *",
scope: { level: "each-project" },
payload: { retentionDays: 90 },
key: "agent.runs.expire",
missed: "skip",
},
])
})
})
+313
View File
@@ -0,0 +1,313 @@
// The run job over the real tools adapter, MCP client and gateway adapter; only the platform is
// answered, at `fetch`. What it pins is the line `StepOutcome` draws: a call a retry cannot fix ends
// the run with a typed failure and the job completes, so the queue does not run it again, while a
// transient failure rejects, so the queue does, and the step resumes on its idempotency key. A tool
// that answers an error is never a committed step: the model would otherwise read the error as the
// tool's result and the run would end `completed`.
import { AGENT_MODEL, AGENT_TOOLS, dataRunStore } from "@conusai-kit/agent"
import type { JobContext } from "@conusai-kit/core"
import { createMemoryDataSource, DATA_SOURCE } from "@conusai-kit/data"
import { afterEach, describe, expect, it, vi } from "vitest"
import { gatewayAgentModel, registryAgentTools, runJob } from "../adapters/procedures.js"
import { AGENT_SCOPE } from "../core/ports.js"
import { cancelRun, startRun } from "../core/runs.js"
import { claimedDataSource, claimedDelivery } from "./claimed-job.js"
import { workerFixture } from "./worker-fixture.js"
const API_URL = "https://cloud.example.test/api"
const MCP_URL = "https://cloud.example.test/v1/orgs/7/mcp"
const GATEWAY_URL = `${API_URL}/ai/v1/chat/completions`
const TOKEN = "dt_synthetic_fixture"
const TOOL_TEXT = "the backing service said something only its tenant may read"
interface ToolCall {
readonly name: string
readonly idempotencyKey: string
readonly authorization: string | null
}
type Mcp = (id: number) => Response
const rpc =
(result: unknown): Mcp =>
(id) =>
Response.json({ jsonrpc: "2.0", id, result })
const answered = rpc({
resultType: "complete",
isError: false,
structuredContent: { rows: 3 },
content: [{ type: "text", text: '{"rows":3}' }],
})
const denied = (reason: string) =>
rpc({
resultType: "complete",
isError: true,
structuredContent: { status: "denied", reason },
content: [{ type: "text", text: `refused: ${reason}` }],
})
const status =
(code: number): Mcp =>
() =>
new Response(null, { status: code })
/** The gateway as a model that follows the tool choice: it calls the step offered, then answers. */
function gatewayReply(body: { tool_choice?: unknown }): Response {
const choice = body.tool_choice
const step =
typeof choice === "object" && choice !== null
? (choice as { function?: { name?: string } }).function?.name
: undefined
const delta =
step === undefined
? { role: "assistant", content: "Done." }
: {
role: "assistant",
tool_calls: [{ index: 0, id: `call-${step}`, type: "function", function: { name: step, arguments: "{}" } }],
}
const chunk = {
id: "chatcmpl-1",
object: "chat.completion.chunk",
created: 1,
model: "gateway-model",
choices: [{ index: 0, delta, finish_reason: step === undefined ? "stop" : "tool_calls" }],
}
return new Response(`data: ${JSON.stringify(chunk)}\n\ndata: [DONE]\n\n`, {
status: 200,
headers: { "content-type": "text/event-stream" },
})
}
/** A queued run of one step, and a platform whose tool endpoint answers with `tool.mcp`. */
async function harness(toolName = "records__read") {
const tool: { mcp: Mcp; calls: ToolCall[] } = { mcp: answered, calls: [] }
vi.stubGlobal(
"fetch",
vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
const url = String(input)
const body = JSON.parse(String(init?.body ?? "{}"))
if (url === GATEWAY_URL) return gatewayReply(body)
if (url !== MCP_URL) throw new Error(`no such stand-in: ${url}`)
tool.calls.push({
name: body.params.name,
idempotencyKey: body.params._meta["com.conusai/idempotencyKey"],
authorization: new Headers(init?.headers).get("authorization"),
})
return tool.mcp(body.id)
}),
)
const data = await claimedDataSource()
const { container, scope } = await workerFixture(data)
container.value(AGENT_SCOPE, scope)
container.value(AGENT_MODEL, gatewayAgentModel({ apiUrl: API_URL, token: TOKEN, model: "gateway-model" }))
container.value(
AGENT_TOOLS,
registryAgentTools({
apiUrl: API_URL,
token: TOKEN,
orgId: "7",
scope: { orgSlug: "acme", workspaceSlug: "main", projectSlug: "p" },
}),
)
const started = await startRun({ data }, scope, {
goal: "Read the records",
plan: [{ key: "read", label: "Read the records", tool: toolName, args: { limit: 1 } }],
})
const store = dataRunStore(data, scope)
return {
tool,
data,
scope,
container,
runId: started.runId,
/** One delivery of the job: a rejection is what makes the queue deliver it again. */
deliver: (extra: Partial<JobContext> = {}) => claimedDelivery(data, container, scope, started.runId, extra),
cancel: () => cancelRun({ data }, scope, started.runId),
run: () => store.get(started.runId),
step: async () => (await store.listSteps(started.runId))[0],
}
}
afterEach(() => {
vi.unstubAllGlobals()
})
describe("the agent run job's tool calls", () => {
it("calls the tool with the deployment token and completes the run", async () => {
const job = await harness()
await job.deliver()
expect(job.tool.calls).toEqual([
{ name: "records__read", idempotencyKey: `${job.runId}:read`, authorization: `Bearer ${TOKEN}` },
])
expect(await job.run()).toMatchObject({ status: "completed", failureCode: null })
expect(await job.step()).toMatchObject({ status: "committed", attempts: 1, result: { rows: 3 } })
})
it.each<[string, Mcp, string]>([
["a token without the grant (403)", status(403), "forbidden"],
["a token the endpoint does not accept (401)", status(401), "unauthenticated"],
["a policy denial", denied("forbidden"), "forbidden"],
["a plan denial", denied("plan-required"), "plan-required"],
])("ends the run failed/tool_error on %s, and the queue does not run it again", async (_case, mcp, reason) => {
const job = await harness()
job.tool.mcp = mcp
await expect(job.deliver()).resolves.toBeUndefined()
const run = await job.run()
expect(run).toMatchObject({ status: "failed", failureCode: "tool_error" })
expect(run?.failureDetail).toContain(reason)
expect(run?.finishedAt).not.toBeNull()
expect(await job.step()).toMatchObject({ status: "failed", attempts: 1, result: null })
// A redelivery reaches a terminal run: no second call.
await job.deliver()
expect(job.tool.calls).toHaveLength(1)
})
it("does not resume a refused run when the grant is approved later", async () => {
const job = await harness()
job.tool.mcp = status(403)
await job.deliver()
job.tool.mcp = answered
await job.deliver()
expect(await job.run()).toMatchObject({ status: "failed", failureCode: "tool_error" })
expect(job.tool.calls).toHaveLength(1)
})
it("does not resume a cancelled run: a run stuck on a transient failure can be ended by a person", async () => {
const job = await harness()
job.tool.mcp = status(503)
await expect(job.deliver()).rejects.toThrow()
await job.cancel()
job.tool.mcp = answered
await job.deliver()
expect(await job.run()).toMatchObject({ status: "cancelled", failureCode: null })
await job.deliver()
expect(job.tool.calls).toHaveLength(1)
})
it("does not commit a step whose tool answered an error, and keeps the tool's text out of the run", async () => {
const job = await harness()
job.tool.mcp = rpc({ resultType: "complete", isError: true, content: [{ type: "text", text: TOOL_TEXT }] })
await expect(job.deliver()).resolves.toBeUndefined()
const run = await job.run()
expect(run).toMatchObject({ status: "failed", failureCode: "tool_error", usageSteps: 0 })
expect(run?.failureDetail).toContain("records__read")
expect(run?.failureDetail).not.toContain(TOOL_TEXT)
const step = await job.step()
expect(step).toMatchObject({ status: "failed", result: null })
expect(step?.error).not.toContain(TOOL_TEXT)
await job.deliver()
expect(job.tool.calls).toHaveLength(1)
})
it.each<[string, Mcp, string?]>([
["a 503", status(503)],
["a 429", status(429)],
["a 500", status(500)],
[
"busy local compute",
rpc({
resultType: "complete",
isError: true,
structuredContent: { status: "compute_busy", retryAfterSeconds: 5 },
}),
],
[
"a catalog that is still indexing",
rpc({ resultType: "complete", isError: true, structuredContent: { status: "indexing", retryAfterSeconds: 5 } }),
"find_tools",
],
["a runtime the platform could not reach", denied("runtime-unavailable")],
])("leaves the run to the queue on %s, and the next delivery resumes the step", async (_case, mcp, toolName) => {
const job = await harness(toolName)
job.tool.mcp = mcp
await expect(job.deliver()).rejects.toThrow()
expect(await job.run()).toMatchObject({ status: "running", failureCode: null })
expect(await job.step()).toMatchObject({ status: "pending", attempts: 1 })
job.tool.mcp = answered
await job.deliver()
expect(await job.run()).toMatchObject({ status: "completed", failureCode: null })
expect(await job.step()).toMatchObject({ status: "committed", attempts: 2 })
// The same key both times: an effect the first call made is not made twice.
expect(new Set(job.tool.calls.map((call) => call.idempotencyKey))).toEqual(new Set([`${job.runId}:read`]))
})
it("leaves the run to the queue when the network fails", async () => {
const job = await harness()
job.tool.mcp = () => {
throw new TypeError("fetch failed")
}
await expect(job.deliver()).rejects.toThrow("fetch failed")
expect(await job.run()).toMatchObject({ status: "running", failureCode: null })
})
})
it("persists sanitized exhaustion on the actual final attempt, with no replay calls", async () => {
const job = await harness()
job.tool.mcp = status(503)
await job.deliver({ finalAttempt: true })
expect(await job.run()).toMatchObject({ status: "failed", failureCode: "internal" })
expect((await job.run())?.failureDetail).toBe("the durable job exhausted its retry attempts")
await job.deliver({ finalAttempt: true })
expect(job.tool.calls).toHaveLength(1)
})
it("a revoked initiating member is refused before any provider call despite the warm memo", async () => {
const job = await harness()
const { orgMemberships } = await import("@conusai-kit/tenancy")
const repos = job.data.forScope(job.scope)
const membership = (await repos.of(orgMemberships).list({ limit: 10 })).items[0]
if (!membership) throw new Error("expected membership")
await repos.of(orgMemberships).delete(membership.id)
await job.deliver()
expect(await job.run()).toMatchObject({ status: "failed", failureCode: "internal" })
expect(vi.mocked(fetch)).not.toHaveBeenCalled()
})
it("revocation after a tool prevents the next model call", async () => {
const job = await harness()
const { orgMemberships } = await import("@conusai-kit/tenancy")
const original = job.container.resolve(AGENT_TOOLS)
const child = job.container.child()
child.value(AGENT_TOOLS, {
async call(...args) {
const result = await original.call(...args)
const repos = job.data.forScope(job.scope)
const member = (await repos.of(orgMemberships).list({ limit: 10 })).items[0]
if (!member) throw new Error("expected membership")
await repos.of(orgMemberships).delete(member.id)
return result
},
})
await job.deliver({ container: child })
expect(await job.run()).toMatchObject({ status: "failed", usageSteps: 1 })
expect(job.tool.calls).toHaveLength(1)
expect(vi.mocked(fetch).mock.calls.filter(([url]) => String(url) === GATEWAY_URL)).toHaveLength(1)
})
it("missing adapter execution refuses before durable or provider work even at exhaustion", async () => {
const job = await harness()
await expect(
runJob.handler(
{ runId: job.runId },
{
container: job.container,
correlationId: "unsupported-adapter",
attempt: 1,
finalAttempt: true,
},
),
).rejects.toMatchObject({ code: "job_claim_lost" })
expect((await job.run())?.status).toBe("queued")
expect(job.tool.calls).toHaveLength(0)
expect(vi.mocked(fetch)).not.toHaveBeenCalled()
})
it("an actual claim with an unsupported data source hook refuses before Agent effects", async () => {
const job = await harness()
const child = job.container.child()
child.value(DATA_SOURCE, createMemoryDataSource({ entities: [] }))
await expect(job.deliver({ container: child, finalAttempt: true })).rejects.toMatchObject({ code: "job_claim_lost" })
expect((await job.run())?.status).toBe("queued")
expect(job.tool.calls).toHaveLength(0)
expect(vi.mocked(fetch)).not.toHaveBeenCalled()
})
+201
View File
@@ -0,0 +1,201 @@
// The agent module's use cases on the in-memory adapter: starting lists and statuses, cancel's
// resume event, and the approval queue — which must surface the EXACT stored proposed arguments.
import { AGENT_ENTITIES, dataAgentPersistence, dataRunStore, threadIdOf } from "@conusai-kit/agent"
import type { TenantScope } from "@conusai-kit/core"
import { createMemoryDataSource } from "@conusai-kit/data"
import { describe, expect, it } from "vitest"
import { cancelRun, getManyRuns, getRun, listApprovals, listRuns, reviewApproval, startRun } from "../core/runs.js"
const USER = "01900000-0000-7000-0000-000000000009"
const scope: TenantScope = {
level: "project",
actor: { userId: USER },
orgId: "01900000-0000-7000-0000-000000000001",
workspaceId: "01900000-0000-7000-0000-000000000002",
projectId: "01900000-0000-7000-0000-000000000003",
}
const makeDeps = () => ({ data: createMemoryDataSource({ entities: [...AGENT_ENTITIES] }) })
const PLAN = [
{ key: "read", label: "Read the document", tool: "documents.read", args: { fileId: "f-1" } },
{ key: "propose", label: "Propose lines", tool: "documents.extract", args: { fileId: "f-1", schema: "line" } },
]
describe("the agent module's run use cases", () => {
const deps = makeDeps()
it("starts a run queued, with the plan visible, and lists it", async () => {
const run = await startRun(deps, scope, { goal: "Review the contract", plan: PLAN })
expect(run.status).toBe("queued")
expect(run.goal).toBe("Review the contract")
expect(run.plan).toEqual([
{
key: "read",
label: "Read the document",
tool: "documents.read",
args: { fileId: "f-1" },
needsApproval: false,
status: "pending",
attempts: 0,
error: null,
},
{
key: "propose",
label: "Propose lines",
tool: "documents.extract",
args: { fileId: "f-1", schema: "line" },
needsApproval: false,
status: "pending",
attempts: 0,
error: null,
},
])
expect(run.percent).toBe(0)
expect(run.answer).toBeNull()
const listed = await listRuns(deps, scope, {})
expect(listed.runs).toHaveLength(1)
expect((await getRun(deps, scope, run.runId)).runId).toBe(run.runId)
// The outbox event that enqueues the run job in the worker.
const pending = await deps.data.outbox.pending(10)
expect(pending.some((record) => record.name === "agent.runResumeRequested")).toBe(true)
})
it("reads runs back by id for the live list, and answers nothing for another project's or no run", async () => {
const own = makeDeps()
const run = await startRun(own, scope, { goal: "Read back", plan: PLAN })
const listed = (await listRuns(own, scope, {})).runs
expect(await getManyRuns(own, scope, [run.runId, run.runId])).toEqual(listed)
const elsewhere: TenantScope = { ...scope, projectId: "01900000-0000-7000-0000-000000000004" }
expect(await getManyRuns(own, elsewhere, [run.runId])).toEqual([])
expect(await getManyRuns(own, scope, ["01900000-0000-7000-0000-0000000000ff"])).toEqual([])
})
it("answers a completed run's answer with the provenance it is stored with (AI Act Art. 50(2))", async () => {
const fresh = makeDeps()
const run = await startRun(fresh, scope, { goal: "Review the contract", plan: PLAN })
expect(run.answerProvenance).toBeNull()
const provenance = {
ai_generated: true as const,
mode: "machine-generated" as const,
digital_source_type: "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia",
generator: "conusai.ai-gateway",
provider: "openai",
model: "gpt-4o-mini-2024-07-18",
generated_at: "2026-11-02T10:30:00Z",
}
const store = dataRunStore(fresh.data, scope)
const record = await store.get(run.runId)
await store.transition(run.runId, record?.version ?? 0, {
status: "completed",
finishedAt: "2026-11-02T10:30:01.000Z",
answerProvenance: provenance,
})
await dataAgentPersistence(fresh.data, scope).stores.messages.saveThread(threadIdOf(run.runId), [
{ role: "user", content: "Review the contract" },
{ role: "assistant", content: "The contract was reviewed." },
])
const completed = await getRun(fresh, scope, run.runId)
expect(completed.answer).toBe("The contract was reviewed.")
expect(completed.answerProvenance).toEqual(provenance)
})
it("refuses an over-long or repeated plan before anything is written", async () => {
const fresh = makeDeps()
const tooLong = await startRun(fresh, scope, {
goal: "x",
plan: Array.from({ length: 26 }, (_, at) => ({ key: `s${at}`, label: `Step ${at}`, tool: "t", args: {} })),
}).catch((error: unknown) => error)
expect((tooLong as { status?: number }).status).toBe(422)
const repeated = await startRun(fresh, scope, {
goal: "x",
plan: [
{ key: "same", label: "One", tool: "t", args: {} },
{ key: "same", label: "Two", tool: "t", args: {} },
],
}).catch((error: unknown) => error)
expect((repeated as { status?: number }).status).toBe(422)
expect((await listRuns(fresh, scope, {})).runs).toHaveLength(0)
})
it("cancel persists the request and re-enqueues the resume; a parked approval surfaces its exact arguments", async () => {
const fresh = makeDeps()
const run = await startRun(fresh, scope, { goal: "Approve-aware run", plan: PLAN })
// Simulate the engine parking an approval by writing the step row as the engine would.
const { dataRunStore } = await import("@conusai-kit/agent")
const store = dataRunStore(fresh.data, scope)
await store.parkStepApproval(
run.runId,
{ key: "read", index: 0, label: "Read the document" },
{
actionId: "act-7",
tool: "documents.read",
arguments: { fileId: "f-1", dryRun: false },
reviewUrl: "https://console/review?action=act-7",
interrupt: null,
},
new Date().toISOString(),
)
await fresh.data
.forScope(scope)
// biome-ignore lint/suspicious/noExplicitAny: test adjusts the run's status as the engine would.
.of(AGENT_ENTITIES[0] as any)
.update(run.runId, { status: "awaiting_approval" }, 1)
const queue = await listApprovals(fresh, scope)
expect(queue.approvals).toHaveLength(1)
expect(queue.approvals[0]).toMatchObject({
runId: run.runId,
stepKey: "read",
tool: "documents.read",
arguments: { fileId: "f-1", dryRun: false },
reviewUrl: "https://console/review?action=act-7",
})
const cancelled = await cancelRun(fresh, scope, run.runId)
expect(cancelled.cancelled).toBe(true)
expect((await getRun(fresh, scope, run.runId)).cancelRequested).toBe(true)
// The cancel re-published the resume event: a parked run notices the request only when resumed.
const pending = await fresh.data.outbox.pending(10)
expect(pending.filter((record) => record.name === "agent.runResumeRequested")).toHaveLength(2)
const review = await reviewApproval(fresh, scope, { runId: run.runId, stepKey: "read", decision: "approve" })
expect(["queued", "running", "awaiting_approval", "cancelled"]).toContain(review.status)
const bad = await reviewApproval(fresh, scope, { runId: run.runId, stepKey: "propose", decision: "approve" }).catch(
(error: unknown) => error,
)
expect((bad as { status?: number }).status).toBe(422)
// The decision is recorded on the step: the queue no longer offers it, and it is not decided twice.
expect((await listApprovals(fresh, scope)).approvals).toHaveLength(0)
const again = await reviewApproval(fresh, scope, { runId: run.runId, stepKey: "read", decision: "reject" }).catch(
(error: unknown) => error,
)
expect((again as { status?: number }).status).toBe(409)
expect((await store.listSteps(run.runId))[0]?.approval?.decision).toBe("approved")
})
})
it("does not offer or accept a pending approval after its run failed", async () => {
const fresh = makeDeps()
const run = await startRun(fresh, scope, { goal: "Synthetic approval", plan: PLAN })
const store = dataRunStore(fresh.data, scope)
await store.parkStepApproval(
run.runId,
{ key: "read", index: 0, label: "Read" },
{
actionId: null,
tool: "records.write",
arguments: {},
reviewUrl: null,
interrupt: null,
},
new Date().toISOString(),
)
const record = await store.get(run.runId)
if (!record) throw new Error("expected a run")
await store.transition(run.runId, record.version, { status: "failed", failureCode: "budget_exhausted" })
expect((await listApprovals(fresh, scope)).approvals).toEqual([])
await expect(
reviewApproval(fresh, scope, { runId: run.runId, stepKey: "read", decision: "approve" }),
).rejects.toMatchObject({ status: 409 })
})
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// The real procedure/kernel/tenancy path over memory repositories. No live Cloud/provider claim.
import { type Actor, buildRegistry, Container, createCaller } from "@conusai-kit/core"
import { createMemoryDataSource, DATA_SOURCE, entitiesOf, SYSTEM_DATA } from "@conusai-kit/data"
import { createTenancyHooks, orgMemberships, TENANCY, tenancyModule, users } from "@conusai-kit/tenancy"
import { expect, it } from "vitest"
import { AGENT_MODULE_BASE } from "../module.shared.js"
it("an open stream observes membership revocation and reconnect is refused", async () => {
const registry = buildRegistry([tenancyModule, AGENT_MODULE_BASE])
const data = createMemoryDataSource({ entities: entitiesOf(registry, "postgres") })
const root = new Container()
root.value(DATA_SOURCE, data)
root.value(SYSTEM_DATA, data)
const caller = (actor: Actor) => {
const tenancy = createTenancyHooks({ data, registry })
const container = root.child()
container.value(TENANCY, tenancy)
return createCaller({ registry, container, tenancy }, { actor })
}
const user = async (subject: string) => {
const row = await data.global(users).insert({
issuer: "https://id.example.test",
subject,
email: `${subject}@example.test`,
displayName: subject,
locale: "en",
})
return { userId: row.id }
}
const owner = await user("owner")
const member = await user("reader")
const call = caller(owner)
const { orgId } = (await call.callByName("tenancy.org.create", { slug: "alpha", name: "Alpha" })) as { orgId: string }
await call.callByName("tenancy.workspace.create", { org: "alpha", slug: "work", name: "Work", visibility: "org" })
await call.callByName("tenancy.project.create", {
org: "alpha",
workspace: "work",
slug: "project",
name: "Project",
moduleKey: "agent",
})
await data.unitOfWork.run({ level: "org", actor: owner, orgId }, (tx) =>
tx.of(orgMemberships).insert({ userId: member.userId, role: "viewer" }),
)
const slugs = { org: "alpha", workspace: "work", project: "project" }
const run = (await call.callByName("agent.run.start", {
...slugs,
goal: "Synthetic run",
plan: [{ key: "read", label: "Read", tool: "records.read", args: {} }],
})) as { runId: string }
const response = (await caller(member).callByName("agent.run.events", { ...slugs, runId: run.runId })) as Response
if (!response.body) throw new Error("expected a streamed response")
const reader = response.body.getReader()
expect(new TextDecoder().decode((await reader.read()).value)).toContain("RUN_STARTED")
await caller(owner).callByName("tenancy.member.remove", { org: "alpha", userId: member.userId })
expect(await reader.read()).toEqual({ done: true, value: undefined })
await expect(caller(member).callByName("agent.run.events", { ...slugs, runId: run.runId })).rejects.toMatchObject({
status: 404,
})
})
+104
View File
@@ -0,0 +1,104 @@
// The approval queue's markup: the EXACT stored proposed arguments are rendered (never a
// narration), the Art. 50 disclosure rides with them, and the controls are named for a keyboard.
import { buildRegistry } from "@conusai-kit/core"
import { createI18n } from "@conusai-kit/i18n"
import { createDataClient, DataProvider } from "@conusai-kit/ui/data"
import { renderToStaticMarkup } from "react-dom/server"
import { describe, expect, it } from "vitest"
import { appModules } from "../../index.js"
import type { ApprovalView } from "../contract/index.js"
import { ApprovalQueue } from "../ui/approval-queue.js"
import { RunControls } from "../ui/run-controls.js"
const catalogues = buildRegistry([...appModules]).catalogues
const i18n = createI18n("en", { en: { agent: catalogues.en?.agent ?? {} } })
const t = (key: string, values?: Record<string, string | number>) => i18n.message(`agent.${key}`, values)
const failed = "That did not work: {detail}"
const slugs = { org: "acme", workspace: "ws", project: "p" }
const inProvider = (node: React.ReactNode) =>
renderToStaticMarkup(
<DataProvider client={createDataClient({ fetch: async () => new Response(null, { status: 501 }) })}>
{node}
</DataProvider>,
)
const approval: ApprovalView = {
runId: "r1",
stepKey: "read",
goal: "Review the contract",
tool: "orders.create",
arguments: { total: 4200, currency: "EUR" },
reviewUrl: "https://console/tool-approvals?action=act-1",
createdAt: "2026-10-23T00:00:00.000Z",
}
const labels = {
heading: t("approvals.heading"),
empty: t("approvals.empty"),
proposed: t("approvals.proposed"),
review: t("approvals.review"),
approve: t("approvals.approve"),
reject: t("approvals.reject"),
decided: t("approvals.decided"),
disclosure: t("approvals.disclosure"),
failed,
}
describe("the approval queue", () => {
const html = inProvider(<ApprovalQueue slugs={slugs} seed={[approval]} labels={labels} />)
it("renders the exact stored proposed arguments, pretty-printed, with the disclosure", () => {
// The exact stored arguments, HTML-escaped as any rendered text is.
expect(html).toContain("&quot;total&quot;: 4200")
expect(html).toContain("&quot;currency&quot;: &quot;EUR&quot;")
expect(html).toContain(t("approvals.disclosure"))
expect(html).toContain(t("approvals.proposed"))
})
it("names the decision controls and links the console review", () => {
expect(html).toContain(`>${t("approvals.approve")}<`)
expect(html).toContain(`>${t("approvals.reject")}<`)
expect(html).toContain('href="https://console/tool-approvals?action=act-1"')
})
it("announces an empty queue", () => {
const empty = inProvider(<ApprovalQueue slugs={slugs} seed={[]} labels={labels} />)
expect(empty).toContain(t("approvals.empty"))
})
})
describe("the run controls", () => {
const labels = {
cancel: t("runs.cancel"),
cancelling: t("runs.cancelling"),
failedHint: t("recovery.failedHint"),
cancelledHint: t("recovery.cancelledHint"),
uncertainHint: t("recovery.uncertainHint"),
budgetExhausted: t("recovery.budgetExhausted"),
approvalUnavailable: t("recovery.approvalUnavailable"),
toolError: t("recovery.toolError"),
planRefused: t("recovery.planRefused"),
internal: t("recovery.internal"),
}
it("offers cancel on an active run and recovery copy on an uncertain one", () => {
const active = inProvider(
<RunControls slugs={slugs} run={{ runId: "r1", status: "running", failureCode: null }} labels={labels} />,
)
expect(active).toContain(`>${t("runs.cancel")}<`)
const uncertain = inProvider(
<RunControls slugs={slugs} run={{ runId: "r1", status: "uncertain", failureCode: null }} labels={labels} />,
)
expect(uncertain).toContain(
t("recovery.uncertainHint")
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll(String.fromCharCode(34), "&quot;")
.replaceAll(String.fromCharCode(39), "&#x27;"),
)
expect(uncertain).not.toContain(`>${t("runs.cancel")}<`)
})
})
+45
View File
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
import { buildRegistry, Container, createCaller } from "@conusai-kit/core"
import { DATA_SOURCE, type DataSource, SYSTEM_DATA, type SystemDataSource } from "@conusai-kit/data"
import { createTenancyHooks, TENANCY, tenancyModule, users } from "@conusai-kit/tenancy"
import type { AgentScope } from "../core/ports.js"
import { AGENT_MODULE_BASE } from "../module.shared.js"
export const workerRegistry = buildRegistry([tenancyModule, AGENT_MODULE_BASE])
/** Real app membership/permission resolution, including a retained memo to expose stale use. */
export async function workerFixture(data: DataSource & SystemDataSource) {
const container = new Container()
container.value(DATA_SOURCE, data)
container.value(SYSTEM_DATA, data)
const tenancy = createTenancyHooks({ data, registry: workerRegistry })
container.value(TENANCY, tenancy)
const user = await data.global(users).insert({
issuer: "https://id.example.test",
subject: crypto.randomUUID(),
email: "worker@example.test",
displayName: "Worker fixture",
locale: "en",
})
const actor = { userId: user.id }
const caller = createCaller({ registry: workerRegistry, container, tenancy }, { actor })
const org = `worker-${crypto.randomUUID()}`
const { orgId } = (await caller.callByName("tenancy.org.create", { slug: org, name: "Worker" })) as { orgId: string }
const { workspaceId } = (await caller.callByName("tenancy.workspace.create", {
org,
slug: "work",
name: "Work",
visibility: "org",
})) as { workspaceId: string }
const { projectId } = (await caller.callByName("tenancy.project.create", {
org,
workspace: "work",
slug: "project",
name: "Project",
moduleKey: "agent",
})) as { projectId: string }
const scope: AgentScope = { level: "project", actor, orgId, workspaceId, projectId }
// Warm the request memo: worker admission must read past this after a revocation.
await tenancy.authorize(scope, "agent.run.start", { name: "agent.run.start", kind: "effect" })
return { container, scope, tenancy }
}
@@ -0,0 +1,223 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// Actual nonowner PostgreSQL + app tenancy + Agent job. Scripted model/tools, no live provider.
import { AGENT_MODEL, AGENT_TOOLS, dataRunStore } from "@conusai-kit/agent"
import { newId } from "@conusai-kit/core"
import type { KyselyDataSource } from "@conusai-kit/data-kysely"
import { orgMemberships, TENANCY } from "@conusai-kit/tenancy"
import { beforeAll, expect, it, vi } from "vitest"
import { AGENT_SCOPE } from "../core/ports.js"
import { startRun } from "../core/runs.js"
import { type ClaimChange, claimedDataSource, claimedDelivery, terminateClaimSession } from "./claimed-job.js"
import { planFollower } from "./plan-model.js"
import { workerFixture } from "./worker-fixture.js"
let data: KyselyDataSource
beforeAll(async () => {
data = await claimedDataSource()
}, 300_000)
async function fixture(needsApproval = false) {
const { container, scope } = await workerFixture(data)
// The actual worker binding uses a system actor; stored actorId alone supplies member authority.
container.value(AGENT_SCOPE, { ...scope, actor: { userId: "system:agent", system: true } })
let models = 0
let revokeDuringModel = false
let loseDuringModel = false
let tools = 0
const adapter = planFollower()
const stream = adapter.chatStream.bind(adapter)
adapter.chatStream = async function* (...args) {
models++
if (revokeDuringModel) await removeMember()
if (loseDuringModel) await terminateClaimSession()
yield* stream(...args)
}
container.value(AGENT_MODEL, adapter)
let revoke = false
let transient = false
const removeMember = async () => {
const repos = data.forScope(scope)
const member = (await repos.of(orgMemberships).list({ limit: 10 })).items[0]
if (!member) throw new Error("expected member")
await repos.of(orgMemberships).delete(member.id)
}
container.value(AGENT_TOOLS, {
async call() {
tools++
if (transient) throw new Error("private upstream failure")
if (revoke) await removeMember()
return { status: "completed", content: [], usage: { costMicrocents: 0, steps: 1, tokens: 0 } }
},
})
const { runId } = await startRun({ data }, scope, {
goal: "Synthetic worker verification",
plan: [
{ key: "read", label: "Read", tool: "records.read", args: {}, needsApproval },
{ key: "next", label: "Next", tool: "records.next", args: {} },
],
})
const store = dataRunStore(data, scope)
return {
container,
scope,
runId,
store,
removeMember,
counts: () => ({ models, tools }),
loseDuringModel: () => {
loseDuringModel = true
},
revokeDuringModel: () => {
revokeDuringModel = true
},
revoke: () => {
revoke = true
},
fail: () => {
transient = true
},
deliver: (finalAttempt = false, change?: ClaimChange) =>
claimedDelivery(data, container, scope, runId, { finalAttempt }, change),
}
}
it("executes and replays without repeating providers through the nonowner runtime", async () => {
const job = await fixture()
await job.deliver()
expect((await job.store.get(job.runId))?.status).toBe("completed")
const counts = job.counts()
expect(counts.tools).toBe(2)
await job.deliver()
expect(job.counts()).toEqual(counts)
})
it("refuses revoked membership before the first model and after a committed step", async () => {
const before = await fixture()
await before.removeMember()
await before.deliver()
expect(before.counts()).toEqual({ models: 0, tools: 0 })
expect((await before.store.get(before.runId))?.status).toBe("failed")
const between = await fixture()
between.revoke()
await between.deliver()
expect(between.counts()).toEqual({ models: 1, tools: 1 })
expect(await between.store.get(between.runId)).toMatchObject({ status: "failed", usageSteps: 1 })
})
it("wrong org, workspace or project cannot execute or alter the immutable stored run", async () => {
const job = await fixture()
for (const field of ["orgId", "workspaceId", "projectId"] as const) {
const container = job.container.child()
container.value(AGENT_SCOPE, { ...job.scope, [field]: newId() })
await expect(claimedDelivery(data, container, job.scope, job.runId, { finalAttempt: true })).rejects.toThrow()
}
expect(job.counts()).toEqual({ models: 0, tools: 0 })
expect((await job.store.get(job.runId))?.status).toBe("queued")
})
it("bounded exhaustion persists terminal failure, preserving committed/replay semantics", async () => {
const job = await fixture()
job.fail()
await expect(job.deliver()).rejects.toThrow()
expect((await job.store.get(job.runId))?.status).toBe("running")
await job.deliver(true)
expect(await job.store.get(job.runId)).toMatchObject({
status: "failed",
failureDetail: "the durable job exhausted its retry attempts",
})
expect((await job.store.listSteps(job.runId))[0]?.attempts).toBe(2)
const counts = job.counts()
await job.deliver(true)
expect(job.counts()).toEqual(counts)
})
it("revocation between model and tool refuses the effect before any tool call", async () => {
const job = await fixture()
job.revokeDuringModel()
await job.deliver()
expect(job.counts()).toEqual({ models: 1, tools: 0 })
expect((await job.store.get(job.runId))?.status).toBe("failed")
})
it("approval resumes the exact call, while revocation prevents approved resumption", async () => {
const job = await fixture(true)
await job.deliver(true)
expect((await job.store.get(job.runId))?.status).toBe("awaiting_approval")
expect(job.counts().tools).toBe(0)
await job.store.decideApproval(job.runId, "read", "approved")
await job.deliver()
expect((await job.store.get(job.runId))?.status).toBe("completed")
expect(job.counts().tools).toBe(2)
await job.deliver()
expect(job.counts().tools).toBe(2)
const revoked = await fixture(true)
await revoked.deliver()
await revoked.store.decideApproval(revoked.runId, "read", "approved")
await revoked.removeMember()
const counts = revoked.counts()
await revoked.deliver()
expect(revoked.counts()).toEqual(counts)
expect((await revoked.store.get(revoked.runId))?.status).toBe("failed")
})
it("a current role demotion removes execution permission despite the retained memo", async () => {
const job = await fixture()
const repos = data.forScope(job.scope)
const member = (await repos.of(orgMemberships).list({ limit: 10 })).items[0]
if (!member) throw new Error("expected membership")
await repos.of(orgMemberships).update(member.id, { role: "viewer" }, member.version)
await job.deliver()
expect(job.counts()).toEqual({ models: 0, tools: 0 })
expect((await job.store.get(job.runId))?.status).toBe("failed")
})
it.each(["cancel", "reclaim", "delete", "scope", "actor"] as const)(
"actual adapter refuses %s before provider or durable run mutation",
async (change) => {
const job = await fixture()
const before = await job.store.get(job.runId)
const storeCalls = vi.spyOn(data, "forScope")
await expect(job.deliver(true, change)).rejects.toMatchObject({ code: "job_claim_lost" })
expect(job.counts()).toEqual({ models: 0, tools: 0 })
expect(storeCalls).not.toHaveBeenCalled()
storeCalls.mockRestore()
expect(await job.store.get(job.runId)).toEqual(before)
expect(await job.store.listSteps(job.runId)).toEqual([])
},
)
it("actual original attribution must match the immutable run owner", async () => {
const job = await fixture()
const before = await job.store.get(job.runId)
await expect(job.deliver(true, "owner")).rejects.toMatchObject({ code: "job_claim_lost" })
expect(job.counts()).toEqual({ models: 0, tools: 0 })
expect(await job.store.get(job.runId)).toEqual(before)
expect(await job.store.listSteps(job.runId)).toEqual([])
})
it("actual owned guard backend loss during model admission prevents every later tool and terminal failure", async () => {
const job = await fixture()
job.loseDuringModel()
await expect(job.deliver(true)).rejects.toMatchObject({ code: "job_claim_lost" })
expect(job.counts()).toEqual({ models: 1, tools: 0 })
expect((await job.store.get(job.runId))?.status).not.toBe("failed")
})
it("actual guard loss during authorization refuses model admission before any provider call", async () => {
const job = await fixture()
const tenancy = job.container.resolve(TENANCY)
const child = job.container.child()
child.value(TENANCY, {
...tenancy,
async authorizeIn(...args) {
const result = await tenancy.authorizeIn(...args)
await terminateClaimSession()
return result
},
})
await expect(claimedDelivery(data, child, job.scope, job.runId, { finalAttempt: true })).rejects.toMatchObject({
code: "job_claim_lost",
})
expect(job.counts()).toEqual({ models: 0, tools: 0 })
expect((await job.store.get(job.runId))?.status).toBe("queued")
})