From 62f817780633c3743dd3e393a58ef2f1f7b91ad8 Mon Sep 17 00:00:00 2001 From: "jason.woltje" Date: Sun, 12 Jul 2026 22:29:21 +0000 Subject: [PATCH] feat(tess): define runtime provider contract (#719) --- .../src/agent/agent-runtime-provider.spec.ts | 44 +++++++ .../types/src/agent/agent-runtime-provider.ts | 110 ++++++++++++++++++ packages/types/src/agent/index.ts | 2 + 3 files changed, 156 insertions(+) create mode 100644 packages/types/src/agent/agent-runtime-provider.spec.ts create mode 100644 packages/types/src/agent/agent-runtime-provider.ts diff --git a/packages/types/src/agent/agent-runtime-provider.spec.ts b/packages/types/src/agent/agent-runtime-provider.spec.ts new file mode 100644 index 0000000..71b2ae7 --- /dev/null +++ b/packages/types/src/agent/agent-runtime-provider.spec.ts @@ -0,0 +1,44 @@ +import { describe, expect, it } from 'vitest'; +import type { + AgentRuntimeProvider, + RuntimeAttachHandle, + RuntimeCapability, + RuntimeError, + RuntimeSession, + RuntimeStreamEvent, +} from './agent-runtime-provider.js'; + +describe('AgentRuntimeProvider contract', (): void => { + it('exposes stable, normalized runtime-only contracts', (): void => { + const capability: RuntimeCapability = 'session.attach'; + const session: RuntimeSession = { + id: 'session-1', + providerId: 'fleet', + runtimeId: 'tmux', + state: 'active', + createdAt: '2026-07-12T00:00:00.000Z', + updatedAt: '2026-07-12T00:00:00.000Z', + }; + const event: RuntimeStreamEvent = { + type: 'message.delta', + sessionId: session.id, + cursor: '2', + occurredAt: session.updatedAt, + content: 'hello', + }; + const error: RuntimeError = { + code: 'capability_unsupported', + message: 'Denied', + retryable: false, + }; + const attach: RuntimeAttachHandle = { + attachmentId: 'attach-1', + sessionId: session.id, + mode: 'read', + expiresAt: session.updatedAt, + }; + const provider: Pick = + {} as Pick; + expect([capability, session.id, event.type, error.code, attach.mode, provider]).toHaveLength(6); + }); +}); diff --git a/packages/types/src/agent/agent-runtime-provider.ts b/packages/types/src/agent/agent-runtime-provider.ts new file mode 100644 index 0000000..4a5fb56 --- /dev/null +++ b/packages/types/src/agent/agent-runtime-provider.ts @@ -0,0 +1,110 @@ +export type RuntimeCapability = + | 'session.list' + | 'session.tree' + | 'session.stream' + | 'session.send' + | 'session.attach' + | 'session.terminate'; +export type RuntimeSessionState = 'starting' | 'active' | 'idle' | 'stopped' | 'failed'; +export type RuntimeAttachMode = 'read' | 'control'; + +/** Server-derived immutable authority context. Client identity fields are intentionally absent. */ +export interface RuntimeScope { + readonly actorId: string; + readonly tenantId: string; + readonly channelId: string; + readonly correlationId: string; +} +export interface RuntimeSession { + id: string; + providerId: string; + runtimeId: string; + parentSessionId?: string; + state: RuntimeSessionState; + createdAt: string; + updatedAt: string; +} +export interface RuntimeSessionTree { + session: RuntimeSession; + children: RuntimeSessionTree[]; +} +export interface RuntimeCapabilitySet { + supported: RuntimeCapability[]; +} +export interface RuntimeHealth { + status: 'healthy' | 'degraded' | 'down'; + checkedAt: string; + detail?: string; +} +export interface RuntimeMessage { + content: string; + idempotencyKey: string; +} +export interface RuntimeAttachHandle { + attachmentId: string; + sessionId: string; + mode: RuntimeAttachMode; + expiresAt: string; +} +export interface RuntimeError { + code: + | 'capability_unsupported' + | 'not_found' + | 'forbidden' + | 'conflict' + | 'unavailable' + | 'invalid_request'; + message: string; + retryable: boolean; +} +export type RuntimeStreamEvent = + | { + type: 'session.state'; + sessionId: string; + cursor: string; + occurredAt: string; + state: RuntimeSessionState; + } + | { + type: 'message.delta'; + sessionId: string; + cursor: string; + occurredAt: string; + content: string; + } + | { + type: 'message.complete'; + sessionId: string; + cursor: string; + occurredAt: string; + messageId: string; + } + | { + type: 'runtime.error'; + sessionId: string; + cursor: string; + occurredAt: string; + error: RuntimeError; + }; + +/** Runtime-neutral boundary; implementations fail closed for unsupported operations. */ +export interface AgentRuntimeProvider { + readonly id: string; + capabilities(scope: RuntimeScope): Promise; + health(scope: RuntimeScope): Promise; + listSessions(scope: RuntimeScope): Promise; + getSessionTree(scope: RuntimeScope): Promise; + streamSession( + sessionId: string, + cursor: string | undefined, + scope: RuntimeScope, + ): AsyncIterable; + sendMessage(sessionId: string, message: RuntimeMessage, scope: RuntimeScope): Promise; + attach( + sessionId: string, + mode: RuntimeAttachMode, + scope: RuntimeScope, + ): Promise; + detach(attachmentId: string, scope: RuntimeScope): Promise; + terminate(sessionId: string, approvalRef: string, scope: RuntimeScope): Promise; +} diff --git a/packages/types/src/agent/index.ts b/packages/types/src/agent/index.ts index 8d303d2..1803cd3 100644 --- a/packages/types/src/agent/index.ts +++ b/packages/types/src/agent/index.ts @@ -2,3 +2,5 @@ export interface AgentSessionHandle { readonly id: string; } + +export * from './agent-runtime-provider.js';