/** * Protocol versioning primitives for Skaile Agent Protocol v2. * * The protocol is versioned by a structured {@link ProtocolVersion} record * (`major.minor.patch`). The compatibility rule applied at handshake is * **major-equality**: a runner emits {@link IncompatibleProtocolEvent} and * shuts down when its declared major does not match the platform's announced * major. Minor and patch differences ride through transparently because * unknown fields are preserved on round-trip (see `MessageMeta` round-trip * contract in `messaging.ts`). * * @category Protocol * @since 2.0.0 */ /** * Structured semantic version triple for the agent protocol. * * @example * ```ts * const v: ProtocolVersion = { major: 2, minor: 0, patch: 0 }; * ``` * * @category Protocol * @since 2.0.0 * @docLink packages/types/protocol-v2#protocol-version */ export type ProtocolVersion = { /** Incremented on breaking wire-format changes (field removed, semantics changed, required field added). */ major: number; /** Incremented on additive wire-format changes (new optional fields, new event types). */ minor: number; /** Incremented on bug-fix or doc-only changes that do not affect the wire. */ patch: number; }; /** * The protocol version the framework currently speaks. Runners and platforms * compare this against the peer's announced version at session boot via * `SessionInitCommand.protocolVersion`. * * @example * ```ts * import { PROTOCOL_VERSION } from '@skaile/workspaces/types'; * if (cmd.protocolVersion.major !== PROTOCOL_VERSION.major) { * emit({ type: 'incompatible_protocol', agentVersion: PROTOCOL_VERSION, platformVersion: cmd.protocolVersion }); * } * ``` * * @category Protocol * @since 3.0.0 * * Changed in 3.12.0: * Optional structured prompt attachments and question/reply requestId correlation. * Older peers retain text prompts and ignore unknown optional fields. Managed * question hosts must echo requestId; this minor does not advertise or admit the * separately gated codex-app-server-v1 runtime. * * Changed in 3.10.0: * Additive rejection cause on the AI-credential refresh input. The * `host.refresh_credential` `ai-credentials` input gains an optional * `rejection?: CredentialRejection` (`'auth' | 'usage-limit'`), sent only * alongside `reason: 'retry-401'` and only from the two runner call sites that * genuinely classified the failure — the driver's auth self-heal (`'auth'`) and * its usage-limit failover (`'usage-limit'`). `reason: 'retry-401'` collapsed * both, so a limit-blocked session on a config that is not opted into * `autoActivate` never re-resolved; the field is what lets the platform tell * them apart. `auth` asserts only that the rejection was auth-shaped, never * that capacity is fine (Anthropic mislabels OAuth quota exhaustion as * `authentication_error`); only `usage-limit` is a positive assertion. The * connector and MCP refresh paths classify nothing and keep emitting exactly * today's bytes. There is no peer-version gate, so a 3.9 peer does receive the * key on those two inputs; it is unaffected because nothing was removed or * reshaped and it must ignore an unknown key — and an unrecognised value — * rather than reject the input, which is also what allows a third rejection * later without a major bump. A 3.10 host against a 3.9 runner never sees the * field and must not read its absence as "not a limit" (feature-detect on * `major === 3 && minor >= 10`). * Spec: skaile-ai/platform#3562. * * Changed in 3.9.0: * Additive live AI-provider-seat signals, all optional under the * major-equality rule: * - `AgentEvent` gains `provider_response_seen`, emitted when the runner * observes a 401 or a 429 / subscription-limit rejection from the AI * provider, attributed to the pinned `AIProviderConfig`. A platform with * no handler broadcasts it harmlessly; consumers must ignore unknown * fields, since the platform half ships independently. * - The `CredentialMint` success branch gains an optional `configId` — the * seat the platform actually minted for. When it differs from the one the * runner asked for, the runner repoints the live session at it. A platform * that omits the field produces exactly 3.8 behaviour (no switch is ever * detected). * - The `credentialRotated` broadcast may carry `entry.data.configId` to * move a running session to a different seat rather than merely rotating * the token on the current one. Absent → today's re-pull. * A 3.8 peer is unaffected: nothing was removed or re-shaped, every addition is * opt-in on a field a 3.8 peer never sets. A 3.9 host against a 3.8 runner sees * no `provider_response_seen` and must not read that as "no limits were hit" * (feature-detect on `major === 3 && minor >= 9`). * * Changed in 3.8.0: * Additive `prompt` receipt acknowledgement. The `prompt` command gains an * optional `messageId`; when set the runner emits exactly one new `prompt_ack` * event echoing it, as the first act of handling the frame — before the * session-readiness gate, the secrets check and the driver start, each of which * could previously drop a prompt with no trace at all. When absent nothing is * emitted, so a 3.7 host sees byte-identical behaviour. A 3.8 host against a * 3.7 runner gets no ack and must not read that as a lost prompt — feature-detect * on `major === 3 && minor >= 8`. The ack is receipt-only: it says the frame * arrived, never that the turn ran. * * Changed in 3.7.0: * Additive `connector_mutate` acknowledgement + flow-hydrate reconciliation. * Three changes, all additive under the major-equality rule: * - `ConnectorMutateCommand` gains an optional `requestId`. When set, the * runner emits exactly one new `connector_mutate_response` event (with * `ok` / `result` / `error` / `code` / `reconciled`) on every terminal path, * including the paths that previously only logged. When absent nothing is * emitted, so a 3.6 host sees byte-identical behaviour. * - `flow.hydrate` accepts an optional `payload.pendingDecisions` — * `PendingGateDecision[]` the runner replays against the snapshot in the * same invocation that creates the flow connector, reporting the outcome as * `reconciled`. A host that omits the key gets today's hydrate. * - A flow-targeted mutate whose connector is not yet registered now waits * (bounded, `SKAILE_FLOW_MUTATE_CONNECTOR_WAIT_MS`, default 8000 ms) and * re-plans instead of failing — a behaviour change on a path that used to * fail silently, visible to a 3.6 host only as the op succeeding. * A 3.6 peer is unaffected: no symbol was removed or re-shaped, the ack is * opt-in on a field a 3.6 host never sets, and unknown fields ride through the * round-trip. A 3.7 host against a 3.6 runner sees `requestId` ignored and no * response, which it must treat as "unacknowledged" (feature-detect on * `major === 3 && minor >= 7`). Spec: `runner/MIGRATION-flow-connector.md`. * * Changed in 3.6.0: * Additive resolved-agent-config wire field. `ResolvedSkaileConfig` gains an * optional `agentConfig?: ResolvedAgentConfig` carrying the platform-resolved * driver / provider / model / cloud / cloudConfig / thinking / effort — the * same values the platform bakes into the generated skaile.yaml * `agent-config.default`. The runner applies it disk-first: any on-disk * `agent-config` profile with at least one agent setting disables the wire * value outright, so yaml-on-disk (docker-mode) sessions are byte-identical. * Additive under the major-equality rule: an older runner ignores the field * and an older platform simply omits it. * * Changed in 3.5.0: * Flow-connector host-contract fix (workspaces#379). Three coordinated changes, * all additive under the major-equality rule: * - `op:"hydrate"` on the bare `"flow"` connector now auto-creates the * `flow:` connector on a cold container from its `{ state, flow }` * payload, so a persisted run rehydrates in one op. A peer that still issues * `start` then `hydrate` keeps working unchanged. * - The dead `SessionInit.activeFlows` field (never read by the runner) and its * `ActiveFlowRehydration` type are removed — wire-compatible (nothing produced * or consumed them) but source-breaking for typed hosts, hence the bump. * - Malformed / conflicting flow `start` and `hydrate` payloads now fail loudly * (warn with a reason) instead of silently falling through. * Because the handshake compares only `major`, a 3.4 host and a 3.5 runner * interoperate: the auto-create path is opt-in on the payload the host sends, and * the removed field was already inert. Spec: `runner/MIGRATION-flow-connector.md`. * * Changed in 3.4.0: * Additive embedded-app capability source. `CapabilityOrigin` gains a * `{ kind: 'app'; appId: string }` variant and `Capability.side` gains `'app'` * ("the handler runs in the embedded app"). Both are additive: a peer that does * not understand `origin:'app'` / `side:'app'` never produces or routes them, so * they ride through transparently under the major-equality rule. No new message * types — `capability_register` / `capability_invoked` / `capability_result` / * `capability_approve` / `render_invoked` are reused verbatim. Spec: * `_devlog/specs/2026-07-07-app-capability-source.md`. * * Changed in 3.3.0: * Additive agent-to-agent (session-to-session) communication extension. * `AgentEvent` gains an `a2a_message` variant carrying cross-session messages * (`direction`, `peerSessionId`, `peerName`, `exchangeId`, `text`). `Capability` * gains an optional `callTimeoutMs?: number` so a long-running capability call * (e.g. a 5-minute `platform.ask_session`) can exceed the default capability-call * timeout. Both are additive: a peer that does not understand them ignores the * event / falls back to the default timeout, so they ride through transparently * under the major-equality rule. * * Changed in 3.2.0: * Additive wake-time resume cascade. `AgentReconfigureOptions` gains optional * `resumeSessionId` and `expectedCapabilitySignature` fields driving the tier-1 * native SDK resume path; `AgentEvent` gains `ResumeAttemptedEvent` and * `ResumeFailedEvent`. `FinishedEvent` gains optional `customType` / * `customData` for capability-routed custom payloads. All additive — clients * that omit the resume hint or ignore the new events keep working unchanged. * * Changed in 3.1.0: * Additive cost / token usage extension. `FinishedEvent` gains an optional * `tokens?: TokenUsage` field carrying per-turn input / output / cache-read / * cache-creation / reasoning token counts. `AgentDriver.getTokenUsage()` is * widened to return the same `TokenUsage` shape (existing consumers reading * `inputTokens` / `outputTokens` keep working unchanged). Drivers that do not * surface token usage continue to return `null` / omit the field. * * Changed in 3.0.0: * Major bump for the deterministic session bootstrap rewrite. `ConfigureCommandV2`, * `provision_secrets`, `request_access_token`, `add_resource`, `remove_resource`, * `set_log_level`, `state_action`, `lifecycle`, `remount_mount`, `compact`, and * `reconfigure_agent` are removed from the `AgentCommand` union. Their semantics * are reachable through: * - `session_init` (one deterministic envelope at session start that delivers * identity, resolved config, pre-minted credentials, secrets, capabilities, * shared state, active flows, resume hints, and logging config), * - `host.refresh_credential` (capability invocation that replaces the * refresh-on-401 path of `request_access_token`), and * - `runner.*` capabilities (`runner.add_mount`, `runner.add_connector`, * `runner.remove_resource`, `runner.update_credential`, `runner.set_log_level`, * `runner.set_state`, `runner.lifecycle`) invoked by the platform via the * bidirectional capability registry. * * Capabilities gain an `audience: ('llm' | 'user' | 'runtime')[]` field that * scopes visibility: host RPCs (`host.*`) and runner RPCs (`runner.*`) are * `['runtime']` and never reach the LLM tool list or the user-facing command * palette. v2.x capabilities without an explicit `audience` default to * `['llm', 'user']`, preserving prior behaviour. * * Spec: `_devlog/specs/2026-05-10-deterministic-session-bootstrap.md`. * * @docLink packages/types/protocol-v3#protocol-version */ export declare const PROTOCOL_VERSION: ProtocolVersion; /** * String form of {@link PROTOCOL_VERSION}, kept in lock-step. Useful for * `package.json` version fields and HTTP `User-Agent` strings. * * @category Protocol * @since 3.0.0 * @docLink packages/types/protocol-v3#protocol-version */ export declare const PROTOCOL_VERSION_STRING = "3.12.0"; /** * Parse a `"major.minor.patch"` string into a {@link ProtocolVersion}. * * @param s - the version string to parse, exactly three dot-separated non-negative integers * @returns the parsed protocol version * @throws {Error} if the string is not exactly three dot-separated non-negative integers * * @example * ```ts * parseVersion('2.0.0'); // { major: 2, minor: 0, patch: 0 } * parseVersion('2.1'); // throws * ``` * * @category Protocol * @since 2.0.0 * @docLink packages/types/protocol-v2#parse-version */ export declare function parseVersion(s: string): ProtocolVersion; /** * Format a {@link ProtocolVersion} record into its `"major.minor.patch"` string form. * * @param v - the protocol version to format * @returns the dot-joined string form * * @example * ```ts * formatVersion({ major: 2, minor: 0, patch: 0 }); // '2.0.0' * ``` * * @category Protocol * @since 2.0.0 * @docLink packages/types/protocol-v2#format-version */ export declare function formatVersion(v: ProtocolVersion): string; //# sourceMappingURL=version.d.ts.map