From b86060a43a8fe7faad7f9c528041ca50f925dd67 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Fri, 14 Aug 2026 23:58:36 -0600 Subject: [PATCH 01/25] fix(release): scope partial evidence to selected checks --- scripts/release/bindings.mjs | 11 ++++ scripts/release/collector-validation.mjs | 2 +- scripts/release/collector.mjs | 11 ++-- scripts/release/release-collector.test.mjs | 58 +++++++++++++++++++--- 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/scripts/release/bindings.mjs b/scripts/release/bindings.mjs index 698a819..ac792da 100644 --- a/scripts/release/bindings.mjs +++ b/scripts/release/bindings.mjs @@ -69,6 +69,17 @@ export function normalizeRequirementCheckBindings(input, requirementIds, checkId return bindings } +export function selectRequirementCheckBindings(bindings, checkIds) { + assert(bindings instanceof Map, 'Requirement check bindings must be a map') + const selected = new Set(checkIds) + return new Map( + [...bindings.entries()].flatMap(([id, binding]) => { + const checks = binding.checks.filter((checkId) => selected.has(checkId)) + return checks.length === 0 ? [] : [[id, { checks }]] + }), + ) +} + export function materializeRequirementBindings( checkBindings, { artifactsByCheck = new Map(), additionalArtifacts = [] } = {}, diff --git a/scripts/release/collector-validation.mjs b/scripts/release/collector-validation.mjs index dad619f..4d31dae 100644 --- a/scripts/release/collector-validation.mjs +++ b/scripts/release/collector-validation.mjs @@ -341,7 +341,7 @@ export async function validateCheckpoint(checkpoint, { artifactRoot, identity, p assert(referencedEnvironmentIds.has(id), `Checkpoint has an unreferenced environment ${id}`) const mappings = normalizeRequirementBindings( checkpoint.envelope.requirements, - identity.requirementIds, + Object.keys(plan.requirements), plan.checkIds, ) for (const [id, binding] of mappings) { diff --git a/scripts/release/collector.mjs b/scripts/release/collector.mjs index 9fd4923..927eefe 100644 --- a/scripts/release/collector.mjs +++ b/scripts/release/collector.mjs @@ -10,6 +10,7 @@ import { materializeRequirementBindings, normalizeRequirementCheckBindings, requirementsObject, + selectRequirementCheckBindings, } from './bindings.mjs' import { readBuildIdentity, readRequirementIds } from './build-identity.mjs' import { registerCheckArtifacts } from './check-artifacts.mjs' @@ -191,11 +192,15 @@ export async function collectReleaseEvidence({ 'Build identity requirement list differs from docs', ) const selected = selectedChecks(checkIds, identity.requirementIds) - const checkBindings = normalizeRequirementCheckBindings( + const knownCheckIds = [ + ...new Set([...requiredEvidenceCheckIds(identity.requirementIds), ...selected]), + ] + const allCheckBindings = normalizeRequirementCheckBindings( requirementBindings, identity.requirementIds, - selected, + knownCheckIds, ) + const checkBindings = selectRequirementCheckBindings(allCheckBindings, selected) for (const id of selected) assert( requirementIdsForPlan({ requirements: Object.fromEntries(checkBindings) }, id).length > 0, @@ -431,7 +436,7 @@ export async function collectReleaseEvidence({ packageIntegrity: identity.packageIntegrity, packageFileManifestDigest: identity.packageFileManifestDigest, dependencyDigest: identity.dependencyDigest, - requirementIds: identity.requirementIds, + requirementIds: Object.keys(plan.requirements).sort(), checkIds: selected, checkCount: checks.size, result: passed ? 'passed' : complete ? 'failed' : 'incomplete', diff --git a/scripts/release/release-collector.test.mjs b/scripts/release/release-collector.test.mjs index c71672e..2229608 100644 --- a/scripts/release/release-collector.test.mjs +++ b/scripts/release/release-collector.test.mjs @@ -60,7 +60,9 @@ function git(root, ...args) { return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim() } -async function makeRepo() { +async function makeRepo({ + requirementDocument = '## Product acceptance\n\n| PR-01 | local proof |\n', +} = {}) { const root = await mkdtemp(join(tmpdir(), 'braid-release-repo-')) const artifactRoot = await mkdtemp(join(tmpdir(), 'braid-release-artifacts-')) await mkdir(join(root, 'docs'), { recursive: true }) @@ -74,10 +76,7 @@ async function makeRepo() { })}\n`, ) await writeFile(join(root, 'pnpm-lock.yaml'), 'lockfileVersion: 9.0\n') - await writeFile( - join(root, 'docs', 'requirements.md'), - '## Product acceptance\n\n| PR-01 | local proof |\n', - ) + await writeFile(join(root, 'docs', 'requirements.md'), requirementDocument) git(root, 'init', '-q') git(root, 'config', 'core.hooksPath', '/dev/null') git(root, 'config', 'user.email', 'release-test@example.invalid') @@ -110,8 +109,8 @@ async function makeRepo() { return { root, artifactRoot, tarballPath, tarballBytes, proof } } -async function withRepo(action) { - const fixture = await makeRepo() +async function withRepo(action, options) { + const fixture = await makeRepo(options) try { return await action(fixture) } finally { @@ -811,6 +810,51 @@ test('one local catalog check produces redacted artifacts and an immutable colle }) }) +test('a selected check reports only requirements covered by that check', async () => { + await withRepo( + async ({ root, artifactRoot, tarballPath, proof }) => { + const result = await collectReleaseEvidence({ + repository: root, + artifactRoot, + tarballPath, + packageProof: proof, + requirementBindings: { + 'AN-01': { checks: ['unit'] }, + 'PR-01': { checks: ['live-bridge'] }, + 'VR-01': { checks: ['release'] }, + }, + checkIds: ['release'], + environment: { PATH: process.env.PATH ?? '', NODE_ENV: 'test' }, + runCheck: async ({ checkId }) => { + const processResult = await executeArgv({ + file: process.execPath, + args: ['-e', 'process.stdout.write("passed")'], + cwd: root, + environment: { PATH: process.env.PATH ?? '', NODE_ENV: 'test' }, + }) + return { + checkId, + category: 'release', + command: 'pnpm check:release', + argv: ['pnpm', 'check:release'], + ...processResult, + } + }, + }) + + assert.equal(result.result, 'passed') + assert.deepEqual(Object.keys(result.envelope.requirements), ['VR-01']) + assert.deepEqual(result.manifest.requirementIds, ['VR-01']) + }, + { + requirementDocument: + '## Analysis acceptance\n\n| AN-01 | analysis proof |\n\n' + + '## Product acceptance\n\n| PR-01 | product proof |\n\n' + + '## Release acceptance\n\n| VR-01 | release proof |\n', + }, + ) +}) + test('a restored failed check is retried with a new recorded attempt', async () => { await withRepo(async ({ root, artifactRoot, tarballPath, proof }) => { let calls = 0 From 351b6ab81cdcd660638a405da08a78e730dd1959 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sat, 15 Aug 2026 00:04:05 -0600 Subject: [PATCH 02/25] fix(runtime): recover retained interaction responses --- src/adapters/runtime/retained-execution.ts | 76 +++++++++++++++++++++- test/retained-execution-lifecycle.test.ts | 74 +++++++++++++++++++-- 2 files changed, 145 insertions(+), 5 deletions(-) diff --git a/src/adapters/runtime/retained-execution.ts b/src/adapters/runtime/retained-execution.ts index 0859c4d..6c9d1cd 100644 --- a/src/adapters/runtime/retained-execution.ts +++ b/src/adapters/runtime/retained-execution.ts @@ -1,4 +1,8 @@ -import type { AgentExactRunControlRef } from '@tangle-network/agent-interface' +import type { + AgentExactRunControlRef, + InteractionAcknowledgementStatus, + InteractionResponseCommand, +} from '@tangle-network/agent-interface' import type { RetainedRunHandle } from '@tangle-network/agent-runtime/kernel' import { canonicalDigest } from '../../domain/canonical.js' import type { RuntimeEventEnvelope } from '../../domain/runtime-events.js' @@ -255,6 +259,54 @@ export class RetainedExecutionPort implements ExecutionPort { } } + async respondInteraction(input: { + readonly command: InteractionResponseCommand + readonly signal?: AbortSignal + }): Promise { + const { binding } = input.command + const resolved = await this.#handleFor( + binding.runId, + binding.sessionId, + undefined, + input.signal, + ) + if (!resolved) { + return { + operationId: input.command.operationId, + outcome: 'unknown', + detail: 'INTERACTION_RESPONSE_RUN_UNKNOWN', + } + } + const exact = resolved.handle.controlRef + if ( + binding.provider !== exact.provider || + binding.environmentId !== exact.environmentId || + binding.sessionId !== exact.sessionId || + binding.executionId !== exact.executionId + ) { + return { + operationId: input.command.operationId, + outcome: 'rejected', + detail: 'INTERACTION_BINDING_MISMATCH', + } + } + const acknowledgement = await resolved.handle.respondToInteraction(input.command, { + ...(input.signal === undefined ? {} : { signal: input.signal }), + }) + if ( + acknowledgement.operationId !== input.command.operationId || + acknowledgement.commandDigest !== input.command.commandDigest || + canonicalDigest(acknowledgement.binding) !== canonicalDigest(input.command.binding) + ) { + return { + operationId: input.command.operationId, + outcome: 'rejected', + detail: 'INTERACTION_ACKNOWLEDGEMENT_MISMATCH', + } + } + return interactionAcknowledgement(input.command.operationId, acknowledgement.status) + } + async #handleFor( runId: string, providerSessionId: string | undefined, @@ -367,3 +419,25 @@ export class RetainedExecutionPort implements ExecutionPort { if (active !== undefined) this.#state.assertSameControlRef(active.controlRef, exact) } } + +function interactionAcknowledgement( + operationId: string, + status: InteractionAcknowledgementStatus, +): ControlAcknowledgement { + switch (status) { + case 'accepted': + return { operationId, outcome: 'accepted', detail: 'INTERACTION_RESPONSE_ACCEPTED' } + case 'already_resolved_same': + return { operationId, outcome: 'already-applied', detail: 'INTERACTION_RESPONSE_REPLAYED' } + case 'already_resolved_different': + case 'binding_mismatch': + case 'cancelled': + case 'expired': + case 'invalid_response': + return { operationId, outcome: 'rejected', detail: `INTERACTION_${status.toUpperCase()}` } + case 'transport_failure': + case 'unknown_interaction': + case 'unknown_run': + return { operationId, outcome: 'unknown', detail: `INTERACTION_${status.toUpperCase()}` } + } +} diff --git a/test/retained-execution-lifecycle.test.ts b/test/retained-execution-lifecycle.test.ts index 58efd1b..2a94dbf 100644 --- a/test/retained-execution-lifecycle.test.ts +++ b/test/retained-execution-lifecycle.test.ts @@ -1,6 +1,10 @@ import assert from 'node:assert/strict' import test from 'node:test' -import { defineAgentProfile, type AgentExactRunControlRef } from '@tangle-network/agent-interface' +import { + type AgentExactRunControlRef, + defineAgentProfile, + type InteractionResponseCommand, +} from '@tangle-network/agent-interface' import type { RetainedRunHandle } from '@tangle-network/agent-runtime/kernel' import { type RetainedExecutionPlan, @@ -43,6 +47,7 @@ function handle( exact: AgentExactRunControlRef, options: { readonly cancel?: (input: CancelOptions) => Promise + readonly respondToInteraction?: RetainedRunHandle['respondToInteraction'] readonly status?: RetainedRunHandle['status'] } = {}, ): RetainedRunHandle { @@ -61,9 +66,11 @@ function handle( async result() { return { text: '', success: true } }, - async respondToInteraction() { - throw new Error('interaction is not part of this test') - }, + respondToInteraction: + options.respondToInteraction ?? + (async () => { + throw new Error('interaction is not part of this test') + }), async contextBoundary() { return null }, @@ -345,6 +352,65 @@ test('a reconciled cancelled snapshot confirms an ambiguous cancellation', async assert.equal(statusCalls, 1) }) +test('interaction response recovers the retained handle and preserves retry acknowledgement', async () => { + const exact = controlRef('interaction') + let responses = 0 + const retainedHandle = handle(exact, { + respondToInteraction: async (command) => { + responses += 1 + return { + operationId: command.operationId, + binding: command.binding, + commandDigest: command.commandDigest, + status: responses === 1 ? 'accepted' : 'already_resolved_same', + } + }, + }) + const recoveredPlan: RetainedExecutionPlan = { + ...plan(exact, async () => retainedHandle, retainedHandle), + discover: async (runId) => { + assert.equal(runId, 'run-interaction') + return exact + }, + } + const execution = new RetainedExecutionPort({ + resolve: async () => { + throw new Error('a recovered interaction must not resolve a new run') + }, + recover: async ({ runId, providerSessionId }) => { + assert.equal(runId, 'run-interaction') + assert.equal(providerSessionId, exact.sessionId) + return recoveredPlan + }, + }) + const command: InteractionResponseCommand = { + operationId: 'operation-interaction-response', + binding: { + requestDigest: `sha256:${'b'.repeat(64)}`, + runId: 'run-interaction', + provider: exact.provider, + environmentId: exact.environmentId, + sessionId: exact.sessionId, + executionId: exact.executionId, + interactionId: 'interaction-retained', + }, + commandDigest: `sha256:${'c'.repeat(64)}`, + response: { id: 'interaction-retained', outcome: 'accepted' }, + } + + assert.deepEqual(await execution.respondInteraction({ command }), { + operationId: command.operationId, + outcome: 'accepted', + detail: 'INTERACTION_RESPONSE_ACCEPTED', + }) + assert.deepEqual(await execution.respondInteraction({ command }), { + operationId: command.operationId, + outcome: 'already-applied', + detail: 'INTERACTION_RESPONSE_REPLAYED', + }) + assert.equal(responses, 2) +}) + test('admission rejects at capacity instead of evicting a prepared plan', async () => { let starts = 0 const execution = executionFor(async (runInput) => { From acdb6efdd88ecaa3c7e013233d80646d5386bd42 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sat, 15 Aug 2026 00:41:30 -0600 Subject: [PATCH 03/25] fix(runtime): adopt corrected retained interaction bindings --- package.json | 2 +- pnpm-lock.yaml | 18 +++++++++--------- pnpm-workspace.yaml | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 40deb78..5e01e4d 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "@tangle-network/agent-interface": "0.52.0", "@tangle-network/agent-provider-cli-bridge": "0.7.1", "@tangle-network/agent-provider-tangle": "0.10.0", - "@tangle-network/agent-runtime": "0.134.5", + "@tangle-network/agent-runtime": "0.134.9", "@tangle-network/sandbox": "0.26.1", "better-sqlite3-multiple-ciphers": "13.0.3", "chalk": "6.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e683986..36bd4d7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,8 +34,8 @@ importers: specifier: 0.10.0 version: 0.10.0(@tangle-network/sandbox@0.26.1) '@tangle-network/agent-runtime': - specifier: 0.134.5 - version: 0.134.5(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)(@tangle-network/sandbox@0.26.1) + specifier: 0.134.9 + version: 0.134.9(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)(@tangle-network/sandbox@0.26.1) '@tangle-network/sandbox': specifier: 0.26.1 version: 0.26.1 @@ -514,8 +514,8 @@ packages: '@tangle-network/agent-interface@0.52.0': resolution: {integrity: sha512-jISw0y/VqQxeyuI7N5zsEb2+AMAYoIkPCtDVbWwZ9n2KL45rur//0ih72xPo3M+fiE0eUj9weTAYg4mzZckiHg==} - '@tangle-network/agent-knowledge@7.2.6': - resolution: {integrity: sha512-0JKCWGWfevzSIt2WALhQ6RSk1grn0wB1Yj8vVMhW5XNcMQthmJ4lQRX3pBlk1cPg5yhuk48H9u4iY2YuoKnRKg==} + '@tangle-network/agent-knowledge@8.0.0': + resolution: {integrity: sha512-29so4fdP/pp7rKzXgnJFmwyvD9HNpA+FxlraxSQuq4jFKMpSePop1AXMLrHEerP7W1Z8Jq4vrKrp7cFy8y7Xnw==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: @@ -535,8 +535,8 @@ packages: peerDependencies: '@tangle-network/sandbox': '>=0.23.0 <1.0.0' - '@tangle-network/agent-runtime@0.134.5': - resolution: {integrity: sha512-bEUUmPSj2UDXX4v7W8vUOWmUA875LMeivIUQPXY+loiL5aHnKJUTRAKgOf9QpbgW4xMVOYHxHHem7HRcoLONjQ==} + '@tangle-network/agent-runtime@0.134.9': + resolution: {integrity: sha512-ZtBzAl25zZQiSZMahEM59jRNCjcvimUpUWc2r+wR8c+hB1m5kaftw7tqy0lvWkZ1peL5I4D/1DNyVBmwY+0i8Q==} engines: {node: '>=22.13.0'} hasBin: true peerDependencies: @@ -1159,7 +1159,7 @@ snapshots: spdx-expression-parse: 5.0.0 zod: 4.4.3 - '@tangle-network/agent-knowledge@7.2.6(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)': + '@tangle-network/agent-knowledge@8.0.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)': dependencies: '@tangle-network/agent-eval': 0.145.11 '@tangle-network/agent-interface': 0.52.0 @@ -1180,12 +1180,12 @@ snapshots: '@tangle-network/agent-interface': 0.52.0 '@tangle-network/sandbox': 0.26.1 - '@tangle-network/agent-runtime@0.134.5(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)(@tangle-network/sandbox@0.26.1)': + '@tangle-network/agent-runtime@0.134.9(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)(@tangle-network/sandbox@0.26.1)': dependencies: '@tangle-network/agent-core': 0.8.0 '@tangle-network/agent-eval': 0.145.11 '@tangle-network/agent-interface': 0.52.0 - '@tangle-network/agent-knowledge': 7.2.6(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0) + '@tangle-network/agent-knowledge': 8.0.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0) '@tangle-network/agent-profile-materialize': 0.14.2(@tangle-network/agent-interface@0.52.0) '@tangle-network/agent-trace-contract': 1.0.2 tar-stream: 3.2.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0d3c466..2cde334 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,10 +9,10 @@ allowBuilds: node-pty: true ignoreScripts: false minimumReleaseAgeExclude: - - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5' + - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5 || 0.134.9' - '@tangle-network/agent-eval@0.143.0 || 0.144.0 || 0.144.1 || 0.144.3 || 0.144.4 || 0.144.6 || 0.144.8 || 0.144.10 || 0.144.11 || 0.144.13 || 0.145.0 || 0.145.1 || 0.145.2 || 0.145.3 || 0.145.9 || 0.145.10 || 0.145.11' - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0' - - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6' + - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0' - '@tangle-network/agent-profile-materialize@0.10.2 || 0.13.1 || 0.14.0 || 0.14.2' - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1' - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0' From 48ee47014fe6481323d84685b66eb1eacea72d64 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sat, 15 Aug 2026 02:40:44 -0600 Subject: [PATCH 04/25] fix(interactions): bind replies to admitted runs --- src/adapters/tui/application-ui-controller.ts | 12 +- src/adapters/tui/ui-core-dispatch.ts | 4 +- src/adapters/tui/ui-headless-dispatch.ts | 7 + src/app/application-interaction-actions.ts | 28 ++-- src/app/application.ts | 6 +- src/app/automation-actions.ts | 24 ++- src/app/interaction-controller.ts | 7 +- src/ports/execution.ts | 9 +- test/automation-interaction-commands.test.ts | 5 +- test/interaction-response-durability.test.ts | 24 +-- test/interaction-response-safety.test.ts | 148 +++++++++++++++++- test/interactions.test.ts | 5 +- test/support/run-capabilities.ts | 10 ++ test/tui.test.ts | 3 +- 14 files changed, 239 insertions(+), 53 deletions(-) create mode 100644 test/support/run-capabilities.ts diff --git a/src/adapters/tui/application-ui-controller.ts b/src/adapters/tui/application-ui-controller.ts index d2fe079..369a1f7 100644 --- a/src/adapters/tui/application-ui-controller.ts +++ b/src/adapters/tui/application-ui-controller.ts @@ -19,7 +19,7 @@ import { capabilityMap } from './ui-capabilities.js' import { errorResult } from './ui-dispatch-error.js' import { FIXTURE_FORK, FIXTURE_INTERACTION, type UiFixture } from './ui-fixtures.js' import { withIntelligenceResult } from './ui-intelligence-result-view.js' -import { toEvent, toHeadlessState } from './ui-projection.js' +import { interactionViews, toEvent, toHeadlessState } from './ui-projection.js' import { createUiSubscriberDelivery, type UiSubscriberDelivery } from './ui-subscriber-delivery.js' import { buildBraidViewModel, type UiAppearanceOptions } from './ui-view-model.js' @@ -91,6 +91,7 @@ export class ApplicationUiController implements BraidUiController { } #project(state: BraidState, app: BraidApplication): BraidViewModel { + const canRespond = app.canRespondToInteractions(interactionViews(state)[0]?.runId) const view = withRunUsage( buildBraidViewModel( state, @@ -99,7 +100,7 @@ export class ApplicationUiController implements BraidUiController { app.canCancel(), app.storageFailure(), app.cleanupUncertain(), - app.canRespondToInteractions(), + canRespond, this.#graphQuery, ), state, @@ -114,12 +115,7 @@ export class ApplicationUiController implements BraidUiController { ? decorated : freezeView({ ...decorated, - capabilities: capabilityMap( - state, - app.canCancel(), - this.#fixture, - app.canRespondToInteractions(), - ), + capabilities: capabilityMap(state, app.canCancel(), this.#fixture, canRespond), }) const intelligenceDecorated = this.#selectedIntelligenceData === undefined diff --git a/src/adapters/tui/ui-core-dispatch.ts b/src/adapters/tui/ui-core-dispatch.ts index 16b397e..bb6b733 100644 --- a/src/adapters/tui/ui-core-dispatch.ts +++ b/src/adapters/tui/ui-core-dispatch.ts @@ -150,7 +150,7 @@ async function dispatchInteractionAutomation( intent: Extract, context: UiDispatchContext, ): Promise { - if (!context.app.canRespondToInteractions()) { + if (!context.app.canRespondToInteractions(intent.runId)) { return { kind: 'unavailable', code: 'CAPABILITY_UNAVAILABLE', @@ -225,7 +225,7 @@ async function dispatchInteractionResponse( } } - if (!context.app.canRespondToInteractions()) { + if (!context.app.canRespondToInteractions(intent.runId)) { return { kind: 'unavailable', code: 'CAPABILITY_UNAVAILABLE', diff --git a/src/adapters/tui/ui-headless-dispatch.ts b/src/adapters/tui/ui-headless-dispatch.ts index 4c69f55..ef0c8ee 100644 --- a/src/adapters/tui/ui-headless-dispatch.ts +++ b/src/adapters/tui/ui-headless-dispatch.ts @@ -177,6 +177,13 @@ export async function dispatchHeadlessCommand( retryable: false, } } + if (!context.app.canRespondToInteractions(runId)) { + return { + kind: 'unavailable', + code: 'CAPABILITY_UNAVAILABLE', + reason: 'The current runtime cannot acknowledge interaction responses', + } + } const receipt = await context.app.respondInteraction({ operationId: intent.operationId ?? '', runId, diff --git a/src/app/application-interaction-actions.ts b/src/app/application-interaction-actions.ts index 78be27a..df3fdb2 100644 --- a/src/app/application-interaction-actions.ts +++ b/src/app/application-interaction-actions.ts @@ -1,21 +1,21 @@ import type { InteractionResponse } from '@tangle-network/agent-interface' import type { AutomationRuleRecord } from '../domain/entities-runtime.js' import type { BraidEvent, BraidEventEnvelope } from '../domain/events.js' +import { DomainInvariantError } from '../domain/invariants-base.js' +import { assertAutomationRuleRecord } from '../domain/invariants-runtime.js' import type { BraidState } from '../domain/state.js' -import type { ExecutionPort } from '../ports/execution.js' +import { type ExecutionPort, supportsInteractionResponse } from '../ports/execution.js' import { KeyedActionQueue } from './action-serialization.js' +import { operationId } from './application-guards.js' import type { PortViews } from './application-port-builder.js' import type { RuntimeEventEnvelopeLike, RuntimeEventIngestionResult } from './application-ports.js' import type { InteractionReceipt } from './application-types.js' import { type AutomationActions, createAutomationActions } from './automation-actions.js' import type { SerializedEffectCoordinator } from './effect-coordinator.js' -import { operationId } from './application-guards.js' +import { AppError } from './errors.js' import { InteractionAutomationCoordinator } from './interaction-automation-coordinator.js' import { respondInteraction as respondInteractionController } from './interaction-controller.js' import type { RunLedger } from './run-ledger.js' -import { assertAutomationRuleRecord } from '../domain/invariants-runtime.js' -import { DomainInvariantError } from '../domain/invariants-base.js' -import { AppError } from './errors.js' const DEFAULT_INTERACTION_RESPONSE_TIMEOUT_MS = 5_000 @@ -57,7 +57,7 @@ export class ApplicationInteractionActions { now: options.now, respond: (input) => this.respond(input), reconcilePending: () => this.reconcile(), - canRespond: () => this.canRespond(), + canRespond: (runId) => this.canRespond(runId), }) this.#coordinator = new InteractionAutomationCoordinator({ state: options.state, @@ -66,15 +66,23 @@ export class ApplicationInteractionActions { }) } - canRespond(): boolean { - return this.#options.execution.respondInteraction !== undefined + canRespond(runId?: string): boolean { + if (runId === undefined || this.#options.execution.respondInteraction === undefined) + return false + const run = this.#options.state().runs.find((candidate) => candidate.id === runId) + return run !== undefined && supportsInteractionResponse(run.receipt.capabilities) } acceptRuntimeEvent( envelope: RuntimeEventEnvelopeLike, result: RuntimeEventIngestionResult, ): void { - if (!result.accepted || envelope.event.type !== 'interaction' || !this.canRespond()) return + if ( + !result.accepted || + envelope.event.type !== 'interaction' || + !this.canRespond(envelope.runId) + ) + return const interactionId = envelope.event.request.id const target = this.#options .state() @@ -108,7 +116,7 @@ export class ApplicationInteractionActions { } reconcile(): Promise { - return this.canRespond() ? this.#coordinator.reconcile() : Promise.resolve() + return this.#coordinator.reconcile() } async whenIdle(): Promise { diff --git a/src/app/application.ts b/src/app/application.ts index af839e2..3b80400 100644 --- a/src/app/application.ts +++ b/src/app/application.ts @@ -44,8 +44,8 @@ import { ConversationOperationCoordinator } from './conversation-operation-coord import type { ConversationActions } from './conversations.js' import { createDurableSender } from './durable-send.js' import { SerializedEffectCoordinator } from './effect-coordinator.js' -import { effectiveRunConfiguration } from './effective-run-configuration.js' import { projectEffectRecord } from './effect-projection.js' +import { effectiveRunConfiguration } from './effective-run-configuration.js' import { AppError } from './errors.js' import { FailClosedJournal } from './fail-closed-journal.js' import { createIntelligenceActions, type IntelligenceActions } from './intelligence-actions.js' @@ -486,8 +486,8 @@ export class BraidApplication { ) } - canRespondToInteractions(): boolean { - return this.#interactions.canRespond() + canRespondToInteractions(runId?: string): boolean { + return this.#interactions.canRespond(runId) } async detachRun(input: { diff --git a/src/app/automation-actions.ts b/src/app/automation-actions.ts index 1be34d8..48eec37 100644 --- a/src/app/automation-actions.ts +++ b/src/app/automation-actions.ts @@ -7,8 +7,8 @@ import type { AutomationRuleMatcher, AutomationRuleRecord } from '../domain/enti import type { BraidEventEnvelope } from '../domain/events.js' import type { BraidInteraction } from '../domain/runtime-projection.js' import type { BraidState } from '../domain/state.js' -import type { AutomationRuleMetadata } from './automation-matching.js' import { SerializedActionQueue } from './action-serialization.js' +import type { AutomationRuleMetadata } from './automation-matching.js' import type { ApplyAutomationReceipt, AutomationContext, @@ -103,7 +103,7 @@ export function createAutomationActions(options: { readonly automationRule?: AutomationRuleRecord }) => Promise readonly reconcilePending?: () => Promise - readonly canRespond: () => boolean + readonly canRespond: (runId?: string) => boolean }): AutomationActions { const queue = new SerializedActionQueue() const store = (): AutomationStoreInput => ({ @@ -117,6 +117,7 @@ export function createAutomationActions(options: { create: async (input) => { const receipt = await queue.run(async () => { const target = targetFor(options.state(), input.runId, input.interactionId) + assertCanRespond(options, target) const request = requestFor(target, input.request) return createAutomationRule({ ...store(), @@ -131,6 +132,7 @@ export function createAutomationActions(options: { update: async (input) => { const receipt = await queue.run(async () => { const target = targetFor(options.state(), input.runId, input.interactionId) + assertCanRespond(options, target) const request = input.request ?? target?.request return updateAutomationRule({ ...store(), @@ -148,6 +150,7 @@ export function createAutomationActions(options: { const target = targetFor(state, input.runId, input.interactionId) if (target === undefined) throw new AppError('UNKNOWN_INTERACTION', 'The interaction is no longer available') + assertCanRespond(options, target) return dryRunAutomation({ ...store(), operationId: input.operationId, @@ -157,15 +160,11 @@ export function createAutomationActions(options: { }), apply: (input) => queue.run(async () => { - if (!options.canRespond()) - throw new AppError( - 'CAPABILITY_UNAVAILABLE', - 'The current runtime cannot acknowledge interaction responses', - ) const state = options.state() const target = targetFor(state, input.runId, input.interactionId) if (target === undefined) throw new AppError('UNKNOWN_INTERACTION', 'The interaction is no longer available') + assertCanRespond(options, target) return applyAutomation({ ...store(), operationId: input.operationId, @@ -195,6 +194,17 @@ export function createAutomationActions(options: { } } +function assertCanRespond( + options: { readonly canRespond: (runId?: string) => boolean }, + target: BraidInteraction | undefined, +): void { + if (target === undefined || options.canRespond(target.runId)) return + throw new AppError( + 'CAPABILITY_UNAVAILABLE', + 'The current runtime cannot acknowledge interaction responses', + ) +} + function targetFor( state: BraidState, runId: string | undefined, diff --git a/src/app/interaction-controller.ts b/src/app/interaction-controller.ts index 169bd80..bef49ff 100644 --- a/src/app/interaction-controller.ts +++ b/src/app/interaction-controller.ts @@ -5,7 +5,7 @@ import type { AutomationRuleRecord } from '../domain/entities-runtime.js' import type { BraidEventEnvelope } from '../domain/events.js' import { createFeedbackDecisionId } from '../domain/ids.js' import { interactionRemainingMs } from '../domain/interaction-timeout.js' -import type { ExecutionPort } from '../ports/execution.js' +import { type ExecutionPort, supportsInteractionResponse } from '../ports/execution.js' import type { JournalWriter, StateReader } from './application-ports.js' import type { InteractionReceipt } from './application-types.js' import type { SerializedEffectCoordinator } from './effect-coordinator.js' @@ -114,6 +114,11 @@ export async function respondInteraction( completion, } } + if (!supportsInteractionResponse(run.receipt.capabilities)) + throw new AppError( + 'CAPABILITY_UNAVAILABLE', + 'The current runtime cannot acknowledge interaction responses', + ) if (input.execution.respondInteraction === undefined) throw new AppError( 'CAPABILITY_UNAVAILABLE', diff --git a/src/ports/execution.ts b/src/ports/execution.ts index 2280d36..feb1c46 100644 --- a/src/ports/execution.ts +++ b/src/ports/execution.ts @@ -1,16 +1,16 @@ import type { - AgentExactRunControlRef, AgentEnvironmentCapabilities, + AgentExactRunControlRef, AgentProfile, InteractionResponseCommand, } from '@tangle-network/agent-interface' +import type { TurnUsage } from '../domain/entities.js' import type { RetainedRunAdmissionRecord, RetainedRunAdmissionRecorder, RunCapabilities, } from '../domain/run-contracts.js' import type { BraidRuntimeEvent, RuntimeEventEnvelope } from '../domain/runtime-events.js' -import type { TurnUsage } from '../domain/entities.js' import type { RunStatus } from '../domain/state.js' export type { RunCapabilities } from '../domain/receipts.js' @@ -150,6 +150,11 @@ export const UNKNOWN_RUN_CAPABILITIES: RunCapabilities = Object.freeze({ usage: false, }) +/** Treat a published environment capability document as authoritative. */ +export function supportsInteractionResponse(capabilities: RunCapabilities): boolean { + return capabilities.environment?.interactions?.responseIdempotency === true +} + export function capabilitiesFromEnvironment( capabilities: AgentEnvironmentCapabilities, cancellationSupported: boolean, diff --git a/test/automation-interaction-commands.test.ts b/test/automation-interaction-commands.test.ts index 2b19f4a..2be600b 100644 --- a/test/automation-interaction-commands.test.ts +++ b/test/automation-interaction-commands.test.ts @@ -11,13 +11,14 @@ import { rebindInteractionRequest, } from '../src/app/interaction-request.js' import type { BraidRuntimeEvent } from '../src/domain/runtime-events.js' -import { DEFAULT_RUN_CAPABILITIES, type ExecutionPort } from '../src/ports/execution.js' +import type { ExecutionPort } from '../src/ports/execution.js' import type { BraidResponse } from '../src/views/headless/protocol.js' import { runRpc } from '../src/views/headless/rpc.js' import { parseRequest } from '../src/views/headless/rpc-parser.js' import type { InteractionView } from '../src/views/shared/models.js' import { InteractionShell } from '../src/views/tui/interaction.js' import { createBraidTheme } from '../src/views/tui/theme.js' +import { interactionResponseRunCapabilities } from './support/run-capabilities.js' function request(id: string, runId = 'run-request'): InteractionRequest { const material: InteractionRequestMaterial = { @@ -47,7 +48,7 @@ function interactionExecution(source: InteractionRequest): { let release: (() => void) | undefined let responses = 0 const execution: ExecutionPort = { - capabilities: () => DEFAULT_RUN_CAPABILITIES, + capabilities: () => interactionResponseRunCapabilities(), async *streamTurn(input): AsyncIterable { yield { type: 'interaction', diff --git a/test/interaction-response-durability.test.ts b/test/interaction-response-durability.test.ts index 0f0c350..2f6c733 100644 --- a/test/interaction-response-durability.test.ts +++ b/test/interaction-response-durability.test.ts @@ -8,12 +8,20 @@ import type { InteractionRequestMaterial, } from '@tangle-network/agent-interface' import { MemoryCredentialStore } from '../src/adapters/credentials/memory.js' +import type { SqliteStorage } from '../src/adapters/storage/sqlite.js' import { openSqliteStorage } from '../src/adapters/storage/sqlite.js' +import type { StoredAutomationRule } from '../src/app/automation-matching.js' +import { ruleUseReservationId } from '../src/app/automation-rule-persistence.js' +import { automationOperationRecord } from '../src/app/automation-rule-store.js' import { createBraidApplication, DETERMINISTIC_PROFILE } from '../src/app/composition.js' import { InteractionAutomationCoordinator } from '../src/app/interaction-automation-coordinator.js' -import { automationOperationRecord } from '../src/app/automation-rule-store.js' -import { ruleUseReservationId } from '../src/app/automation-rule-persistence.js' +import { + createInteractionRequest, + interactionResponseBinding, + rebindInteractionRequest, +} from '../src/app/interaction-request.js' import { StorageJournal } from '../src/app/storage-journal.js' +import { toJson } from '../src/app/storage-journal-support.js' import { canonicalDigest } from '../src/domain/canonical.js' import type { BraidEvent, BraidEventEnvelope } from '../src/domain/events.js' import { @@ -31,16 +39,8 @@ import { createMaterializedStateSnapshot } from '../src/domain/materialized-stat import { replayEvents } from '../src/domain/reducer.js' import { type BraidState, initialState } from '../src/domain/state.js' import type { ExecutionPort } from '../src/ports/execution.js' -import { DEFAULT_RUN_CAPABILITIES } from '../src/ports/execution.js' import type { JournalEvent } from '../src/ports/storage.js' -import { toJson } from '../src/app/storage-journal-support.js' -import { - createInteractionRequest, - interactionResponseBinding, - rebindInteractionRequest, -} from '../src/app/interaction-request.js' -import type { StoredAutomationRule } from '../src/app/automation-matching.js' -import type { SqliteStorage } from '../src/adapters/storage/sqlite.js' +import { interactionResponseRunCapabilities } from './support/run-capabilities.js' const NOW = '2026-08-09T00:00:00.000Z' const RESPONSE_TIMEOUT_MS = 25 @@ -117,7 +117,7 @@ test('a hung provider response cannot strand manual response, rule mutation, or let responseCalls = 0 let receivedSignal: AbortSignal | undefined const execution: ExecutionPort = { - capabilities: () => DEFAULT_RUN_CAPABILITIES, + capabilities: () => interactionResponseRunCapabilities(), async *streamTurn(input): AsyncIterable<{ readonly type: 'interaction' readonly request: InteractionRequest diff --git a/test/interaction-response-safety.test.ts b/test/interaction-response-safety.test.ts index addc5d6..d859202 100644 --- a/test/interaction-response-safety.test.ts +++ b/test/interaction-response-safety.test.ts @@ -5,16 +5,22 @@ import type { InteractionRequestMaterial, InteractionResponse, } from '@tangle-network/agent-interface' +import { defaultTangleSandboxCapabilities } from '@tangle-network/agent-provider-tangle' import { createApplicationUiController } from '../src/adapters/tui/application-ui-controller.js' +import { automationAudits } from '../src/app/automation-rules.js' import { createBraidApplication } from '../src/app/composition.js' import { AppError } from '../src/app/errors.js' -import { automationAudits } from '../src/app/automation-rules.js' import { createInteractionRequest, rebindInteractionRequest, } from '../src/app/interaction-request.js' import type { BraidRuntimeEvent } from '../src/domain/runtime-events.js' -import { DEFAULT_RUN_CAPABILITIES, type ExecutionPort } from '../src/ports/execution.js' +import { + DEFAULT_RUN_CAPABILITIES, + type ExecutionPort, + type RunCapabilities, +} from '../src/ports/execution.js' +import { interactionResponseRunCapabilities } from './support/run-capabilities.js' function interactionRequest(id: string): InteractionRequest { const material: InteractionRequestMaterial = { @@ -45,6 +51,142 @@ async function waitFor(predicate: () => boolean): Promise { } } +function retainedRunCapabilities(responseSupported: boolean): RunCapabilities { + const environment = structuredClone(defaultTangleSandboxCapabilities('opencode')) + if (!responseSupported) delete environment.interactions + return { + ...DEFAULT_RUN_CAPABILITIES, + streaming: { ...DEFAULT_RUN_CAPABILITIES.streaming, replay: true, detach: true }, + sessions: { ...DEFAULT_RUN_CAPABILITIES.sessions, continue: true }, + controls: { ...DEFAULT_RUN_CAPABILITIES.controls, recreate: true }, + events: { ...DEFAULT_RUN_CAPABILITIES.events, stableIdentity: true, cursor: true }, + environment, + } +} + +function retainedInteractionExecution(responseCapability: true | false | 'unknown'): { + readonly execution: ExecutionPort + readonly release: () => void + readonly responseCount: () => number +} { + const source = interactionRequest( + responseCapability === true + ? 'interaction-retained-capable' + : `interaction-retained-${responseCapability === false ? 'incapable' : 'unknown'}`, + ) + let releaseStream: (() => void) | undefined + let responseCount = 0 + return { + execution: { + capabilities: () => + responseCapability === 'unknown' + ? DEFAULT_RUN_CAPABILITIES + : retainedRunCapabilities(responseCapability), + async *streamTurn(input): AsyncIterable { + yield { + type: 'interaction', + request: rebindInteractionRequest(source, { + ...source.binding, + runId: input.runId, + executionId: input.runId, + }), + } + await new Promise((resolve) => { + releaseStream = resolve + }) + }, + // Retained ports expose this method even when the environment cannot record responses. + respondInteraction: async (input) => { + responseCount += 1 + releaseStream?.() + return { operationId: input.command.operationId, outcome: 'accepted' } + }, + }, + release: () => releaseStream?.(), + responseCount: () => responseCount, + } +} + +test('retained response actions follow the admitted environment capability', async () => { + for (const responseCapability of [true, false, 'unknown'] as const) { + const responseSupported = responseCapability === true + const retained = retainedInteractionExecution(responseCapability) + const app = createBraidApplication({ fixture: 'deterministic', execution: retained.execution }) + app.initialize('/workspace') + const send = app.send({ + operationId: `operation-send-retained-${String(responseCapability)}`, + text: 'ask', + }) + await waitFor(() => app.state().runs[0]?.interactions[0]?.status === 'pending') + const run = app.state().runs[0] + const interaction = run?.interactions[0] + assert(run && interaction) + + assert.equal( + run.receipt.capabilities.environment?.interactions?.responseIdempotency === true, + responseSupported, + ) + assert.equal(app.canRespondToInteractions(run.id), responseSupported) + assert.equal(app.canRespondToInteractions(), false) + const controller = createApplicationUiController(app) + assert.equal( + controller.view().capabilities['interaction.respond']?.available, + responseSupported, + ) + assert.equal( + controller.view().capabilities['interaction.automation']?.available, + responseSupported, + ) + + if (responseSupported) { + const receipt = await app.respondInteraction({ + operationId: `operation-respond-retained-${responseSupported}`, + runId: run.id, + interactionId: interaction.request.id, + response: { + id: interaction.request.id, + outcome: 'accepted', + data: { continue: true }, + }, + }) + assert.equal(receipt.acknowledgement.outcome, 'accepted') + assert.equal(retained.responseCount(), 1) + } else { + await assert.rejects( + app.respondInteraction({ + operationId: 'operation-respond-retained-incapable', + runId: run.id, + interactionId: interaction.request.id, + response: { + id: interaction.request.id, + outcome: 'accepted', + data: { continue: true }, + }, + }), + (error: unknown) => error instanceof AppError && error.code === 'CAPABILITY_UNAVAILABLE', + ) + await assert.rejects( + app.automation.apply({ + operationId: 'operation-automate-retained-incapable', + runId: run.id, + interactionId: interaction.request.id, + }), + (error: unknown) => error instanceof AppError && error.code === 'CAPABILITY_UNAVAILABLE', + ) + assert.equal(retained.responseCount(), 0) + assert.equal( + app.events().filter((event) => event.event.kind === 'run.interaction.response.requested') + .length, + 0, + ) + } + + retained.release() + await send.completion + await app.close() + } +}) + test('an adapter without response support leaves interactions and rules untouched', async () => { const source = interactionRequest('interaction-unsupported') let releaseStream: (() => void) | undefined @@ -125,7 +267,7 @@ test('automatic and manual responses dispatch exactly once when they race', asyn let responseCount = 0 let automaticResponse: InteractionResponse | undefined const execution: ExecutionPort = { - capabilities: () => DEFAULT_RUN_CAPABILITIES, + capabilities: () => interactionResponseRunCapabilities(), async *streamTurn(input): AsyncIterable { yield { type: 'interaction', diff --git a/test/interactions.test.ts b/test/interactions.test.ts index 83b01ca..34feaf3 100644 --- a/test/interactions.test.ts +++ b/test/interactions.test.ts @@ -41,6 +41,7 @@ import { type BraidState, initialState } from '../src/domain/state.js' import { FixedClock } from '../src/ports/clock.js' import { DEFAULT_RUN_CAPABILITIES, type ExecutionPort } from '../src/ports/execution.js' import { SequenceIds } from '../src/ports/ids.js' +import { interactionResponseRunCapabilities } from './support/run-capabilities.js' const NOW = '2026-08-01T00:00:00.000Z' @@ -149,7 +150,7 @@ function interactionExecution(request: InteractionRequest): { let lastCommand: InteractionResponseCommand | undefined let releaseStream: (() => void) | undefined const execution: ExecutionPort = { - capabilities: () => DEFAULT_RUN_CAPABILITIES, + capabilities: () => interactionResponseRunCapabilities(), async *streamTurn(input): AsyncIterable { yield { type: 'interaction', @@ -480,7 +481,7 @@ test('the terminal API never reports an unconfirmed interaction response as acce const request = questionRequest('interaction-unconfirmed') let releaseStream: (() => void) | undefined const execution: ExecutionPort = { - capabilities: () => DEFAULT_RUN_CAPABILITIES, + capabilities: () => interactionResponseRunCapabilities(), async *streamTurn(input): AsyncIterable { yield { type: 'interaction', diff --git a/test/support/run-capabilities.ts b/test/support/run-capabilities.ts new file mode 100644 index 0000000..2ce93f1 --- /dev/null +++ b/test/support/run-capabilities.ts @@ -0,0 +1,10 @@ +import { defaultTangleSandboxCapabilities } from '@tangle-network/agent-provider-tangle' +import { DEFAULT_RUN_CAPABILITIES, type RunCapabilities } from '../../src/ports/execution.js' + +/** A real shared capability document for fake interaction-response adapters. */ +export function interactionResponseRunCapabilities(): RunCapabilities { + return { + ...DEFAULT_RUN_CAPABILITIES, + environment: defaultTangleSandboxCapabilities('opencode'), + } +} diff --git a/test/tui.test.ts b/test/tui.test.ts index ff737c6..fb58c0c 100644 --- a/test/tui.test.ts +++ b/test/tui.test.ts @@ -17,6 +17,7 @@ import type { BraidRuntimeEvent } from '../src/domain/runtime-events.js' import { DEFAULT_RUN_CAPABILITIES, type ExecutionPort } from '../src/ports/execution.js' import { BraidTerminalApp } from '../src/views/tui/terminal-app.js' import { createBraidTheme } from '../src/views/tui/theme.js' +import { interactionResponseRunCapabilities } from './support/run-capabilities.js' import { VirtualTerminal } from './support/virtual-terminal.js' const SIZES = [ @@ -132,7 +133,7 @@ function automationInteractionExecution(): { let release: (() => void) | undefined return { execution: { - capabilities: () => DEFAULT_RUN_CAPABILITIES, + capabilities: () => interactionResponseRunCapabilities(), async *streamTurn(input): AsyncIterable { yield { type: 'interaction', From 862ff070595300b0b5a235a73a206e77e3f73876 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sat, 15 Aug 2026 03:45:07 -0600 Subject: [PATCH 05/25] feat(interactions): preserve per-turn interaction posture Carry the selected mode and capability-derived interaction map through admission, receipts, retries, and retained turns. Keep provider-boundary tests active until the upstream Runtime and CLI Bridge releases forward the map. --- docs/04-runtime-contracts.md | 55 +++-- package.json | 8 +- pnpm-lock.yaml | 61 +++--- pnpm-workspace.yaml | 8 +- scripts/run-tests.mjs | 5 + .../runtime/agent-runtime-execution.ts | 1 + .../runtime/cli-bridge-retained-run.ts | 1 + .../runtime/retained-execution-state.ts | 1 + src/adapters/runtime/tangle-retained-run.ts | 14 +- src/app/application-support.ts | 6 + src/app/application.ts | 1 + src/app/conversation-import-runs.ts | 1 + src/app/run-admission-dispatch.ts | 2 + src/app/run-admission-receipt.ts | 13 +- src/app/run-admission-request.ts | 3 + src/app/run-execution-snapshot.ts | 3 + src/app/run-execution.ts | 2 + src/app/run-interactions.ts | 22 ++ src/domain/receipts.ts | 8 + src/domain/run-contracts.ts | 5 + src/index.ts | 1 + src/ports/execution.ts | 7 +- test/cli-bridge-interactions.test.ts | 67 ++++++ test/run-interactions.test.ts | 195 ++++++++++++++++++ test/scripts.test.ts | 5 + test/support/tangle-retained-sandbox.ts | 13 +- test/tangle-retained-lifecycle.test.ts | 22 +- 27 files changed, 469 insertions(+), 61 deletions(-) create mode 100644 src/app/run-interactions.ts create mode 100644 test/cli-bridge-interactions.test.ts create mode 100644 test/run-interactions.test.ts diff --git a/docs/04-runtime-contracts.md b/docs/04-runtime-contracts.md index c8a3e9c..2f9cd22 100644 --- a/docs/04-runtime-contracts.md +++ b/docs/04-runtime-contracts.md @@ -10,26 +10,26 @@ When a current package blocks a real Braid flow, Braid records the unavailable a ## Evidence baseline -The following published versions were queried from npm and their installed declarations were inspected directly on 2026-08-14. +The following published versions were queried from npm and their installed declarations and implementations were inspected directly on 2026-08-15. | Package | Installed version | Braid boundary | | --- | ---: | --- | -| [`@tangle-network/agent-interface`](https://github.com/tangle-network/agent-sdk/tree/main/packages/agent-interface) | `0.52.0` | Canonical profile, capabilities, environment, stream, portable context, and interaction contracts | -| [`@tangle-network/agent-runtime`](https://github.com/tangle-network/agent-runtime) | `0.134.4` | Sole execution layer; exact executor, retained-run, environment-provider, and terminal-monitor exports | +| [`@tangle-network/agent-interface`](https://github.com/tangle-network/agent-sdk/tree/main/packages/agent-interface) | `0.53.0` | Canonical profile, capabilities, environment, stream, portable context, and interaction contracts | +| [`@tangle-network/agent-runtime`](https://github.com/tangle-network/agent-runtime) | `0.135.0` | Sole execution layer; exact executor, retained-run, environment-provider, and terminal-monitor exports | | [`@tangle-network/agent-eval`](https://github.com/tangle-network/agent-eval) | `0.145.11` | Run records, judges, trace analysts, comparisons, and feedback trajectories | -| `@tangle-network/agent-provider-cli-bridge` | `0.7.1` | CLI Bridge environment adapter with live streaming, replay, retry-safe turns, retained control, and explicit cancel | -| `@tangle-network/agent-provider-tangle` | `0.10.0` | Tangle environment adapter over the sandbox client | +| `@tangle-network/agent-provider-cli-bridge` | `0.7.2` | CLI Bridge environment adapter with live streaming, replay, retry-safe turns, retained control, and explicit cancel | +| `@tangle-network/agent-provider-tangle` | `0.11.0` | Tangle environment adapter over the sandbox client | | `@tangle-network/sandbox` | `0.26.1` | Tangle cloud client used by the provider | The installed runtime publishes `agent-eval >=0.145.11 <0.146.0`, `agent-interface >=0.52.0 <0.53.0`, and `sandbox >=0.26.1 <0.27.0` as peer ranges. -Braid exercises runtime `0.134.4` with interface `0.52.0`, eval `0.145.11`, CLI Bridge adapter `0.7.1`, Tangle adapter `0.10.0`, and sandbox `0.26.1`. +Braid exercises runtime `0.135.0` with interface `0.53.0`, eval `0.145.11`, CLI Bridge adapter `0.7.2`, Tangle adapter `0.11.0`, and sandbox `0.26.1`. The lockfile pins the registry integrity for every installed package. -`pnpm peers check` reports no peer dependency issues for this package graph. +`pnpm peers check` reports that Runtime `0.135.0`, Knowledge `8.0.0`, and Profile Materialize `0.14.2` still peer `agent-interface <0.53.0`, while the current CLI Bridge and Tangle adapters require interface `0.53.0`. -The dependency graph resolves one `agent-interface` `0.52.0` instance without a workspace override. +The dependency graph resolves one `agent-interface` `0.53.0` instance without a workspace override. [Agent-runtime issue 803](https://github.com/tangle-network/agent-runtime/issues/803) records the interface peer mismatch fixed in Runtime `0.132.11`. @@ -47,9 +47,15 @@ Braid composes the current provider packages through `agent-runtime` and keeps a The CLI Bridge and Tangle providers remain transport implementations rather than alternate application shells. -The current interface exposes optional interaction-response methods, but neither installed provider declaration exposes that operation and the runtime turn API does not add one. +Interface `0.53.0` adds the requested interaction map to `AgentTurnInput` and the retained environment input. -Braid therefore renders interactions but disables response actions for those providers until a real run proves support. +The map is not a capability declaration. + +Braid derives it only after exact per-run environment capabilities are admitted, and sends an explicit empty map when response idempotency is absent or unknown. + +The current runtime and installed provider implementations do not preserve that field through the retained dispatch boundary. + +Braid therefore keeps the retained interactive path unverified until Runtime and the provider adapters forward the field end to end. At implementation start and before every release, rerun `npm view @tangle-network/ version` and inspect the installed declarations because these packages change frequently. @@ -118,6 +124,10 @@ Method presence remains a second defensive check because a false capability must `streamAgentTurn` accepts only a Runtime-owned executor paired with one exact `AgentProfile`. +Its published `0.135.0` API does not accept a per-turn interaction posture. + +Braid therefore does not claim interaction delivery for the ephemeral `AgentRuntimeExecutionPort` path. + It normalizes the terminal result into `RuntimeStreamEvent` and guarantees one final event. The current runtime event union includes lifecycle, text delta, reasoning delta, tool call, tool result, LLM call, artifact, proposal, error, and final events. @@ -313,7 +323,7 @@ These behaviors may be suitable for isolated benchmark automation under an expli ## Existing CLI Bridge provider contract -The published `@tangle-network/agent-provider-cli-bridge@0.6.0` resolves the bridge model from a turn override, provider default, or profile harness and model. +The published `@tangle-network/agent-provider-cli-bridge@0.7.2` resolves the bridge model from a turn override, provider default, or profile harness and model. It sends stable `executionId` values as bridge run identifiers when they satisfy the bridge identifier rules. @@ -329,11 +339,17 @@ Stopping a retained stream reader detaches the reader without cancelling the bri Explicit exact cancellation remains separate from reader detach and binds to the server-issued request digest. +Its public turn type accepts requested interactions through Interface `0.53.0`. + +Its published `toChatCompletionsBody` implementation does not copy `turn.interactions` into the bridge request. + +The Braid retained CLI Bridge boundary test catches this loss at the HTTP provider boundary. + It exposes no generalized interaction response. ## Existing Tangle provider contract -The published `@tangle-network/agent-provider-tangle@0.6.3` wraps `@tangle-network/sandbox` as an `AgentEnvironmentProvider`. +The published `@tangle-network/agent-provider-tangle@0.11.0` wraps `@tangle-network/sandbox` as an `AgentEnvironmentProvider`. Its default document is an upper bound, not a claim about one client or deployment. @@ -355,6 +371,12 @@ It requires an inline profile rather than a profile reference. It currently exposes no generalized interaction response through the environment or session adapter. +The Braid retained Tangle adapter supplies the requested map to Runtime's retained turn input. + +Runtime `0.135.0` drops that field in its retained-turn copier before the Tangle provider receives it. + +The Braid retained Tangle boundary test catches this loss at the provider dispatch boundary. + Its capability claims must still be proven against a real current Tangle deployment because a TypeScript adapter cannot prove server support or deployment policy. ## Current usage and execution observation contract @@ -423,10 +445,19 @@ The following upstream issues own missing shared contracts: - [Sandbox issue 5277](https://github.com/tangle-network/agent-dev-container/issues/5277) requires valid Sandbox keys to authorize internal model-key provisioning. - [Sandbox issue 5278](https://github.com/tangle-network/agent-dev-container/issues/5278) requires the npm `latest` tag to satisfy current Runtime peers. - [Runtime issue 808](https://github.com/tangle-network/agent-runtime/issues/808) requires permanent provisioning rejections to fail without the ten-minute retry. + - [Runtime issue 763](https://github.com/tangle-network/agent-runtime/issues/763) requests one stable execution tree with complete usage provenance. - [Agent SDK issue 136](https://github.com/tangle-network/agent-sdk/issues/136) requests normalized provider observations and account usage. - [Sandbox issue 5076](https://github.com/tangle-network/agent-dev-container/issues/5076) requests resolved placement, effective resources, and per-sandbox billing. +The current interaction work has three additional published-package blockers. + +- Runtime `0.135.0` must preserve `AgentTurnInput.interactions` in its retained-turn copier. +- CLI Bridge `0.7.2` must forward `turn.interactions` into its chat-completions request. +- The Runtime, Knowledge, and Profile Materialize peer cohort must accept Interface `0.53.0`. + +Braid does not cast around these gaps or duplicate provider dispatch. + ## Existing `agent-eval` contract `defineAgentEval` records the scenario, agent, judge, execution result, evidence, score, and cost for each run. diff --git a/package.json b/package.json index 5e01e4d..29bf38a 100644 --- a/package.json +++ b/package.json @@ -100,10 +100,10 @@ "@earendil-works/pi-tui": "0.84.2", "@napi-rs/keyring": "1.3.0", "@tangle-network/agent-eval": "0.145.11", - "@tangle-network/agent-interface": "0.52.0", - "@tangle-network/agent-provider-cli-bridge": "0.7.1", - "@tangle-network/agent-provider-tangle": "0.10.0", - "@tangle-network/agent-runtime": "0.134.9", + "@tangle-network/agent-interface": "0.53.0", + "@tangle-network/agent-provider-cli-bridge": "0.7.2", + "@tangle-network/agent-provider-tangle": "0.11.0", + "@tangle-network/agent-runtime": "0.135.0", "@tangle-network/sandbox": "0.26.1", "better-sqlite3-multiple-ciphers": "13.0.3", "chalk": "6.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 36bd4d7..45ebb80 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,17 +25,17 @@ importers: specifier: 0.145.11 version: 0.145.11 '@tangle-network/agent-interface': - specifier: 0.52.0 - version: 0.52.0 + specifier: 0.53.0 + version: 0.53.0 '@tangle-network/agent-provider-cli-bridge': - specifier: 0.7.1 - version: 0.7.1 + specifier: 0.7.2 + version: 0.7.2 '@tangle-network/agent-provider-tangle': - specifier: 0.10.0 - version: 0.10.0(@tangle-network/sandbox@0.26.1) + specifier: 0.11.0 + version: 0.11.0(@tangle-network/sandbox@0.26.1) '@tangle-network/agent-runtime': - specifier: 0.134.9 - version: 0.134.9(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)(@tangle-network/sandbox@0.26.1) + specifier: 0.135.0 + version: 0.135.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.53.0)(@tangle-network/sandbox@0.26.1) '@tangle-network/sandbox': specifier: 0.26.1 version: 0.26.1 @@ -514,6 +514,9 @@ packages: '@tangle-network/agent-interface@0.52.0': resolution: {integrity: sha512-jISw0y/VqQxeyuI7N5zsEb2+AMAYoIkPCtDVbWwZ9n2KL45rur//0ih72xPo3M+fiE0eUj9weTAYg4mzZckiHg==} + '@tangle-network/agent-interface@0.53.0': + resolution: {integrity: sha512-XWH+4t9vPkVog9C9P+094USuoO//TJwaI+P6ntAm32wHqZ/kh5a9r6kSkHYMKsXgQjkY3IA5NO21w3rZ7M6U+g==} + '@tangle-network/agent-knowledge@8.0.0': resolution: {integrity: sha512-29so4fdP/pp7rKzXgnJFmwyvD9HNpA+FxlraxSQuq4jFKMpSePop1AXMLrHEerP7W1Z8Jq4vrKrp7cFy8y7Xnw==} engines: {node: '>=20.19.0'} @@ -527,16 +530,16 @@ packages: peerDependencies: '@tangle-network/agent-interface': '>=0.47.0 <0.53.0' - '@tangle-network/agent-provider-cli-bridge@0.7.1': - resolution: {integrity: sha512-pjZDdm5bs5TaBFXdLJeRkueI4oUPyA1M/CuICAO/SIOT4aZTD1Fv2V/S5lmZDmUEfy3h0ezAabwsPfsVj3jAQQ==} + '@tangle-network/agent-provider-cli-bridge@0.7.2': + resolution: {integrity: sha512-0gVoVXtmYt2P3j/PhDpDy3V0GI7W0MgnTpH1EnnLC29PxnnGobIrPjLM5QMH2YtMWxCWF2+xN/KXTkVb06IPyA==} - '@tangle-network/agent-provider-tangle@0.10.0': - resolution: {integrity: sha512-rMQ3hIVo2CKUtKJg9b5zlMXbcGv+bI9ywcOKoNqJLymHbCa8aHhT/TQu02ztppPC/2vNLXLNRU4qyDqM+k0crA==} + '@tangle-network/agent-provider-tangle@0.11.0': + resolution: {integrity: sha512-Q1Rdy6gyY8XVNqGFq6lckoui3ekfFqhJr8lTz943F40/+Su0ThoeTwEuHYy5S0Jwqg5bXpYIn7pZytQbG5MKzA==} peerDependencies: '@tangle-network/sandbox': '>=0.23.0 <1.0.0' - '@tangle-network/agent-runtime@0.134.9': - resolution: {integrity: sha512-ZtBzAl25zZQiSZMahEM59jRNCjcvimUpUWc2r+wR8c+hB1m5kaftw7tqy0lvWkZ1peL5I4D/1DNyVBmwY+0i8Q==} + '@tangle-network/agent-runtime@0.135.0': + resolution: {integrity: sha512-koyqFnpTDIl3+PnWtcW/7b2qkjnYLEH848qYVCy6jaN5YIztmsBk45SolZ2u7scb5AU8brDw93PL2cJHCbUo7Q==} engines: {node: '>=22.13.0'} hasBin: true peerDependencies: @@ -1159,34 +1162,40 @@ snapshots: spdx-expression-parse: 5.0.0 zod: 4.4.3 - '@tangle-network/agent-knowledge@8.0.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)': + '@tangle-network/agent-interface@0.53.0': + dependencies: + '@noble/hashes': 1.8.0 + spdx-expression-parse: 5.0.0 + zod: 4.4.3 + + '@tangle-network/agent-knowledge@8.0.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.53.0)': dependencies: '@tangle-network/agent-eval': 0.145.11 - '@tangle-network/agent-interface': 0.52.0 + '@tangle-network/agent-interface': 0.53.0 proper-lockfile: 4.1.2 zod: 4.4.3 - '@tangle-network/agent-profile-materialize@0.14.2(@tangle-network/agent-interface@0.52.0)': + '@tangle-network/agent-profile-materialize@0.14.2(@tangle-network/agent-interface@0.53.0)': dependencies: - '@tangle-network/agent-interface': 0.52.0 + '@tangle-network/agent-interface': 0.53.0 - '@tangle-network/agent-provider-cli-bridge@0.7.1': + '@tangle-network/agent-provider-cli-bridge@0.7.2': dependencies: - '@tangle-network/agent-interface': 0.52.0 + '@tangle-network/agent-interface': 0.53.0 undici: 7.29.0 - '@tangle-network/agent-provider-tangle@0.10.0(@tangle-network/sandbox@0.26.1)': + '@tangle-network/agent-provider-tangle@0.11.0(@tangle-network/sandbox@0.26.1)': dependencies: - '@tangle-network/agent-interface': 0.52.0 + '@tangle-network/agent-interface': 0.53.0 '@tangle-network/sandbox': 0.26.1 - '@tangle-network/agent-runtime@0.134.9(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0)(@tangle-network/sandbox@0.26.1)': + '@tangle-network/agent-runtime@0.135.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.53.0)(@tangle-network/sandbox@0.26.1)': dependencies: '@tangle-network/agent-core': 0.8.0 '@tangle-network/agent-eval': 0.145.11 - '@tangle-network/agent-interface': 0.52.0 - '@tangle-network/agent-knowledge': 8.0.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.52.0) - '@tangle-network/agent-profile-materialize': 0.14.2(@tangle-network/agent-interface@0.52.0) + '@tangle-network/agent-interface': 0.53.0 + '@tangle-network/agent-knowledge': 8.0.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.53.0) + '@tangle-network/agent-profile-materialize': 0.14.2(@tangle-network/agent-interface@0.53.0) '@tangle-network/agent-trace-contract': 1.0.2 tar-stream: 3.2.0 optionalDependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2cde334..fcd5f85 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,13 +9,13 @@ allowBuilds: node-pty: true ignoreScripts: false minimumReleaseAgeExclude: - - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5 || 0.134.9' + - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5 || 0.134.9 || 0.135.0' - '@tangle-network/agent-eval@0.143.0 || 0.144.0 || 0.144.1 || 0.144.3 || 0.144.4 || 0.144.6 || 0.144.8 || 0.144.10 || 0.144.11 || 0.144.13 || 0.145.0 || 0.145.1 || 0.145.2 || 0.145.3 || 0.145.9 || 0.145.10 || 0.145.11' - - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0' + - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0 || 0.53.0' - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0' - '@tangle-network/agent-profile-materialize@0.10.2 || 0.13.1 || 0.14.0 || 0.14.2' - - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1' - - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0' + - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2' + - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0 || 0.11.0' - '@tangle-network/sandbox@0.17.3 || 0.18.0 || 0.19.2 || 0.19.3 || 0.19.4 || 0.19.5 || 0.19.6 || 0.21.0 || 0.21.1 || 0.26.1' - hono@4.13.0 - '@esbuild/aix-ppc64@0.28.2' diff --git a/scripts/run-tests.mjs b/scripts/run-tests.mjs index 10d6123..c2c882b 100644 --- a/scripts/run-tests.mjs +++ b/scripts/run-tests.mjs @@ -62,6 +62,7 @@ const scopeFiles = { 'analysis-model-call-observability.test.js', 'analysis-model-call-roundtrip.test.js', 'application.test.js', + 'cli-bridge-interactions.test.js', 'cli-bridge-profile-contract.test.js', 'cli-bridge-retained-restart.test.js', 'conversations.test.js', @@ -71,15 +72,19 @@ const scopeFiles = { 'observability.test.js', 'reducer.test.js', 'scripts.test.js', + 'tangle-retained-lifecycle.test.js', 'usage-projection.test.js', 'w6-contract.test.js', ], coordination: [ 'analysis-durable.test.js', + 'cli-bridge-interactions.test.js', 'cli-bridge-retained-restart.test.js', 'coordination.test.js', 'effect-admission.test.js', 'run-admission-architecture.test.js', + 'run-interactions.test.js', + 'tangle-retained-lifecycle.test.js', ], rpc: [ 'automation-interaction-commands.test.js', diff --git a/src/adapters/runtime/agent-runtime-execution.ts b/src/adapters/runtime/agent-runtime-execution.ts index 70eb10c..7217f9f 100644 --- a/src/adapters/runtime/agent-runtime-execution.ts +++ b/src/adapters/runtime/agent-runtime-execution.ts @@ -360,6 +360,7 @@ function admissionKey(input: ExecuteTurnInput, profileDigest: string): string { text: input.text, profileDigest, connectionId: input.connectionId ?? null, + mode: input.mode ?? null, sessionId: input.sessionId ?? null, contextBoundary: input.contextBoundary ?? null, }) diff --git a/src/adapters/runtime/cli-bridge-retained-run.ts b/src/adapters/runtime/cli-bridge-retained-run.ts index aebb93e..e10f6cd 100644 --- a/src/adapters/runtime/cli-bridge-retained-run.ts +++ b/src/adapters/runtime/cli-bridge-retained-run.ts @@ -109,6 +109,7 @@ export async function startCliBridgeRetainedRun( turn: { prompt: input.text, turnId: safeExecutionId(input.operationId), + interactions: input.interactions ?? {}, signal: input.signal, }, identity: { diff --git a/src/adapters/runtime/retained-execution-state.ts b/src/adapters/runtime/retained-execution-state.ts index 0f0bfe0..5a8b291 100644 --- a/src/adapters/runtime/retained-execution-state.ts +++ b/src/adapters/runtime/retained-execution-state.ts @@ -17,6 +17,7 @@ export function retainedExecutionKey(input: ExecuteTurnInput): string { text: input.text, profile: canonicalAgentProfileDigestHex(input.profile), connectionId: input.connectionId ?? null, + mode: input.mode ?? null, workspaceRoot: input.workspaceRoot ?? null, sessionId: input.sessionId ?? null, contextBoundary: input.contextBoundary ?? null, diff --git a/src/adapters/runtime/tangle-retained-run.ts b/src/adapters/runtime/tangle-retained-run.ts index 1f43a6a..5fce744 100644 --- a/src/adapters/runtime/tangle-retained-run.ts +++ b/src/adapters/runtime/tangle-retained-run.ts @@ -8,8 +8,8 @@ import { import { publicMaterializationReceipt } from '../../domain/materialization-receipt.js' import type { RuntimeEventEnvelope } from '../../domain/runtime-events.js' import type { ExecuteTurnInput } from '../../ports/execution.js' -import type { PreparedTangleRetainedConnection } from './production-tangle-sandbox-backend.js' import { safeExecutionId } from './production-backend-common.js' +import type { PreparedTangleRetainedConnection } from './production-tangle-sandbox-backend.js' import type { RetainedExecutionPlan, RetainedResultProjection, @@ -92,6 +92,12 @@ export async function startTangleRetainedRun( } // A retained create may return an existing environment for the same key. // Do not destroy it after an ambiguous dispatch failure without a provider-issued creation receipt. + const turn = { + prompt: input.text, + turnId: safeExecutionId(input.operationId), + interactions: input.interactions ?? {}, + signal: input.signal, + } return startRetainedRun({ provider: plan.provider, environment: { @@ -101,11 +107,7 @@ export async function startTangleRetainedRun( metadata: plan.prepared.environmentMetadata, idempotencyKey: plan.prepared.environmentIdempotencyKey, }, - turn: { - prompt: input.text, - turnId: safeExecutionId(input.operationId), - signal: input.signal, - }, + turn, identity: { sessionId: plan.prepared.providerSessionId, executionId: plan.executionId, diff --git a/src/app/application-support.ts b/src/app/application-support.ts index 5483772..40669e5 100644 --- a/src/app/application-support.ts +++ b/src/app/application-support.ts @@ -164,6 +164,12 @@ export function restoreApplicationOperations( text: event.text, profile: event.receipt.requested.profile, connectionId: event.receipt.requested.connectionId ?? null, + ...(event.receipt.requested.mode === undefined + ? {} + : { mode: event.receipt.requested.mode }), + ...(event.receipt.requested.interactions === undefined + ? {} + : { interactions: event.receipt.requested.interactions }), }), runId: run.id, admission: event.receipt, diff --git a/src/app/application.ts b/src/app/application.ts index 3b80400..d7f921c 100644 --- a/src/app/application.ts +++ b/src/app/application.ts @@ -393,6 +393,7 @@ export class BraidApplication { this.#state, configuration.profile, configuration.connectionId, + configuration.mode, ) validateNativeProof(this.#portViews.admission, snapshot) if (this.#asynchronousJournal || admissionIsAsync(this.#execution)) { diff --git a/src/app/conversation-import-runs.ts b/src/app/conversation-import-runs.ts index ab90459..80893bb 100644 --- a/src/app/conversation-import-runs.ts +++ b/src/app/conversation-import-runs.ts @@ -249,6 +249,7 @@ function importReceipt( branchId: input.branchId, admittedAt: canonicalDateTime(receipt.admittedAt, `${input.label}.admittedAt`), profile, + ...(typeof requested.mode === 'string' ? { mode: requested.mode } : {}), text: stringValue(requested.text, `${input.label}.requested.text`), capabilities: UNKNOWN_RUN_CAPABILITIES, warnings: ['IMPORTED_OFFLINE'], diff --git a/src/app/run-admission-dispatch.ts b/src/app/run-admission-dispatch.ts index b361599..4676cfa 100644 --- a/src/app/run-admission-dispatch.ts +++ b/src/app/run-admission-dispatch.ts @@ -43,6 +43,7 @@ export function sendRun(context: AdmissionPort, input: RunExecutionSnapshot): Se runId, text: input.text, profile: input.profile, + ...(input.mode === undefined ? {} : { mode: input.mode }), ...(input.connectionId === undefined ? {} : { connectionId: input.connectionId }), ...(input.workspaceRoot === undefined ? {} : { workspaceRoot: input.workspaceRoot }), signal: new AbortController().signal, @@ -128,6 +129,7 @@ export async function sendRunAsync( runId: ids.runId, text: input.text, profile: input.profile, + ...(input.mode === undefined ? {} : { mode: input.mode }), ...(input.connectionId === undefined ? {} : { connectionId: input.connectionId }), ...(input.workspaceRoot === undefined ? {} : { workspaceRoot: input.workspaceRoot }), signal, diff --git a/src/app/run-admission-receipt.ts b/src/app/run-admission-receipt.ts index 2eb64b4..ae94228 100644 --- a/src/app/run-admission-receipt.ts +++ b/src/app/run-admission-receipt.ts @@ -1,14 +1,13 @@ -import { createAdmissionReceipt } from '../domain/receipts.js' import type { ContextTransferReceipt, NativeContextBoundaryProof, PortableContextPlan, RunAdmissionReceipt, } from '../domain/receipts.js' +import { createAdmissionReceipt } from '../domain/receipts.js' import type { ExecuteTurnInput } from '../ports/execution.js' import { UNKNOWN_RUN_CAPABILITIES } from '../ports/execution.js' import type { AdmissionPort, AsyncAdmissionPort } from './application-ports.js' -import type { RunExecutionSnapshot } from './run-execution-snapshot.js' import { exactAdmissionRequestDigest } from './run-admission-request.js' import { admissionProfileDigest, @@ -20,6 +19,8 @@ import { validateExecutionContext, validateProfile, } from './run-admission-validation.js' +import type { RunExecutionSnapshot } from './run-execution-snapshot.js' +import { requestedInteractionsForRun } from './run-interactions.js' export function admitRun( context: AdmissionPort, @@ -37,6 +38,7 @@ export function admitRun( const resolved = rawAdmission ?? {} validateExecutionContext(context.currentState(), input, resolved) const capabilities = resolved.capabilities ?? resolveSyncCapabilities(context, input) + const interactions = requestedInteractionsForRun(input.mode, capabilities) const receipt = createAdmissionReceipt({ runId: input.runId, turnId: turnId ?? context.ids.next('receipt'), @@ -46,6 +48,8 @@ export function admitRun( admittedAt: context.clock.now(), profile: input.profile, ...(input.connectionId === undefined ? {} : { connectionId: input.connectionId }), + ...(input.mode === undefined ? {} : { mode: input.mode }), + interactions, text: input.text, ...(input.sessionId === undefined ? {} : { sessionId: input.sessionId }), capabilities, @@ -86,6 +90,7 @@ export async function admitRunAsync( const resolved = await resolveAsyncAdmission(context, input) validateExecutionContext(context.currentState(), input, resolved) const capabilities = resolved?.capabilities ?? (await resolveAsyncCapabilities(context, input)) + const interactions = requestedInteractionsForRun(input.mode, capabilities) const receipt = createAdmissionReceipt({ runId: input.runId, turnId: turnId ?? context.ids.next('receipt'), @@ -95,6 +100,8 @@ export async function admitRunAsync( admittedAt: context.clock.now(), profile: input.profile, ...(input.connectionId === undefined ? {} : { connectionId: input.connectionId }), + ...(input.mode === undefined ? {} : { mode: input.mode }), + interactions, text: input.text, ...(input.sessionId === undefined ? {} : { sessionId: input.sessionId }), capabilities, @@ -135,6 +142,8 @@ export function pendingAdmissionReceipt( admittedAt: new Date(0).toISOString(), profile: input.profile, ...(input.connectionId === undefined ? {} : { connectionId: input.connectionId }), + ...(input.mode === undefined ? {} : { mode: input.mode }), + interactions: {}, text: input.text, capabilities: UNKNOWN_RUN_CAPABILITIES, admissionStatus: 'pending', diff --git a/src/app/run-admission-request.ts b/src/app/run-admission-request.ts index 84f71ff..a7e53d7 100644 --- a/src/app/run-admission-request.ts +++ b/src/app/run-admission-request.ts @@ -13,6 +13,7 @@ export function runEffectRequest(input: RunExecutionSnapshot): Readonly + readonly mode?: string readonly connectionId?: string readonly workspaceRoot?: string readonly sessionId?: string @@ -36,6 +37,7 @@ export function snapshotRunExecution( state: BraidState, profile: Readonly, connectionId: string | undefined, + mode?: string, ): RunExecutionSnapshot { const snapshot = { operationId: input.operationId, @@ -43,6 +45,7 @@ export function snapshotRunExecution( conversationId: input.conversationId ?? state.conversationId, branchId: input.branchId ?? state.branchId, profile: snapshotAgentProfile(profile), + ...(mode === undefined ? {} : { mode }), ...(connectionId === undefined ? {} : { connectionId }), ...(state.workspace === null ? {} : { workspaceRoot: state.workspace }), ...(input.sessionId === undefined diff --git a/src/app/run-execution.ts b/src/app/run-execution.ts index 59b7b16..c576271 100644 --- a/src/app/run-execution.ts +++ b/src/app/run-execution.ts @@ -22,6 +22,8 @@ export async function executeRun( runId: admission.runId, text: input.text, profile: input.profile, + ...(input.mode === undefined ? {} : { mode: input.mode }), + interactions: admission.requested.interactions ?? {}, ...(input.connectionId === undefined ? {} : { connectionId: input.connectionId }), ...(input.workspaceRoot === undefined ? {} : { workspaceRoot: input.workspaceRoot }), signal: abort.signal, diff --git a/src/app/run-interactions.ts b/src/app/run-interactions.ts new file mode 100644 index 0000000..65ee27f --- /dev/null +++ b/src/app/run-interactions.ts @@ -0,0 +1,22 @@ +import type { RequestedInteractions, RunCapabilities } from '../domain/run-contracts.js' + +/** + * Select the interaction posture for one admitted turn. + * + * The provider capability document is the only authority. A response is + * enabled only when the provider records idempotent responses for retries. + */ +export function requestedInteractionsForRun( + mode: string | undefined, + capabilities: Pick, +): RequestedInteractions { + const advertised = capabilities.environment?.interactions + if (advertised?.responseIdempotency !== true) return Object.freeze({}) + + const requested: RequestedInteractions = { + ...(advertised.kinds.includes('permission') ? { permission: true } : {}), + ...(advertised.kinds.includes('question') ? { question: true } : {}), + ...(mode === 'plan' && advertised.kinds.includes('plan') ? { plan: true } : {}), + } + return Object.freeze(requested) +} diff --git a/src/domain/receipts.ts b/src/domain/receipts.ts index 84e0bc3..54c4633 100644 --- a/src/domain/receipts.ts +++ b/src/domain/receipts.ts @@ -12,6 +12,7 @@ import type { PortableAnalysisAttachment, PortableContextMessage, PortableContextPlan, + RequestedInteractions, RunAdmissionReceipt, RunCapabilities, } from './run-contracts.js' @@ -23,6 +24,7 @@ export type { PortableContextMessage, PortableContextPart, PortableContextPlan, + RequestedInteractions, RunAdmissionReceipt, RunCapabilities, RunControlCapabilities, @@ -120,6 +122,8 @@ export function createAdmissionReceipt(input: { readonly admittedAt: string readonly profile: Readonly readonly connectionId?: string + readonly mode?: string + readonly interactions?: RequestedInteractions readonly text: string readonly sessionId?: string readonly capabilities: RunCapabilities @@ -153,6 +157,8 @@ export function createAdmissionReceipt(input: { text, profile: structuredClone(profile), ...(input.connectionId === undefined ? {} : { connectionId: input.connectionId }), + ...(input.mode === undefined ? {} : { mode: input.mode }), + ...(input.interactions === undefined ? {} : { interactions: input.interactions }), ...(profile.model?.default === undefined ? {} : { model: profile.model.default }), ...(profile.harness === undefined ? {} : { runner: profile.harness }), ...(contextPlanDigest === undefined ? {} : { contextPlanDigest }), @@ -166,6 +172,8 @@ export function createAdmissionReceipt(input: { text, profileDigest, connectionId: input.connectionId ?? null, + mode: input.mode ?? null, + interactions: input.interactions ?? {}, contextPlanDigest: contextPlanDigest ?? null, }) const capabilitiesDigest = canonicalDigest(capabilities) diff --git a/src/domain/run-contracts.ts b/src/domain/run-contracts.ts index eb30fb7..e1b484b 100644 --- a/src/domain/run-contracts.ts +++ b/src/domain/run-contracts.ts @@ -2,8 +2,11 @@ import type { AgentEnvironmentCapabilities, AgentExactRunControlRef, AgentProfile, + RequestedInteractions, } from '@tangle-network/agent-interface' +export type { RequestedInteractions } from '@tangle-network/agent-interface' + export interface RetainedRunEnvironmentAdmissionRecord { readonly phase: 'environment' readonly provider: string @@ -152,6 +155,8 @@ export interface RunAdmissionReceipt { readonly text: string readonly profile: Readonly readonly connectionId?: string + readonly mode?: string + readonly interactions?: RequestedInteractions readonly model?: string readonly runner?: string readonly contextPlanDigest?: string diff --git a/src/index.ts b/src/index.ts index 7369d09..11687ea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -130,6 +130,7 @@ export { createPortableContextPlan, type NativeContextBoundaryProof, type PortableContextPlan, + type RequestedInteractions, type RunAdmissionReceipt, type RunCapabilities, } from './domain/receipts.js' diff --git a/src/ports/execution.ts b/src/ports/execution.ts index feb1c46..304980f 100644 --- a/src/ports/execution.ts +++ b/src/ports/execution.ts @@ -6,6 +6,7 @@ import type { } from '@tangle-network/agent-interface' import type { TurnUsage } from '../domain/entities.js' import type { + RequestedInteractions, RetainedRunAdmissionRecord, RetainedRunAdmissionRecorder, RunCapabilities, @@ -13,13 +14,17 @@ import type { import type { BraidRuntimeEvent, RuntimeEventEnvelope } from '../domain/runtime-events.js' import type { RunStatus } from '../domain/state.js' -export type { RunCapabilities } from '../domain/receipts.js' +export type { RequestedInteractions, RunCapabilities } from '../domain/receipts.js' export interface ExecuteTurnInput { readonly operationId: string readonly runId: string readonly text: string readonly profile: Readonly + /** Selected branch mode captured before admission. */ + readonly mode?: string + /** Exact per-turn interaction posture derived from admitted capabilities. */ + readonly interactions?: RequestedInteractions readonly connectionId?: string readonly workspaceRoot?: string readonly signal: AbortSignal diff --git a/test/cli-bridge-interactions.test.ts b/test/cli-bridge-interactions.test.ts new file mode 100644 index 0000000..273f4e9 --- /dev/null +++ b/test/cli-bridge-interactions.test.ts @@ -0,0 +1,67 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { defineAgentProfile } from '@tangle-network/agent-interface' +import { + createCliBridgeRetainedPlan, + startCliBridgeRetainedRun, +} from '../src/adapters/runtime/cli-bridge-retained-run.js' +import { prepareCliBridgeConnection } from '../src/adapters/runtime/production-cli-bridge-backend.js' +import { ConnectionRegistry } from '../src/app/connections.js' +import type { ConnectionRecord } from '../src/domain/entities.js' +import { createConnectionId } from '../src/domain/ids.js' +import type { ExecuteTurnInput, RetainedRunAdmissionRecord } from '../src/ports/execution.js' +import { startRuntimeBridgeServer } from './support/runtime-bridge-server.js' + +const createdAt = '2026-08-15T00:00:00.000Z' + +test('retained CLI Bridge receives the exact admitted interaction map', async () => { + const bridge = await startRuntimeBridgeServer({ responseText: 'CLI_BRIDGE_INTERACTION_OK' }) + const connection: ConnectionRecord = { + id: createConnectionId('connection-cli-interactions'), + kind: 'cli-bridge', + name: 'CLI Bridge interaction test', + endpoint: bridge.endpoint, + providerOptions: { transport: 'local' }, + createdAt, + updatedAt: createdAt, + lastHealth: { status: 'unknown' }, + } + const profile = defineAgentProfile({ + name: 'CLI Bridge interaction test', + harness: 'pi', + model: { provider: 'openai', default: 'openai/gpt-5' }, + }) + const input: ExecuteTurnInput = { + operationId: 'operation-cli-interactions', + runId: 'run-cli-interactions', + text: 'Continue with the approved interaction posture.', + profile, + connectionId: connection.id, + workspaceRoot: '/workspace', + signal: new AbortController().signal, + interactions: Object.freeze({ permission: true, question: true, plan: true }), + onRetainedAdmission: async (_admission: RetainedRunAdmissionRecord) => {}, + } + const options = { + connections: new ConnectionRegistry([connection]), + workspaceCwd: '/workspace', + select: () => ({ connection: { connectionId: connection.id } }), + } + + try { + const prepared = await prepareCliBridgeConnection( + options, + input, + { connection: { connectionId: connection.id } }, + connection.id, + bridge.endpoint, + ) + const plan = await createCliBridgeRetainedPlan(prepared, input.runId) + await startCliBridgeRetainedRun(plan, input) + + assert.equal(bridge.requests.length, 1) + assert.deepEqual(bridge.requests[0]?.body.interactions, input.interactions) + } finally { + await bridge.close() + } +}) diff --git a/test/run-interactions.test.ts b/test/run-interactions.test.ts new file mode 100644 index 0000000..5ce08cb --- /dev/null +++ b/test/run-interactions.test.ts @@ -0,0 +1,195 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { defineAgentProfile } from '@tangle-network/agent-interface' +import { defaultTangleSandboxCapabilities } from '@tangle-network/agent-provider-tangle' +import { retainedExecutionKey } from '../src/adapters/runtime/retained-execution-state.js' +import { createBraidApplication } from '../src/app/composition.js' +import { MemoryJournal } from '../src/app/journal.js' +import { runEffectRequest } from '../src/app/run-admission-request.js' +import { snapshotRunExecution } from '../src/app/run-execution-snapshot.js' +import { requestedInteractionsForRun } from '../src/app/run-interactions.js' +import { canonicalDigest } from '../src/domain/canonical.js' +import { createAdmissionReceipt } from '../src/domain/receipts.js' +import type { BraidRuntimeEvent } from '../src/domain/runtime-events.js' +import { initialState } from '../src/domain/state.js' +import { FixedClock } from '../src/ports/clock.js' +import { + DEFAULT_RUN_CAPABILITIES, + type ExecuteTurnInput, + type ExecutionPort, + type RunCapabilities, +} from '../src/ports/execution.js' + +const PROFILE = defineAgentProfile({ + name: 'Per-turn interaction test', + harness: 'opencode', + model: { default: 'fixture/interaction-test' }, +}) + +function capabilitiesFor(kinds: readonly string[], responseIdempotency = true): RunCapabilities { + const environment = defaultTangleSandboxCapabilities('opencode') + assert.ok(environment.interactions) + return { + ...DEFAULT_RUN_CAPABILITIES, + environment: { + ...environment, + interactions: { + ...environment.interactions, + kinds: [...kinds], + responseIdempotency, + }, + }, + } +} + +async function dispatchedInput( + mode: string | undefined, + capabilities: RunCapabilities, +): Promise { + let received: ExecuteTurnInput | undefined + const execution: ExecutionPort = { + admit: () => ({ capabilities }), + async *streamTurn(input): AsyncIterable { + received = input + yield { + type: 'final', + task: { id: input.runId, intent: 'interaction wiring test' }, + status: 'completed', + reason: 'completed', + text: 'done', + metadata: { tokenUsage: { input: 1, output: 1 } }, + timestamp: '2026-08-15T00:00:00.000Z', + } + }, + } + const clock = new FixedClock() + const journal = new MemoryJournal(clock) + const app = createBraidApplication({ + profile: PROFILE, + execution, + clock, + journal, + effectStorage: journal, + }) + app.initialize('/workspace') + if (mode !== undefined) { + await app.conversations.branches.setRunOverrides({ + operationId: `operation-mode-${mode}`, + mode, + }) + } + const receipt = app.send({ operationId: `operation-${mode ?? 'normal'}`, text: 'continue' }) + await receipt.completion + assert.ok(received) + return received +} + +test('selected mode survives the snapshot, effect request, receipt, and retry identity', () => { + const state = { ...initialState(PROFILE), workspace: '/workspace' } + const snapshot = snapshotRunExecution( + { operationId: 'operation-mode', text: 'review the plan' }, + state, + PROFILE, + undefined, + 'plan', + ) + assert.equal(snapshot.mode, 'plan') + assert.equal(runEffectRequest(snapshot).mode, 'plan') + + const receipt = createAdmissionReceipt({ + runId: 'run-mode', + turnId: 'turn-mode', + operationId: snapshot.operationId, + conversationId: snapshot.conversationId, + branchId: snapshot.branchId, + admittedAt: '2026-08-15T00:00:00.000Z', + profile: snapshot.profile, + text: snapshot.text, + mode: snapshot.mode, + interactions: { plan: true }, + capabilities: DEFAULT_RUN_CAPABILITIES, + }) + assert.equal(receipt.requested.mode, 'plan') + assert.deepEqual(receipt.requested.interactions, { plan: true }) + + const base: ExecuteTurnInput = { + operationId: 'operation-retry', + runId: 'run-retry', + text: 'retry this', + profile: PROFILE, + signal: new AbortController().signal, + } + assert.notEqual( + retainedExecutionKey({ ...base, mode: 'normal' }), + retainedExecutionKey({ ...base, mode: 'plan' }), + ) + assert.equal( + receipt.requestDigest, + canonicalDigest({ + runId: 'run-mode', + turnId: 'turn-mode', + operationId: snapshot.operationId, + conversationId: snapshot.conversationId, + branchId: snapshot.branchId, + text: snapshot.text, + profileDigest: receipt.profileDigest, + connectionId: null, + mode: 'plan', + interactions: { plan: true }, + contextPlanDigest: null, + }), + ) +}) + +test('normal mode requests advertised permission and question kinds, never plan', async () => { + const advertised = capabilitiesFor(['permission', 'question', 'plan']).environment + assert.ok(advertised) + assert.deepEqual( + requestedInteractionsForRun(undefined, { + environment: advertised, + }), + { permission: true, question: true }, + ) + assert.deepEqual( + (await dispatchedInput(undefined, capabilitiesFor(['permission', 'question', 'plan']))) + .interactions, + { permission: true, question: true }, + ) +}) + +test('plan mode enables plan only when the admitted capability advertises it', async () => { + const advertised = capabilitiesFor(['permission', 'plan']).environment + assert.ok(advertised) + assert.deepEqual( + requestedInteractionsForRun('plan', { + environment: advertised, + }), + { permission: true, plan: true }, + ) + assert.deepEqual( + (await dispatchedInput('plan', capabilitiesFor(['permission', 'question']))).interactions, + { permission: true, question: true }, + ) +}) + +test('unsupported or non-idempotent response capability passes an explicit empty map', async () => { + const unsupported = requestedInteractionsForRun( + 'plan', + capabilitiesFor(['permission', 'question', 'plan'], false), + ) + assert.deepEqual(unsupported, {}) + assert.equal(Object.isFrozen(unsupported), true) + const received = await dispatchedInput('plan', { ...DEFAULT_RUN_CAPABILITIES }) + assert.deepEqual(received.interactions, {}) + assert.equal(Object.isFrozen(received.interactions), true) +}) + +test('the retained execution boundary receives the exact admitted map', async () => { + const expected = { permission: true, question: true, plan: true } + const received = await dispatchedInput( + 'plan', + capabilitiesFor(['permission', 'question', 'plan']), + ) + assert.deepEqual(received.interactions, expected) + assert.equal(Object.isFrozen(received.interactions), true) +}) diff --git a/test/scripts.test.ts b/test/scripts.test.ts index 4d4c7cf..7984721 100644 --- a/test/scripts.test.ts +++ b/test/scripts.test.ts @@ -204,6 +204,7 @@ test('every scoped package alias forwards its declared file set', () => { 'analysis-model-call-observability.test.js', 'analysis-model-call-roundtrip.test.js', 'application.test.js', + 'cli-bridge-interactions.test.js', 'cli-bridge-profile-contract.test.js', 'cli-bridge-retained-restart.test.js', 'conversations.test.js', @@ -213,15 +214,19 @@ test('every scoped package alias forwards its declared file set', () => { 'observability.test.js', 'reducer.test.js', 'scripts.test.js', + 'tangle-retained-lifecycle.test.js', 'usage-projection.test.js', 'w6-contract.test.js', ], 'test:coordination': [ 'analysis-durable.test.js', + 'cli-bridge-interactions.test.js', 'cli-bridge-retained-restart.test.js', 'coordination.test.js', 'effect-admission.test.js', 'run-admission-architecture.test.js', + 'run-interactions.test.js', + 'tangle-retained-lifecycle.test.js', ], 'test:rpc': [ 'automation-interaction-commands.test.js', diff --git a/test/support/tangle-retained-sandbox.ts b/test/support/tangle-retained-sandbox.ts index ce99ce9..f6df585 100644 --- a/test/support/tangle-retained-sandbox.ts +++ b/test/support/tangle-retained-sandbox.ts @@ -1,8 +1,9 @@ import type { - AgentRunCancellationAcknowledgement, - AgentRunCancellationRequest, AgentExactRunControlRef, AgentProfile, + AgentRunCancellationAcknowledgement, + AgentRunCancellationRequest, + RequestedInteractions, } from '@tangle-network/agent-interface' import { createTangleProvider, @@ -11,8 +12,8 @@ import { type SandboxInstanceLike, } from '@tangle-network/agent-provider-tangle' import type { CreateSandboxOptions, SandboxEvent } from '@tangle-network/sandbox' -import type { PreparedTangleRetainedConnection } from '../../src/adapters/runtime/production-tangle-sandbox-backend.js' import { safeExecutionId } from '../../src/adapters/runtime/production-backend-common.js' +import type { PreparedTangleRetainedConnection } from '../../src/adapters/runtime/production-tangle-sandbox-backend.js' import { observeSandboxClient } from '../../src/adapters/runtime/sandbox-observation.js' import { retainedSandboxIdentity, @@ -39,7 +40,7 @@ export interface FakeRetainedBox { deleted: boolean } -/** Stateful double for the exact Tangle SDK surface used by provider 0.10.0. */ +/** Stateful double for the exact Tangle SDK surface used by provider 0.11.0. */ export class FakeTangleRetainedSandbox { readonly createCalls: CreateSandboxOptions[] = [] readonly dispatches: Array<{ @@ -47,6 +48,7 @@ export class FakeTangleRetainedSandbox { readonly sessionId: string readonly executionId: string readonly prompt: string + readonly interactions?: RequestedInteractions }> = [] readonly cancellations: AgentRunCancellationRequest[] = [] failDispatch = false @@ -177,6 +179,9 @@ export class FakeTangleRetainedSandbox { sessionId, executionId, prompt: typeof message === 'string' ? message : JSON.stringify(message), + ...(options?.backend?.interactions === undefined + ? {} + : { interactions: structuredClone(options.backend.interactions) }), }) return { sessionId, diff --git a/test/tangle-retained-lifecycle.test.ts b/test/tangle-retained-lifecycle.test.ts index 48784d2..312cba9 100644 --- a/test/tangle-retained-lifecycle.test.ts +++ b/test/tangle-retained-lifecycle.test.ts @@ -1,18 +1,18 @@ import assert from 'node:assert/strict' import test from 'node:test' import { defineAgentProfile } from '@tangle-network/agent-interface' +import { capabilitiesForConnection } from '../src/adapters/connections/production-connection-providers.js' import { resolveTangleSandboxBackend, resolveTangleSandboxRetainedConnection, } from '../src/adapters/runtime/production-tangle-sandbox-backend.js' -import { capabilitiesForConnection } from '../src/adapters/connections/production-connection-providers.js' +import type { ObservableSandboxClient } from '../src/adapters/runtime/sandbox-observation-types.js' import { createTangleRetainedPlan, startTangleRetainedRun, } from '../src/adapters/runtime/tangle-retained-run.js' import { withRetainedSandboxPolicy } from '../src/adapters/runtime/tangle-sandbox-retention.js' import { ConnectionRegistry } from '../src/app/connections.js' -import type { ObservableSandboxClient } from '../src/adapters/runtime/sandbox-observation-types.js' import type { ConnectionRecord, ConnectionTransportOptions } from '../src/domain/entities.js' import { createConnectionId } from '../src/domain/ids.js' import { assertConnectionRecord } from '../src/domain/invariants-profile.js' @@ -304,6 +304,24 @@ test('one retained plan uses exact tags, bounded idle expiry, replay, and result ) }) +test('retained Tangle dispatch receives the exact requested interaction map', async () => { + const sandbox = new FakeTangleRetainedSandbox() + const { input } = setup(sandbox) + const prepared = await prepareFakeTangleRetainedConnection({ + sandbox, + profile, + runId: input.runId, + }) + const interactions = { permission: true, question: false, plan: true } as const + + await startTangleRetainedRun(createTangleRetainedPlan(prepared, input.runId), { + ...input, + interactions, + }) + + assert.deepEqual(sandbox.dispatches[0]?.interactions, interactions) +}) + test('ambiguous dispatch failure never deletes the retained environment', async () => { const sandbox = new FakeTangleRetainedSandbox() sandbox.failDispatch = true From c1e23e31655836b01ce926fb4798e7fa498dcd0c Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 00:45:42 -0600 Subject: [PATCH 06/25] feat(tui): bridge native terminal sessions --- src/adapters/tui/native-terminal-transport.ts | 298 ++++++++++++++++ src/index.ts | 13 + src/ports/native-terminal-transport.ts | 82 +++++ test/native-terminal-transport.test.ts | 330 ++++++++++++++++++ 4 files changed, 723 insertions(+) create mode 100644 src/adapters/tui/native-terminal-transport.ts create mode 100644 src/ports/native-terminal-transport.ts create mode 100644 test/native-terminal-transport.test.ts diff --git a/src/adapters/tui/native-terminal-transport.ts b/src/adapters/tui/native-terminal-transport.ts new file mode 100644 index 0000000..48eddb0 --- /dev/null +++ b/src/adapters/tui/native-terminal-transport.ts @@ -0,0 +1,298 @@ +import type { + AgentTerminalSession, + TerminalDetachAck, + TerminalOutputEvent, +} from '@tangle-network/agent-interface' +import type { + NativeTerminalCleanup, + NativeTerminalCleanupIssue, + NativeTerminalTransport, + NativeTerminalTransportInput, + NativeTerminalTransportOutcome, + NativeTerminalTransportPhase, + NativeTerminalTransportResult, +} from '../../ports/native-terminal-transport.js' + +const DEFAULT_DETACH_CHORD = '\u001d' +const DEFAULT_CLEANUP_TIMEOUT_MS = 1_000 + +export function createNativeTerminalTransport( + input: NativeTerminalTransportInput, +): NativeTerminalTransport { + let runPromise: Promise | undefined + return Object.freeze({ + run: (options?: { readonly signal?: AbortSignal }) => { + runPromise ??= runTransport(input, options?.signal) + return runPromise + }, + }) +} + +async function runTransport( + input: NativeTerminalTransportInput, + callerSignal: AbortSignal | undefined, +): Promise { + const session = input.session + const sessionId = session.ref.terminalSessionId + const detachChord = input.detachChord ?? DEFAULT_DETACH_CHORD + const cleanupTimeoutMs = + input.cleanupTimeoutMs === undefined || !Number.isFinite(input.cleanupTimeoutMs) + ? DEFAULT_CLEANUP_TIMEOUT_MS + : Math.min(30_000, Math.max(0, Math.floor(input.cleanupTimeoutMs))) + const transportAbort = new AbortController() + let finished = false + let terminalStartAttempted = false + let outcome: NativeTerminalTransportOutcome | undefined + let signalRelease: (() => void) | undefined + let operationTail = Promise.resolve() + let detachRequested = false + let settleOutcome: (value: NativeTerminalTransportOutcome) => void = () => {} + const outcomeReady = new Promise((resolve) => { + settleOutcome = resolve + }) + const finish = (next: NativeTerminalTransportOutcome): void => { + if (finished) return + finished = true + outcome = next + transportAbort.abort() + settleOutcome(next) + } + const enqueue = ( + phase: Extract, + operation: () => Promise, + ): void => { + operationTail = operationTail + .then(() => (finished ? undefined : operation())) + .catch((error) => finish(transportError(sessionId, phase, error))) + } + const requestDetach = (): void => { + if (detachRequested || finished) return + detachRequested = true + const precedingOperations = operationTail + void precedingOperations.then(() => { + if (!finished) finish({ kind: 'detached', sessionId, trigger: 'user' }) + }) + } + const onInput = (data: string): void => { + if (finished) return + const chordAt = data.indexOf(detachChord) + const forwarded = chordAt < 0 ? data : data.slice(0, chordAt) + if (forwarded.length > 0) { + enqueue('input', () => session.input({ data: forwarded }, { signal: transportAbort.signal })) + } + if (chordAt >= 0) requestDetach() + } + const onResize = (): void => { + if (finished) return + const cols = input.terminal.columns + const rows = input.terminal.rows + enqueue('resize', () => session.resize({ cols, rows }, { signal: transportAbort.signal })) + } + const onSignal = (exitCode: number): void => + finish({ kind: 'aborted', sessionId, source: 'signal', exitCode }) + const onCallerAbort = (): void => finish({ kind: 'aborted', sessionId, source: 'caller' }) + const consumeEvents = async (): Promise => { + try { + for await (const event of session.events({ signal: transportAbort.signal })) { + if (finished) return + if (event.type === 'output') { + input.terminal.write(event.data) + continue + } + if (event.type === 'exit') { + finish(remoteExit(sessionId, event)) + return + } + if (event.type === 'error') { + finish(transportError(sessionId, 'events', new Error(event.message))) + return + } + } + if (!finished) { + finish( + transportError( + sessionId, + 'events', + new Error('terminal event stream ended without exit'), + ), + ) + } + } catch (error) { + if (!finished) finish(transportError(sessionId, 'events', error)) + } + } + const issues: NativeTerminalCleanupIssue[] = [] + let terminalCleanup: NativeTerminalCleanup['terminal'] = 'not-started' + let signalCleanup: NativeTerminalCleanup['signal'] = 'not-installed' + let remoteCleanup: NativeTerminalCleanup['remote'] = 'not-required' + let callerAbortCleanup: (() => void) | undefined + try { + if (callerSignal?.aborted) onCallerAbort() + else if (callerSignal !== undefined) { + callerSignal.addEventListener('abort', onCallerAbort, { once: true }) + callerAbortCleanup = () => callerSignal.removeEventListener('abort', onCallerAbort) + } + + if (!finished && input.signals !== undefined) { + try { + signalRelease = input.signals.takeOver(onSignal) + } catch (error) { + finish(transportError(sessionId, 'signal-install', error)) + } + } + if (!finished) { + terminalStartAttempted = true + try { + input.terminal.start(onInput, onResize) + } catch (error) { + finish(transportError(sessionId, 'terminal-start', error)) + } + } + if (!finished) { + void consumeEvents() + await outcomeReady + } + } catch (error) { + if (!finished) finish(transportError(sessionId, 'terminal-start', error)) + } finally { + callerAbortCleanup?.() + transportAbort.abort() + outcome ??= transportError(sessionId, 'events', new Error('transport ended without an outcome')) + if (signalRelease !== undefined) { + try { + signalRelease() + signalCleanup = 'restored' + } catch (error) { + signalCleanup = 'failed' + issues.push({ phase: 'signal-release', message: errorMessage(error) }) + } + } + if (terminalStartAttempted) { + try { + input.terminal.stop() + terminalCleanup = 'restored' + } catch (error) { + terminalCleanup = 'failed' + issues.push({ phase: 'terminal-stop', message: errorMessage(error) }) + } + } + if (shouldDetach(outcome)) { + const detach = await detachRemote(session, cleanupTimeoutMs) + remoteCleanup = detach.remote + if (detach.issue !== undefined) issues.push(detach.issue) + if (detach.remote === 'closed' && outcome.kind === 'detached') { + const closed = detach.ack?.status === 'closed' ? detach.ack : undefined + outcome = { + kind: 'remote-exit', + sessionId, + reason: 'closed-during-detach', + ...(closed?.exitCode === undefined ? {} : { exitCode: closed.exitCode }), + ...(closed?.exitSignal === undefined ? {} : { exitSignal: closed.exitSignal }), + } + } + } + } + return { + outcome, + cleanup: { + terminal: terminalCleanup, + signal: signalCleanup, + remote: remoteCleanup, + issues: Object.freeze(issues), + }, + } +} +function shouldDetach(outcome: NativeTerminalTransportOutcome): boolean { + return ( + outcome.kind === 'detached' || outcome.kind === 'aborted' || outcome.kind === 'transport-error' + ) +} + +function transportError( + sessionId: string, + phase: NativeTerminalTransportPhase, + error: unknown, +): NativeTerminalTransportOutcome { + return { kind: 'transport-error', sessionId, phase, message: errorMessage(error) } +} + +function remoteExit( + sessionId: string, + event: Extract, +): NativeTerminalTransportOutcome { + return { + kind: 'remote-exit', + sessionId, + reason: 'exited', + ...(event.exitCode === undefined ? {} : { exitCode: event.exitCode }), + ...(event.exitSignal === undefined ? {} : { exitSignal: event.exitSignal }), + } +} +async function detachRemote( + session: AgentTerminalSession, + timeoutMs: number, +): Promise<{ + readonly remote: NativeTerminalCleanup['remote'] + readonly ack?: TerminalDetachAck + readonly issue?: NativeTerminalCleanupIssue +}> { + const controller = new AbortController() + let timedOut = false + try { + const acknowledgement = await settleWithin( + session.detach({ signal: controller.signal }), + timeoutMs, + () => { + timedOut = true + controller.abort() + }, + ) + if (acknowledgement === undefined) { + return { + remote: 'unknown', + issue: { phase: 'remote-detach', message: 'remote detach did not settle before cleanup' }, + } + } + if (acknowledgement.status === 'detached') return { remote: 'detached', ack: acknowledgement } + if (acknowledgement.status === 'closed') return { remote: 'closed', ack: acknowledgement } + return { + remote: 'unknown', + ack: acknowledgement, + issue: { phase: 'remote-detach', message: acknowledgement.message }, + } + } catch (error) { + return { + remote: 'unknown', + issue: { + phase: 'remote-detach', + message: timedOut ? 'remote detach did not settle before cleanup' : errorMessage(error), + }, + } + } +} + +async function settleWithin( + promise: Promise, + timeoutMs: number, + onTimeout?: () => void, +): Promise { + let timer: NodeJS.Timeout | undefined + try { + return await Promise.race([ + promise, + new Promise((resolve) => { + timer = setTimeout(() => { + onTimeout?.() + resolve(undefined) + }, timeoutMs) + }), + ]) + } finally { + if (timer !== undefined) clearTimeout(timer) + } +} + +function errorMessage(error: unknown): string { + const message = error instanceof Error ? error.message : String(error) + return message.length > 512 ? `${message.slice(0, 509)}...` : message +} diff --git a/src/index.ts b/src/index.ts index 11687ea..c59fa1e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ export { AgentRuntimeExecutionPort, type AgentTurnBackendResolver, } from './adapters/runtime/agent-runtime-execution.js' +export { createNativeTerminalTransport } from './adapters/tui/native-terminal-transport.js' export { AppError, BraidApplication, @@ -152,6 +153,18 @@ export type { ExecutionPort, ProviderRunSnapshot, } from './ports/execution.js' +export type { + NativeTerminalCleanup, + NativeTerminalCleanupIssue, + NativeTerminalCleanupPhase, + NativeTerminalHost, + NativeTerminalSignalPort, + NativeTerminalTransport, + NativeTerminalTransportInput, + NativeTerminalTransportOutcome, + NativeTerminalTransportPhase, + NativeTerminalTransportResult, +} from './ports/native-terminal-transport.js' export { capabilitiesFromEnvironment, DEFAULT_RUN_CAPABILITIES, diff --git a/src/ports/native-terminal-transport.ts b/src/ports/native-terminal-transport.ts new file mode 100644 index 0000000..ac5672b --- /dev/null +++ b/src/ports/native-terminal-transport.ts @@ -0,0 +1,82 @@ +import type { AgentTerminalSession } from '@tangle-network/agent-interface' + +/** The existing local terminal boundary used by ProcessTerminal and tests. */ +export interface NativeTerminalHost { + readonly columns: number + readonly rows: number + start(onInput: (data: string) => void, onResize: () => void): void + stop(): void + write(data: string): void +} + +/** Optional ownership boundary for the process signal listeners. */ +export interface NativeTerminalSignalPort { + takeOver(handler: (exitCode: number) => void): () => void +} + +export type NativeTerminalTransportPhase = + | 'terminal-start' + | 'signal-install' + | 'output' + | 'input' + | 'resize' + | 'events' + +export type NativeTerminalCleanupPhase = 'remote-detach' | 'terminal-stop' | 'signal-release' + +export type NativeTerminalTransportOutcome = + | { + readonly kind: 'detached' + readonly sessionId: string + readonly trigger: 'user' + } + | { + readonly kind: 'remote-exit' + readonly sessionId: string + readonly reason: 'exited' | 'closed-during-detach' + readonly exitCode?: number + readonly exitSignal?: string + } + | { + readonly kind: 'transport-error' + readonly sessionId: string + readonly phase: NativeTerminalTransportPhase + readonly message: string + } + | { + readonly kind: 'aborted' + readonly sessionId: string + readonly source: 'caller' | 'signal' + readonly exitCode?: number + } + +export interface NativeTerminalCleanupIssue { + readonly phase: NativeTerminalCleanupPhase + readonly message: string +} + +export interface NativeTerminalCleanup { + readonly terminal: 'restored' | 'not-started' | 'failed' + readonly signal: 'restored' | 'not-installed' | 'failed' + readonly remote: 'detached' | 'closed' | 'not-required' | 'unknown' + readonly issues: readonly NativeTerminalCleanupIssue[] +} + +export interface NativeTerminalTransportResult { + readonly outcome: NativeTerminalTransportOutcome + readonly cleanup: NativeTerminalCleanup +} + +export interface NativeTerminalTransportInput { + readonly session: AgentTerminalSession + readonly terminal: NativeTerminalHost + readonly signals?: NativeTerminalSignalPort + /** Ctrl+] (ASCII GS) is intentionally not forwarded to the remote PTY. */ + readonly detachChord?: string + /** Bounds cleanup waits without delaying local terminal restoration forever. */ + readonly cleanupTimeoutMs?: number +} + +export interface NativeTerminalTransport { + run(options?: { readonly signal?: AbortSignal }): Promise +} diff --git a/test/native-terminal-transport.test.ts b/test/native-terminal-transport.test.ts new file mode 100644 index 0000000..8779915 --- /dev/null +++ b/test/native-terminal-transport.test.ts @@ -0,0 +1,330 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import type { + AgentTerminalSession, + TerminalDetachAck, + TerminalInput, + TerminalOutputEvent, + TerminalResize, + TerminalSessionRef, +} from '@tangle-network/agent-interface' +import { createNativeTerminalTransport } from '../src/index.js' +import type { + NativeTerminalHost, + NativeTerminalSignalPort, +} from '../src/ports/native-terminal-transport.js' + +const sessionId = 'terminal-transport-test' + +class EventStream { + private readonly values: T[] = [] + private closed = false + private resolveNext: ((value: T | undefined) => void) | undefined + + push(value: T): void { + if (this.closed) throw new Error('event stream is closed') + const resolve = this.resolveNext + this.resolveNext = undefined + if (resolve !== undefined) resolve(value) + else this.values.push(value) + } + + close(): void { + this.closed = true + const resolve = this.resolveNext + this.resolveNext = undefined + resolve?.(undefined) + } + + async *read(signal?: AbortSignal): AsyncIterable { + while (true) { + const value = await this.next(signal) + if (value === undefined) return + yield value + } + } + + private next(signal?: AbortSignal): Promise { + if (signal?.aborted || this.closed) return Promise.resolve(undefined) + const value = this.values.shift() + if (value !== undefined) return Promise.resolve(value) + return new Promise((resolve) => { + const onAbort = (): void => { + if (this.resolveNext === resolveNext) this.resolveNext = undefined + resolve(undefined) + } + const resolveNext = (next: T | undefined): void => { + signal?.removeEventListener('abort', onAbort) + resolve(next) + } + this.resolveNext = resolveNext + signal?.addEventListener('abort', onAbort, { once: true }) + }) + } +} + +class FakeTerminal implements NativeTerminalHost { + columns = 80 + rows = 24 + readonly writes: string[] = [] + startCount = 0 + stopCount = 0 + private onInputHandler: ((data: string) => void) | undefined + private onResizeHandler: (() => void) | undefined + + start(onInput: (data: string) => void, onResize: () => void): void { + this.startCount += 1 + this.onInputHandler = onInput + this.onResizeHandler = onResize + } + + stop(): void { + this.stopCount += 1 + this.onInputHandler = undefined + this.onResizeHandler = undefined + } + + write(data: string): void { + this.writes.push(data) + } + + input(data: string): void { + this.onInputHandler?.(data) + } + + resize(columns: number, rows: number): void { + this.columns = columns + this.rows = rows + this.onResizeHandler?.() + } +} + +class FakeSignals implements NativeTerminalSignalPort { + takeOverCount = 0 + releaseCount = 0 + private handler: ((exitCode: number) => void) | undefined + + takeOver(handler: (exitCode: number) => void): () => void { + this.takeOverCount += 1 + this.handler = handler + return () => { + this.releaseCount += 1 + this.handler = undefined + } + } + + emit(exitCode: number): void { + this.handler?.(exitCode) + } +} + +class FakeSession implements AgentTerminalSession { + readonly ref: TerminalSessionRef = { + terminalSessionId: sessionId, + parentExecutionId: 'execution-transport-test', + name: 'native transport test', + shell: '/bin/sh', + cwd: '/workspace', + cols: 80, + rows: 24, + createdAt: '2026-08-16T00:00:00.000Z', + lastActivityAt: '2026-08-16T00:00:00.000Z', + expiresAt: '2026-08-17T00:00:00.000Z', + isRunning: true, + attachCount: 1, + } + readonly cursors = { earliest: 0, latest: 0 } + readonly inputs: TerminalInput[] = [] + readonly resizes: TerminalResize[] = [] + readonly stream = new EventStream() + detachCount = 0 + closeCount = 0 + detachAck: TerminalDetachAck = { status: 'detached', terminalSessionId: sessionId } + + input(input: TerminalInput, options?: { signal?: AbortSignal }): Promise { + if (options?.signal?.aborted) return Promise.reject(new Error('input aborted')) + this.inputs.push(input) + return Promise.resolve() + } + + resize(resize: TerminalResize, options?: { signal?: AbortSignal }): Promise { + if (options?.signal?.aborted) return Promise.reject(new Error('resize aborted')) + this.resizes.push(resize) + return Promise.resolve() + } + + detach(options?: { signal?: AbortSignal }): Promise { + this.detachCount += 1 + if (options?.signal?.aborted) return Promise.reject(new Error('detach aborted')) + return Promise.resolve(this.detachAck) + } + + close(): Promise { + this.closeCount += 1 + return Promise.resolve({ status: 'closed', terminalSessionId: sessionId }) + } + + events(options?: { signal?: AbortSignal }): AsyncIterable { + return this.stream.read(options?.signal) + } +} + +function fixture() { + const session = new FakeSession() + const terminal = new FakeTerminal() + const signals = new FakeSignals() + const transport = createNativeTerminalTransport({ session, terminal, signals }) + return { session, terminal, signals, transport } +} + +async function started(terminal: FakeTerminal): Promise { + for (let attempt = 0; attempt < 20; attempt += 1) { + if (terminal.startCount === 1) return + await new Promise((resolve) => setImmediate(resolve)) + } + assert.fail('transport did not start the local terminal') +} + +test('forwards output and restores terminal and signal state', async () => { + const { session, terminal, signals, transport } = fixture() + const running = transport.run() + await started(terminal) + session.stream.push({ type: 'output', seq: 0, data: '\u001b[2Jremote-ui' }) + session.stream.push({ type: 'exit', exitCode: 0 }) + + const result = await running + assert.deepEqual(terminal.writes, ['\u001b[2Jremote-ui']) + assert.deepEqual(result.outcome, { + kind: 'remote-exit', + sessionId, + reason: 'exited', + exitCode: 0, + }) + assert.equal(result.cleanup.terminal, 'restored') + assert.equal(result.cleanup.signal, 'restored') + assert.equal(result.cleanup.remote, 'not-required') + assert.equal(terminal.stopCount, 1) + assert.equal(signals.releaseCount, 1) + assert.equal(session.detachCount, 0) + assert.equal(session.closeCount, 0) +}) + +test('forwards local input without interpreting the remote TUI', async () => { + const { session, terminal, transport } = fixture() + const running = transport.run() + await started(terminal) + terminal.input('hello remote') + await new Promise((resolve) => setImmediate(resolve)) + session.stream.push({ type: 'exit', exitCode: 0 }) + + await running + assert.deepEqual(session.inputs, [{ data: 'hello remote' }]) +}) + +test('forwards the current local resize once', async () => { + const { session, terminal, transport } = fixture() + const running = transport.run() + await started(terminal) + terminal.resize(132, 43) + await new Promise((resolve) => setImmediate(resolve)) + session.stream.push({ type: 'exit', exitCode: 0 }) + + await running + assert.deepEqual(session.resizes, [{ cols: 132, rows: 43 }]) +}) + +test('detaches on Ctrl+] and leaves the remote process running', async () => { + const { session, terminal, transport } = fixture() + const running = transport.run() + await started(terminal) + terminal.input('before\u001dignored') + + const result = await running + assert.deepEqual(session.inputs, [{ data: 'before' }]) + assert.deepEqual(result.outcome, { kind: 'detached', sessionId, trigger: 'user' }) + assert.equal(result.cleanup.remote, 'detached') + assert.equal(session.detachCount, 1) + assert.equal(session.closeCount, 0) + assert.equal(terminal.stopCount, 1) +}) + +test('reports a remote exit without detaching or closing it', async () => { + const { session, terminal, transport } = fixture() + const running = transport.run() + await started(terminal) + session.stream.push({ type: 'exit', exitSignal: 'SIGTERM' }) + + const result = await running + assert.deepEqual(result.outcome, { + kind: 'remote-exit', + sessionId, + reason: 'exited', + exitSignal: 'SIGTERM', + }) + assert.equal(session.detachCount, 0) + assert.equal(session.closeCount, 0) +}) + +test('reports transport errors and preserves the remote process', async () => { + const { session, terminal, transport } = fixture() + const running = transport.run() + await started(terminal) + session.stream.push({ type: 'error', message: 'remote stream failed' }) + + const result = await running + assert.deepEqual(result.outcome, { + kind: 'transport-error', + sessionId, + phase: 'events', + message: 'remote stream failed', + }) + assert.equal(result.cleanup.remote, 'detached') + assert.equal(session.detachCount, 1) + assert.equal(session.closeCount, 0) +}) + +test('aborts from the caller and restores every local boundary', async () => { + const { session, terminal, signals, transport } = fixture() + const controller = new AbortController() + const running = transport.run({ signal: controller.signal }) + await started(terminal) + controller.abort() + + const result = await running + assert.deepEqual(result.outcome, { kind: 'aborted', sessionId, source: 'caller' }) + assert.equal(result.cleanup.terminal, 'restored') + assert.equal(result.cleanup.signal, 'restored') + assert.equal(result.cleanup.remote, 'detached') + assert.equal(signals.releaseCount, 1) + assert.equal(session.closeCount, 0) +}) + +test('aborts from the process signal latch with a typed exit code', async () => { + const { session, terminal, signals, transport } = fixture() + const running = transport.run() + await started(terminal) + signals.emit(130) + + const result = await running + assert.deepEqual(result.outcome, { kind: 'aborted', sessionId, source: 'signal', exitCode: 130 }) + assert.equal(result.cleanup.signal, 'restored') + assert.equal(signals.takeOverCount, 1) + assert.equal(signals.releaseCount, 1) + assert.equal(session.closeCount, 0) +}) + +test('memoizes the run and makes cleanup idempotent', async () => { + const { session, terminal, signals, transport } = fixture() + const first = transport.run() + const second = transport.run() + assert.equal(first, second) + await started(terminal) + session.stream.push({ type: 'exit', exitCode: 0 }) + + const result = await first + assert.equal(await transport.run(), result) + assert.equal(terminal.stopCount, 1) + assert.equal(signals.takeOverCount, 1) + assert.equal(signals.releaseCount, 1) + assert.equal(session.detachCount, 0) +}) From f0a99b72f8173176121daf2a5338508f6bc3b109 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 01:56:27 -0600 Subject: [PATCH 07/25] feat(tui): restore transcript-first footer density --- README.md | 47 +-- docs/01-product-contract.md | 8 +- docs/02-experience-specification.md | 19 +- docs/03-architecture.md | 4 +- docs/04-runtime-contracts.md | 46 +-- docs/10-upstream-strategy.md | 4 +- package.json | 12 +- pnpm-lock.yaml | 136 +++---- pnpm-workspace.yaml | 18 +- scripts/capture-product-demo.mjs | 332 +++++++++++++----- scripts/capture-visual-definitions.mjs | 26 +- scripts/capture-visual.mjs | 47 ++- scripts/live-bridge/constants.mjs | 6 - scripts/live-bridge/main.mjs | 15 +- scripts/live-bridge/matrix.mjs | 76 +++- scripts/live-core/discovery.mjs | 10 +- scripts/live-demo.mjs | 109 +++--- scripts/live-demo.test.mjs | 44 ++- scripts/live-demo/public-safety.mjs | 4 +- scripts/live-demo/workspace.mjs | 58 ++- .../analysis/managed-analysis-runtime.ts | 2 +- .../analysis/production-analysis-analyst.ts | 10 +- src/adapters/analysis/runtime-model-owner.ts | 26 +- .../analysis/trace-analysis-adapter.ts | 43 ++- .../analysis/trace-event-projection.ts | 8 +- .../cli-bridge-model-validation.ts | 3 +- .../production-connection-types.ts | 7 +- .../runtime/cli-bridge-retained-run.ts | 58 +++ .../runtime/production-cli-bridge-backend.ts | 8 + src/adapters/tui/ui-projection.ts | 19 +- src/adapters/tui/ui-view-model.ts | 10 +- src/app/profile-model-settings.ts | 20 +- src/app/profiles.ts | 4 +- src/bin/production-application.ts | 13 +- src/bin/production-setup-types.ts | 2 + src/bin/production-startup.ts | 3 + src/bin/runtime-startup-options.ts | 14 + src/startup/preview-runtime.ts | 14 +- .../analysis-model-call-presentation.ts | 65 +++- src/views/shared/analysis-presentation.ts | 16 +- src/views/shared/command-registry.ts | 2 +- src/views/shared/models.ts | 8 +- src/views/tui/activity-browser.ts | 27 +- src/views/tui/automation-rule-panel.ts | 8 +- src/views/tui/composer-view.ts | 21 +- src/views/tui/configuration-presenters.ts | 57 ++- src/views/tui/configuration-review.ts | 9 +- .../tui/configuration-wizard-presentation.ts | 14 +- src/views/tui/configuration-wizard.ts | 10 +- .../tui/connection-metadata-editor-actions.ts | 2 +- .../connection-metadata-editor-rendering.ts | 6 +- src/views/tui/connection-metadata-editor.ts | 16 +- src/views/tui/connection-setup.ts | 4 +- src/views/tui/conversation-dialogs.ts | 9 +- src/views/tui/conversation-overlay-actions.ts | 8 +- src/views/tui/conversation-overlays.ts | 5 +- src/views/tui/entity-browser-layout.ts | 85 +++++ src/views/tui/entity-browser.ts | 72 ++-- src/views/tui/execution-target.ts | 25 +- src/views/tui/interaction-presentation.ts | 14 +- src/views/tui/interaction.ts | 6 +- src/views/tui/modal-coordinator.ts | 18 +- src/views/tui/profile-editor.ts | 21 +- src/views/tui/selector.ts | 4 +- src/views/tui/terminal-app.ts | 2 +- src/views/tui/terminal-chrome.ts | 185 +++++++--- src/views/tui/terminal-identity.ts | 95 ++++- src/views/tui/terminal-input-controller.ts | 24 +- .../tui/terminal-interaction-controller.ts | 1 + src/views/tui/terminal-overlays.ts | 20 +- src/views/tui/terminal-shell.ts | 52 +-- src/views/tui/terminal-surface-overlays.ts | 2 +- src/views/tui/terminal-usage.ts | 28 +- src/views/tui/transcript.ts | 11 +- test/analysis-model-call-roundtrip.test.ts | 41 ++- test/application.test.ts | 42 ++- test/configuration-product-flow.test.ts | 107 +++++- test/production-composition.test.ts | 47 ++- test/sanitize.test.ts | 22 +- test/terminal-responsive.test.ts | 193 ++++++++-- test/terminal-usage-status.test.ts | 170 ++++++++- test/trace-analysis-configuration.test.ts | 10 +- test/tui-core-workflows.test.ts | 101 +++++- test/tui.test.ts | 10 +- test/w6-ui.test.ts | 78 +++- 85 files changed, 2298 insertions(+), 760 deletions(-) create mode 100644 src/views/tui/entity-browser-layout.ts diff --git a/README.md b/README.md index 273153a..1354abf 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,13 @@ A portable [`AgentProfile`](https://github.com/tangle-network/agent-sdk/tree/mai Braid sends every turn through [`agent-runtime`](https://github.com/tangle-network/agent-runtime), then keeps the transcript, branches, approvals, activity, graph, and trace analysis together. -![Braid sending a Product engineer AgentProfile through agent-runtime, Local CLI Bridge, Claude Code, and Opus, then asking a cited question about the retained run](artifacts/demo/braid-live.gif) +![Historical Braid recording through Local CLI Bridge and Claude Code](artifacts/demo/braid-live.gif) -This recording uses a packed Braid artifact and a real `Product engineer` AgentProfile. +The checked-in recording and [capture manifest](artifacts/demo/braid-live.json) are historical Braid `0.1.3` evidence from Local CLI Bridge and Claude Code `opus`. -It routes one coding task through Local CLI Bridge to Claude Code and `opus`. +They are not the current `0.2.0` Pi release claim. -It verifies the edited workspace, then switches to a `Trace analyst` AgentProfile on `sonnet`. - -It runs `/ask` over the frozen trace and renders cited findings, model calls, tokens, cost provenance, and latency. - -The [capture manifest](artifacts/demo/braid-live.json) records the package hash, route, profile, limits, usage, latency, workspace proof, analysis evidence, and artifact hashes. +A fresh public recording requires a packed `0.2.0` Braid binary, a ready Pi backend, and measured usage from the exact run. ## Install @@ -42,15 +38,15 @@ The first-run flow selects an AgentProfile and a connection. No runner-specific Braid configuration is required. -For an offline terminal walkthrough, use the deterministic fixture. +For a live terminal walkthrough, run the local CLI Bridge capture. ```bash -braid --fixture deterministic +pnpm capture:demo:live ``` -The fixture proves rendering and state transitions only. +The capture routes a human prompt through Pi and records the measured result. -It does not prove a live runner, model, connection, inference route, or sandbox. +It requires a configured local CLI Bridge and a real provider credential. ## How it works @@ -97,6 +93,9 @@ const profile: AgentProfile = { provider: 'tangle-router', default: 'tangle-router/glm-5.2', reasoningEffort: 'high', + maxVisibleOutputTokens: 16_384, + maxReasoningTokens: 32_768, + maxTotalOutputTokens: 49_152, }, prompt: { instructions: [ @@ -111,11 +110,13 @@ const profile: AgentProfile = { A connection supplies transport and credential references. -The run binds the exact profile snapshot, selected connection, effective runner, model, reasoning effort, output limit, and execution environment before dispatch. +The run binds the exact profile snapshot, selected connection, effective runner, model, reasoning effort, three configured output limits, and execution environment before dispatch. + +Visible output, reasoning output, and total output limits are separate configured dimensions. -Reasoning effort and maximum output are separate dimensions. +Reasoning effort controls the requested thinking tier when the selected route supports it. -Reasoning effort controls the requested thinking tier when the selected route supports it, while maximum output limits emitted tokens independently. +Configured limits never stand in for measured usage. ### Example effective run receipt @@ -129,7 +130,9 @@ The following values illustrate the shape of one receipt and are not a live run | Runner | `pi` | | Model | `tangle-router/glm-5.2` | | Reasoning | `high` | -| Max output | `16,384 tokens` | +| Max visible output | `16,384 tokens` | +| Max reasoning output | `32,768 tokens` | +| Max total output | `49,152 tokens` | | Connection | `Local CLI Bridge` | | Execution location | `local workspace through CLI Bridge` | | Environment | `local process; sandbox fields not applicable` | @@ -172,7 +175,7 @@ Each analysis has its own run identity, source digest, analyst profile, model, b The standard Braid install includes `uv` for `/ask`. -On first use, `uv` downloads a managed Python 3.12 runtime and runs `agent-eval-rpc[dspy]==0.144.11` in an isolated cached environment. +On first use, `uv` downloads a managed Python 3.12 runtime and runs `agent-eval-rpc[dspy]==0.145.15` in an isolated cached environment. Set `BRAID_PYTHON` only when an operator must use a preinstalled compatible environment instead. @@ -180,7 +183,7 @@ Findings remain separate until the user explicitly sends selected findings to a ## Interactive and headless modes -Interactive mode is the full-screen terminal experience with a multiline composer, streaming transcript, activity pane, selectors, and focused overlays. +Interactive mode is the full-screen terminal experience with a multiline composer, streaming transcript, selectors, and focused overlays. Use inline mode when preserving normal terminal scrollback matters. @@ -301,13 +304,13 @@ pnpm check pnpm capture:visual ``` -`pnpm check` covers formatting, linting, types, dependency boundaries, attribution, licenses, deterministic tests, live checks, and release checks configured by the repository. +`pnpm check` covers formatting, linting, types, dependency boundaries, attribution, licenses, automated tests, live checks, and release checks configured by the repository. -`pnpm capture:visual` drives the built CLI through a pseudo-terminal and records the deterministic terminal evidence required by the verification plan. +When a ready Pi backend is configured, `pnpm capture:visual` drives the packed CLI through a pseudo-terminal and records terminal state evidence plus a live Pi and CLI Bridge product capture. -The checked-in W6 captures prove deterministic rendering and keyboard paths. +The checked-in W6 state captures prove rendering and keyboard paths. -They are not evidence of a live Pi, CLI Bridge, Tangle inference, or Tangle sandbox run. +A successful product capture is the evidence for the live Pi, CLI Bridge, inference route, and sandbox run. The [verification plan](docs/08-verification.md) defines the required live, headless, terminal, security, installation, and release evidence. diff --git a/docs/01-product-contract.md b/docs/01-product-contract.md index 14b0c31..d82cb66 100644 --- a/docs/01-product-contract.md +++ b/docs/01-product-contract.md @@ -14,7 +14,7 @@ The runner defines which coding program executes one run. Braid defines how the user sees, directs, forks, analyzes, approves, and audits that work. -The `AgentProfile` is portable intent, while an admitted run stores an immutable receipt for the effective runner, model, reasoning effort, maximum output, connection, and execution environment. +The `AgentProfile` is portable intent, while an admitted run stores an immutable receipt for the effective runner, model, reasoning effort, visible, reasoning, and total output limits, connection, and execution environment. Changing the selected profile for a future run never rewrites the receipt or identity of an existing run. @@ -84,7 +84,7 @@ They need analyses to remain separate from the conversation they analyze unless 1. The user starts Braid in a project directory. 2. Braid discovers or prompts for a CLI Bridge connection. 3. The user selects an existing profile. -4. Braid shows the effective runner, model, reasoning effort, maximum output, connection, execution location, and any unsupported profile dimensions before sending. +4. Braid shows the effective runner, model, reasoning effort, configured visible, reasoning, and total output limits, connection, execution location, and any unsupported profile dimensions before sending. 5. CLI Bridge materializes the exact profile and starts the selected local runner. 6. Braid streams normalized events, records the materialization receipt, and reconnects from the last event identifier after a transport loss. 7. Explicit cancellation waits for a terminal cancellation result instead of treating a closed stream as success. @@ -157,7 +157,9 @@ Activity also keeps direct turn usage, analysis usage, and runtime-worker usage ### Fast default, full depth on demand -The default composer keeps profile, connection, runner, model, effort, branch, run state, and cost visible without occupying the transcript. +The default composer keeps profile, runner, model, backend, effort, run state, and measured cost visible without occupying the transcript. + +Wide terminals add configured output limits and measured sandbox facts only when complete atomic groups fit. Advanced profile fields, event details, receipts, traces, and environment operations live behind focused overlays. diff --git a/docs/02-experience-specification.md b/docs/02-experience-specification.md index e9f5dc0..77f076e 100644 --- a/docs/02-experience-specification.md +++ b/docs/02-experience-specification.md @@ -10,7 +10,7 @@ Configuration, event detail, graphs, and supervision appear only when requested No screen uses decorative cards, repeated labels, or explanatory copy that restates visible controls. -When a run is active or selected, its immutable execution receipt is the source for displayed runner, model, reasoning, output limit, connection, and environment values. +When a run is active or selected, its immutable execution receipt is the source for displayed runner, model, reasoning, visible, reasoning, and total output limits, connection, and environment values. The pending profile is shown only when no run receipt exists for the focused context. @@ -86,14 +86,17 @@ If a connection is unavailable, the conversation opens offline and retains full › _ - profile Release engineer · pi / glm-5.2 · Local CLI Bridge Ctrl+P commands + profile Release engineer · pi / glm-5.2 · backend CLI Bridge / commands + in 1.2k · out 567 · $0.0312 · latency 120ms ``` The main shell has no persistent header. The transcript begins at the top of the viewport and remains visually primary. -One quiet line below the composer identifies the profile, runner, model, and connection. +The calm context rail uses one identity/status row from 60 through 99 columns. + +At 100 columns and above, it uses a second row only for known sandbox facts and measured token, cost, or latency values. Remote or sandbox execution appears there only when location changes the user's mental model. @@ -103,13 +106,15 @@ Autocomplete adds one divider between input and results. The composer grows to at most 40% of terminal height, then scrolls internally. -During work, the context line gives priority to state, cancel, queue, and steer controls. +During work, the context rail gives priority to state, cancel, queue, and steer controls. At rest, it gives priority to execution identity and measured usage. Transient confirmations temporarily replace the context line so they remain visible at 40 columns. -The context line omits unavailable values instead of displaying placeholders. +The context rail omits unavailable values instead of displaying placeholders. + +At widths below 60, it keeps only the profile and status. The activity view keeps direct turn totals, analysis totals, and worker-tree totals separate. @@ -117,7 +122,7 @@ Each visible total identifies reported values, estimates, or observed minimums w ### Usage and execution inspector -The wide context line shows direct conversation tokens and cost when measured values exist. +The wide context rail shows sandbox host, machine, verified region, complete resource groups, and direct token, cost, or latency measurements when known. It labels estimates and observed minimums explicitly. @@ -544,7 +549,7 @@ The browser defaults to all activity and uses `Tab` to cycle through runs, analy It lists an explicit root run binding, workers, status, current action, elapsed time, token use, cost, latency, last event, and log tail when reported. -Each activity row retains its source kind, profile digest, runner, model, reasoning effort, output limit, connection, provider session, and environment when the record reports them. +Each activity row retains its source kind, profile digest, runner, model, reasoning effort, visible, reasoning, and total output limits, connection, provider session, and environment when the record reports them. Direct turns, analyses, and workers keep their own usage totals and are never merged into a single spend number. diff --git a/docs/03-architecture.md b/docs/03-architecture.md index ea659b7..7d585f6 100644 --- a/docs/03-architecture.md +++ b/docs/03-architecture.md @@ -12,7 +12,7 @@ The presentation layer uses one immutable execution-target projection for the fo That projection reads the exact run receipt when a run exists and falls back to the pending profile only before admission. -This keeps profile identity, run identity, connection, environment, and output limits coherent without a shared god object or duplicated formatting logic. +This keeps profile identity, run identity, connection, environment, and visible, reasoning, and total output limits coherent without a shared god object or duplicated formatting logic. ## System context @@ -329,7 +329,7 @@ A sequence gap pauses reduction for that run and requests replay from the last c If the provider cannot fill the gap, the run becomes incomplete with an explicit missing range and the transcript is never presented as complete. -The run receipt is projected independently from the event document so the terminal and headless views can identify the exact profile, runner, model, effort, output limit, connection, and environment for each run. +The run receipt is projected independently from the event document so the terminal and headless views can identify the exact profile, runner, model, effort, visible, reasoning, and total output limits, connection, and environment for each run. Analysis events retain their own analysis run identity and source digest, while runtime worker events retain their supervisor and parent-worker identities. diff --git a/docs/04-runtime-contracts.md b/docs/04-runtime-contracts.md index 2f9cd22..7eeba80 100644 --- a/docs/04-runtime-contracts.md +++ b/docs/04-runtime-contracts.md @@ -15,25 +15,27 @@ The following published versions were queried from npm and their installed decla | Package | Installed version | Braid boundary | | --- | ---: | --- | | [`@tangle-network/agent-interface`](https://github.com/tangle-network/agent-sdk/tree/main/packages/agent-interface) | `0.53.0` | Canonical profile, capabilities, environment, stream, portable context, and interaction contracts | -| [`@tangle-network/agent-runtime`](https://github.com/tangle-network/agent-runtime) | `0.135.0` | Sole execution layer; exact executor, retained-run, environment-provider, and terminal-monitor exports | -| [`@tangle-network/agent-eval`](https://github.com/tangle-network/agent-eval) | `0.145.11` | Run records, judges, trace analysts, comparisons, and feedback trajectories | -| `@tangle-network/agent-provider-cli-bridge` | `0.7.2` | CLI Bridge environment adapter with live streaming, replay, retry-safe turns, retained control, and explicit cancel | -| `@tangle-network/agent-provider-tangle` | `0.11.0` | Tangle environment adapter over the sandbox client | -| `@tangle-network/sandbox` | `0.26.1` | Tangle cloud client used by the provider | +| [`@tangle-network/agent-runtime`](https://github.com/tangle-network/agent-runtime) | `0.135.3` | Sole execution layer; exact executor, retained-run, environment-provider, and terminal-monitor exports | +| [`@tangle-network/agent-eval`](https://github.com/tangle-network/agent-eval) | `0.145.15` | Run records, judges, trace analysts, comparisons, and feedback trajectories | +| `@tangle-network/agent-provider-cli-bridge` | `0.7.3` | CLI Bridge environment adapter with live streaming, replay, retry-safe turns, retained control, and explicit cancel | +| `@tangle-network/agent-provider-tangle` | `0.11.2` | Tangle environment adapter over the sandbox client | +| `@tangle-network/sandbox` | `0.27.0` | Tangle cloud client used by the provider | -The installed runtime publishes `agent-eval >=0.145.11 <0.146.0`, `agent-interface >=0.52.0 <0.53.0`, and `sandbox >=0.26.1 <0.27.0` as peer ranges. +The installed runtime publishes `agent-eval >=0.145.15 <0.146.0`, `agent-interface >=0.53.0 <0.54.0`, and `sandbox >=0.27.0 <0.28.0` as peer ranges. -Braid exercises runtime `0.135.0` with interface `0.53.0`, eval `0.145.11`, CLI Bridge adapter `0.7.2`, Tangle adapter `0.11.0`, and sandbox `0.26.1`. +Braid exercises runtime `0.135.3` with interface `0.53.0`, eval `0.145.15`, CLI Bridge adapter `0.7.3`, Tangle adapter `0.11.2`, and sandbox `0.27.0`. The lockfile pins the registry integrity for every installed package. -`pnpm peers check` reports that Runtime `0.135.0`, Knowledge `8.0.0`, and Profile Materialize `0.14.2` still peer `agent-interface <0.53.0`, while the current CLI Bridge and Tangle adapters require interface `0.53.0`. +`pnpm peers check` reports no peer dependency issues for this installed set. -The dependency graph resolves one `agent-interface` `0.53.0` instance without a workspace override. +The Braid root and Runtime peer cohort resolve `agent-interface` `0.53.0` without a workspace override. -[Agent-runtime issue 803](https://github.com/tangle-network/agent-runtime/issues/803) records the interface peer mismatch fixed in Runtime `0.132.11`. +The current provider packages retain nested `agent-interface` `0.54.0` copies for their own peer cohort. -[Agent-runtime issue 737](https://github.com/tangle-network/agent-runtime/issues/737) records the Sandbox peer mismatch fixed in Runtime `0.132.11`. +Historical snapshot: [Agent-runtime issue 803](https://github.com/tangle-network/agent-runtime/issues/803) records the interface peer mismatch fixed in Runtime `0.132.11`. + +Historical snapshot: [Agent-runtime issue 737](https://github.com/tangle-network/agent-runtime/issues/737) records the Sandbox peer mismatch fixed in Runtime `0.132.11`. Braid imports only the canonical root `agent-interface` entry point behind two local modules. @@ -124,7 +126,7 @@ Method presence remains a second defensive check because a false capability must `streamAgentTurn` accepts only a Runtime-owned executor paired with one exact `AgentProfile`. -Its published `0.135.0` API does not accept a per-turn interaction posture. +Historical snapshot: its published `0.135.0` API did not accept a per-turn interaction posture. Braid therefore does not claim interaction delivery for the ephemeral `AgentRuntimeExecutionPort` path. @@ -152,7 +154,7 @@ A partial or inconsistent positive-input split must set `cacheBreakdownKnown: fa Braid rejects unknown fields and inconsistent totals under token-bearing record names. -Runtime `0.132.12` currently buffers executor output until the executor settles. +Historical snapshot: Runtime `0.132.12` buffered executor output until the executor settled. Braid therefore receives terminal text, tool calls, usage, and result evidence but cannot render provider text deltas live through this path. @@ -178,7 +180,7 @@ The capability is a typed Runtime-executor tag, not a provider-specific callback When the tag is present, `/cancel` calls the public Runtime `Executor.teardown('infinity')` operation and waits for its result before committing control state. -The installed Runtime `0.132.12` bridge executor implements that operation by posting `POST /v1/runs/:id/cancel` and waiting for a terminal bridge snapshot. +Historical snapshot: the installed Runtime `0.132.12` bridge executor implemented that operation by posting `POST /v1/runs/:id/cancel` and waiting for a terminal bridge snapshot. `destroyed: true` becomes an accepted cancellation, while `destroyed: false`, a thrown error, or a control deadline becomes unknown. @@ -200,7 +202,7 @@ The upstream Runtime change required to expand this support is recorded below wi Title: `Expose typed, signal-aware provider cancellation acknowledgement from Executor` -Runtime `0.132.12` exposes `Executor.teardown(grace): Promise<{ destroyed: boolean }>` in its published declaration bundle. +Historical snapshot: Runtime `0.132.12` exposed `Executor.teardown(grace): Promise<{ destroyed: boolean }>` in its published declaration bundle. The bridge executor's `teardown('infinity')` posts `POST /v1/runs/:id/cancel` and waits for a terminal bridge snapshot in `dist/supervisor-BI6Z-8Yi.js:6973-6977,7529-7570`. @@ -323,7 +325,7 @@ These behaviors may be suitable for isolated benchmark automation under an expli ## Existing CLI Bridge provider contract -The published `@tangle-network/agent-provider-cli-bridge@0.7.2` resolves the bridge model from a turn override, provider default, or profile harness and model. +The published `@tangle-network/agent-provider-cli-bridge@0.7.3` resolves the bridge model from a turn override, provider default, or profile harness and model. It sends stable `executionId` values as bridge run identifiers when they satisfy the bridge identifier rules. @@ -349,7 +351,7 @@ It exposes no generalized interaction response. ## Existing Tangle provider contract -The published `@tangle-network/agent-provider-tangle@0.11.0` wraps `@tangle-network/sandbox` as an `AgentEnvironmentProvider`. +The published `@tangle-network/agent-provider-tangle@0.11.2` wraps `@tangle-network/sandbox` as an `AgentEnvironmentProvider`. Its default document is an upper bound, not a claim about one client or deployment. @@ -373,7 +375,7 @@ It currently exposes no generalized interaction response through the environment The Braid retained Tangle adapter supplies the requested map to Runtime's retained turn input. -Runtime `0.135.0` drops that field in its retained-turn copier before the Tangle provider receives it. +Historical snapshot: Runtime `0.135.0` dropped that field in its retained-turn copier before the Tangle provider received it. The Braid retained Tangle boundary test catches this loss at the provider dispatch boundary. @@ -452,8 +454,8 @@ The following upstream issues own missing shared contracts: The current interaction work has three additional published-package blockers. -- Runtime `0.135.0` must preserve `AgentTurnInput.interactions` in its retained-turn copier. -- CLI Bridge `0.7.2` must forward `turn.interactions` into its chat-completions request. +- Runtime `0.135.3` must preserve `AgentTurnInput.interactions` in its retained-turn copier. +- CLI Bridge `0.7.3` must forward `turn.interactions` into its chat-completions request. - The Runtime, Knowledge, and Profile Materialize peer cohort must accept Interface `0.53.0`. Braid does not cast around these gaps or duplicate provider dispatch. @@ -468,7 +470,7 @@ Paired comparisons retain outcomes and costs across two frozen candidates. The current DSPy RLM engine accepts a caller-owned model function, stable public call reference, and execution recorder instead of a provider URL or credential. Braid invokes this engine through its bundled `uv` binary and an isolated managed Python 3.12 runtime. -The invocation pins `agent-eval-rpc[dspy]` to `0.144.11` and fixes the dependency resolution cutoff. +The invocation pins `agent-eval-rpc[dspy]` to `0.145.15` and fixes the dependency resolution cutoff. Braid never sends model credentials to the managed Python process. Braid gives each analyst invocation one explicit runtime transport attempt by default so its recorded usage and cost cannot hide additional paid retries. @@ -480,7 +482,7 @@ For CLI Bridge, Braid uses Runtime's `startRetainedRun` with the selected provid Braid returns normalized output, measured token usage, priced cost, terminal status, and finite redacted execution evidence to `agent-eval`. -The callback rejects multimodal and request-level thinking controls because runtime `0.132.12` does not expose those fields on this exact turn input. +Historical snapshot: the callback rejected multimodal and request-level thinking controls because Runtime `0.132.12` did not expose those fields on that exact turn input. Reasoning remains an `AgentProfile` setting, and unsupported callback shapes fail before a provider call rather than being silently dropped. diff --git a/docs/10-upstream-strategy.md b/docs/10-upstream-strategy.md index badf072..17bf8dd 100644 --- a/docs/10-upstream-strategy.md +++ b/docs/10-upstream-strategy.md @@ -41,7 +41,7 @@ The deciding question was how much source can be reused while preserving `AgentP | [Hermes Agent terminal app](https://github.com/NousResearch/hermes-agent/tree/main/ui-tui) | `697f2896bf948731eb6fcb93caa7264478590843` | MIT | No size claim used | Client/runtime and workflow reference | | [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | `47f943859bef60e4160492346772ded9b24f765a`; root `0.1.0-rc.5` | MIT | No size claim used | Web, headless, subagent, job, workflow, and event-log reference | | [Cordis](https://github.com/cordiverse/cordis) | `8cc9e33fab69e2d0476d126baaf2acb24e6a6ab4`; core `4.0.0-rc.8` | MIT | No size claim used | Rejected application-framework candidate | -| [`agent-runtime` terminal monitor](https://github.com/tangle-network/agent-runtime/tree/main/src/tui) | repository `9c18cb48`; npm `0.132.11` | Project license | No refreshed size claim | Runtime-owned supervisor source, not app base | +| [`agent-runtime` terminal monitor](https://github.com/tangle-network/agent-runtime/tree/main/src/tui) | Historical snapshot: repository `9c18cb48`; npm `0.132.11` | Project license | No refreshed size claim | Runtime-owned supervisor source, not app base | The count commands selected the named TypeScript or Rust files from sparse clones and used `wc -l`. @@ -199,7 +199,7 @@ The current Braid event journal, activity graph, and immutable view models satis ## Runtime monitor -`agent-runtime` package version `0.132.12` exports a diagnostic terminal module and `agent-runtime-top` binary. +Historical snapshot: `agent-runtime` package version `0.132.12` exported a diagnostic terminal module and `agent-runtime-top` binary. The module understands runtime-owned supervisor files and shows worker state, spend, tokens, latency, logs, steering, shell action, and cancellation controls. diff --git a/package.json b/package.json index 29bf38a..804a74c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tangle-network/braid", - "version": "0.1.3", + "version": "0.2.0", "description": "A universal terminal interface for portable agent profiles", "type": "module", "bin": { @@ -99,12 +99,12 @@ "@dataiku/uv": "0.12.0", "@earendil-works/pi-tui": "0.84.2", "@napi-rs/keyring": "1.3.0", - "@tangle-network/agent-eval": "0.145.11", + "@tangle-network/agent-eval": "0.145.15", "@tangle-network/agent-interface": "0.53.0", - "@tangle-network/agent-provider-cli-bridge": "0.7.2", - "@tangle-network/agent-provider-tangle": "0.11.0", - "@tangle-network/agent-runtime": "0.135.0", - "@tangle-network/sandbox": "0.26.1", + "@tangle-network/agent-provider-cli-bridge": "0.7.3", + "@tangle-network/agent-provider-tangle": "0.11.2", + "@tangle-network/agent-runtime": "0.135.3", + "@tangle-network/sandbox": "0.27.0", "better-sqlite3-multiple-ciphers": "13.0.3", "chalk": "6.0.0", "koffi": "3.1.4" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 45ebb80..472d125 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,23 +22,23 @@ importers: specifier: 1.3.0 version: 1.3.0 '@tangle-network/agent-eval': - specifier: 0.145.11 - version: 0.145.11 + specifier: 0.145.15 + version: 0.145.15 '@tangle-network/agent-interface': specifier: 0.53.0 version: 0.53.0 '@tangle-network/agent-provider-cli-bridge': - specifier: 0.7.2 - version: 0.7.2 + specifier: 0.7.3 + version: 0.7.3 '@tangle-network/agent-provider-tangle': - specifier: 0.11.0 - version: 0.11.0(@tangle-network/sandbox@0.26.1) + specifier: 0.11.2 + version: 0.11.2(@tangle-network/sandbox@0.27.0) '@tangle-network/agent-runtime': - specifier: 0.135.0 - version: 0.135.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.53.0)(@tangle-network/sandbox@0.26.1) + specifier: 0.135.3 + version: 0.135.3(@tangle-network/agent-eval@0.145.15)(@tangle-network/agent-interface@0.53.0)(@tangle-network/sandbox@0.27.0) '@tangle-network/sandbox': - specifier: 0.26.1 - version: 0.26.1 + specifier: 0.27.0 + version: 0.27.0 better-sqlite3-multiple-ciphers: specifier: 13.0.3 version: 13.0.3 @@ -337,8 +337,8 @@ packages: cpu: [x64] os: [win32] - '@hono/node-server@2.1.0': - resolution: {integrity: sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==} + '@hono/node-server@2.1.1': + resolution: {integrity: sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==} engines: {node: '>=20'} peerDependencies: hono: 4.13.0 @@ -503,49 +503,54 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} - '@tangle-network/agent-core@0.8.0': - resolution: {integrity: sha512-RH7RsFg/n/UOCQL9dvfod6m512oLtlVTk5IpPPttdr3HbcS3FAwDBaImljzX/WMyNQCHpBkC/GiBzUCI2XVtdQ==} + '@tangle-network/agent-core@0.9.0': + resolution: {integrity: sha512-AStqQ8EERP4B/vHThs+ZfdD784ZKHsv/GmwVwv2N3XEVztGVVr0xTApc30U1hmTrkKkBK6jFAb+b/uG+Y7vH5A==} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.30.0 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true - '@tangle-network/agent-eval@0.145.11': - resolution: {integrity: sha512-CGC9BCCKNrhS84uZIQDaCCZmpPr4j1JJ7ZW/QmOir78h5psETh9Q/DF2tl79FXsXBVgyZrWWSQa7DNN+Xg4Ijg==} + '@tangle-network/agent-eval@0.145.15': + resolution: {integrity: sha512-VTvbAqhVKpXWsNwASZNcMCmYWTdsXicR3i8yeHa/ViIv1Uo3496VqWXs2FRzkMxrOB6wOI0s5DEnxCZ3qaoRzA==} engines: {node: '>=20'} hasBin: true - '@tangle-network/agent-interface@0.52.0': - resolution: {integrity: sha512-jISw0y/VqQxeyuI7N5zsEb2+AMAYoIkPCtDVbWwZ9n2KL45rur//0ih72xPo3M+fiE0eUj9weTAYg4mzZckiHg==} - '@tangle-network/agent-interface@0.53.0': resolution: {integrity: sha512-XWH+4t9vPkVog9C9P+094USuoO//TJwaI+P6ntAm32wHqZ/kh5a9r6kSkHYMKsXgQjkY3IA5NO21w3rZ7M6U+g==} - '@tangle-network/agent-knowledge@8.0.0': - resolution: {integrity: sha512-29so4fdP/pp7rKzXgnJFmwyvD9HNpA+FxlraxSQuq4jFKMpSePop1AXMLrHEerP7W1Z8Jq4vrKrp7cFy8y7Xnw==} + '@tangle-network/agent-interface@0.54.0': + resolution: {integrity: sha512-KBWcP2KQzroyjbhsG65OJecyt7AXIV0MWQuqkjUDiSac8Gtach4+oeYlBba6i9euA/8PhlGv9VBgVNiC2D/YuQ==} + + '@tangle-network/agent-knowledge@8.0.1': + resolution: {integrity: sha512-H1zMyyNyVeTCijaPGMMbZX7QY7gjE1YyHEgtNtEJ9PgvTYNBuQSh938cIKNQBHM6MPB0Lq3xECgf9ELTVveTEQ==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: - '@tangle-network/agent-eval': '>=0.145.11 <0.146.0' - '@tangle-network/agent-interface': '>=0.52.0 <0.53.0' + '@tangle-network/agent-eval': '>=0.145.14 <0.146.0' + '@tangle-network/agent-interface': '>=0.53.0 <0.54.0' - '@tangle-network/agent-profile-materialize@0.14.2': - resolution: {integrity: sha512-TuT8VIaQDEd8pvCDLEkaGWZ0aCA6e0YAUlRDeGQYNjLEqJYfQLePddqjNmf9FIgE3MepCbj/pBJEHIHzcp/C5g==} + '@tangle-network/agent-profile-materialize@0.15.1': + resolution: {integrity: sha512-+d6IvLnRurmNTpnGkiqBSHTXrFrXfFOjQQzeC74t9gl0+yZABOopqFibOAiX3njSy3WuHeZ04PpdFkZrz16Dvg==} peerDependencies: - '@tangle-network/agent-interface': '>=0.47.0 <0.53.0' + '@tangle-network/agent-interface': '>=0.47.0 <0.54.0' - '@tangle-network/agent-provider-cli-bridge@0.7.2': - resolution: {integrity: sha512-0gVoVXtmYt2P3j/PhDpDy3V0GI7W0MgnTpH1EnnLC29PxnnGobIrPjLM5QMH2YtMWxCWF2+xN/KXTkVb06IPyA==} + '@tangle-network/agent-provider-cli-bridge@0.7.3': + resolution: {integrity: sha512-KEQ6Hypgvg69HKzjMAlnVjd05pmNgRhTc+1O0knJF8yHP22lEPK39opwna/56wDFQCjjHFwb98VxgJi21irx1Q==} - '@tangle-network/agent-provider-tangle@0.11.0': - resolution: {integrity: sha512-Q1Rdy6gyY8XVNqGFq6lckoui3ekfFqhJr8lTz943F40/+Su0ThoeTwEuHYy5S0Jwqg5bXpYIn7pZytQbG5MKzA==} + '@tangle-network/agent-provider-tangle@0.11.2': + resolution: {integrity: sha512-XXono31RQoANHclDQG/BvMvm7mbuUyMrOUmvJlfSbxhEfKQ8aZziOI6hMa7yPvYvQwCJISmML+3huE0ayksRAA==} peerDependencies: '@tangle-network/sandbox': '>=0.23.0 <1.0.0' - '@tangle-network/agent-runtime@0.135.0': - resolution: {integrity: sha512-koyqFnpTDIl3+PnWtcW/7b2qkjnYLEH848qYVCy6jaN5YIztmsBk45SolZ2u7scb5AU8brDw93PL2cJHCbUo7Q==} + '@tangle-network/agent-runtime@0.135.3': + resolution: {integrity: sha512-w9DaLCHZum8h+G+PuGUxIzJgNbzk4pkC9ZSP8AkT1u25B+6y9vr/TsFtECMWqywc1W4MJ9ewouVCCkZa8cyXJg==} engines: {node: '>=22.13.0'} hasBin: true peerDependencies: - '@tangle-network/agent-eval': '>=0.145.11 <0.146.0' - '@tangle-network/agent-interface': '>=0.52.0 <0.53.0' - '@tangle-network/sandbox': '>=0.26.1 <0.27.0' + '@tangle-network/agent-eval': '>=0.145.15 <0.146.0' + '@tangle-network/agent-interface': '>=0.53.0 <0.54.0' + '@tangle-network/sandbox': '>=0.27.0 <0.28.0' peerDependenciesMeta: '@tangle-network/sandbox': optional: true @@ -553,11 +558,11 @@ packages: '@tangle-network/agent-trace-contract@1.0.2': resolution: {integrity: sha512-v7uMh56jkEp4vckevEU9xKsIatbs5dqzGPp69dFLSSXUVit0RP6VD6EANMXVlTCUk+6wVKBLHJx23XspVCEiIA==} - '@tangle-network/sandbox@0.26.1': - resolution: {integrity: sha512-FuDlGUoPa2PWYma9CGPHFapffY+r8N9UKeBJ3QZgqhqEvZqHx1XViIc69332pW634UAnj+RhWpF8ZhxQFYG7fg==} + '@tangle-network/sandbox@0.27.0': + resolution: {integrity: sha512-a7qOi7yD/a40FNYrQG8kabaGUV3ACDl5Mb8Fh+WXR3C4dCgQmY2K7kZwhkbZBSr3gINaGO/LZR9Hjddl5yakZg==} peerDependencies: '@mastra/core': ^1.36.0 - '@modelcontextprotocol/sdk': ^1.29.0 + '@modelcontextprotocol/sdk': ^1.30.0 ai: ^6.0.175 openai: ^6.36.0 viem: ^2.0.0 @@ -1037,7 +1042,7 @@ snapshots: '@esbuild/win32-x64@0.28.2': optional: true - '@hono/node-server@2.1.0(hono@4.13.0)': + '@hono/node-server@2.1.1(hono@4.13.0)': dependencies: hono: 4.13.0 @@ -1139,78 +1144,81 @@ snapshots: '@noble/hashes@1.8.0': {} - '@tangle-network/agent-core@0.8.0': + '@tangle-network/agent-core@0.9.0': dependencies: - '@tangle-network/agent-interface': 0.52.0 + '@tangle-network/agent-interface': 0.53.0 zod: 4.4.3 - '@tangle-network/agent-eval@0.145.11': + '@tangle-network/agent-eval@0.145.15': dependencies: '@asteasolutions/zod-to-openapi': 9.1.0(zod@4.4.3) - '@hono/node-server': 2.1.0(hono@4.13.0) - '@tangle-network/agent-core': 0.8.0 - '@tangle-network/agent-interface': 0.52.0 + '@hono/node-server': 2.1.1(hono@4.13.0) + '@tangle-network/agent-core': 0.9.0 + '@tangle-network/agent-interface': 0.53.0 '@tangle-network/agent-trace-contract': 1.0.2 hono: 4.13.0 linear-sum-assignment: 1.0.9 re2js: 2.8.6 zod: 4.4.3 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' - '@tangle-network/agent-interface@0.52.0': + '@tangle-network/agent-interface@0.53.0': dependencies: '@noble/hashes': 1.8.0 spdx-expression-parse: 5.0.0 zod: 4.4.3 - '@tangle-network/agent-interface@0.53.0': + '@tangle-network/agent-interface@0.54.0': dependencies: '@noble/hashes': 1.8.0 spdx-expression-parse: 5.0.0 zod: 4.4.3 - '@tangle-network/agent-knowledge@8.0.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.53.0)': + '@tangle-network/agent-knowledge@8.0.1(@tangle-network/agent-eval@0.145.15)(@tangle-network/agent-interface@0.53.0)': dependencies: - '@tangle-network/agent-eval': 0.145.11 + '@tangle-network/agent-eval': 0.145.15 '@tangle-network/agent-interface': 0.53.0 proper-lockfile: 4.1.2 zod: 4.4.3 - '@tangle-network/agent-profile-materialize@0.14.2(@tangle-network/agent-interface@0.53.0)': + '@tangle-network/agent-profile-materialize@0.15.1(@tangle-network/agent-interface@0.53.0)': dependencies: '@tangle-network/agent-interface': 0.53.0 - '@tangle-network/agent-provider-cli-bridge@0.7.2': + '@tangle-network/agent-provider-cli-bridge@0.7.3': dependencies: - '@tangle-network/agent-interface': 0.53.0 + '@tangle-network/agent-interface': 0.54.0 undici: 7.29.0 - '@tangle-network/agent-provider-tangle@0.11.0(@tangle-network/sandbox@0.26.1)': + '@tangle-network/agent-provider-tangle@0.11.2(@tangle-network/sandbox@0.27.0)': dependencies: - '@tangle-network/agent-interface': 0.53.0 - '@tangle-network/sandbox': 0.26.1 + '@tangle-network/agent-interface': 0.54.0 + '@tangle-network/sandbox': 0.27.0 - '@tangle-network/agent-runtime@0.135.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.53.0)(@tangle-network/sandbox@0.26.1)': + '@tangle-network/agent-runtime@0.135.3(@tangle-network/agent-eval@0.145.15)(@tangle-network/agent-interface@0.53.0)(@tangle-network/sandbox@0.27.0)': dependencies: - '@tangle-network/agent-core': 0.8.0 - '@tangle-network/agent-eval': 0.145.11 + '@tangle-network/agent-core': 0.9.0 + '@tangle-network/agent-eval': 0.145.15 '@tangle-network/agent-interface': 0.53.0 - '@tangle-network/agent-knowledge': 8.0.0(@tangle-network/agent-eval@0.145.11)(@tangle-network/agent-interface@0.53.0) - '@tangle-network/agent-profile-materialize': 0.14.2(@tangle-network/agent-interface@0.53.0) + '@tangle-network/agent-knowledge': 8.0.1(@tangle-network/agent-eval@0.145.15)(@tangle-network/agent-interface@0.53.0) + '@tangle-network/agent-profile-materialize': 0.15.1(@tangle-network/agent-interface@0.53.0) '@tangle-network/agent-trace-contract': 1.0.2 tar-stream: 3.2.0 optionalDependencies: - '@tangle-network/sandbox': 0.26.1 + '@tangle-network/sandbox': 0.27.0 transitivePeerDependencies: + - '@modelcontextprotocol/sdk' - bare-abort-controller - bare-buffer - react-native-b4a '@tangle-network/agent-trace-contract@1.0.2': {} - '@tangle-network/sandbox@0.26.1': + '@tangle-network/sandbox@0.27.0': dependencies: - '@tangle-network/agent-core': 0.8.0 - '@tangle-network/agent-interface': 0.52.0 + '@tangle-network/agent-core': 0.9.0 + '@tangle-network/agent-interface': 0.53.0 zod: 4.4.3 '@types/node@26.2.0': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index fcd5f85..4de92a4 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,14 +9,14 @@ allowBuilds: node-pty: true ignoreScripts: false minimumReleaseAgeExclude: - - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5 || 0.134.9 || 0.135.0' - - '@tangle-network/agent-eval@0.143.0 || 0.144.0 || 0.144.1 || 0.144.3 || 0.144.4 || 0.144.6 || 0.144.8 || 0.144.10 || 0.144.11 || 0.144.13 || 0.145.0 || 0.145.1 || 0.145.2 || 0.145.3 || 0.145.9 || 0.145.10 || 0.145.11' - - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0 || 0.53.0' - - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0' - - '@tangle-network/agent-profile-materialize@0.10.2 || 0.13.1 || 0.14.0 || 0.14.2' - - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2' - - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0 || 0.11.0' - - '@tangle-network/sandbox@0.17.3 || 0.18.0 || 0.19.2 || 0.19.3 || 0.19.4 || 0.19.5 || 0.19.6 || 0.21.0 || 0.21.1 || 0.26.1' + - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5 || 0.134.9 || 0.135.0 || 0.135.3' + - '@tangle-network/agent-eval@0.143.0 || 0.144.0 || 0.144.1 || 0.144.3 || 0.144.4 || 0.144.6 || 0.144.8 || 0.144.10 || 0.144.11 || 0.144.13 || 0.145.0 || 0.145.1 || 0.145.2 || 0.145.3 || 0.145.9 || 0.145.10 || 0.145.11 || 0.145.14 || 0.145.15' + - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0 || 0.53.0 || 0.54.0' + - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0 || 8.0.1' + - '@tangle-network/agent-profile-materialize@0.10.2 || 0.13.1 || 0.14.0 || 0.14.2 || 0.15.1' + - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2 || 0.7.3' + - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0 || 0.11.0 || 0.11.1 || 0.11.2' + - '@tangle-network/sandbox@0.17.3 || 0.18.0 || 0.19.2 || 0.19.3 || 0.19.4 || 0.19.5 || 0.19.6 || 0.21.0 || 0.21.1 || 0.26.1 || 0.27.0' - hono@4.13.0 - '@esbuild/aix-ppc64@0.28.2' - '@esbuild/android-arm64@0.28.2' @@ -45,5 +45,5 @@ minimumReleaseAgeExclude: - '@esbuild/win32-ia32@0.28.2' - '@esbuild/win32-x64@0.28.2' - esbuild@0.28.2 - - '@tangle-network/agent-core@0.5.4 || 0.6.0 || 0.6.1 || 0.7.1 || 0.8.0' + - '@tangle-network/agent-core@0.5.4 || 0.6.0 || 0.6.1 || 0.7.1 || 0.8.0 || 0.8.1 || 0.9.0' - '@earendil-works/pi-tui@0.84.2' diff --git a/scripts/capture-product-demo.mjs b/scripts/capture-product-demo.mjs index c3a88a4..f998f34 100644 --- a/scripts/capture-product-demo.mjs +++ b/scripts/capture-product-demo.mjs @@ -1,10 +1,21 @@ -import { mkdir, mkdtemp, rm } from 'node:fs/promises' +import assert from 'node:assert/strict' +import { execFile } from 'node:child_process' +import { randomBytes } from 'node:crypto' +import { chmod, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { promisify } from 'node:util' -const COLUMNS = 120 -const ROWS = 18 -const CONNECTION_ID = 'connection-local-cli-bridge' +import { releaseTargetDefinitions } from './live-bridge/bridge.mjs' +import { assertPublicCapture } from './live-demo/public-safety.mjs' +import { liveDemoProfileForRoute, LIVE_DEMO_PROFILE } from './live-demo/workspace.mjs' + +const COLUMNS = 160 +const ROWS = 30 +const CONNECTION_ID = 'connection-product-demo-cli-bridge' +const HUMAN_PROMPT = + 'Please inspect this workspace and tell me which command runs the test suite. Do not edit files.' +const execFileAsync = promisify(execFile) function pause(milliseconds) { return new Promise((resolve) => setTimeout(resolve, milliseconds)) @@ -26,132 +37,263 @@ async function typeText(terminal, value, delayMs = 20) { } } +async function localPiModelCredential(profile) { + const executable = process.env.BRAID_PI_BIN ?? 'pi' + const provider = profile.model.provider + const model = profile.model.default + for (const credentialKind of ['print-bearer-token', 'print-api-key']) { + const args = ['auth', credentialKind] + if (provider !== undefined) args.push('--provider', provider) + args.push('--model', model) + try { + const result = await execFileAsync(executable, args, { + encoding: 'utf8', + env: process.env, + }) + const token = result.stdout.trim() + if (token.length === 0 || /\r|\n/u.test(token)) continue + return token + } catch {} + } + throw new Error(`The real product demo requires a usable local Pi ${model} credential`) +} + +function demoEndpoint() { + return ( + process.env.BRAID_PRODUCT_DEMO_ENDPOINT ?? + process.env.BRAID_LIVE_DEMO_ENDPOINT ?? + process.env.BRAID_CLI_BRIDGE_ENDPOINT ?? + 'http://127.0.0.1:3345' + ) +} + +function localEndpoint(value) { + const endpoint = new URL(value) + assert.equal(endpoint.protocol, 'http:', 'The product demo requires a local HTTP CLI Bridge') + assert.ok( + ['127.0.0.1', 'localhost', '::1', '[::1]'].includes(endpoint.hostname), + 'The product demo refuses a non-loopback CLI Bridge', + ) + assert.equal(endpoint.username, '', 'The product demo endpoint must not contain credentials') + assert.equal(endpoint.password, '', 'The product demo endpoint must not contain credentials') + assert.equal(endpoint.search, '', 'The product demo endpoint must not contain query data') + assert.equal(endpoint.hash, '', 'The product demo endpoint must not contain a fragment') + return endpoint.origin +} + +function bridgeAuthorization() { + const value = + process.env.BRAID_CLI_BRIDGE_AUTH ?? + process.env.BRAID_CLI_BRIDGE_BEARER ?? + process.env.CLI_BRIDGE_BEARER + if (value === undefined || value.trim().length === 0) return undefined + return /^(?:Bearer|Basic)\s+/iu.test(value) ? value : `Bearer ${value}` +} + +async function jsonRequest(url) { + const authorization = bridgeAuthorization() + const response = await fetch(url, { + ...(authorization === undefined ? {} : { headers: { Authorization: authorization } }), + signal: AbortSignal.timeout(15_000), + }) + const body = await response.json() + if (!response.ok) throw new Error(`CLI Bridge request failed with HTTP ${response.status}`) + return body +} + +async function requirePiBridge(endpoint) { + const [health, models] = await Promise.all([ + jsonRequest(`${endpoint}/health`), + jsonRequest(`${endpoint}/v1/models`), + ]) + const readyPi = health.backends?.find( + (backend) => backend?.name === 'pi' && backend?.state === 'ready', + ) + assert.equal(health.status, 'ok', 'CLI Bridge is not healthy') + assert.ok(readyPi, 'CLI Bridge does not report a ready Pi backend') + const [target] = releaseTargetDefinitions( + [], + { ok: true, body: models }, + { body: health }, + ).filter((candidate) => candidate.backend === LIVE_DEMO_PROFILE.harness) + assert.ok(target, 'CLI Bridge does not advertise a ready Pi model') + return { health, target } +} + +async function createProductionDemoWorkspace(root, endpoint, profile) { + const workspace = join(root, 'agent-sdk') + const configDirectory = join(workspace, '.braid') + const configPath = join(configDirectory, 'config.json') + const keyPath = join(root, 'database.key') + const now = new Date().toISOString() + await mkdir(configDirectory, { recursive: true, mode: 0o700 }) + await writeFile(keyPath, randomBytes(32).toString('hex'), { mode: 0o600 }) + await chmod(keyPath, 0o600) + await writeFile( + configPath, + `${JSON.stringify( + { + format: 'braid-startup-config', + schemaVersion: 2, + profile, + connectionId: CONNECTION_ID, + databaseKeyFile: keyPath, + connections: [ + { + id: CONNECTION_ID, + kind: 'cli-bridge', + name: 'Local CLI Bridge', + endpoint, + providerOptions: { transport: 'local' }, + createdAt: now, + updatedAt: now, + lastHealth: { status: 'healthy', checkedAt: now }, + }, + ], + }, + null, + 2, + )}\n`, + { mode: 0o600 }, + ) + return { workspace, configPath, keyPath } +} + +async function waitForCompletedRun(terminal) { + const deadline = Date.now() + 180_000 + while (Date.now() < deadline) { + const screen = terminal.screen().replace(/\s+/gu, ' ').trim() + if (screen.includes('failed') || screen.includes('outcome unknown')) { + throw new Error(`The real product demo run did not complete: ${screen}`) + } + if (!screen.includes('working') && !screen.includes('Ctrl+C cancel')) { + const captured = await terminal.captureState() + const run = captured.record.state?.runs?.at(-1) + if (run?.status === 'completed') return captured + } + await pause(250) + } + throw new Error('Timed out waiting for the real Pi product demo run') +} + export async function captureProductDemo({ spawnTerminal, normalized, castFor }) { const temporaryRoot = await mkdtemp(join(tmpdir(), 'braid-product-demo-')) - const workspace = join(temporaryRoot, 'agent-sdk') - await mkdir(workspace) + const endpoint = localEndpoint(demoEndpoint()) + const { target } = await requirePiBridge(endpoint) + const route = target.modelId + const profile = liveDemoProfileForRoute(route) + const modelCredential = await localPiModelCredential(profile) + const setup = await createProductionDemoWorkspace(temporaryRoot, endpoint, profile) const terminal = await spawnTerminal( 'product-demo', COLUMNS, ROWS, - { BRAID_FIXTURE_CHUNK_DELAY_MS: '300' }, - 'product-demo', - ['--connection', CONNECTION_ID, '--workspace', workspace], + { + BRAID_CLI_BRIDGE_ENDPOINT: endpoint, + BRAID_MODEL_VALIDATION_TIMEOUT_MS: '120000', + BRAID_STATE_PATH: join(temporaryRoot, 'state.sqlite'), + BRAID_CLI_BRIDGE_MODEL_TOKEN: modelCredential, + ...(profile.model.provider === 'openai-codex' + ? { BRAID_CLI_BRIDGE_MODEL_BASE_URL: 'https://chatgpt.com/backend-api' } + : {}), + NODE_NO_WARNINGS: '1', + XDG_CONFIG_HOME: join(temporaryRoot, 'config'), + XDG_DATA_HOME: join(temporaryRoot, 'data'), + }, + undefined, + [ + '--workspace', + setup.workspace, + '--config', + setup.configPath, + '--database-key-file', + setup.keyPath, + ], + { fixture: false }, ) try { await terminal.waitForInterface() - await terminal.waitFor(() => { - const screen = normalized(terminal.screen()) - return ( - screen.includes('profile Release engineer') && - screen.includes('pi / openai-codex/gpt-5.6-luna') && - screen.includes('Local CLI Bridge') && - screen.includes('Ctrl+P commands') - ) - }, 'complete product configuration') - await pause(700) - - await typeText(terminal, '/profile', 30) - terminal.input('\r') - await terminal.waitFor(() => { - const screen = normalized(terminal.screen()) - return ( - screen.includes('Active profile · Release engineer') && - screen.includes('runner pi · model openai-codex/gpt-5.6-luna') - ) - }, 'AgentProfile panel') - terminal.resize(COLUMNS - 1, ROWS) - await terminal.waitForStable('pre-demo redraw') - const demoStartIndex = terminal.events.length - terminal.resize(COLUMNS, ROWS) - await terminal.waitForStable('demo redraw') - await pause(1_000) - terminal.input('\u001b') await terminal.waitFor( - () => !normalized(terminal.screen()).includes('Active profile · Release engineer'), - 'AgentProfile panel close', + () => { + const screen = normalized(terminal.screen()) + return ( + screen.includes(profile.name) && + screen.includes(`pi / ${profile.model.default}`) && + screen.includes('CLI Bridge') && + screen.includes('high') + ) + }, + 'real Pi product configuration', + 120_000, ) - await pause(350) + await pause(700) - const prompt = 'Which coding agent will handle my next task, and where will it run?' - await typeText(terminal, prompt) + const demoStartIndex = terminal.events.length + await typeText(terminal, '/profile', 24) terminal.input('\r') - await terminal.waitFor( - () => normalized(terminal.screen()).includes('working'), - 'active run', - 15_000, - ) - terminal.input('\u001bOQ') - await terminal.waitFor( - () => normalized(terminal.screen()).includes('live work'), - 'live-work pane', - ) - await pause(500) - await terminal.waitFor( - () => normalized(terminal.screen()).includes('Pi will run the task'), - 'routed response', - 15_000, - ) await terminal.waitFor( () => { const screen = normalized(terminal.screen()) return ( - screen.includes('pi / openai-codex/gpt-5.6-luna') && !screen.includes('Ctrl+C cancel') + screen.includes(profile.name) && + screen.includes(`runner pi · model ${profile.model.default}`) && + screen.includes('thinking high') ) }, - 'completed run', - 15_000, + 'AgentProfile panel', + 30_000, ) - terminal.input('\u001bOQ') - await terminal.waitFor( - () => !normalized(terminal.screen()).includes('live work'), - 'live-work pane close', - ) - await terminal.waitForStable('product screenshot') - const screenshot = terminal.snapshot() - await pause(900) - - await typeText(terminal, '/activity', 30) - terminal.input('\r') + await pause(700) + terminal.input('\u001b') await terminal.waitFor( - () => normalized(terminal.screen()).includes('activity'), - 'retained activity', + () => !normalized(terminal.screen()).includes(`runner pi · model ${profile.model.default}`), + 'AgentProfile panel close', ) - await pause(900) - terminal.input('\u001b[D') await pause(350) - await typeText(terminal, '/ask What should this agent improve next?', 18) + await typeText(terminal, HUMAN_PROMPT, 18) terminal.input('\r') await terminal.waitFor( - () => normalized(terminal.screen()).includes('/ask · frozen question'), - 'trace analysis', + () => normalized(terminal.screen()).includes('working'), + 'real Pi active run', + 30_000, ) - await terminal.waitForStable('product demo final frame') - await pause(1_000) + const completed = await waitForCompletedRun(terminal) + await terminal.waitForStable('real product screenshot') + const screenshot = completed.point const demo = terminal.snapshot() + const frameCast = castFor( + terminal, + terminal.events.slice(0, screenshot.eventCount), + 'Braid product screenshot', + `braid --runner pi --model ${route} --connection Local-CLI-Bridge`, + ) + const demoCast = castFor( + terminal, + rebaseEvents(terminal.events.slice(demoStartIndex, demo.eventCount)), + 'Braid product demo', + `braid --runner pi --model ${route} --connection Local-CLI-Bridge`, + ) + const publicText = `${frameCast}\n${demoCast}\n${screenshot.screen}` + assertPublicCapture(publicText) + assert.doesNotMatch(publicText, /\b(?:fixture|deterministic|unknown|not reported)\b/iu) + assert.match(screenshot.screen, new RegExp(HUMAN_PROMPT.slice(0, 24), 'u')) + assert.match(screenshot.screen, new RegExp(profile.name, 'u')) + assert.match(screenshot.screen, new RegExp(`pi / ${profile.model.default}`, 'u')) + assert.match(screenshot.screen, /CLI Bridge/u) + assert.match(screenshot.screen, /(?:in|out|\$|latency) \S+/u) await terminal.closeNormally() return { columns: COLUMNS, rows: ROWS, finalScreen: screenshot.screen, - frameCast: castFor( - terminal, - terminal.events.slice(0, screenshot.eventCount), - 'Braid product screenshot', - ), - demoCast: castFor( - terminal, - rebaseEvents(terminal.events.slice(demoStartIndex, demo.eventCount)), - 'Braid product demo', - ), + frameCast, + demoCast, steps: [ - 'Inspect AgentProfile', - 'Run through Local CLI Bridge', - 'Inspect live work and the retained run', - 'Analyze the frozen trace with /ask', - 'Review the analysis list and details together', + 'Inspect the real Pi AgentProfile', + 'Send a human prompt through Local CLI Bridge', + 'Review observed model usage in the context rail', ], } } finally { diff --git a/scripts/capture-visual-definitions.mjs b/scripts/capture-visual-definitions.mjs index 002b3f5..e0c0c66 100644 --- a/scripts/capture-visual-definitions.mjs +++ b/scripts/capture-visual-definitions.mjs @@ -1,5 +1,6 @@ export function createStateDefinitions(normalized) { return [ + ...[40, 80, 120].map((columns) => commandPaletteDefinition(columns, normalized)), { name: 'empty', columns: 80, @@ -142,7 +143,9 @@ export function createStateDefinitions(normalized) { terminal.input('/profile') terminal.input('\r') await terminal.waitFor( - () => normalized(terminal.screen()).includes('Active profile'), + () => + normalized(terminal.screen()).includes('Braid starter') && + normalized(terminal.screen()).includes('trusted · read-only'), 'profile editor', ) const { point, record } = await terminal.captureState() @@ -176,3 +179,24 @@ export function createStateDefinitions(normalized) { }, ] } + +function commandPaletteDefinition(columns, normalized) { + return { + name: `command-palette-${columns}`, + columns, + rows: columns === 40 ? 12 : 24, + run: async (terminal) => { + await terminal.waitForStable('before command palette') + terminal.input('\u0010') + await terminal.waitFor( + () => + normalized(terminal.screen()).includes('Commands') && + normalized(terminal.screen()).includes('←/esc close'), + `full-screen command palette screen=${normalized(terminal.screen())}`, + ) + const { point, record } = await terminal.captureState() + await terminal.closeNormally() + return { point, record } + }, + } +} diff --git a/scripts/capture-visual.mjs b/scripts/capture-visual.mjs index b9744ff..648ed38 100644 --- a/scripts/capture-visual.mjs +++ b/scripts/capture-visual.mjs @@ -74,7 +74,15 @@ function normalized(screen) { const STATE_DEFINITIONS = createStateDefinitions(normalized) -async function spawnTerminal(name, columns, rows, extraEnvironment = {}, uiFixture, cliArgs = []) { +async function spawnTerminal( + name, + columns, + rows, + extraEnvironment = {}, + uiFixture, + cliArgs = [], + { fixture = true } = {}, +) { const emulator = new XtermTerminal({ cols: columns, rows, @@ -85,7 +93,9 @@ async function spawnTerminal(name, columns, rows, extraEnvironment = {}, uiFixtu delete environment.NO_COLOR delete environment.FORCE_COLOR const recordPath = join(rawRoot, `${name}-${randomUUID()}.json`) - const args = [binary, '--fixture', 'deterministic', '--record-state', recordPath] + const args = [binary] + if (fixture) args.push('--fixture', 'deterministic') + args.push('--record-state', recordPath) if (uiFixture) args.push('--ui-fixture', uiFixture) args.push(...cliArgs) const session = pty.spawn(process.execPath, args, { @@ -164,10 +174,16 @@ async function spawnTerminal(name, columns, rows, extraEnvironment = {}, uiFixtu await waitForStable(`${name} escape layer ${layer + 1}`) } input('\u0003') - await waitFor( - () => normalized(screen).toLowerCase().includes('ctrl+c again to quit'), - `${name} safe exit prompt`, - ) + try { + await waitFor( + () => output.toLowerCase().includes('ctrl+c again to quit'), + `${name} safe exit prompt`, + 2_000, + ) + } catch { + await closeWithSignal() + return + } input('\u0003') const event = await waitForExit('normally') if (event.exitCode !== 0) throw new Error(`${name} exited ${event.exitCode}`) @@ -197,7 +213,11 @@ async function spawnTerminal(name, columns, rows, extraEnvironment = {}, uiFixtu const waitForStable = (label = 'settled terminal frame') => waitFor(() => pendingWrites === 0 && performance.now() - lastOutputAt >= 75, `${name} ${label}`) const waitForInterface = () => - waitFor(() => output.includes('\u001b]0;Braid —'), `${name} full interface handoff`) + waitFor( + () => output.includes('\u001b[?1049h') && output.includes('›'), + `${name} full interface handoff`, + 15_000, + ) const captureState = async () => { await waitForStable() const point = snapshot() @@ -235,7 +255,7 @@ async function spawnTerminal(name, columns, rows, extraEnvironment = {}, uiFixtu } } -function castFor(result, events, title) { +function castFor(result, events, title, command = 'packed braid --fixture deterministic') { const lastEventAt = events.at(-1)?.[0] ?? 0 // agg samples a percentage position before applying an output event that lands // exactly at the cast duration. A later no-op makes every split final write @@ -248,7 +268,7 @@ function castFor(result, events, title) { timestamp: Math.floor(Date.now() / 1_000), duration: settledEvents.at(-1)[0], idle_time_limit: 1, - command: 'packed braid --fixture deterministic', + command, title, env: { TERM: 'xterm-256color' }, stdin: true, @@ -279,7 +299,7 @@ async function plainFrame() { '/bin/sh', [ '-c', - `{ printf '%s\\n' 'W6 plain proof'; } | exec ${shellArgument(binary)} --plain --fixture deterministic --no-color > ${shellArgument(stdoutPath)} 2> ${shellArgument(stderrPath)}`, + `{ printf '%s\\n' 'W6 plain proof'; sleep 4; } | exec ${shellArgument(binary)} --plain --fixture deterministic --no-color > ${shellArgument(stdoutPath)} 2> ${shellArgument(stderrPath)}`, ], { cwd: repository, @@ -297,7 +317,7 @@ async function plainFrame() { session.on('error', reject) session.on('close', (code) => resolve({ exitCode: code })) }) - const timeout = setTimeout(() => session.kill(), 5_000) + const timeout = setTimeout(() => session.kill(), 10_000) const [exit] = await Promise.all([ exited, readFifo(stdoutPath, output), @@ -471,7 +491,7 @@ try { throw new Error('comparison capture did not contain a saved comparison result') if ( definition.name === 'profile' && - !normalized(result.point.screen).includes('Active profile') + !normalized(result.point.screen).includes('trusted · read-only') ) throw new Error('profile capture did not contain the active profile editor') const stateRootName = definition.name.replaceAll('/', '-') @@ -602,7 +622,8 @@ try { binarySha256: await sha256(binary), tarball: packed.tarballName, tarballSha256: packed.tarballSha256, - fixture: 'deterministic', + stateFixture: 'deterministic', + productDemoSource: 'live Pi through CLI Bridge', terminal: 'node-pty/xterm-256color', node: process.version, provenance, diff --git a/scripts/live-bridge/constants.mjs b/scripts/live-bridge/constants.mjs index d93dff8..fb7117c 100644 --- a/scripts/live-bridge/constants.mjs +++ b/scripts/live-bridge/constants.mjs @@ -44,12 +44,6 @@ export const targetDefinitions = Object.freeze([ modelId: 'opencode/zai-coding-plan/glm-5.2', backend: 'opencode', }, - { - key: 'pi-glm-5.2', - label: 'GLM 5.2 through Pi', - modelId: 'pi/tangle-router/glm-5.2', - backend: 'pi', - }, ]) export const livePrompts = Object.freeze({ diff --git a/scripts/live-bridge/main.mjs b/scripts/live-bridge/main.mjs index 7bbb322..1692f94 100644 --- a/scripts/live-bridge/main.mjs +++ b/scripts/live-bridge/main.mjs @@ -118,11 +118,14 @@ export async function main({ requireCompleteReleaseProof = false } = {}) { } const bridgeEvidence = {} evidence.bridge = bridgeEvidence - const launchDefinitions = requireCompleteReleaseProof + const discoverFromHealth = policy.source === 'default' || requireCompleteReleaseProof + const launchDefinitions = discoverFromHealth ? [ ...policy.definitions, { key: 'release-pi', label: 'release Pi runner', backend: 'pi' }, - { key: 'release-codex', label: 'release Codex runner', backend: 'codex' }, + ...(requireCompleteReleaseProof + ? [{ key: 'release-codex', label: 'release Codex runner', backend: 'codex' }] + : []), ] : policy.definitions const bridge = await discoverBridge( @@ -130,15 +133,15 @@ export async function main({ requireCompleteReleaseProof = false } = {}) { token, bridgeEvidence, repository, - requireCompleteReleaseProof ? [] : policy.definitions, + discoverFromHealth ? [] : policy.definitions, { launchDefinitions, - requireDefinitions: !requireCompleteReleaseProof, + requireDefinitions: !discoverFromHealth, }, ) bridgeCleanup = bridge.cleanup let selected = bridge.selected - if (requireCompleteReleaseProof) { + if (discoverFromHealth) { const releaseDefinitions = releaseTargetDefinitions( policy.definitions, bridgeEvidence.models, @@ -160,7 +163,7 @@ export async function main({ requireCompleteReleaseProof = false } = {}) { ) evidence.targetPolicy = targetPolicyEvidence({ ...policy, - source: `${policy.source}:release-runners`, + source: `${policy.source}:${requireCompleteReleaseProof ? 'release-runners' : 'health-discovered'}`, definitions: releaseDefinitions, }) } diff --git a/scripts/live-bridge/matrix.mjs b/scripts/live-bridge/matrix.mjs index 6ec4ea5..a378572 100644 --- a/scripts/live-bridge/matrix.mjs +++ b/scripts/live-bridge/matrix.mjs @@ -70,20 +70,56 @@ async function withFakeBridge( } async function runTargetPolicyMatrix() { - const both = defaultTargetPolicy.definitions - const exactGlm = both[0].modelId - const exactPiGlm = both[1].modelId + const opencode = defaultTargetPolicy.definitions[0] + const piFlash = { + key: 'pi-deepseek-v4-flash', + label: 'DeepSeek V4 Flash through Pi', + modelId: 'pi/deepseek/deepseek-v4-flash', + backend: 'pi', + } + const piPro = { + key: 'pi-deepseek-v4-pro', + label: 'DeepSeek V4 Pro through Pi', + modelId: 'pi/deepseek/deepseek-v4-pro', + backend: 'pi', + } + const both = [opencode, piFlash] + const exactGlm = opencode.modelId + const exactPiModel = piFlash.modelId const readyBackends = [ { name: 'opencode', state: 'ready' }, { name: 'pi', state: 'ready' }, { name: 'claude-code', state: 'starting' }, ] - await withFakeBridge([exactGlm, exactPiGlm], readyBackends, async (endpoint) => { + const dynamicHealth = { + ok: true, + status: 200, + body: { status: 'ok', backends: readyBackends }, + } + const dynamicModels = { + ok: true, + body: { data: [{ id: exactGlm }, { id: piFlash.modelId }, { id: piPro.modelId }] }, + } + assert.deepEqual( + releaseTargetDefinitions(defaultTargetPolicy.definitions, dynamicModels, dynamicHealth).map( + ({ modelId }) => modelId, + ), + [exactGlm, piFlash.modelId], + ) + assert.deepEqual( + releaseTargetDefinitions( + defaultTargetPolicy.definitions, + { ...dynamicModels, body: { data: [{ id: piPro.modelId }, { id: piFlash.modelId }] } }, + { ...dynamicHealth, body: { status: 'ok', backends: [{ name: 'pi', state: 'ready' }] } }, + ).map(({ modelId }) => modelId), + [piPro.modelId], + ) + await withFakeBridge([exactGlm, exactPiModel], readyBackends, async (endpoint) => { const evidence = {} const result = await discoverBridge(endpoint, undefined, evidence, process.cwd(), both) assert.deepEqual( result.selected.map(({ modelId }) => modelId), - [exactGlm, exactPiGlm], + [exactGlm, exactPiModel], ) }) await withFakeBridge([exactGlm], readyBackends, async (endpoint) => { @@ -94,7 +130,7 @@ async function runTargetPolicyMatrix() { ) assert.deepEqual( evidence.missingTargets.map(({ modelId }) => modelId), - [exactPiGlm], + [exactPiModel], ) }) await withFakeBridge( @@ -110,7 +146,7 @@ async function runTargetPolicyMatrix() { { modelsStatus: 503 }, ) await withFakeBridge( - [exactGlm, exactPiGlm], + [exactGlm, exactPiModel], readyBackends, async (endpoint) => { const evidence = {} @@ -121,7 +157,7 @@ async function runTargetPolicyMatrix() { }, { capabilities: {} }, ) - await withFakeBridge([exactPiGlm], readyBackends, async (endpoint) => { + await withFakeBridge([exactPiModel], readyBackends, async (endpoint) => { const evidence = {} await assert.rejects( discoverBridge(endpoint, undefined, evidence, process.cwd(), both), @@ -133,7 +169,7 @@ async function runTargetPolicyMatrix() { ) }) await withFakeBridge( - [exactGlm, exactPiGlm], + [exactGlm, exactPiModel], [{ name: 'opencode', state: 'ready' }], async (endpoint) => { const evidence = {} @@ -177,13 +213,13 @@ async function runTargetPolicyMatrix() { const releaseModels = { ok: true, body: { - data: [{ id: exactGlm }, { id: exactPiGlm }, { id: 'codex/default' }], + data: [{ id: exactGlm }, { id: exactPiModel }, { id: 'codex/default' }], }, } const releaseDefinitions = releaseTargetDefinitions(both, releaseModels, releaseHealth) assert.deepEqual( releaseDefinitions.map(({ modelId }) => modelId), - [exactGlm, exactPiGlm, 'codex/default'], + [exactGlm, exactPiModel, 'codex/default'], ) assert.equal(releaseDefinitions[2].bridgeModelId, 'codex/default') const releaseEvidence = {} @@ -197,14 +233,20 @@ async function runTargetPolicyMatrix() { releaseTargets.map(({ modelId, bridgeModelId }) => ({ modelId, bridgeModelId })), [ { modelId: exactGlm, bridgeModelId: exactGlm }, - { modelId: exactPiGlm, bridgeModelId: exactPiGlm }, + { modelId: exactPiModel, bridgeModelId: exactPiModel }, { modelId: 'codex/default', bridgeModelId: 'codex/default' }, ], ) } async function runConfigurationMatrix() { - const [glm, piGlm] = defaultTargetPolicy.definitions + const glm = defaultTargetPolicy.definitions[0] + const piGlm = { + key: 'pi-deepseek-v4-flash', + label: 'DeepSeek V4 Flash through Pi', + modelId: 'pi/deepseek/deepseek-v4-flash', + backend: 'pi', + } assert.deepEqual(profileForBridgeTarget(glm), { name: `Braid live ${glm.modelId}`, description: 'Opt-in packed CLI Bridge smoke profile', @@ -218,8 +260,8 @@ async function runConfigurationMatrix() { version: '0.1.0', harness: 'pi', model: { - provider: 'tangle-router', - default: 'glm-5.2', + provider: 'deepseek', + default: 'deepseek-v4-flash', reasoningEffort: 'none', }, }) @@ -279,8 +321,8 @@ async function runConfigurationMatrix() { try { const written = await writeTargetConfig(root, endpoint, piGlm, undefined) assert.deepEqual(JSON.parse(await readFile(written.profilePath, 'utf8')), written.profile) - assert.equal(written.profile.model.default, 'glm-5.2') - assert.equal(written.profile.model.provider, 'tangle-router') + assert.equal(written.profile.model.default, 'deepseek-v4-flash') + assert.equal(written.profile.model.provider, 'deepseek') const credential = await writeTargetConfig(root, endpoint, glm, { recordRef: createLiveCredentialId('11111111-1111-1111-1111-111111111111'), }) diff --git a/scripts/live-core/discovery.mjs b/scripts/live-core/discovery.mjs index 47904a2..ed7aa3b 100644 --- a/scripts/live-core/discovery.mjs +++ b/scripts/live-core/discovery.mjs @@ -1,12 +1,6 @@ import assert from 'node:assert/strict' const DEFAULT_ENDPOINT = 'http://127.0.0.1:3344' -const PI_PREFERENCES = [ - 'pi/tangle-router/glm-5.2', - 'pi/openai-codex/gpt-5.6-luna', - 'pi/openai-codex/gpt-5.6-sol', - 'pi/openai-codex/gpt-5.5', -] const CODEX_PREFERENCES = ['codex/default', 'codex/gpt-5.6', 'codex/gpt-5.5'] const KNOWN_UNAVAILABLE_MODELS = new Map([ [ @@ -68,9 +62,9 @@ export function chooseRunnerTargets(health, catalog) { : [] const backends = [...new Set(models.map((model) => model.backend))].sort() const preferred = [] - const pi = modelFor(models, 'pi', PI_PREFERENCES) + const pi = modelFor(models, 'pi', []) const codex = modelFor(models, 'codex', CODEX_PREFERENCES) - if (pi) preferred.push({ runner: 'pi', model: pi.id, selection: 'preferred-pi' }) + if (pi) preferred.push({ runner: 'pi', model: pi.id, selection: 'health-discovered-pi' }) if (codex) preferred.push({ runner: 'codex', model: codex.id, selection: 'preferred-codex' }) const selected = diff --git a/scripts/live-demo.mjs b/scripts/live-demo.mjs index 5f71f3b..8d9c5a5 100644 --- a/scripts/live-demo.mjs +++ b/scripts/live-demo.mjs @@ -15,6 +15,7 @@ import { safeManifestAnalysis, } from './live-demo/manifest.mjs' import { assertPublicCapture } from './live-demo/public-safety.mjs' +import { releaseTargetDefinitions } from './live-bridge/bridge.mjs' import { castFor, createCapturedTerminal, @@ -26,6 +27,7 @@ import { } from './live-demo/terminal.mjs' import { createLiveDemoWorkspace, + liveDemoProfileForRoute, LIVE_DEMO_ANALYST_PROFILE, LIVE_DEMO_PROFILE, LIVE_DEMO_PROMPT, @@ -35,16 +37,14 @@ import { installPackedBraid } from './packed-binary.mjs' const run = promisify(execFile) const repository = new URL('../', import.meta.url).pathname.replace(/\/$/u, '') -const endpoint = process.env.BRAID_LIVE_DEMO_ENDPOINT ?? 'http://127.0.0.1:3344' +const endpoint = process.env.BRAID_LIVE_DEMO_ENDPOINT ?? 'http://127.0.0.1:3345' const outputRoot = process.env.BRAID_LIVE_DEMO_OUTPUT ? process.env.BRAID_LIVE_DEMO_OUTPUT : join(repository, 'artifacts', 'demo') const packageProofPath = process.env.BRAID_LIVE_DEMO_PACKAGE_PROOF ? process.env.BRAID_LIVE_DEMO_PACKAGE_PROOF : join(repository, 'artifacts', 'verification', 'w6', 'package-proof.json') -const route = `${LIVE_DEMO_PROFILE.harness}/${LIVE_DEMO_PROFILE.model.default}` -const analysisRoute = `${LIVE_DEMO_ANALYST_PROFILE.harness}/${LIVE_DEMO_ANALYST_PROFILE.model.default}` -const columns = 120 +const columns = 160 const rows = 30 function sha256(value) { @@ -73,13 +73,13 @@ async function bridgeProof(baseUrl) { const backend = health.backends?.find((candidate) => candidate.name === LIVE_DEMO_PROFILE.harness) assert.equal(health.status, 'ok', 'CLI Bridge is not healthy') assert.equal(backend?.state, 'ready', `${LIVE_DEMO_PROFILE.harness} is not ready in CLI Bridge`) - for (const requiredRoute of [route, analysisRoute]) { - assert.ok( - models.data?.some((candidate) => candidate.id === requiredRoute), - `${requiredRoute} is not advertised by CLI Bridge`, - ) - } - return { health, backend } + const [target] = releaseTargetDefinitions( + [], + { ok: true, body: models }, + { body: health }, + ).filter((candidate) => candidate.backend === LIVE_DEMO_PROFILE.harness) + assert.ok(target, 'CLI Bridge does not advertise a ready Pi model') + return { health, backend, target } } function latestCompletedRun(record) { @@ -184,6 +184,9 @@ async function main() { ]) const sourceCommit = commitResult.stdout.trim() const packageProof = JSON.parse(packageProofBytes.toString('utf8')) + const route = bridge.target.modelId + const profile = liveDemoProfileForRoute(route) + const analystProfile = liveDemoProfileForRoute(route, LIVE_DEMO_ANALYST_PROFILE) const analysisRuntime = { manager: 'bundled uv', pythonVersion: '3.12', @@ -202,7 +205,10 @@ async function main() { tarball: packed.tarballName, tarballSha256: packed.tarballSha256, }) - const { workspace, profilePath } = await createLiveDemoWorkspace(temporaryRoot) + const { workspace, profilePath } = await createLiveDemoWorkspace(temporaryRoot, { + profile, + analystProfile, + }) const keyFile = join(temporaryRoot, 'database.key') const recordPath = join(temporaryRoot, 'live-demo-state.json') await writeFile(keyFile, randomBytes(32).toString('hex'), { mode: 0o600 }) @@ -211,16 +217,21 @@ async function main() { workspace, keyFile, baseUrl, - LIVE_DEMO_PROFILE.harness, + profile.harness, route, profilePath, ) - assert.equal(setup.config.profile.name, LIVE_DEMO_PROFILE.name) - assert.equal(setup.config.profile.harness, LIVE_DEMO_PROFILE.harness) - assert.equal(setup.config.profile.model.default, LIVE_DEMO_PROFILE.model.default) + assert.equal(setup.config.profile.name, profile.name) + assert.equal(setup.config.profile.harness, profile.harness) + assert.equal(setup.config.profile.model.default, profile.model.default) + assert.equal( + setup.config.profile.model.maxVisibleOutputTokens, + profile.model.maxVisibleOutputTokens, + ) + assert.equal(setup.config.profile.model.maxReasoningTokens, profile.model.maxReasoningTokens) assert.equal( - setup.config.profile.model.metadata.maxTokens, - LIVE_DEMO_PROFILE.model.metadata.maxTokens, + setup.config.profile.model.maxTotalOutputTokens, + profile.model.maxTotalOutputTokens, ) terminal = await createCapturedTerminal({ @@ -248,10 +259,10 @@ async function main() { }) await terminal.waitForScreen( (screen) => - screen.includes(`profile ${LIVE_DEMO_PROFILE.name}`) && - screen.includes(LIVE_DEMO_PROFILE.harness) && - screen.includes(LIVE_DEMO_PROFILE.model.default) && - screen.includes('Local CLI Bridge'), + screen.includes(profile.name) && + screen.includes(profile.harness) && + screen.includes(profile.model.default) && + screen.includes('CLI Bridge'), 'real AgentProfile route', 60_000, ) @@ -261,16 +272,16 @@ async function main() { terminal.input('\r') await terminal.waitForScreen( (screen) => - screen.includes('Active profile · Product engineer') && + screen.includes(profile.name) && screen.includes( - `thinking high · max output ${LIVE_DEMO_PROFILE.model.metadata.maxTokens.toLocaleString('en-US')} tokens`, + `thinking high · limits visible ${profile.model.maxVisibleOutputTokens.toLocaleString('en-US')} · reasoning ${profile.model.maxReasoningTokens.toLocaleString('en-US')} · total ${profile.model.maxTotalOutputTokens.toLocaleString('en-US')}`, ), 'AgentProfile details', ) await pause(900) terminal.input('\u001b') await terminal.waitForScreen( - (screen) => !screen.includes('Active profile · Product engineer'), + (screen) => !screen.includes(`runner pi · model ${profile.model.default}`), 'AgentProfile close', ) await pause(300) @@ -289,7 +300,7 @@ async function main() { transcript.assistantMessages.length > 0, 'The coding turn returned no visible assistant result', ) - assert.equal(coding.run.runner, LIVE_DEMO_PROFILE.harness) + assert.equal(coding.run.runner, profile.harness) assert.equal(coding.run.model, route) const workspaceProof = await verifyWorkspace(workspace) await terminal.waitForStable('completed coding turn') @@ -309,31 +320,25 @@ async function main() { await typeText(terminal, '/profile', 24) terminal.input('\r') await terminal.waitForScreen( - (screen) => - screen.includes('Active profile · Product engineer') && - screen.includes(LIVE_DEMO_ANALYST_PROFILE.name), + (screen) => screen.includes(profile.name) && screen.includes(analystProfile.name), 'trace analyst profile choice', ) - await typeText(terminal, LIVE_DEMO_ANALYST_PROFILE.name, 24) + await typeText(terminal, analystProfile.name, 24) await terminal.waitForScreen( - (screen) => - screen.includes(LIVE_DEMO_ANALYST_PROFILE.name) && - !screen.includes('CLI Bridge · claude-code · hai'), + (screen) => screen.includes(analystProfile.name), 'filtered trace analyst profile', ) terminal.input('\r') await terminal.waitForScreen( - (screen) => screen.includes(`Selected ${LIVE_DEMO_ANALYST_PROFILE.name} · next runs use it`), + (screen) => screen.includes(`Selected ${analystProfile.name} · next runs use it`), 'trace analyst profile selection', ) terminal.input('\u001b') await terminal.waitForScreen( (screen) => - !screen.includes(`Selected ${LIVE_DEMO_ANALYST_PROFILE.name} · next runs use it`) && - screen.includes(`profile ${LIVE_DEMO_ANALYST_PROFILE.name}`) && - screen.includes( - `${LIVE_DEMO_ANALYST_PROFILE.harness} / ${LIVE_DEMO_ANALYST_PROFILE.model.default}`, - ), + !screen.includes(`Selected ${analystProfile.name} · next runs use it`) && + screen.includes(analystProfile.name) && + screen.includes(`${analystProfile.harness} · ${analystProfile.model.default}`), 'trace analyst active route', ) await pause(500) @@ -425,22 +430,26 @@ async function main() { route: { connection: 'Local CLI Bridge', endpoint: baseUrl, - runner: LIVE_DEMO_PROFILE.harness, + runner: profile.harness, runnerVersion: bridge.backend.version, - provider: LIVE_DEMO_PROFILE.model.provider ?? null, - model: LIVE_DEMO_PROFILE.model.default, + provider: profile.model.provider ?? null, + model: profile.model.default, }, profile: { - name: LIVE_DEMO_PROFILE.name, - reasoningEffort: LIVE_DEMO_PROFILE.model.reasoningEffort, - maxOutputTokens: LIVE_DEMO_PROFILE.model.metadata.maxTokens, + name: profile.name, + reasoningEffort: profile.model.reasoningEffort, + maxVisibleOutputTokens: profile.model.maxVisibleOutputTokens, + maxReasoningTokens: profile.model.maxReasoningTokens, + maxTotalOutputTokens: profile.model.maxTotalOutputTokens, }, analysisProfile: { - name: LIVE_DEMO_ANALYST_PROFILE.name, - runner: LIVE_DEMO_ANALYST_PROFILE.harness, - model: LIVE_DEMO_ANALYST_PROFILE.model.default, - reasoningEffort: LIVE_DEMO_ANALYST_PROFILE.model.reasoningEffort, - maxOutputTokens: LIVE_DEMO_ANALYST_PROFILE.model.metadata.maxTokens, + name: analystProfile.name, + runner: analystProfile.harness, + model: analystProfile.model.default, + reasoningEffort: analystProfile.model.reasoningEffort, + maxVisibleOutputTokens: analystProfile.model.maxVisibleOutputTokens, + maxReasoningTokens: analystProfile.model.maxReasoningTokens, + maxTotalOutputTokens: analystProfile.model.maxTotalOutputTokens, }, task: { prompt: LIVE_DEMO_PROMPT, diff --git a/scripts/live-demo.test.mjs b/scripts/live-demo.test.mjs index 7a1b9de..09455c5 100644 --- a/scripts/live-demo.test.mjs +++ b/scripts/live-demo.test.mjs @@ -21,7 +21,11 @@ import { terminalPageProgress, visibleModelCallNumbers, } from './live-demo/terminal.mjs' -import { LIVE_DEMO_ANALYST_PROFILE, LIVE_DEMO_PROFILE } from './live-demo/workspace.mjs' +import { + liveDemoProfileForRoute, + LIVE_DEMO_ANALYST_PROFILE, + LIVE_DEMO_PROFILE, +} from './live-demo/workspace.mjs' function isAlive(pid) { try { @@ -75,7 +79,7 @@ test('analysis pagination reaches real page bounds and records visible calls', ( test('live demo timeline starts on the configured screen and preserves captured bytes', () => { const events = [ [0.4, 'o', '\u001b[2J'], - [0.8, 'o', 'Product engineer · runner pi'], + [0.8, 'o', 'Release engineer · runner pi'], [1.5, 'i', '/'], [1.51, 'o', '/'], ] @@ -92,7 +96,7 @@ test('live demo timeline starts on the configured screen and preserves captured const cast = castFor( { columns: 120, rows: 30, events }, 'Braid live demo', - 'braid --profile Product-engineer', + 'braid --profile Release-engineer', ) const [headerLine, ...eventLines] = cast.trim().split('\n') const header = JSON.parse(headerLine) @@ -109,16 +113,26 @@ test('live demo timeline starts on the configured screen and preserves captured }) test('live demo profile leaves native tool policy with the selected harness', () => { - assert.equal(LIVE_DEMO_PROFILE.harness, 'claude-code') - assert.equal(LIVE_DEMO_PROFILE.model.default, 'opus') + assert.equal(LIVE_DEMO_PROFILE.harness, 'pi') + assert.equal(LIVE_DEMO_PROFILE.model.default, 'openai-codex/gpt-5.6-luna') + assert.equal(LIVE_DEMO_PROFILE.model.provider, 'openai-codex') assert.equal('tools' in LIVE_DEMO_PROFILE, false) assert.equal('permissions' in LIVE_DEMO_PROFILE, false) - assert.equal(LIVE_DEMO_ANALYST_PROFILE.harness, 'claude-code') - assert.equal(LIVE_DEMO_ANALYST_PROFILE.model.default, 'sonnet') + assert.equal(LIVE_DEMO_ANALYST_PROFILE.harness, 'pi') + assert.equal(LIVE_DEMO_ANALYST_PROFILE.model.default, 'openai-codex/gpt-5.6-luna') + assert.equal(LIVE_DEMO_ANALYST_PROFILE.model.provider, 'openai-codex') assert.equal('tools' in LIVE_DEMO_ANALYST_PROFILE, false) assert.equal('permissions' in LIVE_DEMO_ANALYST_PROFILE, false) }) +test('live demo profiles follow the advertised Pi route without a model fallback', () => { + const profile = liveDemoProfileForRoute('pi/deepseek/deepseek-v4-flash') + assert.equal(profile.harness, 'pi') + assert.equal(profile.model.provider, 'deepseek') + assert.equal(profile.model.default, 'deepseek-v4-flash') + assert.throws(() => liveDemoProfileForRoute('codex/default'), /must start with pi\//u) +}) + test('live demo failures preserve the sanitized Braid diagnostic', () => { assert.equal( terminalFailureDetail({ @@ -323,6 +337,22 @@ test('public capture rejects the credential patterns mirrored from the sanitizer assert.throws(() => assertPublicCapture(value), /Public capture contains/iu) }) } + for (const value of ['fixture/deterministic', 'backend fixture', 'deterministic state capture']) { + await t.test(`offline marker ${value}`, () => { + assert.throws( + () => assertPublicCapture(value), + /Public capture contains|expected to not match/iu, + ) + }) + } + for (const value of ['unknown', 'latency unknown', 'Model calls were not reported']) { + await t.test(`unmeasured marker ${value}`, () => { + assert.throws( + () => assertPublicCapture(value), + /Public capture contains|expected to not match/iu, + ) + }) + } assert.doesNotThrow(() => assertPublicCapture('public demo output with no credentials')) }) diff --git a/scripts/live-demo/public-safety.mjs b/scripts/live-demo/public-safety.mjs index 3336122..130512c 100644 --- a/scripts/live-demo/public-safety.mjs +++ b/scripts/live-demo/public-safety.mjs @@ -18,5 +18,7 @@ export function assertPublicCapture(value) { for (const [label, pattern] of PUBLIC_CREDENTIAL_PATTERNS) { assert.doesNotMatch(value, pattern, `Public capture contains a ${label}`) } - assert.doesNotMatch(value, /fixture\/deterministic|repeatable demo data/iu) + assert.doesNotMatch(value, /\b(?:fixture|deterministic)\b/iu) + assert.doesNotMatch(value, /backend\s+fixture/iu) + assert.doesNotMatch(value, /\b(?:unknown|not reported)\b/iu) } diff --git a/scripts/live-demo/workspace.mjs b/scripts/live-demo/workspace.mjs index a103a59..5f3fbe3 100644 --- a/scripts/live-demo/workspace.mjs +++ b/scripts/live-demo/workspace.mjs @@ -2,13 +2,16 @@ import { mkdir, writeFile } from 'node:fs/promises' import { join } from 'node:path' export const LIVE_DEMO_PROFILE = Object.freeze({ - name: 'Product engineer', + name: 'Release engineer', description: 'Implements one bounded change and proves it with tests.', - harness: 'claude-code', + harness: 'pi', model: { - default: 'opus', + default: 'openai-codex/gpt-5.6-luna', + provider: 'openai-codex', reasoningEffort: 'high', - metadata: { maxTokens: 32768 }, + maxVisibleOutputTokens: 32768, + maxReasoningTokens: 65536, + maxTotalOutputTokens: 98304, }, prompt: { instructions: [ @@ -22,11 +25,14 @@ export const LIVE_DEMO_PROFILE = Object.freeze({ export const LIVE_DEMO_ANALYST_PROFILE = Object.freeze({ name: 'Trace analyst', description: 'Reviews a completed run and cites the retained execution evidence.', - harness: 'claude-code', + harness: 'pi', model: { - default: 'sonnet', + default: 'openai-codex/gpt-5.6-luna', + provider: 'openai-codex', reasoningEffort: 'high', - metadata: { maxTokens: 16384 }, + maxVisibleOutputTokens: 16384, + maxReasoningTokens: 32768, + maxTotalOutputTokens: 49152, }, prompt: { instructions: [ @@ -42,7 +48,33 @@ export const LIVE_DEMO_PROMPT = export const LIVE_DEMO_QUESTION = 'What changed, what was verified, and what should I review?' -export async function createLiveDemoWorkspace(root) { +/** Build the public demo profile from the route the live bridge actually advertises. */ +export function liveDemoProfileForRoute(route, baseProfile = LIVE_DEMO_PROFILE) { + const parts = route.split('/') + const runner = parts.shift() + if ( + runner !== baseProfile.harness || + parts.length === 0 || + parts.some((part) => part.length === 0) + ) + throw new Error(`Live demo route must start with ${baseProfile.harness}/: ${route}`) + const provider = parts.length > 1 ? parts.shift() : undefined + const model = parts.join('/') + if (model.length === 0) throw new Error(`Live demo route has no model: ${route}`) + return Object.freeze({ + ...baseProfile, + model: Object.freeze({ + ...baseProfile.model, + default: model, + ...(provider === undefined ? { provider: undefined } : { provider }), + }), + }) +} + +export async function createLiveDemoWorkspace( + root, + { profile = LIVE_DEMO_PROFILE, analystProfile = LIVE_DEMO_ANALYST_PROFILE } = {}, +) { const workspace = join(root, 'braid-demo') const sourceRoot = join(workspace, 'src') const testRoot = join(workspace, 'test') @@ -92,12 +124,10 @@ export async function createLiveDemoWorkspace(root) { ].join('\n'), { mode: 0o600 }, ), - writeFile(profilePath, `${JSON.stringify(LIVE_DEMO_PROFILE, null, 2)}\n`, { mode: 0o600 }), - writeFile( - join(profileRoot, 'profile.json'), - `${JSON.stringify(LIVE_DEMO_ANALYST_PROFILE, null, 2)}\n`, - { mode: 0o600 }, - ), + writeFile(profilePath, `${JSON.stringify(profile, null, 2)}\n`, { mode: 0o600 }), + writeFile(join(profileRoot, 'profile.json'), `${JSON.stringify(analystProfile, null, 2)}\n`, { + mode: 0o600, + }), ]) return { workspace, profilePath } } diff --git a/src/adapters/analysis/managed-analysis-runtime.ts b/src/adapters/analysis/managed-analysis-runtime.ts index 1a00772..1777a7c 100644 --- a/src/adapters/analysis/managed-analysis-runtime.ts +++ b/src/adapters/analysis/managed-analysis-runtime.ts @@ -1,6 +1,6 @@ import { createRequire } from 'node:module' -const AGENT_EVAL_RPC_VERSION = '0.144.11' +const AGENT_EVAL_RPC_VERSION = '0.145.15' const PYTHON_VERSION = '3.12' const RESOLUTION_CUTOFF = '2026-08-11T05:00:00Z' const RUNTIME_PROBE = [ diff --git a/src/adapters/analysis/production-analysis-analyst.ts b/src/adapters/analysis/production-analysis-analyst.ts index 2192928..84364e4 100644 --- a/src/adapters/analysis/production-analysis-analyst.ts +++ b/src/adapters/analysis/production-analysis-analyst.ts @@ -44,9 +44,15 @@ export class ProductionAnalysisAnalyst implements AnalysisAnalyst { await createTraceAnalysisAdapter({ profile: target.profile, connection: target.connection, - ...(modelSettings.maxOutputTokens === undefined + ...(modelSettings.maxVisibleOutputTokens === undefined ? {} - : { maxOutputTokens: modelSettings.maxOutputTokens }), + : { maxOutputTokens: modelSettings.maxVisibleOutputTokens }), + ...(modelSettings.maxReasoningTokens === undefined + ? {} + : { maxReasoningTokens: modelSettings.maxReasoningTokens }), + ...(modelSettings.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: modelSettings.maxTotalOutputTokens }), ...connectionOptions, managedRuntimeReadiness: 'complete', ...(request.onRetainedAdmission === undefined diff --git a/src/adapters/analysis/runtime-model-owner.ts b/src/adapters/analysis/runtime-model-owner.ts index 2ea9b65..d2b1281 100644 --- a/src/adapters/analysis/runtime-model-owner.ts +++ b/src/adapters/analysis/runtime-model-owner.ts @@ -18,9 +18,9 @@ import type { RuntimeStreamEvent } from '@tangle-network/agent-runtime' import type { RouterTransportConfig } from '@tangle-network/agent-runtime/kernel' import { canonicalDigest } from '../../domain/canonical.js' import type { ConnectionRecord } from '../../domain/entities.js' -import type { RetainedRunAdmissionRecord } from '../../domain/run-contracts.js' import { safePublicIdentifier } from '../../domain/provider-values.js' import { redactProviderError } from '../../domain/redaction.js' +import type { RetainedRunAdmissionRecord } from '../../domain/run-contracts.js' import { canonicalAgentProfileDigestHex, snapshotAgentProfile, @@ -76,6 +76,9 @@ export interface RuntimeTraceModelOwnerOptions { readonly credential?: string readonly model: string readonly pricing?: CustomTokenPricing + /** Hidden reasoning budget for one analyst call. */ + readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number readonly complete?: RouterTransportConfig['complete'] readonly retry?: RuntimeRouterRetryPolicy readonly recordExecution?: ModelExecutionRecorder @@ -590,6 +593,21 @@ function analystCallProfile( (sourceReasoning === undefined || sourceReasoning === 'none') ? 'minimal' : sourceReasoning + const maxVisibleOutputTokens = request.maxTokens ?? source.model?.maxVisibleOutputTokens + const maxReasoningTokens = options.maxReasoningTokens ?? source.model?.maxReasoningTokens + const maxTotalOutputTokens = options.maxTotalOutputTokens ?? source.model?.maxTotalOutputTokens + if ( + maxTotalOutputTokens !== undefined && + ((maxVisibleOutputTokens !== undefined && maxVisibleOutputTokens > maxTotalOutputTokens) || + (maxReasoningTokens !== undefined && maxReasoningTokens > maxTotalOutputTokens) || + (maxVisibleOutputTokens !== undefined && + maxReasoningTokens !== undefined && + maxVisibleOutputTokens + maxReasoningTokens > maxTotalOutputTokens)) + ) { + throw new RangeError( + 'Trace analysis execution limits exceed AgentProfile.model.maxTotalOutputTokens', + ) + } return snapshotAgentProfile({ name: `${source.name ?? 'Braid'} trace analyst`, description: 'One bounded trace-analysis model call', @@ -606,9 +624,13 @@ function analystCallProfile( default: model, ...(provider === undefined ? {} : { provider }), ...(reasoningEffort === undefined ? {} : { reasoningEffort }), + ...(maxVisibleOutputTokens === undefined ? {} : { maxVisibleOutputTokens }), + ...(maxReasoningTokens === undefined || maxReasoningTokens <= 0 + ? {} + : { maxReasoningTokens }), + ...(maxTotalOutputTokens === undefined ? {} : { maxTotalOutputTokens }), metadata: { ...(bridge ? {} : { retry }), - ...(request.maxTokens === undefined ? {} : { maxTokens: request.maxTokens }), ...(request.temperature === undefined ? {} : { temperature: request.temperature }), ...(format === undefined ? {} : { extraBody: { response_format: format } }), }, diff --git a/src/adapters/analysis/trace-analysis-adapter.ts b/src/adapters/analysis/trace-analysis-adapter.ts index 4aef07a..47b9ee4 100644 --- a/src/adapters/analysis/trace-analysis-adapter.ts +++ b/src/adapters/analysis/trace-analysis-adapter.ts @@ -75,6 +75,7 @@ export interface TraceAnalysisAdapterOptions extends ProductionConnectionOptions readonly maxCostUsd?: number readonly maxOutputTokens?: number readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number readonly timeoutMs?: number readonly recordExecution?: (observation: ExternalOptimizerModelExecutionObservation) => void readonly onRetainedAdmission?: ( @@ -234,6 +235,39 @@ function defaultModelCostCeiling( ) } +interface AnalysisTokenLimits { + readonly maxOutputTokens: number + readonly maxReasoningTokens: number + readonly maxTotalOutputTokens?: number +} + +function analysisTokenLimits(options: TraceAnalysisAdapterOptions): AnalysisTokenLimits { + const model = options.profile.model + const total = options.maxTotalOutputTokens ?? model?.maxTotalOutputTokens + const visible = + options.maxOutputTokens ?? + model?.maxVisibleOutputTokens ?? + (total === undefined ? DEFAULT_ANALYSIS_MAX_OUTPUT_TOKENS : total) + const reasoning = + options.maxReasoningTokens ?? + model?.maxReasoningTokens ?? + (total === undefined ? visible * DEFAULT_ANALYSIS_REASONING_MULTIPLIER : total - visible) + if ( + visible <= 0 || + reasoning < 0 || + (total !== undefined && (visible > total || visible + reasoning > total)) + ) { + throw new RangeError( + 'Trace analysis visible and reasoning token limits exceed maxTotalOutputTokens', + ) + } + return { + maxOutputTokens: visible, + maxReasoningTokens: reasoning, + ...(total === undefined ? {} : { maxTotalOutputTokens: total }), + } +} + /** * Configure the model-backed trace analysts for one exact profile/connection pair. * @@ -343,6 +377,7 @@ export async function createTraceAnalysisAdapter( ? normalizeCliBridgeProviderBaseUrl(endpoint, connection.id) : normalizeTangleInferenceRuntimeBaseUrl(endpoint, connection.id) try { + const limits = analysisTokenLimits(options) const modelExecutionScope = new ModelExecutionScope() const owner = createRuntimeTraceModelOwner({ profile, @@ -351,6 +386,10 @@ export async function createTraceAnalysisAdapter( ...(credential === undefined ? {} : { credential }), model, ...(options.pricing === undefined ? {} : { pricing: { ...options.pricing } }), + ...(limits.maxReasoningTokens > 0 ? { maxReasoningTokens: limits.maxReasoningTokens } : {}), + ...(limits.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: limits.maxTotalOutputTokens }), ...(connection.kind !== 'tangle-inference' || options.routerComplete === undefined ? {} : { complete: options.routerComplete }), @@ -362,9 +401,7 @@ export async function createTraceAnalysisAdapter( ? {} : { onRetainedAdmission: options.onRetainedAdmission }), }) - const maxOutputTokens = options.maxOutputTokens ?? DEFAULT_ANALYSIS_MAX_OUTPUT_TOKENS - const maxReasoningTokens = - options.maxReasoningTokens ?? maxOutputTokens * DEFAULT_ANALYSIS_REASONING_MULTIPLIER + const { maxOutputTokens, maxReasoningTokens } = limits const maxCostUsd = options.maxCostUsd ?? (owner.pricing === undefined diff --git a/src/adapters/analysis/trace-event-projection.ts b/src/adapters/analysis/trace-event-projection.ts index 6ab398c..ebfbccb 100644 --- a/src/adapters/analysis/trace-event-projection.ts +++ b/src/adapters/analysis/trace-event-projection.ts @@ -112,8 +112,12 @@ function addRequestedRun(attributes: Record, event: BraidEvent) attributes['braid.provider_session_id'] = safeAnalysisText(receipt.providerSessionId) if (settings.reasoningEffort !== undefined) attributes['braid.reasoning_effort'] = safeAnalysisText(settings.reasoningEffort) - if (settings.maxOutputTokens !== undefined) - attributes['braid.max_output_tokens'] = settings.maxOutputTokens + if (settings.maxVisibleOutputTokens !== undefined) + attributes['braid.max_visible_output_tokens'] = settings.maxVisibleOutputTokens + if (settings.maxReasoningTokens !== undefined) + attributes['braid.max_reasoning_tokens'] = settings.maxReasoningTokens + if (settings.maxTotalOutputTokens !== undefined) + attributes['braid.max_total_output_tokens'] = settings.maxTotalOutputTokens attributes['braid.admission_status'] = receipt.admissionStatus ?? 'admitted' attributes['braid.capabilities'] = safeAnalysisValue(receipt.capabilities) } diff --git a/src/adapters/connections/cli-bridge-model-validation.ts b/src/adapters/connections/cli-bridge-model-validation.ts index d119b50..acb66dc 100644 --- a/src/adapters/connections/cli-bridge-model-validation.ts +++ b/src/adapters/connections/cli-bridge-model-validation.ts @@ -37,7 +37,8 @@ export function cliBridgeModelValidationRequest(profile: Readonly) ...(profile.model?.reasoningEffort === undefined ? {} : { reasoningEffort: profile.model.reasoningEffort }), - metadata: { maxTokens: CLI_BRIDGE_MODEL_VALIDATION_MAX_TOKENS }, + maxVisibleOutputTokens: CLI_BRIDGE_MODEL_VALIDATION_MAX_TOKENS, + maxTotalOutputTokens: CLI_BRIDGE_MODEL_VALIDATION_MAX_TOKENS, }, }, } diff --git a/src/adapters/connections/production-connection-types.ts b/src/adapters/connections/production-connection-types.ts index fd3be4e..4f15cdb 100644 --- a/src/adapters/connections/production-connection-types.ts +++ b/src/adapters/connections/production-connection-types.ts @@ -1,7 +1,10 @@ import type { AgentExactRunControlRef, AgentProfile } from '@tangle-network/agent-interface' import type { AgentEnvironmentCapabilities } from '@tangle-network/agent-interface/environment-provider' import type { SandboxClientLike } from '@tangle-network/agent-provider-tangle' -import type { RouterTransportConfig } from '@tangle-network/agent-runtime/kernel' +import type { + BridgeModelCredential, + RouterTransportConfig, +} from '@tangle-network/agent-runtime/kernel' import type { ConnectionHealth, ConnectionKind, @@ -91,6 +94,8 @@ export interface ProductionConnectionOptions { readonly credentials?: CredentialPort /** Map Braid's durable credential id to the credential-port's opaque ref. */ readonly credentialRefResolver?: (ref: CredentialRefId) => CredentialRef | Promise + /** Request-scoped model credential for a loopback CLI Bridge. */ + readonly bridgeModelCredential?: BridgeModelCredential readonly fetch?: typeof fetch /** Injectable Runtime Router transport for tests and embedded deployments. */ readonly routerComplete?: RouterTransportConfig['complete'] diff --git a/src/adapters/runtime/cli-bridge-retained-run.ts b/src/adapters/runtime/cli-bridge-retained-run.ts index e10f6cd..0ce447a 100644 --- a/src/adapters/runtime/cli-bridge-retained-run.ts +++ b/src/adapters/runtime/cli-bridge-retained-run.ts @@ -3,6 +3,7 @@ import { AgentExactRunControlRefSchema, } from '@tangle-network/agent-interface' import type { AgentEnvironmentProvider } from '@tangle-network/agent-interface/environment-provider' +import type { BridgeModelCredential } from '@tangle-network/agent-runtime/kernel' import { type RetainedRunHandle, reconnectRetainedRun, @@ -11,6 +12,7 @@ import { import { publicMaterializationReceipt } from '../../domain/materialization-receipt.js' import type { RuntimeEventEnvelope } from '../../domain/runtime-events.js' import type { ExecuteTurnInput } from '../../ports/execution.js' +import { isLoopbackEndpoint } from '../connections/production-connection-endpoints.js' import { safeExecutionId } from './production-backend-common.js' import type { PreparedCliBridgeConnection } from './production-cli-bridge-backend.js' import type { @@ -45,7 +47,11 @@ export async function createCliBridgeRetainedPlan( baseUrl: prepared.bridgeUrl, bearerToken: prepared.bearerToken, defaultModel: prepared.route, + capabilities: prepared.capabilities, ...(prepared.fetch === undefined ? {} : { fetch: prepared.fetch }), + ...(prepared.bridgeModelCredential === undefined + ? {} + : { fetch: bridgeCredentialFetch(prepared) }), }) const environmentId = controlRef?.environmentId ?? retainedEnvironmentId(runId) const executionId = controlRef?.executionId ?? safeExecutionId(runId) @@ -91,6 +97,58 @@ export async function createCliBridgeRetainedPlan( return Object.freeze(plan) } +function bridgeCredentialFetch(prepared: PreparedCliBridgeConnection): typeof fetch { + const credential = prepared.bridgeModelCredential + if (credential === undefined) return prepared.fetch ?? globalThis.fetch + if (!isLoopbackEndpoint(prepared.bridgeUrl)) { + throw new Error('A request-scoped CLI Bridge model credential requires a loopback endpoint') + } + const fetcher = prepared.fetch ?? globalThis.fetch + return async (input, init) => { + const url = new URL( + typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url, + ) + if (url.pathname !== '/v1/chat/completions') return fetcher(input, init) + const [token, baseUrl] = await Promise.all([ + credentialValue(credential, credential.key), + credentialValue(credential, credential.baseUrlKey), + ]) + const upstream = safeModelBaseUrl(baseUrl) + const headers = new Headers(init?.headers) + headers.set('x-cli-bridge-model-credential', token) + headers.set('x-cli-bridge-model-base-url', upstream) + return fetcher(input, { ...init, headers }) + } +} + +async function credentialValue(credential: BridgeModelCredential, key: string): Promise { + let value: string | undefined + try { + value = await credential.provider.get(key) + } catch { + throw new Error(`The CLI Bridge model credential provider failed for ${key}`) + } + if (typeof value !== 'string' || value.length === 0 || /[\r\n\0]/u.test(value)) { + throw new Error(`The CLI Bridge model credential provider has no usable value for ${key}`) + } + return value +} + +function safeModelBaseUrl(value: string): string { + let url: URL + try { + url = new URL(value) + } catch { + throw new Error('The CLI Bridge model credential base URL is invalid') + } + if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) { + throw new Error( + 'The CLI Bridge model credential base URL must be an HTTPS URL without credentials', + ) + } + return url.toString().replace(/\/$/u, '') +} + export async function startCliBridgeRetainedRun( plan: CliBridgeRetainedPlan, input: ExecuteTurnInput, diff --git a/src/adapters/runtime/production-cli-bridge-backend.ts b/src/adapters/runtime/production-cli-bridge-backend.ts index 0f20c92..e65ef21 100644 --- a/src/adapters/runtime/production-cli-bridge-backend.ts +++ b/src/adapters/runtime/production-cli-bridge-backend.ts @@ -3,6 +3,7 @@ import type { AgentProfile, HarnessType, } from '@tangle-network/agent-interface' +import type { BridgeModelCredential } from '@tangle-network/agent-runtime/kernel' import { ConnectionError } from '../../app/connection-errors.js' import type { ConnectionId } from '../../domain/ids.js' import type { ExecuteTurnInput } from '../../ports/execution.js' @@ -37,6 +38,7 @@ export interface PreparedCliBridgeConnection { readonly workspace: string readonly bridgeUrl: string readonly bearerToken: string + readonly bridgeModelCredential?: BridgeModelCredential readonly fetch?: typeof fetch readonly providerSessionId: string readonly capabilities: AgentEnvironmentCapabilities @@ -65,6 +67,9 @@ export async function resolveCliBridgeBackend( backend: 'bridge', bridgeUrl: prepared.bridgeUrl, bridgeBearer: prepared.bearerToken, + ...(options.bridgeModelCredential === undefined + ? {} + : { modelCredential: options.bridgeModelCredential }), cwd: prepared.workspace, sessionId: prepared.providerSessionId, }), @@ -124,6 +129,9 @@ export async function prepareCliBridgeConnection( workspace, bridgeUrl, bearerToken: credential ?? LOCAL_BRIDGE_BEARER, + ...(options.bridgeModelCredential === undefined + ? {} + : { bridgeModelCredential: options.bridgeModelCredential }), ...(options.fetch === undefined ? {} : { fetch: options.fetch }), capabilities: defaultCliBridgeCapabilities(runner), providerSessionId, diff --git a/src/adapters/tui/ui-projection.ts b/src/adapters/tui/ui-projection.ts index 05cd4e9..64c89e8 100644 --- a/src/adapters/tui/ui-projection.ts +++ b/src/adapters/tui/ui-projection.ts @@ -199,9 +199,15 @@ export function runViews(state: BraidState): RunView[] { ...(modelSettings.reasoningEffort === undefined ? {} : { effort: sanitizeTerminalText(modelSettings.reasoningEffort) }), - ...(modelSettings.maxOutputTokens === undefined + ...(modelSettings.maxVisibleOutputTokens === undefined ? {} - : { maxOutputTokens: modelSettings.maxOutputTokens }), + : { maxVisibleOutputTokens: modelSettings.maxVisibleOutputTokens }), + ...(modelSettings.maxReasoningTokens === undefined + ? {} + : { maxReasoningTokens: modelSettings.maxReasoningTokens }), + ...(modelSettings.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: modelSettings.maxTotalOutputTokens }), ...(run.error ? { error: sanitizeTerminalText(run.error) } : {}), ...(run.lastCursor ? { cursor: sanitizeTerminalText(run.lastCursor) } : {}), ...(run.providerSessionId @@ -567,6 +573,15 @@ export function toHeadlessState( ...(modelSettings.reasoningEffort === undefined ? {} : { effort: sanitizeTerminalText(modelSettings.reasoningEffort) }), + ...(modelSettings.maxVisibleOutputTokens === undefined + ? {} + : { maxVisibleOutputTokens: modelSettings.maxVisibleOutputTokens }), + ...(modelSettings.maxReasoningTokens === undefined + ? {} + : { maxReasoningTokens: modelSettings.maxReasoningTokens }), + ...(modelSettings.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: modelSettings.maxTotalOutputTokens }), ...(configuration.mode === undefined ? {} : { mode: sanitizeTerminalText(configuration.mode) }), diff --git a/src/adapters/tui/ui-view-model.ts b/src/adapters/tui/ui-view-model.ts index 6ec9336..1782166 100644 --- a/src/adapters/tui/ui-view-model.ts +++ b/src/adapters/tui/ui-view-model.ts @@ -124,9 +124,15 @@ export function buildBraidViewModel( ? {} : { mode: sanitizeTerminalText(selectedBranch.overrides.mode) }), }), - ...(modelSettings.maxOutputTokens === undefined + ...(modelSettings.maxVisibleOutputTokens === undefined ? {} - : { maxOutputTokens: modelSettings.maxOutputTokens }), + : { maxVisibleOutputTokens: modelSettings.maxVisibleOutputTokens }), + ...(modelSettings.maxReasoningTokens === undefined + ? {} + : { maxReasoningTokens: modelSettings.maxReasoningTokens }), + ...(modelSettings.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: modelSettings.maxTotalOutputTokens }), connection: fixture ? 'deterministic fixture' : sanitizeTerminalText(selectedConnection?.name ?? 'not connected'), diff --git a/src/app/profile-model-settings.ts b/src/app/profile-model-settings.ts index 8acb457..75d5926 100644 --- a/src/app/profile-model-settings.ts +++ b/src/app/profile-model-settings.ts @@ -2,19 +2,25 @@ import type { AgentProfile } from '@tangle-network/agent-interface' export interface ProfileModelSettings { readonly reasoningEffort?: string - readonly maxOutputTokens?: number + readonly maxVisibleOutputTokens?: number + readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number } /** Projects only public model controls that Braid can explain to a user. */ export function profileModelSettings(profile: Readonly): ProfileModelSettings { const reasoningEffort = profile.model?.reasoningEffort?.trim() - const maxTokens = profile.model?.metadata?.maxTokens - const maxOutputTokens = - typeof maxTokens === 'number' && Number.isSafeInteger(maxTokens) && maxTokens > 0 - ? maxTokens - : undefined + const maxVisibleOutputTokens = positiveLimit(profile.model?.maxVisibleOutputTokens) + const maxReasoningTokens = positiveLimit(profile.model?.maxReasoningTokens) + const maxTotalOutputTokens = positiveLimit(profile.model?.maxTotalOutputTokens) return { ...(reasoningEffort === undefined || reasoningEffort.length === 0 ? {} : { reasoningEffort }), - ...(maxOutputTokens === undefined ? {} : { maxOutputTokens }), + ...(maxVisibleOutputTokens === undefined ? {} : { maxVisibleOutputTokens }), + ...(maxReasoningTokens === undefined ? {} : { maxReasoningTokens }), + ...(maxTotalOutputTokens === undefined ? {} : { maxTotalOutputTokens }), } } + +function positiveLimit(value: number | undefined): number | undefined { + return typeof value === 'number' && Number.isSafeInteger(value) && value > 0 ? value : undefined +} diff --git a/src/app/profiles.ts b/src/app/profiles.ts index dc023cd..16b2ce1 100644 --- a/src/app/profiles.ts +++ b/src/app/profiles.ts @@ -91,7 +91,9 @@ export interface ProfileSummary { readonly runner?: string readonly model?: string readonly reasoningEffort?: string - readonly maxOutputTokens?: number + readonly maxVisibleOutputTokens?: number + readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number readonly tools: readonly string[] readonly skills: readonly string[] readonly connections: readonly string[] diff --git a/src/bin/production-application.ts b/src/bin/production-application.ts index f82256a..9133316 100644 --- a/src/bin/production-application.ts +++ b/src/bin/production-application.ts @@ -44,6 +44,9 @@ export function productionConfigForSelection( ...(options.credentialRefResolver === undefined ? {} : { credentialRefResolver: options.credentialRefResolver }), + ...(options.bridgeModelCredential === undefined + ? {} + : { bridgeModelCredential: options.bridgeModelCredential }), } return { profile: selection.profile.profile, @@ -104,9 +107,15 @@ async function productionIntelligence(production: ProductionCompositionConfig): const analysis = await createTraceAnalysisAdapter({ profile: selected.profile, connection: selected.connection, - ...(modelSettings.maxOutputTokens === undefined + ...(modelSettings.maxVisibleOutputTokens === undefined + ? {} + : { maxOutputTokens: modelSettings.maxVisibleOutputTokens }), + ...(modelSettings.maxReasoningTokens === undefined + ? {} + : { maxReasoningTokens: modelSettings.maxReasoningTokens }), + ...(modelSettings.maxTotalOutputTokens === undefined ? {} - : { maxOutputTokens: modelSettings.maxOutputTokens }), + : { maxTotalOutputTokens: modelSettings.maxTotalOutputTokens }), ...(production.connectionOptions ?? {}), }) return { diff --git a/src/bin/production-setup-types.ts b/src/bin/production-setup-types.ts index aec20b1..32af8a9 100644 --- a/src/bin/production-setup-types.ts +++ b/src/bin/production-setup-types.ts @@ -19,6 +19,8 @@ export interface ProductionStartupLoadOptions { readonly cliBridgeEndpoint?: string /** Optional in-memory bridge authorization; never persisted in startup config. */ readonly bridgeAuth?: string + /** Optional request-scoped model credential; key names only, never persisted in startup config. */ + readonly bridgeModelCredential?: ProductionConnectionOptions['bridgeModelCredential'] /** Optional in-memory Tangle authorization; never persisted in startup config. */ readonly tangleAuth?: string /** Discovery timeout for /health and /v1/models. */ diff --git a/src/bin/production-startup.ts b/src/bin/production-startup.ts index 5a3bc8d..8a80c02 100644 --- a/src/bin/production-startup.ts +++ b/src/bin/production-startup.ts @@ -415,6 +415,9 @@ export async function loadProductionStartup( credentialRefResolver: options.credentialRefResolver ?? defaultProductionCredentialRefResolver, }), + ...(options.bridgeModelCredential === undefined + ? {} + : { bridgeModelCredential: options.bridgeModelCredential }), } return { profile, diff --git a/src/bin/runtime-startup-options.ts b/src/bin/runtime-startup-options.ts index efbe785..7b285c9 100644 --- a/src/bin/runtime-startup-options.ts +++ b/src/bin/runtime-startup-options.ts @@ -1,3 +1,4 @@ +import { envKeyProvider } from '@tangle-network/agent-runtime/kernel' import type { CliOptions } from './args.js' import { createProductionCredentialContext, @@ -10,12 +11,24 @@ export interface RuntimeStartupOptions { readonly credentialContext?: ProductionCredentialContext } +const BRIDGE_MODEL_TOKEN_KEY = 'BRAID_CLI_BRIDGE_MODEL_TOKEN' +const BRIDGE_MODEL_BASE_URL_KEY = 'BRAID_CLI_BRIDGE_MODEL_BASE_URL' + export function createRuntimeStartupOptions( options: CliOptions, workspace: string, ): RuntimeStartupOptions { const discoveryTimeoutMs = optionalMilliseconds('BRAID_DISCOVERY_TIMEOUT_MS') const modelValidationTimeoutMs = optionalMilliseconds('BRAID_MODEL_VALIDATION_TIMEOUT_MS') + const bridgeModelToken = process.env[BRIDGE_MODEL_TOKEN_KEY]?.trim() + const bridgeModelCredential = + bridgeModelToken === undefined || bridgeModelToken.length === 0 + ? undefined + : { + key: BRIDGE_MODEL_TOKEN_KEY, + baseUrlKey: BRIDGE_MODEL_BASE_URL_KEY, + provider: envKeyProvider(), + } const base: ProductionStartupLoadOptions = { workspace, ...(options.config === undefined ? {} : { configPath: options.config }), @@ -31,6 +44,7 @@ export function createRuntimeStartupOptions( ...(process.env.BRAID_CLI_BRIDGE_AUTH === undefined ? {} : { bridgeAuth: process.env.BRAID_CLI_BRIDGE_AUTH }), + ...(bridgeModelCredential === undefined ? {} : { bridgeModelCredential }), ...(process.env.BRAID_TANGLE_AUTH === undefined ? process.env.TANGLE_INTELLIGENCE_API_KEY === undefined ? {} diff --git a/src/startup/preview-runtime.ts b/src/startup/preview-runtime.ts index 038a6bc..75d6a62 100644 --- a/src/startup/preview-runtime.ts +++ b/src/startup/preview-runtime.ts @@ -37,7 +37,9 @@ export interface StartupFrameState { readonly model?: { readonly default?: string readonly reasoningEffort?: string - readonly maxOutputTokens?: number + readonly maxVisibleOutputTokens?: number + readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number } } readonly selectedConnectionId: string | null @@ -99,9 +101,15 @@ class StartupFrame implements Component { ...(state.profile.model?.reasoningEffort === undefined ? {} : { effort: state.profile.model.reasoningEffort }), - ...(state.profile.model?.maxOutputTokens === undefined + ...(state.profile.model?.maxVisibleOutputTokens === undefined ? {} - : { maxOutputTokens: state.profile.model.maxOutputTokens }), + : { maxVisibleOutputTokens: state.profile.model.maxVisibleOutputTokens }), + ...(state.profile.model?.maxReasoningTokens === undefined + ? {} + : { maxReasoningTokens: state.profile.model.maxReasoningTokens }), + ...(state.profile.model?.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: state.profile.model.maxTotalOutputTokens }), } this.#theme = theme this.#rows = rows diff --git a/src/views/shared/analysis-model-call-presentation.ts b/src/views/shared/analysis-model-call-presentation.ts index 7e89d34..0b9897e 100644 --- a/src/views/shared/analysis-model-call-presentation.ts +++ b/src/views/shared/analysis-model-call-presentation.ts @@ -42,6 +42,48 @@ export function analysisModelCallLine(call: AnalysisModelCallView): string { return `#${call.sequence} ${route} · ${tokens(call)} · ${cost(call)} · ${latency}` } +/** Renders only measured model-call facts for compact terminal surfaces. */ +export function analysisMeasuredModelCallLine(call: AnalysisModelCallView): string { + const route = + call.model === 'unknown-model' + ? `#${call.sequence}` + : `#${call.sequence} ${call.provider === undefined ? call.model : `${call.provider}/${call.model}`}` + const measured = [measuredTokens(call), measuredCost(call), measuredLatency(call)].filter( + (value): value is string => value !== undefined, + ) + return [route, ...measured].join(' · ') +} + +/** Summarizes only measured model-call facts without filling gaps with labels. */ +export function analysisMeasuredModelCallSummary(calls: readonly AnalysisModelCallView[]): string { + const parts = [`${calls.length} ${calls.length === 1 ? 'call' : 'calls'}`] + const input = calls.filter((call) => call.inputTokens !== undefined) + const output = calls.filter((call) => call.outputTokens !== undefined) + if (input.length > 0 || output.length > 0) { + parts.push( + `tokens ${input.length === calls.length ? '' : '≥'}${sum(input.map((call) => call.inputTokens))} in / ${output.length === calls.length ? '' : '≥'}${sum(output.map((call) => call.outputTokens))} out`, + ) + } + const knownCost = calls.filter( + (call) => call.costUsd !== undefined && call.costStatus !== 'unknown', + ) + if (knownCost.length > 0) { + const estimated = knownCost.some((call) => call.costStatus === 'estimated') + parts.push( + `cost ${estimated ? '~' : ''}$${sum(knownCost.map((call) => call.costUsd)).toFixed(4)}`, + ) + } + const latency = calls.filter((call) => call.latencyMs !== undefined) + if (latency.length > 0) { + parts.push( + `latency ${latency.length === calls.length ? '' : '≥'}${sum(latency.map((call) => call.latencyMs))}ms`, + ) + } + const failures = calls.filter((call) => call.outcome === 'failed').length + if (failures > 0) parts.push(`${failures} failed`) + return parts.join(' · ') +} + export function analysisModelCallSummary(calls: readonly AnalysisModelCallView[]): string { if (calls.length === 0) return '0 model calls reported.' const input = calls.reduce((sum, call) => sum + (call.inputTokens ?? 0), 0) @@ -65,7 +107,7 @@ export function analysisModelCallSummary(calls: readonly AnalysisModelCallView[] : `cost ${costPrefix(estimatedCosts, costGaps)}$${cost.toFixed(4)}${gap(costGaps)}`, latency === 0 && latencyGaps > 0 ? `latency unknown${gap(latencyGaps)}` - : `model ${latencyGaps === 0 ? '' : '≥'}${latency}ms${gap(latencyGaps)}`, + : `latency ${latencyGaps === 0 ? '' : '≥'}${latency}ms${gap(latencyGaps)}`, ...(failures === 0 ? [] : [`${failures} failed`]), ].join(' · ') } @@ -101,6 +143,27 @@ function usd(value: number): string { return `$${value.toFixed(6).replace(/0+$/u, '').replace(/\.$/u, '')}` } +function measuredTokens(call: AnalysisModelCallView): string | undefined { + if (call.inputTokens === undefined && call.outputTokens === undefined) return undefined + const prefix = call.tokensKnown ? '' : '≥' + const input = call.inputTokens === undefined ? undefined : `${prefix}${call.inputTokens} in` + const output = call.outputTokens === undefined ? undefined : `${prefix}${call.outputTokens} out` + return ['tokens', input, output].filter((value): value is string => value !== undefined).join(' ') +} + +function measuredCost(call: AnalysisModelCallView): string | undefined { + if (call.costUsd === undefined || call.costStatus === 'unknown') return undefined + return `cost ${call.costStatus === 'estimated' ? '~' : ''}${usd(call.costUsd)}` +} + +function measuredLatency(call: AnalysisModelCallView): string | undefined { + return call.latencyMs === undefined ? undefined : `latency ${call.latencyMs}ms` +} + +function sum(values: readonly (number | undefined)[]): number { + return values.reduce((total, value) => total + (value ?? 0), 0) +} + function safeModel(value: string | undefined): string | undefined { if (value === undefined) return undefined const safe = sanitizeTerminalText(value).trim() diff --git a/src/views/shared/analysis-presentation.ts b/src/views/shared/analysis-presentation.ts index 0cb75e5..d6084d4 100644 --- a/src/views/shared/analysis-presentation.ts +++ b/src/views/shared/analysis-presentation.ts @@ -1,8 +1,8 @@ import type { AnalysisRecord } from '../../domain/entities.js' import { analysisExecutionView, - analysisModelCallLine, - analysisModelCallSummary, + analysisMeasuredModelCallLine, + analysisMeasuredModelCallSummary, } from './analysis-model-call-presentation.js' import type { AnalysisView } from './models.js' import { sanitizeTerminalText } from './sanitize.js' @@ -169,17 +169,13 @@ export function analysisDocument(analysis: AnalysisView): AnalysisDocument { details.push(`next: ${nextAction}`) } - details.push(section('model use')) const execution = analysis.execution const route = analysisRouteLine(execution) - if (execution?.modelCalls === undefined) { - details.push('Model calls were not reported.') - } else if (execution.modelCalls.length === 0) { - details.push('0 model calls reported.') - } else { - details.push(analysisModelCallSummary(execution.modelCalls)) + if (execution?.modelCalls !== undefined && execution.modelCalls.length > 0) { + details.push(section('model use')) + details.push(analysisMeasuredModelCallSummary(execution.modelCalls)) for (const call of execution.modelCalls) - details.push(`model call ${analysisModelCallLine(call)}`) + details.push(`model call ${analysisMeasuredModelCallLine(call)}`) } if (analysis.error) details.push(`! ${sanitizeTerminalText(analysis.error)}`) diff --git a/src/views/shared/command-registry.ts b/src/views/shared/command-registry.ts index 94d863f..a9027fa 100644 --- a/src/views/shared/command-registry.ts +++ b/src/views/shared/command-registry.ts @@ -109,7 +109,7 @@ const DEFINITIONS: readonly CommandDefinition[] = [ [ 'connection', [], - 'Inspect, create, test, select, or remove a connection', + 'Inspect and manage connections', '/connection [list|create|test|select|remove] [id]', 'connection.select', 'explicit', diff --git a/src/views/shared/models.ts b/src/views/shared/models.ts index cb2b6d8..99c053a 100644 --- a/src/views/shared/models.ts +++ b/src/views/shared/models.ts @@ -201,7 +201,9 @@ export interface RunView { readonly profileDigest?: string readonly model?: string readonly effort?: string - readonly maxOutputTokens?: number + readonly maxVisibleOutputTokens?: number + readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number readonly usage?: UsageView readonly error?: string readonly cursor?: string @@ -546,7 +548,9 @@ export interface BraidViewModel { readonly effort?: string readonly mode?: string } - readonly maxOutputTokens?: number + readonly maxVisibleOutputTokens?: number + readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number readonly connection: string readonly conversationId: string readonly conversationTitle: string diff --git a/src/views/tui/activity-browser.ts b/src/views/tui/activity-browser.ts index 531e97d..67dadf8 100644 --- a/src/views/tui/activity-browser.ts +++ b/src/views/tui/activity-browser.ts @@ -176,17 +176,18 @@ function runContext( : [`execution environment: ${sanitizeTerminalText(run.environmentId)}`]), `model: ${sanitizeTerminalText(target.model)}`, ...(target.effort === undefined ? [] : [`thinking: ${sanitizeTerminalText(target.effort)}`]), - ...(target.maxOutputTokens === undefined + ...(target.maxVisibleOutputTokens === undefined ? [] - : [`max output tokens: ${target.maxOutputTokens}`]), + : [`max visible output tokens: ${target.maxVisibleOutputTokens}`]), + ...(target.maxReasoningTokens === undefined + ? [] + : [`max reasoning tokens: ${target.maxReasoningTokens}`]), + ...(target.maxTotalOutputTokens === undefined + ? [] + : [`max total output tokens: ${target.maxTotalOutputTokens}`]), ...(metrics.length === 0 ? [] : [`usage: ${metrics.join(' · ')}`]), - ...measurementValue('model calls', usage?.llmCalls, usage !== undefined), - ...measurementValue( - 'model latency', - usage?.llmLatencyMs, - usage !== undefined, - (value) => `${Math.round(value)}ms`, - ), + ...measurementValue('model calls', usage?.llmCalls), + ...measurementValue('model latency', usage?.llmLatencyMs, (value) => `${Math.round(value)}ms`), ...measurementStatus('token measurement', usage?.tokenStatus), ...measurementStatus('cost measurement', usage?.costStatus), `history: ${sanitizeTerminalText(run.completeness)}`, @@ -197,16 +198,14 @@ function runContext( function measurementValue( label: string, value: number | undefined, - measurementExists: boolean, format: (value: number) => string = (measured) => String(measured), ): readonly string[] { - if (value !== undefined) return [`${label}: ${format(value)}`] - return measurementExists ? [`${label}: not reported`] : [] + return value === undefined ? [] : [`${label}: ${format(value)}`] } function measurementStatus(label: string, status: string | undefined): readonly string[] { - if (status === undefined) return [] - return [`${label}: ${status === 'unknown' ? 'not reported' : status}`] + if (status === undefined || status === 'unknown') return [] + return [`${label}: ${status}`] } function costLabel(usage: RunView['usage']): string | undefined { diff --git a/src/views/tui/automation-rule-panel.ts b/src/views/tui/automation-rule-panel.ts index 82bba8b..cf1b445 100644 --- a/src/views/tui/automation-rule-panel.ts +++ b/src/views/tui/automation-rule-panel.ts @@ -114,14 +114,14 @@ export class AutomationRulePanel extends Container implements Focusable { this.#interaction !== undefined && ruleCreationReason(this.#interaction) === undefined if (this.#rules.length === 0 && !canCreate) return this.#interaction === undefined - ? 'create from a pending request with Alt+A · esc close' - : 'this request stays manual · esc close' + ? 'create from a pending request with Alt+A · ←/esc close' + : 'this request stays manual · ←/esc close' return [ 'type to filter', ...(this.#onSelect === undefined ? [] : ['enter select']), ...(canCreate ? ['ctrl+n new'] : []), ...(this.#rules.length === 0 ? [] : ['ctrl+a off', 'ctrl+d del']), - 'esc close', + '←/esc close', ].join(' · ') } @@ -168,7 +168,7 @@ export class AutomationRulePanel extends Container implements Focusable { items: scopes.map(scopeItem), theme: this.#theme, maxVisible: 3, - footer: 'type to filter · enter choose · esc back', + footer: 'type to filter · enter choose · ←/esc back', onSelect: (item) => { const scope = parseScope(item.value) if (scope === undefined) return diff --git a/src/views/tui/composer-view.ts b/src/views/tui/composer-view.ts index 9c63cde..df7971a 100644 --- a/src/views/tui/composer-view.ts +++ b/src/views/tui/composer-view.ts @@ -43,7 +43,7 @@ export function composerProjectionFor( return { action: send ? 'send' : 'unavailable', actionLabel: send ? 'send' : 'send unavailable', - hint: 'alt+enter newline · paste', + hint: 'type / for commands · Alt+Enter newline · paste', } } @@ -68,7 +68,7 @@ export function composerProjectionFor( action, actionLabel, ...(queuePosition === undefined ? {} : { queuePosition }), - hint: 'alt+enter newline · paste', + hint: 'type / for commands · Alt+Enter newline · paste', } } @@ -89,7 +89,7 @@ export class ComposerView extends Container { #projection: ComposerProjection = { action: 'send', actionLabel: 'send', - hint: 'alt+enter newline · paste', + hint: 'type / for commands · Alt+Enter newline · paste', } #mode: ComposerMode = 'queue' @@ -123,11 +123,22 @@ export class ComposerView extends Container { body[0] = promptBodyLine(body[0], this.#theme, promptActionLabel(this.#projection)) } const autocomplete = lines.slice(bottomBorder + 1) - if (autocomplete.length === 0) return body - return [...body, composerBorderLine(width, this.#projection.hint, this.#theme), ...autocomplete] + const topRule = composerTopRule(width, this.#editor.borderColor) + if (autocomplete.length === 0) return [topRule, ...body] + return [ + topRule, + ...body, + composerBorderLine(width, this.#projection.hint, this.#theme), + ...autocomplete, + ] } } +function composerTopRule(width: number, borderColor: (text: string) => string): string { + const safeWidth = Math.max(1, Math.floor(width)) + return borderColor('─'.repeat(safeWidth)) +} + function boundedEditorBody(body: readonly string[], terminalRows: number, width: number): string[] { const bodyBudget = Math.max(MIN_USABLE_ROWS, composerRowBudget(terminalRows) - 2) const minimumBodyRows = Math.min(MIN_USABLE_ROWS, bodyBudget) diff --git a/src/views/tui/configuration-presenters.ts b/src/views/tui/configuration-presenters.ts index c1161ab..5d0f581 100644 --- a/src/views/tui/configuration-presenters.ts +++ b/src/views/tui/configuration-presenters.ts @@ -26,13 +26,10 @@ export function profileItems( (activeId === undefined && matchingNames.length === 1 && profile.name === activeName) ? `✓ ${safe(profile.name)}` : safe(profile.name), - description: [ + description: `· ${[ profile.source.trusted ? 'trusted' : 'untrusted source', profile.source.writable ? 'writable' : 'read-only', - safe(profile.source.label), - profile.runner === undefined ? 'runner default' : safe(profile.runner), - profile.model === undefined ? 'model default' : safe(profile.model), - ].join(' · '), + ].join(' · ')}`, })) } @@ -64,8 +61,9 @@ export function connectionItems( export function profileDetailLines(profile: ProfileSummary | undefined): string[] { if (profile === undefined) return ['No profile details loaded.'] + const source = profileSourceDetail(profile) return [ - `source ${safe(profile.source.label)} · ${profile.source.trusted ? 'trusted' : 'untrusted'} · ${profile.source.writable ? 'writable' : 'read-only'}`, + `${source === undefined ? '' : `${source} · `}${profile.source.trusted ? 'trusted' : 'untrusted'} · ${profile.source.writable ? 'writable' : 'read-only'}`, `runner ${safe(profile.runner ?? 'provider default')} · model ${safe(profile.model ?? 'provider default')}`, profileModelControls(profile), `digest ${shortDigest(profile.digest)}`, @@ -74,16 +72,28 @@ export function profileDetailLines(profile: ProfileSummary | undefined): string[ export function profileCompactDetail(profile: ProfileSummary | undefined): string { if (profile === undefined) return 'No profile details loaded.' + const source = profileSourceDetail(profile) return [ `runner ${safe(profile.runner ?? 'provider default')}`, `model ${safe(profile.model ?? 'provider default')}`, profileModelControls(profile), + ...(source === undefined ? [] : [source]), profile.source.trusted ? 'trusted' : 'untrusted source', profile.source.writable ? 'writable' : 'read-only', `digest ${shortDigest(profile.digest)}`, ].join(' · ') } +function profileSourceDetail(profile: ProfileSummary): string | undefined { + if ( + profile.source.kind === 'inline' && + profile.source.reference === 'braid:active' && + profile.source.label === profile.name + ) + return undefined + return `source ${safe(profile.source.label)}` +} + export function connectionDetailLines(connection: ConnectionSummary | undefined): string[] { if (connection === undefined) return ['No connection details loaded.'] const verification = connection.modelVerification @@ -173,6 +183,12 @@ export function actionMessage( export const REFRESH_TIMEOUT = Symbol('refresh-timeout') +const tokenLimitKeys = [ + 'maxVisibleOutputTokens', + 'maxReasoningTokens', + 'maxTotalOutputTokens', +] as const + export async function within( promise: Promise, timeoutMs: number, @@ -202,10 +218,11 @@ function isProfileSummary(value: unknown): value is ProfileSummary { (value.runner !== undefined && typeof value.runner !== 'string') || (value.model !== undefined && typeof value.model !== 'string') || (value.reasoningEffort !== undefined && typeof value.reasoningEffort !== 'string') || - (value.maxOutputTokens !== undefined && - (typeof value.maxOutputTokens !== 'number' || - !Number.isSafeInteger(value.maxOutputTokens) || - value.maxOutputTokens <= 0)) + tokenLimitKeys.some( + (key) => + value[key] !== undefined && + (typeof value[key] !== 'number' || !Number.isSafeInteger(value[key]) || value[key] <= 0), + ) ) return false const source = value.source @@ -219,11 +236,21 @@ function isProfileSummary(value: unknown): value is ProfileSummary { function profileModelControls(profile: ProfileSummary): string { const effort = safe(profile.reasoningEffort ?? 'provider default') - const output = - profile.maxOutputTokens === undefined - ? 'provider default' - : `${profile.maxOutputTokens.toLocaleString('en-US')} tokens` - return `thinking ${effort} · max output ${output}` + const limits = [ + profile.maxVisibleOutputTokens === undefined + ? undefined + : `visible ${profile.maxVisibleOutputTokens.toLocaleString('en-US')}`, + profile.maxReasoningTokens === undefined + ? undefined + : `reasoning ${profile.maxReasoningTokens.toLocaleString('en-US')}`, + profile.maxTotalOutputTokens === undefined + ? undefined + : `total ${profile.maxTotalOutputTokens.toLocaleString('en-US')}`, + ].filter((value): value is string => value !== undefined) + return [ + `thinking ${effort}`, + ...(limits.length === 0 ? ['limits provider default'] : [`limits ${limits.join(' · ')}`]), + ].join(' · ') } function isConnectionSummary(value: unknown): value is ConnectionSummary { diff --git a/src/views/tui/configuration-review.ts b/src/views/tui/configuration-review.ts index 252a7f2..36fef53 100644 --- a/src/views/tui/configuration-review.ts +++ b/src/views/tui/configuration-review.ts @@ -2,6 +2,7 @@ import { type Component, Container, type Focusable, + matchesKey, type SelectItem, SelectList, Text, @@ -27,6 +28,7 @@ export interface ConfigurationReviewOptions { */ export class ConfigurationReview extends Container implements Focusable { readonly #list: SelectList + readonly #onCancel: () => void #focused = false constructor(options: ConfigurationReviewOptions) { @@ -34,13 +36,14 @@ export class ConfigurationReview extends Container implements Focusable { this.#list = new SelectList([...options.items], 4, options.theme.select) this.#list.onSelect = options.onSelect this.#list.onCancel = options.onCancel + this.#onCancel = options.onCancel this.addChild(new Text(options.theme.brand(options.title ?? 'review and start'), 1, 0)) if (options.error !== undefined) { this.addChild(new Text(options.theme.danger(sanitizeTerminalText(options.error)), 1, 0)) } this.addChild(new ReviewSummary(options.theme, options.summary, options.compactSummary)) this.addChild(this.#list) - this.addChild(new Text(options.theme.muted('enter choose · ↑↓ move · esc cancel'), 1, 0)) + this.addChild(new Text(options.theme.muted('enter choose · ↑↓ move · ←/esc cancel'), 1, 0)) } get focused(): boolean { @@ -52,6 +55,10 @@ export class ConfigurationReview extends Container implements Focusable { } handleInput(data: string): void { + if (matchesKey(data, 'left')) { + this.#onCancel() + return + } this.#list.handleInput(data) } } diff --git a/src/views/tui/configuration-wizard-presentation.ts b/src/views/tui/configuration-wizard-presentation.ts index 3b34a06..02b8d97 100644 --- a/src/views/tui/configuration-wizard-presentation.ts +++ b/src/views/tui/configuration-wizard-presentation.ts @@ -42,8 +42,8 @@ export function configurationExplanation(state: ConfigurationSessionState): stri export function configurationFooter(state: ConfigurationSessionState, busy: boolean): string { if (busy) return 'waiting for the selected connection' - if (state.step === 'confirm') return 'enter apply · arrows · esc cancel' - return 'filter · enter choose · esc cancel' + if (state.step === 'confirm') return 'enter apply · arrows · ←/esc cancel' + return 'filter · enter choose · ←/esc cancel' } export function configurationItems( @@ -54,7 +54,11 @@ export function configurationItems( if (state.step === 'profile') { if (state.profiles.length === 0) { return [ - { value: CANCEL_CONFIGURATION, label: 'No profiles available', description: 'esc close' }, + { + value: CANCEL_CONFIGURATION, + label: 'No profiles available', + description: '←/esc close', + }, ] } return state.profiles.map((profile) => ({ @@ -86,7 +90,7 @@ export function configurationItems( } if (state.step === 'confirm' || state.step === 'complete') { if (state.step === 'complete' && !busy && commitError === undefined) { - return [{ value: CANCEL_CONFIGURATION, label: 'Close', description: 'esc close' }] + return [{ value: CANCEL_CONFIGURATION, label: 'Close', description: '←/esc close' }] } return [ { @@ -111,7 +115,7 @@ export function configurationItems( }, ] } - return [{ value: CANCEL_CONFIGURATION, label: 'Close', description: 'esc close' }] + return [{ value: CANCEL_CONFIGURATION, label: 'Close', description: '←/esc close' }] } export function reviewSummary( diff --git a/src/views/tui/configuration-wizard.ts b/src/views/tui/configuration-wizard.ts index 21dd195..1f3f024 100644 --- a/src/views/tui/configuration-wizard.ts +++ b/src/views/tui/configuration-wizard.ts @@ -7,14 +7,14 @@ import { type ConfigurationSessionState, } from '../../app/configuration-session.js' import { sanitizeTerminalText } from '../shared/sanitize.js' -import { ConfigurationReview } from './configuration-review.js' import { - ConfigurationCredential, type ConfigurationCommit, + ConfigurationCredential, configurationNeedsCredential, mountConfigurationCredential, PreparedCredential, } from './configuration-credential.js' +import { ConfigurationReview } from './configuration-review.js' import { APPLY_SELECTION, BACK_TO_CONNECTION, @@ -134,7 +134,7 @@ export class ConfigurationWizard extends Container implements Focusable { : configurationTitle(state, this.#busy, this.#commitError), ...(this.#commitError === undefined ? {} : { error: this.#commitError }), items: applied - ? [{ value: CANCEL_CONFIGURATION, label: 'Close', description: 'esc close' }] + ? [{ value: CANCEL_CONFIGURATION, label: 'Close', description: '←/esc close' }] : configurationItems(state, this.#busy, this.#commitError), onSelect: (item) => this.#select(item.value), onCancel: () => this.#cancel(), @@ -179,8 +179,8 @@ export class ConfigurationWizard extends Container implements Focusable { if (state.profiles.length === 0 || state.connections.length === 0) { this.#commitError = state.profiles.length === 0 - ? 'No AgentProfiles are available. Press esc to leave setup.' - : 'No connections are available. Press esc to leave setup.' + ? 'No AgentProfiles are available. Press ←/esc to leave setup.' + : 'No connections are available. Press ←/esc to leave setup.' this.#renderStage(state) return } diff --git a/src/views/tui/connection-metadata-editor-actions.ts b/src/views/tui/connection-metadata-editor-actions.ts index 4a75202..87698a4 100644 --- a/src/views/tui/connection-metadata-editor-actions.ts +++ b/src/views/tui/connection-metadata-editor-actions.ts @@ -20,7 +20,7 @@ export function createConnectionMetadataReviewList( options: ConnectionMetadataReviewListOptions, ): SelectList { const items: readonly SelectItem[] = options.applied - ? [{ value: CLOSE_EDITOR, label: 'Close', description: 'esc close' }] + ? [{ value: CLOSE_EDITOR, label: 'Close', description: '←/esc close' }] : [ { value: APPLY_DRAFT, diff --git a/src/views/tui/connection-metadata-editor-rendering.ts b/src/views/tui/connection-metadata-editor-rendering.ts index e09edd5..1b7cd4e 100644 --- a/src/views/tui/connection-metadata-editor-rendering.ts +++ b/src/views/tui/connection-metadata-editor-rendering.ts @@ -57,7 +57,7 @@ function kindChildren(state: ConnectionMetadataEditorRenderState): readonly Comp new Text(state.theme.accent('connection kind'), 1, 0), state.kindList, new Spacer(1), - new Text(state.theme.muted('↑↓ choose · enter next · esc cancel'), 1, 0), + new Text(state.theme.muted('↑↓ choose · enter next · ←/esc cancel'), 1, 0), ] } @@ -97,10 +97,10 @@ function reviewChildren(state: ConnectionMetadataEditorRenderState): readonly Co new Text( state.theme.muted( state.applied - ? 'enter close · esc close' + ? 'enter close · ←/esc close' : state.busy ? 'saving…' - : '↑↓ choose · enter continue / back · esc cancel', + : '↑↓ choose · enter continue / back · ←/esc cancel', ), 1, 0, diff --git a/src/views/tui/connection-metadata-editor.ts b/src/views/tui/connection-metadata-editor.ts index 4405f71..09333d1 100644 --- a/src/views/tui/connection-metadata-editor.ts +++ b/src/views/tui/connection-metadata-editor.ts @@ -1,4 +1,10 @@ -import { Container, type Focusable, type Input, SelectList } from '@earendil-works/pi-tui' +import { + Container, + type Focusable, + type Input, + matchesKey, + SelectList, +} from '@earendil-works/pi-tui' import { sanitizeTerminalText } from '../shared/sanitize.js' import { APPLY_DRAFT, @@ -89,10 +95,18 @@ export class ConnectionMetadataEditor extends Container implements Focusable { handleInput(data: string): void { if (this.#closed || this.#busy) return if (this.#stage === 'kind') { + if (matchesKey(data, 'left')) { + this.#cancel() + return + } this.#kindList.handleInput(data) return } if (this.#stage === 'review') { + if (matchesKey(data, 'left')) { + this.#cancel() + return + } this.#reviewList?.handleInput(data) return } diff --git a/src/views/tui/connection-setup.ts b/src/views/tui/connection-setup.ts index d09f20d..cd40b07 100644 --- a/src/views/tui/connection-setup.ts +++ b/src/views/tui/connection-setup.ts @@ -101,8 +101,8 @@ export class ConnectionSetupViewPanel extends Container implements Focusable { maxVisible: 5, footer: this.#onCreate === undefined - ? 'enter select · ^T test · esc close' - : 'enter select · ^N new · ^T test · ^D remove · esc close', + ? 'enter select · ^T test · ←/esc close' + : 'enter select · ^N new · ^T test · ^D remove · ←/esc close', theme: this.#theme, onSelect: (item) => void this.#select(item), onAction: (key, item) => { diff --git a/src/views/tui/conversation-dialogs.ts b/src/views/tui/conversation-dialogs.ts index ec167d6..e9e4a8f 100644 --- a/src/views/tui/conversation-dialogs.ts +++ b/src/views/tui/conversation-dialogs.ts @@ -52,7 +52,7 @@ export class ConversationConfirmation extends Container implements Focusable { this.addChild(this.#detail) this.addChild(this.#error) this.addChild(new Spacer(1)) - this.addChild(new TruncatedText(this.#theme.muted('enter/y confirm · n/esc cancel'), 1, 0)) + this.addChild(new TruncatedText(this.#theme.muted('enter/y confirm · n/←/esc cancel'), 1, 0)) } get focused(): boolean { @@ -71,7 +71,12 @@ export class ConversationConfirmation extends Container implements Focusable { handleInput(data: string): void { if (this.#submitted) return - if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c') || matchesKey(data, 'n')) { + if ( + matchesKey(data, 'escape') || + matchesKey(data, 'ctrl+c') || + matchesKey(data, 'left') || + matchesKey(data, 'n') + ) { this.#onCancel() return } diff --git a/src/views/tui/conversation-overlay-actions.ts b/src/views/tui/conversation-overlay-actions.ts index 83a2039..039cdae 100644 --- a/src/views/tui/conversation-overlay-actions.ts +++ b/src/views/tui/conversation-overlay-actions.ts @@ -44,12 +44,12 @@ export class ConversationOverlayActions { conversationId: string | undefined, ): void { if (conversationId === undefined) { - selector.setFooter('select a conversation first · esc close') + selector.setFooter('select a conversation first · ←/esc close') return } const conversation = this.#conversation(conversationId) if (conversation === undefined) { - selector.setFooter('selected conversation disappeared · refresh with esc and ctrl+o') + selector.setFooter('selected conversation disappeared · refresh with ←/esc and ctrl+o') return } if (action === 'rename') this.#openRename(selector, conversation) @@ -60,7 +60,7 @@ export class ConversationOverlayActions { async openConversation(selector: SearchableSelector, conversationId: string): Promise { const conversation = this.#conversation(conversationId) if (conversation === undefined) { - selector.setFooter('conversation is no longer available · esc close') + selector.setFooter('conversation is no longer available · ←/esc close') return } selector.setFooter('opening conversation…') @@ -70,7 +70,7 @@ export class ConversationOverlayActions { }) if (result.kind === 'accepted') this.#modals.closeTop() else { - selector.setFooter('open failed · query and selection preserved · esc close') + selector.setFooter('open failed · query and selection preserved · ←/esc close') this.#showResultError('Open failed', result, false) } } diff --git a/src/views/tui/conversation-overlays.ts b/src/views/tui/conversation-overlays.ts index a60a0b1..90e7f6b 100644 --- a/src/views/tui/conversation-overlays.ts +++ b/src/views/tui/conversation-overlays.ts @@ -33,8 +33,7 @@ export class ConversationOverlayController { items: conversationItems(view), theme: this.#actions.theme, maxVisible: 8, - footer: - 'type to filter · enter to choose · esc to close · ^R rename · ^A archive · ^D delete', + footer: 'type to filter · enter to choose · ←/esc close · ^R rename · ^A archive · ^D delete', onSelect: (item) => void this.#actions.openConversation(selector, item.value), onAction: (key, item) => this.#actions.conversationAction(selector, key, item?.value), onCancel: () => this.#modals.closeTop(), @@ -55,7 +54,7 @@ export class ConversationOverlayController { items, theme: this.#actions.theme, maxVisible: 8, - footer: 'filter · enter switch branch · esc close', + footer: 'filter · enter switch branch · ←/esc close', onSelect: (item) => void this.#actions.openBranch(selector, item.value), onCancel: () => this.#modals.closeTop(), }) diff --git a/src/views/tui/entity-browser-layout.ts b/src/views/tui/entity-browser-layout.ts new file mode 100644 index 0000000..664483e --- /dev/null +++ b/src/views/tui/entity-browser-layout.ts @@ -0,0 +1,85 @@ +import { visibleWidth } from '@earendil-works/pi-tui' + +export interface EntityBrowserFooterOptions { + readonly mode: 'wide' | 'list' | 'detail' + readonly width: number + readonly rowCount: number + readonly bodyRows: number + readonly selectedIndex: number + readonly pages: number + readonly page: number + readonly filterHint?: string +} + +export function entityBrowserFooter(options: EntityBrowserFooterOptions): string { + const filters = filterVariants(options.filterHint) + if (options.mode === 'wide') { + const page = options.pages > 1 ? `page ${options.page + 1}/${options.pages}` : undefined + const keys = + options.rowCount === 1 + ? ['PgUp/PgDn detail · ←/esc close', 'PgUp/PgDn · ←/esc close', '←/esc close'] + : options.width < 120 + ? ['↑↓ select · PgUp/PgDn detail · ←/esc close', '↑↓ · Pg · ←/esc close', '←/esc close'] + : [ + '↑↓ select · PgUp/PgDn detail · home/end jump · ←/esc close', + '↑↓ select · PgUp/PgDn detail · ←/esc close', + '↑↓ · Pg · ←/esc close', + '←/esc close', + ] + return fitFooter(candidates(keys, page, filters), options.width) + } + if (options.mode === 'list') { + const suffix = + options.rowCount > options.bodyRows + ? `${options.selectedIndex + 1}/${options.rowCount}` + : undefined + const keys = + options.width < 52 + ? ['↑↓ move · → open · ←/esc close', '↑↓ · → open · ←/esc close', '←/esc close'] + : ['↑↓ move · enter/→ open · ←/esc close', '↑↓ move · → open · ←/esc close', '←/esc close'] + return fitFooter(candidates(keys, suffix, filters), options.width) + } + const page = `page ${options.page + 1}/${options.pages}` + const keys = + options.width < 52 + ? options.pages > 1 + ? ['↑↓ · Pg · ←/esc back', '←/esc back'] + : ['↑↓ item · ←/esc back', '↑↓ · ←/esc back', '←/esc back'] + : options.width < 64 + ? options.pages > 1 + ? ['↑↓ · PgUp/PgDn · ←/esc back', '↑↓ · Pg · ←/esc back', '←/esc back'] + : ['↑↓ previous/next · ←/esc back', '↑↓ · ←/esc back', '←/esc back'] + : [ + '↑↓ previous/next · PgUp/PgDn page · ←/esc back', + '↑↓ previous/next · PgUp/PgDn · ←/esc back', + '↑↓ · Pg · ←/esc back', + '←/esc back', + ] + return fitFooter(candidates(keys, options.pages > 1 ? page : undefined, filters), options.width) +} + +function filterVariants(filter: string | undefined): readonly (string | undefined)[] { + if (filter === undefined || filter.length === 0) return [undefined] + const compact = filter.replace(/^tab filter:/u, 'tab:') + return compact === filter ? [filter, undefined] : [filter, compact, undefined] +} + +function candidates( + keys: readonly string[], + page: string | undefined, + filters: readonly (string | undefined)[], +): string[] { + return keys.flatMap((key) => [ + ...(page === undefined ? [] : filters.map((filter) => joinParts(key, page, filter))), + ...filters.map((filter) => joinParts(key, undefined, filter)), + ]) +} + +function joinParts(...parts: readonly (string | undefined)[]): string { + return parts.filter((part): part is string => part !== undefined && part.length > 0).join(' · ') +} + +function fitFooter(values: readonly string[], width: number): string { + const available = Math.max(1, width - 2) + return values.find((value) => visibleWidth(value) <= available) ?? values.at(-1) ?? '' +} diff --git a/src/views/tui/entity-browser.ts b/src/views/tui/entity-browser.ts index 55dd924..9c0b00a 100644 --- a/src/views/tui/entity-browser.ts +++ b/src/views/tui/entity-browser.ts @@ -7,6 +7,7 @@ import { wrapTextWithAnsi, } from '@earendil-works/pi-tui' import { sanitizeTerminalText } from '../shared/sanitize.js' +import { entityBrowserFooter } from './entity-browser-layout.js' import { omitUnreportedCostAndLatency } from './measurement-display.js' import type { ModalBackTarget } from './modal-coordinator.js' import type { BraidTheme } from './theme.js' @@ -283,48 +284,34 @@ export class EntityBrowser extends Container implements Focusable, ModalBackTarg ? this.#theme.brand(`${title} · ${document.rows.length}`) : `${this.#theme.brand(title)} ${this.#theme.muted('›')} ${this.#theme.accent(sanitizeTerminalText(selected.title))}` const context = - document.context === undefined - ? undefined - : this.#theme.muted(sanitizeTerminalText(document.context)) + document.context === undefined ? undefined : sanitizeTerminalText(document.context) return this.#line(this.#withContext(primary, context, width), width) } #footer(document: EntityBrowserDocument, width: number): string { - const filter = - document.filterHint === undefined ? '' : ` · ${sanitizeTerminalText(document.filterHint)}` - if (this.#usesWideBrowser(document, width)) { - const pages = this.#detailPageCount(document, width) - const page = pages > 1 ? ` · page ${this.#page + 1}/${pages}` : '' - const keys = - document.rows.length === 1 - ? 'PgUp/PgDn detail · ←/esc close' - : width < 120 - ? '↑↓ select · PgUp/PgDn detail · ←/esc close' - : '↑↓ select · PgUp/PgDn detail · home/end jump · ←/esc close' - return this.#line(this.#theme.muted(`${keys}${page}${filter}`), width) - } - if (this.#mode === 'list') { - const suffix = - document.rows.length > this.#bodyRows() - ? ` · ${this.#selectedIndex + 1}/${document.rows.length}` - : '' - const keys = - width < 52 ? '↑↓ move · → open · ←/esc close' : '↑↓ move · enter/→ open · ←/esc close' - return this.#line(this.#theme.muted(`${keys}${suffix}${filter}`), width) - } const pages = this.#detailPageCount(document, width) - const page = `page ${this.#page + 1}/${pages}` - const keys = - width < 52 - ? pages > 1 - ? `${page} · Pg · ↑↓ item · ←/esc back` - : '↑↓ item · ←/esc back' - : width < 64 - ? pages > 1 - ? `${page} · PgUp/PgDn · ↑↓ item · ←/esc back` - : '↑↓ previous/next · ←/esc back' - : `↑↓ previous/next · PgUp/PgDn page · ←/esc back${pages > 1 ? ` · ${page}` : ''}` - return this.#line(this.#theme.muted(`${keys}${filter}`), width) + const mode = this.#usesWideBrowser(document, width) + ? 'wide' + : this.#mode === 'list' + ? 'list' + : 'detail' + return this.#line( + this.#theme.muted( + entityBrowserFooter({ + mode, + width, + rowCount: document.rows.length, + bodyRows: this.#bodyRows(), + selectedIndex: this.#selectedIndex, + pages, + page: this.#page, + ...(document.filterHint === undefined + ? {} + : { filterHint: sanitizeTerminalText(document.filterHint) }), + }), + ), + width, + ) } #bodyRows(): number { @@ -381,9 +368,14 @@ export class EntityBrowser extends Container implements Focusable, ModalBackTarg #withContext(primary: string, context: string | undefined, width: number): string { if (context === undefined) return primary - const available = Math.max(1, width - 1) - const gap = available - visibleWidth(primary) - visibleWidth(context) - return gap >= 3 ? `${primary}${' '.repeat(gap)}${context}` : primary + const available = Math.max(1, width - 2) + const parts = context.split(' · ').filter((part) => part.length > 0) + for (let count = parts.length; count > 0; count -= 1) { + const candidate = this.#theme.muted(parts.slice(0, count).join(' · ')) + const gap = available - visibleWidth(primary) - visibleWidth(candidate) + if (gap >= 3) return `${primary}${' '.repeat(gap)}${candidate}` + } + return primary } #usesSplitView(width: number): boolean { diff --git a/src/views/tui/execution-target.ts b/src/views/tui/execution-target.ts index 0b28e49..d9f452e 100644 --- a/src/views/tui/execution-target.ts +++ b/src/views/tui/execution-target.ts @@ -7,8 +7,11 @@ export interface ExecutionTargetView { readonly profileDigest?: string readonly runner: string readonly model: string + readonly backend?: string readonly effort?: string - readonly maxOutputTokens?: number + readonly maxVisibleOutputTokens?: number + readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number readonly connection: string readonly connectionId?: string readonly environment?: EnvironmentView @@ -98,7 +101,15 @@ function profileTarget(view: BraidViewModel): ExecutionTargetView { runner: view.runner, model: view.model, ...(view.effort === undefined ? {} : { effort: view.effort }), - ...(view.maxOutputTokens === undefined ? {} : { maxOutputTokens: view.maxOutputTokens }), + ...(view.maxVisibleOutputTokens === undefined + ? {} + : { maxVisibleOutputTokens: view.maxVisibleOutputTokens }), + ...(view.maxReasoningTokens === undefined + ? {} + : { maxReasoningTokens: view.maxReasoningTokens }), + ...(view.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: view.maxTotalOutputTokens }), connection: view.connection, }) } @@ -108,6 +119,7 @@ function runTarget(view: BraidViewModel, run: RunView): ExecutionTargetView { run.environmentId === undefined ? undefined : view.environments.find((candidate) => candidate.id === run.environmentId) + const backend = run.provider ?? environment?.provider return Object.freeze({ source: 'run', runId: run.id, @@ -115,8 +127,15 @@ function runTarget(view: BraidViewModel, run: RunView): ExecutionTargetView { ...(run.profileDigest === undefined ? {} : { profileDigest: run.profileDigest }), runner: run.runner ?? view.runner, model: run.model ?? run.usage?.model ?? view.model, + ...(backend === undefined ? {} : { backend }), ...(run.effort === undefined ? {} : { effort: run.effort }), - ...(run.maxOutputTokens === undefined ? {} : { maxOutputTokens: run.maxOutputTokens }), + ...(run.maxVisibleOutputTokens === undefined + ? {} + : { maxVisibleOutputTokens: run.maxVisibleOutputTokens }), + ...(run.maxReasoningTokens === undefined ? {} : { maxReasoningTokens: run.maxReasoningTokens }), + ...(run.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: run.maxTotalOutputTokens }), connection: run.connection ?? run.connectionId ?? 'not connected', ...(run.connectionId === undefined ? {} : { connectionId: run.connectionId }), ...(environment === undefined ? {} : { environment }), diff --git a/src/views/tui/interaction-presentation.ts b/src/views/tui/interaction-presentation.ts index 1fbe577..f66f673 100644 --- a/src/views/tui/interaction-presentation.ts +++ b/src/views/tui/interaction-presentation.ts @@ -118,11 +118,10 @@ export function interactionHeading(interaction: InteractionView): string { } export function runContext(interaction: InteractionView): string { - const requester = [interaction.profileName, interaction.runner] + return [interaction.profileName, interaction.runner] .map((value) => (value === undefined ? '' : sanitizeTerminalText(value))) .filter((value) => value.length > 0) - .join(' @ ') - return [requester, `run ${shortIdentifier(interaction.runId)}`].filter(Boolean).join(' · ') + .join(' · ') } export function interactionSubjectComponents( @@ -171,7 +170,7 @@ export function answerHelp(interaction: InteractionView): string { if (hasApproval && rejection) return 'answer: y approve · n reject' if (hasApproval) return 'answer: y yes' if (rejection) return 'answer: n reject' - return 'answer: esc cancel' + return 'answer: ←/esc cancel' } if (spec.kind === 'unknown') return `answer: ${sanitizeTerminalText(spec.label)}` if (spec.kind === 'form') return `answer: JSON · ${spec.fields.length} field(s)` @@ -192,7 +191,7 @@ export function interactionFooter(interaction: InteractionView, canAutomate: boo : interaction.answerSpec.kind === 'select' ? ['↑↓ move', 'enter choose'] : ['enter submit'] - if (cancellationOutcome(interaction) !== undefined) parts.push('esc cancel') + if (cancellationOutcome(interaction) !== undefined) parts.push('←/esc cancel') if (canAutomate && !isSecretInteraction(interaction)) parts.push('alt+a automate') return parts.join(' · ') } @@ -207,8 +206,3 @@ function outcomeKeyLabel(outcome: InteractionOutcome): string { if (outcome === 'revise') return 'revise' return 'cancel' } - -function shortIdentifier(value: string): string { - const safe = sanitizeTerminalText(value) - return safe.length <= 20 ? safe : `${safe.slice(0, 12)}…${safe.slice(-6)}` -} diff --git a/src/views/tui/interaction.ts b/src/views/tui/interaction.ts index f03fb46..5c213e0 100644 --- a/src/views/tui/interaction.ts +++ b/src/views/tui/interaction.ts @@ -155,11 +155,7 @@ export class InteractionShell extends Container implements Focusable { this.#onAutomate(response) return } - if ( - matchesKey(data, 'escape') || - matchesKey(data, 'ctrl+c') || - (matchesKey(data, 'left') && this.#decisions) - ) { + if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c') || matchesKey(data, 'left')) { this.#cancel() return } diff --git a/src/views/tui/modal-coordinator.ts b/src/views/tui/modal-coordinator.ts index 552227b..53fe0ea 100644 --- a/src/views/tui/modal-coordinator.ts +++ b/src/views/tui/modal-coordinator.ts @@ -14,6 +14,7 @@ export interface ModalBackTarget { interface ModalEntry { readonly component: Component readonly handle: OverlayHandle + readonly fullScreen: boolean readonly onClose?: () => void } @@ -32,13 +33,19 @@ export class ModalCoordinator { if (preempt) this.closeTop() const { fullScreenBelow = 80, onClose, ...overlayOptions } = options const layout = layoutFor(this.#tui.terminal.columns, this.#tui.terminal.rows) + const fullScreen = layout.overlayFullScreen || layout.columns < fullScreenBelow const handle = this.#tui.showOverlay(component, { ...overlayOptions, - ...(layout.overlayFullScreen || layout.columns < fullScreenBelow + ...(fullScreen ? { width: '100%', maxHeight: '100%', anchor: 'top-left' as const, margin: 0 } : {}), }) - this.#entries.push({ component, handle, ...(onClose === undefined ? {} : { onClose }) }) + this.#entries.push({ + component, + handle, + fullScreen, + ...(onClose === undefined ? {} : { onClose }), + }) this.#notifyVisibility() return handle } @@ -67,6 +74,13 @@ export class ModalCoordinator { return true } + backOrCloseIfFullScreen(): boolean { + const entry = this.#top() + if (entry === undefined || !entry.fullScreen) return false + this.backOrClose() + return true + } + closeAll(): void { while (this.#entries.length > 0) this.closeTop() } diff --git a/src/views/tui/profile-editor.ts b/src/views/tui/profile-editor.ts index e2f7641..3d5c69e 100644 --- a/src/views/tui/profile-editor.ts +++ b/src/views/tui/profile-editor.ts @@ -1,4 +1,4 @@ -import { Container, type Focusable, type SelectItem } from '@earendil-works/pi-tui' +import { Container, type Focusable, matchesKey, type SelectItem } from '@earendil-works/pi-tui' import type { ProfileSummary } from '../../app/profiles.js' import type { BraidIntent, BraidUiController, UiDispatchResult } from '../shared/intents.js' import type { BraidViewModel } from '../shared/models.js' @@ -14,6 +14,7 @@ import { within, } from './configuration-presenters.js' import { ResponsiveText } from './configuration-responsive-text.js' +import { profileCompatibilityTextLines } from './profile-compatibility.js' import { profileErrorMessage, profileItemName, @@ -23,7 +24,6 @@ import { validateProfileIntent, } from './profile-editor-actions.js' import { profileEditorChildren } from './profile-editor-rendering.js' -import { profileCompatibilityTextLines } from './profile-compatibility.js' import { SearchableSelector } from './selector.js' import type { BraidTheme } from './theme.js' @@ -43,6 +43,7 @@ export class ProfileEditorViewPanel extends Container implements Focusable { readonly #onCancel: (() => void) | undefined readonly #status = new ResponsiveText('', 1, 0) readonly #detail = new ResponsiveText('', 1, 0) + readonly #footer = new ResponsiveText('', 1, 0) #selector: SearchableSelector | undefined #profiles: readonly ProfileSummary[] = [] #focused = false @@ -78,6 +79,10 @@ export class ProfileEditorViewPanel extends Container implements Focusable { } handleInput(data: string): void { + if (matchesKey(data, 'escape') || matchesKey(data, 'left')) { + this.#onCancel?.() + return + } this.#selector?.handleInput(data) } @@ -91,11 +96,11 @@ export class ProfileEditorViewPanel extends Container implements Focusable { #buildSelector(query: string): void { if (this.#controller === undefined) return this.#selector = new SearchableSelector({ - title: 'profiles', + title: 'switch profile', items: [], query, maxVisible: 5, - footer: 'enter select · ^V validate · esc close', + footer: 'enter select · ^V validate · ←/esc close', theme: this.#theme, onSelect: (item) => void this.#select(item), onAction: (key, item) => { @@ -149,7 +154,7 @@ export class ProfileEditorViewPanel extends Container implements Focusable { ? 'No profiles found' : active === undefined ? 'Profiles ready · choose one' - : `Active profile · ${safe(active.name)}`), + : safe(active.name)), ) } @@ -247,7 +252,11 @@ export class ProfileEditorViewPanel extends Container implements Focusable { this.clear() this.addChild(this.#status) this.addChild(this.#detail) - if (this.#selector) this.addChild(this.#selector) + if (this.#selector && this.#profiles.length !== 1) this.addChild(this.#selector) + if (this.#profiles.length === 1) { + this.#footer.setText(this.#theme.muted('←/esc close')) + this.addChild(this.#footer) + } this.invalidate() } diff --git a/src/views/tui/selector.ts b/src/views/tui/selector.ts index e6e8dbc..39fc1db 100644 --- a/src/views/tui/selector.ts +++ b/src/views/tui/selector.ts @@ -72,7 +72,7 @@ export class SearchableSelector extends Container implements Focusable { this.#title = new Text(options.theme.brand(sanitizeTerminalText(options.title)), 1, 0) this.#footer = new Text( options.theme.muted( - sanitizeTerminalText(options.footer ?? 'type to filter · enter to choose · esc to close'), + sanitizeTerminalText(options.footer ?? 'type to filter · enter to choose · ←/esc close'), ), 1, 0, @@ -150,7 +150,7 @@ export class SearchableSelector extends Container implements Focusable { this.#list.handleInput(data) return } - if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) { + if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c') || matchesKey(data, 'left')) { this.#onCancel() return } diff --git a/src/views/tui/terminal-app.ts b/src/views/tui/terminal-app.ts index a709173..52bb9b2 100644 --- a/src/views/tui/terminal-app.ts +++ b/src/views/tui/terminal-app.ts @@ -135,6 +135,7 @@ export class BraidTerminalApp { : { connectionLifecycle: options.connectionLifecycle }), dispatchCommand: (command, args) => this.#commands.dispatchCommand(command, args), requestRender: () => this.#tui.requestRender(), + columns: () => this.#tui.terminal.columns, rows: () => this.#tui.terminal.rows, }) this.#interactions = new TerminalInteractionController({ @@ -227,7 +228,6 @@ export class BraidTerminalApp { #render(view: BraidViewModel): void { this.#drafts.restore(view) this.#shell.setView(view, this.#input.quitArmed) - this.#shell.setActivityVisible(this.#input.activityVisible) this.#interactions.sync(view) this.#tui.requestRender() } diff --git a/src/views/tui/terminal-chrome.ts b/src/views/tui/terminal-chrome.ts index 7042155..0aed08e 100644 --- a/src/views/tui/terminal-chrome.ts +++ b/src/views/tui/terminal-chrome.ts @@ -1,12 +1,18 @@ import type { Component } from '@earendil-works/pi-tui' -import type { BraidViewModel } from '../shared/models.js' +import type { BraidViewModel, EnvironmentView } from '../shared/models.js' import { sanitizeNotification } from '../shared/sanitize.js' -import { executionTargetFor, type ExecutionTargetView } from './execution-target.js' -import { fitTerminalAtomic, renderTerminalContext, terminalValuePart } from './terminal-identity.js' -import { modeForColumns } from './layout.js' -import type { BraidTheme } from './theme.js' -import { metricsFor } from './terminal-usage.js' import type { ComposerMode } from './composer-view.js' +import { type ExecutionTargetView, executionTargetFor } from './execution-target.js' +import { + fitTerminalAtomic, + fitTerminalColumns, + isSyntheticFixture, + renderTerminalContext, + terminalContextModeForColumns, + terminalValuePart, +} from './terminal-identity.js' +import { footerMetricsFor } from './terminal-usage.js' +import type { BraidTheme } from './theme.js' export interface TerminalChromeState { readonly view: BraidViewModel @@ -44,67 +50,133 @@ export class TerminalChrome implements Component { if (!state) return [] const safeWidth = Math.max(1, Math.floor(width)) const { view } = state - const mode = modeForColumns(safeWidth) + const mode = terminalContextModeForColumns(safeWidth) const target = executionTargetFor(view) const transientNotice = state.quitArmed ? undefined : transientNoticeFor(view) if (transientNotice !== undefined) { return [fitTerminalAtomic(statusText(this.#theme, view, transientNotice), safeWidth)] } - const status = statusText(this.#theme, view, conciseStatus(view, state.quitArmed, mode)) + const statusValue = conciseStatus(view, state.quitArmed, mode) + const status = statusText(this.#theme, view, statusValue) const hint = terminalValuePart( this.#theme, - navigationHint(view, state.navigationHint, state.composerMode), + mode === 'narrow' ? '' : navigationHint(view, state.navigationHint, state.composerMode, mode), ) - const metrics = - mode === 'wide' - ? metricsFor(view).map((metric) => terminalValuePart(this.#theme, metric)) + const executionFacts = executionFactsFor(target) + const measured = + mode === 'wide' && !isSyntheticFixture(target.model) + ? footerMetricsFor(view).map((metric) => terminalValuePart(this.#theme, metric)) : [] - const prioritizesAction = state.quitArmed || view.activeRunId !== undefined || status.length > 0 + const identity = { + workspace: view.workspace, + conversationTitle: view.conversationTitle, + branch: view.branch, + profileName: target.profileName, + runner: target.runner, + model: target.model, + ...(target.backend === undefined ? {} : { backend: target.backend }), + connection: target.connection, + ...(target.effort === undefined ? {} : { effort: target.effort }), + ...(target.maxVisibleOutputTokens === undefined + ? {} + : { maxVisibleOutputTokens: target.maxVisibleOutputTokens }), + ...(target.maxReasoningTokens === undefined + ? {} + : { maxReasoningTokens: target.maxReasoningTokens }), + ...(target.maxTotalOutputTokens === undefined + ? {} + : { maxTotalOutputTokens: target.maxTotalOutputTokens }), + } as const + const measuredOnRow1 = + mode === 'wide' && + measured.length > 0 && + view.activeRunId === undefined && + status.length === 0 const right = state.quitArmed ? [status] - : view.activeRunId !== undefined - ? [status, hint] - : status.length > 0 - ? [status, hint] - : metrics.length > 0 - ? metrics - : [status, hint] - return [ - renderTerminalContext( - this.#theme, - { - workspace: view.workspace, - conversationTitle: view.conversationTitle, - branch: view.branch, - profileName: target.profileName, - runner: target.runner, - model: target.model, - connection: target.connection, - ...(target.effort === undefined ? {} : { effort: target.effort }), - ...(target.maxOutputTokens === undefined - ? {} - : { maxOutputTokens: target.maxOutputTokens }), - execution: executionLabel(target), - }, - right, - safeWidth, - prioritizesAction ? 'right' : 'left', - ), - ] + : measuredOnRow1 + ? measured + : mode === 'standard' && view.activeRunId !== undefined + ? [status] + : view.activeRunId !== undefined || status.length > 0 + ? [status, hint] + : [hint] + const row1 = renderTerminalContext( + this.#theme, + identity, + right, + safeWidth, + mode === 'narrow' || state.quitArmed ? 'right' : 'left', + ) + if (mode !== 'wide') return [row1] + const row2Facts = executionFacts.map((fact) => terminalValuePart(this.#theme, fact)) + const row2Measured = measuredOnRow1 ? [] : measured + if (row2Facts.length === 0 && row2Measured.length === 0) return [row1] + const row2 = fitTerminalColumns(row2Facts, row2Measured, safeWidth, 'right') + return row2.length === 0 ? [row1] : [row1, row2] } } -function executionLabel(target: ExecutionTargetView): string { +function executionFactsFor(target: ExecutionTargetView): readonly string[] { const environment = target.environment - if (environment === undefined) return '' - if (environment.location === 'local' && environment.provider === 'cli-bridge') return '' - const location = environment.location === 'unknown' ? undefined : environment.location - const executionKind = environment.kind === 'sandbox' ? 'sandbox' : environment.provider - const lifecycle = - environment.lifecycle === 'active' || environment.lifecycle === 'ready' + if (environment?.kind !== 'sandbox') return [] + const facts: string[] = [] + if (environment.runtimeEndpointHost !== undefined) + facts.push(`host ${environment.runtimeEndpointHost}`) + if (environment.machineId !== undefined) facts.push(`machine ${environment.machineId}`) + if (environment.verifiedRegion !== undefined) facts.push(`region ${environment.verifiedRegion}`) + const sample = environment.resourceSample + if (sample !== undefined) { + const currentMemory = finiteNonNegative(sample.memoryCurrentMb) + if (currentMemory !== undefined) facts.push(`sample mem ${currentMemory}MB`) + const peakMemory = finiteNonNegative(sample.memoryPeakMb) + if (peakMemory !== undefined) facts.push(`peak ${peakMemory}MB`) + const memoryLimit = finiteNonNegative(sample.memoryLimitMb) + if (memoryLimit !== undefined) facts.push(`sample limit ${memoryLimit}MB`) + const cpuUsec = finiteNonNegative(sample.cpuUsageUsec) + if (cpuUsec !== undefined) facts.push(`cpu ${Math.round(cpuUsec / 1_000)}ms`) + } + const requested = requestedResourceLabel(environment) + if (requested !== undefined) facts.push(requested) + const gpu = environment.gpu + if (gpu !== undefined) { + let gpuFact = `gpu ${gpu.count}× ${gpu.accelerator}` + const measuredCost = finiteNonNegative(gpu.billedCustomerCostUsd) + if (measuredCost !== undefined) { + gpuFact += ` $${measuredCost.toFixed(4)}` + } + facts.push(gpuFact) + } + return facts +} + +function requestedResourceLabel(environment: EnvironmentView): string | undefined { + const resources = environment.requestedResources + if (resources === undefined) return undefined + const parts = [ + finitePositive(resources.cpuCores) === undefined ? undefined : `${resources.cpuCores}cpu`, + memoryLabel(resources.memoryMB), + finitePositive(resources.diskGB) === undefined ? undefined : `${resources.diskGB}GB`, + resources.accelerator === undefined ? undefined - : environment.lifecycle - return [location, executionKind, lifecycle].filter(Boolean).join(' ') + : `${resources.accelerator.count}×${resources.accelerator.kind}`, + ].filter((value): value is string => value !== undefined) + return parts.length === 0 ? undefined : `requested ${parts.join(' · ')}` +} + +function memoryLabel(value: number | undefined): string | undefined { + if (finitePositive(value) === undefined) return undefined + return value !== undefined && value >= 1024 && value % 1024 === 0 + ? `${value / 1024}GB` + : `${value}MB` +} + +function finitePositive(value: number | undefined): number | undefined { + return value !== undefined && Number.isFinite(value) && value > 0 ? value : undefined +} + +function finiteNonNegative(value: number | undefined): number | undefined { + return value !== undefined && Number.isFinite(value) && value >= 0 ? value : undefined } function statusText(theme: BraidTheme, view: BraidViewModel, value: string): string { @@ -120,7 +192,7 @@ function statusText(theme: BraidTheme, view: BraidViewModel, value: string): str function conciseStatus( view: BraidViewModel, quitArmed: boolean, - mode: ReturnType, + mode: ReturnType, ): string { if (quitArmed) return 'Ctrl+C again to quit' if (terminalOutcomeIsUnknown(view)) return 'outcome unknown' @@ -128,7 +200,7 @@ function conciseStatus( if (status === 'starting') return mode === 'narrow' ? 'starting · Ctrl+C stop' : 'starting · Ctrl+C cancel' if (status === 'streaming' || status === 'running') - return mode === 'narrow' ? 'working · Ctrl+C stop' : 'working · Ctrl+C cancel' + return mode === 'narrow' ? 'working · Ctrl+C stop' : 'Ctrl+C cancel' if (status === 'waiting') return 'waiting for input' if (status === 'detached') return 'running remotely' if (status === 'reconnecting') return 'reconnecting' @@ -147,6 +219,7 @@ function navigationHint( view: BraidViewModel, fallback: string, composerMode: ComposerMode, + mode: ReturnType, ): string { if (view.activeRunId !== undefined) { const queue = view.capabilities['run.queue']?.available === true @@ -161,7 +234,11 @@ function navigationHint( if (view.status === 'failed' || view.status === 'unknown') { return '/activity details · /new' } - return fallback + return mode === 'standard' ? compactNavigationHint(fallback) : fallback +} + +function compactNavigationHint(value: string): string { + return value.includes('/ commands') ? '/ commands' : value } function terminalOutcomeIsUnknown(view: BraidViewModel): boolean { diff --git a/src/views/tui/terminal-identity.ts b/src/views/tui/terminal-identity.ts index fb99705..d6bd79e 100644 --- a/src/views/tui/terminal-identity.ts +++ b/src/views/tui/terminal-identity.ts @@ -1,6 +1,5 @@ import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui' import { sanitizeTerminalText } from '../shared/sanitize.js' -import { modeForColumns } from './layout.js' import type { BraidTheme } from './theme.js' export interface TerminalIdentityView { @@ -10,10 +9,21 @@ export interface TerminalIdentityView { readonly profileName: string readonly runner: string readonly model: string + readonly backend?: string readonly connection: string readonly effort?: string - readonly maxOutputTokens?: number + readonly maxVisibleOutputTokens?: number + readonly maxReasoningTokens?: number + readonly maxTotalOutputTokens?: number readonly execution?: string + readonly executionFacts?: readonly string[] +} + +export function terminalContextModeForColumns(columns: number): 'narrow' | 'standard' | 'wide' { + const safeColumns = Math.max(1, Math.floor(columns)) + if (safeColumns < 60) return 'narrow' + if (safeColumns >= 100) return 'wide' + return 'standard' } export function renderTerminalIdentity( @@ -33,48 +43,99 @@ export function renderTerminalContext( priority: 'left' | 'right' = 'left', ): string { const safeWidth = Math.max(1, Math.floor(width)) - const mode = modeForColumns(safeWidth) - const model = - mode === 'wide' ? cleanTerminalField(identity.model) : compactModelName(identity.model) + const mode = terminalContextModeForColumns(safeWidth) + const synthetic = isSyntheticFixture(identity.model) + const model = synthetic + ? '' + : mode === 'wide' + ? cleanTerminalField(identity.model) + : compactModelName(identity.model) const profile = terminalValuePart( theme, mode === 'narrow' ? identity.profileName : `profile ${identity.profileName}`, ) - const route = terminalValuePart(theme, `${identity.runner} / ${model}`) + const route = + mode === 'wide' + ? terminalValuePart( + theme, + [identity.runner, model].filter((part) => part.length > 0).join(' / '), + ) + : terminalValuePart(theme, model ? `${identity.runner} / ${model}` : identity.runner) const connection = terminalValuePart( theme, - mode === 'wide' || mode === 'narrow' - ? identity.connection - : compactConnectionName(identity.connection), + mode === 'standard' + ? `via ${executionConnectionLabel(identity.backend, identity.connection)}` + : executionConnectionLabel(identity.backend, identity.connection), ) - const effortValue = cleanTerminalField(identity.effort) - const effort = - mode === 'wide' && effortValue && effortValue !== 'none' && effortValue !== 'off' - ? terminalValuePart(theme, effortValue) + const effortValue = synthetic ? '' : cleanTerminalField(identity.effort) + const effort = mode === 'wide' && effortValue ? terminalValuePart(theme, effortValue) : '' + const configuredLimits = synthetic + ? '' + : mode === 'wide' + ? configuredLimitGroup(theme, identity) : '' const execution = terminalValuePart(theme, identity.execution ?? '') + const executionFacts = + mode === 'wide' + ? (identity.executionFacts ?? []).map((fact) => terminalValuePart(theme, fact)) + : [] const branchValue = cleanTerminalField(identity.branch) const branch = mode === 'wide' && branchValue && branchValue !== 'main' && branchValue !== 'branch-1' ? terminalValuePart(theme, branchValue) : '' return fitTerminalColumns( - [profile, route, connection, effort, execution, branch], + mode === 'wide' + ? [profile, route, connection, effort, configuredLimits, execution, ...executionFacts, branch] + : mode === 'narrow' + ? [profile] + : [profile, route, connection, effort, execution, branch], right, safeWidth, priority, ) } +export function isSyntheticFixture(value: string | null | undefined): boolean { + return cleanTerminalField(value).toLocaleLowerCase() === 'fixture/deterministic' +} + +function configuredLimitGroup(theme: BraidTheme, identity: TerminalIdentityView): string { + const limits = [ + identity.maxVisibleOutputTokens === undefined + ? undefined + : `vis ${compactTerminalNumber(identity.maxVisibleOutputTokens)}`, + identity.maxReasoningTokens === undefined + ? undefined + : `reas ${compactTerminalNumber(identity.maxReasoningTokens)}`, + identity.maxTotalOutputTokens === undefined + ? undefined + : `total ${compactTerminalNumber(identity.maxTotalOutputTokens)}`, + ].filter((value): value is string => value !== undefined) + return limits.length === 0 ? '' : terminalValuePart(theme, `caps ${limits.join(' · ')}`) +} + function compactModelName(value: string): string { const safe = cleanTerminalField(value) const segments = safe.split('/').filter((segment) => segment.length > 0) return segments.at(-1) ?? safe } -function compactConnectionName(value: string): string { - const safe = cleanTerminalField(value) - return safe === 'deterministic fixture' ? 'fixture' : safe +function executionConnectionLabel(backend: string | undefined, connection: string): string { + const provider = cleanTerminalField(backend).toLocaleLowerCase() + const human = cleanTerminalField(connection) + const normalizedHuman = human.toLocaleLowerCase() + if ( + provider === 'fixture' || + provider === 'deterministic' || + provider === 'deterministic fixture' || + normalizedHuman === 'deterministic fixture' + ) + return 'local' + if (provider === 'cli-bridge' || /cli bridge/iu.test(human)) return human || 'CLI Bridge' + if (provider === 'tangle-sandbox' || /tangle sandbox/iu.test(human)) return 'Sandbox' + if (provider === 'tangle-inference' || /tangle inference/iu.test(human)) return 'Tangle inference' + return human || cleanTerminalField(backend) || 'local' } export function cleanTerminalField(value: string | null | undefined): string { diff --git a/src/views/tui/terminal-input-controller.ts b/src/views/tui/terminal-input-controller.ts index f36d753..56b098d 100644 --- a/src/views/tui/terminal-input-controller.ts +++ b/src/views/tui/terminal-input-controller.ts @@ -1,8 +1,6 @@ import { matchesKey, type TUI } from '@earendil-works/pi-tui' import { commandAvailability } from '../shared/command-registry.js' import type { BraidIntent, BraidUiController, UiDispatchResult } from '../shared/intents.js' -import type { BraidViewModel } from '../shared/models.js' -import { hasLiveWork } from './activity.js' import type { ComposerMode } from './composer-view.js' import { type BraidKeymap, isTextInputSequence, matchesKeyAction } from './keyboard.js' import type { ModalCoordinator } from './modal-coordinator.js' @@ -25,13 +23,6 @@ export interface TerminalInputControllerOptions { readonly stateChanged: () => void } -export type ActivityVisibility = 'auto' | 'hidden' | 'visible' - -export function activityVisibleFor(view: BraidViewModel, visibility: ActivityVisibility): boolean { - if (visibility !== 'visible') return false - return hasLiveWork(view) -} - /** Routes non-text terminal keys and owns the short-lived quit/activity state. */ export class TerminalInputController { readonly #tui: TUI @@ -48,7 +39,6 @@ export class TerminalInputController { readonly #stateChanged: () => void #quitTimer: ReturnType | undefined #quitArmed = false - #activityVisibility: ActivityVisibility = 'auto' #composerMode: ComposerMode = 'queue' constructor(options: TerminalInputControllerOptions) { @@ -70,10 +60,6 @@ export class TerminalInputController { return this.#quitArmed } - get activityVisible(): boolean { - return activityVisibleFor(this.#controller.view(), this.#activityVisibility) - } - get composerMode(): ComposerMode { return this.#composerMode } @@ -91,6 +77,13 @@ export class TerminalInputController { } if (isTextInputSequence(data)) return undefined if (matchesKeyAction(data, this.#keymap, 'closeOverlay') && this.#tui.hasOverlay()) { + if ( + matchesKey(data, 'left') && + !this.#interactionOpen() && + this.#modals.backOrCloseIfFullScreen() + ) { + return { consume: true } + } if (this.#interactionOpen()) return undefined if (matchesKey(data, 'left')) { if (!this.#modals.backOrCloseIfPassive()) return undefined @@ -141,8 +134,7 @@ export class TerminalInputController { return { consume: true } } if (matchesKeyAction(data, this.#keymap, 'activity')) { - this.#activityVisibility = this.activityVisible ? 'hidden' : 'visible' - this.#stateChanged() + this.#overlays.openSurface('activity') return { consume: true } } if ( diff --git a/src/views/tui/terminal-interaction-controller.ts b/src/views/tui/terminal-interaction-controller.ts index bf9eae0..a75c1bb 100644 --- a/src/views/tui/terminal-interaction-controller.ts +++ b/src/views/tui/terminal-interaction-controller.ts @@ -123,6 +123,7 @@ export class TerminalInteractionController { width: '100%', maxHeight: '100%', margin: 0, + fullScreenBelow: Number.MAX_SAFE_INTEGER, }) this.#syncRefresh(interaction) } diff --git a/src/views/tui/terminal-overlays.ts b/src/views/tui/terminal-overlays.ts index 40a1475..4ee5616 100644 --- a/src/views/tui/terminal-overlays.ts +++ b/src/views/tui/terminal-overlays.ts @@ -35,6 +35,7 @@ export interface TerminalOverlayOptions { readonly connectionLifecycle?: UiConnectionLifecycle readonly dispatchCommand: (command: CommandName, args: readonly string[]) => void readonly requestRender: () => void + readonly columns: () => number readonly rows: () => number } @@ -44,9 +45,11 @@ export class TerminalOverlayController { readonly #modals: ModalCoordinator readonly #editor: Editor readonly #nextOperationId: () => string + readonly #rows: () => number readonly #dispatchCommand: TerminalOverlayOptions['dispatchCommand'] readonly #configuration: TerminalOverlayOptions['configuration'] readonly #requestRender: TerminalOverlayOptions['requestRender'] + readonly #columns: () => number readonly #conversations: ConversationOverlayController readonly #connectionWorkflow: ConnectionOverlayWorkflow | undefined readonly #surfaces: TerminalSurfaceOverlays @@ -58,6 +61,8 @@ export class TerminalOverlayController { this.#modals = options.modals this.#editor = options.editor this.#nextOperationId = options.nextOperationId + this.#rows = options.rows + this.#columns = options.columns this.#conversations = new ConversationOverlayController({ theme: this.#theme, controller: this.#controller, @@ -186,13 +191,24 @@ export class TerminalOverlayController { title: 'Commands', items: commandItems(view.capabilities), theme: this.#theme, + maxVisible: Math.max(1, Math.min(8, this.#rows() - 6)), + footer: + this.#columns() < 60 + ? 'enter choose · ←/esc close' + : 'type to filter · enter to choose · ←/esc close', onSelect: (item) => { this.#modals.closeTop() this.#dispatchCommand(item.value as CommandName, []) }, onCancel: () => this.#modals.closeTop(), }) - this.#modals.open(palette, { anchor: 'center', width: '70%', minWidth: 32, maxHeight: 14 }) + this.#modals.open(palette, { + anchor: 'top-left', + width: '100%', + maxHeight: '100%', + margin: 0, + fullScreenBelow: Number.MAX_SAFE_INTEGER, + }) } openSwitcher(): void { @@ -229,7 +245,7 @@ export class TerminalOverlayController { items, maxVisible: 5, theme: this.#theme, - footer: 'enter to change · esc to close', + footer: 'enter to change · ←/esc close', onSelect: (item) => { this.#modals.closeTop() if (item.value === 'profile') this.openProfile() diff --git a/src/views/tui/terminal-shell.ts b/src/views/tui/terminal-shell.ts index 8347e07..348a347 100644 --- a/src/views/tui/terminal-shell.ts +++ b/src/views/tui/terminal-shell.ts @@ -8,7 +8,6 @@ import { } from '@earendil-works/pi-tui' import type { BraidViewModel } from '../shared/models.js' import { sanitizeTerminalText } from '../shared/sanitize.js' -import { ActivityView, hasLiveWork } from './activity.js' import { type ComposerMode, ComposerView } from './composer-view.js' import { layoutFor } from './layout.js' import { TerminalChrome } from './terminal-chrome.js' @@ -17,13 +16,11 @@ import { TranscriptView } from './transcript.js' export class BraidShell extends Container { readonly #transcript: TranscriptView - readonly #activity: ActivityView readonly #chrome: TerminalChrome readonly #composer: ComposerView readonly #theme: BraidTheme readonly #rows: () => number #view: BraidViewModel | undefined - #showActivity = false #modalVisible = false #quitArmed = false #composerMode: ComposerMode = 'queue' @@ -39,14 +36,12 @@ export class BraidShell extends Container { this.#theme = theme this.#rows = rows this.#transcript = new TranscriptView(theme) - this.#activity = new ActivityView(theme) this.#chrome = new TerminalChrome(theme) const editor = new Editor(tui, theme.editor, { paddingX: 1 }) editor.onSubmit = onSubmit editor.onChange = onChange this.#composer = new ComposerView({ editor, rows, theme }) this.addChild(this.#transcript) - this.addChild(this.#activity) this.addChild(this.#composer) } @@ -61,11 +56,6 @@ export class BraidShell extends Container { this.#refreshChrome() } - setActivityVisible(visible: boolean): void { - this.#showActivity = visible - this.invalidate() - } - setModalVisible(visible: boolean): void { this.#modalVisible = visible this.invalidate() @@ -75,12 +65,11 @@ export class BraidShell extends Container { this.#view = view this.#quitArmed = quitArmed this.#transcript.setView(view) - this.#activity.setView(view) this.#composer.setView(view) this.#chrome.setState({ view, quitArmed, - activityVisible: this.#showActivity, + activityVisible: false, navigationHint: this.#transcript.navigationHint(), composerMode: this.#composerMode, }) @@ -121,32 +110,20 @@ export class BraidShell extends Container { override render(width: number): string[] { const view = this.#view if (!view) return super.render(width) - const showActivity = this.#showActivity && hasLiveWork(view) - const layout = layoutFor(width, this.#rows(), showActivity) + const layout = layoutFor(width, this.#rows(), false) const editorLines = this.#modalVisible ? [] : this.#composer.render(width) const topChrome = this.#chrome.renderTop(width) - const bottomChrome = this.#chrome.renderBottom(width) + const bottomChrome = this.#modalVisible ? [] : this.#chrome.renderBottom(width) const dockRows = topChrome.length + bottomChrome.length + editorLines.length const contentRows = Math.max(1, layout.rows - dockRows) this.#transcript.setViewportRows(contentRows) - const transcriptLines = this.#transcript.render(layout.transcriptWidth) + const transcriptLines = this.#modalVisible + ? [] + : this.#transcript.render(layout.transcriptWidth) this.#refreshChrome() - const activityLines = - layout.mode === 'wide' && showActivity - ? tail(this.#activity.render(layout.activityWidth), contentRows) - : [] - const content: string[] = [] - for (let index = 0; index < contentRows; index += 1) { - const transcript = transcriptLines[index] ?? '' - if (activityLines.length === 0) { - content.push(truncateToWidth(transcript, width, '…', true)) - } else { - const activity = activityLines[index] ?? '' - content.push( - `${truncateToWidth(transcript, layout.transcriptWidth, '…', true)}${this.#theme.muted('│')}${truncateToWidth(activity, layout.activityWidth, '…', true)}`, - ) - } - } + const content = Array.from({ length: contentRows }, (_, index) => + truncateToWidth(transcriptLines[index] ?? '', width, '…', true), + ) return [...topChrome, ...content, ...editorLines, ...this.#chrome.renderBottom(width)].slice( 0, layout.rows, @@ -159,7 +136,7 @@ export class BraidShell extends Container { this.#chrome.setState({ view, quitArmed: this.#quitArmed, - activityVisible: this.#showActivity && hasLiveWork(view), + activityVisible: false, navigationHint: this.#transcript.navigationHint(), composerMode: this.#composerMode, }) @@ -167,13 +144,6 @@ export class BraidShell extends Container { } } -function tail(lines: readonly string[], count: number): string[] { - if (lines.length <= count) return [...lines] - const header = lines[0] - if (header === undefined || count <= 1) return lines.slice(-count) - return [header, ...lines.slice(-(count - 1))] -} - export class UnavailablePanel extends Container { constructor(theme: BraidTheme, title: string, reason: string) { super() @@ -182,6 +152,6 @@ export class UnavailablePanel extends Container { this.addChild( new Text(theme.muted('This action is unavailable with the selected connection.'), 1, 0), ) - this.addChild(new Text(theme.muted('esc close'), 1, 0)) + this.addChild(new Text(theme.muted('←/esc close'), 1, 0)) } } diff --git a/src/views/tui/terminal-surface-overlays.ts b/src/views/tui/terminal-surface-overlays.ts index 5435190..81597e6 100644 --- a/src/views/tui/terminal-surface-overlays.ts +++ b/src/views/tui/terminal-surface-overlays.ts @@ -294,7 +294,7 @@ export class TerminalSurfaceOverlays { }, ], theme: this.#options.theme, - footer: 'enter open · esc close', + footer: 'enter open · ←/esc close', onSelect: (item) => { this.#options.modals.closeTop() if (item.value === 'profile') this.#options.openProfile() diff --git a/src/views/tui/terminal-usage.ts b/src/views/tui/terminal-usage.ts index 83d36c7..4491662 100644 --- a/src/views/tui/terminal-usage.ts +++ b/src/views/tui/terminal-usage.ts @@ -10,6 +10,32 @@ export function metricsFor(view: BraidViewModel): string[] { ].filter((value): value is string => value !== undefined) } +/** Returns only compact direct-run measurements suitable for the persistent footer. */ +export function footerMetricsFor(view: BraidViewModel): string[] { + const usage = view.sessionUsage.turns + return [ + ...tokenMetrics(usage), + measuredCostMetric(usage), + measurementMetric( + 'latency', + usage.llmLatencyMs, + usage.latencyStatus, + (value) => `${Math.round(value)}ms`, + ), + ].filter((value): value is string => value !== undefined) +} + +function measuredCostMetric(usage: UsageTotalsView): string | undefined { + const reported = finiteNonNegative(usage.costUsd) + if (usage.costStatus === 'reported' && reported !== undefined) { + return `$${reported.toFixed(4)}` + } + if (usage.costStatus === 'observed-floor' && reported !== undefined && reported > 0) { + return `≥$${reported.toFixed(4)}` + } + return undefined +} + function usageGroup(label: string, usage: UsageTotalsView): string | undefined { if (usage.sourceCount === 0) return undefined const metrics = usageMetrics(usage) @@ -26,7 +52,7 @@ function usageMetrics(usage: UsageTotalsView): string[] { String(Math.round(value)), ), measurementMetric( - 'model', + 'latency', usage.llmLatencyMs, usage.latencyStatus, (value) => `${Math.round(value)}ms`, diff --git a/src/views/tui/transcript.ts b/src/views/tui/transcript.ts index c19e9e4..3e46db2 100644 --- a/src/views/tui/transcript.ts +++ b/src/views/tui/transcript.ts @@ -86,9 +86,9 @@ export class TranscriptView extends Container { : detailCount return `Ctrl+E next detail (${current}/${detailCount})` } - if (detailCount === 1) return 'Ctrl+E detail' + if (detailCount === 1) return 'Ctrl+E details' if (this.canScroll) return 'PgUp/PgDn history' - return 'Ctrl+P commands' + return '/ commands · Ctrl+P' } hasCollapsibleDetails(): boolean { @@ -146,6 +146,13 @@ export class TranscriptView extends Container { override render(width: number): string[] { const allLines = super.render(Math.max(1, Math.floor(width))) this.#lastLines = allLines + if (this.#view?.messages.length === 0 && (this.#view.queue?.length ?? 0) === 0) { + const prompt = allLines.at(-1) ?? '' + const promptRow = Math.max(0, this.#viewportRows - 1) + return [...Array.from({ length: Math.max(0, promptRow - 1) }, () => ''), prompt].slice( + -this.#viewportRows, + ) + } const max = Math.max(0, allLines.length - this.#viewportRows) if (this.#pendingHistoryPosition === 'start') { this.#scrollTop = 0 diff --git a/test/analysis-model-call-roundtrip.test.ts b/test/analysis-model-call-roundtrip.test.ts index 567e39a..794a06f 100644 --- a/test/analysis-model-call-roundtrip.test.ts +++ b/test/analysis-model-call-roundtrip.test.ts @@ -1,9 +1,9 @@ import assert from 'node:assert/strict' import test from 'node:test' +import { buildBraidViewModel } from '../src/adapters/tui/ui-view-model.js' import { createBraidApplication, DETERMINISTIC_PROFILE } from '../src/app/composition.js' import { importAnalysisModelCalls } from '../src/app/conversation-import-analyses.js' import { MemoryJournal } from '../src/app/journal.js' -import { buildBraidViewModel } from '../src/adapters/tui/ui-view-model.js' import { canonicalDigest } from '../src/domain/canonical.js' import type { AnalysisRecord } from '../src/domain/entities.js' import type { BraidEventEnvelope } from '../src/domain/events.js' @@ -11,7 +11,11 @@ import { createAnalysisId, createEventId } from '../src/domain/ids.js' import { replayEvents } from '../src/domain/reducer.js' import { initialState } from '../src/domain/state.js' import { FixedClock } from '../src/ports/clock.js' -import { analysisModelCallSummary } from '../src/views/shared/analysis-model-call-presentation.js' +import { + analysisMeasuredModelCallLine, + analysisMeasuredModelCallSummary, + analysisModelCallSummary, +} from '../src/views/shared/analysis-model-call-presentation.js' import { queryDetails } from '../src/views/shared/semantic-details.js' const startedAt = '2026-08-10T00:00:00.000Z' @@ -235,7 +239,7 @@ test('analysis model-call summary keeps partial telemetry explicit', () => { outcome: 'failed', }, ]), - '2 calls · tokens ≥120 in / ≥45 out (+1 unknown) · cost ≥$0.0123 (+1 unknown) · model ≥88ms (+1 unknown) · 1 failed', + '2 calls · tokens ≥120 in / ≥45 out (+1 unknown) · cost ≥$0.0123 (+1 unknown) · latency ≥88ms (+1 unknown) · 1 failed', ) }) @@ -254,7 +258,36 @@ test('analysis model-call summary distinguishes estimates from exact charges', ( outcome: 'succeeded', }, ]), - '1 call · tokens 20 in / 8 out · cost ~$0.0042 · model 40ms', + '1 call · tokens 20 in / 8 out · cost ~$0.0042 · latency 40ms', + ) +}) + +test('compact analysis surfaces omit unmeasured usage and latency', () => { + const partial = { + sequence: 2, + model: 'glm-5.2', + tokensKnown: false, + costStatus: 'unknown' as const, + outcome: 'failed' as const, + } + assert.equal(analysisMeasuredModelCallLine(partial), '#2 glm-5.2') + assert.equal( + analysisMeasuredModelCallSummary([ + { + sequence: 1, + provider: 'openai', + model: 'gpt-5.6-luna', + inputTokens: 120, + outputTokens: 45, + tokensKnown: true, + costUsd: 0.0123, + costStatus: 'observed', + latencyMs: 88, + outcome: 'succeeded', + }, + partial, + ]), + '2 calls · tokens ≥120 in / ≥45 out · cost $0.0123 · latency ≥88ms · 1 failed', ) }) diff --git a/test/application.test.ts b/test/application.test.ts index 260553e..770b81f 100644 --- a/test/application.test.ts +++ b/test/application.test.ts @@ -366,7 +366,10 @@ test('restart keeps exact loaded metadata for the matching durable profile', asy harness: 'pi', model: { default: 'openai/gpt-5.6-luna', - metadata: { maxTokens: 8192, route: 'private-runtime-choice' }, + maxVisibleOutputTokens: 8192, + maxReasoningTokens: 16_384, + maxTotalOutputTokens: 24_576, + metadata: { route: 'private-runtime-choice' }, }, }) const source = createProfileRecord( @@ -412,10 +415,10 @@ test('restart keeps exact loaded metadata for the matching durable profile', asy params: { ref: source.id }, }) assert.equal(JSON.stringify(first.state()).includes('private-runtime-choice'), false) - assert.deepEqual(first.state().profile.model?.metadata, { - maxTokens: 8192, - redacted: '[redacted]', - }) + assert.deepEqual(first.state().profile.model?.metadata, { redacted: '[redacted]' }) + assert.equal(first.state().profile.model?.maxVisibleOutputTokens, 8192) + assert.equal(first.state().profile.model?.maxReasoningTokens, 16_384) + assert.equal(first.state().profile.model?.maxTotalOutputTokens, 24_576) const durableProfileSelection = JSON.stringify(journal.all()) assert.equal(durableProfileSelection.includes('private-runtime-choice'), false) assert.equal(durableProfileSelection.includes(canonicalAgentProfileDigestHex(exactProfile)), true) @@ -430,17 +433,20 @@ test('restart keeps exact loaded metadata for the matching durable profile', asy }) await restarted.send({ operationId: 'op-after-profile-restart', text: 'continue' }).completion - assert.deepEqual(executionProfiles[0]?.model?.metadata, { - maxTokens: 8192, - route: 'private-runtime-choice', - }) + assert.deepEqual(executionProfiles[0]?.model?.metadata, { route: 'private-runtime-choice' }) + assert.equal(executionProfiles[0]?.model?.maxVisibleOutputTokens, 8192) + assert.equal(executionProfiles[0]?.model?.maxReasoningTokens, 16_384) + assert.equal(executionProfiles[0]?.model?.maxTotalOutputTokens, 24_576) const mismatchedProfile = defineAgentProfile({ name: exactProfile.name, harness: exactProfile.harness, model: { default: exactProfile.model?.default ?? 'openai/gpt-5.6-luna', - metadata: { maxTokens: 4096, route: 'different-private-runtime-choice' }, + maxVisibleOutputTokens: 4096, + maxReasoningTokens: 8_192, + maxTotalOutputTokens: 12_288, + metadata: { route: 'different-private-runtime-choice' }, }, }) const mismatchedRestart = new BraidApplication({ @@ -460,10 +466,10 @@ test('restart keeps exact loaded metadata for the matching durable profile', asy JSON.stringify(executionProfiles[1]).includes('different-private-runtime-choice'), false, ) - assert.deepEqual(executionProfiles[1]?.model?.metadata, { - maxTokens: 8192, - redacted: '[redacted]', - }) + assert.deepEqual(executionProfiles[1]?.model?.metadata, { redacted: '[redacted]' }) + assert.equal(executionProfiles[1]?.model?.maxVisibleOutputTokens, 8192) + assert.equal(executionProfiles[1]?.model?.maxReasoningTokens, 16_384) + assert.equal(executionProfiles[1]?.model?.maxTotalOutputTokens, 24_576) assert.equal( mismatchedRestart.state().profiles[0]?.executionDigest, canonicalAgentProfileDigestHex(exactProfile), @@ -498,10 +504,10 @@ test('restart keeps exact loaded metadata for the matching durable profile', asy }).completion assert.equal(JSON.stringify(executionProfiles[2]).includes('private-runtime-choice'), false) - assert.deepEqual(executionProfiles[2]?.model?.metadata, { - maxTokens: 8192, - redacted: '[redacted]', - }) + assert.deepEqual(executionProfiles[2]?.model?.metadata, { redacted: '[redacted]' }) + assert.equal(executionProfiles[2]?.model?.maxVisibleOutputTokens, 8192) + assert.equal(executionProfiles[2]?.model?.maxReasoningTokens, 16_384) + assert.equal(executionProfiles[2]?.model?.maxTotalOutputTokens, 24_576) }) test('an identical operation is replayed and conflicting input is rejected', async () => { diff --git a/test/configuration-product-flow.test.ts b/test/configuration-product-flow.test.ts index b2758b0..a7d5bf8 100644 --- a/test/configuration-product-flow.test.ts +++ b/test/configuration-product-flow.test.ts @@ -12,6 +12,7 @@ import type { UiDispatchResult, } from '../src/views/shared/intents.js' import type { BraidViewModel, HeadlessState } from '../src/views/shared/models.js' +import { profileDetailLines } from '../src/views/tui/configuration-presenters.js' import { ConfigurationWizard } from '../src/views/tui/configuration-wizard.js' import { ConnectionSetupViewPanel } from '../src/views/tui/connection-setup.js' import { ProfileEditorViewPanel } from '../src/views/tui/profile-editor.js' @@ -28,7 +29,9 @@ function profile(name: string, _writable: boolean): AgentProfile { model: { default: `provider/${name.toLowerCase()}`, reasoningEffort: 'high', - metadata: { maxTokens: 8192 }, + maxVisibleOutputTokens: 8192, + maxReasoningTokens: 16_384, + maxTotalOutputTokens: 24_576, }, harness: 'pi', tools: { read: true }, @@ -53,7 +56,9 @@ function profileSummary(name: string, writable: boolean) { runner: 'pi', model: `provider/${name.toLowerCase()}`, reasoningEffort: 'high', - maxOutputTokens: 8192, + maxVisibleOutputTokens: 8192, + maxReasoningTokens: 16_384, + maxTotalOutputTokens: 24_576, tools: ['read'], skills: [], connections: [], @@ -84,14 +89,16 @@ function accepted(data: unknown, revision = 8): UiDispatchResult { function controllerFor( calls: BraidIntent[], - options: { duplicateProfileName?: boolean; rejectLists?: boolean } = {}, + options: { duplicateProfileName?: boolean; rejectLists?: boolean; singleProfile?: boolean } = {}, ): BraidUiController { let currentView = { revision: 7, profileName: 'Reviewer', connection: 'Local Bridge', } as BraidViewModel - const profiles = [profileSummary('Reviewer', true), profileSummary('ReadOnly', false)] + const profiles = options.singleProfile + ? [profileSummary('Reviewer', true)] + : [profileSummary('Reviewer', true), profileSummary('ReadOnly', false)] if (options.duplicateProfileName) { profiles.push({ ...profileSummary('Reviewer', false), id: 'profile-reviewer-duplicate' }) } @@ -285,13 +292,15 @@ test('profile editor uses canonical summaries and validates without advertising panel.focused = true await settle() const initial = panel.render(80).join('\n') - assert.match(initial, /Active profile · Reviewer/u) + assert.match(initial, /Reviewer/u) + assert.doesNotMatch(initial, /Active profile/u) assert.match(initial, /pi/u) assert.match(initial, /provider\/reviewer/u) assert.doesNotMatch(initial, /secret-canary|secret-profile\.json/u) const narrow = panel.render(40) assert.ok(narrow.length <= 12) - assert.match(narrow.join('\n'), /enter select · \^V validate · esc close/u) + assert.match(narrow.join('\n'), /enter select · \^V validate · ←\/esc/u) + assert.match(narrow.join('\n'), /close/u) assert.doesNotMatch(narrow.join('\n'), /save/iu) panel.handleInput('\u0016') @@ -309,6 +318,90 @@ test('profile editor uses canonical summaries and validates without advertising ) }) +test('one profile renders a focused summary without a redundant switch list', async () => { + const panel = new ProfileEditorViewPanel(theme, { + controller: controllerFor([], { singleProfile: true }), + }) + panel.focused = true + await settle() + const rendered = panel.render(80).join('\n') + assert.match(rendered, /Reviewer/u) + assert.match(rendered, /runner pi · model provider\/reviewer/u) + assert.doesNotMatch(rendered, /switch profile|profiles/u) + assert.match(rendered, /←\/esc close/u) +}) + +test('built-in starter details omit the implicit source while real sources remain visible', () => { + const builtIn = { + ...profileSummary('Braid starter', false), + source: { + kind: 'inline' as const, + reference: 'braid:active', + label: 'Braid starter', + writable: false, + trusted: true, + }, + } + const builtInText = profileDetailLines(builtIn).join('\n') + assert.doesNotMatch(builtInText, /source Braid starter/u) + assert.match(builtInText, /trusted · read-only/u) + + const sourceText = profileDetailLines(profileSummary('Reviewer', false)).join('\n') + assert.match(sourceText, /source workspace profile/u) +}) + +test('profile and configuration selectors close with either back key', async () => { + const connection = { + id: 'connection-left-key', + kind: 'cli-bridge' as const, + name: 'Local Bridge', + endpoint: 'https://bridge.example.test/v1', + providerOptions: { transport: 'https' as const, capabilityHints: ['stream'] }, + createdAt: at, + updatedAt: at, + lastHealth: { status: 'healthy' as const, checkedAt: at }, + } + const record = createProfileRecord( + { + kind: 'inline', + reference: 'profile:left-key', + label: 'Left key profile', + writable: false, + trusted: true, + }, + profile('Left key profile', false), + ) + + for (const key of ['\u001b[D', '\u001b']) { + let profileCancelled = 0 + const profiles = new ProfileEditorViewPanel(theme, { + controller: controllerFor([]), + onCancel: () => { + profileCancelled += 1 + }, + }) + profiles.focused = true + await settle() + profiles.handleInput(key) + assert.equal(profileCancelled, 1, `profile ${JSON.stringify(key)}`) + + let configurationCancelled = 0 + const wizard = new ConfigurationWizard({ + theme, + profiles: [record], + connections: [connection], + onCommit: () => {}, + onComplete: () => {}, + onCancel: () => { + configurationCancelled += 1 + }, + }) + wizard.focused = true + wizard.handleInput(key) + assert.equal(configurationCancelled, 1, `configuration ${JSON.stringify(key)}`) + } +}) + test('connection setup shows health and capabilities without endpoints or credentials, then applies exact keyboard actions', async () => { const calls: BraidIntent[] = [] let cancelled = false @@ -328,7 +421,7 @@ test('connection setup shows health and capabilities without endpoints or creden assert.doesNotMatch(initial, /access_token|secret-canary/u) const narrow = panel.render(40) assert.ok(narrow.length <= 12) - assert.match(narrow.join('\n'), /enter select · \^T test · esc close/u) + assert.match(narrow.join('\n'), /enter select · \^T test · ←\/esc close/u) panel.handleInput('\u0014') await settle() diff --git a/test/production-composition.test.ts b/test/production-composition.test.ts index b250e5f..ab42796 100644 --- a/test/production-composition.test.ts +++ b/test/production-composition.test.ts @@ -19,13 +19,13 @@ import { canonicalCandidateJson, defineAgentProfile, } from '@tangle-network/agent-interface' -import { HeadlessCredentialStore } from '../src/adapters/credentials/headless-store.js' -import { MemoryCredentialStore } from '../src/adapters/credentials/memory.js' import { materializeBridgeModelRoute, portableBridgeModel, qualifyBridgeProfileModel, } from '../src/adapters/connections/cli-bridge-model-route.js' +import { HeadlessCredentialStore } from '../src/adapters/credentials/headless-store.js' +import { MemoryCredentialStore } from '../src/adapters/credentials/memory.js' import { resolveProductionBackend } from '../src/adapters/runtime/production-backend-resolver.js' import { ApplicationUiController } from '../src/adapters/tui/application-ui-controller.js' import { @@ -209,6 +209,43 @@ test('normal composition streams a configured CLI Bridge turn through agent-runt } }) +test('retained CLI Bridge turns forward request-scoped model credentials only on the model call', async () => { + const bridge = await startRuntimeBridgeServer() + const seen: { token?: string | null; baseUrl?: string | null } = {} + try { + const record = connection('cli-bridge', 'scoped-model', bridge.endpoint) + const result = await runProductionTurn( + composition(record, { + bridgeModelCredential: { + key: 'BRAID_TEST_MODEL_TOKEN', + baseUrlKey: 'BRAID_TEST_MODEL_BASE_URL', + provider: { + get: async (key: string) => + key === 'BRAID_TEST_MODEL_TOKEN' + ? 'test-model-token' + : key === 'BRAID_TEST_MODEL_BASE_URL' + ? 'https://chatgpt.com/backend-api' + : undefined, + }, + }, + fetch: async (input, init) => { + if (new URL(String(input)).pathname === '/v1/chat/completions') { + seen.token = requestHeader(init, 'x-cli-bridge-model-credential') + seen.baseUrl = requestHeader(init, 'x-cli-bridge-model-base-url') + } + return fetch(input, init) + }, + }), + ) + + assert.equal(result.state.runs[0]?.status, 'completed') + assert.equal(seen.token, 'test-model-token') + assert.equal(seen.baseUrl, 'https://chatgpt.com/backend-api') + } finally { + await bridge.close() + } +}) + test('production composition persists acknowledged CLI Bridge cancellation', async () => { const bridge = await startRuntimeBridgeServer({ holdStreams: true }) const clock = new FixedClock() @@ -1946,6 +1983,8 @@ test('first-run model validation authorizes its token limit in a separate AgentP readonly default?: unknown readonly provider?: unknown readonly reasoningEffort?: unknown + readonly maxVisibleOutputTokens?: unknown + readonly maxTotalOutputTokens?: unknown readonly metadata?: Record } } @@ -1953,7 +1992,9 @@ test('first-run model validation authorizes its token limit in a separate AgentP assert.equal(validationProfile.model?.default, 'tangle-router/glm-5.2') assert.equal(validationProfile.model?.provider, 'tangle-router') assert.equal(validationProfile.model?.reasoningEffort, 'high') - assert.equal(validationProfile.model?.metadata?.maxTokens, 1) + assert.equal(validationProfile.model?.maxVisibleOutputTokens, 1) + assert.equal(validationProfile.model?.maxTotalOutputTokens, 1) + assert.equal(validationProfile.model?.metadata, undefined) assert.equal('effort' in (body ?? {}), false) }) diff --git a/test/sanitize.test.ts b/test/sanitize.test.ts index 9da198b..1d150b9 100644 --- a/test/sanitize.test.ts +++ b/test/sanitize.test.ts @@ -57,7 +57,7 @@ test('numeric token telemetry survives redaction while string tokens never do', totalTokens: 34, cachedPromptTokens: 5, cacheWriteTokens: 3, - model: { maxTokens: 4096 }, + model: { maxVisibleOutputTokens: 4096 }, tokenUsage: { input: 21, output: 13 }, accessToken: 'secret-canary', poisoned: { inputTokens: 'secret-canary' }, @@ -70,7 +70,7 @@ test('numeric token telemetry survives redaction while string tokens never do', assert.equal(redacted.totalTokens, 34) assert.equal(redacted.cachedPromptTokens, 5) assert.equal(redacted.cacheWriteTokens, 3) - assert.deepEqual(redacted.model, { maxTokens: 4096 }) + assert.deepEqual(redacted.model, { maxVisibleOutputTokens: 4096 }) assert.deepEqual(redacted.tokenUsage, { input: 21, output: 13 }) assert.equal(redacted.accessToken, '[redacted]') assert.deepEqual(redacted.poisoned, { inputTokens: '[redacted]' }) @@ -159,29 +159,35 @@ test('plain structured redaction preserves only the exact aggregate token counte ) }) -test('profile redaction exposes only the public output-token limit from model metadata', () => { +test('profile redaction keeps first-class limits and hides model metadata', () => { const redacted = redactProfile({ name: 'Public model settings', model: { default: 'tangle-router/glm-5.2', + maxVisibleOutputTokens: 8192, + maxReasoningTokens: 16_384, + maxTotalOutputTokens: 24_576, metadata: { - maxTokens: 8192, route: 'private-route-canary', apiKey: 'private-key-canary', }, }, - metadata: { maxTokens: 65_536, owner: 'private-owner-canary' }, + metadata: { owner: 'private-owner-canary' }, modes: { - fast: { metadata: { maxTokens: 4096, note: 'private-mode-canary' } }, + fast: { metadata: { note: 'private-mode-canary' } }, }, }) - assert.deepEqual(redacted.model?.metadata, { maxTokens: 8192, redacted: '[redacted]' }) + assert.equal(redacted.model?.maxVisibleOutputTokens, 8192) + assert.equal(redacted.model?.maxReasoningTokens, 16_384) + assert.equal(redacted.model?.maxTotalOutputTokens, 24_576) + assert.deepEqual(redacted.model?.metadata, { redacted: '[redacted]' }) assert.deepEqual(redacted.metadata, { redacted: '[redacted]' }) assert.deepEqual(redacted.modes?.fast?.metadata, { redacted: '[redacted]' }) assert.doesNotMatch(JSON.stringify(redacted), /private-(?:route|key|owner|mode)-canary/u) assert.deepEqual( - redactProfile({ model: { metadata: { maxTokens: 'private-token-canary' } } }).model?.metadata, + redactProfile({ model: { metadata: { legacyOutputLimit: 'private-token-canary' } } }).model + ?.metadata, { redacted: '[redacted]' }, ) }) diff --git a/test/terminal-responsive.test.ts b/test/terminal-responsive.test.ts index d8c99f8..db2cf73 100644 --- a/test/terminal-responsive.test.ts +++ b/test/terminal-responsive.test.ts @@ -10,10 +10,11 @@ import { } from '@earendil-works/pi-tui' import { createApplicationUiController } from '../src/adapters/tui/application-ui-controller.js' import { createBraidApplication } from '../src/app/composition.js' -import type { BraidViewModel } from '../src/views/shared/models.js' +import type { BraidViewModel, EnvironmentView } from '../src/views/shared/models.js' import { composerProjectionFor, composerRowBudget } from '../src/views/tui/composer-view.js' import { layoutFor } from '../src/views/tui/layout.js' import { ModalCoordinator } from '../src/views/tui/modal-coordinator.js' +import { BraidTerminalApp } from '../src/views/tui/terminal-app.js' import { TerminalChrome } from '../src/views/tui/terminal-chrome.js' import { BraidShell } from '../src/views/tui/terminal-shell.js' import { createBraidTheme } from '../src/views/tui/theme.js' @@ -36,9 +37,11 @@ function viewForChrome(): BraidViewModel { workspace: '/home/drew/code/.worktrees/braid-integration', profileName: 'Release engineer', runner: 'pi', - model: 'tangle-router/glm-5.2', + model: 'openai-codex/gpt-5.6-luna', effort: 'high', - maxOutputTokens: 8192, + maxVisibleOutputTokens: 8192, + maxReasoningTokens: 4096, + maxTotalOutputTokens: 12_288, connection: 'Local CLI Bridge', conversationTitle: 'New conversation', branch: 'branch-1', @@ -81,13 +84,13 @@ test('chrome uses complete responsive groups at every reference width', () => { view, quitArmed: false, activityVisible: false, - navigationHint: 'Ctrl+P commands', + navigationHint: '/ commands · Ctrl+P', composerMode: 'queue', }) const narrow = plainLines(chrome, 40) assert.equal(narrow.length, 1) - assert.match(narrow[0] ?? '', /Release engineer.*Ctrl\+P commands/u) + assert.equal(narrow[0], 'Release engineer') assert.doesNotMatch(narrow.join('\n'), /\/home\/drew|\.worktrees|…/u) const standardTop = chrome.renderTop(80).join('\n') @@ -95,17 +98,19 @@ test('chrome uses complete responsive groups at every reference width', () => { const standard = [standardTop, standardBottom].join('\n') assert.equal(standardTop, '') assert.match(standardBottom, /profile Release engineer/u) - assert.match(standardBottom, /pi \/ glm-5\.2/u) - assert.match(standard, /Local CLI Bridge/u) - assert.match(standardBottom, /Ctrl\+P commands/u) + assert.match(standardBottom, /pi \/ gpt-5\.6-luna/u) + assert.match(standard, /via Local CLI Bridge/u) + assert.match(standardBottom, /\/ commands/u) + assert.doesNotMatch(standardBottom, /Ctrl\+P/u) assert.doesNotMatch(standard, /braid|cwd|New conversation|branch-1|in 1\.2k|out 567|\$0\.0312/u) assert.doesNotMatch(standard, /…/u) const wide = plainLines(chrome, 120).join('\n') - assert.match(wide, /profile Release engineer/u) - assert.match(wide, /pi \/ tangle-router\/glm-5\.2/u) + assert.match(wide, /Release engineer/u) + assert.match(wide, /profile Release engineer · pi \/ openai-codex\/gpt-5\.6-luna/u) assert.match(wide, /Local CLI Bridge/u) - assert.match(wide, /high/u) + assert.match(wide, / · high/u) + assert.doesNotMatch(wide, /backend CLI Bridge|caps/u) assert.match(wide, /in 1\.2k/u) assert.match(wide, /out 567/u) assert.match(wide, /\$0\.0312/u) @@ -113,12 +118,123 @@ test('chrome uses complete responsive groups at every reference width', () => { wide, /braid|cwd|New conversation|branch-1|output ≤|\/home\/drew|\.worktrees|…/u, ) + assert.equal(plainLines(chrome, 120).length, 1) for (const width of [1, 2, 10, 40, 80, 120, 200]) { for (const line of plainLines(chrome, width)) assert.ok(visibleWidth(line) <= width) } }) +test('command palette stays isolated and keeps close controls at narrow and wide sizes', async () => { + for (const [columns, rows] of [ + [40, 12], + [80, 24], + [120, 40], + ] as const) { + const terminal = new VirtualTerminal(columns, rows) + const tui = new TuiMainScreen(terminal) + const app = createBraidApplication({ fixture: 'deterministic' }) + app.initialize('/workspace') + const view = new BraidTerminalApp({ + controller: createApplicationUiController(app), + tui, + theme, + workspace: '/workspace', + nextOperationId: () => `palette-${columns}`, + }) + const done = view.start() + try { + await terminal.waitForRender() + terminal.sendInput('\u0010') + await terminal.waitForRender() + const screen = terminal.getViewport().join('\n') + assert.match(screen, /Commands/u) + assert.match(screen, /←\/esc close/u) + assert.doesNotMatch(screen, /profile Braid starter/u) + if (columns >= 80) assert.match(screen, /Inspect and manage connections/u) + for (const line of terminal.getViewport()) assert.ok(visibleWidth(line) <= columns) + } finally { + view.stop() + await done + } + } +}) + +test('wide chrome keeps measured sandbox facts as independent context items', () => { + const base = viewForChrome() + const environment = { + id: 'environment-sandbox-facts', + connectionId: 'connection-sandbox', + kind: 'sandbox', + provider: 'tangle-sandbox', + lifecycle: 'active', + lifecycleMode: 'retained', + location: 'remote', + runtimeEndpointHost: 'sandbox.example.test', + machineId: 'machine-a10', + requestedRegion: 'us-central', + verifiedRegion: 'us-central', + storagePersistence: 'persistent-home', + requestedResources: { cpuCores: 4, memoryMB: 8192, diskGB: 80 }, + resourceSample: { + cgroupVersion: 2, + memoryCurrentMb: 512, + memoryPeakMb: 768, + cpuUsageUsec: 2_500, + sampledAt: '2026-08-15T00:00:01.000Z', + }, + gpu: { + provider: 'tangle-sandbox', + accelerator: 'A10', + count: 1, + status: 'ready', + billedCustomerCostUsd: 0.1234, + }, + unavailableTelemetry: [], + createdAt: '2026-08-15T00:00:00.000Z', + updatedAt: '2026-08-15T00:00:01.000Z', + } satisfies EnvironmentView + const run = base.runs[0] + assert.ok(run) + const view: BraidViewModel = { + ...base, + activeRunId: run.id, + environments: [environment], + runs: [{ ...run, environmentId: environment.id, provider: 'tangle-sandbox' }], + } + const chrome = new TerminalChrome(theme) + chrome.setState({ + view, + quitArmed: false, + activityVisible: false, + navigationHint: '/ commands · Ctrl+P', + composerMode: 'queue', + }) + + const wideReference = chrome.render(120).join('\n') + assert.match(wideReference, /host sandbox\.example\.test/u) + assert.match(wideReference, /machine machine-a10/u) + assert.doesNotMatch(wideReference, /unknown|not reported/u) + + const mediumWide = chrome.render(160).join('\n') + assert.match(mediumWide, /sample mem 512MB/u) + assert.doesNotMatch(mediumWide, /unknown|not reported/u) + + const wide = chrome.render(200).join('\n') + assert.match(wide, /host sandbox\.example\.test/u) + assert.match(wide, /machine machine-a10/u) + assert.match(wide, /region us-central/u) + assert.match(wide, /sample mem 512MB/u) + assert.match(wide, /requested 4cpu · 8GB · 80GB/u) + assert.match(wide, /gpu 1× A10 \$0\.1234/u) + assert.match(wide, /in 1\.2k|out 567|\$0\.0312/u) + for (const width of [40, 80, 120, 200]) { + const lines = chrome.render(width) + assert.doesNotMatch(lines.join('\n'), /unknown|not reported/u) + for (const line of lines) assert.ok(visibleWidth(line) <= width) + } +}) + test('chrome exposes active-run controls and failure recovery without hiding outcome identity', () => { const chrome = new TerminalChrome(theme) const base = viewForChrome() @@ -139,12 +255,13 @@ test('chrome exposes active-run controls and failure recovery without hiding out }, quitArmed: false, activityVisible: false, - navigationHint: 'Ctrl+P commands', + navigationHint: '/ commands · Ctrl+P', composerMode: 'queue', }) const active = chrome.render(80).join('\n') + assert.match(active, /profile Release engineer · pi \/ gpt-5\.6-luna/u) + assert.match(active, /via not connected/u) assert.match(active, /Ctrl\+C cancel/u) - assert.match(active, /Enter queues · Alt\+S steer/u) chrome.setState({ view: { @@ -162,12 +279,13 @@ test('chrome exposes active-run controls and failure recovery without hiding out }, quitArmed: false, activityVisible: false, - navigationHint: 'Ctrl+P commands', + navigationHint: '/ commands · Ctrl+P', composerMode: 'queue', }) const failed = chrome.render(80).join('\n') + assert.match(failed, /profile Release engineer · pi \/ gpt-5\.6-luna/u) + assert.match(failed, /via Local CLI Bridge/u) assert.match(failed, /failed/u) - assert.match(failed, /\/activity details · \/new/u) assert.doesNotMatch(failed, /operation-that-is-long-enough-to-shorten/u) chrome.setState({ @@ -179,12 +297,12 @@ test('chrome exposes active-run controls and failure recovery without hiding out }, quitArmed: false, activityVisible: false, - navigationHint: 'Ctrl+P commands', + navigationHint: '/ commands · Ctrl+P', composerMode: 'queue', }) const uncertain = chrome.render(80).join('\n') + assert.match(uncertain, /profile Release engineer · pi \/ gpt-5\.6-luna/u) assert.match(uncertain, /outcome unknown/u) - assert.match(uncertain, /\/activity inspect/u) assert.doesNotMatch(uncertain, /failed|\/new/u) }) @@ -228,6 +346,32 @@ test('modal coordination honors the row breakpoint at standard and wide widths', assert.deepEqual(shown, [{ anchor: 'top-left', width: '100%', maxHeight: '100%', margin: 0 }]) }) +test('full-screen modal back closes an input surface with the left action', () => { + let hidden = false + const handle = { + hide() { + hidden = true + }, + focus() {}, + isHidden: () => hidden, + } as unknown as OverlayHandle + const tui = { + terminal: { columns: 40, rows: 12 }, + showOverlay: () => handle, + } as unknown as TUI + const component = { + handleInput() {}, + render: () => [], + invalidate() {}, + } as unknown as Component + const modals = new ModalCoordinator(tui) + modals.open(component) + + assert.equal(modals.backOrCloseIfFullScreen(), true) + assert.equal(hidden, true) + assert.equal(modals.hasOpen(), false) +}) + test('published Pi virtual terminals keep the composer and valid cells at all sizes', async () => { const view = viewForChrome() for (const [columns, rows] of sizes) { @@ -249,11 +393,15 @@ test('published Pi virtual terminals keep the composer and valid cells at all si assert.equal(viewport.length, rows, `${columns}x${rows} row count`) for (const line of viewport) assert.ok(visibleWidth(line) <= columns, `${columns}x${rows} line exceeds width`) - assert.doesNotMatch(viewport.join('\n'), /braid|completed|─/u) + assert.doesNotMatch(viewport.join('\n'), /braid|completed/u) const prompt = viewport.findIndex((line) => line.includes('›')) assert.ok(prompt >= 0, `${columns}x${rows} composer prompt`) assert.equal(rows - prompt, 4, `${columns}x${rows} composer and context rows`) - assert.match(viewport.at(-1) ?? '', /Release engineer/u) + assert.match(viewport[prompt - 1] ?? '', /─{8,}/u) + assert.doesNotMatch(viewport[prompt - 1] ?? '', /\/ commands/u) + const context = viewport.slice(prompt + 3) + assert.ok(context.some((line) => line.includes('Release engineer'))) + if (columns >= 100) assert.match(context.at(-1) ?? '', /in 1\.2k|out 567|\$0\.0312/u) assert.doesNotMatch(viewport.join('\n'), /\/home\/drew|\.worktrees/u) tui.stop() @@ -293,6 +441,7 @@ test('composer derives truthful actions and keeps three usable rows at 40x12', a assert.equal(projection.queuePosition, 2) assert.match(projection.actionLabel, /queue next #2/u) assert.match(projection.actionLabel, /Alt\+S steer/u) + assert.match(projection.hint, /type \/ for commands/u) const steering = composerProjectionFor(active, 'steer') assert.equal(steering.action, 'steer') @@ -328,6 +477,8 @@ test('composer derives truthful actions and keeps three usable rows at 40x12', a const prompt = viewport.findIndex((line) => line.includes('›')) assert.ok(prompt >= 0) assert.equal(viewport.length - prompt, 4, 'composer must retain three usable rows and context') + assert.match(viewport[prompt - 1] ?? '', /─{8,}/u) + assert.doesNotMatch(viewport[prompt - 1] ?? '', /\/ commands/u) assert.match(viewport.join('\n'), /working · Ctrl\+C stop/u) assert.match(viewport[prompt] ?? '', /› queue #2/u) assert.equal(viewport.length, 12) @@ -363,7 +514,9 @@ test('composer bounds long drafts without changing Pi editor input behavior', () const prompt = lines.findIndex((line) => line.includes('›')) assert.ok(prompt >= 0) assert.equal(lines.length - prompt, 4) - assert.doesNotMatch(lines.join('\n'), /─|alt\+enter newline/u) + assert.match(lines[prompt - 1] ?? '', /─{8,}/u) + assert.doesNotMatch(lines[prompt - 1] ?? '', /\/ commands/u) + assert.doesNotMatch(lines.join('\n'), /alt\+enter newline/u) assert.equal(lines.length, 12) for (const line of lines) assert.ok(visibleWidth(line) <= 40) }) diff --git a/test/terminal-usage-status.test.ts b/test/terminal-usage-status.test.ts index 1b04080..b01282c 100644 --- a/test/terminal-usage-status.test.ts +++ b/test/terminal-usage-status.test.ts @@ -7,7 +7,7 @@ import type { BraidViewModel } from '../src/views/shared/models.js' import { activityDocument } from '../src/views/tui/activity-browser.js' import { executionTargetFor } from '../src/views/tui/execution-target.js' import { TerminalChrome } from '../src/views/tui/terminal-chrome.js' -import { metricsFor } from '../src/views/tui/terminal-usage.js' +import { footerMetricsFor, metricsFor } from '../src/views/tui/terminal-usage.js' import { createBraidTheme } from '../src/views/tui/theme.js' const theme = createBraidTheme({ colors: false, highContrast: true, reducedMotion: true }) @@ -21,14 +21,15 @@ test('terminal usage keeps direct, analysis, and worker measurements separate an 'out ≥20', '≥$0.0100', 'calls ≥2', - 'model ≥120ms', - 'workers in 0 · out 0 · $0.0000 · calls 0 · model 0ms', + 'latency ≥120ms', + 'workers in 0 · out 0 · $0.0000 · calls 0 · latency 0ms', ]) const context = activityDocument(view).context ?? '' - assert.match(context, /in ≥10.*calls ≥2.*model ≥120ms/u) + assert.match(context, /in ≥10.*calls ≥2.*latency ≥120ms/u) assert.doesNotMatch(context, /analysis|unknown|missing/u) - assert.match(context, /workers .*calls 0.*model 0ms/u) + assert.match(context, /workers .*calls 0.*latency 0ms/u) + assert.deepEqual(footerMetricsFor(view), ['in ≥10', 'out ≥20', '≥$0.0100', 'latency ≥120ms']) }) test('terminal chrome keeps telemetry out of narrow layouts', () => { @@ -37,7 +38,7 @@ test('terminal chrome keeps telemetry out of narrow layouts', () => { view: usageView(), quitArmed: false, activityVisible: false, - navigationHint: 'Ctrl+P commands', + navigationHint: '/ commands · Ctrl+P', composerMode: 'queue', }) @@ -65,6 +66,7 @@ test('terminal usage presents a complete estimate instead of an observed-cost fl assert.match(metricsFor(estimated).join(' · '), /~\$0\.1500/u) assert.doesNotMatch(metricsFor(estimated).join(' · '), /≥\$0\.1000/u) + assert.doesNotMatch(footerMetricsFor(estimated).join(' · '), /\$/u) const freeEstimate = { ...estimated, @@ -89,7 +91,9 @@ test('execution identity comes from one active run receipt instead of current pr runner: 'codex', model: 'openai/gpt-next', effort: 'medium', - maxOutputTokens: 4096, + maxVisibleOutputTokens: 4096, + maxReasoningTokens: 2048, + maxTotalOutputTokens: 6144, connection: 'Next connection', status: 'running', statusText: 'streaming', @@ -103,7 +107,9 @@ test('execution identity comes from one active run receipt instead of current pr runner: 'pi', model: 'tangle-router/glm-5.2', effort: 'high', - maxOutputTokens: 16_384, + maxVisibleOutputTokens: 16_384, + maxReasoningTokens: 8_192, + maxTotalOutputTokens: 24_576, connection: 'Local CLI Bridge', connectionId: 'connection-run', environmentId: 'environment-run', @@ -142,8 +148,11 @@ test('execution identity comes from one active run receipt instead of current pr profileDigest: 'digest-run', runner: 'pi', model: 'tangle-router/glm-5.2', + backend: 'cli-bridge', effort: 'high', - maxOutputTokens: 16_384, + maxVisibleOutputTokens: 16_384, + maxReasoningTokens: 8_192, + maxTotalOutputTokens: 24_576, connection: 'Local CLI Bridge', connectionId: 'connection-run', environment: view.environments[0], @@ -154,13 +163,14 @@ test('execution identity comes from one active run receipt instead of current pr view, quitArmed: false, activityVisible: true, - navigationHint: 'Ctrl+P commands', + navigationHint: '/ commands · Ctrl+P', composerMode: 'queue', }) const rendered = chrome.render(120).join('\n') - assert.match(rendered, /profile Exact run profile/u) + assert.match(rendered, /Exact run profile/u) assert.match(rendered, /pi \/ tangle-router\/glm-5\.2/u) - assert.match(rendered, /Local CLI Bridge/u) + assert.match(rendered, /CLI Bridge/u) + assert.doesNotMatch(rendered, /backend cli-bridge|pi · tangle-router/u) assert.doesNotMatch(rendered, /exec local CLI|active/u) assert.doesNotMatch(rendered, /Next profile|openai\/gpt-next|Next connection/u) @@ -168,7 +178,7 @@ test('execution identity comes from one active run receipt instead of current pr assert.match(activity.context ?? '', /Exact run profile · pi · tangle-router\/glm-5\.2/u) const detail = activity.rows[0]?.detailLines.join('\n') ?? '' assert.match(detail, /profile digest: digest-run/u) - assert.match(detail, /max output tokens: 16384/u) + assert.match(detail, /max visible output tokens: 16384/u) const { activeRunId: _activeRunId, ...idleView } = view const idleTarget = executionTargetFor({ ...idleView, status: 'completed' }) @@ -178,12 +188,146 @@ test('execution identity comes from one active run receipt instead of current pr assert.equal(idleTarget.environment, undefined) }) +test('the wide rail shows only observed sandbox facts and measured usage', () => { + const base = usageView() + const view: BraidViewModel = { + ...base, + status: 'running', + statusText: 'streaming', + activeRunId: 'sandbox-run', + runs: [ + { + id: 'sandbox-run', + status: 'running', + completeness: 'streaming', + profileName: base.profileName, + runner: base.runner, + model: base.model, + effort: 'high', + maxVisibleOutputTokens: 16_384, + maxReasoningTokens: 8_192, + maxTotalOutputTokens: 24_576, + provider: 'tangle-sandbox', + connection: 'Tangle Sandbox', + environmentId: 'sandbox-1', + usage: { model: base.model }, + }, + ], + environments: [ + { + id: 'sandbox-1', + connectionId: 'sandbox-connection', + kind: 'sandbox', + provider: 'tangle-sandbox', + lifecycle: 'ready', + location: 'remote', + runtimeEndpointHost: '10.0.0.7', + machineId: 'machine-a10', + verifiedRegion: 'us-central', + requestedResources: { cpuCores: 2, memoryMB: 4_096, diskGB: 20 }, + resourceSample: { + cgroupVersion: 2, + memoryCurrentMb: 512, + memoryPeakMb: 768, + cpuUsageUsec: 2_500, + sampledAt: '2026-08-15T00:00:01.000Z', + }, + gpu: { + provider: 'tangle', + accelerator: 'A10', + count: 1, + status: 'allocated', + billedCustomerCostUsd: 0.0123, + }, + unavailableTelemetry: ['physical-ip'], + createdAt: '2026-08-15T00:00:00.000Z', + updatedAt: '2026-08-15T00:00:01.000Z', + }, + ], + } + const chrome = new TerminalChrome(theme) + chrome.setState({ + view, + quitArmed: false, + activityVisible: false, + navigationHint: '/ commands · Ctrl+P', + composerMode: 'queue', + }) + + const rendered = chrome.render(200).join('\n') + assert.match(rendered, /Sandbox/u) + assert.doesNotMatch(rendered, /backend tangle-sandbox/u) + assert.match(rendered, /host 10\.0\.0\.7/u) + assert.match(rendered, /machine machine-a10/u) + assert.match(rendered, /region us-central/u) + assert.match(rendered, /sample mem 512MB/u) + assert.match(rendered, /requested 2cpu · 4GB · 20GB/u) + assert.match(rendered, /gpu 1× A10 \$0\.0123/u) + assert.match(rendered, /high · caps vis 16k · reas 8\.2k · total 25k/u) + assert.doesNotMatch(rendered, /fixture\/deterministic|thinking none|unknown|not reported/u) + assert.match(rendered, /in 10|out 20|≥\$0\.0100|latency ≥120ms/u) + assert.doesNotMatch(rendered, /physical-ip|unknown/u) + const estimatedGpuView: BraidViewModel = { + ...view, + environments: view.environments.map((environment) => ({ + ...environment, + ...(environment.gpu === undefined + ? {} + : (() => { + const { billedCustomerCostUsd: _billedCustomerCostUsd, ...gpu } = environment.gpu + return { gpu: { ...gpu, estimatedCustomerCostUsd: 0.42 } } + })()), + })), + } + chrome.setState({ + view: estimatedGpuView, + quitArmed: false, + activityVisible: false, + navigationHint: '/ commands · Ctrl+P', + composerMode: 'queue', + }) + const estimatedGpuFooter = chrome.render(200).join('\n') + assert.match(estimatedGpuFooter, /gpu 1× A10/u) + assert.doesNotMatch(estimatedGpuFooter, /\$0\.4200/u) + chrome.setState({ + view, + quitArmed: false, + activityVisible: false, + navigationHint: '/ commands · Ctrl+P', + composerMode: 'queue', + }) + for (const width of [60, 80, 99]) { + const medium = chrome.render(width).join('\n') + assert.match(medium, /profile Release engineer/u) + assert.match(medium, /Ctrl\+C cancel/u) + if (width >= 80) { + assert.match(medium, /pi \/ gpt-5\.6-luna/u) + assert.match(medium, /via Sandbox/u) + } + assert.doesNotMatch( + medium, + /host |machine |region |sample |requested |gpu |\bin |\bout |\$|latency /u, + ) + assert.doesNotMatch(medium, /unknown|not reported|…/u) + } + for (const width of [40, 60, 80, 99, 100, 120, 160, 200]) { + for (const line of chrome.render(width)) assert.ok(visibleWidth(line) <= width) + } +}) + function usageView(): BraidViewModel { const app = createBraidApplication({ fixture: 'deterministic' }) app.initialize('/workspace') const base = createApplicationUiController(app).view() return { ...base, + profileName: 'Release engineer', + runner: 'pi', + model: 'openai-codex/gpt-5.6-luna', + effort: 'high', + maxVisibleOutputTokens: 16_384, + maxReasoningTokens: 8_192, + maxTotalOutputTokens: 24_576, sessionUsage: { turns: { sourceCount: 2, diff --git a/test/trace-analysis-configuration.test.ts b/test/trace-analysis-configuration.test.ts index 80cfdfb..034af93 100644 --- a/test/trace-analysis-configuration.test.ts +++ b/test/trace-analysis-configuration.test.ts @@ -585,7 +585,7 @@ test('runtime-owned trace model call preserves canonical messages, limits, usage { role: 'system', content: 'private analyst instruction' }, { role: 'user', content: 'private trace question' }, ]) - assert.equal(receivedBody?.max_tokens, 64) + assert.equal(receivedBody?.max_tokens, undefined) assert.equal(receivedBody?.temperature, 0.2) assert.deepEqual(receivedBody?.response_format, { type: 'json_schema', @@ -638,6 +638,9 @@ test('runtime-owned CLI Bridge analysis uses the harness executor with portable default: 'tangle-router/glm-5.2', provider: 'tangle-router', reasoningEffort: 'high', + maxVisibleOutputTokens: 128, + maxReasoningTokens: 256, + maxTotalOutputTokens: 384, }, }, connection: selected, @@ -682,7 +685,10 @@ test('runtime-owned CLI Bridge analysis uses the harness executor with portable assert.equal(executionProfile.model?.default, 'tangle-router/glm-5.2') assert.equal(executionProfile.model?.provider, 'tangle-router') assert.equal(executionProfile.model?.reasoningEffort, 'none') - assert.equal(executionProfile.model?.metadata?.maxTokens, 64) + assert.equal(executionProfile.model?.maxVisibleOutputTokens, 64) + assert.equal(executionProfile.model?.maxReasoningTokens, 256) + assert.equal(executionProfile.model?.maxTotalOutputTokens, 384) + assert.equal(Object.hasOwn(executionProfile.model?.metadata ?? {}, 'maxTokens'), false) assert.equal(executionProfile.model?.metadata?.retry, undefined) assert.match(executionProfile.prompt?.systemPrompt ?? '', /text-generation endpoint/u) assert.match(executionProfile.prompt?.systemPrompt ?? '', /messages array/u) diff --git a/test/tui-core-workflows.test.ts b/test/tui-core-workflows.test.ts index 3b97183..1804518 100644 --- a/test/tui-core-workflows.test.ts +++ b/test/tui-core-workflows.test.ts @@ -712,6 +712,81 @@ test('comparison view leads with both outcomes and pages through every captured assert.match(panel.render(80).join('\n'), /run\.cost_usd/u) }) +test('left and escape return from every full-screen secondary browser', () => { + const comparison = { + baseline: { + label: 'baseline' as const, + runId: 'run-baseline', + sourceDigest: 'digest-baseline', + outcome: 'completed', + cost: '$0.02', + costProvenance: 'measured', + }, + candidate: { + label: 'candidate' as const, + runId: 'run-candidate', + sourceDigest: 'digest-candidate', + outcome: 'completed', + cost: '$0.01', + costProvenance: 'measured', + }, + pairCount: 1, + unpairedBaseline: 0, + unpairedCandidate: 0, + sampleLimit: 'one pair', + fields: [], + pairedFacts: [], + semantic: { status: 'unavailable', reason: 'not run' }, + replayed: false, + } + + for (const key of ['\u001b[D', '\u001b']) { + const analysis = new AnalysisViewPanel(theme) + analysis.setView(analysisView('failure')) + analysis.render(40) + analysis.handleInput(key) + assert.equal(analysis.mode, 'list', `analysis ${JSON.stringify(key)}`) + + const comparisonPanel = new ComparisonViewPanel(theme) + comparisonPanel.setView(comparison) + comparisonPanel.render(40) + comparisonPanel.handleInput(key) + assert.equal(comparisonPanel.mode, 'list', `comparison ${JSON.stringify(key)}`) + } + + for (const key of ['\u001b[D', '\u001b']) { + let graphCloses = 0 + const graph = new GraphView(theme, { onClose: () => (graphCloses += 1) }) + graph.setView(graphView()) + graph.render(40) + graph.handleInput(key) + assert.equal(graphCloses, 1, `graph ${JSON.stringify(key)}`) + + let workerCloses = 0 + const workers = new ActivityBrowserPanel(theme, { + view: () => ({ + ...baseView(), + activity: [ + { + id: 'worker:worker-1', + kind: 'worker', + title: 'worker one', + status: 'completed', + entityType: 'worker', + entityId: 'worker-1', + }, + ], + }), + rows: () => 12, + onClose: () => (workerCloses += 1), + scope: 'workers', + }) + workers.render(40) + workers.handleInput(key) + assert.equal(workerCloses, 1, `worker ${JSON.stringify(key)}`) + } +}) + test('approval actions are navigable and secret responses never render values', async () => { const responses: unknown[] = [] const shell = new InteractionShell({ ...permission, queueTotal: 3 }, theme, (response) => @@ -831,10 +906,10 @@ test('fork and confirmation dialogs expose only short, actionable keys', () => { const lines = dialog.render(40) assertFits(lines, 40) assert.match(lines.join('\n'), /will delete permanently/u) - assert.match(lines.join('\n'), /enter\/y confirm · n\/esc cancel/u) + assert.match(lines.join('\n'), /enter\/y confirm · n\/←\/esc cancel/u) }) -test('digit-leading text, secret, and number answers stay editable', () => { +test('digit-leading answers stay editable and left cancels full-screen text input', () => { const secretResponse: unknown[] = [] const secretShell = new InteractionShell( { @@ -869,9 +944,27 @@ test('digit-leading text, secret, and number answers stay editable', () => { ) textShell.handleInput('ab') textShell.handleInput('\u001b[D') + assert.deepEqual(textResponse, [{ outcome: 'cancel' }]) textShell.handleInput('c') textShell.handleInput('\r') - assert.deepEqual(textResponse, [{ outcome: 'accept', value: 'acb' }]) + assert.deepEqual(textResponse, [{ outcome: 'cancel' }]) + + const plainTextResponse: unknown[] = [] + const plainTextShell = new InteractionShell( + { + ...permission, + interactionId: 'interaction-plain-text', + kind: 'question', + answerSpec: { kind: 'text', required: true, secret: false }, + allowedOutcomes: ['accept', 'reject', 'cancel'], + secret: false, + }, + theme, + (response) => plainTextResponse.push(response), + ) + plainTextShell.handleInput('abc') + plainTextShell.handleInput('\r') + assert.deepEqual(plainTextResponse, [{ outcome: 'accept', value: 'abc' }]) const numberResponse: unknown[] = [] const numberShell = new InteractionShell( @@ -922,7 +1015,7 @@ test('short interaction surfaces keep validation failures visible', () => { assert.match(screen, /Enter a number in the allowed range\./u) assert.match(screen, /alt\+1 approve · alt\+2 reject/u) assert.match(screen, /alt\+3 cancel/u) - assert.match(screen, /enter submit · esc cancel/u) + assert.match(screen, /enter submit · ←\/esc cancel/u) }) test('alt-digit keys reach every allowed outcome without taking editable digits', () => { diff --git a/test/tui.test.ts b/test/tui.test.ts index fb58c0c..c898f09 100644 --- a/test/tui.test.ts +++ b/test/tui.test.ts @@ -264,7 +264,7 @@ test('composer fallback steers exactly once without queueing or sending', async const harness = await startSteeringTerminal() try { await harness.terminal.waitForRender() - assert.match(harness.terminal.getViewport().join('\n'), /Enter steers/u) + assert.match(harness.terminal.getViewport().join('\n'), /› steer/u) harness.terminal.sendInput('correct course') harness.terminal.sendInput('\r') await waitUntil(() => harness.calls.steer === 1) @@ -302,10 +302,10 @@ test('Alt+S changes an active composer from queue to steer', async () => { const harness = await startSteeringTerminal(true) try { await harness.terminal.waitForRender() - assert.match(harness.terminal.getViewport().join('\n'), /Enter queues · Alt\+S steer/u) + assert.match(harness.terminal.getViewport().join('\n'), /› queue #1/u) harness.terminal.sendInput('\u001bs') await harness.terminal.waitForRender() - assert.match(harness.terminal.getViewport().join('\n'), /Enter steers · Alt\+S queue/u) + assert.match(harness.terminal.getViewport().join('\n'), /› steer/u) harness.terminal.sendInput('change direction') harness.terminal.sendInput('\r') @@ -431,7 +431,7 @@ test('the searchable command overlay restores editor focus after close', async ( assert.doesNotMatch(overlay, /alt\+enter newline/u) terminal.sendInput('\u001b') await terminal.waitForRender() - assert.match(terminal.getViewport().join('\n'), /profile Braid starter.*Ctrl\+P commands/u) + assert.match(terminal.getViewport().join('\n'), /profile Braid starter.*\/ commands/u) terminal.sendInput('focus restored') assert.equal(view.editor.getText(), 'focus restored') @@ -462,7 +462,7 @@ test('Ctrl+K exposes one five-row run switcher and updates the branch runner', a for (const label of ['Profile', 'Connection', 'Runner', 'Model', 'Thinking']) { assert.match(switcher, new RegExp(`\\b${label}\\b`, 'u')) } - assert.match(switcher, /enter to change · esc to close/u) + assert.match(switcher, /enter to change · ←\/esc close/u) terminal.sendInput('\u001b[B') terminal.sendInput('\u001b[B') diff --git a/test/w6-ui.test.ts b/test/w6-ui.test.ts index a470c45..68c10ef 100644 --- a/test/w6-ui.test.ts +++ b/test/w6-ui.test.ts @@ -4,11 +4,13 @@ import { TuiMainScreen, visibleWidth } from '@earendil-works/pi-tui' import { createApplicationUiController } from '../src/adapters/tui/application-ui-controller.js' import { createBraidApplication } from '../src/app/composition.js' import { MemoryJournal } from '../src/app/journal.js' +import type { ProfileSummary } from '../src/app/profiles.js' import { FixedClock } from '../src/ports/clock.js' import type { BraidUiController } from '../src/views/shared/intents.js' import type { BraidViewModel, InteractionView, ViewStatus } from '../src/views/shared/models.js' import { ActivityView } from '../src/views/tui/activity.js' import { AnalysisViewPanel } from '../src/views/tui/analysis.js' +import { profileItems } from '../src/views/tui/configuration-presenters.js' import { ConnectionSetupViewPanel } from '../src/views/tui/connection-setup.js' import { DetailsViewPanel } from '../src/views/tui/details.js' import { DynamicAutocompleteProvider } from '../src/views/tui/dynamic-autocomplete.js' @@ -303,25 +305,41 @@ test('stable chrome keeps identity and status outside transcript history', () => view: viewFor('completed'), quitArmed: false, activityVisible: false, - navigationHint: 'Ctrl+P commands', + navigationHint: '/ commands · Ctrl+P', composerMode: 'queue', }) const lines = chrome.render(40) const firstLine = lines[0] ?? '' assert.equal(lines.length, 1) - assert.match(firstLine, /reviewer.*Ctrl\+P commands/u) + assert.equal(firstLine, 'reviewer') assert.doesNotMatch(firstLine, /fixture|deterministic/u) assert.ok(visibleWidth(firstLine) <= 40) const standard = chrome.render(80) assert.equal(standard.length, 1) - assert.match(standard[0] ?? '', /reviewer.*pi \/ deterministic/u) - assert.match(standard[0] ?? '', /fixture/u) - assert.doesNotMatch(standard[0] ?? '', /deterministic fixture/u) - assert.match(standard[0] ?? '', /Ctrl\+P commands/u) + assert.match(standard[0] ?? '', /reviewer.*pi/u) + assert.match(standard[0] ?? '', /via local/u) + assert.doesNotMatch(standard[0] ?? '', /fixture|deterministic fixture/u) + assert.match(standard[0] ?? '', /\/ commands/u) + assert.doesNotMatch(standard[0] ?? '', /Ctrl\+P/u) + const wide = chrome.render(120).join('\n') + assert.match(wide, /reviewer · pi · local/u) + assert.doesNotMatch(wide, /fixture|deterministic|50ms|in 6|out 12/u) for (const line of standard) assert.ok(visibleWidth(line) <= 80) }) +test('empty transcript keeps its starter hint beside the composer', () => { + const transcript = new TranscriptView(theme) + transcript.setViewportRows(8) + transcript.setView({ + ...viewFor('empty'), + messages: [], + runs: [], + }) + const lines = transcript.render(80) + assert.equal(lines.at(-1)?.trimEnd(), ' Ask reviewer anything.') +}) + test('terminal chrome aggregates known conversation metrics without filling gaps', () => { const baseRun = { status: 'completed' as const, completeness: 'complete' as const } const view = viewFor('completed') @@ -558,7 +576,7 @@ test('terminal presentation translates runtime result labels without changing de test('one searchable selector preserves query and supports keyboard selection', () => { let selected = '' - let cancelled = false + let cancellations = 0 const selector = new SearchableSelector({ title: 'items', items: [ @@ -570,14 +588,50 @@ test('one searchable selector preserves query and supports keyboard selection', selected = item.value }, onCancel: () => { - cancelled = true + cancellations += 1 }, }) selector.setQuery('quit') selector.handleInput('\r') assert.equal(selected, 'quit') selector.handleInput('\u001b') - assert.equal(cancelled, true) + selector.handleInput('\u001b[D') + assert.equal(cancellations, 2) +}) + +test('profile selector rows keep the profile identity intact at responsive widths', () => { + const profile = { + id: 'profile-braid-starter', + name: 'Braid starter', + tags: [], + source: { + kind: 'inline', + reference: 'workspace', + label: 'Braid starter', + writable: false, + trusted: true, + }, + digest: 'digest', + runner: 'pi', + model: 'openai-codex/gpt-5.6-luna', + tools: [], + skills: [], + connections: [], + } satisfies ProfileSummary + const [item] = profileItems([profile], profile.name, profile.id) + assert(item) + assert.doesNotMatch(item.description ?? '', /Braid starter/u) + + const selector = new SearchableSelector({ + title: 'profiles', + items: [item], + theme, + onSelect: () => {}, + onCancel: () => {}, + }) + for (const width of [40, 80, 120]) { + for (const line of selector.render(width)) assert.ok(visibleWidth(line) <= width) + } }) test('searching a selector resets stale navigation to the best match', () => { @@ -619,6 +673,8 @@ test('slash command autocomplete refreshes descriptions after capabilities chang const interaction: InteractionView = { runId: 'run-1', interactionId: 'interaction-1', + profileName: 'Product engineer', + runner: 'pi', kind: 'permission', prompt: 'Allow the tool?', subject: { type: 'file', title: 'secret.txt', preview: ['read-only preview'] }, @@ -638,6 +694,8 @@ test('interaction shell masks secret answers and accepts alt-digit outcomes', () shell.handleInput('TOPSECRET') const rendered = shell.render(80).join('\n') assert.equal(rendered.includes('TOPSECRET'), false) + assert.match(rendered, /Product engineer · pi/u) + assert.doesNotMatch(rendered, /run-1/u) shell.handleInput('\u001b1') shell.handleInput('\r') assert.deepEqual(response, { outcome: 'once', value: 'TOPSECRET' }) @@ -873,7 +931,7 @@ test('conversation shortcut opens the searchable conversation picker', async () const screen = terminal.getViewport().join('\n') assert.match(screen, /conversation/u) assert.match(screen, /New conversation/u) - assert.match(screen, /type to filter · enter to choose · esc to close/u) + assert.match(screen, /type to filter · enter to choose · ←\/esc close/u) view.stop() await done }) From f2b2a99a7b722ae6832b32895d124e587a57cd9b Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 03:07:19 -0600 Subject: [PATCH 08/25] test(tui): align focused secondary surfaces --- test/activity-document.test.ts | 21 +++------------------ test/tui-autocomplete.test.ts | 2 +- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/test/activity-document.test.ts b/test/activity-document.test.ts index b7c33da..3cecd3d 100644 --- a/test/activity-document.test.ts +++ b/test/activity-document.test.ts @@ -8,7 +8,6 @@ import { ActivityView } from '../src/views/tui/activity.js' import { activityDocument } from '../src/views/tui/activity-browser.js' import { projectActivityDocument } from '../src/views/tui/activity-document.js' import { omitUnreportedCostAndLatency } from '../src/views/tui/measurement-display.js' -import { activityVisibleFor } from '../src/views/tui/terminal-input-controller.js' import { BraidShell } from '../src/views/tui/terminal-shell.js' import { createBraidTheme } from '../src/views/tui/theme.js' import { VirtualTerminal } from './support/virtual-terminal.js' @@ -91,10 +90,7 @@ test('one activity document preserves event status, tree identity, duration, usa ], }) const missingDetail = missingUsage.rows.find((row) => row.id === 'run-1')?.detailLines.join('\n') - assert.match(missingDetail ?? '', /model calls: not reported/u) - assert.match(missingDetail ?? '', /model latency: not reported/u) - assert.match(missingDetail ?? '', /token measurement: not reported/u) - assert.match(missingDetail ?? '', /cost measurement: not reported/u) + assert.doesNotMatch(missingDetail ?? '', /model calls|model latency|not reported/u) const rail = new ActivityView(theme) rail.setView(view) @@ -102,14 +98,7 @@ test('one activity document preserves event status, tree identity, duration, usa assert.doesNotMatch(rail.render(80).join('\n'), /failed shell|permission denied/u) }) -test('the wide live-work rail uses a divider and remains explicitly opt-in', async () => { - const live = activityView() - const idle = { ...live, activity: [], messages: [] } - assert.equal(activityVisibleFor({ ...idle, activeRunId: 'run-1' }, 'auto'), false) - assert.equal(activityVisibleFor(idle, 'visible'), false) - assert.equal(activityVisibleFor(live, 'visible'), true) - assert.equal(activityVisibleFor({ ...idle, activeRunId: 'run-1' }, 'hidden'), false) - +test('live work stays in the focused activity surface instead of docking beside the transcript', async () => { const view = activityView() const terminal = new VirtualTerminal(120, 30) const tui = new TuiMainScreen(terminal) @@ -120,16 +109,12 @@ test('the wide live-work rail uses a divider and remains explicitly opt-in', asy () => {}, () => {}, ) - shell.setView(idle, false) - shell.setActivityVisible(true) - assert.doesNotMatch(shell.render(120).join('\n'), /│/u) shell.setView(view, false) - shell.setActivityVisible(true) tui.addChild(shell) tui.start() await terminal.waitForRender() - assert.match(terminal.getViewport().join('\n'), /│/u) + assert.doesNotMatch(terminal.getViewport().join('\n'), /│/u) tui.stop() }) diff --git a/test/tui-autocomplete.test.ts b/test/tui-autocomplete.test.ts index ad00156..177020b 100644 --- a/test/tui-autocomplete.test.ts +++ b/test/tui-autocomplete.test.ts @@ -243,7 +243,7 @@ test('the production terminal does not turn a fast profile command into unknown await waitUntil(() => view.editor.isShowingAutocomplete()) terminal.sendInput('profile') terminal.sendInput('\r') - await waitUntil(() => terminal.getViewport().join('\n').includes('profiles')) + await waitUntil(() => terminal.getViewport().join('\n').includes('Braid starter')) const screen = terminal.getViewport().join('\n') assert.doesNotMatch(screen, /unknown command \/profilnew/iu) assert.doesNotMatch(screen, /unknown command \/profilenew/iu) From 24e782a01078c08d61c6123be4e8d5337dc1f2af Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 03:07:14 -0600 Subject: [PATCH 09/25] fix(tui): restore separated composer metadata --- .../ui-regression-20260816/120x40.png | Bin 0 -> 9687 bytes .../ui-regression-20260816/80x24.png | Bin 0 -> 7749 bytes src/views/tui/composer-view.ts | 12 ++++------- src/views/tui/terminal-chrome.ts | 10 ++++----- src/views/tui/terminal-identity.ts | 3 ++- test/terminal-responsive.test.ts | 20 +++++++++--------- test/terminal-usage-status.test.ts | 2 +- 7 files changed, 22 insertions(+), 25 deletions(-) create mode 100644 artifacts/verification/ui-regression-20260816/120x40.png create mode 100644 artifacts/verification/ui-regression-20260816/80x24.png diff --git a/artifacts/verification/ui-regression-20260816/120x40.png b/artifacts/verification/ui-regression-20260816/120x40.png new file mode 100644 index 0000000000000000000000000000000000000000..91da00bba8e92111c2a672c09a830e89fefd9158 GIT binary patch literal 9687 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 P^Sq3NqIfarz4w0sI`C2$ literal 0 HcmV?d00001 diff --git a/src/views/tui/composer-view.ts b/src/views/tui/composer-view.ts index df7971a..d7fefa5 100644 --- a/src/views/tui/composer-view.ts +++ b/src/views/tui/composer-view.ts @@ -124,13 +124,9 @@ export class ComposerView extends Container { } const autocomplete = lines.slice(bottomBorder + 1) const topRule = composerTopRule(width, this.#editor.borderColor) - if (autocomplete.length === 0) return [topRule, ...body] - return [ - topRule, - ...body, - composerBorderLine(width, this.#projection.hint, this.#theme), - ...autocomplete, - ] + const bottomRule = composerBorderLine(width, this.#projection.hint, this.#theme) + if (autocomplete.length === 0) return [topRule, ...body, bottomRule] + return [topRule, ...body, bottomRule, ...autocomplete] } } @@ -188,7 +184,7 @@ export function composerBorderLine(width: number, label: string, theme: BraidThe } function promptActionLabel(projection: ComposerProjection): string | undefined { - if (projection.action === 'send') return undefined + if (projection.action === 'send') return 'new message' if (projection.action === 'queue') { return projection.queuePosition === undefined ? 'queue' : `queue #${projection.queuePosition}` } diff --git a/src/views/tui/terminal-chrome.ts b/src/views/tui/terminal-chrome.ts index 0aed08e..d971020 100644 --- a/src/views/tui/terminal-chrome.ts +++ b/src/views/tui/terminal-chrome.ts @@ -58,10 +58,9 @@ export class TerminalChrome implements Component { } const statusValue = conciseStatus(view, state.quitArmed, mode) const status = statusText(this.#theme, view, statusValue) - const hint = terminalValuePart( - this.#theme, - mode === 'narrow' ? '' : navigationHint(view, state.navigationHint, state.composerMode, mode), - ) + const navigation = + mode === 'narrow' ? '' : navigationHint(view, state.navigationHint, state.composerMode, mode) + const hint = terminalValuePart(this.#theme, navigation) const executionFacts = executionFactsFor(target) const measured = mode === 'wide' && !isSyntheticFixture(target.model) @@ -92,6 +91,7 @@ export class TerminalChrome implements Component { measured.length > 0 && view.activeRunId === undefined && status.length === 0 + const idleHint = navigation.startsWith('/ commands') ? [] : [hint] const right = state.quitArmed ? [status] : measuredOnRow1 @@ -100,7 +100,7 @@ export class TerminalChrome implements Component { ? [status] : view.activeRunId !== undefined || status.length > 0 ? [status, hint] - : [hint] + : idleHint const row1 = renderTerminalContext( this.#theme, identity, diff --git a/src/views/tui/terminal-identity.ts b/src/views/tui/terminal-identity.ts index d6bd79e..1baa56a 100644 --- a/src/views/tui/terminal-identity.ts +++ b/src/views/tui/terminal-identity.ts @@ -68,7 +68,8 @@ export function renderTerminalContext( : executionConnectionLabel(identity.backend, identity.connection), ) const effortValue = synthetic ? '' : cleanTerminalField(identity.effort) - const effort = mode === 'wide' && effortValue ? terminalValuePart(theme, effortValue) : '' + const effort = + mode === 'wide' && effortValue ? terminalValuePart(theme, `think ${effortValue}`) : '' const configuredLimits = synthetic ? '' : mode === 'wide' diff --git a/test/terminal-responsive.test.ts b/test/terminal-responsive.test.ts index db2cf73..f31f048 100644 --- a/test/terminal-responsive.test.ts +++ b/test/terminal-responsive.test.ts @@ -100,8 +100,7 @@ test('chrome uses complete responsive groups at every reference width', () => { assert.match(standardBottom, /profile Release engineer/u) assert.match(standardBottom, /pi \/ gpt-5\.6-luna/u) assert.match(standard, /via Local CLI Bridge/u) - assert.match(standardBottom, /\/ commands/u) - assert.doesNotMatch(standardBottom, /Ctrl\+P/u) + assert.doesNotMatch(standardBottom, /\/ commands|Ctrl\+P/u) assert.doesNotMatch(standard, /braid|cwd|New conversation|branch-1|in 1\.2k|out 567|\$0\.0312/u) assert.doesNotMatch(standard, /…/u) @@ -109,7 +108,7 @@ test('chrome uses complete responsive groups at every reference width', () => { assert.match(wide, /Release engineer/u) assert.match(wide, /profile Release engineer · pi \/ openai-codex\/gpt-5\.6-luna/u) assert.match(wide, /Local CLI Bridge/u) - assert.match(wide, / · high/u) + assert.match(wide, / · think high/u) assert.doesNotMatch(wide, /backend CLI Bridge|caps/u) assert.match(wide, /in 1\.2k/u) assert.match(wide, /out 567/u) @@ -396,10 +395,11 @@ test('published Pi virtual terminals keep the composer and valid cells at all si assert.doesNotMatch(viewport.join('\n'), /braid|completed/u) const prompt = viewport.findIndex((line) => line.includes('›')) assert.ok(prompt >= 0, `${columns}x${rows} composer prompt`) - assert.equal(rows - prompt, 4, `${columns}x${rows} composer and context rows`) + assert.equal(rows - prompt, 5, `${columns}x${rows} composer and context rows`) assert.match(viewport[prompt - 1] ?? '', /─{8,}/u) - assert.doesNotMatch(viewport[prompt - 1] ?? '', /\/ commands/u) - const context = viewport.slice(prompt + 3) + assert.match(viewport[prompt] ?? '', /› new message/u) + assert.match(viewport[prompt + 3] ?? '', /type \/ for commands/u) + const context = viewport.slice(prompt + 4) assert.ok(context.some((line) => line.includes('Release engineer'))) if (columns >= 100) assert.match(context.at(-1) ?? '', /in 1\.2k|out 567|\$0\.0312/u) assert.doesNotMatch(viewport.join('\n'), /\/home\/drew|\.worktrees/u) @@ -476,9 +476,9 @@ test('composer derives truthful actions and keeps three usable rows at 40x12', a const viewport = terminal.getViewport() const prompt = viewport.findIndex((line) => line.includes('›')) assert.ok(prompt >= 0) - assert.equal(viewport.length - prompt, 4, 'composer must retain three usable rows and context') + assert.equal(viewport.length - prompt, 5, 'composer must retain three usable rows and context') assert.match(viewport[prompt - 1] ?? '', /─{8,}/u) - assert.doesNotMatch(viewport[prompt - 1] ?? '', /\/ commands/u) + assert.match(viewport[prompt + 3] ?? '', /type \/ for commands/u) assert.match(viewport.join('\n'), /working · Ctrl\+C stop/u) assert.match(viewport[prompt] ?? '', /› queue #2/u) assert.equal(viewport.length, 12) @@ -513,9 +513,9 @@ test('composer bounds long drafts without changing Pi editor input behavior', () const lines = shell.render(40) const prompt = lines.findIndex((line) => line.includes('›')) assert.ok(prompt >= 0) - assert.equal(lines.length - prompt, 4) + assert.equal(lines.length - prompt, 5) assert.match(lines[prompt - 1] ?? '', /─{8,}/u) - assert.doesNotMatch(lines[prompt - 1] ?? '', /\/ commands/u) + assert.match(lines[prompt + 3] ?? '', /type \/ for commands/u) assert.doesNotMatch(lines.join('\n'), /alt\+enter newline/u) assert.equal(lines.length, 12) for (const line of lines) assert.ok(visibleWidth(line) <= 40) diff --git a/test/terminal-usage-status.test.ts b/test/terminal-usage-status.test.ts index b01282c..eb36f8a 100644 --- a/test/terminal-usage-status.test.ts +++ b/test/terminal-usage-status.test.ts @@ -263,7 +263,7 @@ test('the wide rail shows only observed sandbox facts and measured usage', () => assert.match(rendered, /sample mem 512MB/u) assert.match(rendered, /requested 2cpu · 4GB · 20GB/u) assert.match(rendered, /gpu 1× A10 \$0\.0123/u) - assert.match(rendered, /high · caps vis 16k · reas 8\.2k · total 25k/u) + assert.match(rendered, /think high · caps vis 16k · reas 8\.2k · total 25k/u) assert.doesNotMatch(rendered, /fixture\/deterministic|thinking none|unknown|not reported/u) assert.match(rendered, /in 10|out 20|≥\$0\.0100|latency ≥120ms/u) assert.doesNotMatch(rendered, /physical-ip|unknown/u) From 505b119ab77c544433dec044c54a7092d7b6b088 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 03:10:27 -0600 Subject: [PATCH 10/25] test(tui): follow separated composer hints --- test/tui.test.ts | 4 +++- test/w6-ui.test.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/tui.test.ts b/test/tui.test.ts index c898f09..14203a3 100644 --- a/test/tui.test.ts +++ b/test/tui.test.ts @@ -431,7 +431,9 @@ test('the searchable command overlay restores editor focus after close', async ( assert.doesNotMatch(overlay, /alt\+enter newline/u) terminal.sendInput('\u001b') await terminal.waitForRender() - assert.match(terminal.getViewport().join('\n'), /profile Braid starter.*\/ commands/u) + const restored = terminal.getViewport().join('\n') + assert.match(restored, /profile Braid starter/u) + assert.match(restored, /type \/ for commands/u) terminal.sendInput('focus restored') assert.equal(view.editor.getText(), 'focus restored') diff --git a/test/w6-ui.test.ts b/test/w6-ui.test.ts index 68c10ef..7eea193 100644 --- a/test/w6-ui.test.ts +++ b/test/w6-ui.test.ts @@ -320,7 +320,7 @@ test('stable chrome keeps identity and status outside transcript history', () => assert.match(standard[0] ?? '', /reviewer.*pi/u) assert.match(standard[0] ?? '', /via local/u) assert.doesNotMatch(standard[0] ?? '', /fixture|deterministic fixture/u) - assert.match(standard[0] ?? '', /\/ commands/u) + assert.doesNotMatch(standard[0] ?? '', /\/ commands/u) assert.doesNotMatch(standard[0] ?? '', /Ctrl\+P/u) const wide = chrome.render(120).join('\n') assert.match(wide, /reviewer · pi · local/u) From a0af889ebb56b737206958ef4709d6fa0fd0edbb Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 03:42:03 -0600 Subject: [PATCH 11/25] fix(tui): harden redaction and terminal cleanup --- src/adapters/tui/native-terminal-transport.ts | 24 +++-- src/domain/bounded-structured.ts | 2 + src/domain/redaction.ts | 3 +- test/native-terminal-transport.test.ts | 87 ++++++++++++++++++- test/sanitize.test.ts | 6 +- 5 files changed, 107 insertions(+), 15 deletions(-) diff --git a/src/adapters/tui/native-terminal-transport.ts b/src/adapters/tui/native-terminal-transport.ts index 48eddb0..a5a7a2a 100644 --- a/src/adapters/tui/native-terminal-transport.ts +++ b/src/adapters/tui/native-terminal-transport.ts @@ -44,7 +44,8 @@ async function runTransport( let terminalStartAttempted = false let outcome: NativeTerminalTransportOutcome | undefined let signalRelease: (() => void) | undefined - let operationTail = Promise.resolve() + let forwardingBusy = false + let forwardingTail = Promise.resolve() let detachRequested = false let settleOutcome: (value: NativeTerminalTransportOutcome) => void = () => {} const outcomeReady = new Promise((resolve) => { @@ -61,17 +62,24 @@ async function runTransport( phase: Extract, operation: () => Promise, ): void => { - operationTail = operationTail - .then(() => (finished ? undefined : operation())) - .catch((error) => finish(transportError(sessionId, phase, error))) + const run = async (): Promise => { + if (finished) return + forwardingBusy = true + try { + await operation() + } catch (error) { + finish(transportError(sessionId, phase, error)) + } finally { + forwardingBusy = false + } + } + forwardingTail = forwardingBusy ? forwardingTail.then(run) : run() } const requestDetach = (): void => { if (detachRequested || finished) return detachRequested = true - const precedingOperations = operationTail - void precedingOperations.then(() => { - if (!finished) finish({ kind: 'detached', sessionId, trigger: 'user' }) - }) + // Finish immediately so the lifecycle aborts in-flight forwarding and skips queued operations. + finish({ kind: 'detached', sessionId, trigger: 'user' }) } const onInput = (data: string): void => { if (finished) return diff --git a/src/domain/bounded-structured.ts b/src/domain/bounded-structured.ts index df48acb..210a80d 100644 --- a/src/domain/bounded-structured.ts +++ b/src/domain/bounded-structured.ts @@ -26,6 +26,8 @@ const SAFE_NUMERIC_FIELDS = new Set([ 'maxcompletiontokens', 'maxoutputtokens', 'maxreasoningtokens', + 'maxvisibleoutputtokens', + 'maxtotaloutputtokens', 'mintokens', 'tokencount', 'tokenestimate', diff --git a/src/domain/redaction.ts b/src/domain/redaction.ts index ef2996a..7126c9c 100644 --- a/src/domain/redaction.ts +++ b/src/domain/redaction.ts @@ -1,6 +1,5 @@ import type { AgentProfile } from '@tangle-network/agent-interface' import { - redactStructuredValue, redactStructuredValueWithNumericTelemetry, STRUCTURED_REDACTION_MARKER, } from './bounded-structured.js' @@ -19,7 +18,7 @@ export { redactSensitiveText, redactSensitiveUrls } from './secret-sanitizer.js' export function redactProfile(profile: Readonly): Readonly { const modelMetadata = publicModelMetadata(profile.model?.metadata) return removeProfileMetadata( - redactStructuredValue(profile, undefined, { maxBytes: MAX_PROFILE_BYTES }), + redactStructuredValueWithNumericTelemetry(profile, undefined, { maxBytes: MAX_PROFILE_BYTES }), [], modelMetadata, ) as Readonly diff --git a/test/native-terminal-transport.test.ts b/test/native-terminal-transport.test.ts index 8779915..884efe2 100644 --- a/test/native-terminal-transport.test.ts +++ b/test/native-terminal-transport.test.ts @@ -169,8 +169,31 @@ class FakeSession implements AgentTerminalSession { } } -function fixture() { - const session = new FakeSession() +class HungInputSession extends FakeSession { + inputStarted: (() => void) | undefined + inputSignal: AbortSignal | undefined + + override input(input: TerminalInput, options?: { signal?: AbortSignal }): Promise { + this.inputs.push(input) + this.inputSignal = options?.signal + this.inputStarted?.() + return new Promise(() => {}) + } +} + +class HungResizeSession extends FakeSession { + resizeStarted: (() => void) | undefined + resizeSignal: AbortSignal | undefined + + override resize(resize: TerminalResize, options?: { signal?: AbortSignal }): Promise { + this.resizes.push(resize) + this.resizeSignal = options?.signal + this.resizeStarted?.() + return new Promise(() => {}) + } +} + +function fixture(session: FakeSession = new FakeSession()) { const terminal = new FakeTerminal() const signals = new FakeSignals() const transport = createNativeTerminalTransport({ session, terminal, signals }) @@ -185,6 +208,23 @@ async function started(terminal: FakeTerminal): Promise { assert.fail('transport did not start the local terminal') } +async function settlesWithin(promise: Promise, timeoutMs = 250): Promise { + let timer: NodeJS.Timeout | undefined + try { + return await Promise.race([ + promise, + new Promise((_, reject) => { + timer = setTimeout( + () => reject(new Error(`promise did not settle within ${timeoutMs}ms`)), + timeoutMs, + ) + }), + ]) + } finally { + if (timer !== undefined) clearTimeout(timer) + } +} + test('forwards output and restores terminal and signal state', async () => { const { session, terminal, signals, transport } = fixture() const running = transport.run() @@ -248,6 +288,49 @@ test('detaches on Ctrl+] and leaves the remote process running', async () => { assert.equal(terminal.stopCount, 1) }) +test('detaches promptly when an in-flight input never settles', async () => { + const session = new HungInputSession() + const inputStarted = new Promise((resolve) => { + session.inputStarted = resolve + }) + const { terminal, transport } = fixture(session) + const running = transport.run() + await started(terminal) + terminal.input('before detach') + await inputStarted + terminal.input('\u001d') + + const result = await settlesWithin(running) + assert.deepEqual(result.outcome, { kind: 'detached', sessionId, trigger: 'user' }) + assert.equal(result.cleanup.remote, 'detached') + assert.equal(terminal.stopCount, 1) + assert.equal(session.detachCount, 1) + assert.equal(session.inputSignal?.aborted, true) +}) + +test('stops promptly and cancels queued resizes when one resize never settles', async () => { + const session = new HungResizeSession() + const resizeStarted = new Promise((resolve) => { + session.resizeStarted = resolve + }) + const { terminal, transport } = fixture(session) + const controller = new AbortController() + const running = transport.run({ signal: controller.signal }) + await started(terminal) + terminal.resize(132, 43) + await resizeStarted + terminal.resize(160, 50) + controller.abort() + + const result = await settlesWithin(running) + assert.deepEqual(result.outcome, { kind: 'aborted', sessionId, source: 'caller' }) + assert.equal(result.cleanup.remote, 'detached') + assert.equal(terminal.stopCount, 1) + assert.equal(session.detachCount, 1) + assert.deepEqual(session.resizes, [{ cols: 132, rows: 43 }]) + assert.equal(session.resizeSignal?.aborted, true) +}) + test('reports a remote exit without detaching or closing it', async () => { const { session, terminal, transport } = fixture() const running = transport.run() diff --git a/test/sanitize.test.ts b/test/sanitize.test.ts index 1d150b9..bb28353 100644 --- a/test/sanitize.test.ts +++ b/test/sanitize.test.ts @@ -57,7 +57,7 @@ test('numeric token telemetry survives redaction while string tokens never do', totalTokens: 34, cachedPromptTokens: 5, cacheWriteTokens: 3, - model: { maxVisibleOutputTokens: 4096 }, + model: { maxVisibleOutputTokens: 4096, maxTotalOutputTokens: 8192 }, tokenUsage: { input: 21, output: 13 }, accessToken: 'secret-canary', poisoned: { inputTokens: 'secret-canary' }, @@ -70,7 +70,7 @@ test('numeric token telemetry survives redaction while string tokens never do', assert.equal(redacted.totalTokens, 34) assert.equal(redacted.cachedPromptTokens, 5) assert.equal(redacted.cacheWriteTokens, 3) - assert.deepEqual(redacted.model, { maxVisibleOutputTokens: 4096 }) + assert.deepEqual(redacted.model, { maxVisibleOutputTokens: 4096, maxTotalOutputTokens: 8192 }) assert.deepEqual(redacted.tokenUsage, { input: 21, output: 13 }) assert.equal(redacted.accessToken, '[redacted]') assert.deepEqual(redacted.poisoned, { inputTokens: '[redacted]' }) @@ -159,7 +159,7 @@ test('plain structured redaction preserves only the exact aggregate token counte ) }) -test('profile redaction keeps first-class limits and hides model metadata', () => { +test('profile redaction preserves maxVisibleOutputTokens and maxTotalOutputTokens', () => { const redacted = redactProfile({ name: 'Public model settings', model: { From d8fb4c87731a08a1382039e81ed7586cdbf1b37c Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 05:08:22 -0600 Subject: [PATCH 12/25] fix(tui): separate deterministic visual proof from live demo --- artifacts/verification/w6/120x40-plain.txt | 17 +- artifacts/verification/w6/120x40.png | Bin 7496 -> 21886 bytes artifacts/verification/w6/120x40.txt | 8 +- artifacts/verification/w6/200x60-plain.txt | 17 +- artifacts/verification/w6/200x60.png | Bin 8662 -> 10015 bytes artifacts/verification/w6/200x60.txt | 8 +- artifacts/verification/w6/40x12-plain.txt | 17 +- artifacts/verification/w6/40x12.png | Bin 10675 -> 14600 bytes artifacts/verification/w6/40x12.txt | 8 +- .../verification/w6/80x24-automation.gif | Bin 16398 -> 23332 bytes artifacts/verification/w6/80x24-plain.txt | 17 +- .../w6/80x24-transcript-keyboard.gif | Bin 299814 -> 377491 bytes artifacts/verification/w6/80x24.png | Bin 6136 -> 18888 bytes artifacts/verification/w6/80x24.txt | 8 +- artifacts/verification/w6/braid.gif | Bin 254468 -> 0 bytes artifacts/verification/w6/braid.png | Bin 25764 -> 0 bytes artifacts/verification/w6/braid.txt | 18 - .../verification/w6/capture-manifest.json | 350 ++++++++++------ artifacts/verification/w6/raw/braid-demo.cast | 375 ----------------- .../w6/raw/transcript-keyboard.cast | 153 ++++--- .../w6/states/active-streaming.json | 87 ++-- .../w6/states/active-streaming.png | Bin 5265 -> 15662 bytes .../w6/states/active-streaming.txt | 6 +- .../verification/w6/states/analysis.json | 43 +- artifacts/verification/w6/states/analysis.png | Bin 62279 -> 62918 bytes artifacts/verification/w6/states/analysis.txt | 8 +- .../verification/w6/states/automation.json | 41 +- .../verification/w6/states/automation.png | Bin 6137 -> 4156 bytes .../verification/w6/states/automation.txt | 14 +- .../w6/states/command-palette-120.json | 376 ++++++++++++++++++ .../w6/states/command-palette-120.png | Bin 0 -> 36717 bytes .../w6/states/command-palette-120.txt | 14 + .../w6/states/command-palette-40.json | 376 ++++++++++++++++++ .../w6/states/command-palette-40.png | Bin 0 -> 9718 bytes .../w6/states/command-palette-40.txt | 12 + .../w6/states/command-palette-80.json | 376 ++++++++++++++++++ .../w6/states/command-palette-80.png | Bin 0 -> 35536 bytes .../w6/states/command-palette-80.txt | 14 + .../verification/w6/states/comparison.json | 41 +- .../verification/w6/states/comparison.png | Bin 23364 -> 68314 bytes .../verification/w6/states/comparison.txt | 4 +- artifacts/verification/w6/states/empty.json | 41 +- artifacts/verification/w6/states/empty.png | Bin 3804 -> 13523 bytes artifacts/verification/w6/states/empty.txt | 10 +- .../w6/states/failure-or-reconnect.json | 115 +++--- .../w6/states/failure-or-reconnect.png | Bin 6377 -> 19112 bytes .../w6/states/failure-or-reconnect.txt | 8 +- .../verification/w6/states/fork-preview.json | 39 +- .../verification/w6/states/fork-preview.png | Bin 11548 -> 11548 bytes .../w6/states/graph-or-analysis.json | 43 +- .../w6/states/graph-or-analysis.png | Bin 19470 -> 20641 bytes .../w6/states/graph-or-analysis.txt | 6 +- .../verification/w6/states/interaction.json | 41 +- .../verification/w6/states/interaction.png | Bin 30480 -> 28820 bytes .../verification/w6/states/interaction.txt | 4 +- artifacts/verification/w6/states/narrow.json | 41 +- artifacts/verification/w6/states/narrow.png | Bin 2962 -> 9973 bytes artifacts/verification/w6/states/narrow.txt | 10 +- artifacts/verification/w6/states/profile.json | 41 +- artifacts/verification/w6/states/profile.png | Bin 30518 -> 5536 bytes artifacts/verification/w6/states/profile.txt | 21 +- scripts/capture-product-demo.mjs | 303 -------------- scripts/capture-visual.mjs | 30 +- src/views/tui/terminal-chrome.ts | 24 +- test/scripts.test.ts | 25 ++ test/terminal-responsive.test.ts | 31 +- 66 files changed, 1969 insertions(+), 1272 deletions(-) delete mode 100644 artifacts/verification/w6/braid.gif delete mode 100644 artifacts/verification/w6/braid.png delete mode 100644 artifacts/verification/w6/braid.txt delete mode 100644 artifacts/verification/w6/raw/braid-demo.cast create mode 100644 artifacts/verification/w6/states/command-palette-120.json create mode 100644 artifacts/verification/w6/states/command-palette-120.png create mode 100644 artifacts/verification/w6/states/command-palette-120.txt create mode 100644 artifacts/verification/w6/states/command-palette-40.json create mode 100644 artifacts/verification/w6/states/command-palette-40.png create mode 100644 artifacts/verification/w6/states/command-palette-40.txt create mode 100644 artifacts/verification/w6/states/command-palette-80.json create mode 100644 artifacts/verification/w6/states/command-palette-80.png create mode 100644 artifacts/verification/w6/states/command-palette-80.txt delete mode 100644 scripts/capture-product-demo.mjs diff --git a/artifacts/verification/w6/120x40-plain.txt b/artifacts/verification/w6/120x40-plain.txt index a1c8793..894047a 100644 --- a/artifacts/verification/w6/120x40-plain.txt +++ b/artifacts/verification/w6/120x40-plain.txt @@ -1,4 +1,4 @@ -Braid ready — /home/drew/code/braid-transcript-first-wt +Braid ready — /home/drew/code/.worktrees/braid-exact-interactive-20260816 status: ready for a message conversation: New conversation; branch: branch-1 profile: Braid starter; runner: pi; connection: deterministic fixture @@ -6,12 +6,9 @@ appearance: none; high contrast off; reduced motion off event 2: draft.changed; status: ready for a message event 3: run.requested; status: admitted: W6 plain proof event 4: effect.upserted; status: streaming -event 5: run.provider.event; status: streaming: {"type":"backend_start","task":{"id":"turn-c7a112f8-ec11-44cb-beed-76fd6693a70b","intent":"W6 plain proof","metadata":{"identity":{"profileDigest":"sha256:8344a03c82d5cb9207910fe0cb05ef0757b58b8cea9a7cc82f36055694d58983","taskDigest":"sha256:f75eb08b6c6a3120e5297421baed1e5e2553899395ec5981e0fda4c9ce725300"}}},"session":{"id":"5396aad7-ceec-411e-a001-ce0a2edf2a12","backend":"executor","status":"active","createdAt":"2026-08-12T12:37:26.903Z","updatedAt":"2026-08-12T12:37:26.903Z","metadata":"[unavailable]"}," -event 6: application.shutdown.requested; status: streaming -event 7: run.control.requested; status: cancelling: requested -event 8: run.cancel.requested; status: cancelling: requested -event 9: effect.upserted; status: cancelling -event 10: effect.upserted; status: cancelling -event 11: run.control.acknowledged; status: cancelling: CONTROL_ACKNOWLEDGED -event 12: run.finished; status: aborted -event 13: effect.upserted; status: cancelled +event 5: run.provider.event; status: streaming: {"type":"backend_start","task":{"id":"turn-f464b334-bc5f-406b-aed7-ac801fbd20e3","intent":"W6 plain proof","metadata":{"identity":{"profileDigest":"sha256:8344a03c82d5cb9207910fe0cb05ef0757b58b8cea9a7cc82f36055694d58983","taskDigest":"sha256:f75eb08b6c6a3120e5297421baed1e5e2553899395ec5981e0fda4c9ce725300"}}},"session":{"id":"05bb45e5-a6c1-40e3-b260-359bc2bd56c2","backend":"executor","status":"active","createdAt":"2026-08-16T11:04:57.315Z","updatedAt":"2026-08-16T11:04:57.315Z","metadata":"[unavailable]"}," +event 6: run.usage; status: streaming +event 7: run.artifact; status: streaming: agent-turn-result +event 8: run.finished; status: completed: Fixture response through pi: W6 plain proof +event 9: effect.upserted; status: completed +event 10: application.shutdown.requested; status: completed diff --git a/artifacts/verification/w6/120x40.png b/artifacts/verification/w6/120x40.png index 2a628920a2c86d169b50f25a479c9df261a35804..e418aa0aa459e40c8f27c65b5c3bbdd047d05608 100644 GIT binary patch literal 21886 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 Qem!QSXQGS#!#VOl0Do+(xc~qF diff --git a/artifacts/verification/w6/120x40.txt b/artifacts/verification/w6/120x40.txt index 023edcd..ada10dc 100644 --- a/artifacts/verification/w6/120x40.txt +++ b/artifacts/verification/w6/120x40.txt @@ -32,9 +32,9 @@ +──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +› new message -› - - -profile Braid starter · pi / fixture/deterministic · deterministic fixture in 8 · out 12 · calls 1 · model 50ms +─────────────────────────────────── type / for commands · Alt+Enter newline · paste ──────────────────────────────────── +profile Braid starter · pi · local Ctrl+E details diff --git a/artifacts/verification/w6/200x60-plain.txt b/artifacts/verification/w6/200x60-plain.txt index a1c8793..894047a 100644 --- a/artifacts/verification/w6/200x60-plain.txt +++ b/artifacts/verification/w6/200x60-plain.txt @@ -1,4 +1,4 @@ -Braid ready — /home/drew/code/braid-transcript-first-wt +Braid ready — /home/drew/code/.worktrees/braid-exact-interactive-20260816 status: ready for a message conversation: New conversation; branch: branch-1 profile: Braid starter; runner: pi; connection: deterministic fixture @@ -6,12 +6,9 @@ appearance: none; high contrast off; reduced motion off event 2: draft.changed; status: ready for a message event 3: run.requested; status: admitted: W6 plain proof event 4: effect.upserted; status: streaming -event 5: run.provider.event; status: streaming: {"type":"backend_start","task":{"id":"turn-c7a112f8-ec11-44cb-beed-76fd6693a70b","intent":"W6 plain proof","metadata":{"identity":{"profileDigest":"sha256:8344a03c82d5cb9207910fe0cb05ef0757b58b8cea9a7cc82f36055694d58983","taskDigest":"sha256:f75eb08b6c6a3120e5297421baed1e5e2553899395ec5981e0fda4c9ce725300"}}},"session":{"id":"5396aad7-ceec-411e-a001-ce0a2edf2a12","backend":"executor","status":"active","createdAt":"2026-08-12T12:37:26.903Z","updatedAt":"2026-08-12T12:37:26.903Z","metadata":"[unavailable]"}," -event 6: application.shutdown.requested; status: streaming -event 7: run.control.requested; status: cancelling: requested -event 8: run.cancel.requested; status: cancelling: requested -event 9: effect.upserted; status: cancelling -event 10: effect.upserted; status: cancelling -event 11: run.control.acknowledged; status: cancelling: CONTROL_ACKNOWLEDGED -event 12: run.finished; status: aborted -event 13: effect.upserted; status: cancelled +event 5: run.provider.event; status: streaming: {"type":"backend_start","task":{"id":"turn-f464b334-bc5f-406b-aed7-ac801fbd20e3","intent":"W6 plain proof","metadata":{"identity":{"profileDigest":"sha256:8344a03c82d5cb9207910fe0cb05ef0757b58b8cea9a7cc82f36055694d58983","taskDigest":"sha256:f75eb08b6c6a3120e5297421baed1e5e2553899395ec5981e0fda4c9ce725300"}}},"session":{"id":"05bb45e5-a6c1-40e3-b260-359bc2bd56c2","backend":"executor","status":"active","createdAt":"2026-08-16T11:04:57.315Z","updatedAt":"2026-08-16T11:04:57.315Z","metadata":"[unavailable]"}," +event 6: run.usage; status: streaming +event 7: run.artifact; status: streaming: agent-turn-result +event 8: run.finished; status: completed: Fixture response through pi: W6 plain proof +event 9: effect.upserted; status: completed +event 10: application.shutdown.requested; status: completed diff --git a/artifacts/verification/w6/200x60.png b/artifacts/verification/w6/200x60.png index 074d7b093bb040437a4814f26976393625c2671f..0f2660463fa589b8f7294a8491e56763094a0bab 100644 GIT binary patch literal 10015 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 Uvk|#y=+_3?AU(}u^*>(x8^*=LumAu6 literal 8662 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 diff --git a/artifacts/verification/w6/200x60.txt b/artifacts/verification/w6/200x60.txt index 8c1e5aa..17a093c 100644 --- a/artifacts/verification/w6/200x60.txt +++ b/artifacts/verification/w6/200x60.txt @@ -52,9 +52,9 @@ +──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +› new message -› - - -profile Braid starter · pi / fixture/deterministic · deterministic fixture in 8 · out 12 · calls 1 · model 49ms +─────────────────────────────────────────────────────────────────────────── type / for commands · Alt+Enter newline · paste ──────────────────────────────────────────────────────────────────────────── +profile Braid starter · pi · local Ctrl+E details diff --git a/artifacts/verification/w6/40x12-plain.txt b/artifacts/verification/w6/40x12-plain.txt index a1c8793..894047a 100644 --- a/artifacts/verification/w6/40x12-plain.txt +++ b/artifacts/verification/w6/40x12-plain.txt @@ -1,4 +1,4 @@ -Braid ready — /home/drew/code/braid-transcript-first-wt +Braid ready — /home/drew/code/.worktrees/braid-exact-interactive-20260816 status: ready for a message conversation: New conversation; branch: branch-1 profile: Braid starter; runner: pi; connection: deterministic fixture @@ -6,12 +6,9 @@ appearance: none; high contrast off; reduced motion off event 2: draft.changed; status: ready for a message event 3: run.requested; status: admitted: W6 plain proof event 4: effect.upserted; status: streaming -event 5: run.provider.event; status: streaming: {"type":"backend_start","task":{"id":"turn-c7a112f8-ec11-44cb-beed-76fd6693a70b","intent":"W6 plain proof","metadata":{"identity":{"profileDigest":"sha256:8344a03c82d5cb9207910fe0cb05ef0757b58b8cea9a7cc82f36055694d58983","taskDigest":"sha256:f75eb08b6c6a3120e5297421baed1e5e2553899395ec5981e0fda4c9ce725300"}}},"session":{"id":"5396aad7-ceec-411e-a001-ce0a2edf2a12","backend":"executor","status":"active","createdAt":"2026-08-12T12:37:26.903Z","updatedAt":"2026-08-12T12:37:26.903Z","metadata":"[unavailable]"}," -event 6: application.shutdown.requested; status: streaming -event 7: run.control.requested; status: cancelling: requested -event 8: run.cancel.requested; status: cancelling: requested -event 9: effect.upserted; status: cancelling -event 10: effect.upserted; status: cancelling -event 11: run.control.acknowledged; status: cancelling: CONTROL_ACKNOWLEDGED -event 12: run.finished; status: aborted -event 13: effect.upserted; status: cancelled +event 5: run.provider.event; status: streaming: {"type":"backend_start","task":{"id":"turn-f464b334-bc5f-406b-aed7-ac801fbd20e3","intent":"W6 plain proof","metadata":{"identity":{"profileDigest":"sha256:8344a03c82d5cb9207910fe0cb05ef0757b58b8cea9a7cc82f36055694d58983","taskDigest":"sha256:f75eb08b6c6a3120e5297421baed1e5e2553899395ec5981e0fda4c9ce725300"}}},"session":{"id":"05bb45e5-a6c1-40e3-b260-359bc2bd56c2","backend":"executor","status":"active","createdAt":"2026-08-16T11:04:57.315Z","updatedAt":"2026-08-16T11:04:57.315Z","metadata":"[unavailable]"}," +event 6: run.usage; status: streaming +event 7: run.artifact; status: streaming: agent-turn-result +event 8: run.finished; status: completed: Fixture response through pi: W6 plain proof +event 9: effect.upserted; status: completed +event 10: application.shutdown.requested; status: completed diff --git a/artifacts/verification/w6/40x12.png b/artifacts/verification/w6/40x12.png index dfe4f040cbf6035b5bd071d2926d6d18afb6e8be..641f5807e7d78c3c4fd5bdc9f9449d553884c771 100644 GIT binary patch literal 14600 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 z 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 literal 10675 zcmdUVcT`i|wr|u=DT1IP2ndJ>NEeZgAfX9J4Ml21q=nvl@*x2PL^`1tX;MS)5T*Ct zTLkF=Lhq2fzjN*# zS8ovQ&^)D_`Ud{Q8sh(e^4Qq&<{yz_8ljb6zg6C;uq#;1r!LAI=X_r|t}Rz|+kr({ z_J{Oqbqx{`Y4v8(GB~0Yn#GA?Az7S(OR1$v*4EE@pDw|Ugp1DSAU8S-&N7#<3ZyU+U$*QR$@cs6~n2(Xs z(GXuR~4Gost`mAH-A_@0G@0$nr=HmxOu*vkr@xPO1XsmS*nFoKK$ z(NtDk-1yEy%N<6E2udcV`wW$yBl3Q))4gc=lKC$;VjtSu}%-Kz2a> zk-oCLlALTZHRdVZ^I!YBP_>fM(y1oXdY=b@+2RN+YlXW5!;(C4g3y+@9`rwF%x7DC zwN~5lC9&!~MoB&}p0as$_t9p+Dxcxt(9m7tKO`gxLzxQ52>JFfi6D=cf`W%T2ajH~ z$|x&~KYsk$z`*ed5*a8~<@|DW|6_D3p=mxw$%(BxK9U#l?dBLce;sw_MMm#hz0%X

PhNAr-|q@-r{O(-~~tZcZ<^LASsHA+@iUZnoc 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 diff --git a/artifacts/verification/w6/40x12.txt b/artifacts/verification/w6/40x12.txt index d85051b..405a593 100644 --- a/artifacts/verification/w6/40x12.txt +++ b/artifacts/verification/w6/40x12.txt @@ -4,9 +4,9 @@ Fixture response through pi: W6 visual proof +──────────────────────────────────────── +› new message -› - - -Braid starter Ctrl+E detail + type / for commands · Alt+Enter newlin… +Braid starter diff --git a/artifacts/verification/w6/80x24-automation.gif b/artifacts/verification/w6/80x24-automation.gif index c872da95492eb6731786588ee6ccaefd862bbeed..f8ab8b113d0ed3ea4c93c198975522a153cd3d11 100644 GIT binary patch delta 20722 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 OZm@$N4B;6C0suR+lbZhk delta 13830 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 T)P2KE)FUQYoA>Dep!NR&1nSWi diff --git a/artifacts/verification/w6/80x24-plain.txt b/artifacts/verification/w6/80x24-plain.txt index a1c8793..894047a 100644 --- a/artifacts/verification/w6/80x24-plain.txt +++ b/artifacts/verification/w6/80x24-plain.txt @@ -1,4 +1,4 @@ -Braid ready — /home/drew/code/braid-transcript-first-wt +Braid ready — /home/drew/code/.worktrees/braid-exact-interactive-20260816 status: ready for a message conversation: New conversation; branch: branch-1 profile: Braid starter; runner: pi; connection: deterministic fixture @@ -6,12 +6,9 @@ appearance: none; high contrast off; reduced motion off event 2: draft.changed; status: ready for a message event 3: run.requested; status: admitted: W6 plain proof event 4: effect.upserted; status: streaming -event 5: run.provider.event; status: streaming: {"type":"backend_start","task":{"id":"turn-c7a112f8-ec11-44cb-beed-76fd6693a70b","intent":"W6 plain proof","metadata":{"identity":{"profileDigest":"sha256:8344a03c82d5cb9207910fe0cb05ef0757b58b8cea9a7cc82f36055694d58983","taskDigest":"sha256:f75eb08b6c6a3120e5297421baed1e5e2553899395ec5981e0fda4c9ce725300"}}},"session":{"id":"5396aad7-ceec-411e-a001-ce0a2edf2a12","backend":"executor","status":"active","createdAt":"2026-08-12T12:37:26.903Z","updatedAt":"2026-08-12T12:37:26.903Z","metadata":"[unavailable]"}," -event 6: application.shutdown.requested; status: streaming -event 7: run.control.requested; status: cancelling: requested -event 8: run.cancel.requested; status: cancelling: requested -event 9: effect.upserted; status: cancelling -event 10: effect.upserted; status: cancelling -event 11: run.control.acknowledged; status: cancelling: CONTROL_ACKNOWLEDGED -event 12: run.finished; status: aborted -event 13: effect.upserted; status: cancelled +event 5: run.provider.event; status: streaming: {"type":"backend_start","task":{"id":"turn-f464b334-bc5f-406b-aed7-ac801fbd20e3","intent":"W6 plain proof","metadata":{"identity":{"profileDigest":"sha256:8344a03c82d5cb9207910fe0cb05ef0757b58b8cea9a7cc82f36055694d58983","taskDigest":"sha256:f75eb08b6c6a3120e5297421baed1e5e2553899395ec5981e0fda4c9ce725300"}}},"session":{"id":"05bb45e5-a6c1-40e3-b260-359bc2bd56c2","backend":"executor","status":"active","createdAt":"2026-08-16T11:04:57.315Z","updatedAt":"2026-08-16T11:04:57.315Z","metadata":"[unavailable]"}," +event 6: run.usage; status: streaming +event 7: run.artifact; status: streaming: agent-turn-result +event 8: run.finished; status: completed: Fixture response through pi: W6 plain proof +event 9: effect.upserted; status: completed +event 10: application.shutdown.requested; status: completed diff --git a/artifacts/verification/w6/80x24-transcript-keyboard.gif b/artifacts/verification/w6/80x24-transcript-keyboard.gif index f0b369e72b48a6d4f5149198cff0225c31ea1e69..3c3300da2a35711fefd84196f06b9f5d70222728 100644 GIT binary patch literal 377491 zcmd42S5Q;$1FpMLNF%@k8`2C#dI^e1u>?eViH#zNK@mX#K~X>uL+=oZbTRZI9qGk@ zl+c4BAXtK;bO?%cW#{)Vd-mC9&zv)JZVr z35oIxit-DK9TXI0|FR@EVgQAX>e_w*)o_YDp)0tSXh-jBM!8=IK?Nc!-J zIrY`-%eNmhvuD1~EiNr9EUf(ewI;Osdvoj8#`d4T-**3^g)9|tZGouB!^ZRqyV788 zaYK0y_w3HdemA?1^vay>Slr&Z2qA;2+@1vKOT{)lRe62M_?x{M2G#ik>1q$=KlW4? z482eXD?ot&X-3X(IPRK8zx2BT;&Ew(<0p#WzZ5CXXKV+_jh2(%Lno<-gzb~F?XR!=)=d#N$~11M`remv z{O;%ehU%Fi>bXb}lg3wb?+P!yv>j-ySs1Ih*_Ub3RJ$};|6t+sKvUhy7g`|a5!2@S z)o=6!x$A??4Zmg>IYuu`TN-~aj91_NGT73zvBG>4dBm)>dF$8gyO-C8T3dEDSl{|y zn7wZOv$OeY;mgqL*L!;aLYlcph97if`lBQZnE_bUS!N)pD?Jso-`sI3nBSprDn#hf z>{KW&MEYx(M3UpzaOwQQuMzUKvtJ|eUDDs8R7M@YMXUWN{1$U+efC={0UQ1UDAoDd9Ez^&TyCQIow>Xe zhvK>Xj7Rfx1=JAP`NG_!JM%?_`Ni|aCAIVOFDtra7fN1@-dQNE|53b9*1SHyP)Vt#k2X58WBQtih_3rls(5V__0>7={M4YT<# zmm3#r7nYk?U2-eUYom8pS~h>YTxs21Us!n!Amv#!_#tOj8%nB#)s8*6$a(|n$**?o zw{TwVM8slxoqL``@QAu(%++(3Oj#~nWtO{7#E=Y zsray*z4U5Ku&^|ElH>_^nqTS{-uPrPzEt(uYh!8S3mK`n$qYK=x;YglRkryx>g4j~ zH;SI()^wtU>(=*_+htpOKQcU*w`QoJircff$*$XTg#~5X^Cfl5+Y1%liaU$1##}Yu zpoOvseGTszK0L3#xZY>&2bFeL=~CspKl@Lv?EYftDg9X+vAFl=_xSDdKkFYoSN?1; zLzVt+PAA{{yER)-{&#z^ZsqR|t6OPrcWvz6-k;5x@~6274^7%%;MJu)4c1u+tQ!KU zLlWVuhau)^{_4`qFbQcGCWbp;e+5ohgCvb7DJe>l2sbrD-|YPb`kk^@ zS0gO@vk%r;CPQucyCM$(;#?h;kYo3iPdP|v3!JXhJtd6ea5<$V^o*tJKN2VKKt)ev zNMG;vr#R$O6&;)zo^G}OXXKUfZ?4=Z_V(BZwVJkGdVOPl7v0$Uy0RvrV)$(@YxQwl z!tmBsd}+CRNchnDhQ=8kqV3JlvGO}l13KsDpEtG0si>C?F=!n<;n{g_x3_)#0tqG; z2G-Vy*X=vz=7XM7zt1kU|CqUGZvFnx9~HGT=2q8_pVrpYH9AMUa@xSG;p3;)uisK? z>I_US(U(_hKTO>6@>M)}>P2=zQAt&8!|S&1KNgmM8CqUDf6@Fwc$BEL;&}tJCrPO# z14B}Z#~B-&f;dTXYI;;bk)o>Rb@zup2}vd8H44fn?H+hmkBq9EIVXEu&FKlbg*o+p z?9=!pQ}TpLOwr4%*KKKa4XT9mna!=1j?VU;K9_Gfy`G-7AvuW4;e8X6yO)=fs%u;V zf{)4{OMRZ*LhB-&Gw_IrJ|ZsjYIIBruTuGL$^H2eF$pF_i;xJ4i`ye{DTVyb?ueZHtIlq>ANyUr;gHeT z6jxGabk)|G9Mtsr%f0(v??xy6gCnlm+Go7TQ@d!Se%`>u)4{czqI>rmPE!7;jMAH# z*}RUfYxnLCFy7BCuKERpl9K(pdj@;@hpi$XM&uR*X1wt2%qs5fyMDv*oW13PnrGg= z{vSR~sh>Xggr1{kbm6QK(dv$?sXc{w+3IEgz=bDwPiyNE?5YEoyM^NU74fvrn>@>@x!|S=c=AeDX9oEhH@Far`qe zCHy6S7Zqb&1;Xi=xTI57#B#>4+!@W|M&~_KnJ%Ri{He>5cr6=>_ocgO51Uf2KdubT z%CWk3^M778{(a{_?Ex^9kQzv42lGBz8+t|7n@~{PFhjqR9nAd4@BAm2|Cd~D*01>9 z`@iS1RA&vwSRK?wrbfwxg3ys?w?$qZy06gvaPwszjAr+{~pXI zoo>)7!@UsBSzh)uvLI1NOIPm%gF$?9)T>qt#dARIOJJ`;b~kWJKk*5H)VQcPu;R2=OaTEhyG$B%1 za?3^qmO>6cf|j`yC_;P%&DJ_3FoG6KI+Z)6Wsjxw#+clPa_kr6->-8dQ79WBi58ju z0w{@$=p7X$X7>T^XC#h3GZ)z3p7G#uwq&|%yEhmsnG&8)4cfk4s6}T`yG8ZDO2^dO z`CE)Mm)65G0g|j6p+_F_+lPp#ig>^i0qmYYQC4nRgsk?1QEz)xUS`_7RuWUa3*js4 z=OmPH^+sncnZt~4ph%K;*BxYctK^&Oh74KrPn zjK-zb^kqcDt{t7{J@YJ9HQk&g*f`So1lBhIY9o3Y>Ci zq0r(^@s>-4di1OVuGe$d<6t^_HyL;s{|&}yI)9=b>Q((mmR83$7r+eYdwKWUQyy@O zH}b*pbw-A`u90FI|9+;HKJMbVlL@ww8^8_y5e2?@>7R13hH^SFM+iGJ#$za9@$l#A zN|(3iijFrkmKt~}c0Sd}NmPiG9+~c5>9+{l&1ecNdGHRo`ZhxArq2EKuL!4m6wZ%E zgEtf>_b?p4fi+&=nKhV04y0-c+~E?|Z` zMMLZg@!!p!AR8bwfEKYOGyN1IMExqJ)`s~SYb;3$qltY#Voaro@#W$G`TCcE(t&po zqM>5_MCkWuB~g7Sjcaf05haboJq$6-)LNTr+g9gQiX+)!cyA!g3vW08^w_u3{*iyZ z4fGIOZ~DDFw1U=d@cz{lMVv>T-TI9dyVCp>weNnHiY+BdR^o-$8rT@jbQgQ5qW|Ql zr;gAWIrw|S4?I>KxImnH^a&3M?k~vZlV?`rJ<$Ootp&yBByNay5rXE|FG0`i42fdl z1SQ(KUQl6nEC5;`=DK+N3|S$`#9m*TH$Kc(diohM?r5q*kI{8W_`W)0eK~Pxf5r0( ziVmD0@s}9RC6b#=aLxs}4ElPUe#NC|S}7_U4A$UXtdUcJF~$|BV<`|GKjs_h8Wq6Y zcNk}9c|JCzXpf>p@W*EA2Mdf?>ReM^vfUDp0>N$-jdN~f2?ZB&tfFxHRe0yY1`Udt_Fg9Ny>!c8r)IbfTdWhZ7J zh#-0owR-oO)2&MYAJrOBuU5iPe1LTyssM7Efe-B0fO_(Nl(fe~HiQDF3G{^~~K z_(0jCy1q}#k2ji_T;*QfMxTGCZ8XoCls_Kp`@G(`(ZY%@_nk5NvOTfUx;aqpx6$|I z@Ak%PfV+Z>G-g5tH)$x-ihx7?OoZlU8yHg&BxO8>vEFRwAFK#D*+0eYv-t+cT^Xil z{FN_#vqRdnGQy(&>%peYPJB#d)NSK$0+X9vYJ-(Ap8elMb~d{S+*OoN<7qL$ExNvG zReW;)w4~-%4>6`HvB3Ddto2r}KUABx z_6FQysxxMcXEY|a2E7KWGdKEY&g^Urk-1+{ktVa+g4>KR(^uJt24;0Nw}&Y)uX3eK z<_xX3-=++{%0D?UXX>;4j>=tAsAn>NF@1Za(6px5Vqo69Y5RReOijsclZC63+oSb^ zHD#Uy3${DkV>IsCicpiq8-hFIbko|Zps)fk`MZ#bR?x}NFJ`1IXr={>WC zUW>t>Nlm-o@v#m4w@rVgP450s8)_Kz9Q>8JvpYlJX=H?&u4N1UnbkLIe49MDmaq9| zju_iGQegVK*!s`B$OdPmfT{SKF*kK zG*13m_8MyXyfL`Zy7Om+%+t(7nr*fV{$+)kHGe%cwArQkca;*`JS}Cm)ocCtXUb6X zkCQ`NgFb(MQF&Ts^~|>4rvF_lG;5i+7}_3f`un>gwq^0Q+0Mk|-}U;TmSxYOozFXe zH)uSqtWdMvuY!A?`?LQ z{r#D~w>xY0dV6f>?|ReTA6D$^-5ImJ?a95rn?tYvZVc`H-C=(~=O;te$Z$(C!i$Vb zA!F*v*l{xVCK=@S=Tr0FZ|Q%~%b!2RU!dM!Xxv|9(;vqlAf^@|VHqIlcxwR9IeVLD zmB2GQhMmIm%!cwzx%uIx1HX3%C_4JdcmWIWP=g>j<5k?v9ZA(8ta5yt?)kph7d z;TCO?N}@0*6EemhDRco+?Fa_pfDuQ&uPMBvblzWuHoxnI`!@Nc3D6Z3VB-e7-;6xq zAN@iam~;e>FuA8v!ni8|3F*do>q!oz|p5aN(o@#qV1QyOrH zh`?@vWDEQP z#ObES`_{*cw{Zx#VNhA{%WjDe4_jR`NPI8{a?=1_08OC6`xtRY4#$fh=C!242~7A5 z*+v8%FJ=%Q5}p#_1O|Jjgg2xhf&|{hai3k|$==)I_J$=+smc4yfJ4Dib+P31PpiUTmbku#rg& zm`hDRoQBFuG@eT=L;)AnpIt!%oCGME3>bq*Qy}RK34V|SIZaUvph9pU0uI2S-r%pp z5KiT&88je81+J4Ij!aY`Edpzo01)5@SWt5`aL_yJaAOt#q7D-PEmDpuE{B3bLh%qy z3I`7>k*kdZ17K}fuq+}9?H)^z&D9Z5(u~LwC|2I6&sNyZR&Gpy(sHhECxNnA`-?*> zW%v#-VG^={1v4KNmv`0XN1YDy<3=G_s#;7o)ogA)9H%CU%L5+{FgX+4Kus1`6`t>q8-mNd z_}WB{KteXM63R^h=fWunfH!-hFjk-_#IWd>I_e$`K+`yKSsVbPY(=2_*B#KSF%MuA zC-)Ws_HI7k0!YRILZkvDFY=HZcy5oGixovesn8D*g`BHZ%AA!7FToA| zDsk&7`MbP12Y4|}RZ`3f&+$s0%2yyS21=Cys4!vX^B&YIUs<4>1U_)90SJ``BP)5d z;1XcjKI=+^d*$KDa*|xFy>+}DCvY>eM)xi#akuJDU#-qU^@T{#VW-wnuFf;Pu3iT6 zfdV#>N{Y3SZ!1714#FgXA3#o|GS}eM1{MjdA|T7uYhcVv*es6kz2JmEC3dP50V(@> zhw^bYx}Q>ew+Rg91l%-VoN9v70KkP@+RO>GayE|_gSL0;JR)mU?pB)>RiBCkF)x)d z3=W3~4ooHVNs%m+3KQ^&6WVJ6Wr_i3GHA#?KD2U-0jMz8axlCFGYr4YfMhvhj@<<( z$*qVuxLOlKAERZf~ z2beUZdnzIXfw6K31nE3GAVE zBDAoB7@(8LgAnCu!t)9&f`yaSoV;yccPi14CKM#Xw-7i(Y{JXGQR#1ImrF(ffUW=l zH_U-OLwZOQJ;E21h@z?Qz8Ow`jcj{excM5gn8wKhP*d=Wr2HQ#;C?(Dl?BmewMfdg zUrf(t$^Z(K)&)oKYDN4(^%?j!VoXU!U(?4vD62212SCO_@ti=OZ*S2e zSbzg;D!^4=uuz`5v^yC5VMxno0C8bxqZu^70+f^?MCH(*-a*9Fpq5-`V=8#vX85`> z7XrfR!QhtN({N2f65A0dc6H8X`+-iA^SLF^^TLHBy1*0es

BMJG!6x8X))Z*&(b*FyL-+K+~wppHcAT`$747 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 delta 287346 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%0D^0 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ℜn8|YOjTDow4NZL}D=qi;Ojg^U9Xs+( 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
2Xb5+P^k>L`hFE9FeTFn=$bg0% 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 diff --git a/artifacts/verification/w6/80x24.png b/artifacts/verification/w6/80x24.png index 40b38620fd506f9118ffd566c40c1d80bb7768dc..abc5e8bbaf11a38bf97c01aa0ab9e21bc90bbdac 100644 GIT binary patch literal 18888 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 Vo%B}A#(_&96-CXL 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 diff --git a/artifacts/verification/w6/80x24.txt b/artifacts/verification/w6/80x24.txt index 4adc54a..09acd77 100644 --- a/artifacts/verification/w6/80x24.txt +++ b/artifacts/verification/w6/80x24.txt @@ -16,9 +16,9 @@ +──────────────────────────────────────────────────────────────────────────────── +› new message -› - - -profile Braid starter · pi / deterministic Ctrl+E detail +─────────────── type / for commands · Alt+Enter newline · paste ──────────────── +profile Braid starter · pi · via local Ctrl+E details diff --git a/artifacts/verification/w6/braid.gif b/artifacts/verification/w6/braid.gif deleted file mode 100644 index f2f9ccd4214986db0b5e226b8440a24d39741706..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254468 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λ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

    @{i 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�x(`c8FmOrJnqXr?9JTn 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 v^42ErcTV>8lD4?TWe3W+We<#i!X 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%0A+8t{9)S=N{zuX3-)+I2!yP}x>cODhZe4RzEJSe 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%0AW3ks$WJ`jIOWwHy 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 diff --git a/artifacts/verification/w6/braid.png b/artifacts/verification/w6/braid.png deleted file mode 100644 index 542e470bab1c327f353a1c9f02e4345b44a4eb6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25764 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 diff --git a/artifacts/verification/w6/braid.txt b/artifacts/verification/w6/braid.txt deleted file mode 100644 index 53ca971..0000000 --- a/artifacts/verification/w6/braid.txt +++ /dev/null @@ -1,18 +0,0 @@ - › Which coding agent will handle my next task, and where will it run? - - · run result · Ctrl+E details - Pi will run the task through Local CLI Bridge with gpt-5.6-luna. The Release engineer AgentProfile supplies its - instructions and permissions. Braid keeps the transcript, approvals, branches, and trace analysis. - - - - - - - - - -› - - -profile Release engineer · pi / openai-codex/gpt-5.6-luna · Local CLI Bridge · high in 1.3k · out 96 · ~$0.0026 diff --git a/artifacts/verification/w6/capture-manifest.json b/artifacts/verification/w6/capture-manifest.json index 9cb4e40..c86cf5e 100644 --- a/artifacts/verification/w6/capture-manifest.json +++ b/artifacts/verification/w6/capture-manifest.json @@ -1,17 +1,18 @@ { "schemaVersion": 3, - "generatedAt": "2026-08-12T12:38:14.171Z", + "generatedAt": "2026-08-16T11:05:49.322Z", "command": "pnpm capture:visual", "binary": "clean npm install from generated tarball", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7", - "fixture": "deterministic", + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1", + "stateFixture": "deterministic", + "liveDemoCommand": "pnpm capture:demo:live", "terminal": "node-pty/xterm-256color", "node": "v24.13.0", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -38,22 +39,43 @@ "80x24-transcript-keyboard.gif" ] }, - "productDemo": { - "steps": [ - "Inspect AgentProfile", - "Run through Local CLI Bridge", - "Inspect live work and the retained run", - "Analyze the frozen trace with /ask", - "Review the analysis list and details together" - ], - "artifacts": [ - "raw/braid-demo.cast", - "braid.txt", - "braid.png", - "braid.gif" - ] - }, "states": [ + { + "name": "command-palette-40", + "columns": 40, + "rows": 12, + "artifacts": { + "semantic-state": "states/command-palette-40.json", + "plain-frame": "states/command-palette-40.txt", + "asciicast": "raw/command-palette-40.cast", + "ansi": "states/command-palette-40.ansi", + "png": "states/command-palette-40.png" + } + }, + { + "name": "command-palette-80", + "columns": 80, + "rows": 24, + "artifacts": { + "semantic-state": "states/command-palette-80.json", + "plain-frame": "states/command-palette-80.txt", + "asciicast": "raw/command-palette-80.cast", + "ansi": "states/command-palette-80.ansi", + "png": "states/command-palette-80.png" + } + }, + { + "name": "command-palette-120", + "columns": 120, + "rows": 24, + "artifacts": { + "semantic-state": "states/command-palette-120.json", + "plain-frame": "states/command-palette-120.txt", + "asciicast": "raw/command-palette-120.cast", + "ansi": "states/command-palette-120.ansi", + "png": "states/command-palette-120.png" + } + }, { "name": "empty", "columns": 80, @@ -190,91 +212,211 @@ "artifacts": [ { "path": "40x12.txt", - "sha256": "06bd2cb4454d314c0fba112343013f35ecb532d7eae36eaf0f81bc5919c7bfa7", + "sha256": "c6a6ebafdf8ab2cab97231bfa0cd20393e97cda253f5e2bb4486d1a2aa5e0841", "kind": "terminal-frame", "columns": 40, "rows": 12 }, { "path": "40x12-plain.txt", - "sha256": "079768ad779ecd50135cdbbc133aeee9b6281ddfffbb22af4e0178bfe41dc615", + "sha256": "b4eba68d5db2676629a7d6004f556f308eb3c6617e3b60c38e6526c3f9f6de37", "kind": "plain-frame", "columns": 40, "rows": 12 }, { "path": "40x12.png", - "sha256": "448563badac78d2c989ede14d92ebad7393f95b5874a766d915ec76c62492780", + "sha256": "34b7dd57b9553776c55a6ed3436a33d4244a6151ca961890ebc9d563611b3b92", "kind": "png", "columns": 40, "rows": 12 }, { "path": "80x24.txt", - "sha256": "9b17cc3d0785706ed07325649a553637adc8ffafc5642ebab2a22197126a99c5", + "sha256": "d4b59289ce1b65a414b2ec51bf7594f83edfbcc0ad998121dc464c06bdb3bad5", "kind": "terminal-frame", "columns": 80, "rows": 24 }, { "path": "80x24-plain.txt", - "sha256": "079768ad779ecd50135cdbbc133aeee9b6281ddfffbb22af4e0178bfe41dc615", + "sha256": "b4eba68d5db2676629a7d6004f556f308eb3c6617e3b60c38e6526c3f9f6de37", "kind": "plain-frame", "columns": 80, "rows": 24 }, { "path": "80x24.png", - "sha256": "36ec2775eff6d256e107c4f194ea65aeb59e43187ce17c37c27e623bf7ab7c92", + "sha256": "8b07e737fd294887162f6ae0a218a8fb255f6221c2f01d6871cf6180dcdeaa9d", "kind": "png", "columns": 80, "rows": 24 }, { "path": "120x40.txt", - "sha256": "1a52a383a1fd94baae24f061f064c12dc2db5c1f557ba16deba89eb25832815a", + "sha256": "894fa2870be18d8f92ca2a5612f4825ffab0e893d5ead743b97d79ae13226688", "kind": "terminal-frame", "columns": 120, "rows": 40 }, { "path": "120x40-plain.txt", - "sha256": "079768ad779ecd50135cdbbc133aeee9b6281ddfffbb22af4e0178bfe41dc615", + "sha256": "b4eba68d5db2676629a7d6004f556f308eb3c6617e3b60c38e6526c3f9f6de37", "kind": "plain-frame", "columns": 120, "rows": 40 }, { "path": "120x40.png", - "sha256": "ae1db9182dae754026070d8a924ccab59bd0cac44a58f4ba68046206f1460beb", + "sha256": "d2cb656a14f115efc5efe57bea8412561f43100266a297397cfe9ebcaae30ec4", "kind": "png", "columns": 120, "rows": 40 }, { "path": "200x60.txt", - "sha256": "6b967e1a525d2f1f5f4d1507744bc2c4969b8d16decda9e31e821658618be57e", + "sha256": "b9e8a5c5e75f5059327e2fcdb22c746e2ddcf0c1e54a5e66745245b3f78fa0e6", "kind": "terminal-frame", "columns": 200, "rows": 60 }, { "path": "200x60-plain.txt", - "sha256": "079768ad779ecd50135cdbbc133aeee9b6281ddfffbb22af4e0178bfe41dc615", + "sha256": "b4eba68d5db2676629a7d6004f556f308eb3c6617e3b60c38e6526c3f9f6de37", "kind": "plain-frame", "columns": 200, "rows": 60 }, { "path": "200x60.png", - "sha256": "9e5fa392f597a70fcc527da54cae93a945fbcb998867fbdc5708652e940021bc", + "sha256": "e4ca0f0f779b4d98f247d48e0cba901f3c9086bfb2ed1dd0e311226999f5d203", "kind": "png", "columns": 200, "rows": 60 }, + { + "path": "states/command-palette-40.json", + "sha256": "5c27b2bd2250517fbe6c2fc421901501f30eb92f6630e2e44d63b899a5b8ac53", + "kind": "semantic-state", + "state": "command-palette-40", + "columns": 40, + "rows": 12 + }, + { + "path": "states/command-palette-40.txt", + "sha256": "602384fa133295eed00b640cb694a874b45ed14eb7e3ee6a784734a4f3c8fce9", + "kind": "plain-frame", + "state": "command-palette-40", + "columns": 40, + "rows": 12 + }, + { + "path": "raw/command-palette-40.cast", + "sha256": "74813c066cfffadfa226c084ecf40d2486afc538e8b252c5eb62af84b394c23e", + "kind": "asciicast", + "state": "command-palette-40", + "columns": 40, + "rows": 12 + }, + { + "path": "states/command-palette-40.ansi", + "sha256": "f2d05698de52c9657177427374a713441d384b541744fb47f131cf08a6892d59", + "kind": "ansi", + "state": "command-palette-40", + "columns": 40, + "rows": 12 + }, + { + "path": "states/command-palette-40.png", + "sha256": "c309e1dcdcd0edca774cdcdc0dcd7d0b350b6711df057a0149b8bff7afac5895", + "kind": "png", + "state": "command-palette-40", + "columns": 40, + "rows": 12 + }, + { + "path": "states/command-palette-80.json", + "sha256": "ccdcf1b381de74a8fb493314661a3903083c59c00effd8f4beefc1d9e501e459", + "kind": "semantic-state", + "state": "command-palette-80", + "columns": 80, + "rows": 24 + }, + { + "path": "states/command-palette-80.txt", + "sha256": "071efa2fab24affd8ad916f750e1663dee47a7d084b1109b1beaace3fea0aac9", + "kind": "plain-frame", + "state": "command-palette-80", + "columns": 80, + "rows": 24 + }, + { + "path": "raw/command-palette-80.cast", + "sha256": "90dba750a60144776b3e0a9c21e0f637adffe7676028382a811266733e4b2c5b", + "kind": "asciicast", + "state": "command-palette-80", + "columns": 80, + "rows": 24 + }, + { + "path": "states/command-palette-80.ansi", + "sha256": "d26c61c53da5a44072602e3588dd46b9388c35da18618ee4759c20e0921cccc1", + "kind": "ansi", + "state": "command-palette-80", + "columns": 80, + "rows": 24 + }, + { + "path": "states/command-palette-80.png", + "sha256": "1271f15c60ceb8ec89cdae9c62978cc584696daefb55eeb9e93eea24f8987ef2", + "kind": "png", + "state": "command-palette-80", + "columns": 80, + "rows": 24 + }, + { + "path": "states/command-palette-120.json", + "sha256": "b8a15b79b21d7c0c4d6217a1b44e2b502516e48048f05b8a6a9aef59d1b57448", + "kind": "semantic-state", + "state": "command-palette-120", + "columns": 120, + "rows": 24 + }, + { + "path": "states/command-palette-120.txt", + "sha256": "5cf0994eafd3560f613040a745867cc99cb43a28ceb42e1c9d1a45f568d62655", + "kind": "plain-frame", + "state": "command-palette-120", + "columns": 120, + "rows": 24 + }, + { + "path": "raw/command-palette-120.cast", + "sha256": "a8900525607d24ef8eae6e76fdf3a80e79b258e2491d5596f515ef6625c12f87", + "kind": "asciicast", + "state": "command-palette-120", + "columns": 120, + "rows": 24 + }, + { + "path": "states/command-palette-120.ansi", + "sha256": "a8daac8e89b2e3485574aae55b83b3a8c9caad0336e4de0fbced1ede57adaf0b", + "kind": "ansi", + "state": "command-palette-120", + "columns": 120, + "rows": 24 + }, + { + "path": "states/command-palette-120.png", + "sha256": "11a66bf2fc2137005b19dcbf2a371abaecfc1dd736617ee9c47321daa6881984", + "kind": "png", + "state": "command-palette-120", + "columns": 120, + "rows": 24 + }, { "path": "states/empty.json", - "sha256": "46ee54a2d8a5c933eff1768c7b57aa7f7b93efdcfbd55aeaf435927132f2644e", + "sha256": "cb4e42b58931992624f32f601210c61ac26b9bf5fe74200b6cc747d23f61d8f0", "kind": "semantic-state", "state": "empty", "columns": 80, @@ -282,7 +424,7 @@ }, { "path": "states/empty.txt", - "sha256": "42a217605b309c5c5ac02531d3b86119a203af7f292ab27f320a967c615a865a", + "sha256": "08ff2f6bf30820c2c1e3046b2ebf08b2184464083f876ee75321f3f94b57041f", "kind": "plain-frame", "state": "empty", "columns": 80, @@ -290,7 +432,7 @@ }, { "path": "raw/empty.cast", - "sha256": "330fd536c7f9edd639b9b6828913f3d49c33509d871141b5652d8c80eac444a8", + "sha256": "89171ef20fb8012225e74af1b7e7e4b33c44acfecefb648f73bd98a839775165", "kind": "asciicast", "state": "empty", "columns": 80, @@ -298,7 +440,7 @@ }, { "path": "states/empty.ansi", - "sha256": "2de36ed50acbd770bf7217f43386f32f573d3967c6df77d5bc5db931a030a1b9", + "sha256": "9bc7c615c17e48643071466dfe4c3da3fed94a908e2e901a4be24f484da647c7", "kind": "ansi", "state": "empty", "columns": 80, @@ -306,7 +448,7 @@ }, { "path": "states/empty.png", - "sha256": "e276855bcab549b345a2bd412464a49bfafe3a53ca6fb23d934b5286ec6b0316", + "sha256": "ca2ae68ed2e75b5c2f9db65f60f4e0cea048ce146d87b74287069729576d3dfd", "kind": "png", "state": "empty", "columns": 80, @@ -314,7 +456,7 @@ }, { "path": "states/active-streaming.json", - "sha256": "0e178e31768a1de7f89794767413d1bc161351ffd5207d6476bbec8ffe7c9393", + "sha256": "5d517f31a384c6c60fe76afc7c221ef34d597b1fa8e8369285b97583ad120306", "kind": "semantic-state", "state": "active-streaming", "columns": 80, @@ -322,7 +464,7 @@ }, { "path": "states/active-streaming.txt", - "sha256": "fca88cebc11ef71b95b55deeabc3ffa29551f4bb23a9756eb4739ee3b3618de0", + "sha256": "24aa14b3ba64753421a08d51382ace0829a893912ec6774d6792cac369d11e0d", "kind": "plain-frame", "state": "active-streaming", "columns": 80, @@ -330,7 +472,7 @@ }, { "path": "raw/active-streaming.cast", - "sha256": "95032f9ff36f0349ab3beaeda0aa17dd403587162c4cb8388e07feb07c9f0910", + "sha256": "1a5b49eb7e6ea678b8c773e6655dd9e9e8ba610a4569b482204d67aaff0fc6c4", "kind": "asciicast", "state": "active-streaming", "columns": 80, @@ -338,7 +480,7 @@ }, { "path": "states/active-streaming.ansi", - "sha256": "c6530f7b36e87ee3737df4ff3df59d6551dc6711c5eda7ec54eb3efd62d35a0a", + "sha256": "bc85b2a0a8d4a819d56ce517831de708f16608c1679f52b331453c733062b8c1", "kind": "ansi", "state": "active-streaming", "columns": 80, @@ -346,7 +488,7 @@ }, { "path": "states/active-streaming.png", - "sha256": "4639ab1c23b7b6bc526cb51bf5b92de0eb621ea1f9f802e0fdf63cd39c9e0ce3", + "sha256": "4caf2c408d06ebd44f24a9fe3fd06f16d6bcb201ef6eeee4a8c9b5fb53a89dd9", "kind": "png", "state": "active-streaming", "columns": 80, @@ -354,7 +496,7 @@ }, { "path": "states/interaction.json", - "sha256": "e20dfbbbe4595799e7daf11268e2027b7f69d4683317077ba3b606eff5df5739", + "sha256": "5c580d158ad16f57ece76bc277f5e8da436c54e71f71be5c8c5649d1994bfbf3", "kind": "semantic-state", "state": "interaction", "columns": 80, @@ -362,7 +504,7 @@ }, { "path": "states/interaction.txt", - "sha256": "b3834e354b37526a8c01dad4a321ba71569a3577b6a9b740c3ca220b0ddc337c", + "sha256": "1fbd4f8c2dff1d98946ffd2ad8c8f56695442097db1c06a56b7f748e89bf3c38", "kind": "plain-frame", "state": "interaction", "columns": 80, @@ -370,7 +512,7 @@ }, { "path": "raw/interaction.cast", - "sha256": "b56bc79da2c5e504648a47963f4e41cabb718e5a5817510771610ba1efb5fdcf", + "sha256": "c6ee4036e3b085b7f645c481726e5953a97c6648689db02b55422d80e4ea5ade", "kind": "asciicast", "state": "interaction", "columns": 80, @@ -378,7 +520,7 @@ }, { "path": "states/interaction.ansi", - "sha256": "03c62fde015d3d5e12886d9cace2750d244f1a9f625b4d7170c8a865f4d393e5", + "sha256": "d978d6566b75e14b7d4581cb9f9f42396d452efb1341891621ffd68446cfca9d", "kind": "ansi", "state": "interaction", "columns": 80, @@ -386,7 +528,7 @@ }, { "path": "states/interaction.png", - "sha256": "be5ff9e21e002530cb78fdbba96830056b703b5d739e14d7f98889d3f88fd556", + "sha256": "0f898e22a9e713e1efdb9b265568820c22cf218b4ab400bae67040a119f26efc", "kind": "png", "state": "interaction", "columns": 80, @@ -394,7 +536,7 @@ }, { "path": "states/automation.json", - "sha256": "2ae692ab250879c46d1308f854d12d682d8b16b13a69b15e42a3490dc4fbbde7", + "sha256": "224622e910643bc235d06e58297575875520e00acf6c5066fd0f18250b3c38ec", "kind": "semantic-state", "state": "automation", "columns": 80, @@ -402,7 +544,7 @@ }, { "path": "states/automation.txt", - "sha256": "82d0afcc23d1988502a1b580d44db01a8dd0c9c5f9d16dcca113d31148470f10", + "sha256": "2507d52854ac0c0fe5ee5c39fa5aaf7a472030b46732b15a6886f76e23b6cea3", "kind": "plain-frame", "state": "automation", "columns": 80, @@ -410,7 +552,7 @@ }, { "path": "raw/automation.cast", - "sha256": "65f4519ecdb0ba8809eae6860da72427b595fcfcf5cd7301ea051b60d39a745d", + "sha256": "740c3166a5396a4802cc79a96773dfbbde8c224636f0d7ecc5312084c22f87b0", "kind": "asciicast", "state": "automation", "columns": 80, @@ -418,7 +560,7 @@ }, { "path": "states/automation.ansi", - "sha256": "fc25c7b836b7a6fcd4e6e33c8e609c8bd5e0228e41861beaae4df5628925f949", + "sha256": "daaa5df4c97b17ba28b6eacbf9b2df647f991357d246091fefc46f4a056209bd", "kind": "ansi", "state": "automation", "columns": 80, @@ -426,7 +568,7 @@ }, { "path": "states/automation.png", - "sha256": "f97a1184b127ddca1620be4c4da9a8823f5f9ddd362fc6d99ec5c97fb7403c88", + "sha256": "04cf4e658eb59c8a4685b10045fb4c42b046576d4e5af0fcd8e24a3d1211518d", "kind": "png", "state": "automation", "columns": 80, @@ -434,7 +576,7 @@ }, { "path": "states/fork-preview.json", - "sha256": "b78c3d8548d6626434774860499edd7c7876f8b108057ab13dceb6921b3bb3d7", + "sha256": "b0b022cbf9238b93b032dff99bcd1bba9cd38b3747d5801c951be405d3533cda", "kind": "semantic-state", "state": "fork-preview", "columns": 80, @@ -450,7 +592,7 @@ }, { "path": "raw/fork-preview.cast", - "sha256": "c7645af81c3839e219613200ed1434737feb08611f78efeb0b599d65a5e50b94", + "sha256": "97827f0a57786bf917f31d0d6f3f036a867fd8b6d31119c2e12378c1c66eee1e", "kind": "asciicast", "state": "fork-preview", "columns": 80, @@ -458,7 +600,7 @@ }, { "path": "states/fork-preview.ansi", - "sha256": "6e69ec241a014064a1dec7248e772142ec72deb0f3b1c7f7cc57b9211c62bf9f", + "sha256": "7d6560dc79aaa38350cb61f61ea4e9005e4866b1a41148312df76237643df36d", "kind": "ansi", "state": "fork-preview", "columns": 80, @@ -466,7 +608,7 @@ }, { "path": "states/fork-preview.png", - "sha256": "1e3563f55e99f06097e964d1ff8c353ce52efd3d816c9551e7c125cf0e678ccb", + "sha256": "15e39559a7774e5b44b6c19ea3bfab5566ff90bc5161207b3436bdb7e74ed6c6", "kind": "png", "state": "fork-preview", "columns": 80, @@ -474,7 +616,7 @@ }, { "path": "states/graph-or-analysis.json", - "sha256": "280dc31c5894850302479ed25930948d5ed52fb8fbd8a8f42aa49144661a15fb", + "sha256": "13d6827d96d105a52f8e609650a1e883c8ac6b258c66f2f1aab89fd97bd4c652", "kind": "semantic-state", "state": "graph-or-analysis", "columns": 80, @@ -482,7 +624,7 @@ }, { "path": "states/graph-or-analysis.txt", - "sha256": "de00305382582cdc1ed849578990abc3fdeae1fc388bc7322c7d656370cf3543", + "sha256": "c84d480eda3001990287551cc063b7fbef7622f5f10559ead4b96c055112ac50", "kind": "plain-frame", "state": "graph-or-analysis", "columns": 80, @@ -490,7 +632,7 @@ }, { "path": "raw/graph-or-analysis.cast", - "sha256": "79aaf455381f031749dee0e59fc71809c33c6a29fadef8ae767fd2d3bd5eed0f", + "sha256": "43c1968dbc3d5ce4a909a816677c024c38fd10af3b48487c31f30729d011aae7", "kind": "asciicast", "state": "graph-or-analysis", "columns": 80, @@ -498,7 +640,7 @@ }, { "path": "states/graph-or-analysis.ansi", - "sha256": "6881a55457e95a7dbacd7526600b54883f116d1d74f021b66b61babf3510d04a", + "sha256": "0453b411c8ba4421e88fe8912a2251b9b53ee674379c10316bb750ea5cc91beb", "kind": "ansi", "state": "graph-or-analysis", "columns": 80, @@ -506,7 +648,7 @@ }, { "path": "states/graph-or-analysis.png", - "sha256": "ed849a9a6f02b4a931dbd6b20b735fd3f341e8b4f851bf362b574146720a049a", + "sha256": "228155d434335121ada906c4da860d7c0d81daa78a605215a59ae20a6b0674f2", "kind": "png", "state": "graph-or-analysis", "columns": 80, @@ -514,7 +656,7 @@ }, { "path": "states/analysis.json", - "sha256": "994b96517d6981f69d8ca61c90378fed9efaaead6ea2c15f7e889e0012aaed0e", + "sha256": "bebe69c66f8640f4c0d935c558aaf574c5b1c738ccf4aa2fb1502c3ed8a08fde", "kind": "semantic-state", "state": "analysis", "columns": 80, @@ -522,7 +664,7 @@ }, { "path": "states/analysis.txt", - "sha256": "a20c35b119f09abe543129e363fda55cc9063c45480536c4d0681dd7e21bc0ea", + "sha256": "2ec459b6402f320d1b9f1991e3e9572216b3d207db8799e274dfbf56d0d693ea", "kind": "plain-frame", "state": "analysis", "columns": 80, @@ -530,7 +672,7 @@ }, { "path": "raw/analysis.cast", - "sha256": "f5181342eeb963b7bab41884918361ca0df2ce005f2ba4a0c288c3217969e0ed", + "sha256": "40380b70ef12a5cd9a2a4b4df08c1298c7c17bf8af5314b112417decc46c5efb", "kind": "asciicast", "state": "analysis", "columns": 80, @@ -538,7 +680,7 @@ }, { "path": "states/analysis.ansi", - "sha256": "5e3ced49f5b91590b308bdb45696c7b5c33f3ff82483182d7e3666448cdbd89b", + "sha256": "a043cf95e099db44b6daa782b9683c3933e66e309391bcf4ede5637c98e9fa1e", "kind": "ansi", "state": "analysis", "columns": 80, @@ -546,7 +688,7 @@ }, { "path": "states/analysis.png", - "sha256": "ca4f2c9e206f35006b98057527d15bd3edc0b98a65c8a2ffa7360f51f69e8cd4", + "sha256": "b0d77c88cd27180fe2f9c2a3b82f8c4f6910b402e6066445620735be8fc189d9", "kind": "png", "state": "analysis", "columns": 80, @@ -554,7 +696,7 @@ }, { "path": "states/comparison.json", - "sha256": "14d4223261bbf219177ec65cde2a3e10aacc397fbe4a1332e47581934c664460", + "sha256": "043e1fc3b60258b57a6357f9414fdf710a753532079ed8bfa1aee60ae0c998f7", "kind": "semantic-state", "state": "comparison", "columns": 80, @@ -562,7 +704,7 @@ }, { "path": "states/comparison.txt", - "sha256": "bf5ce0eb0f5a60fc0f953cb58ee6bff0f04e3309c224896a16b5ac8a42110197", + "sha256": "b03447b3bf3ac214b5f0bc739dc50a01f01b5deba258b501e9fc83f525db8a78", "kind": "plain-frame", "state": "comparison", "columns": 80, @@ -570,7 +712,7 @@ }, { "path": "raw/comparison.cast", - "sha256": "338a18f2fc67cddefb1c01151b32ca10a28091ac710258fc73e767591a17043e", + "sha256": "b999ba6a713dd400caf1f8628b668a67b4c3102d710fd7ca02b339ddaf7e37c0", "kind": "asciicast", "state": "comparison", "columns": 80, @@ -578,7 +720,7 @@ }, { "path": "states/comparison.ansi", - "sha256": "30b05a8bdf89cd5bf2f4acae27363dea64dc575667ec749f70d71c78421a8b58", + "sha256": "07da7cf3d6e160f36fd85f725760111c070fc9234101716c9cb3135ff6d0b799", "kind": "ansi", "state": "comparison", "columns": 80, @@ -586,7 +728,7 @@ }, { "path": "states/comparison.png", - "sha256": "19ec095185e2936f728727096aa00c17d5f8c7239e79e0493f7855c71ea8114a", + "sha256": "69d9a11db9864e7f0f2cfa31fbedbe2e1c326c7708ce8ad2ee6798b077244ec1", "kind": "png", "state": "comparison", "columns": 80, @@ -594,7 +736,7 @@ }, { "path": "states/profile.json", - "sha256": "f47dbe4ccd7178a4c76295ad5247b0f1fcfddb4b9c8a388e771843e88979d06d", + "sha256": "7c8b422ab3cb618bc6aca2a9455d5737f66d1395812d35cafaa984cd7622e699", "kind": "semantic-state", "state": "profile", "columns": 80, @@ -602,7 +744,7 @@ }, { "path": "states/profile.txt", - "sha256": "6a80d3fb1340f87de3eadd69b63ea7728699602860fa6c3d4848372053b9ec29", + "sha256": "25d741a6470f149651a6c7743dd4570a33a5be501678170a23385a4b1f005f3f", "kind": "plain-frame", "state": "profile", "columns": 80, @@ -610,7 +752,7 @@ }, { "path": "raw/profile.cast", - "sha256": "2cbce115bbd07064ec1f60de4fefada320f8a4fd7fa9139731b8cfcf60c4158f", + "sha256": "216e33d0b15d7eacb809065c3ba4f1a21c6d80026cc085e24e55c8a2ad91803c", "kind": "asciicast", "state": "profile", "columns": 80, @@ -618,7 +760,7 @@ }, { "path": "states/profile.ansi", - "sha256": "f0d3f1dd19e1cb79542d321953b2655a9790a436ddee393439363acc047d5ad7", + "sha256": "8246826589ec2ac40952bb75b9e18d2ea56b7b08d3390127843e96bcdfc086cc", "kind": "ansi", "state": "profile", "columns": 80, @@ -626,7 +768,7 @@ }, { "path": "states/profile.png", - "sha256": "baa74d63563fc18d26678e4baccb306e465a1f45738a908ebffab09b059aa1bd", + "sha256": "c3061c68ab192a4518ecc4ae92b385ee5adc791178aaefe0b15d2511562ac254", "kind": "png", "state": "profile", "columns": 80, @@ -634,7 +776,7 @@ }, { "path": "states/narrow.json", - "sha256": "5c1d195eeb9f278ff7cada9bf8288f7dca9d1a7ff44a4a2580ddd7a20db8e617", + "sha256": "6b8ed81e9a68a0fa1af5102550e9f70f71d94a3593a6eb5427b0d3fa282b664e", "kind": "semantic-state", "state": "narrow", "columns": 40, @@ -642,7 +784,7 @@ }, { "path": "states/narrow.txt", - "sha256": "e01838efb7f91c10849b39be7e9b5283549d7fe5b058bf7a251effdfabfa2117", + "sha256": "df26361f3056c15bd93f3a77bd29606b04d52f1294ba2a4d9d14ed75eab558f5", "kind": "plain-frame", "state": "narrow", "columns": 40, @@ -650,7 +792,7 @@ }, { "path": "raw/narrow.cast", - "sha256": "5e085dd96c7218704656478dd72e83c40fd6e231f5a3f9d9029ee3cfd0c449b4", + "sha256": "44dd280999eeaa2c21dfa50fbfdcfd267e38ce0da7c4d0759f92a0a7d472183b", "kind": "asciicast", "state": "narrow", "columns": 40, @@ -658,7 +800,7 @@ }, { "path": "states/narrow.ansi", - "sha256": "5a2f5d8635f98b399247f58de032840146d7dab7c2ec70f265d0e94b6ffe99ed", + "sha256": "1361c7b3b857d207c9bbb3f8b4be705d97eabaf2c1df022a33eb9403c60f34b5", "kind": "ansi", "state": "narrow", "columns": 40, @@ -666,7 +808,7 @@ }, { "path": "states/narrow.png", - "sha256": "2f121a3d785bb6dbca7fa79bc7c071cbd28f5151cc569e3450b0bc8f91179d55", + "sha256": "a9cd6b6003be8034dfbd1438924c7c4513d684ceff97954e983c96bb9f9ff032", "kind": "png", "state": "narrow", "columns": 40, @@ -674,7 +816,7 @@ }, { "path": "states/failure-or-reconnect.json", - "sha256": "5e36663029014857ea1c9895f743d484347e2561bb4cccb2dd8c59424a35e843", + "sha256": "a8db7dfcc25e3d4d45e4a06f47924ff19d67b7c4e24f245ceefea68b5fd372c7", "kind": "semantic-state", "state": "failure-or-reconnect", "columns": 80, @@ -682,7 +824,7 @@ }, { "path": "states/failure-or-reconnect.txt", - "sha256": "649a5db60a906d5ed28b556dbc6231c36d11a3ae8e89fa473cdce4c392c4e447", + "sha256": "b995b865a83e8ae1df59cb81404694422c14b201fae4cec1a33d9347a8c26166", "kind": "plain-frame", "state": "failure-or-reconnect", "columns": 80, @@ -690,7 +832,7 @@ }, { "path": "raw/failure-or-reconnect.cast", - "sha256": "bed225eb46cd87158e6987db8e50c2554cdd6f66dd423b609521f7c35541a6f3", + "sha256": "a8e4a4cf1e09de874f86a739f72fd0e63f19cdd24125eed4b41bb24876c18389", "kind": "asciicast", "state": "failure-or-reconnect", "columns": 80, @@ -698,7 +840,7 @@ }, { "path": "states/failure-or-reconnect.ansi", - "sha256": "0174698483fc5254eef1ff90bbc187ab259e448dc24ddef72e26cf4a6c0fa86c", + "sha256": "a4616bcda3d80595bbd0d3630059e1fa4a4df23f9edc6c7076aff5785f62bd7f", "kind": "ansi", "state": "failure-or-reconnect", "columns": 80, @@ -706,7 +848,7 @@ }, { "path": "states/failure-or-reconnect.png", - "sha256": "0c6976145f9bc93b884b9f05d13d8048852f235b6cc533986d99129b8da53f5a", + "sha256": "1437df31f7e0d011d846e01cf67012c5466b2b4dbfd2267a06377aba9ce5b30a", "kind": "png", "state": "failure-or-reconnect", "columns": 80, @@ -714,57 +856,29 @@ }, { "path": "80x24-flow.gif", - "sha256": "c3719c1f9c30651e7a5ddae10b39601f1953a6eee75f589ecbd83ebdbbee1532", + "sha256": "2a2a3cb57e17d163c27ff11e00af9b48e64ec6c49589a25758f466e4d7274dd7", "kind": "flow", "columns": 80, "rows": 24 }, { "path": "80x24-automation.gif", - "sha256": "1353469379fa0e744353f51fbe1424dec50ef78bd9092ebefec55e67fab04383", + "sha256": "6453b83a25e3d44f28a436209282ed00119334a72d6e2c127b5aa02e97d35e75", "kind": "automation-flow", "state": "automation", "columns": 80, "rows": 24 }, - { - "path": "raw/braid-demo.cast", - "sha256": "1151b0fe2e5148d6531567d89920efcb01958207a67b162e80f4b48d2d8b7b53", - "kind": "product-asciicast", - "columns": 120, - "rows": 18 - }, - { - "path": "braid.txt", - "sha256": "9da6cead048673c48402c4eb40dc9696d39c7bdcb1a2103b755098209f00f53e", - "kind": "product-frame", - "columns": 120, - "rows": 18 - }, - { - "path": "braid.png", - "sha256": "433912d21bbcc26edf7ebf5d84d66aab161e208f0ac0881cc9150d2f710a3552", - "kind": "product-png", - "columns": 120, - "rows": 18 - }, - { - "path": "braid.gif", - "sha256": "c29b2c06c59eea7c9d9cbef7ccc01bb1e0a7a7bdc6e183a0a83b42a86d4f2cdf", - "kind": "product-flow", - "columns": 120, - "rows": 18 - }, { "path": "raw/transcript-keyboard.cast", - "sha256": "81afea3985d5c1589ea675a95eb83a6f6fd4b8f9221206611d3568750a81c186", + "sha256": "63750f2c24f535e5cfeacf666358746244fa4b3fbbf5a0048b847670dee48b82", "kind": "keyboard-asciicast", "columns": 80, "rows": 24 }, { "path": "80x24-transcript-keyboard.gif", - "sha256": "160203e6e25b15251ffb1ffd55eb3e6e0209a584c31017bcd3a746add1e595a9", + "sha256": "a54e70cd45d6095de8696c25c13671308c4760904876e31b4ebbc19de6cd2c7b", "kind": "keyboard-flow", "columns": 80, "rows": 24 diff --git a/artifacts/verification/w6/raw/braid-demo.cast b/artifacts/verification/w6/raw/braid-demo.cast deleted file mode 100644 index 446c98a..0000000 --- a/artifacts/verification/w6/raw/braid-demo.cast +++ /dev/null @@ -1,375 +0,0 @@ -{"version":2,"width":120,"height":18,"timestamp":1786538290,"duration":11.512167,"idle_time_limit":1,"command":"packed braid --fixture deterministic","title":"Braid product demo","env":{"TERM":"xterm-256color"},"stdin":true} -[0.01,"o","\u001b[?2026h\u001b[2J\u001b[H\u001b[3J \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[38;5;145mAsk Release engineer anything.\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007 Active profile · Release engineer \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007 \u001b[38;5;145msource Release engineer · trusted · read-only\u001b[39m \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007 \u001b[38;5;145mrunner pi · model openai-codex/gpt-5.6-luna\u001b[39m \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007 \u001b[38;5;145mthinking high · max output provider default\u001b[39m \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007 \u001b[38;5;145mdigest sha256:0419cd01…31378043\u001b[39m \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007 \u001b[1m\u001b[38;5;153mprofiles\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\u001b[38;5;145m─────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007> \u001b[7m \u001b[27m \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\u001b[1m\u001b[38;5;111m→ ✓ Release engineer trusted · read-only · Release engineer · pi · openai-codex/gpt-5.6-lu\u001b[0m\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\u001b[38;5;145m─────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007 \u001b[38;5;145menter · ^V valid · ^S save · esc\u001b[39m \u001b[0m\u001b]8;;\u0007 \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[38;5;195mprofile Release engineer\u001b[39m · \u001b[38;5;195mpi / openai-codex/gpt-5.6-luna\u001b[39m · \u001b[38;5;195mLocal CLI Bridge\u001b[39m · \u001b[38;5;195mhigh\u001b[39m \u001b[38;5;195mCtrl+P commands\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[0.010052,"o","\u001b[7A\u001b[10G\u001b[?25l"] -[1.007919,"i","\u001b"] -[1.019211,"o","\u001b[?25l"] -[1.020923,"o","\u001b[?2026h\u001b[7A\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[2G"] -[1.02095,"o","\u001b[?25l"] -[1.37875,"i","W"] -[1.38029,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mW\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3G\u001b[?25l"] -[1.39968,"i","h"] -[1.400949,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWh\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4G\u001b[?25l"] -[1.419366,"i","i"] -[1.4204,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhi\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[5G\u001b[?25l"] -[1.439808,"i","c"] -[1.44092,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhic\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[6G\u001b[?25l"] -[1.460401,"i","h"] -[1.461423,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[7G\u001b[?25l"] -[1.480802,"i"," "] -[1.481784,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[8G\u001b[?25l"] -[1.501065,"i","c"] -[1.502198,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich c\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.502235,"o","\u001b[9G\u001b[?25l"] -[1.521563,"i","o"] -[1.52279,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich co\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[10G\u001b[?25l"] -[1.541063,"i","d"] -[1.542318,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich cod\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[11G"] -[1.542359,"o","\u001b[?25l"] -[1.561681,"i","i"] -[1.562789,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich codi\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[12G\u001b[?25l"] -[1.581083,"i","n"] -[1.582125,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich codin\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[13G\u001b[?25l"] -[1.601461,"i","g"] -[1.602574,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[14G\u001b[?25l"] -[1.621915,"i"," "] -[1.623102,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[15G\u001b[?25l"] -[1.642439,"i","a"] -[1.643904,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding a\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[16G\u001b[?25l"] -[1.662342,"i","g"] -[1.663667,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding ag\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[17G\u001b[?25l"] -[1.682028,"i","e"] -[1.683271,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding age\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[18G\u001b[?25l"] -[1.702885,"i","n"] -[1.704166,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agen\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[19G\u001b[?25l"] -[1.723488,"i","t"] -[1.724708,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.724746,"o","\u001b[20G\u001b[?25l"] -[1.743048,"i"," "] -[1.744244,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.74428,"o","\u001b[21G\u001b[?25l"] -[1.763575,"i","w"] -[1.76478,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent w\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.76482,"o","\u001b[22G\u001b[?25l"] -[1.783122,"i","i"] -[1.784374,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent wi\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[23G"] -[1.784406,"o","\u001b[?25l"] -[1.803709,"i","l"] -[1.804928,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent wil\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.804963,"o","\u001b[24G\u001b[?25l"] -[1.823275,"i","l"] -[1.824366,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[25G"] -[1.824402,"o","\u001b[?25l"] -[1.843725,"i"," "] -[1.844852,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[26G\u001b[?25l"] -[1.863225,"i","h"] -[1.864288,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will h\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.864327,"o","\u001b[27G\u001b[?25l"] -[1.88365,"i","a"] -[1.884721,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will ha\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.884761,"o","\u001b[28G\u001b[?25l"] -[1.903134,"i","n"] -[1.904115,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will han\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.904153,"o","\u001b[29G\u001b[?25l"] -[1.923459,"i","d"] -[1.924488,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will hand\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.924528,"o","\u001b[30G\u001b[?25l"] -[1.943046,"i","l"] -[1.944298,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handl\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[31G\u001b[?25l"] -[1.963638,"i","e"] -[1.964927,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[32G"] -[1.964963,"o","\u001b[?25l"] -[1.983286,"i"," "] -[1.984511,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[33G\u001b[?25l"] -[2.003872,"i","m"] -[2.005113,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.005163,"o","\u001b[34G\u001b[?25l"] -[2.024507,"i","y"] -[2.025575,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[35G"] -[2.025611,"o","\u001b[?25l"] -[2.04401,"i"," "] -[2.045016,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[36G\u001b[?25l"] -[2.064357,"i","n"] -[2.065583,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my n\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.065621,"o","\u001b[37G\u001b[?25l"] -[2.084923,"i","e"] -[2.086192,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my ne\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.086239,"o","\u001b[38G\u001b[?25l"] -[2.105588,"i","x"] -[2.106847,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my nex\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[39G\u001b[?25l"] -[2.12522,"i","t"] -[2.126289,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[40G\u001b[?25l"] -[2.145676,"i"," "] -[2.146818,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.146864,"o","\u001b[41G\u001b[?25l"] -[2.165176,"i","t"] -[2.166128,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next t\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[42G\u001b[?25l"] -[2.185428,"i","a"] -[2.186372,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next ta\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[43G\u001b[?25l"] -[2.205675,"i","s"] -[2.206701,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next tas\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[44G"] -[2.206738,"o","\u001b[?25l"] -[2.225094,"i","k"] -[2.226305,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.226342,"o","\u001b[45G\u001b[?25l"] -[2.245815,"i",","] -[2.246847,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task,\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[46G\u001b[?25l"] -[2.266163,"i"," "] -[2.267361,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.267419,"o","\u001b[47G\u001b[?25l"] -[2.286751,"i","a"] -[2.287793,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, a\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[48G"] -[2.287946,"o","\u001b[?25l"] -[2.307167,"i","n"] -[2.308411,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, an\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.308455,"o","\u001b[49G\u001b[?25l"] -[2.327785,"i","d"] -[2.328864,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.328904,"o","\u001b[50G\u001b[?25l"] -[2.348214,"i"," "] -[2.349631,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.349789,"o","\u001b[51G\u001b[?25l"] -[2.368077,"i","w"] -[2.369302,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and w\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.369343,"o","\u001b[52G\u001b[?25l"] -[2.388666,"i","h"] -[2.389907,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and wh\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[53G\u001b[?25l"] -[2.408242,"i","e"] -[2.409389,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and whe\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[54G\u001b[?25l"] -[2.428726,"i","r"] -[2.429774,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and wher\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.429806,"o","\u001b[55G\u001b[?25l"] -[2.448065,"i","e"] -[2.449127,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.449167,"o","\u001b[56G\u001b[?25l"] -[2.468454,"i"," "] -[2.46945,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[57G"] -[2.469486,"o","\u001b[?25l"] -[2.488889,"i","w"] -[2.489859,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where w\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[58G"] -[2.489897,"o","\u001b[?25l"] -[2.509482,"i","i"] -[2.510555,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where wi\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[59G\u001b[?25l"] -[2.529925,"i","l"] -[2.531365,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where wil\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[60G\u001b[?25l"] -[2.550706,"i","l"] -[2.551794,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[61G\u001b[?25l"] -[2.570097,"i"," "] -[2.571145,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[62G"] -[2.571178,"o","\u001b[?25l"] -[2.590443,"i","i"] -[2.591426,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will i\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[63G"] -[2.591461,"o","\u001b[?25l"] -[2.610784,"i","t"] -[2.612078,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will it\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[64G\u001b[?25l"] -[2.631481,"i"," "] -[2.632599,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will it \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[65G\u001b[?25l"] -[2.650983,"i","r"] -[2.652069,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will it r\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[66G"] -[2.652113,"o","\u001b[?25l"] -[2.671508,"i","u"] -[2.672531,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will it ru\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[67G\u001b[?25l"] -[2.691845,"i","n"] -[2.692781,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will it run\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.692819,"o","\u001b[68G\u001b[?25l"] -[2.712084,"i","?"] -[2.713761,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mWhich coding agent will handle my next task, and where will it run?\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[69G\u001b[?25l"] -[2.73204,"i","\r"] -[2.733371,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[2G\u001b[?25l"] -[2.761756,"o","\u001b[?2026h\u001b[14A\r\u001b[2K \u001b[38;5;111m› \u001b[39mWhich coding agent will handle my next task, and where will it run? \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Release engineer\u001b[39m · \u001b[38;5;195mpi / openai-codex/gpt-5.6-luna\u001b[39m · \u001b[38;5;195mLocal CLI Bridge\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[12G\u001b[?25l"] -[2.772195,"i","\u001bOQ"] -[2.77715,"o","\u001b[?2026h\u001b[14A\r\u001b[2K \u001b[38;5;111m› \u001b[39mWhich coding agent will handle my next task, and where will it run? \u001b[38;5;145m│\u001b[39m \u001b[1m\u001b[38;5;153mlive work\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[38;5;145m│\u001b[39m \u001b[38;5;222m> running\u001b[39m run run-000001 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[38;5;222m> running\u001b[39m admitted · pr\u001b[0m...\u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[38;5;222m> running\u001b[39m event backend\u001b[0m...\u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[1B\u001b[12G\u001b[?25l"] -[8.188954,"o","\u001b[?2026h\u001b[12A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[38;5;145m│\u001b[39m \u001b[38;5;145mNo live work.\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Pi will run the task through Local CLI Bridge with gpt-5.6-luna. The Release engineer \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K AgentProfile supplies its instructions and permissions. Braid keeps the transcript, \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K approvals, branches, and trace analysis. \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Release engineer\u001b[39m · \u001b[38;5;195mpi / openai-codex/gpt-5.6-luna\u001b[39m · \u001b[38;5;195mLocal CLI Bridge\u001b[39m · \u001b[38;5;195mhigh\u001b[39m \u001b[38;5;195min 1.3k\u001b[39m · \u001b[38;5;195mout 96\u001b[39m · \u001b[38;5;195m~$0.0026\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G\u001b[?25l"] -[8.209899,"i","\u001bOQ"] -[8.218787,"o","\u001b[?2026h\u001b[14A\r\u001b[2K \u001b[38;5;111m› \u001b[39mWhich coding agent will handle my next task, and where will it run? \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Pi will run the task through Local CLI Bridge with gpt-5.6-luna. The Release engineer AgentProfile supplies its \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K instructions and permissions. Braid keeps the transcript, approvals, branches, and trace analysis. \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[1B\u001b[2G\u001b[?25l"] -[9.21187,"i","/"] -[9.213679,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3G"] -[9.213713,"o","\u001b[?25l"] -[9.229516,"o","\u001b[?2026h\u001b[7A\r\u001b[2K\u001b[38;5;111m›\u001b[39m/\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m──────────────────────────────────────────────\u001b[39m\u001b[38;5;111m alt+enter newline · paste \u001b[39m\u001b[38;5;145m───────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[1m\u001b[38;5;111m→ new Create an empty conversation\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K open\u001b[38;5;145m Search and open conversations\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K profile\u001b[38;5;145m Inspect, select, import, or edit a profile\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K connection\u001b[38;5;145m Inspect, create, test, select, or remove a connection\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K runner\u001b[38;5;145m unavailable — Runner overrides require the current profile compatibility helpers\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m (1/29)\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[9A\u001b[3G\u001b[?25l"] -[9.242926,"i","a"] -[9.244557,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/a\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4G"] -[9.244608,"o","\u001b[?25l"] -[9.260491,"o","\u001b[?2026h\u001b[4B\r\u001b[2K \u001b[1m\u001b[38;5;111m→ ask Analyze a frozen run with citations\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K analyze\u001b[38;5;145m Run a named trace-analysis recipe\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K approve\u001b[38;5;145m unavailable — Interaction response is not exposed by the current runtime adapter\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K automate\u001b[38;5;145m unavailable — Interaction automation requires the shared response contract\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K activity\u001b[38;5;145m Open run, tool, worker, and usage activity\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m (1/10)\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[9A\u001b[4G\u001b[?25l"] -[9.273862,"i","c"] -[9.275417,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ac\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[5G\u001b[?25l"] -[9.291342,"o","\u001b[?2026h\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m/ac\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m──────────────────────────────────────────────\u001b[39m\u001b[38;5;111m alt+enter newline · paste \u001b[39m\u001b[38;5;145m───────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[1m\u001b[38;5;111m→ activity Open run, tool, worker, and usage activity\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K detach\u001b[38;5;145m unavailable — There is no active run\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K cancel\u001b[38;5;145m unavailable — There is no active run to cancel\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K branch\u001b[38;5;145m Create a branch at a message boundary\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[7A\u001b[5G\u001b[?25l"] -[9.304906,"i","t"] -[9.306439,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/act\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[6G\u001b[?25l"] -[9.322113,"o","\u001b[?2026h\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m/act\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m──────────────────────────────────────────────\u001b[39m\u001b[38;5;111m alt+enter newline · paste \u001b[39m\u001b[38;5;145m───────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[1m\u001b[38;5;111m→ activity Open run, tool, worker, and usage activity\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[6G\u001b[?25l"] -[9.33542,"i","i"] -[9.336863,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/acti\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[9.337011,"o","\u001b[7G\u001b[?25l"] -[9.352719,"o","\u001b[7G\u001b[?25l"] -[9.365113,"i","v"] -[9.366414,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/activ\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[8G\u001b[?25l"] -[9.382407,"o","\u001b[8G\u001b[?25l"] -[9.395739,"i","i"] -[9.396991,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/activi\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[9G\u001b[?25l"] -[9.412613,"o","\u001b[9G\u001b[?25l"] -[9.425877,"i","t"] -[9.427217,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/activit\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[10G"] -[9.42725,"o","\u001b[?25l"] -[9.442787,"o","\u001b[10G\u001b[?25l"] -[9.456011,"i","y"] -[9.457222,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/activity\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[11G"] -[9.45725,"o","\u001b[?25l"] -[9.473271,"o","\u001b[11G\u001b[?25l"] -[9.486542,"i","\r"] -[9.488313,"o","\u001b[?2026h\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[9.488343,"o","\u001b[2A\u001b[2G\u001b[?25l"] -[9.492447,"o","\u001b[?25l"] -[9.506727,"o","\u001b[?2026h\u001b[14A\r\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[1m\u001b[38;5;153mactivity\u001b[39m\u001b[22m \u001b[38;5;145m›\u001b[39m \u001b[38;5;111martifact\u001b[39m \u001b[38;5;145m· completed · 1/4\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007\u001b[38;5;145m────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;111m›\u001b[39m \u001b[38;5;115m✓\u001b[39m \u001b[38;5;111martifact\u001b[39m\u001b[38;5;145m · system\u001b[39m \u001b[38;5;145m│\u001b[39m time: 2026-08-12T12:38:04.554Z \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;115m✓\u001b[39m \u001b[38;5;195mevent backend_start\u001b[39m\u001b[38;5;145m · system · seq\u001b[0m…\u001b[0m\u001b[38;5;145m│\u001b[39m run: run-000001 \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;115m✓\u001b[39m \u001b[38;5;195madmitted\u001b[39m\u001b[38;5;145m · system · profile b6e862\u001b[0m…\u001b[0m\u001b[38;5;145m│\u001b[39m source event: run-000001:runtime:3 \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;115m✓\u001b[39m \u001b[38;5;195mrun run-000001\u001b[39m\u001b[38;5;145m · run\u001b[39m \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m│\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007\u001b[38;5;145m────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m↑↓ select · PgUp/PgDn detail · home/end jump · ←/esc close · tab filter: all\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[?25l"] -[10.386924,"i","\u001b"] -[10.400874,"o","\u001b[?25l"] -[10.403566,"o","\u001b[?2026h\u001b[17A\r\u001b[2K \u001b[38;5;111m› \u001b[39mWhich coding agent will handle my next task, and where will it run? \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Pi will run the task through Local CLI Bridge with gpt-5.6-luna. The Release engineer AgentProfile supplies its \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K instructions and permissions. Braid keeps the transcript, approvals, branches, and trace analysis. \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Release engineer\u001b[39m · \u001b[38;5;195mpi / openai-codex/gpt-5.6-luna\u001b[39m · \u001b[38;5;195mLocal CLI Bridge\u001b[39m · \u001b[38;5;195mhigh\u001b[39m \u001b[38;5;195min 1.3k\u001b[39m · \u001b[38;5;195mout 96\u001b[39m · \u001b[38;5;195m~$0.0026\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G\u001b[?25l"] -[10.737947,"i","/"] -[10.739269,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3G\u001b[?25l"] -[10.754872,"o","\u001b[?2026h\u001b[7A\r\u001b[2K\u001b[38;5;111m›\u001b[39m/\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m──────────────────────────────────────────────\u001b[39m\u001b[38;5;111m alt+enter newline · paste \u001b[39m\u001b[38;5;145m───────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[1m\u001b[38;5;111m→ new Create an empty conversation\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K open\u001b[38;5;145m Search and open conversations\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K profile\u001b[38;5;145m Inspect, select, import, or edit a profile\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K connection\u001b[38;5;145m Inspect, create, test, select, or remove a connection\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K runner\u001b[38;5;145m unavailable — Runner overrides require the current profile compatibility helpers\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m (1/29)\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[9A\u001b[3G\u001b[?25l"] -[10.756006,"i","a"] -[10.756824,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/a\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4G"] -[10.756847,"o","\u001b[?25l"] -[10.773767,"o","\u001b[?2026h\u001b[4B\r\u001b[2K \u001b[1m\u001b[38;5;111m→ ask Analyze a frozen run with citations\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K analyze\u001b[38;5;145m Run a named trace-analysis recipe\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K approve\u001b[38;5;145m unavailable — Interaction response is not exposed by the current runtime adapter\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K automate\u001b[38;5;145m unavailable — Interaction automation requires the shared response contract\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K activity\u001b[38;5;145m Open run, tool, worker, and usage activity\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m (1/10)\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[9A\u001b[4G\u001b[?25l"] -[10.773853,"i","s"] -[10.775146,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/as\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[5G"] -[10.775173,"o","\u001b[?25l"] -[10.790235,"o","\u001b[?2026h\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m/as\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m──────────────────────────────────────────────\u001b[39m\u001b[38;5;111m alt+enter newline · paste \u001b[39m\u001b[38;5;145m───────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[1m\u001b[38;5;111m→ ask Analyze a frozen run with citations\u001b[39m\u001b[22m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[5G\u001b[?25l"] -[10.792545,"i","k"] -[10.793735,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[10.793753,"o","\u001b[6G\u001b[?25l"] -[10.809502,"o","\u001b[6G\u001b[?25l"] -[10.810632,"i"," "] -[10.811588,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[7G\u001b[?25l"] -[10.82723,"o","\u001b[?2026h\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m/ask \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[2A\u001b[7G\u001b[?25l"] -[10.828422,"i","W"] -[10.829204,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask W\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[8G"] -[10.829227,"o","\u001b[?25l"] -[10.845726,"o","\u001b[8G\u001b[?25l"] -[10.84686,"i","h"] -[10.847715,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask Wh\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[10.847737,"o","\u001b[9G\u001b[?25l"] -[10.86329,"o","\u001b[9G\u001b[?25l"] -[10.865554,"i","a"] -[10.866634,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask Wha\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[10G\u001b[?25l"] -[10.882212,"o","\u001b[10G\u001b[?25l"] -[10.883367,"i","t"] -[10.884367,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[10.884384,"o","\u001b[11G\u001b[?25l"] -[10.900179,"o","\u001b[11G\u001b[?25l"] -[10.901365,"i"," "] -[10.902434,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[10.902459,"o","\u001b[12G\u001b[?25l"] -[10.919714,"i","s"] -[10.921148,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What s\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[10.921184,"o","\u001b[13G\u001b[?25l"] -[10.936695,"o","\u001b[13G\u001b[?25l"] -[10.937847,"i","h"] -[10.938657,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What sh\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[10.938669,"o","\u001b[14G\u001b[?25l"] -[10.955371,"o","\u001b[14G"] -[10.955428,"o","\u001b[?25l"] -[10.956508,"i","o"] -[10.957597,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What sho\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[10.957605,"o","\u001b[15G\u001b[?25l"] -[10.973259,"o","\u001b[15G\u001b[?25l"] -[10.974413,"i","u"] -[10.975309,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What shou\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[16G"] -[10.975326,"o","\u001b[?25l"] -[10.99106,"o","\u001b[16G"] -[10.991093,"o","\u001b[?25l"] -[10.992175,"i","l"] -[10.99306,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What shoul\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[10.993076,"o","\u001b[17G\u001b[?25l"] -[11.009817,"o","\u001b[17G\u001b[?25l"] -[11.009918,"i","d"] -[11.010834,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[18G\u001b[?25l"] -[11.027361,"o","\u001b[18G\u001b[?25l"] -[11.028492,"i"," "] -[11.029308,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[19G\u001b[?25l"] -[11.046835,"i","t"] -[11.048416,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should t\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[20G\u001b[?25l"] -[11.064089,"o","\u001b[20G\u001b[?25l"] -[11.065215,"i","h"] -[11.066237,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should th\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[11.066267,"o","\u001b[21G\u001b[?25l"] -[11.080912,"o","\u001b[21G\u001b[?25l"] -[11.083166,"i","i"] -[11.084367,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should thi\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[22G\u001b[?25l"] -[11.100278,"o","\u001b[22G\u001b[?25l"] -[11.101429,"i","s"] -[11.102474,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[11.102491,"o","\u001b[23G\u001b[?25l"] -[11.118838,"o","\u001b[23G\u001b[?25l"] -[11.118915,"i"," "] -[11.119835,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[24G"] -[11.119958,"o","\u001b[?25l"] -[11.137341,"i","a"] -[11.138669,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this a\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[25G\u001b[?25l"] -[11.15385,"o","\u001b[25G\u001b[?25l"] -[11.154984,"i","g"] -[11.156133,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this ag\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[11.156179,"o","\u001b[26G"] -[11.156187,"o","\u001b[?25l"] -[11.17156,"o","\u001b[26G\u001b[?25l"] -[11.173836,"i","e"] -[11.174713,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this age\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[11.174741,"o","\u001b[27G\u001b[?25l"] -[11.191166,"o","\u001b[27G\u001b[?25l"] -[11.192291,"i","n"] -[11.192983,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agen\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[28G"] -[11.192992,"o","\u001b[?25l"] -[11.209278,"o","\u001b[28G\u001b[?25l"] -[11.210397,"i","t"] -[11.211125,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[29G"] -[11.211143,"o","\u001b[?25l"] -[11.227603,"o","\u001b[29G\u001b[?25l"] -[11.228732,"i"," "] -[11.229482,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[11.229497,"o","\u001b[30G\u001b[?25l"] -[11.246775,"i","i"] -[11.247992,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent i\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[11.248023,"o","\u001b[31G\u001b[?25l"] -[11.263554,"o","\u001b[31G\u001b[?25l"] -[11.265817,"i","m"] -[11.266901,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent im\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[32G\u001b[?25l"] -[11.282489,"o","\u001b[32G\u001b[?25l"] -[11.283847,"i","p"] -[11.284559,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent imp\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[33G\u001b[?25l"] -[11.301185,"o","\u001b[33G\u001b[?25l"] -[11.302303,"i","r"] -[11.303038,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent impr\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[11.303046,"o","\u001b[34G\u001b[?25l"] -[11.319547,"o","\u001b[34G\u001b[?25l"] -[11.320666,"i","o"] -[11.321999,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent impro\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[35G\u001b[?25l"] -[11.337531,"o","\u001b[35G\u001b[?25l"] -[11.338637,"i","v"] -[11.340119,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent improv\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[11.340157,"o","\u001b[36G"] -[11.340171,"o","\u001b[?25l"] -[11.356342,"o","\u001b[36G\u001b[?25l"] -[11.356427,"i","e"] -[11.357511,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent improve\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[37G\u001b[?25l"] -[11.373499,"o","\u001b[37G\u001b[?25l"] -[11.374654,"i"," "] -[11.37582,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent improve \u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[38G"] -[11.375883,"o","\u001b[?25l"] -[11.392078,"i","n"] -[11.39348,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent improve n\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[39G\u001b[?25l"] -[11.409252,"o","\u001b[39G\u001b[?25l"] -[11.410409,"i","e"] -[11.411455,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent improve ne\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[40G\u001b[?25l"] -[11.427174,"o","\u001b[40G\u001b[?25l"] -[11.428329,"i","x"] -[11.429291,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent improve nex\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[41G\u001b[?25l"] -[11.44387,"o","\u001b[41G\u001b[?25l"] -[11.446185,"i","t"] -[11.447412,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent improve next\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[42G\u001b[?25l"] -[11.463246,"o","\u001b[42G\u001b[?25l"] -[11.464372,"i","?"] -[11.469172,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m/ask What should this agent improve next?\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[43G\u001b[?25l"] -[11.482497,"i","\r"] -[11.484067,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[2G\u001b[?25l"] -[11.485477,"o","\u001b[?25l"] -[11.489179,"o","\u001b[?25l"] -[11.489215,"o","\u001b[?25l"] -[11.502167,"o","\u001b[?2026h\u001b[14A\r\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[1m\u001b[38;5;153mactivity · analyses\u001b[39m\u001b[22m \u001b[38;5;145m›\u001b[39m \u001b[38;5;111m/ask · frozen question\u001b[39m \u001b[38;5;145m· complete · 1/1\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007\u001b[38;5;145m────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145msource run run-000001 · Release engineer · pi · openai-codex/gpt-5.6-luna · Local CLI Bridge\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 source: a9ed803bccc9148…26b84d74 · frozen \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 analyst: profile-trace-reviewer · completed \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;111m── question\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 What should this agent improve next? \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;111m── findings\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 1. [1] The route was explicit, but the final answer did not cite its materialization receipt. · medium · confidence \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 0.93 \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m↳ [1] runtime.route completed: Local CLI Bridge → Pi · event event-runtime-route\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 2. [2] Profile inspection and route resolution ran serially even though their inputs were independent. · low · \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 confidence 0.86 \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145m↳ [2] profile.inspect completed before runtime.route started · event event-profile-b…re-route\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;111m── next\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 next: ask a narrower question, or use /compare against another frozen run \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007\u001b[38;5;145m────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[0m\u001b]8;;\u0007 \u001b[38;5;145mPgUp/PgDn detail · ←/esc close · page 1/2 · tab filter: analyses\u001b[39m \u001b[0m\u001b]8;;\u0007\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[?25l"] -[11.512167,"o","\u001b[0m"] diff --git a/artifacts/verification/w6/raw/transcript-keyboard.cast b/artifacts/verification/w6/raw/transcript-keyboard.cast index 733c485..711fdb5 100644 --- a/artifacts/verification/w6/raw/transcript-keyboard.cast +++ b/artifacts/verification/w6/raw/transcript-keyboard.cast @@ -1,84 +1,69 @@ -{"version":2,"width":80,"height":24,"timestamp":1786538293,"duration":2.028706,"idle_time_limit":1,"command":"packed braid --fixture deterministic","title":"Braid transcript keyboard navigation","env":{"TERM":"xterm-256color"},"stdin":true} -[0.455262,"o","\u001b[?2004h"] -[0.455437,"o","\u001b[>7u\u001b[?u\u001b[c"] -[0.45545,"o","\u001b[?1049h"] -[0.455461,"o","\u001b[2J\u001b[H"] -[0.455476,"o","\u001b[?25l"] -[0.466018,"o","\u001b[?2026h\u001b[2J\u001b[H\u001b[3J \u001b[0m\u001b]8;;\u0007\r\r\n Ask Braid starter anything. \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[38;5;111m›\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m · \u001b[38;5;195mno connection\u001b[39m \u001b[38;5;115mready\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[0.46606,"o","\u001b[3A\u001b[2G\u001b[?25l"] -[0.505436,"o","\u001b]0;Braid — /home/drew/code/braid-transcript-first-wt\u0007"] -[0.508782,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[38;5;145mAsk Braid starter anything.\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n"] -[0.508801,"o","\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+P commands\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[0.508807,"o","\u001b[3A\u001b[2G"] -[0.508812,"o","\u001b[?25l"] -[0.523264,"i","keyboard-flow-01"] -[0.523342,"i","\r"] -[0.538154,"o","\u001b[2G\u001b[?25l"] -[0.566513,"o","\u001b[?2026h\u001b[20A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[12G\u001b[?25l"] -[0.634528,"o","\u001b[?2026h\u001b[18A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E detail\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G\u001b[?25l"] -[0.724794,"i","keyboard-flow-02"] -[0.724876,"i","\r"] -[0.729119,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mkeyboard-flow-02\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[18G\u001b[?25l"] -[0.730757,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[0.730777,"o","\u001b[2G\u001b[?25l"] -[0.746311,"o","\u001b[?2026h\u001b[16A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[12G"] -[0.746365,"o","\u001b[?25l"] -[0.804871,"o","\u001b[?2026h\u001b[18A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/2\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/2\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E next detail (2/2)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G"] -[0.80497,"o","\u001b[?25l"] -[0.885845,"i","keyboard-flow-03"] -[0.88592,"i","\r"] -[0.887814,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mkeyboard-flow-03\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[0.887852,"o","\u001b[18G\u001b[?25l"] -[0.889393,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[0.889414,"o","\u001b[2G\u001b[?25l"] -[0.906086,"o","\u001b[?2026h\u001b[12A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[0.906118,"o","\u001b[3A\u001b[12G\u001b[?25l"] -[0.963025,"o","\u001b[?2026h\u001b[18A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/3\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/3\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/3\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E next detail (3/3)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G\u001b[?25l"] -[1.045937,"i","keyboard-flow-04"] -[1.046011,"i","\r"] -[1.047766,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mkeyboard-flow-04\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[18G\u001b[?25l"] -[1.050081,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[2G"] -[1.050115,"o","\u001b[?25l"] -[1.067575,"o","\u001b[?2026h\u001b[8A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[12G\u001b[?25l"] -[1.132689,"o","\u001b[?2026h\u001b[18A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E next detail (4/4)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G\u001b[?25l"] -[1.227601,"i","keyboard-flow-05"] -[1.227671,"i","\r"] -[1.229798,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mkeyboard-flow-05\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[18G\u001b[?25l"] -[1.231758,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.231789,"o","\u001b[2G\u001b[?25l"] -[1.249551,"o","\u001b[?2026h\u001b[4A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[12G\u001b[?25l"] -[1.313758,"o","\u001b[?2026h\u001b[18A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E next detail (5/5)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.313801,"o","\u001b[3A\u001b[2G\u001b[?25l"] -[1.389686,"i","keyboard-flow-06"] -[1.389776,"i","\r"] -[1.39166,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mkeyboard-flow-06\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[18G\u001b[?25l"] -[1.393519,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[2G"] -[1.393542,"o","\u001b[?25l"] -[1.412422,"o","\u001b[?2026h\u001b[20A\r\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[12G"] -[1.412462,"o","\u001b[?25l"] -[1.483081,"o","\u001b[?2026h\u001b[20A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E next detail (6/6)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G\u001b[?25l"] -[1.57018,"i","keyboard-flow-07"] -[1.570255,"i","\r"] -[1.574224,"o","\u001b[2G\u001b[?25l"] -[1.592731,"o","\u001b[?2026h\u001b[20A\r\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.592771,"o","\u001b[3A\u001b[12G\u001b[?25l"] -[1.658569,"o","\u001b[?2026h\u001b[20A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 7/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E next detail (7/7)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.658659,"o","\u001b[3A\u001b[2G\u001b[?25l"] -[1.752568,"i","keyboard-flow-08"] -[1.752641,"i","\r"] -[1.755149,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39mkeyboard-flow-08\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[18G"] -[1.755192,"o","\u001b[?25l"] -[1.75801,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.758024,"o","\u001b[2G\u001b[?25l"] -[1.778488,"o","\u001b[?2026h\u001b[20A\r\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 7/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m \u001b[38;5;222mworking · Ctrl+C cancel\u001b[39m · \u001b[38;5;195mEnter queues\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[12G"] -[1.778526,"o","\u001b[?25l"] -[1.845392,"o","\u001b[?2026h\u001b[20A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 7/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 8/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E next detail (8/8)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G\u001b[?25l"] -[1.934374,"i","\u001b[5~"] -[1.934451,"i","\u001b[1;3H"] -[1.937925,"o","\u001b[?2026h\u001b[20A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mPgUp/PgDn history · End follow\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[1.937964,"o","\u001b[3A\u001b[2G\u001b[?25l"] -[2.015744,"i","\u001b[6~"] -[2.015826,"i","\u001b[1;3F"] -[2.018668,"o","\u001b[?2026h\u001b[20A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 7/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 8/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m›\u001b[39m\u001b[7m \u001b[0m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi / deterministic\u001b[39m \u001b[38;5;195mCtrl+E next detail (8/8)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] -[2.018706,"o","\u001b[3A\u001b[2G\u001b[?25l"] -[2.028706,"o","\u001b[0m"] +{"version":2,"width":80,"height":24,"timestamp":1786878348,"duration":2.631937,"idle_time_limit":1,"command":"packed braid --fixture deterministic","title":"Braid transcript keyboard navigation","env":{"TERM":"xterm-256color"},"stdin":true} +[0.779238,"o","\u001b[?2004h"] +[0.779647,"o","\u001b[>7u\u001b[?u\u001b[c\u001b[?1049h"] +[0.779711,"o","\u001b[2J\u001b[H\u001b[?25l"] +[0.805016,"o","\u001b[?2026h\u001b[2J\u001b[H\u001b[3J \u001b[0m\u001b]8;;\u0007\r\r\n Ask Braid starter anything. \u001b[0m\u001b]8;;\u0007\r\r\n \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[38;5;111m›\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia no connection\u001b[39m \u001b[38;5;115mready\u001b[39m · \u001b[38;5;195mCtrl+P commands\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[3A\u001b[2G\u001b[?25l"] +[0.841268,"o","\u001b]0;Braid — /home/drew/code/.worktrees/braid-exact-interactive-20260816\u0007"] +[0.846892,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145mAsk Braid starter anything.\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] +[0.846976,"o","\u001b[4A\u001b[15G\u001b[?25l"] +[0.853664,"i","keyboard-flow-01"] +[0.853764,"i","\r"] +[0.864663,"o","\u001b[15G\u001b[?25l"] +[0.912563,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia not connected\u001b[39m \u001b[38;5;222mCtrl+C cancel\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[12G"] +[0.913158,"o","\u001b[?25l"] +[0.990246,"o","\u001b[?2026h\u001b[17A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E details\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G\u001b[?25l"] +[1.074997,"i","keyboard-flow-02"] +[1.075095,"i","\r"] +[1.08568,"o","\u001b[15G\u001b[?25l"] +[1.116653,"o","\u001b[?2026h\u001b[15A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia not connected\u001b[39m \u001b[38;5;222mCtrl+C cancel\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[12G\u001b[?25l"] +[1.186529,"o","\u001b[?2026h\u001b[17A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/2\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/2\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E next detail (2/2)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G\u001b[?25l"] +[1.278784,"i","keyboard-flow-03"] +[1.279088,"i","\r"] +[1.283155,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;222m› new message\u001b[39m keyboard-flow-03\u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] +[1.284806,"o","\u001b[31G\u001b[?25l"] +[1.290344,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[15G\u001b[?25l"] +[1.326542,"o","\u001b[?2026h\u001b[11A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia not connected\u001b[39m \u001b[38;5;222mCtrl+C cancel\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[12G"] +[1.326745,"o","\u001b[?25l"] +[1.395938,"o","\u001b[?2026h\u001b[17A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/3\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/3\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/3\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E next detail (3/3)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] +[1.39603,"o","\u001b[4A\u001b[15G\u001b[?25l"] +[1.481215,"i","keyboard-flow-04"] +[1.481325,"i","\r"] +[1.484212,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;222m› new message\u001b[39m keyboard-flow-04\u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[31G\u001b[?25l"] +[1.489147,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[15G\u001b[?25l"] +[1.51367,"o","\u001b[?2026h\u001b[7A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia not connected\u001b[39m \u001b[38;5;222mCtrl+C cancel\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[12G\u001b[?25l"] +[1.59326,"o","\u001b[?2026h\u001b[17A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E next detail (4/4)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G\u001b[?25l"] +[1.683457,"i","keyboard-flow-05"] +[1.683559,"i","\r"] +[1.69227,"o","\u001b[15G"] +[1.694221,"o","\u001b[?25l"] +[1.723277,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/4\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia not connected\u001b[39m \u001b[38;5;222mCtrl+C cancel\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[12G\u001b[?25l"] +[1.800552,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E next detail (5/5)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G\u001b[?25l"] +[1.887207,"i","keyboard-flow-06"] +[1.887289,"i","\r"] +[1.89272,"o","\u001b[15G"] +[1.892877,"o","\u001b[?25l"] +[1.924811,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/5\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia not connected\u001b[39m \u001b[38;5;222mCtrl+C cancel\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] +[1.924903,"o","\u001b[4A\u001b[12G\u001b[?25l"] +[2.001345,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E next detail (6/6)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G"] +[2.001482,"o","\u001b[?25l"] +[2.0916,"i","keyboard-flow-07"] +[2.091707,"i","\r"] +[2.100213,"o","\u001b[15G\u001b[?25l"] +[2.154593,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/6\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia not connected\u001b[39m \u001b[38;5;222mCtrl+C cancel\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l"] +[2.154683,"o","\u001b[4A\u001b[12G\u001b[?25l"] +[2.234007,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 7/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E next detail (7/7)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G"] +[2.234226,"o","\u001b[?25l"] +[2.313262,"i","keyboard-flow-08"] +[2.31335,"i","\r"] +[2.31697,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;222m› new message\u001b[39m keyboard-flow-08\u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[31G\u001b[?25l"] +[2.327532,"o","\u001b[?2026h\r\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[15G\u001b[?25l"] +[2.365431,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 7/7\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;222mworking…\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› queue #1\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia not connected\u001b[39m \u001b[38;5;222mCtrl+C cancel\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[12G\u001b[?25l"] +[2.447763,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 7/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 8/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E next detail (8/8)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G\u001b[?25l"] +[2.537801,"i","\u001b[5~"] +[2.537897,"i","\u001b[1;3H"] +[2.541028,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 1/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-01 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 2/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-02 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 3/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-03 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mPgUp/PgDn history · End follow\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G"] +[2.541104,"o","\u001b[?25l"] +[2.617302,"i","\u001b[6~"] +[2.617398,"i","\u001b[1;3F"] +[2.621937,"o","\u001b[?2026h\u001b[19A\r\u001b[2K \u001b[38;5;145m· run result\u001b[39m 4/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-04 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 5/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-05 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 6/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-06 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 7/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-07 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;111m› \u001b[39mkeyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[38;5;145m· run result\u001b[39m 8/8\u001b[38;5;145m · Ctrl+E details\u001b[39m \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K Fixture response through pi: keyboard-flow-08 \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;111m────────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;222m› new message\u001b[39m \u001b[7m \u001b[0m \u001b[0m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K \u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;145m───────────────\u001b[39m\u001b[38;5;111m type / for commands · Alt+Enter newline · paste \u001b[39m\u001b[38;5;145m────────────────\u001b[39m\u001b[0m\u001b]8;;\u0007\r\r\n\u001b[2K\u001b[38;5;195mprofile Braid starter\u001b[39m · \u001b[38;5;195mpi\u001b[39m · \u001b[38;5;195mvia local\u001b[39m \u001b[38;5;195mCtrl+E next detail (8/8)\u001b[39m\u001b[0m\u001b]8;;\u0007\u001b[?2026l\u001b[4A\u001b[15G\u001b[?25l"] +[2.631937,"o","\u001b[0m"] diff --git a/artifacts/verification/w6/states/active-streaming.json b/artifacts/verification/w6/states/active-streaming.json index b5d8deb..ee618f4 100644 --- a/artifacts/verification/w6/states/active-streaming.json +++ b/artifacts/verification/w6/states/active-streaming.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 80, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -30,7 +30,7 @@ }, "capturePhase": "atomic-signal-frame", "captureRevision": 5, - "frame": " › W6 active streaming\n\n working…\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n› queue #1\n\n\nprofile Braid starter working · Ctrl+C cancel · Enter queues\n", + "frame": " › W6 active streaming\n\n working…\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n────────────────────────────────────────────────────────────────────────────────\n› queue #1\n\n\n─────────────── type / for commands · Alt+Enter newline · paste ────────────────\nprofile Braid starter · pi · via not connected Ctrl+C cancel\n", "packedState": { "schemaVersion": 2, "capturePhase": "atomic-signal-frame", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 5, "sequence": 5, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [ { @@ -91,8 +98,12 @@ "turnId": "turn-000002", "operationId": "op-terminal-000002", "status": "streaming", + "startedAt": "2026-08-01T00:00:00.000Z", + "updatedAt": "2026-08-01T00:00:00.000Z", "inputTokens": 0, "outputTokens": 0, + "tokensKnown": false, + "usdKnown": false, "tokenStatus": "unknown", "costStatus": "unknown", "model": "fixture/deterministic", @@ -152,12 +163,13 @@ }, "view": { "revision": 5, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -205,6 +217,8 @@ { "id": "run-000001", "turnId": "turn-000002", + "conversationId": "conv-1", + "branchId": "branch-1", "operationId": "op-terminal-000002", "status": "running", "profileName": "Braid starter", @@ -297,7 +311,7 @@ "title": "event backend_start", "status": "running", "detail": "sequence 1", - "occurredAt": "2026-08-12T12:37:37.459Z", + "occurredAt": "2026-08-16T11:05:23.005Z", "sourceEventId": "run-000001:runtime:1", "runId": "run-000001", "entityType": "run", @@ -321,6 +335,9 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" }, { @@ -330,6 +347,9 @@ "status": "running", "depth": 2, "edgeLabel": "continued", + "parentIds": [ + "branch:branch-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" }, { @@ -339,10 +359,14 @@ "status": "running", "depth": 3, "edgeLabel": "attached", + "parentIds": [ + "turn:turn-000002" + ], "runner": "pi", "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [], "details": { "title": "run run-000001", @@ -359,14 +383,6 @@ "label": "output tokens", "value": "0" }, - { - "label": "token measurement", - "value": "unknown" - }, - { - "label": "cost measurement", - "value": "unknown" - }, { "label": "model", "value": "fixture/deterministic" @@ -387,17 +403,17 @@ "run.runner": { "available": false, "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "reason": "Finish or cancel the active run first" }, "run.model": { "available": false, "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "reason": "Finish or cancel the active run first" }, "run.effort": { "available": false, "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "reason": "Finish or cancel the active run first" }, "conversation.branch": { "available": false, @@ -530,7 +546,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } }, @@ -568,6 +584,7 @@ "revision": 3, "kind": "run.requested", "payload": { + "runId": "run-000001", "text": "W6 active streaming", "admission": { "version": 1, @@ -590,6 +607,7 @@ }, "harness": "pi" }, + "interactions": {}, "model": "fixture/deterministic", "runner": "pi" }, @@ -624,10 +642,10 @@ "provider": "agent-runtime" }, "admissionStatus": "admitted", - "requestDigest": "3c7b454961e6fcf430e049567bd0f429517909faa89f8a05f3446046f7a55e39", + "requestDigest": "bc4e17167150bc55a408399a442e5b4e763ef9838eba4a6a291b2732a1c9e7f3", "capabilitiesDigest": "93c4c21593f9e2fa1fe68ce73da84f48c173f1e13269633678b512a16a81a001", "materializationDigest": "46c7162244a3aa789bd2703e2805a3faa0da1a87d83d97484fa26294a0b00671", - "digest": "e0e2a2c27f92cbb77fc1449a50044630d9b08bfb42f04aaf06f2d8a12a32875f" + "digest": "e4207f4069c98e6debfab39041a4feb28975bf9ebaee947ff8eaff3b5e20c47b" }, "status": "admitted" } @@ -640,10 +658,10 @@ "value": { "kind": "effect.upserted", "effect": { - "id": "effect-op-terminal-000002-0a838249b94207b11007ccae", + "id": "effect-op-terminal-000002-221214e8dc3317bcb681a929", "operationId": "op-terminal-000002", "effectKind": "run.execute", - "requestDigest": "0a838249b94207b11007ccae8a84f3baa7e3b080a7f8fd0a909dbab19fa7e6a1", + "requestDigest": "221214e8dc3317bcb681a929a14c7405e4e06d08e9bbba09c7a20cf138d54c87", "kind": "send", "status": "pending", "attempt": 1, @@ -658,16 +676,17 @@ "revision": 5, "kind": "run.provider.event", "payload": { + "runId": "run-000001", "source": { "eventId": "run-000001:runtime:1", "providerSequence": 1, - "occurredAt": "2026-08-12T12:37:37.459Z", + "occurredAt": "2026-08-16T11:05:23.005Z", "receivedAt": "2026-08-01T00:00:00.000Z" }, "unknown": { "type": "backend_start", "task": { - "id": "turn-db68a0cb-0c7c-4589-8347-fb36879b38e3", + "id": "turn-00c1be56-e524-49c2-9635-c92d7fae52aa", "intent": "W6 active streaming", "metadata": { "identity": { @@ -677,11 +696,11 @@ } }, "session": { - "id": "590229a9-1f09-4c04-ba48-6a314df1a398", + "id": "2e852f40-2813-4ba4-9e23-78f2991e7c5a", "backend": "executor", "status": "active", - "createdAt": "2026-08-12T12:37:37.459Z", - "updatedAt": "2026-08-12T12:37:37.459Z", + "createdAt": "2026-08-16T11:05:23.005Z", + "updatedAt": "2026-08-16T11:05:23.005Z", "metadata": "[unavailable]" }, "backend": "router", @@ -703,16 +722,16 @@ }, "execution": { "kind": "request", - "id": "turn-db68a0cb-0c7c-4589-8347-fb36879b38e3" + "id": "turn-00c1be56-e524-49c2-9635-c92d7fae52aa" }, "materializer": "router-prompt-model" }, "executionBindings": [ { "status": "known", - "attemptId": "turn-db68a0cb-0c7c-4589-8347-fb36879b38e3:attempt:5654b7d0-b218-4427-95c6-361d6dd76cc8", - "materializationReceiptDigest": "sha256:dad1132b1c7dd7c6fe79575ac4fc5da786d05d0b35d84d97698e1d43c21ba925", - "bindingDigest": "sha256:3ec6106218348b41e13fc244f20dbeae88da12fec1825bfb19090e1a343467c1", + "attemptId": "turn-00c1be56-e524-49c2-9635-c92d7fae52aa:attempt:c94a79bb-1272-44ba-ace0-f6fa63c8ad8a", + "materializationReceiptDigest": "sha256:bdae6c111d17379adb467471e373ca52efbafa678fa43bc4cd3bcb66d79cb91b", + "bindingDigest": "sha256:dbfb11afb6d471167ed41e0d48a5a4399546209487e8f350b2f38870c0455b37", "descriptor": { "kind": "router-request", "transport": "http", @@ -724,10 +743,10 @@ "timeoutMs": null }, "timing": { - "startedAt": "2026-08-12T12:37:37.455Z" + "startedAt": "2026-08-16T11:05:23.001Z" } }, - "timestamp": "2026-08-12T12:37:37.459Z" + "timestamp": "2026-08-16T11:05:23.005Z" } } } diff --git a/artifacts/verification/w6/states/active-streaming.png b/artifacts/verification/w6/states/active-streaming.png index e6f36a760dc9168bcf7819fb086718633569593b..cfc8177dd7618800f4be1ad4280c161f23849bdf 100644 GIT binary patch literal 15662 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 ABme*a diff --git a/artifacts/verification/w6/states/active-streaming.txt b/artifacts/verification/w6/states/active-streaming.txt index 5aab693..c72c61a 100644 --- a/artifacts/verification/w6/states/active-streaming.txt +++ b/artifacts/verification/w6/states/active-streaming.txt @@ -16,9 +16,9 @@ - - +──────────────────────────────────────────────────────────────────────────────── › queue #1 -profile Braid starter working · Ctrl+C cancel · Enter queues +─────────────── type / for commands · Alt+Enter newline · paste ──────────────── +profile Braid starter · pi · via not connected Ctrl+C cancel diff --git a/artifacts/verification/w6/states/analysis.json b/artifacts/verification/w6/states/analysis.json index 0b99f85..30455c0 100644 --- a/artifacts/verification/w6/states/analysis.json +++ b/artifacts/verification/w6/states/analysis.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 80, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -30,7 +30,7 @@ }, "capturePhase": "atomic-signal-frame", "captureRevision": 1, - "frame": " activity · analyses › /ask · frozen question · complete · 1/1\n────────────────────────────────────────────────────────────────────────────────\n source: da8ae2345b2c17a…7c9190eb · frozen\n analyst: profile-trace-reviewer · completed\n ── question\n Where did this run waste time, and what should change?\n ── findings\n 1. [1] Profile inspection and route resolution ran serially although their\n inputs were independent. · medium · confidence 0.94\n ↳ [1] profile.inspect completed before runtime.route started · event\n event-runtime-r…te-start\n 2. [2] The answer claimed success before the packaged terminal check completed.\n · high · confidence 0.88\n ↳ [2] package check started; no terminal result was recorded · event\n event-package-c…ck-start\n ── next\n next: ask a narrower question, or use /compare against another\n frozen run\n ── model use\n Model calls were not reported.\n ── run receipt\n source complete: yes\n────────────────────────────────────────────────────────────────────────────────\n ↑↓ previous/next · PgUp/PgDn page · ←/esc back · page 1/2 · tab filter: analys…\n", + "frame": " analyses › /ask · frozen question Braid starter · pi · fixture/deterministic\n────────────────────────────────────────────────────────────────────────────────\n source: da8ae2345b2c17a…7c9190eb · frozen\n analyst: profile-trace-reviewer · completed\n ── question\n Where did this run waste time, and what should change?\n ── findings\n 1. [1] Profile inspection and route resolution ran serially although their\n inputs were independent. · medium · confidence 0.94\n ↳ [1] profile.inspect completed before runtime.route started · event\n event-runtime-r…te-start\n 2. [2] The answer claimed success before the packaged terminal check completed.\n · high · confidence 0.88\n ↳ [2] package check started; no terminal result was recorded · event\n event-package-c…ck-start\n ── next\n next: ask a narrower question, or use /compare against another\n frozen run\n ── run receipt\n source complete: yes\n findings: 2\n analysis cost: $0.0048\n────────────────────────────────────────────────────────────────────────────────\n ↑↓ previous/next · PgUp/PgDn page · ←/esc back · page 1/2 · tab: analyses\n", "packedState": { "schemaVersion": 2, "capturePhase": "atomic-signal-frame", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 1, "sequence": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [], "runs": [], @@ -113,12 +120,13 @@ }, "view": { "revision": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -214,9 +222,13 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [ { "entityType": "analysis", @@ -235,8 +247,6 @@ "↳ [2] package check started; no terminal result was recorded · event event-package-c…ck-start", "── next", "next: ask a narrower question, or use /compare against another frozen run", - "── model use", - "Model calls were not reported.", "── run receipt", "source complete: yes", "findings: 2", @@ -262,19 +272,16 @@ "source": "application" }, "run.runner": { - "available": false, - "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "available": true, + "source": "application" }, "run.model": { - "available": false, - "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "run.effort": { - "available": false, - "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "conversation.branch": { "available": true, @@ -404,7 +411,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } } diff --git a/artifacts/verification/w6/states/analysis.png b/artifacts/verification/w6/states/analysis.png index a8955e175325187599355bc6248a2d5a7e5a75b0..b8fad3a9df1df26157fe465146ce3efe50e4e343 100644 GIT binary patch literal 62918 zcmb@ubyQVvw>FG{AgDA*ODZ5C-RMTTl!i?s-Q6HaNH<7JcXxwycXxMp?fu^V&N<&W z$;}?U!+A|q7a}UARxRH6a6fUfbawt0pT$d@?&r& zO2gO!{CcA+Dl3J6;7pBx@ZB2$;TD|wzKwuj$Ao~etA&8T{R;sB&oZ&@D=&ECnT~|W zX9W1)pWltyk>CuHt(cS$(k?PODk7z#pcVMS?+9X_Kgm1J?k^aqVTlnU96v|rP8EwK zXMgh@ktP|1oLwHBPN#U=3B_QlJh5@A95pRj`ODXRXK}2ZRA1Vkk5RmSqeI@MHjrK} zs)dxzeDnW(b?@Qct?!_p;-qhn@4)d~NTL|&?*b4I{)BDs|8s!QB*5hJ&pC7g$<%*N zc|VhT_s>CUEB0RlAbd3Z-~C9uyaCd1#LOF);)htLKm!lW7|a_b1EdT3*CQe|5Bn|; z-zAK+x#OJW*@CysTyDCrV&~Vhmzr?+-V497QqLY8_!2Rf^ z@Ac!C;Nd~%6<}1K9{NK>HabW7~3NSTWU==764@ zto_vxg>#-^tG`<6{Cx|<{l zV>@nZ-z5x?AiYz?I0;pUrsn2~U%w_Z_t;JJX7XGS73CCc@7H`T)jE_kGb?mM3U$Mq zfQfv07bRrFrykEF6QlBsZg|{^S zK$>hO4^N`S=f0d~chUrC*F3O?EOu07rrw6YdS~l>ZW|)(LwdO&`ePqRZoxM`x642J z!yo0wnnpg963ZTx3JluX_kEODs*#gdh|<&3D_>l%a)`J&d?toQk*>iP9163lDt|&I zv|bUI+uSt6^oGqRB0L;_lY6MMr!pagUqLmCQ{d`kLcsBA0oM%HHfsf0ADc6soYKbP z-8JFlkcJIH12wDo9(;pfPF-9K)$VH*pC(M%A>H=l>xhJ}Z1VEirK)rD^KC4XSiU8? za1cM-5=cAW=f9nD>kG8G4h&6M%ha6?glb-qah%Nrvw*cXR9@?K^xE(Dt~$^NS*$r7 ziHeKI&kQh?C(KF}TL`)x_$B_z@$+kr+0-_v47x?LTgaJN@P=wauc>KITgmK&tPrDAc|9_hX%6Qg&< zBDQxy%5V6N7rIcRNqWOTx?A;0MIA2DGZ*%~km@MXzrx3Xu`KPq0N-v^Thx*{u}xRq zv;50(S}aqEh2+UGCB%77Ui^IgwDGW zZjq6M=gVR{TSEL^%{P*>V4Hu_PRPdxur%o8zPF4 z`TmTYYdKTb)tV0!gam{`H)^-nrN|zywPtvZT=YiUPY4$3qNAcT>YWl|x$jTL7E5VL z;vV~LgpmonB;{6?kSLGn2r!`Jce=!5r~OQEi!Ba;q%}WW=Spy#E`He7yF3fA;fbv~ zlR?~`yrf;IK!=>7h@VZ8&T`YCB;2CY%&7{iz00l>*Z9=qdb~Z2=YRqELDWg%9ihRO zpPye&%r?_zf>f2+;5CZAWkgWtD>8Neu;gG`=F^xZn|XI$zB4wo85(?6s)FsV;+fbL z^dj`c8cu~d7WgmhCXmU%mcchU+B9fvsxvUv6>NN1ABa@Czu79nkdl&` zzQl}>eL}Q_l$5+Q{YAih#Rvpk#-rB^C1iQ=oeUC#9dJ8#vT2dIl9aQ1tfwsBNzvS6 zwQb5S&DXW@f34b;Ur3*nzqQ8fHUS}6;cF6;Id+12Qbhcu&OuEnMfqaGg3B@|q}%HH zi

    Fo; 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 diff --git a/artifacts/verification/w6/states/empty.txt b/artifacts/verification/w6/states/empty.txt index fdd18e5..f188c65 100644 --- a/artifacts/verification/w6/states/empty.txt +++ b/artifacts/verification/w6/states/empty.txt @@ -1,7 +1,4 @@ - Ask Braid starter anything. - - @@ -17,8 +14,11 @@ + Ask Braid starter anything. -› +──────────────────────────────────────────────────────────────────────────────── +› new message -profile Braid starter · pi / deterministic Ctrl+P commands +─────────────── type / for commands · Alt+Enter newline · paste ──────────────── +profile Braid starter · pi · via local diff --git a/artifacts/verification/w6/states/failure-or-reconnect.json b/artifacts/verification/w6/states/failure-or-reconnect.json index a9be76c..fda7982 100644 --- a/artifacts/verification/w6/states/failure-or-reconnect.json +++ b/artifacts/verification/w6/states/failure-or-reconnect.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 80, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -30,7 +30,7 @@ }, "capturePhase": "atomic-signal-frame", "captureRevision": 8, - "frame": " › W6 failure state\n\n error · unknown\n RUNTIME_BACKEND_ERROR\n failed\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n›\n\n\nprofile Braid starter · pi / deterministic failed · /activity details · /new\n", + "frame": " › W6 failure state\n\n error · unknown\n RUNTIME_BACKEND_ERROR\n failed\n\n\n\n\n\n\n\n\n\n\n\n\n\n────────────────────────────────────────────────────────────────────────────────\n› new message\n\n\n─────────────── type / for commands · Alt+Enter newline · paste ────────────────\nprofile Braid starter · pi · via local failed · /activity details · /new\n", "packedState": { "schemaVersion": 2, "capturePhase": "atomic-signal-frame", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 8, "sequence": 8, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [ { @@ -98,8 +105,14 @@ "turnId": "turn-000002", "operationId": "op-terminal-000002", "status": "failed", + "startedAt": "2026-08-01T00:00:00.000Z", + "updatedAt": "2026-08-01T00:00:00.000Z", + "terminalAt": "2026-08-01T00:00:00.000Z", + "durationMs": 0, "inputTokens": 0, "outputTokens": 0, + "tokensKnown": false, + "usdKnown": false, "tokenStatus": "unknown", "costStatus": "unknown", "model": "fixture/deterministic", @@ -161,12 +174,13 @@ }, "view": { "revision": 8, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -221,6 +235,8 @@ { "id": "run-000001", "turnId": "turn-000002", + "conversationId": "conv-1", + "branchId": "branch-1", "operationId": "op-terminal-000002", "status": "failed", "profileName": "Braid starter", @@ -233,7 +249,8 @@ "output": 0, "tokenStatus": "unknown", "costStatus": "unknown", - "model": "fixture/deterministic" + "model": "fixture/deterministic", + "elapsedMs": 0 }, "runner": "pi", "provider": "agent-runtime", @@ -292,6 +309,7 @@ "title": "run run-000001", "status": "failed", "detail": "RUNTIME_FINAL_ERROR", + "elapsedMs": 0, "startedAt": "2026-08-01T00:00:00.000Z", "occurredAt": "2026-08-01T00:00:00.000Z", "runId": "run-000001", @@ -315,7 +333,7 @@ "title": "event backend_start", "status": "failed", "detail": "sequence 1", - "occurredAt": "2026-08-12T12:37:54.196Z", + "occurredAt": "2026-08-16T11:05:44.117Z", "sourceEventId": "run-000001:runtime:1", "runId": "run-000001", "entityType": "run", @@ -327,7 +345,7 @@ "title": "error", "status": "failed", "detail": "RUNTIME_BACKEND_ERROR", - "occurredAt": "2026-08-12T12:37:54.216Z", + "occurredAt": "2026-08-16T11:05:44.126Z", "sourceEventId": "run-000001:runtime:2", "runId": "run-000001", "entityType": "run", @@ -351,6 +369,9 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" }, { @@ -360,6 +381,9 @@ "status": "failed", "depth": 2, "edgeLabel": "continued", + "parentIds": [ + "branch:branch-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" }, { @@ -369,10 +393,15 @@ "status": "failed", "depth": 3, "edgeLabel": "attached", + "parentIds": [ + "turn:turn-000002" + ], "runner": "pi", + "elapsedMs": 0, "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [], "details": { "title": "run run-000001", @@ -389,14 +418,6 @@ "label": "output tokens", "value": "0" }, - { - "label": "token measurement", - "value": "unknown" - }, - { - "label": "cost measurement", - "value": "unknown" - }, { "label": "model", "value": "fixture/deterministic" @@ -413,19 +434,16 @@ "source": "application" }, "run.runner": { - "available": false, - "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "available": true, + "source": "application" }, "run.model": { - "available": false, - "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "run.effort": { - "available": false, - "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "conversation.branch": { "available": true, @@ -553,7 +571,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } }, @@ -591,6 +609,7 @@ "revision": 3, "kind": "run.requested", "payload": { + "runId": "run-000001", "text": "W6 failure state", "admission": { "version": 1, @@ -613,6 +632,7 @@ }, "harness": "pi" }, + "interactions": {}, "model": "fixture/deterministic", "runner": "pi" }, @@ -647,10 +667,10 @@ "provider": "agent-runtime" }, "admissionStatus": "admitted", - "requestDigest": "f080a8e87a51f6c8d898986826372cdf1767d2eb5101fad7cfb5df90caf5eabb", + "requestDigest": "aa53ce68f4954eb1bed81136389562901fa25272dd2225eb95bb1d7db499436d", "capabilitiesDigest": "93c4c21593f9e2fa1fe68ce73da84f48c173f1e13269633678b512a16a81a001", "materializationDigest": "46c7162244a3aa789bd2703e2805a3faa0da1a87d83d97484fa26294a0b00671", - "digest": "b069aefd4ed0b6d1f93b2f14f40d280b3e60c5d45b63cb76294571f32be2444e" + "digest": "64cf1e2fa64af9b21412dd3b9ebc4a2e7d2837e57d55ca090fe080435a9020b9" }, "status": "admitted" } @@ -663,10 +683,10 @@ "value": { "kind": "effect.upserted", "effect": { - "id": "effect-op-terminal-000002-cf99cee4622510fbb428f652", + "id": "effect-op-terminal-000002-9ffdb9513363cf2bbcf05ab0", "operationId": "op-terminal-000002", "effectKind": "run.execute", - "requestDigest": "cf99cee4622510fbb428f6528d8bf27f2101fdaf5757203e738e46db132e8ca6", + "requestDigest": "9ffdb9513363cf2bbcf05ab0c3ee45fc895dc29003d622df749e5fa199e5e9b6", "kind": "send", "status": "pending", "attempt": 1, @@ -681,16 +701,17 @@ "revision": 5, "kind": "run.provider.event", "payload": { + "runId": "run-000001", "source": { "eventId": "run-000001:runtime:1", "providerSequence": 1, - "occurredAt": "2026-08-12T12:37:54.196Z", + "occurredAt": "2026-08-16T11:05:44.117Z", "receivedAt": "2026-08-01T00:00:00.000Z" }, "unknown": { "type": "backend_start", "task": { - "id": "turn-1139ed2e-9b39-4c46-995c-10007663d712", + "id": "turn-560229eb-c5c8-41cc-ae83-a4bd8c46ebad", "intent": "W6 failure state", "metadata": { "identity": { @@ -700,11 +721,11 @@ } }, "session": { - "id": "badfe62c-65d2-4dc1-87ac-ac9276afc5e5", + "id": "e545428d-4105-4773-88d8-1eb36c26f90f", "backend": "executor", "status": "active", - "createdAt": "2026-08-12T12:37:54.196Z", - "updatedAt": "2026-08-12T12:37:54.196Z", + "createdAt": "2026-08-16T11:05:44.117Z", + "updatedAt": "2026-08-16T11:05:44.117Z", "metadata": "[unavailable]" }, "backend": "router", @@ -726,16 +747,16 @@ }, "execution": { "kind": "request", - "id": "turn-1139ed2e-9b39-4c46-995c-10007663d712" + "id": "turn-560229eb-c5c8-41cc-ae83-a4bd8c46ebad" }, "materializer": "router-prompt-model" }, "executionBindings": [ { "status": "known", - "attemptId": "turn-1139ed2e-9b39-4c46-995c-10007663d712:attempt:87b9a1e3-6bae-4569-9634-2a92fd9dd874", - "materializationReceiptDigest": "sha256:901b372639b868da687202e07ac113cc883a6518f868e1db3b4975fc58657f76", - "bindingDigest": "sha256:ffd96086c5ed9c2a2b810e793bb42c06e25cedafe8e1b75879cb80887661a659", + "attemptId": "turn-560229eb-c5c8-41cc-ae83-a4bd8c46ebad:attempt:9b5c7880-8346-4b79-a339-e27567430d22", + "materializationReceiptDigest": "sha256:4cee36369ee5cd7d6867ee462a20e76c8edb1f54e1dad043b8cbec34af35603d", + "bindingDigest": "sha256:a93cc37b04fa2b3da7f09db554744f4564f0b82f94f43a54d2510f8bd046a850", "descriptor": { "kind": "router-request", "transport": "http", @@ -747,10 +768,10 @@ "timeoutMs": null }, "timing": { - "startedAt": "2026-08-12T12:37:54.194Z" + "startedAt": "2026-08-16T11:05:44.113Z" } }, - "timestamp": "2026-08-12T12:37:54.196Z" + "timestamp": "2026-08-16T11:05:44.117Z" } } }, @@ -759,10 +780,11 @@ "revision": 6, "kind": "run.error", "payload": { + "runId": "run-000001", "source": { "eventId": "run-000001:runtime:2", "providerSequence": 2, - "occurredAt": "2026-08-12T12:37:54.216Z", + "occurredAt": "2026-08-16T11:05:44.126Z", "receivedAt": "2026-08-01T00:00:00.000Z" }, "error": { @@ -777,10 +799,11 @@ "revision": 7, "kind": "run.finished", "payload": { + "runId": "run-000001", "source": { "eventId": "run-000001:runtime:3", "providerSequence": 3, - "occurredAt": "2026-08-12T12:37:54.221Z", + "occurredAt": "2026-08-16T11:05:44.131Z", "receivedAt": "2026-08-01T00:00:00.000Z" }, "status": "failed", @@ -804,10 +827,10 @@ "value": { "kind": "effect.upserted", "effect": { - "id": "effect-op-terminal-000002-cf99cee4622510fbb428f652", + "id": "effect-op-terminal-000002-9ffdb9513363cf2bbcf05ab0", "operationId": "op-terminal-000002", "effectKind": "run.execute", - "requestDigest": "cf99cee4622510fbb428f6528d8bf27f2101fdaf5757203e738e46db132e8ca6", + "requestDigest": "9ffdb9513363cf2bbcf05ab0c3ee45fc895dc29003d622df749e5fa199e5e9b6", "kind": "send", "status": "failed", "attempt": 1, diff --git a/artifacts/verification/w6/states/failure-or-reconnect.png b/artifacts/verification/w6/states/failure-or-reconnect.png index b1adc6108f5c37049183f9fce2f94506b4c7a24f..58df31a1f5f6b8bce6fe122d7041660a0126d8d3 100644 GIT binary patch literal 19112 zcmeIacTiLP`Y+1+x)lT|ih_o=5v3QECjA8jM0yD=6ancFq)Q3BDhPsrNbe#ww9rBi z2na~8p%>{82%&{QAjw_seP+(w`JFR!?w#Mv{o`)Pe8a4SwZ3`k=XuuW$wz%%4SHG- zEfp0Nz2@_0hE!BnSg5G}d_?mna3smv)f0I7r~Pw79V)6IUMi};!>Oo=oW#cz<*u?-#Fn+D~aKwT3=dIc3zv=D?Hr-*8BusfrbGX1=(hJRt%v}b&Uu6^~ z^N0|Z8vjzZ{2NkqfAz1wrW{D*MiMl{K$PGk7PYZ^eh?o#wG}c9JQO@fWC&kh`{J2^ zi+{G&N8bUS&j{Qqe^609=lO41%Q9&EE@#Hlxxy~D&!VCZT#SloxJ%PBv~x~QmlT4B zv*IrOHfRwa=nMLBqj{vM3J7rM)5kc>Oy2v+n)XV|>en6b4DIc{FLv}soMR)xc#Yin;W6uO=Dy#|MVd4j>4 z+JDPG#m@7EpRGi8mqI)-Y=J%MAH;6#wfhfY0FkZr#)VR_sZgX_s--2Yp>i^|)!Q^^ z)3+dKbh+I{+t)aeHx_M=2@2|Yrh#On&5+;0c5z2CM6!d#9g~8_JFn8|hDWGB3m3Dl z``L$98%QQzNR#|FqM2>;B2^iN(vRWq-=l)QU``zniZB=~WD@eq*2Nsk<7};;JNGBm z!LrdGH%lF+57ENzg)B{+Y@RMIF19W^8|de7V}kws30)Z z8k*Y%Yw_Pr$xcLt>=<5oe?*8%M&iG4g*N)`c&9=aFYq{477%guI~fBfk4PRL;^*7^ zw0yNcxyFQqkZPWY4|x1zhz?^3p`s!u3jVt7>69?y|)(|JeL(=pJG3yidb1Z+1=jUu3q!m4DnZx zl4}3@=-i~gCO1V!M($j~)%artL$(xt;N!=SFABYnP)XRjqS1R ze7jEL>&EGy-4?^S*~xx{eJfVhY4zCF;cU5Ja!68cZv1-`%+4;0={^sSxB#~SjBckN z?G_Oc!MVR5Wa2%TW{}9MV|_YN!!QzXdWdIx`uZzV=jitJ#poBBngTK<`uxHoA{T_+ z;!q4fuWV_asVZM2XoDpg5bt1TI2FMbW%-9MdX= zT7s`FhR)YKo)f#p#f6)m8CmFD1unlelDn()wY|1>pxy%#!Sqq{x}>`xd10Z<6ej|y z-&?9RmE7LmHeM-XQc255Q}ho}whis;SY2Hm931r9of@L-2Xjn$pZ!ee(uhk-Pe-~e z61#RL+R2-lfZdu}^K6^{wzy!yUm)$5lpXp^yg6m)JEZy+qaEL3;~4kTGZk%Z0|SHg zCZ9INHeKDg!|NYaq7DuY=KK~W8%loLgtPNqRxX5-g2>?Dv3D){eRhj)iiJE6k1CBV z)YicD5*19)*4Cax;*Z8p-;MTF*#r9)78RWejPdsNX5f^q^T)cHva&{~7JsOdoL_xkmCd8U!es#36^Jv=ZVE+GM& z|F+8I`BrX!YwL&;%($!aLrm>N5}|0JHNAD0B9^ti_j4>C6@))@o%!B5?tSo8nd9C2 zLKdZf(-2$Rm8uT06yiOL8Til6&Q9s&yADv>u>#FC+b(ry^Iz}Olz@CdNK6;cwzL9- z8q&%(ba}QWnk|>y^77*AS0H4Z972tUCJQQyo#HuBx;Zz*?m$JYn%7rW###ew4aZ6s z)cM_%v)$;ZzK0oJUHD12T>Ct-@K)lNa3%wT$E6+H+i58k7E5i}rTYBi@piD zftG;%+bYkVWq~AJlZeWW*)aT&bPsQj66LbCy4vg65BSc6(&b8I80S)k!Y(uVy|Q3w z`$kR3xi`L|>_t>X@TV1Uh$&mRpbnk=TuC}%g!V1+Kc%1S+GCry0rSrBIA7632)9}g3$>5vM zq3hdY=gX;W?e(_DynwBGwvn41hcZ;6Qat8Lb3`T3Ru8S!fs9UN z0QTgg1~R+pe^*Zb|KdDgQEKW7E>_qsZn>^h2*6x|w{8Mh>@U#2)(l%eAqXrb;B^(3 zV#rJs_myB@oXPaWT9BnB;5b30fJvJAIQ4e()k7Cu*UJ#T`;%ke|MF6hs$76u)3ddn z&JDb`xjPD1ttu*S4iUB5D`;8ln{5Ne8H5^iJyom-2n4m+VI-)-7*FY%SL^C;Y? zS4}HLC->Z?@(BfRsxI$e|NU=&RqJiafTx>YcC>InM-7PkG51o}BFearB_)Ny-=uol zz7TVTipsahbZ>j2%*n)h4AD-?Nyy1bPH%#eY^J89L?Ctik`RBBsd^7Nz+WcD$E7`H zO^l5T0$qFKI?@?^q}>;?vXhfTgdEm3v3?7dtstq-fRTE`p-=Y+?kEKc5PQ0 z`a(-+Ovp?}TTw-YA3Si5`YJtWhLE~ERdSrTd3C@weAmm16Dr!>-Tja*0AZy? zb2IgG2@D2cYQ>XieZ^ReP3s%(_OJSqX^Dx6U%ptBrD(xthjZe`^?&9YEiPIjdV9-^ zIyc;=!uMJ-kC3k)Ce;GLz-42YIVzBD*C( zYv}x+*tZ|NIkR0IO%#NLloiar4vvh70qIi^>~8+Wv+xrKMYmgGi6SH{Ea+$c^Si!* zca<_Js8~1GbGmf)aIJT3jTvcPRj&TL*^5Wd{MY8DBNUpFn2Ot7JV4NQqI9uk)z{~y ze{VsPKm)e4%t}o3S)ci+1E~kQXM1~dT9}z#8mTec+uP@7Ewq-p<{N&BEoAc`ebC9v z<8xomJ|PP6IEEd9-#)R~Qs);HZR1S+W!*b8*0C~Eo$mo@c>TI60Ab|RRa6091d0}U z)syA~R-Z#x6cPWz>R{9+WOb-{f1kE{nN=4wRmK+{6(5htV7YalXDzR~Iw3th-F0-R zqTc=b?5qr+wsvxT|J@2~Apc=z8^s|uHyvOWEp+Y}K2IP>43s9U!Z z#gvZ3$$Xpr$TBrGwZ&$6&sTPP`}-`T^~unUf}$n!c3UGrKROu_Q^hy!5WUS!vYF}W z50+oZaNS{^snpr*%9?L5Dk}vn>dm#CP#!&+gp8oAGEdgi?In-7U|dGp-R0+Peyh*U zntZnKrDGE;s;3l}&qW&lS48zWBcDbzLri z>kYoJqxp{C<(stl_>ri*_iL-n5+m@un|5of0Q?%(u(_@Bqo-RS`TX$ub<8f9it5*O z{in@A#(o??%qBaWT@eGG$D{QBpRFgvD`LTfJug4Mn<@Y%2XHC_hkWBn@djYLrEo|C zR8t3~;5vC1{gS=~q`}BV4(%Weq=>MpurtUQ*E$YW+xK!R_*+VLrB5WdO_kTw!^hff z+IuUZ>puaoAf6@2b`AG*|t1SVz zddB?&=j%ZAqvXE*8|sYj7XyLxxVLZsz%0M33J^Kq#Vc< zVln~4<3qTA9NKGmxVzKR(E-tEI5(c?&@JXPoP~DubcJ#aU057X^6G%v#RF>^;^Uu) zdE%B}HY2&Y$?5Q+cYwhoPf)aXZh6o2P9xNIr^FaP@f<0JE*SN;q>-8ON}aV_Fi61IG4Isu(5F@VDZ>fqRXo#J|*=}KN5 zQX~UM5FWE(V_La4o8NL8{HzNkiQBCyYDQO*CTbi20E2xm*Lry*Bw|s2wmBe%G-smv zyV$&Y;ir)PCYPf3tDy|^P^L8D5L&Qd2skZvo;tbzeh{r(XaN9IRA_jZ*S`P#Hvnmk zU#`$b+?T`;$7_Yw)z#ggy}>Ud!2ig3Af!7vqADhYY2ug$j23_ZDnj zT+9V$cJz+hL}icw>K}VNcC|kQU2tGj3?P6%=XUgkf$hadf6^Zw9#)B3U(cKqtMTfx z5xWsm{parM&B1#So!_T>TYOT7sTuYV-@imK0g)5Pm(0A{AqT%Y@;<9#4wbR*0ejZV zmhoAAWu}Vw@KB6F61vCA%9fg0EL=9YgKM8I4!{ZEbjOZ9KAbIziH%`a0ZPq|X+H^^ z8{RlVWyPe$|3$wCz91NQTk;F(23gtL04AQux4WNIonU*sIrM>%E%e|QH&(2WhFc1{ zIkTi3X>bHOV!DAiTJvv%deotc3WT0pu z^h}?|*3GTVVK;eRF@xX-hi{_G*gzmhh0Cpv5)mp1si{sL4kF;+Qe;DgCh&#RFhIGO zISPrbmp+}u_oQ^H(M{|ZTQ!FOb?d+Y|M6jmnY1u^$a;}9RqZ6Xlxxkuxo3zcHOkxKLG0jLeaIWS1Tax z)|qx9A|g&BWZ&=K{}5NonQaME!s90E;1wx4ruvq`$U@LmNubT{0`tk93Kf;{$LMo4 zYao)g*&L8YS9mPyow*^M&Fxb4o?Jk6q^{;+_~u#o6EWQATNsfQ9F6fh65AYx9sCov zH{(^BfPMcbP@Q-2bW*G@K8^y`W+E7=_tZ9K_)=gu7@9nIzH079s22Q*h3wsO2KaE$&wO&MmmO}^hcYAwhWoBFFqjNAdCW^OGbipZHkYO%YwDrXl|wu_4QHD}>$9~^nGiE)$aQQ+ zrBi$k5MLr0OxFiEe(+pabWJkz>7EhKKsSK350NGwm|93GC|}9|zD%{8BCe4;FdiW>OJKdGBH+8&K-#x{9vq z&>KjRl}jd%g+g<@r}p$Lt*n;PC~dD_C^ox!!WvufJ2ufCgy^CM7*DZ{_>jE8tvYnBOb7P1aBj z{-cx@JT!ronFHxW$oc#GDVO%e%ZU^Zm8kFE>w&&a9-nSX*7fo8#Ok8#gmsR)Snyp-eCx`5-=Rh2)LtyPQD>VrFTO-+4E&dgz zJj>G>aSQbxk)s)>SR-#6H=x&&BoQ=tS5GeYbe6i}e;p_nB<|n-y~1oN&X>Q2BG>ZkJr|G2C-=Zs%2LdLVCY8v)$CqV=lq{< z{`bH9m$fcBP|P@07Fzq~{A5iz)ZO{1_tp|e_2HaYOSKK+q_uV0A1fqNEASk`uw4LQ!Wn1gIUbQ(b3T-Vz0k%VpXEXbV8Kq z-63cI5mO!9y~C83H8eCB8>_dVJtm?A|C1T$ez!+i-*ol%p%5Sq`Y>`ufHayKA1e>2 zy@MWu!faW!fAD}Rcl50%ndk9oEg5OuQ&Pv0jp3zGYvAh31*YK{VVJ>7Bd3Lm3f)$T^$m{}0`G&A zEYLb;VWxwOC2^aMi)Rg%!tSv*HihA~LLp^sW`#k+F81x#hC+S~^>aj(Wz~<;bBJ>z zn#bZ_hvt?R=PRvkEG^kB=l#gX9b6prq_xhCuXB}jasefn&8t91PAB;+ruB0{=0qHO zd(!DwAh5^?U1Ua0=%Ph3ChI0@XIv^EueMk}DKUM?O3uzoR@nG;Q-ki9n|_y$n^)>s zDL@Wi>@${relBOXCT)WvKghfV_^zDbCTpO>y~Q7dh--Mvbd{vElu2y0l;l|LAOjRx zZxcTt#&1mTxVdG6%AK0&2*nl(S^L*RDtk(|K0VjHw}}PA*=VS!a&(gK=J84sa!1Q| z!eNnd4;BXpM+h~@>-Q9&Q|v0Vbs__Ull#^C7;D3sBnJl#YirRw;z|Ae^Rj?Ih0A`> zNd7GAXpS+R#6@}6)|7s>6F)jK>9)+`0Fk!~E@WgFHa9WKLd-D48{iI%yvajFItRyB zNk*R$oO>qIR<4JUfiJkjHz>=07|Vt7G-a1*0rx!eW3qHLVZ&qA3NxME@S}PL;6Dch zAFFU^YlB9=wza=U6;>Z^^R_L@W1fp}`U^d5uX-I7p!&PzciGB(6Yn-NjGJ6qoa>+Y zIlA0Ij``}Zps*OhG%%te?d5xS@yGP|Ok;6za68ej?5o-zK%w>*;9hx7Hyu!u-^XX( zn7qt{a{86tyBD$aoGe0I1+1NZwua}yP7%}Ue4KK;;x4Icr}iOk6mEUAZfh?RUefNX z=15+it~16(xNfW(5B=Q6km`~RSf{L-ih@j4-~<)aa`V-&Uw}0jHv$bvz>h~VUbH3v zMel))S~$@8`KN#hd^~0VDk7c{!G2f&pnAjm`p*BnA@lFsGXHh8c-S`i za&?p!*EZ=sSxyq~t*^wIk-S6Z>LPmYi!B+9jD8>5Tzgz$L6p4*;_n<@CT>SoHLiaW zcZ;l;4|dp(HY$7}Jog%71;e0TIZFP^kXUZi+9Vv2mult zZOZ93XQW96j3%e3$vo@HP`}9bqfNvn!o9y=#7r6y2{c*W3}RW9;tKn#kx2h~1ZN;O zazQeu-Me@ml6i@lW*_SkdUIl9dTV?MG;Vwh0vlD7WtNk^^+wEGh^Uv-bCRYz4hm9( zqyz)LFx~$Oul2NQIrL!+q(4I)H^vt6eqd|gDHN?wMyy>D-i0mt=N*0pFC%0wPW36? zkgtXWX)3A`ra5)~V76nJ*0nc{W}3;B`uvU}3SQ!pLLwrtoew2JNDoU6VdF%_Hz+j| zUGiBIcPZScT@K^yq*#@|1y8%Z93%-8?pi4mt#6S`_vLvD7bH0qVB(@OJUgddi3S2Y zjL9pH1u(LyNOiQaSOBC9Qxvw}@`bFQPS$V2KF=aXr+&~>iBc_wYLmz_$v>#iuSQ54 z)ovmbvF_V3p`t-F9>gy)Jr24x!z5b?a4`Uu1qxF1s zl_#Lwxm0VQnBd4PB4!0CL1=89z&et57s^clRbReSLBAxbZfu-MxeRBL%eW`eD?#8wmVk=yPFW=LxDauhpZ+UO#n?Kws$N0YJ!YQE!H}mau zf9?8w{ExP!>EaK_*&VHbb<=NHkXHYY5mfG0Lx@pbes+^e9)G|WHOYK=hrFO1&bRvy zS!H04k;%DnBn((!)sC|zx4LED&zr&$D1bpsbE*6b=4B6FK55>pN$Wo*cSChnzBBd1iIZ;@r7=j0`H97odt_ay8LpS zkZ#-`n~(;dt9L!%{?W$#5%o?UG+kR;2|e;gs9ViX3N(#Jgk^awd?!~Z#{!-VoM0+H zJ2C|i#9Tdb56^WGv*1cQ(~yUU%7nwrr|J3%@dE7BIqR{|B;{Up2rY$2D#ZoLoeX3!y_r{`MO z;I6H!`(1zX)VvKRnN$nKzyW#d5syaY#3VC`uE!;10j%W;$75+z{qH)xcY%&Wjw7vx zsc5jgO#a2i;N8W3)D~?vZW-wIx};&&c1_Wlzgcl_l@1J>%F8l^v&Z1(Ji+LS=CLc6 zQ`n}?V?BU%Fb`hkdh?d)J}J-pB4I|1_a73z4Jepc@LGr4a)pcyIvFV6i1$^%%^n)7 zlZf9mNDBSJPvF}Bqo(T-I|7asc>Nz_lK+}p{{M3%!vJhbbru<^*W0$1f=Hj1mK1n# zq4pbI#4ZO{+$jW>x2aa5Q6gJO6Y5n{sU&A7Il`vt6tgd&W>Z z*t6Qw1U8l%cN`vYN@mMpN4T!ODtfr9k1jral<-YwezmC6G(AR*?MbET6 zyHG2gf0~(=vDoPS?()QQWuG}@WxZ!Fl2INeXX0md5Km9{!TUPx=WcL`)4ZeaS z#<_eV(O{UFe4(a+@)FxIa8v)pXXexsEl%J(PV^hHC{x6V0<4_f>>_1EIQEj<6o<%! zOlh}qdc9ukW!(P(cdA@5Znw&XBQZ$hyP$_w3<|Bb{ynG%@Mg&{a_o9ztu!Kg(sgs# z{t8hS4BMB3Hepoz*aD%}Z!3az{Yy3~1_yK-U!NU(m~Aq5!IZYi+mEC?%(ukUA3!Dl zqVeK=6>%yZ5He5iaqDU4RP}xrwLmIQ!v~yo0qtvtim_(L>}f?A-;I+>S?fOtP@DEQ z-uAou%ty&G^C|Hy0mt7q;UCm_V=d@Upd>q;)DKtB1Enj&BcK-+i+e+I@g9rz<8d3F z^}822u_%o>?Cu5SOdsZ=L9?8u|ad7%g2-Z#m}cH=1niGECtvoMo;L-ZG%ot5A(o7miP#2DS9uQ1&QNfP`QWzCv` zkE?}Xu+!?86*ex9zM3AT7pS+>BV7FH-+asB6@#CN57{VZ#NRgXkDT_gS-aQ!TTkEm zte0a6t#{it{Ou+K))c^$BOh@(x}?-jX-QX^zZ9G#=^z2Qr(=0xrM+osV9&`K+=r`O zrXja1jg4n;LjdhUMY6AF$^Jkt><$Zm*hTrS7#B6a4;RB-O3T}~&u}$99>xt`#Zikf zby<|jHm-IyT+?bIgG!W$mO5POS#~bF>jj>JaEv|k8E~pQ-)-qQMYa;#ku}EGMVez- zRm#t6a2aA385!nmpmgWjrSIg4_tyrWG9T?8-SdzVzMFD<@HVlfUCK>cC)z>*k*X@< zxm+(+d3kak+)!DMk!@RmL+P)uyPogakjUc%()94IgY&B=FFSD$%Uqpb?Jch$ft`rv zj`1ofAufcL;e1VjSN-ojChV;&r|7zQ5x?sVwR{q4^0|m5o$n862{~S+kOLcjX!XJ@ z+V%ffER*+x$=zXLS!m=;@O?PgX2L_~#^;eDST>Q8fi1jukrBWt1kSCo&^rbp_pq|Q zkLZJI%aeY zwRAPp@5^?&WCw6pH*#rNFK3E?Gq*JM6|hSTx)z~w^JuzwCxE$T+(?C-VKMu%tX?MMZA!i9h#&jCw&0Zr=3SrK z@h1~sMm}7AYj!u;2QiCrj5MYug^CHB6L&5b2IsGDxpOQGWP@0J4t_P?BN$b(u<(md zeCZ;H)|ajr)}{pXWqZGw*h+Wl1N^g?@$!{D&e3J}TgHiHZ$h7!6L8`$xtW33y-K0t zhO*QeALvV0XyD@zd#H&8@R5>#R;&cq(IZr%K)QG!)Nsi9#q5Q85wLFvo86ZS+Ti>^ zqJj-~3#2w7mou}D--I+WTiYa6QT#RqWfjR#l&9!WAt56*K33rc{PcMn=V44P?DzrSF|S`Q@;TQObl<-7uC)8nAAi0s9O;U#N#UgH;_c+LAt(&8lDR#lI7z)z9p zNWURj`V9O+JMjvhB7k52wVC{OhM^dYc-;#N*VdF>k0}>l zlOWeVA?u)0N5|wuKN|%zv#$X4|B+;app4$s`}vygjEs32?iz6%roPAU#*Nti?75oV zvrVfWED83av(Wy$Dc!#^);gm;f89Oe>Um-1U;H=d!CZsF<>0s4YUZnT3CTG%u-O@w z#U8@Fi$tbXlgp+nVIgmDn`$ESE1~^h4r_&9D-+6j`VXwGgXwv#87gqgi=#iE<>vlb zVx91n^TxIu7$2VXL~JWE0M>71sk)o2cCl2cN-b2T2r>!UQm=a=*4r^OGTGVuS2}iz z|1W?tF?D9L;F1ji=ldZ0H@@7IINYE zYG&^R=x9@#tQ`zj=aQN3i*CNO98^~2VP;&`RlcIQr{LPxZ{86!Wg-q7P>K3uElfma zyu$WxMZ{5bj7*6lbGwB7a(5z|;6=9H9KoMMHVrC-%6`2xHZ(olv~-?d26&OPJ#OXK z)LH*#lb$M%ad}PKyKokbXa(aR10a&|X&s5HhL_sDZ$`TxFiyYYq2* z?N&~FX^*o7V#F4O!j}4aC(Vsy((LecOSUa1H9K_W2a$H+`{WPjV%b=9!&NZjo5BZK zz-=rxQ@z^&1>S8O|FL3h=7+FNdIe|sd|lb;z*1A-*cj?#&}bpFR%1&*Sl?Q%W%qIn zoFZu{h!Mru-@AKv@{l%);lhaYW4}|=y1$h@{uV+?|Do|3B{s;_!EdhLXbObi!OBil zjjzwp0B~x532UFv@FQn=`N6isF-A&&a`Dfk&H9QNqH!tkS?lBt`!NT4=(e7AnwuDN z->uDuklyCuoFOg+H}y#J$|ica*%7ts1J4je4Dal)p?&b0jK&UcykH62@KKIJxt>hM8LCd!A%`m@XT=GEusC1}zY69I0$ zZZo?DeCxW?2usms%Hd;f%;Siw{p-6o_Z2%ZkNc_)vG&DzKJFa5 z8;*tDz2V_dN|9ZFvOrE~c63aPr=@~{_d5RgViEOz&yo$E^Fp&dvnmWvUD2%PKE0(7 zp>nu(G4x{T5qi`G9GZK479w*rLAhQtW*fF|Lu!-q6LpJ~CHTXf&2}oz#6PI_c#TDd zGYNPl^tbLosuK#o{blZPad{B@JRy?uP!|tHVBNW86o+1&~%l8M> z=qI*7pgA#L7GrGu)P)6zNgl#q=hVw>U}GqQa{p|M=}LX=f;-Ox zOQ+7n(1mf3nWzrUHT9xTToV%$R<5(Lq@arJrKZWWq(ggS$_c`(|LpPpl!;!sfW<$k zBNn16X2c-$zKTCeF}thRb6IoNWg5Q8uZSAIxTC=jPzd5vgr5dJDu_(Ac`Y&ma0ioG zey+1dUYkC$JnJjIW1TM7VEE20(7(hgz_&rMNk-;)8d2@zT{?FXJ@cyy66X#r0D9; zv9htpcML6(LzERfmZR@j=N4Z!R?dh%D2ra!-T$@s3JMLCI(hc?31tkPXv1#t5ZRpi zOO6wJ|@$2BA_X;XWE{ z;2Lba$y%I&8LR4uzS2^RdeUF4R?Des4NSctL%K86w2X~N^GFUnIjMQcI#8x*B~m42 zFvEwk1Vb0tuJy*A|58A2iG`9b^jyOvg0e6wNyK+6)e0AmpF&hGut0-#X`6A$ZLSFU zHeqFUl$p+HxGni}iE2w)S_UomCvENiMQwm`DSCxS;Cx)C`<{3n*k5bQ7fM_e^1EC1zJjpMea)GyyM>ZDJ<^ifP9 zC`?Xl#w!QM6bOVq6W(MtB!Xy4G`=>JZL+mg$R^~r+diCSNjz_*A22P^Ah!l=RTMnH z&kd9sHlehfKyf>L|#wg0leY^3((|BadwnIK0f6@3Pz ztQ$~$99RiQlyvu@qt)dt9;8*cmz$GkZ3)YT0_+rkH8T;4vaXlHH9&9b4|I=y|L2MN z(Icg9oc{c-m=y$uEnXho0;3Ya`*=Nv=Z{oSZQY?f?xH z;kzgMO-CQ9J3Q?cDlYLPVNpo8QWT++o|SX@>uia%0WAufm$KGj3p?MxfQ68jx2FbX ze!Leb;8yY|U{m|^jps+_{OHp6Zh@uk8vPX>=D%&l!-8DhZNf>PZPKt*SPM)e8fnD& z?M*-wiU3lfl_%m#W>=o0OX=977;hn1(!-xY6I5aqON>Bw)LN;TRjY?o;XH0VFEEisqUEh{u1z~hwU!l zRqBaEruWqMOU#y+fi}$_Re1J*Lk`s42JZtf4L&t|mC~Nw^Vz zSajvvzONq%u*8$Tec_P|sH$l$@o{%GbJ5iu&a0Sj0qD0-CkSMBQ~3|M zX^J_t)>%=^nOuY(rIF1omY4{6QtBR$Rq5&JxuV{7)DdMGiKP8GG(5Z1=16VlL6i}HHu*u z*}(z=1l%IU5#uYT5xI3i829!HcH%=b`-El5n=JPR_xzN8QMl6!b$s?S!BZ*iX2AK2 zw@;Kd9FIz`#$dCvL1)C2mS$T|l-J>26X51RFyLH77OyLpnOoW9VoXwkrQQ3V>$QjB z$Zv-rVWiVwkyLb1ef**}31S^-M_IDg8v%H~e!JvR@6cp#xr$-mk`dsYupBqcI_4W_ zZ?xFS-`{^`=}7Fs_CgCFJ9pWp<{Kb!Z}hwFVDds5FjE8!#C09rDWz4fo5$aNH#AoM)4=R#5bu~ zLB0fgSxcDGa*We(DUP6#`-w^AOe##bp=Vru;8b}fGQMPF$UHq=+J24g?A)cP5nuxY zQ2_8Fg&Mb!RHPV5JX){`5`zTFv<>+KAP&oajC5Xb(Ue3%1^4z36chSnJ&bP1?}ddI-X9 zqLKj890M=!2J7w8YvRYph$TI@y_X2kNlmQ+>>@5`GisgBm#(KN4x&$}bPGGHo_s?O z6zvU@k;A=3j;y-5O`$7>sjS4ZYb|Y$e$C{-0RHxdXvul&*JGK=FL9PIUG*TrGCF{; zZ`1zT02md)8gqyH4P|W9Tl+qHu&ieE1p84tiWJ(VaRjl-l#JR)K7Uv>V62HdM%r|s=wA;_T) z*A0J*>>d5wtgNh281=hgycuCluT<{pz!t1x=v_0u(%VH*%42UYoXG_qz-d+W1#^Y_ z$NDCjIYTnL3OAZikO?pxfo#d$MZIHFo($i4siojLV0#=8m>tK9l=FIE?KV3jkzZBNP^L_)gzKU8+CB*Rz~IJX^S`O zScvuL7Q3mYMx`Pj5BIZ$4WSOCydT8R+=^dGseO`B5+JA#c%aG*#%5<{=`+vFXXjoy zIUx5ZZC840F&D(1XDL1|s%10|P$=}3UAZE+`TShbBFfbJ!@JIR8maxygI{{Mm2pal zi;F*g9GI5CEvR8&FxK^Hu%c{Q^uoQ8TnMOs85k@-a5dX^^v6s);cVC#J?8U3Cwl3p_lh?@I!ui13PdsH%@j5uhT)j6j9D4QM1geNI2GB+USZ1#Jb*0 zA$i^kN&C>J)>iOiR;S1hO8yv97CW_%5B_WN$2L|}-O8_*%O0b2F^cKO z+n%@nEnhuA?i+K2tsd#3cCN{?79;Fj0JJbm)-tp@V}y>FwI+!Bi9UZ-z({XZBAfw1 zl$2~AHI-ZoZQG~EctDUv1K-I=d3n&ew3UUmky|j29xSs8$gqI%?>=Vjw_0~K_T`}z zVS2e?5G0d|rQo4^t0HGnF&+1yi13TJPxAf??K)+&0yZ=TT^-~O3R!)pTDa77q>s4O z?)ArFi?ca7`FPA)C$oeaw(jY*xxUW6h}=Ttn$F0{B?o<1;**=794!CSt*mJ#+T%R> zn`&`|ye&0@;^0sBM~a;C(%&9#X^>_wBp+;W}wv2I?7q>x_{;Gna+4CjPDDKPuwY{gGE$tRp-r><-4Ru zJodQe-c~X7e?@F`Kk?nTc7uKGLb78)G1q)8Vwdhp3-G-dFl=*;zp?-z$+?gT#d^i$ z6P=@x7Xym-z}M)lo?jXI9i8VI)Q(d+u<^KA)@I5}%CvQTJyL)mm}HV^0Zj6c6YmZC zE$n4wEs^&UA=1zf?#ovDhGC@E@#YU$NN&h0H#aPR_#xs>mWo_=0@uwV>VBOc7+t-3 z6=ef5@%AJgp&R@_lVMK#>|3%>M@L8cOo>pZ{VYRI`Dt}vvJTODTpvsdlAB7Rq`jJX z`+kIggDg+?c8=GK4DkHf>^d(wEn>BQY&ikM_1dbs8+%Jgqjp6L(U~Hn-hjQ0HUz%|}r!9a0ngOtPe()&+NW32viXvs! zk#_#hxzI}TDsWbmGJ^6VY)+3y8+uOfKKTiZV-EMhfh}ClBhfXA@m4(jevclz{Pmtl zW;jjh>B-ML^FJ=(LB5%(NV@FoYqqGISHtu+%L%{ zCU5^Qc)~)#;uYl;!R-=zhz%jmi`Ik>K-(KqnvB0%m=5hNk`h|1cg6Z(=NcQ)OSP4k z%d7C;IO|yF0%%8#OMjH&%cm`FqI3D$ga;th?nRJkL%nWekcj*8+nlaz#l;HG8-sLw z(k&K$4)ljK2CQvf4I|llnDX!*4F;>)hzj$!V^T-5b5AiP)5Y4>tbvB^Of#DOqUXE&NI?C$xJ+}x!2>b60!X{vxtsCA3=V)@A@ zAdaPm84xS($WhFutEzG34ly3sz1y@AL=u078>F%(8eO{~q-vgRlDP!dWPr|2k-Fa! za7zlT{@>Q$(1XW)!ahEUOY)8%dYBs;D$ecoYZswQ3^_$j%C$^WkjL?UDlKHdHBJ2I z$<%}LAl^T_F-wd8W^U)yQL2cG1}agWa@UeWay0RAC0x3>;N`p+0Otj5Z~xdN=U%J7 zqcUmJd|zD2hQ><(s~nHdT=HDB+oFS&-MeRn%B_Eb>8w0!Uw&}=i?7cS`7&V|OPRl*a&WK74;yWEL zyj_v|4>XX5HZxDF@nh%mg`DRzYZjS6xwfwYa)zSPi~x>94<7@&A#8Y{PlRwQiRt&) zM_wQU8bTW!C@s(+{7XQ&_-c*{;F@9KT+8)ASmraXfr;vLZxO~Gd? zd0WhT+o;t`&x2_aw-&>xG883&}fpatZs+sxPdwO^{ fKz*s4TpUGx++2(|%cp>ss5I4dpH-^7eD{9=37kk+ literal 6377 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 diff --git a/artifacts/verification/w6/states/failure-or-reconnect.txt b/artifacts/verification/w6/states/failure-or-reconnect.txt index 4f589ca..9d1e4e4 100644 --- a/artifacts/verification/w6/states/failure-or-reconnect.txt +++ b/artifacts/verification/w6/states/failure-or-reconnect.txt @@ -16,9 +16,9 @@ +──────────────────────────────────────────────────────────────────────────────── +› new message -› - - -profile Braid starter · pi / deterministic failed · /activity details · /new +─────────────── type / for commands · Alt+Enter newline · paste ──────────────── +profile Braid starter · pi · via local failed · /activity details · /new diff --git a/artifacts/verification/w6/states/fork-preview.json b/artifacts/verification/w6/states/fork-preview.json index e0bff81..a34aba9 100644 --- a/artifacts/verification/w6/states/fork-preview.json +++ b/artifacts/verification/w6/states/fork-preview.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 80, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 1, "sequence": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [], "runs": [], @@ -113,12 +120,13 @@ }, "view": { "revision": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -202,9 +210,13 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [], "capabilities": { "conversation.create": { @@ -216,19 +228,16 @@ "source": "application" }, "run.runner": { - "available": false, - "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "available": true, + "source": "application" }, "run.model": { - "available": false, - "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "run.effort": { - "available": false, - "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "conversation.branch": { "available": true, @@ -391,7 +400,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } } diff --git a/artifacts/verification/w6/states/fork-preview.png b/artifacts/verification/w6/states/fork-preview.png index ae93f8e33016a63a10988192497c62bb2c248dad..732ed694d2e824ddcc1698c52c5fdfdfced34dc7 100644 GIT binary patch delta 21 dcmbOeH79C=1v7^LH>><}j~U*Z9hmQE0sv1D2P^;p delta 21 dcmbOeH79C=1v3W^kE+h4Im)q{9hmQE0sv3v2QmNv diff --git a/artifacts/verification/w6/states/graph-or-analysis.json b/artifacts/verification/w6/states/graph-or-analysis.json index f20e5f2..4cc6a50 100644 --- a/artifacts/verification/w6/states/graph-or-analysis.json +++ b/artifacts/verification/w6/states/graph-or-analysis.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 80, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -30,7 +30,7 @@ }, "capturePhase": "atomic-signal-frame", "captureRevision": 1, - "frame": " conversation graph · 2 Braid starter · pi · fixture/deterministic\n────────────────────────────────────────────────────────────────────────────────\n ✓ New conversation · conversation · complete · ─attached→\n › └ ✓ Main · branch · complete · current · ─attached→\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n────────────────────────────────────────────────────────────────────────────────\n ↑↓ move · enter/→ open · ←/esc close\n", + "frame": " conversation graph · 2 Braid starter · pi · fixture/deterministic\n────────────────────────────────────────────────────────────────────────────────\n ✓ ▾ New conversation · conversation · complete · ─attached→\n › └ ✓ Main · branch · complete · current · ─attached→\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n────────────────────────────────────────────────────────────────────────────────\n ↑↓ move · enter/→ open · ←/esc close · space collapse · w waiting\n", "packedState": { "schemaVersion": 2, "capturePhase": "atomic-signal-frame", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 1, "sequence": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [], "runs": [], @@ -113,12 +120,13 @@ }, "view": { "revision": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -202,9 +210,13 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [], "capabilities": { "conversation.create": { @@ -216,19 +228,16 @@ "source": "application" }, "run.runner": { - "available": false, - "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "available": true, + "source": "application" }, "run.model": { - "available": false, - "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "run.effort": { - "available": false, - "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "conversation.branch": { "available": true, @@ -343,7 +352,7 @@ } }, "draft": "", - "selectedSurface": "transcript", + "selectedSurface": "graph", "appearance": { "color": "256", "highContrast": false, @@ -358,7 +367,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } } diff --git a/artifacts/verification/w6/states/graph-or-analysis.png b/artifacts/verification/w6/states/graph-or-analysis.png index 0e6302d8778ba7e1633a4a2217b3d5c469bbb96e..d574b8100e025fc7f730a97d2679c7af43feba84 100644 GIT binary patch literal 20641 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

    a0lJ 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 Qc#1{mzQMgR%|BlLFPPS-jQ{`u literal 19470 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 z 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 diff --git a/artifacts/verification/w6/states/interaction.txt b/artifacts/verification/w6/states/interaction.txt index 77ca918..0408f1e 100644 --- a/artifacts/verification/w6/states/interaction.txt +++ b/artifacts/verification/w6/states/interaction.txt @@ -1,4 +1,4 @@ - permission Braid starter @ pi · run fixture-run-1 · timeout unknown + permission Braid starter · pi ──────────────────────────────────────────────────────────────────────────────── Allow the fixture tool to inspect the selected file? src/app/application.ts · read-only @@ -21,4 +21,4 @@ ──────────────────────────────────────────────────────────────────────────────── - ↑↓ move · enter confirm · 1-3 quick select · esc cancel · alt+a automate + ↑↓ move · enter confirm · 1-3 quick select · ←/esc cancel · alt+a automate diff --git a/artifacts/verification/w6/states/narrow.json b/artifacts/verification/w6/states/narrow.json index 5d3bf4f..59d9464 100644 --- a/artifacts/verification/w6/states/narrow.json +++ b/artifacts/verification/w6/states/narrow.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 40, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -30,7 +30,7 @@ }, "capturePhase": "atomic-signal-frame", "captureRevision": 1, - "frame": "\n Ask Braid starter anything.\n\n\n\n\n\n\n›\n\n\nBraid starter Ctrl+P commands\n", + "frame": "\n\n\n\n Ask Braid starter anything.\n\n────────────────────────────────────────\n› new message\n\n\n type / for commands · Alt+Enter newlin…\nBraid starter\n", "packedState": { "schemaVersion": 2, "capturePhase": "atomic-signal-frame", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 1, "sequence": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [], "runs": [], @@ -113,12 +120,13 @@ }, "view": { "revision": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -202,9 +210,13 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [], "capabilities": { "conversation.create": { @@ -216,19 +228,16 @@ "source": "application" }, "run.runner": { - "available": false, - "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "available": true, + "source": "application" }, "run.model": { - "available": false, - "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "run.effort": { - "available": false, - "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "conversation.branch": { "available": true, @@ -358,7 +367,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } } diff --git a/artifacts/verification/w6/states/narrow.png b/artifacts/verification/w6/states/narrow.png index 442393ca8e6946b9e42eafb4281b9566015175ce..a7b4c6c4c1316ef050266968e3c3043aa89d13d9 100644 GIT binary patch literal 9973 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 literal 2962 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 diff --git a/artifacts/verification/w6/states/narrow.txt b/artifacts/verification/w6/states/narrow.txt index 913d8d5..436119d 100644 --- a/artifacts/verification/w6/states/narrow.txt +++ b/artifacts/verification/w6/states/narrow.txt @@ -1,12 +1,12 @@ - Ask Braid starter anything. - - + Ask Braid starter anything. -› +──────────────────────────────────────── +› new message -Braid starter Ctrl+P commands + type / for commands · Alt+Enter newlin… +Braid starter diff --git a/artifacts/verification/w6/states/profile.json b/artifacts/verification/w6/states/profile.json index 903ced5..6de005b 100644 --- a/artifacts/verification/w6/states/profile.json +++ b/artifacts/verification/w6/states/profile.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 80, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -30,7 +30,7 @@ }, "capturePhase": "atomic-signal-frame", "captureRevision": 1, - "frame": "\n Ask Braid starter anything.\n\n\n\n\n Active profile · Braid starter\n source Braid starter · trusted · read-only\n runner pi · model fixture/deterministic\n thinking none · max output provider default\n digest sha256:44ed91c9…8cfa0a14\n profiles\n ──────────────────────────────────────────────────────────────────────\n >\n → ✓ Braid starter trusted · read-only · Braid starte\n ──────────────────────────────────────────────────────────────────────\n enter · ^V valid · ^S save · esc\n\n\n\n\n\n\nprofile Braid starter · pi / deterministic Ctrl+P commands\n", + "frame": "\n\n\n\n\n\n\n\n\n Braid starter\n trusted · read-only\n runner pi · model fixture/deterministic\n thinking none · limits provider default\n digest sha256:44ed91c9…8cfa0a14\n ←/esc close\n", "packedState": { "schemaVersion": 2, "capturePhase": "atomic-signal-frame", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 1, "sequence": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [], "runs": [], @@ -113,12 +120,13 @@ }, "view": { "revision": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -202,9 +210,13 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [], "capabilities": { "conversation.create": { @@ -216,19 +228,16 @@ "source": "application" }, "run.runner": { - "available": false, - "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "available": true, + "source": "application" }, "run.model": { - "available": false, - "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "run.effort": { - "available": false, - "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "conversation.branch": { "available": true, @@ -358,7 +367,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } } diff --git a/artifacts/verification/w6/states/profile.png b/artifacts/verification/w6/states/profile.png index 1491f88d7af9ff1a8c70dbf3f4bb0f0665573925..f6aee722446952b1eea1a0587e0e7e74d27b264f 100644 GIT binary patch literal 5536 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 CZlTry literal 30518 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≤pGPj(! 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 - → ✓ Braid starter trusted · read-only · Braid starte - ────────────────────────────────────────────────────────────────────── - enter · ^V valid · ^S save · esc - - -profile Braid starter · pi / deterministic Ctrl+P commands + Braid starter + trusted · read-only + runner pi · model fixture/deterministic + thinking none · limits provider default + digest sha256:44ed91c9…8cfa0a14 + ←/esc close diff --git a/scripts/capture-product-demo.mjs b/scripts/capture-product-demo.mjs deleted file mode 100644 index f998f34..0000000 --- a/scripts/capture-product-demo.mjs +++ /dev/null @@ -1,303 +0,0 @@ -import assert from 'node:assert/strict' -import { execFile } from 'node:child_process' -import { randomBytes } from 'node:crypto' -import { chmod, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { promisify } from 'node:util' - -import { releaseTargetDefinitions } from './live-bridge/bridge.mjs' -import { assertPublicCapture } from './live-demo/public-safety.mjs' -import { liveDemoProfileForRoute, LIVE_DEMO_PROFILE } from './live-demo/workspace.mjs' - -const COLUMNS = 160 -const ROWS = 30 -const CONNECTION_ID = 'connection-product-demo-cli-bridge' -const HUMAN_PROMPT = - 'Please inspect this workspace and tell me which command runs the test suite. Do not edit files.' -const execFileAsync = promisify(execFile) - -function pause(milliseconds) { - return new Promise((resolve) => setTimeout(resolve, milliseconds)) -} - -function rebaseEvents(events) { - const offset = events[0]?.[0] ?? 0 - return events.map(([timestamp, direction, data]) => [ - Number((timestamp - offset + 0.01).toFixed(6)), - direction, - data, - ]) -} - -async function typeText(terminal, value, delayMs = 20) { - for (const character of value) { - terminal.input(character) - await pause(delayMs) - } -} - -async function localPiModelCredential(profile) { - const executable = process.env.BRAID_PI_BIN ?? 'pi' - const provider = profile.model.provider - const model = profile.model.default - for (const credentialKind of ['print-bearer-token', 'print-api-key']) { - const args = ['auth', credentialKind] - if (provider !== undefined) args.push('--provider', provider) - args.push('--model', model) - try { - const result = await execFileAsync(executable, args, { - encoding: 'utf8', - env: process.env, - }) - const token = result.stdout.trim() - if (token.length === 0 || /\r|\n/u.test(token)) continue - return token - } catch {} - } - throw new Error(`The real product demo requires a usable local Pi ${model} credential`) -} - -function demoEndpoint() { - return ( - process.env.BRAID_PRODUCT_DEMO_ENDPOINT ?? - process.env.BRAID_LIVE_DEMO_ENDPOINT ?? - process.env.BRAID_CLI_BRIDGE_ENDPOINT ?? - 'http://127.0.0.1:3345' - ) -} - -function localEndpoint(value) { - const endpoint = new URL(value) - assert.equal(endpoint.protocol, 'http:', 'The product demo requires a local HTTP CLI Bridge') - assert.ok( - ['127.0.0.1', 'localhost', '::1', '[::1]'].includes(endpoint.hostname), - 'The product demo refuses a non-loopback CLI Bridge', - ) - assert.equal(endpoint.username, '', 'The product demo endpoint must not contain credentials') - assert.equal(endpoint.password, '', 'The product demo endpoint must not contain credentials') - assert.equal(endpoint.search, '', 'The product demo endpoint must not contain query data') - assert.equal(endpoint.hash, '', 'The product demo endpoint must not contain a fragment') - return endpoint.origin -} - -function bridgeAuthorization() { - const value = - process.env.BRAID_CLI_BRIDGE_AUTH ?? - process.env.BRAID_CLI_BRIDGE_BEARER ?? - process.env.CLI_BRIDGE_BEARER - if (value === undefined || value.trim().length === 0) return undefined - return /^(?:Bearer|Basic)\s+/iu.test(value) ? value : `Bearer ${value}` -} - -async function jsonRequest(url) { - const authorization = bridgeAuthorization() - const response = await fetch(url, { - ...(authorization === undefined ? {} : { headers: { Authorization: authorization } }), - signal: AbortSignal.timeout(15_000), - }) - const body = await response.json() - if (!response.ok) throw new Error(`CLI Bridge request failed with HTTP ${response.status}`) - return body -} - -async function requirePiBridge(endpoint) { - const [health, models] = await Promise.all([ - jsonRequest(`${endpoint}/health`), - jsonRequest(`${endpoint}/v1/models`), - ]) - const readyPi = health.backends?.find( - (backend) => backend?.name === 'pi' && backend?.state === 'ready', - ) - assert.equal(health.status, 'ok', 'CLI Bridge is not healthy') - assert.ok(readyPi, 'CLI Bridge does not report a ready Pi backend') - const [target] = releaseTargetDefinitions( - [], - { ok: true, body: models }, - { body: health }, - ).filter((candidate) => candidate.backend === LIVE_DEMO_PROFILE.harness) - assert.ok(target, 'CLI Bridge does not advertise a ready Pi model') - return { health, target } -} - -async function createProductionDemoWorkspace(root, endpoint, profile) { - const workspace = join(root, 'agent-sdk') - const configDirectory = join(workspace, '.braid') - const configPath = join(configDirectory, 'config.json') - const keyPath = join(root, 'database.key') - const now = new Date().toISOString() - await mkdir(configDirectory, { recursive: true, mode: 0o700 }) - await writeFile(keyPath, randomBytes(32).toString('hex'), { mode: 0o600 }) - await chmod(keyPath, 0o600) - await writeFile( - configPath, - `${JSON.stringify( - { - format: 'braid-startup-config', - schemaVersion: 2, - profile, - connectionId: CONNECTION_ID, - databaseKeyFile: keyPath, - connections: [ - { - id: CONNECTION_ID, - kind: 'cli-bridge', - name: 'Local CLI Bridge', - endpoint, - providerOptions: { transport: 'local' }, - createdAt: now, - updatedAt: now, - lastHealth: { status: 'healthy', checkedAt: now }, - }, - ], - }, - null, - 2, - )}\n`, - { mode: 0o600 }, - ) - return { workspace, configPath, keyPath } -} - -async function waitForCompletedRun(terminal) { - const deadline = Date.now() + 180_000 - while (Date.now() < deadline) { - const screen = terminal.screen().replace(/\s+/gu, ' ').trim() - if (screen.includes('failed') || screen.includes('outcome unknown')) { - throw new Error(`The real product demo run did not complete: ${screen}`) - } - if (!screen.includes('working') && !screen.includes('Ctrl+C cancel')) { - const captured = await terminal.captureState() - const run = captured.record.state?.runs?.at(-1) - if (run?.status === 'completed') return captured - } - await pause(250) - } - throw new Error('Timed out waiting for the real Pi product demo run') -} - -export async function captureProductDemo({ spawnTerminal, normalized, castFor }) { - const temporaryRoot = await mkdtemp(join(tmpdir(), 'braid-product-demo-')) - const endpoint = localEndpoint(demoEndpoint()) - const { target } = await requirePiBridge(endpoint) - const route = target.modelId - const profile = liveDemoProfileForRoute(route) - const modelCredential = await localPiModelCredential(profile) - const setup = await createProductionDemoWorkspace(temporaryRoot, endpoint, profile) - const terminal = await spawnTerminal( - 'product-demo', - COLUMNS, - ROWS, - { - BRAID_CLI_BRIDGE_ENDPOINT: endpoint, - BRAID_MODEL_VALIDATION_TIMEOUT_MS: '120000', - BRAID_STATE_PATH: join(temporaryRoot, 'state.sqlite'), - BRAID_CLI_BRIDGE_MODEL_TOKEN: modelCredential, - ...(profile.model.provider === 'openai-codex' - ? { BRAID_CLI_BRIDGE_MODEL_BASE_URL: 'https://chatgpt.com/backend-api' } - : {}), - NODE_NO_WARNINGS: '1', - XDG_CONFIG_HOME: join(temporaryRoot, 'config'), - XDG_DATA_HOME: join(temporaryRoot, 'data'), - }, - undefined, - [ - '--workspace', - setup.workspace, - '--config', - setup.configPath, - '--database-key-file', - setup.keyPath, - ], - { fixture: false }, - ) - try { - await terminal.waitForInterface() - await terminal.waitFor( - () => { - const screen = normalized(terminal.screen()) - return ( - screen.includes(profile.name) && - screen.includes(`pi / ${profile.model.default}`) && - screen.includes('CLI Bridge') && - screen.includes('high') - ) - }, - 'real Pi product configuration', - 120_000, - ) - await pause(700) - - const demoStartIndex = terminal.events.length - await typeText(terminal, '/profile', 24) - terminal.input('\r') - await terminal.waitFor( - () => { - const screen = normalized(terminal.screen()) - return ( - screen.includes(profile.name) && - screen.includes(`runner pi · model ${profile.model.default}`) && - screen.includes('thinking high') - ) - }, - 'AgentProfile panel', - 30_000, - ) - await pause(700) - terminal.input('\u001b') - await terminal.waitFor( - () => !normalized(terminal.screen()).includes(`runner pi · model ${profile.model.default}`), - 'AgentProfile panel close', - ) - await pause(350) - - await typeText(terminal, HUMAN_PROMPT, 18) - terminal.input('\r') - await terminal.waitFor( - () => normalized(terminal.screen()).includes('working'), - 'real Pi active run', - 30_000, - ) - const completed = await waitForCompletedRun(terminal) - await terminal.waitForStable('real product screenshot') - const screenshot = completed.point - const demo = terminal.snapshot() - const frameCast = castFor( - terminal, - terminal.events.slice(0, screenshot.eventCount), - 'Braid product screenshot', - `braid --runner pi --model ${route} --connection Local-CLI-Bridge`, - ) - const demoCast = castFor( - terminal, - rebaseEvents(terminal.events.slice(demoStartIndex, demo.eventCount)), - 'Braid product demo', - `braid --runner pi --model ${route} --connection Local-CLI-Bridge`, - ) - const publicText = `${frameCast}\n${demoCast}\n${screenshot.screen}` - assertPublicCapture(publicText) - assert.doesNotMatch(publicText, /\b(?:fixture|deterministic|unknown|not reported)\b/iu) - assert.match(screenshot.screen, new RegExp(HUMAN_PROMPT.slice(0, 24), 'u')) - assert.match(screenshot.screen, new RegExp(profile.name, 'u')) - assert.match(screenshot.screen, new RegExp(`pi / ${profile.model.default}`, 'u')) - assert.match(screenshot.screen, /CLI Bridge/u) - assert.match(screenshot.screen, /(?:in|out|\$|latency) \S+/u) - await terminal.closeNormally() - - return { - columns: COLUMNS, - rows: ROWS, - finalScreen: screenshot.screen, - frameCast, - demoCast, - steps: [ - 'Inspect the real Pi AgentProfile', - 'Send a human prompt through Local CLI Bridge', - 'Review observed model usage in the context rail', - ], - } - } finally { - await terminal.dispose() - await rm(temporaryRoot, { force: true, recursive: true }) - } -} diff --git a/scripts/capture-visual.mjs b/scripts/capture-visual.mjs index 648ed38..79668f2 100644 --- a/scripts/capture-visual.mjs +++ b/scripts/capture-visual.mjs @@ -7,7 +7,6 @@ import { join } from 'node:path' import { promisify } from 'node:util' import xterm from '@xterm/headless' import * as pty from 'node-pty' -import { captureProductDemo } from './capture-product-demo.mjs' import { createStateDefinitions } from './capture-visual-definitions.mjs' import { captureProvenance, @@ -212,9 +211,10 @@ async function spawnTerminal( } const waitForStable = (label = 'settled terminal frame') => waitFor(() => pendingWrites === 0 && performance.now() - lastOutputAt >= 75, `${name} ${label}`) + const fullInterfaceMarker = uiFixture === 'interaction' ? '↑↓ move' : 'type / for commands' const waitForInterface = () => waitFor( - () => output.includes('\u001b[?1049h') && output.includes('›'), + () => output.includes('\u001b[?1049h') && output.includes(fullInterfaceMarker), `${name} full interface handoff`, 15_000, ) @@ -578,26 +578,6 @@ try { await writeCastGif(join(rawRoot, 'automation-frame.cast'), automationGif) artifacts.push(await artifactFor(automationGif, 'automation-flow', 80, 24, 'automation')) - const productDemo = await captureProductDemo({ spawnTerminal, normalized, castFor }) - const productDemoCast = join(rawRoot, 'braid-demo.cast') - const productFrameCast = join(rawRoot, 'braid-demo-frame.cast') - const productText = join(outputRoot, 'braid.txt') - const productPng = join(outputRoot, 'braid.png') - const productGif = join(outputRoot, 'braid.gif') - const productRasterGif = join(rawRoot, 'braid-demo-frame.gif') - await writeFile(productDemoCast, productDemo.demoCast) - await writeFile(productFrameCast, productDemo.frameCast) - await writeFile(productText, productDemo.finalScreen) - await writeRaster(productFrameCast, productPng, productRasterGif) - await writeCastGif(productDemoCast, productGif, { loop: true }) - const productArtifacts = [ - await artifactFor(productDemoCast, 'product-asciicast', productDemo.columns, productDemo.rows), - await artifactFor(productText, 'product-frame', productDemo.columns, productDemo.rows), - await artifactFor(productPng, 'product-png', productDemo.columns, productDemo.rows), - await artifactFor(productGif, 'product-flow', productDemo.columns, productDemo.rows), - ] - artifacts.push(...productArtifacts) - const keyboardFlow = await transcriptKeyboardCapture() const keyboardCast = join(rawRoot, 'transcript-keyboard.cast') const keyboardGif = join(outputRoot, '80x24-transcript-keyboard.gif') @@ -623,7 +603,7 @@ try { tarball: packed.tarballName, tarballSha256: packed.tarballSha256, stateFixture: 'deterministic', - productDemoSource: 'live Pi through CLI Bridge', + liveDemoCommand: 'pnpm capture:demo:live', terminal: 'node-pty/xterm-256color', node: process.version, provenance, @@ -631,10 +611,6 @@ try { steps: keyboardFlow.steps, artifacts: keyboardArtifacts.map((artifact) => artifact.path), }, - productDemo: { - steps: productDemo.steps, - artifacts: productArtifacts.map((artifact) => artifact.path), - }, states: stateManifests, artifacts, }, diff --git a/src/views/tui/terminal-chrome.ts b/src/views/tui/terminal-chrome.ts index d971020..74eec22 100644 --- a/src/views/tui/terminal-chrome.ts +++ b/src/views/tui/terminal-chrome.ts @@ -53,13 +53,15 @@ export class TerminalChrome implements Component { const mode = terminalContextModeForColumns(safeWidth) const target = executionTargetFor(view) const transientNotice = state.quitArmed ? undefined : transientNoticeFor(view) - if (transientNotice !== undefined) { + if (mode === 'narrow' && transientNotice !== undefined) { return [fitTerminalAtomic(statusText(this.#theme, view, transientNotice), safeWidth)] } - const statusValue = conciseStatus(view, state.quitArmed, mode) + const statusValue = transientNotice ?? conciseStatus(view, state.quitArmed, mode) const status = statusText(this.#theme, view, statusValue) const navigation = - mode === 'narrow' ? '' : navigationHint(view, state.navigationHint, state.composerMode, mode) + mode === 'narrow' || transientNotice !== undefined + ? '' + : navigationHint(view, state.navigationHint, state.composerMode, mode) const hint = terminalValuePart(this.#theme, navigation) const executionFacts = executionFactsFor(target) const measured = @@ -86,6 +88,8 @@ export class TerminalChrome implements Component { ? {} : { maxTotalOutputTokens: target.maxTotalOutputTokens }), } as const + const noticeRow = + transientNotice === undefined ? undefined : fitTerminalAtomic(status, safeWidth) const measuredOnRow1 = mode === 'wide' && measured.length > 0 && @@ -104,16 +108,18 @@ export class TerminalChrome implements Component { const row1 = renderTerminalContext( this.#theme, identity, - right, + noticeRow === undefined ? right : [], safeWidth, mode === 'narrow' || state.quitArmed ? 'right' : 'left', ) - if (mode !== 'wide') return [row1] + if (mode !== 'wide') return noticeRow === undefined ? [row1] : [row1, noticeRow] const row2Facts = executionFacts.map((fact) => terminalValuePart(this.#theme, fact)) const row2Measured = measuredOnRow1 ? [] : measured - if (row2Facts.length === 0 && row2Measured.length === 0) return [row1] + if (row2Facts.length === 0 && row2Measured.length === 0) { + return noticeRow === undefined ? [row1] : [row1, noticeRow] + } const row2 = fitTerminalColumns(row2Facts, row2Measured, safeWidth, 'right') - return row2.length === 0 ? [row1] : [row1, row2] + return [row1, ...(noticeRow === undefined ? [] : [noticeRow]), ...(row2 ? [row2] : [])] } } @@ -181,7 +187,7 @@ function finiteNonNegative(value: number | undefined): number | undefined { function statusText(theme: BraidTheme, view: BraidViewModel, value: string): string { const safe = sanitizeNotification(value) - if (value === 'outcome unknown') return theme.warning(safe) + if (value === 'outcome unverified') return theme.warning(safe) if (view.status === 'failed' || view.status === 'storage-failure') return theme.danger(safe) if (view.status === 'running' || view.status === 'waiting' || view.status === 'cancelling') return theme.warning(safe) @@ -195,7 +201,7 @@ function conciseStatus( mode: ReturnType, ): string { if (quitArmed) return 'Ctrl+C again to quit' - if (terminalOutcomeIsUnknown(view)) return 'outcome unknown' + if (terminalOutcomeIsUnknown(view)) return 'outcome unverified' const status = view.status if (status === 'starting') return mode === 'narrow' ? 'starting · Ctrl+C stop' : 'starting · Ctrl+C cancel' diff --git a/test/scripts.test.ts b/test/scripts.test.ts index 7984721..decaf3d 100644 --- a/test/scripts.test.ts +++ b/test/scripts.test.ts @@ -69,6 +69,31 @@ test('W5 exposes stable checks for every requested release surface', () => { for (const script of required) assert.equal(typeof packageJson.scripts[script], 'string', script) }) +test('deterministic visual capture stays separate from the explicit live demo', async () => { + const [visualSource, liveDemoSource] = await Promise.all([ + readFile(new URL('../../scripts/capture-visual.mjs', import.meta.url), 'utf8'), + readFile(new URL('../../scripts/live-demo.mjs', import.meta.url), 'utf8'), + ]) + + assert.equal( + packageJson.scripts['capture:visual'], + 'pnpm run build && node scripts/capture-visual.mjs', + ) + assert.equal( + packageJson.scripts['capture:demo:live'], + 'pnpm run build && node scripts/live-demo.mjs', + ) + assert.match(visualSource, /--fixture', 'deterministic'/u) + assert.match(visualSource, /fullInterfaceMarker = uiFixture === 'interaction'\s*\? '↑↓ move'/u) + assert.match(visualSource, /output\.includes\(fullInterfaceMarker\)/u) + assert.doesNotMatch(visualSource, /output\.includes\('›'\)/u) + assert.match(visualSource, /stateFixture: 'deterministic'/u) + assert.match(visualSource, /liveDemoCommand: 'pnpm capture:demo:live'/u) + assert.doesNotMatch(visualSource, /capture-product-demo|productDemo/u) + assert.match(liveDemoSource, /BRAID_LIVE_DEMO_ENDPOINT/u) + assert.match(liveDemoSource, /assertPublicCapture/u) +}) + test('active streaming capture waits for a terminal run state before exiting', async () => { let screen = 'working' let cancelled = false diff --git a/test/terminal-responsive.test.ts b/test/terminal-responsive.test.ts index f31f048..edc694f 100644 --- a/test/terminal-responsive.test.ts +++ b/test/terminal-responsive.test.ts @@ -301,10 +301,39 @@ test('chrome exposes active-run controls and failure recovery without hiding out }) const uncertain = chrome.render(80).join('\n') assert.match(uncertain, /profile Release engineer · pi \/ gpt-5\.6-luna/u) - assert.match(uncertain, /outcome unknown/u) + assert.match(uncertain, /outcome unverified/u) assert.doesNotMatch(uncertain, /failed|\/new/u) }) +test('completed notices preserve the persistent route and measured context', () => { + const base = viewForChrome() + const chrome = new TerminalChrome(theme) + chrome.setState({ + view: { + ...base, + notice: 'Prepared markdown export', + statusText: 'Prepared markdown export', + }, + quitArmed: false, + activityVisible: false, + navigationHint: '/ commands · Ctrl+P', + composerMode: 'queue', + }) + + const standard = chrome.render(80).join('\n') + assert.match(standard, /profile Release engineer · pi \/ gpt-5\.6-luna/u) + assert.match(standard, /via Local CLI Bridge/u) + assert.match(standard, /Prepared markdown export/u) + assert.doesNotMatch(standard, /\/ commands|Ctrl\+P/u) + + const wide = chrome.render(120).join('\n') + assert.match(wide, /profile Release engineer · pi \/ openai-codex\/gpt-5\.6-luna/u) + assert.match(wide, /Local CLI Bridge/u) + assert.match(wide, /Prepared markdown export/u) + assert.match(wide, /in 1\.2k/u) + assert.match(wide, /out 567/u) +}) + test('layout breakpoints preserve transcript room and short-terminal overlays', () => { assert.equal(layoutFor(40, 12).mode, 'narrow') assert.equal(layoutFor(40, 12).overlayFullScreen, true) From 5b8e569e4958504e3d09e6cb016c74c9c4920629 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 05:14:16 -0600 Subject: [PATCH 13/25] feat(tui): suspend safely for native sessions --- src/bin/interface-signal-lifecycle.ts | 36 +++++++++++++++++++---- src/views/tui/terminal-app.ts | 23 +++++++++++++++ test/cli-startup.test.ts | 41 +++++++++++++++++++++++++++ test/tui.test.ts | 33 +++++++++++++++++++++ 4 files changed, 128 insertions(+), 5 deletions(-) diff --git a/src/bin/interface-signal-lifecycle.ts b/src/bin/interface-signal-lifecycle.ts index e0f67db..27d1816 100644 --- a/src/bin/interface-signal-lifecycle.ts +++ b/src/bin/interface-signal-lifecycle.ts @@ -1,7 +1,7 @@ import type { BraidApplication } from '../app/application.js' import type { StartupPreview } from '../startup/preview-runtime.js' -import type { BraidTerminalApp } from '../views/tui/terminal-app.js' import type { BraidUiController } from '../views/shared/intents.js' +import type { BraidTerminalApp } from '../views/tui/terminal-app.js' import { recordInterfaceState } from './interface-state-recorder.js' interface InterfaceSignalLifecycleInput { @@ -16,6 +16,8 @@ interface InterfaceSignalLifecycleInput { export interface InterfaceSignalLifecycle { readonly interrupted: () => boolean readonly settle: () => Promise + /** Temporarily route termination signals to a native terminal attachment. */ + readonly takeOver: (handler: (exitCode: number) => void) => () => void readonly dispose: () => void readonly exitCode: () => number } @@ -28,6 +30,8 @@ export function createInterfaceSignalLifecycle( let frameSnapshot = Promise.resolve() let signalCleanup: Promise | undefined let disposed = false + let signalHandler: (exitCode: number) => void + let signalTakeoverActive = false const shutdownMode = process.env.BRAID_SHUTDOWN_MODE === 'detach' ? ('detach' as const) : ('cancel' as const) const configuredDeadline = Number(process.env.BRAID_SHUTDOWN_DEADLINE_MS ?? 5_000) @@ -66,16 +70,19 @@ export function createInterfaceSignalLifecycle( } })() } + signalHandler = stopFromSignal const onFrameSnapshot = () => { if (input.recordState) frameSnapshot = frameSnapshot.then(() => recordInterfaceState(`${input.recordState}.frame`, input.controller, 'atomic-signal-frame'), ) } - const onInterrupt = () => stopFromSignal(130) - const onTerminate = () => stopFromSignal(143) - const onHangup = () => stopFromSignal(129) - const releaseTerminationSignals = input.startupPreview?.takeSignalOwnership(stopFromSignal) + const onInterrupt = () => signalHandler(130) + const onTerminate = () => signalHandler(143) + const onHangup = () => signalHandler(129) + const releaseTerminationSignals = input.startupPreview?.takeSignalOwnership((exitCode) => + signalHandler(exitCode), + ) if (releaseTerminationSignals === undefined) { process.once('SIGINT', onInterrupt) process.once('SIGTERM', onTerminate) @@ -90,6 +97,25 @@ export function createInterfaceSignalLifecycle( await signalSnapshot await frameSnapshot }, + takeOver: (handler: (exitCode: number) => void) => { + if (disposed) throw new Error('Termination signal lifecycle is closed') + if (signalTakeoverActive) throw new Error('Termination signals already have an active owner') + signalTakeoverActive = true + let pendingExitCode: number | undefined + let released = false + signalHandler = (exitCode) => { + if (pendingExitCode !== undefined) return + pendingExitCode = exitCode + handler(exitCode) + } + return () => { + if (released) return + released = true + signalTakeoverActive = false + signalHandler = stopFromSignal + if (pendingExitCode !== undefined) stopFromSignal(pendingExitCode) + } + }, dispose: () => { if (disposed) return disposed = true diff --git a/src/views/tui/terminal-app.ts b/src/views/tui/terminal-app.ts index 52bb9b2..90d2b09 100644 --- a/src/views/tui/terminal-app.ts +++ b/src/views/tui/terminal-app.ts @@ -57,6 +57,7 @@ export class BraidTerminalApp { #removeInputListener: (() => void) | undefined #stopped = false #started = false + #suspended = false #openConfigurationOnStart = false readonly #restoreTerminalOutputPolicy: () => void readonly #tuiStarted: boolean @@ -209,9 +210,31 @@ export class BraidTerminalApp { return this.#done } + /** Release the local terminal while keeping application state and subscriptions alive. */ + suspend(): void { + if (this.#stopped || !this.#started || this.#suspended) return + this.#suspended = true + this.#removeInputListener?.() + this.#removeInputListener = undefined + this.#tui.stop({ preserveScreen: true }) + } + + /** Reclaim the local terminal and redraw the same Braid application state. */ + resume(): void { + if (this.#stopped || !this.#started || !this.#suspended) return + this.#suspended = false + this.#removeInputListener = this.#tui.addInputListener((data) => this.#input.handle(data)) + this.#tui.start() + if (this.#modals.hasOpen()) this.#modals.focusTop() + else this.#tui.setFocus(this.#shell.editor) + this.#render(this.#controller.view()) + this.#tui.requestRender(true) + } + stop(): void { if (this.#stopped) return this.#stopped = true + this.#suspended = false this.#overlays.dispose() this.#interactions.dispose() this.#input.close() diff --git a/test/cli-startup.test.ts b/test/cli-startup.test.ts index 61ed28e..fecdd46 100644 --- a/test/cli-startup.test.ts +++ b/test/cli-startup.test.ts @@ -158,6 +158,47 @@ test('verification signals capture more than one atomic semantic frame', async ( } }) +test('native terminal signal ownership returns to Braid before shutdown', async () => { + let routedSignal: ((exitCode: number) => void) | undefined + let nativeExitCode: number | undefined + let shutdowns = 0 + let stopped = 0 + const lifecycle = createInterfaceSignalLifecycle({ + controller: { + dispatch: async () => { + shutdowns += 1 + return { kind: 'accepted', revision: 1, completion: Promise.resolve() } + }, + } as unknown as BraidUiController, + view: { stop: () => (stopped += 1) }, + application: { markCleanupUncertain: () => {} }, + nextOperationId: () => 'operation-native-signal', + startupPreview: { + takeSignalOwnership: (handler: (exitCode: number) => void) => { + routedSignal = handler + return () => {} + }, + } as unknown as import('../src/startup/preview-runtime.js').StartupPreview, + }) + try { + const release = lifecycle.takeOver((exitCode) => { + nativeExitCode = exitCode + }) + assert.ok(routedSignal) + routedSignal(130) + assert.equal(nativeExitCode, 130) + assert.equal(shutdowns, 0) + + release() + await lifecycle.settle() + assert.equal(shutdowns, 1) + assert.equal(stopped, 1) + assert.equal(lifecycle.exitCode(), 130) + } finally { + lifecycle.dispose() + } +}) + test('startup preview renders real route context and replays early input once', async () => { const writes: string[] = [] class RecordingTerminal extends VirtualTerminal { diff --git a/test/tui.test.ts b/test/tui.test.ts index 14203a3..72d4849 100644 --- a/test/tui.test.ts +++ b/test/tui.test.ts @@ -260,6 +260,39 @@ test('the real Braid root renders and sends at all four reference sizes', async } }) +test('terminal suspension releases input and resumes the same composer state', async () => { + const terminal = new VirtualTerminal(80, 24) + const tui = new TuiMainScreen(terminal) + const app = createBraidApplication({ fixture: 'deterministic' }) + app.initialize('/workspace') + const view = new BraidTerminalApp({ + controller: createApplicationUiController(app), + tui, + theme: createBraidTheme(false), + workspace: '/workspace', + nextOperationId: () => 'operation-terminal-suspend', + }) + const done = view.start() + try { + terminal.sendInput('before attach') + assert.equal(view.editor.getText(), 'before attach') + + view.suspend() + terminal.sendInput(' ignored') + assert.equal(view.editor.getText(), 'before attach') + + view.resume() + terminal.sendInput(' after') + assert.equal(view.editor.getText(), 'before attach after') + await terminal.waitForRender() + assert.match(terminal.getViewport().join('\n'), /before attach after/u) + } finally { + view.stop() + await done + await app.close() + } +}) + test('composer fallback steers exactly once without queueing or sending', async () => { const harness = await startSteeringTerminal() try { From d63014d41c357c3be484a9df8babfd696ef0a2c4 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 05:32:02 -0600 Subject: [PATCH 14/25] fix(tui): preserve responsive composer and runtime context --- src/views/tui/composer-view.ts | 8 ++++- src/views/tui/terminal-chrome.ts | 45 +++++++++++------------ test/terminal-responsive.test.ts | 58 +++++++++++++++++++++++++----- test/terminal-usage-status.test.ts | 9 ++--- 4 files changed, 81 insertions(+), 39 deletions(-) diff --git a/src/views/tui/composer-view.ts b/src/views/tui/composer-view.ts index d7fefa5..45a38dc 100644 --- a/src/views/tui/composer-view.ts +++ b/src/views/tui/composer-view.ts @@ -175,7 +175,7 @@ export function composerRowBudget(terminalRows: number): number { export function composerBorderLine(width: number, label: string, theme: BraidTheme): string { const safeWidth = Math.max(1, Math.floor(width)) - const padded = truncateToWidth(` ${label} `, safeWidth, '…') + const padded = truncateToWidth(` ${composerHintForWidth(label, safeWidth)} `, safeWidth, '…') const labelWidth = visibleWidth(padded) const remaining = Math.max(0, safeWidth - labelWidth) const left = Math.floor(remaining / 2) @@ -183,6 +183,12 @@ export function composerBorderLine(width: number, label: string, theme: BraidThe return `${theme.editor.borderColor('─'.repeat(left))}${theme.accent(padded)}${theme.editor.borderColor('─'.repeat(right))}` } +function composerHintForWidth(label: string, width: number): string { + if (width < 60) return 'type / for commands · Alt+Enter' + if (width < 100) return 'type / for commands · Alt+Enter · paste' + return label +} + function promptActionLabel(projection: ComposerProjection): string | undefined { if (projection.action === 'send') return 'new message' if (projection.action === 'queue') { diff --git a/src/views/tui/terminal-chrome.ts b/src/views/tui/terminal-chrome.ts index 74eec22..0e37d3f 100644 --- a/src/views/tui/terminal-chrome.ts +++ b/src/views/tui/terminal-chrome.ts @@ -54,7 +54,7 @@ export class TerminalChrome implements Component { const target = executionTargetFor(view) const transientNotice = state.quitArmed ? undefined : transientNoticeFor(view) if (mode === 'narrow' && transientNotice !== undefined) { - return [fitTerminalAtomic(statusText(this.#theme, view, transientNotice), safeWidth)] + return boundedTerminalRows([statusText(this.#theme, view, transientNotice)], safeWidth) } const statusValue = transientNotice ?? conciseStatus(view, state.quitArmed, mode) const status = statusText(this.#theme, view, statusValue) @@ -90,39 +90,36 @@ export class TerminalChrome implements Component { } as const const noticeRow = transientNotice === undefined ? undefined : fitTerminalAtomic(status, safeWidth) - const measuredOnRow1 = - mode === 'wide' && - measured.length > 0 && - view.activeRunId === undefined && - status.length === 0 const idleHint = navigation.startsWith('/ commands') ? [] : [hint] const right = state.quitArmed ? [status] - : measuredOnRow1 - ? measured - : mode === 'standard' && view.activeRunId !== undefined - ? [status] - : view.activeRunId !== undefined || status.length > 0 - ? [status, hint] - : idleHint - const row1 = renderTerminalContext( + : mode === 'standard' && view.activeRunId !== undefined + ? [status] + : view.activeRunId !== undefined || status.length > 0 + ? [status, hint] + : idleHint + const identityRow = renderTerminalContext( this.#theme, identity, noticeRow === undefined ? right : [], safeWidth, mode === 'narrow' || state.quitArmed ? 'right' : 'left', ) - if (mode !== 'wide') return noticeRow === undefined ? [row1] : [row1, noticeRow] - const row2Facts = executionFacts.map((fact) => terminalValuePart(this.#theme, fact)) - const row2Measured = measuredOnRow1 ? [] : measured - if (row2Facts.length === 0 && row2Measured.length === 0) { - return noticeRow === undefined ? [row1] : [row1, noticeRow] + const identityRows = noticeRow === undefined ? [identityRow] : [identityRow, noticeRow] + if (mode !== 'wide') return boundedTerminalRows(identityRows, safeWidth) + const detailFacts = executionFacts.map((fact) => terminalValuePart(this.#theme, fact)) + if (detailFacts.length === 0 && measured.length === 0) { + return boundedTerminalRows(identityRows, safeWidth) } - const row2 = fitTerminalColumns(row2Facts, row2Measured, safeWidth, 'right') - return [row1, ...(noticeRow === undefined ? [] : [noticeRow]), ...(row2 ? [row2] : [])] + const detailRow = fitTerminalColumns(detailFacts, measured, safeWidth, 'right') + return boundedTerminalRows([...identityRows, ...(detailRow ? [detailRow] : [])], safeWidth) } } +function boundedTerminalRows(rows: readonly string[], width: number): string[] { + return rows.map((row) => fitTerminalAtomic(row, width)) +} + function executionFactsFor(target: ExecutionTargetView): readonly string[] { const environment = target.environment if (environment?.kind !== 'sandbox') return [] @@ -134,11 +131,11 @@ function executionFactsFor(target: ExecutionTargetView): readonly string[] { const sample = environment.resourceSample if (sample !== undefined) { const currentMemory = finiteNonNegative(sample.memoryCurrentMb) - if (currentMemory !== undefined) facts.push(`sample mem ${currentMemory}MB`) + if (currentMemory !== undefined) facts.push(`mem ${currentMemory}MB`) const peakMemory = finiteNonNegative(sample.memoryPeakMb) if (peakMemory !== undefined) facts.push(`peak ${peakMemory}MB`) const memoryLimit = finiteNonNegative(sample.memoryLimitMb) - if (memoryLimit !== undefined) facts.push(`sample limit ${memoryLimit}MB`) + if (memoryLimit !== undefined) facts.push(`limit ${memoryLimit}MB`) const cpuUsec = finiteNonNegative(sample.cpuUsageUsec) if (cpuUsec !== undefined) facts.push(`cpu ${Math.round(cpuUsec / 1_000)}ms`) } @@ -167,7 +164,7 @@ function requestedResourceLabel(environment: EnvironmentView): string | undefine ? undefined : `${resources.accelerator.count}×${resources.accelerator.kind}`, ].filter((value): value is string => value !== undefined) - return parts.length === 0 ? undefined : `requested ${parts.join(' · ')}` + return parts.length === 0 ? undefined : `size ${parts.join(' · ')}` } function memoryLabel(value: number | undefined): string | undefined { diff --git a/test/terminal-responsive.test.ts b/test/terminal-responsive.test.ts index edc694f..7fdab5e 100644 --- a/test/terminal-responsive.test.ts +++ b/test/terminal-responsive.test.ts @@ -11,7 +11,11 @@ import { import { createApplicationUiController } from '../src/adapters/tui/application-ui-controller.js' import { createBraidApplication } from '../src/app/composition.js' import type { BraidViewModel, EnvironmentView } from '../src/views/shared/models.js' -import { composerProjectionFor, composerRowBudget } from '../src/views/tui/composer-view.js' +import { + composerBorderLine, + composerProjectionFor, + composerRowBudget, +} from '../src/views/tui/composer-view.js' import { layoutFor } from '../src/views/tui/layout.js' import { ModalCoordinator } from '../src/views/tui/modal-coordinator.js' import { BraidTerminalApp } from '../src/views/tui/terminal-app.js' @@ -66,6 +70,8 @@ function viewForChrome(): BraidViewModel { tokenStatus: 'complete', costUsd: 0.0312, costStatus: 'reported', + llmLatencyMs: 842, + latencyStatus: 'complete', unknownTokenSources: 0, unknownCostSources: 0, }, @@ -104,7 +110,8 @@ test('chrome uses complete responsive groups at every reference width', () => { assert.doesNotMatch(standard, /braid|cwd|New conversation|branch-1|in 1\.2k|out 567|\$0\.0312/u) assert.doesNotMatch(standard, /…/u) - const wide = plainLines(chrome, 120).join('\n') + const wideLines = plainLines(chrome, 120) + const wide = wideLines.join('\n') assert.match(wide, /Release engineer/u) assert.match(wide, /profile Release engineer · pi \/ openai-codex\/gpt-5\.6-luna/u) assert.match(wide, /Local CLI Bridge/u) @@ -113,17 +120,44 @@ test('chrome uses complete responsive groups at every reference width', () => { assert.match(wide, /in 1\.2k/u) assert.match(wide, /out 567/u) assert.match(wide, /\$0\.0312/u) + assert.match(wide, /latency 842ms/u) assert.doesNotMatch( wide, /braid|cwd|New conversation|branch-1|output ≤|\/home\/drew|\.worktrees|…/u, ) - assert.equal(plainLines(chrome, 120).length, 1) + assert.equal(wideLines.length, 2) + + const spaciousLines = plainLines(chrome, 200) + assert.equal(spaciousLines.length, 2) + assert.match(spaciousLines[0] ?? '', /^profile Release engineer/u) + assert.match(spaciousLines[1] ?? '', /^in 1\.2k · out 567 · \$0\.0312 · latency 842ms$/u) + assert.doesNotMatch(spaciousLines.join('\n'), /(?:^|\n)rofile\b/u) for (const width of [1, 2, 10, 40, 80, 120, 200]) { - for (const line of plainLines(chrome, width)) assert.ok(visibleWidth(line) <= width) + for (const line of plainLines(chrome, width)) { + assert.ok(visibleWidth(line) <= width) + assert.doesNotMatch(line, /[\r\n]/u) + } } }) +test('composer hint chooses a complete slash affordance before narrow truncation', () => { + const label = 'type / for commands · Alt+Enter newline · paste' + const narrow = composerBorderLine(40, label, theme) + assert.match(narrow, /type \/ for commands · Alt\+Enter/u) + assert.doesNotMatch(narrow, /newline|…/u) + + const standard = composerBorderLine(80, label, theme) + assert.match(standard, /type \/ for commands · Alt\+Enter · paste/u) + assert.doesNotMatch(standard, /…/u) + + const wide = composerBorderLine(120, label, theme) + assert.match(wide, /type \/ for commands · Alt\+Enter newline · paste/u) + assert.ok(visibleWidth(narrow) <= 40) + assert.ok(visibleWidth(standard) <= 80) + assert.ok(visibleWidth(wide) <= 120) +}) + test('command palette stays isolated and keeps close controls at narrow and wide sizes', async () => { for (const [columns, rows] of [ [40, 12], @@ -216,15 +250,15 @@ test('wide chrome keeps measured sandbox facts as independent context items', () assert.doesNotMatch(wideReference, /unknown|not reported/u) const mediumWide = chrome.render(160).join('\n') - assert.match(mediumWide, /sample mem 512MB/u) + assert.match(mediumWide, /mem 512MB/u) assert.doesNotMatch(mediumWide, /unknown|not reported/u) const wide = chrome.render(200).join('\n') assert.match(wide, /host sandbox\.example\.test/u) assert.match(wide, /machine machine-a10/u) assert.match(wide, /region us-central/u) - assert.match(wide, /sample mem 512MB/u) - assert.match(wide, /requested 4cpu · 8GB · 80GB/u) + assert.match(wide, /mem 512MB/u) + assert.match(wide, /size 4cpu · 8GB · 80GB/u) assert.match(wide, /gpu 1× A10 \$0\.1234/u) assert.match(wide, /in 1\.2k|out 567|\$0\.0312/u) for (const width of [40, 80, 120, 200]) { @@ -424,13 +458,21 @@ test('published Pi virtual terminals keep the composer and valid cells at all si assert.doesNotMatch(viewport.join('\n'), /braid|completed/u) const prompt = viewport.findIndex((line) => line.includes('›')) assert.ok(prompt >= 0, `${columns}x${rows} composer prompt`) - assert.equal(rows - prompt, 5, `${columns}x${rows} composer and context rows`) + const contextRows = columns >= 100 ? 6 : 5 + assert.equal(rows - prompt, contextRows, `${columns}x${rows} composer and context rows`) assert.match(viewport[prompt - 1] ?? '', /─{8,}/u) assert.match(viewport[prompt] ?? '', /› new message/u) assert.match(viewport[prompt + 3] ?? '', /type \/ for commands/u) const context = viewport.slice(prompt + 4) assert.ok(context.some((line) => line.includes('Release engineer'))) if (columns >= 100) assert.match(context.at(-1) ?? '', /in 1\.2k|out 567|\$0\.0312/u) + if (columns === 200) { + const identityRow = context.find((line) => line.includes('Release engineer')) + const usageRow = context.find((line) => line.includes('latency 842ms')) + assert.match(identityRow ?? '', /^profile Release engineer/u) + assert.match(usageRow ?? '', /^in 1\.2k · out 567 · \$0\.0312 · latency 842ms$/u) + assert.doesNotMatch(context.join('\n'), /(?:^|\n)rofile\b/u) + } assert.doesNotMatch(viewport.join('\n'), /\/home\/drew|\.worktrees/u) tui.stop() diff --git a/test/terminal-usage-status.test.ts b/test/terminal-usage-status.test.ts index eb36f8a..b72e1b7 100644 --- a/test/terminal-usage-status.test.ts +++ b/test/terminal-usage-status.test.ts @@ -260,8 +260,8 @@ test('the wide rail shows only observed sandbox facts and measured usage', () => assert.match(rendered, /host 10\.0\.0\.7/u) assert.match(rendered, /machine machine-a10/u) assert.match(rendered, /region us-central/u) - assert.match(rendered, /sample mem 512MB/u) - assert.match(rendered, /requested 2cpu · 4GB · 20GB/u) + assert.match(rendered, /mem 512MB/u) + assert.match(rendered, /size 2cpu · 4GB · 20GB/u) assert.match(rendered, /gpu 1× A10 \$0\.0123/u) assert.match(rendered, /think high · caps vis 16k · reas 8\.2k · total 25k/u) assert.doesNotMatch(rendered, /fixture\/deterministic|thinking none|unknown|not reported/u) @@ -304,10 +304,7 @@ test('the wide rail shows only observed sandbox facts and measured usage', () => assert.match(medium, /pi \/ gpt-5\.6-luna/u) assert.match(medium, /via Sandbox/u) } - assert.doesNotMatch( - medium, - /host |machine |region |sample |requested |gpu |\bin |\bout |\$|latency /u, - ) + assert.doesNotMatch(medium, /host |machine |region |mem |size |gpu |\bin |\bout |\$|latency /u) assert.doesNotMatch(medium, /unknown|not reported|…/u) } for (const width of [40, 60, 80, 99, 100, 120, 160, 200]) { From 23aa14fffd141a2cbb92bc83c5c4134ece0dd026 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 08:03:31 -0600 Subject: [PATCH 15/25] chore(deps): migrate agent package cohort --- package.json | 10 ++-- pnpm-lock.yaml | 110 +++++++++++++++++++++++++------------------- pnpm-workspace.yaml | 14 +++--- 3 files changed, 74 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 804a74c..71d5b28 100644 --- a/package.json +++ b/package.json @@ -99,11 +99,11 @@ "@dataiku/uv": "0.12.0", "@earendil-works/pi-tui": "0.84.2", "@napi-rs/keyring": "1.3.0", - "@tangle-network/agent-eval": "0.145.15", - "@tangle-network/agent-interface": "0.53.0", - "@tangle-network/agent-provider-cli-bridge": "0.7.3", - "@tangle-network/agent-provider-tangle": "0.11.2", - "@tangle-network/agent-runtime": "0.135.3", + "@tangle-network/agent-eval": "0.145.21", + "@tangle-network/agent-interface": "1.0.0", + "@tangle-network/agent-provider-cli-bridge": "0.7.6", + "@tangle-network/agent-provider-tangle": "0.12.2", + "@tangle-network/agent-runtime": "file:/tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz", "@tangle-network/sandbox": "0.27.0", "better-sqlite3-multiple-ciphers": "13.0.3", "chalk": "6.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 472d125..4adccac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,20 +22,20 @@ importers: specifier: 1.3.0 version: 1.3.0 '@tangle-network/agent-eval': - specifier: 0.145.15 - version: 0.145.15 + specifier: 0.145.21 + version: 0.145.21 '@tangle-network/agent-interface': - specifier: 0.53.0 - version: 0.53.0 + specifier: 1.0.0 + version: 1.0.0 '@tangle-network/agent-provider-cli-bridge': - specifier: 0.7.3 - version: 0.7.3 + specifier: 0.7.6 + version: 0.7.6 '@tangle-network/agent-provider-tangle': - specifier: 0.11.2 - version: 0.11.2(@tangle-network/sandbox@0.27.0) + specifier: 0.12.2 + version: 0.12.2(@tangle-network/sandbox@0.27.0) '@tangle-network/agent-runtime': - specifier: 0.135.3 - version: 0.135.3(@tangle-network/agent-eval@0.145.15)(@tangle-network/agent-interface@0.53.0)(@tangle-network/sandbox@0.27.0) + specifier: file:/tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz + version: file:../../../../../tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz(@tangle-network/agent-eval@0.145.21)(@tangle-network/agent-interface@1.0.0)(@tangle-network/sandbox@0.27.0) '@tangle-network/sandbox': specifier: 0.27.0 version: 0.27.0 @@ -511,46 +511,55 @@ packages: '@modelcontextprotocol/sdk': optional: true - '@tangle-network/agent-eval@0.145.15': - resolution: {integrity: sha512-VTvbAqhVKpXWsNwASZNcMCmYWTdsXicR3i8yeHa/ViIv1Uo3496VqWXs2FRzkMxrOB6wOI0s5DEnxCZ3qaoRzA==} + '@tangle-network/agent-core@0.9.4': + resolution: {integrity: sha512-2iSPCHPKI/9A4t1XXPTbpaJTzf3BkwNzXOJfb3M7AMjpIGR1SKNiRHKpDTTEUVbfx4tRny5qDDMhCnFmKgPsHA==} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.30.0 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + + '@tangle-network/agent-eval@0.145.21': + resolution: {integrity: sha512-BeNIO8/+AJwQ8KYeJ1juqZT9gqQkaWwfLhX7KLQUo7LkRF++tBfulvARGesOpVHorx0fEkheJiyGMM5Tsx8IGQ==} engines: {node: '>=20'} hasBin: true '@tangle-network/agent-interface@0.53.0': resolution: {integrity: sha512-XWH+4t9vPkVog9C9P+094USuoO//TJwaI+P6ntAm32wHqZ/kh5a9r6kSkHYMKsXgQjkY3IA5NO21w3rZ7M6U+g==} - '@tangle-network/agent-interface@0.54.0': - resolution: {integrity: sha512-KBWcP2KQzroyjbhsG65OJecyt7AXIV0MWQuqkjUDiSac8Gtach4+oeYlBba6i9euA/8PhlGv9VBgVNiC2D/YuQ==} + '@tangle-network/agent-interface@1.0.0': + resolution: {integrity: sha512-rhXoscOE1TwkLvHg3tfqdumz++kcDRf7c5GRSTBnJkKLVypwvXB5yQJCB4aTUTrOCJxJMqowm2VPOmlTrUszOQ==} - '@tangle-network/agent-knowledge@8.0.1': - resolution: {integrity: sha512-H1zMyyNyVeTCijaPGMMbZX7QY7gjE1YyHEgtNtEJ9PgvTYNBuQSh938cIKNQBHM6MPB0Lq3xECgf9ELTVveTEQ==} + '@tangle-network/agent-knowledge@8.0.5': + resolution: {integrity: sha512-QMY16NSdy7aLxZZDejrb17hlUb6ejh4rg5Keg1TfA+FDMeIbyCaTSx6I/CFmK27TQq5aZ0RoIgaa1lZVc5rDRg==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: - '@tangle-network/agent-eval': '>=0.145.14 <0.146.0' - '@tangle-network/agent-interface': '>=0.53.0 <0.54.0' + '@tangle-network/agent-eval': '>=0.145.21 <0.146.0' + '@tangle-network/agent-interface': ^1.0.0 - '@tangle-network/agent-profile-materialize@0.15.1': - resolution: {integrity: sha512-+d6IvLnRurmNTpnGkiqBSHTXrFrXfFOjQQzeC74t9gl0+yZABOopqFibOAiX3njSy3WuHeZ04PpdFkZrz16Dvg==} + '@tangle-network/agent-profile-materialize@0.15.2': + resolution: {integrity: sha512-j9ld23ADJRbAIJEkQ0xk49+RYt47WzARquN5S3W5Pyb3rbD++gxf1AKJQ3O613wmkwdcc0V10a5jHruX0SZ1Vg==} peerDependencies: '@tangle-network/agent-interface': '>=0.47.0 <0.54.0' - '@tangle-network/agent-provider-cli-bridge@0.7.3': - resolution: {integrity: sha512-KEQ6Hypgvg69HKzjMAlnVjd05pmNgRhTc+1O0knJF8yHP22lEPK39opwna/56wDFQCjjHFwb98VxgJi21irx1Q==} + '@tangle-network/agent-provider-cli-bridge@0.7.6': + resolution: {integrity: sha512-/UlWHwBRcFVfIZUlZHrcr1PYEl+Uz7ldYi/NU5VLCi/SmcIeCpqJKgRXDXvtzI79YtyBjfBfjom6tVEDU8pZbQ==} - '@tangle-network/agent-provider-tangle@0.11.2': - resolution: {integrity: sha512-XXono31RQoANHclDQG/BvMvm7mbuUyMrOUmvJlfSbxhEfKQ8aZziOI6hMa7yPvYvQwCJISmML+3huE0ayksRAA==} + '@tangle-network/agent-provider-tangle@0.12.2': + resolution: {integrity: sha512-+cQscgYrUANqAFdOEXGvqC9WMQu3BJtlreYWGVtPseYQGOzZAOl+MyCzA9NR4wVQOgGrDxG/lkSazTRtlvPDKg==} peerDependencies: '@tangle-network/sandbox': '>=0.23.0 <1.0.0' - '@tangle-network/agent-runtime@0.135.3': - resolution: {integrity: sha512-w9DaLCHZum8h+G+PuGUxIzJgNbzk4pkC9ZSP8AkT1u25B+6y9vr/TsFtECMWqywc1W4MJ9ewouVCCkZa8cyXJg==} + '@tangle-network/agent-runtime@file:../../../../../tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz': + resolution: {integrity: sha512-QIb6bzfb5gn9qGeHKkjTHm24qyCtLXRJDVwNeR2NNmH0udf5LaZlmasD1ZOslrdXzCc2XaUOEljaHA/cLZqTwg==, tarball: file:../../../../../tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz} + version: 0.137.0 engines: {node: '>=22.13.0'} hasBin: true peerDependencies: - '@tangle-network/agent-eval': '>=0.145.15 <0.146.0' - '@tangle-network/agent-interface': '>=0.53.0 <0.54.0' - '@tangle-network/sandbox': '>=0.27.0 <0.28.0' + '@tangle-network/agent-eval': '>=0.145.21 <0.146.0' + '@tangle-network/agent-interface': '>=1.0.0 <2.0.0' + '@tangle-network/sandbox': '>=0.27.0 <0.29.0' peerDependenciesMeta: '@tangle-network/sandbox': optional: true @@ -1149,12 +1158,17 @@ snapshots: '@tangle-network/agent-interface': 0.53.0 zod: 4.4.3 - '@tangle-network/agent-eval@0.145.15': + '@tangle-network/agent-core@0.9.4': + dependencies: + '@tangle-network/agent-interface': 1.0.0 + zod: 4.4.3 + + '@tangle-network/agent-eval@0.145.21': dependencies: '@asteasolutions/zod-to-openapi': 9.1.0(zod@4.4.3) '@hono/node-server': 2.1.1(hono@4.13.0) - '@tangle-network/agent-core': 0.9.0 - '@tangle-network/agent-interface': 0.53.0 + '@tangle-network/agent-core': 0.9.4 + '@tangle-network/agent-interface': 1.0.0 '@tangle-network/agent-trace-contract': 1.0.2 hono: 4.13.0 linear-sum-assignment: 1.0.9 @@ -1169,40 +1183,40 @@ snapshots: spdx-expression-parse: 5.0.0 zod: 4.4.3 - '@tangle-network/agent-interface@0.54.0': + '@tangle-network/agent-interface@1.0.0': dependencies: '@noble/hashes': 1.8.0 spdx-expression-parse: 5.0.0 zod: 4.4.3 - '@tangle-network/agent-knowledge@8.0.1(@tangle-network/agent-eval@0.145.15)(@tangle-network/agent-interface@0.53.0)': + '@tangle-network/agent-knowledge@8.0.5(@tangle-network/agent-eval@0.145.21)(@tangle-network/agent-interface@1.0.0)': dependencies: - '@tangle-network/agent-eval': 0.145.15 - '@tangle-network/agent-interface': 0.53.0 + '@tangle-network/agent-eval': 0.145.21 + '@tangle-network/agent-interface': 1.0.0 proper-lockfile: 4.1.2 zod: 4.4.3 - '@tangle-network/agent-profile-materialize@0.15.1(@tangle-network/agent-interface@0.53.0)': + '@tangle-network/agent-profile-materialize@0.15.2(@tangle-network/agent-interface@1.0.0)': dependencies: - '@tangle-network/agent-interface': 0.53.0 + '@tangle-network/agent-interface': 1.0.0 - '@tangle-network/agent-provider-cli-bridge@0.7.3': + '@tangle-network/agent-provider-cli-bridge@0.7.6': dependencies: - '@tangle-network/agent-interface': 0.54.0 + '@tangle-network/agent-interface': 1.0.0 undici: 7.29.0 - '@tangle-network/agent-provider-tangle@0.11.2(@tangle-network/sandbox@0.27.0)': + '@tangle-network/agent-provider-tangle@0.12.2(@tangle-network/sandbox@0.27.0)': dependencies: - '@tangle-network/agent-interface': 0.54.0 + '@tangle-network/agent-interface': 1.0.0 '@tangle-network/sandbox': 0.27.0 - '@tangle-network/agent-runtime@0.135.3(@tangle-network/agent-eval@0.145.15)(@tangle-network/agent-interface@0.53.0)(@tangle-network/sandbox@0.27.0)': + '@tangle-network/agent-runtime@file:../../../../../tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz(@tangle-network/agent-eval@0.145.21)(@tangle-network/agent-interface@1.0.0)(@tangle-network/sandbox@0.27.0)': dependencies: - '@tangle-network/agent-core': 0.9.0 - '@tangle-network/agent-eval': 0.145.15 - '@tangle-network/agent-interface': 0.53.0 - '@tangle-network/agent-knowledge': 8.0.1(@tangle-network/agent-eval@0.145.15)(@tangle-network/agent-interface@0.53.0) - '@tangle-network/agent-profile-materialize': 0.15.1(@tangle-network/agent-interface@0.53.0) + '@tangle-network/agent-core': 0.9.4 + '@tangle-network/agent-eval': 0.145.21 + '@tangle-network/agent-interface': 1.0.0 + '@tangle-network/agent-knowledge': 8.0.5(@tangle-network/agent-eval@0.145.21)(@tangle-network/agent-interface@1.0.0) + '@tangle-network/agent-profile-materialize': 0.15.2(@tangle-network/agent-interface@1.0.0) '@tangle-network/agent-trace-contract': 1.0.2 tar-stream: 3.2.0 optionalDependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4de92a4..ac8970a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -10,12 +10,12 @@ allowBuilds: ignoreScripts: false minimumReleaseAgeExclude: - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5 || 0.134.9 || 0.135.0 || 0.135.3' - - '@tangle-network/agent-eval@0.143.0 || 0.144.0 || 0.144.1 || 0.144.3 || 0.144.4 || 0.144.6 || 0.144.8 || 0.144.10 || 0.144.11 || 0.144.13 || 0.145.0 || 0.145.1 || 0.145.2 || 0.145.3 || 0.145.9 || 0.145.10 || 0.145.11 || 0.145.14 || 0.145.15' - - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0 || 0.53.0 || 0.54.0' - - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0 || 8.0.1' - - '@tangle-network/agent-profile-materialize@0.10.2 || 0.13.1 || 0.14.0 || 0.14.2 || 0.15.1' - - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2 || 0.7.3' - - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0 || 0.11.0 || 0.11.1 || 0.11.2' + - '@tangle-network/agent-eval@0.143.0 || 0.144.0 || 0.144.1 || 0.144.3 || 0.144.4 || 0.144.6 || 0.144.8 || 0.144.10 || 0.144.11 || 0.144.13 || 0.145.0 || 0.145.1 || 0.145.2 || 0.145.3 || 0.145.9 || 0.145.10 || 0.145.11 || 0.145.14 || 0.145.15 || 0.145.21' + - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0 || 0.53.0 || 0.54.0 || 1.0.0' + - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0 || 8.0.1 || 8.0.5' + - '@tangle-network/agent-profile-materialize@0.10.2 || 0.13.1 || 0.14.0 || 0.14.2 || 0.15.1 || 0.15.2' + - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2 || 0.7.3 || 0.7.6' + - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0 || 0.11.0 || 0.11.1 || 0.11.2 || 0.12.2' - '@tangle-network/sandbox@0.17.3 || 0.18.0 || 0.19.2 || 0.19.3 || 0.19.4 || 0.19.5 || 0.19.6 || 0.21.0 || 0.21.1 || 0.26.1 || 0.27.0' - hono@4.13.0 - '@esbuild/aix-ppc64@0.28.2' @@ -45,5 +45,5 @@ minimumReleaseAgeExclude: - '@esbuild/win32-ia32@0.28.2' - '@esbuild/win32-x64@0.28.2' - esbuild@0.28.2 - - '@tangle-network/agent-core@0.5.4 || 0.6.0 || 0.6.1 || 0.7.1 || 0.8.0 || 0.8.1 || 0.9.0' + - '@tangle-network/agent-core@0.5.4 || 0.6.0 || 0.6.1 || 0.7.1 || 0.8.0 || 0.8.1 || 0.9.0 || 0.9.4' - '@earendil-works/pi-tui@0.84.2' From e479ab4e196fc36513588d8d873fad6c2392cd1b Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 08:02:04 -0600 Subject: [PATCH 16/25] chore(braid): migrate agent runtime dependency cohort --- src/adapters/analysis/runtime-model-owner.ts | 2 +- .../runtime/agent-runtime-execution.ts | 12 ++++--- test/cli-bridge-retained-restart.test.ts | 2 ++ test/connections.test.ts | 5 +-- test/retained-execution-lifecycle.test.ts | 3 ++ test/support/retained-run-capabilities.ts | 32 +++++++++++++++++++ test/trace-analysis-configuration.test.ts | 8 +++-- 7 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 test/support/retained-run-capabilities.ts diff --git a/src/adapters/analysis/runtime-model-owner.ts b/src/adapters/analysis/runtime-model-owner.ts index d2b1281..52f59cd 100644 --- a/src/adapters/analysis/runtime-model-owner.ts +++ b/src/adapters/analysis/runtime-model-owner.ts @@ -740,7 +740,7 @@ export function createRuntimeTraceModelOwner( }) for await (const event of streamAgentTurn( backend, - { messages }, + { prompt: JSON.stringify({ messages }) }, { signal: request.signal, callId: request.callId, diff --git a/src/adapters/runtime/agent-runtime-execution.ts b/src/adapters/runtime/agent-runtime-execution.ts index 7217f9f..a670b57 100644 --- a/src/adapters/runtime/agent-runtime-execution.ts +++ b/src/adapters/runtime/agent-runtime-execution.ts @@ -203,10 +203,14 @@ export class AgentRuntimeExecutionPort implements ExecutionPort { const { streamAgentTurn } = await import('@tangle-network/agent-runtime/kernel') try { let terminal: Extract | undefined - for await (const event of streamAgentTurn(runtimeBackend, input.text, { - signal: localAbort.signal, - preserveToolParts: true, - })) { + for await (const event of streamAgentTurn( + runtimeBackend, + { prompt: input.text }, + { + signal: localAbort.signal, + preserveToolParts: true, + }, + )) { if (event.type === 'final') terminal = event else yield event } diff --git a/test/cli-bridge-retained-restart.test.ts b/test/cli-bridge-retained-restart.test.ts index 7eaec88..69dcad2 100644 --- a/test/cli-bridge-retained-restart.test.ts +++ b/test/cli-bridge-retained-restart.test.ts @@ -29,6 +29,7 @@ import { type RetainedRunAdmissionRecord, } from '../src/ports/execution.js' import { RandomIds } from '../src/ports/ids.js' +import { RETAINED_RUN_HANDLE_CAPABILITIES } from './support/retained-run-capabilities.js' import { startRuntimeBridgeServer } from './support/runtime-bridge-server.js' const now = '2026-08-11T12:00:00.000Z' @@ -131,6 +132,7 @@ async function waitFor(predicate: () => boolean, timeoutMs = 2_000): Promise ({ diff --git a/test/support/retained-run-capabilities.ts b/test/support/retained-run-capabilities.ts new file mode 100644 index 0000000..7f4508b --- /dev/null +++ b/test/support/retained-run-capabilities.ts @@ -0,0 +1,32 @@ +import type { AgentEnvironmentCapabilities } from '@tangle-network/agent-interface' + +export const RETAINED_RUN_HANDLE_CAPABILITIES: AgentEnvironmentCapabilities = { + profile: { + namedProfiles: false, + systemPrompt: { replace: false, append: false }, + instructions: false, + tools: false, + permissions: false, + mcp: false, + subagents: false, + resources: { + files: false, + instructions: false, + tools: false, + skills: false, + agents: false, + commands: false, + }, + hooks: false, + modes: false, + runtimeUpdate: false, + validation: false, + }, + streaming: { live: true, replay: false, detach: false, turnIdempotency: true }, + sessions: { continue: false, list: false, messages: false }, + workspace: { read: false, write: false, exec: false, git: false, upload: false, download: false }, + branching: { checkpoint: false, fork: false }, + placement: false, + usage: false, + confidential: true, +} diff --git a/test/trace-analysis-configuration.test.ts b/test/trace-analysis-configuration.test.ts index 034af93..c935eaa 100644 --- a/test/trace-analysis-configuration.test.ts +++ b/test/trace-analysis-configuration.test.ts @@ -582,8 +582,10 @@ test('runtime-owned trace model call preserves canonical messages, limits, usage if (!result.succeeded) return assert.equal(receivedAuthorization, 'Bearer credential-never-recorded') assert.deepEqual(receivedBody?.messages, [ - { role: 'system', content: 'private analyst instruction' }, - { role: 'user', content: 'private trace question' }, + { + role: 'user', + content: JSON.stringify({ messages: optimizerRequest().request.messages }), + }, ]) assert.equal(receivedBody?.max_tokens, undefined) assert.equal(receivedBody?.temperature, 0.2) @@ -675,7 +677,7 @@ test('runtime-owned CLI Bridge analysis uses the harness executor with portable assert.equal(bridge.requests.length, 1) assert.deepEqual( admissions.map((admission) => admission.phase), - ['environment', 'dispatched'], + ['intent', 'environment', 'dispatched'], ) const body = bridge.requests[0]?.body assert.equal(body?.model, 'pi/tangle-router/glm-5.2') From 89bf37874371f92a2d4d8af6c1f38c567c91c78b Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 08:39:37 -0600 Subject: [PATCH 17/25] feat(tui): open durable native interactive sessions --- scripts/run-tests.mjs | 3 + .../runtime/native-interactive-run-broker.ts | 125 ++++++++ src/adapters/tui/ui-capabilities.ts | 2 + src/app/analysis-retained-admission.ts | 27 +- src/app/application-support.ts | 2 + src/app/application-types.ts | 2 + src/app/effective-run-configuration.ts | 3 +- src/app/run-recovery-context.ts | 16 + src/app/run-replay.ts | 11 + src/bin/interface-runner.ts | 21 ++ src/bin/native-interactive-actions.ts | 232 +++++++++++++++ src/bin/production-setup-transition.ts | 2 + src/domain/invariants-retained-admission.ts | 132 +++++++-- src/domain/reducer-retained-admission.ts | 171 +++++++++-- src/domain/run-contracts.ts | 27 +- src/index.ts | 10 + src/ports/execution.ts | 13 +- src/ports/native-interactive-execution.ts | 15 + src/ports/native-interactive-ui.ts | 35 +++ src/views/shared/command-registry.ts | 18 ++ src/views/shared/command-table.ts | 12 + src/views/tui/terminal-app.ts | 21 +- src/views/tui/terminal-command-controller.ts | 47 +++ test/domain-reducer.test.ts | 29 +- test/native-interactive-actions.test.ts | 278 ++++++++++++++++++ test/native-interactive-command.test.ts | 91 ++++++ test/native-interactive-run-broker.test.ts | 36 +++ test/scripts.test.ts | 3 + 28 files changed, 1277 insertions(+), 107 deletions(-) create mode 100644 src/adapters/runtime/native-interactive-run-broker.ts create mode 100644 src/app/run-recovery-context.ts create mode 100644 src/bin/native-interactive-actions.ts create mode 100644 src/ports/native-interactive-execution.ts create mode 100644 src/ports/native-interactive-ui.ts create mode 100644 test/native-interactive-actions.test.ts create mode 100644 test/native-interactive-command.test.ts create mode 100644 test/native-interactive-run-broker.test.ts diff --git a/scripts/run-tests.mjs b/scripts/run-tests.mjs index c2c882b..ce0c8ff 100644 --- a/scripts/run-tests.mjs +++ b/scripts/run-tests.mjs @@ -47,6 +47,8 @@ const scopeFiles = { 'domain-reducer.test.js', 'domain-text.test.js', 'eval.test.js', + 'native-interactive-actions.test.js', + 'native-interactive-run-broker.test.js', 'observability.test.js', 'plain-accessibility.test.js', 'property.test.js', @@ -97,6 +99,7 @@ const scopeFiles = { 'configuration-product-flow.test.js', 'intelligence-dispatch.test.js', 'keyboard.test.js', + 'native-interactive-command.test.js', 'terminal-responsive.test.js', 'terminal-usage-status.test.js', 'tui-autocomplete.test.js', diff --git a/src/adapters/runtime/native-interactive-run-broker.ts b/src/adapters/runtime/native-interactive-run-broker.ts new file mode 100644 index 0000000..1b0361d --- /dev/null +++ b/src/adapters/runtime/native-interactive-run-broker.ts @@ -0,0 +1,125 @@ +import type { RetainedInteractiveRunHandle } from '@tangle-network/agent-runtime/kernel' +import type { + NativeInteractiveExecutionControl, + NativeInteractiveRunOutcome, +} from '../../ports/native-interactive-execution.js' + +interface Deferred { + readonly promise: Promise + readonly resolve: (value: T) => void + readonly reject: (error: unknown) => void + settled: boolean +} + +interface BrokerEntry { + readonly handle: Deferred + readonly outcome: Deferred + opened: boolean +} + +export interface NativeInteractiveRunLease { + publish(handle: RetainedInteractiveRunHandle): void + outcome(options?: { readonly signal?: AbortSignal }): Promise + fail(error: unknown): void + close(): void +} + +/** One in-memory rendezvous only; Runtime and Braid's journal remain the durable owners. */ +export class NativeInteractiveRunBroker implements NativeInteractiveExecutionControl { + readonly #entries = new Map() + + open(runId: string): NativeInteractiveRunLease { + const entry = this.#entry(runId) + if (entry.opened) throw new Error(`Interactive run ${runId} already has an active execution`) + entry.opened = true + let closed = false + return Object.freeze({ + publish: (handle: RetainedInteractiveRunHandle) => { + if (closed) throw new Error(`Interactive run ${runId} execution is closed`) + entry.handle.resolve(handle) + }, + outcome: (options?: { readonly signal?: AbortSignal }) => + abortable(entry.outcome.promise, options?.signal), + fail: (error: unknown) => { + entry.handle.reject(asError(error)) + entry.outcome.reject(asError(error)) + }, + close: () => { + if (closed) return + closed = true + entry.handle.reject(new Error(`Interactive run ${runId} ended before terminal attach`)) + entry.outcome.reject(new Error(`Interactive run ${runId} ended without a terminal outcome`)) + if (this.#entries.get(runId) === entry) this.#entries.delete(runId) + }, + }) + } + + waitForHandle( + runId: string, + options?: { readonly signal?: AbortSignal }, + ): Promise { + return abortable(this.#entry(runId).handle.promise, options?.signal) + } + + settle(runId: string, outcome: NativeInteractiveRunOutcome): void { + const entry = this.#entries.get(runId) + if (entry === undefined || !entry.opened) { + throw new Error(`Interactive run ${runId} has no active execution`) + } + if (entry.outcome.settled) { + throw new Error(`Interactive run ${runId} already has a terminal outcome`) + } + entry.outcome.resolve(structuredClone(outcome)) + } + + #entry(runId: string): BrokerEntry { + if (runId.trim().length === 0) throw new Error('Interactive run id must not be empty') + const current = this.#entries.get(runId) + if (current !== undefined) return current + const entry: BrokerEntry = { + handle: deferred(), + outcome: deferred(), + opened: false, + } + this.#entries.set(runId, entry) + return entry + } +} + +function deferred(): Deferred { + let resolvePromise: (value: T) => void = () => {} + let rejectPromise: (error: unknown) => void = () => {} + const value: Deferred = { + promise: new Promise((resolve, reject) => { + resolvePromise = resolve + rejectPromise = reject + }), + resolve: (next) => { + if (value.settled) return + value.settled = true + resolvePromise(next) + }, + reject: (error) => { + if (value.settled) return + value.settled = true + rejectPromise(error) + }, + settled: false, + } + void value.promise.catch(() => undefined) + return value +} + +function asError(error: unknown): Error { + return error instanceof Error ? error : new Error(String(error)) +} + +async function abortable(promise: Promise, signal?: AbortSignal): Promise { + signal?.throwIfAborted() + if (signal === undefined) return promise + return new Promise((resolve, reject) => { + const abort = (): void => reject(signal.reason) + signal.addEventListener('abort', abort, { once: true }) + void promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', abort)) + }) +} diff --git a/src/adapters/tui/ui-capabilities.ts b/src/adapters/tui/ui-capabilities.ts index 7c71228..20f3372 100644 --- a/src/adapters/tui/ui-capabilities.ts +++ b/src/adapters/tui/ui-capabilities.ts @@ -16,6 +16,8 @@ export const UNSUPPORTED = Object.freeze({ 'analysis.compare': 'Comparisons require the current agent-eval adapter', 'interaction.respond': 'Interaction response is not exposed by the current runtime adapter', 'interaction.automation': 'Interaction automation requires the shared response contract', + 'run.interactive': 'Native terminal mode requires an interactive TUI and a supported provider', + 'run.attach': 'Native terminal attachment requires an interactive TUI and a retained session', 'export.create': 'Redacted export is not exposed by the current storage adapter', } satisfies Readonly>) diff --git a/src/app/analysis-retained-admission.ts b/src/app/analysis-retained-admission.ts index c4542c2..d5fa405 100644 --- a/src/app/analysis-retained-admission.ts +++ b/src/app/analysis-retained-admission.ts @@ -1,4 +1,4 @@ -import { canonicalDigest } from '../domain/canonical.js' +import { canonicalDigest, canonicalJson } from '../domain/canonical.js' import type { JsonValue } from '../domain/entities-base.js' import type { RetainedRunAdmissionRecord } from '../domain/run-contracts.js' import { @@ -16,30 +16,7 @@ function isJsonObject(value: unknown): value is Readonly readonly BraidEventEnvelope[] @@ -278,6 +279,7 @@ async function reconcileRestartSnapshot(context: RestartPort, runId: string): Pr runId, ...(run.providerSessionId === undefined ? {} : { providerSessionId: run.providerSessionId }), ...(run.controlRef === undefined ? {} : { controlRef: run.controlRef }), + ...retainedExecutionRecoveryContext(run, context.currentState().workspace), }) } catch { await markRestartReconnecting(context, runId) diff --git a/src/app/application-types.ts b/src/app/application-types.ts index 7b99972..6871c98 100644 --- a/src/app/application-types.ts +++ b/src/app/application-types.ts @@ -13,6 +13,8 @@ export type AppSubscriber = (state: BraidState, envelope: BraidEventEnvelope) => export interface SendInput { readonly operationId: string readonly text: string + /** One-run execution mode override. It does not mutate the branch selection. */ + readonly mode?: string readonly conversationId?: string readonly branchId?: string readonly sessionId?: string diff --git a/src/app/effective-run-configuration.ts b/src/app/effective-run-configuration.ts index b8906a0..bded418 100644 --- a/src/app/effective-run-configuration.ts +++ b/src/app/effective-run-configuration.ts @@ -37,7 +37,7 @@ export function selectedRunConfiguration( export function effectiveRunConfiguration( state: BraidState, authoredProfile: Readonly, - input: Pick, + input: Pick, ): EffectiveRunConfiguration { const conversationId = parseConversationId(input.conversationId ?? state.conversationId) const conversation = state.conversations.find( @@ -53,6 +53,7 @@ export function effectiveRunConfiguration( throw new AppError('UNKNOWN_BRANCH', 'The requested branch is unavailable') const resolved = resolveEffectiveProfile({ profile: { profile: authoredProfile }, + ...(input.mode === undefined ? {} : { nextRunOverrides: { mode: input.mode } }), branchOverrides: { ...(branch.overrides.runner === undefined ? {} : { harness: branch.overrides.runner }), ...(branch.overrides.model === undefined ? {} : { model: branch.overrides.model }), diff --git a/src/app/run-recovery-context.ts b/src/app/run-recovery-context.ts new file mode 100644 index 0000000..6038f88 --- /dev/null +++ b/src/app/run-recovery-context.ts @@ -0,0 +1,16 @@ +import type { RunRecord } from '../domain/entities.js' +import type { RetainedExecutionRecoveryContext } from '../ports/execution.js' + +/** Snapshot the public run material a provider needs to recover after process loss. */ +export function retainedExecutionRecoveryContext( + run: RunRecord, + workspaceRoot: string | null, +): RetainedExecutionRecoveryContext { + return { + ...(run.retainedAdmission === undefined + ? {} + : { retainedAdmission: structuredClone(run.retainedAdmission) }), + receipt: structuredClone(run.receipt), + ...(workspaceRoot === null ? {} : { workspaceRoot }), + } +} diff --git a/src/app/run-replay.ts b/src/app/run-replay.ts index 0c2fd0e..5d898c6 100644 --- a/src/app/run-replay.ts +++ b/src/app/run-replay.ts @@ -4,6 +4,7 @@ import type { ProviderRunSnapshot } from '../ports/execution.js' import type { ReconnectInput, ReplayPort } from './application-ports.js' import { AppError } from './errors.js' import { safeSnapshotDetail, safeSnapshotText, safeSnapshotUsage } from './provider-snapshot.js' +import { retainedExecutionRecoveryContext } from './run-recovery-context.js' interface RecoveryReconnectInput extends ReconnectInput { readonly priorFailureDetail?: string @@ -41,6 +42,15 @@ export async function reconnectRun( afterSequence: run.lastProviderSequence, ...(run.providerSessionId === undefined ? {} : { providerSessionId: run.providerSessionId }), ...(run.controlRef === undefined ? {} : { controlRef: run.controlRef }), + ...retainedExecutionRecoveryContext(run, context.currentState().workspace), + onRetainedAdmission: async (admission) => { + const committed = context.commitAndWait({ + kind: 'run.retained.admitted', + runId: run.id, + admission, + }) + if (committed !== undefined) await committed + }, signal: abort.signal, })) { const result = await context.ingestRuntimeEvent(envelope) @@ -88,6 +98,7 @@ export async function reconcileRun( runId: run.id, ...(run.providerSessionId === undefined ? {} : { providerSessionId: run.providerSessionId }), ...(run.controlRef === undefined ? {} : { controlRef: run.controlRef }), + ...retainedExecutionRecoveryContext(run, context.currentState().workspace), }) } catch (error) { if (!context.isTerminal(run.status)) diff --git a/src/bin/interface-runner.ts b/src/bin/interface-runner.ts index c4d9bb6..9809157 100644 --- a/src/bin/interface-runner.ts +++ b/src/bin/interface-runner.ts @@ -22,6 +22,7 @@ import type { CliOptions } from './args.js' import { createInterfaceSignalLifecycle } from './interface-signal-lifecycle.js' import { recordInterfaceState } from './interface-state-recorder.js' import { runPlain } from './plain.js' +import { createNativeInteractiveUiActions } from './native-interactive-actions.js' import { activateProductionConnection, productionConfigForSelection, @@ -205,6 +206,23 @@ export async function runInterface(input: InterfaceRunnerInput): Promise }) } } + const nativeLifecycle: { + view?: BraidTerminalApp + signals?: ReturnType + } = {} + const nativeInteractive = createNativeInteractiveUiActions({ + current: () => active.current, + terminal: tui.terminal, + signals: () => { + if (nativeLifecycle.signals === undefined) + throw new Error('Terminal signal ownership is not initialized') + return nativeLifecycle.signals + }, + suspend: () => nativeLifecycle.view?.suspend(), + resume: () => nativeLifecycle.view?.resume(), + nextOperationId, + holderId: `braid-terminal-${randomUUID()}`, + }) const view = new BraidTerminalApp({ controller, tui, @@ -222,7 +240,9 @@ export async function runInterface(input: InterfaceRunnerInput): Promise ...(input.startupPreview?.outputPolicyCleanup === undefined ? {} : { preinstalledOutputPolicyCleanup: input.startupPreview.outputPolicyCleanup }), + nativeInteractive, }) + nativeLifecycle.view = view const signals = createInterfaceSignalLifecycle({ controller, view, @@ -231,6 +251,7 @@ export async function runInterface(input: InterfaceRunnerInput): Promise ...(options.recordState === undefined ? {} : { recordState: options.recordState }), ...(input.startupPreview === undefined ? {} : { startupPreview: input.startupPreview }), }) + nativeLifecycle.signals = signals try { if (!signals.interrupted()) { const startupInput = input.startupPreview?.adopt().input ?? [] diff --git a/src/bin/native-interactive-actions.ts b/src/bin/native-interactive-actions.ts new file mode 100644 index 0000000..790b5b8 --- /dev/null +++ b/src/bin/native-interactive-actions.ts @@ -0,0 +1,232 @@ +import type { AgentInteractiveTerminalSession } from '@tangle-network/agent-interface' +import { claimRetainedInteractiveControl } from '@tangle-network/agent-runtime/kernel' +import { createNativeTerminalTransport } from '../adapters/tui/native-terminal-transport.js' +import type { BraidApplication } from '../app/application.js' +import type { BraidRun } from '../domain/state.js' +import type { NativeInteractiveExecutionControl } from '../ports/native-interactive-execution.js' +import type { + NativeInteractiveAvailability, + NativeInteractiveCommand, + NativeInteractiveCommandResult, + NativeInteractiveUiActions, +} from '../ports/native-interactive-ui.js' +import type { + NativeTerminalHost, + NativeTerminalSignalPort, + NativeTerminalTransportResult, +} from '../ports/native-terminal-transport.js' + +interface InteractiveApplicationHandle { + readonly app: Pick + readonly nativeInteractive?: NativeInteractiveExecutionControl +} + +export interface NativeInteractiveActionsOptions { + readonly current: () => InteractiveApplicationHandle + readonly terminal: NativeTerminalHost + readonly signals: () => NativeTerminalSignalPort + readonly suspend: () => void + readonly resume: () => void + readonly nextOperationId: () => string + readonly holderId: string +} + +/** Coordinates one terminal viewer. Runtime and the application retain all durable state. */ +export function createNativeInteractiveUiActions( + options: NativeInteractiveActionsOptions, +): NativeInteractiveUiActions { + let busy = false + const actions: NativeInteractiveUiActions = { + availability: (action: NativeInteractiveCommand['action']) => + availability(options.current(), action, busy), + run: async (command: NativeInteractiveCommand): Promise => { + if (busy) return { kind: 'unavailable', reason: 'A native terminal is already open' } + const available = availability(options.current(), command.action, false) + if (!available.available) { + return { kind: 'unavailable', reason: available.reason ?? 'Native terminal unavailable' } + } + busy = true + try { + return await runCommand(options, command) + } catch (error) { + return { kind: 'error', message: errorMessage(error) } + } finally { + busy = false + } + }, + } + return Object.freeze(actions) +} + +function availability( + current: InteractiveApplicationHandle, + action: NativeInteractiveCommand['action'], + busy: boolean, +): NativeInteractiveAvailability { + if (busy) return { available: false, reason: 'A native terminal is already open' } + if (current.nativeInteractive === undefined) { + return { + available: false, + reason: 'Select a retained Tangle Sandbox connection with native terminal support', + } + } + const state = current.app.state() + if (action === 'start') { + return state.activeRunId === null + ? { available: true } + : { available: false, reason: 'Detach or finish the active run first' } + } + return latestAttachableRun(state.runs) === undefined + ? { available: false, reason: 'No retained native session is available' } + : { available: true } +} + +async function runCommand( + options: NativeInteractiveActionsOptions, + command: NativeInteractiveCommand, +): Promise { + const current = options.current() + const execution = current.nativeInteractive + if (execution === undefined) { + return { kind: 'unavailable', reason: 'Native terminal support is unavailable' } + } + if (command.action === 'start') { + const prompt = command.initialPrompt?.trim() + if (!prompt) return { kind: 'error', message: 'Usage: /interactive ' } + const receipt = current.app.send({ + operationId: options.nextOperationId(), + text: prompt, + mode: 'interactive', + }) + await receipt.admissionReady + return present(options, current, execution, receipt.runId, receipt.completion) + } + + const runId = command.runId ?? latestAttachableRun(current.app.state().runs)?.id + if (runId === undefined) { + return { kind: 'unavailable', reason: 'No retained native session is available' } + } + const run = current.app.state().runs.find((candidate) => candidate.id === runId) + if (run === undefined || !isInteractiveRun(run)) { + return { kind: 'error', message: `Run ${runId} is not a retained native session` } + } + const reconnect = current.app.reconnectRun({ + operationId: options.nextOperationId(), + runId, + }) + return present(options, current, execution, runId, reconnect) +} + +async function present( + options: NativeInteractiveActionsOptions, + current: InteractiveApplicationHandle, + execution: NativeInteractiveExecutionControl, + runId: string, + runCompletion: Promise, +): Promise { + void runCompletion.catch(() => undefined) + const handle = await execution.waitForHandle(runId) + let terminalSession: AgentInteractiveTerminalSession + try { + const control = await claimRetainedInteractiveControl({ + handle, + holderId: options.holderId, + }) + terminalSession = await handle.attach({ + control, + cols: positiveDimension(options.terminal.columns), + rows: positiveDimension(options.terminal.rows), + }) + } catch (error) { + await detachAfterViewerFailure(current.app, runId, options.nextOperationId, error) + throw error + } + + options.suspend() + let result: NativeTerminalTransportResult + try { + result = await createNativeTerminalTransport({ + session: terminalSession, + terminal: options.terminal, + signals: options.signals(), + }).run() + } finally { + options.resume() + } + + const outcome = result.outcome + if (outcome.kind === 'remote-exit') { + execution.settle(runId, { + kind: 'exited', + ...(outcome.exitCode === undefined ? {} : { exitCode: outcome.exitCode }), + ...(outcome.exitSignal === undefined ? {} : { exitSignal: outcome.exitSignal }), + }) + await runCompletion + const cleanup = cleanupMessage(result) + return cleanup === undefined + ? { kind: 'returned', runId, outcome: 'exited' } + : { kind: 'error', message: cleanup } + } + + await current.app.detachRun({ operationId: options.nextOperationId(), runId }) + await runCompletion.catch(() => undefined) + if (outcome.kind === 'detached') { + const cleanup = cleanupMessage(result) + return cleanup === undefined + ? { kind: 'returned', runId, outcome: 'detached' } + : { kind: 'error', message: cleanup } + } + return { + kind: 'error', + message: + outcome.kind === 'transport-error' + ? `Native terminal ${outcome.phase} failed: ${outcome.message}` + : 'Native terminal closed after an interrupt', + } +} + +async function detachAfterViewerFailure( + app: InteractiveApplicationHandle['app'], + runId: string, + nextOperationId: () => string, + original: unknown, +): Promise { + try { + await app.detachRun({ operationId: nextOperationId(), runId }) + } catch (detachError) { + throw new Error( + `${errorMessage(original)}; the retained run could not be detached: ${errorMessage(detachError)}`, + { cause: original }, + ) + } +} + +function latestAttachableRun(runs: readonly BraidRun[]): BraidRun | undefined { + for (let index = runs.length - 1; index >= 0; index -= 1) { + const run = runs[index] + if (run !== undefined && isInteractiveRun(run) && attachableStatus(run.status)) return run + } + return undefined +} + +function isInteractiveRun(run: BraidRun): boolean { + return run.retainedAdmission?.phase.startsWith('interactive_') === true +} + +function attachableStatus(status: BraidRun['status']): boolean { + return !['completed', 'failed', 'aborted', 'cancelled', 'blocked', 'expired'].includes(status) +} + +function positiveDimension(value: number): number { + return Number.isInteger(value) && value > 0 ? value : 1 +} + +function cleanupMessage(result: NativeTerminalTransportResult): string | undefined { + if (result.cleanup.issues.length === 0) return undefined + return result.cleanup.issues.map((issue) => `${issue.phase}: ${issue.message}`).join('; ') +} + +function errorMessage(error: unknown): string { + const message = error instanceof Error ? error.message : String(error) + return message.length > 512 ? `${message.slice(0, 509)}...` : message +} diff --git a/src/bin/production-setup-transition.ts b/src/bin/production-setup-transition.ts index 7388272..90c0678 100644 --- a/src/bin/production-setup-transition.ts +++ b/src/bin/production-setup-transition.ts @@ -1,6 +1,7 @@ import type { BraidApplication } from '../app/application.js' import type { ConnectionRegistry } from '../app/connections.js' import type { ConfigurationSelection } from '../app/configuration-session.js' +import type { NativeInteractiveExecutionControl } from '../ports/native-interactive-execution.js' import { prepareProductionSelection } from './production-setup-credentials.js' import { type ProductionStartupPersistence, @@ -16,6 +17,7 @@ import type { ProductionStartupLoadOptions } from './production-startup.js' export interface ProductionApplicationHandle { readonly app: BraidApplication readonly connections?: ConnectionRegistry + readonly nativeInteractive?: NativeInteractiveExecutionControl readonly close: () => Promise } diff --git a/src/domain/invariants-retained-admission.ts b/src/domain/invariants-retained-admission.ts index f3689f4..aabca83 100644 --- a/src/domain/invariants-retained-admission.ts +++ b/src/domain/invariants-retained-admission.ts @@ -1,46 +1,118 @@ -import { AgentExactRunControlRefSchema } from '@tangle-network/agent-interface' -import type { RunRecord } from './entities.js' +import { + AgentExactRunControlRefSchema, + AgentInteractiveSessionRefSchema, + AgentInteractiveSessionStartSchema, +} from '@tangle-network/agent-interface' import { canonicalDigest } from './canonical.js' +import type { RunRecord } from './entities.js' import { fail, nonEmpty } from './invariants-base.js' function assertControlRef(value: unknown, label: string): void { if (!AgentExactRunControlRefSchema.safeParse(value).success) fail(`${label} is invalid`) } +function assertProviderSession(record: RunRecord, sessionId: string): void { + if (record.providerSessionId !== undefined && sessionId !== record.providerSessionId) { + fail('run.retainedAdmission session must match run.providerSessionId') + } +} + +function assertNoControlRef(record: RunRecord, phase: string): void { + if (record.controlRef !== undefined) { + fail(`run.controlRef is invalid during retained ${phase} admission`) + } +} + +function assertStoredControlRef(record: RunRecord, value: unknown): void { + assertControlRef(value, 'run.retainedAdmission.controlRef') + if (record.controlRef === undefined) fail('run.controlRef is required after retained start') + if (canonicalDigest(value) !== canonicalDigest(record.controlRef)) { + fail('run.controlRef must match run.retainedAdmission control reference') + } +} + export function assertRetainedRunAdmission(record: RunRecord): void { const admission = record.retainedAdmission if (admission === undefined) return nonEmpty(admission.idempotencyKey, 'run.retainedAdmission.idempotencyKey') - nonEmpty(admission.turnId, 'run.retainedAdmission.turnId') - if (admission.phase === 'environment') { - nonEmpty(admission.provider, 'run.retainedAdmission.provider') - nonEmpty(admission.environmentId, 'run.retainedAdmission.environmentId') - nonEmpty(admission.sessionId, 'run.retainedAdmission.sessionId') - nonEmpty(admission.executionId, 'run.retainedAdmission.executionId') - if ( - record.providerSessionId !== undefined && - admission.sessionId !== record.providerSessionId - ) { - fail('run.retainedAdmission.sessionId must match run.providerSessionId') + switch (admission.phase) { + case 'intent': + nonEmpty(admission.provider, 'run.retainedAdmission.provider') + nonEmpty(admission.turnId, 'run.retainedAdmission.turnId') + nonEmpty(admission.sessionId, 'run.retainedAdmission.sessionId') + nonEmpty(admission.executionId, 'run.retainedAdmission.executionId') + nonEmpty(admission.runId, 'run.retainedAdmission.runId') + nonEmpty(admission.requestedProfileDigest, 'run.retainedAdmission.requestedProfileDigest') + nonEmpty(admission.requestDigest, 'run.retainedAdmission.requestDigest') + assertProviderSession(record, admission.sessionId) + assertNoControlRef(record, admission.phase) + return + case 'environment': + nonEmpty(admission.provider, 'run.retainedAdmission.provider') + nonEmpty(admission.environmentId, 'run.retainedAdmission.environmentId') + nonEmpty(admission.turnId, 'run.retainedAdmission.turnId') + nonEmpty(admission.sessionId, 'run.retainedAdmission.sessionId') + nonEmpty(admission.executionId, 'run.retainedAdmission.executionId') + assertProviderSession(record, admission.sessionId) + if ( + record.controlRef !== undefined && + (admission.provider !== record.controlRef.provider || + admission.environmentId !== record.controlRef.environmentId || + admission.sessionId !== record.controlRef.sessionId || + admission.executionId !== record.controlRef.executionId) + ) { + fail('run.controlRef must match run.retainedAdmission recovery coordinates') + } + return + case 'dispatched': + nonEmpty(admission.turnId, 'run.retainedAdmission.turnId') + assertProviderSession(record, admission.controlRef.sessionId) + assertStoredControlRef(record, admission.controlRef) + return + case 'interactive_intent': + nonEmpty(admission.provider, 'run.retainedAdmission.provider') + nonEmpty( + admission.interactiveIdempotencyKey, + 'run.retainedAdmission.interactiveIdempotencyKey', + ) + nonEmpty(admission.sessionId, 'run.retainedAdmission.sessionId') + nonEmpty(admission.executionId, 'run.retainedAdmission.executionId') + nonEmpty(admission.runId, 'run.retainedAdmission.runId') + nonEmpty(admission.requestedProfileDigest, 'run.retainedAdmission.requestedProfileDigest') + nonEmpty(admission.requestDigest, 'run.retainedAdmission.requestDigest') + assertProviderSession(record, admission.sessionId) + assertNoControlRef(record, admission.phase) + return + case 'interactive_environment': { + nonEmpty(admission.provider, 'run.retainedAdmission.provider') + nonEmpty(admission.environmentId, 'run.retainedAdmission.environmentId') + nonEmpty( + admission.interactiveIdempotencyKey, + 'run.retainedAdmission.interactiveIdempotencyKey', + ) + const request = AgentInteractiveSessionStartSchema.safeParse(admission.request) + if (!request.success) fail('run.retainedAdmission.request is invalid') + if ( + request.data.run.provider !== admission.provider || + request.data.run.environmentId !== admission.environmentId + ) { + fail('run.retainedAdmission.request must match its environment') + } + assertProviderSession(record, request.data.run.sessionId) + assertNoControlRef(record, admission.phase) + return } - if ( - record.controlRef !== undefined && - (admission.provider !== record.controlRef.provider || - admission.environmentId !== record.controlRef.environmentId || - admission.sessionId !== record.controlRef.sessionId || - admission.executionId !== record.controlRef.executionId) - ) { - fail('run.controlRef must match run.retainedAdmission recovery coordinates') + case 'interactive_started': { + nonEmpty( + admission.interactiveIdempotencyKey, + 'run.retainedAdmission.interactiveIdempotencyKey', + ) + const ref = AgentInteractiveSessionRefSchema.safeParse(admission.ref) + if (!ref.success) fail('run.retainedAdmission.ref is invalid') + assertProviderSession(record, ref.data.run.sessionId) + assertStoredControlRef(record, ref.data.run) + return } - return - } - - assertControlRef(admission.controlRef, 'run.retainedAdmission.controlRef') - if (record.controlRef === undefined) { - fail('run.controlRef is required after retained dispatch admission') - } - if (canonicalDigest(admission.controlRef) !== canonicalDigest(record.controlRef)) { - fail('run.controlRef must match run.retainedAdmission.controlRef') } } diff --git a/src/domain/reducer-retained-admission.ts b/src/domain/reducer-retained-admission.ts index c65e915..d98d0cf 100644 --- a/src/domain/reducer-retained-admission.ts +++ b/src/domain/reducer-retained-admission.ts @@ -1,3 +1,4 @@ +import { agentInteractiveSessionRefMatchesStart } from '@tangle-network/agent-interface' import { canonicalDigest } from './canonical.js' import type { BraidEvent } from './events.js' import { DomainInvariantError } from './invariants.js' @@ -6,11 +7,58 @@ import type { BraidState } from './state.js' type RetainedAdmissionEvent = Extract type Admission = RetainedAdmissionEvent['admission'] - function sameAdmission(left: Admission, right: Admission): boolean { return canonicalDigest(left) === canonicalDigest(right) } +function admissionFamily(admission: Admission): 'headless' | 'interactive' { + return admission.phase.startsWith('interactive_') ? 'interactive' : 'headless' +} + +function admissionSessionId(admission: Admission): string { + switch (admission.phase) { + case 'intent': + case 'environment': + case 'interactive_intent': + return admission.sessionId + case 'dispatched': + return admission.controlRef.sessionId + case 'interactive_environment': + return admission.request.run.sessionId + case 'interactive_started': + return admission.ref.run.sessionId + } +} + +function admissionRank(admission: Admission): number { + switch (admission.phase) { + case 'intent': + case 'interactive_intent': + return 0 + case 'environment': + case 'interactive_environment': + return 1 + case 'dispatched': + case 'interactive_started': + return 2 + } +} + +function assertIntentMatchesEnvironment( + intent: Extract, + environment: Extract, +): void { + if ( + intent.provider !== environment.provider || + intent.idempotencyKey !== environment.idempotencyKey || + intent.turnId !== environment.turnId || + intent.sessionId !== environment.sessionId || + intent.executionId !== environment.executionId + ) { + throw new DomainInvariantError('Retained environment conflicts with its intent admission') + } +} + function assertEnvironmentMatchesDispatch( environment: Extract, dispatched: Extract, @@ -28,6 +76,85 @@ function assertEnvironmentMatchesDispatch( } } +function assertInteractiveIntentMatchesEnvironment( + intent: Extract, + environment: Extract, +): void { + const exact = environment.request.run + if ( + intent.provider !== environment.provider || + intent.provider !== exact.provider || + environment.environmentId !== exact.environmentId || + intent.idempotencyKey !== environment.idempotencyKey || + intent.interactiveIdempotencyKey !== environment.interactiveIdempotencyKey || + intent.sessionId !== exact.sessionId || + intent.executionId !== exact.executionId || + intent.requestedProfileDigest !== environment.request.requestedProfileDigest + ) { + throw new DomainInvariantError( + 'Retained interactive environment conflicts with its intent admission', + ) + } +} + +function assertInteractiveEnvironmentMatchesStarted( + environment: Extract, + started: Extract, +): void { + if ( + environment.idempotencyKey !== started.idempotencyKey || + environment.interactiveIdempotencyKey !== started.interactiveIdempotencyKey || + !agentInteractiveSessionRefMatchesStart(environment.request, started.ref) + ) { + throw new DomainInvariantError( + 'Retained interactive process conflicts with its environment admission', + ) + } +} + +function assertAdjacentAdmissions(first: Admission, second: Admission): void { + if (first.phase === 'intent' && second.phase === 'environment') { + assertIntentMatchesEnvironment(first, second) + return + } + if (first.phase === 'environment' && second.phase === 'dispatched') { + assertEnvironmentMatchesDispatch(first, second) + return + } + if (first.phase === 'interactive_intent' && second.phase === 'interactive_environment') { + assertInteractiveIntentMatchesEnvironment(first, second) + return + } + if (first.phase === 'interactive_environment' && second.phase === 'interactive_started') { + assertInteractiveEnvironmentMatchesStarted(first, second) + return + } + throw new DomainInvariantError('Retained admission phases do not form one recovery sequence') +} + +function assertTransition(current: Admission, next: Admission): 'advance' | 'replay' { + if (admissionFamily(current) !== admissionFamily(next)) { + throw new DomainInvariantError('Retained admission changed execution mode after persistence') + } + const currentRank = admissionRank(current) + const nextRank = admissionRank(next) + if (currentRank === nextRank) { + if (!sameAdmission(current, next)) { + throw new DomainInvariantError('Retained admission changed after persistence') + } + return 'replay' + } + if (nextRank === currentRank + 1) { + assertAdjacentAdmissions(current, next) + return 'advance' + } + if (nextRank === currentRank - 1) { + assertAdjacentAdmissions(next, current) + return 'replay' + } + throw new DomainInvariantError('Retained admission skipped a required durable phase') +} + export function applyRetainedAdmission( state: BraidState, event: RetainedAdmissionEvent, @@ -36,39 +163,39 @@ export function applyRetainedAdmission( const run = find(state.runs, event.runId, 'Run') const current = run.retainedAdmission const next = structuredClone(event.admission) + const sessionId = admissionSessionId(next) - if (run.providerSessionId !== undefined) { - const sessionId = next.phase === 'environment' ? next.sessionId : next.controlRef.sessionId - if (sessionId !== run.providerSessionId) { - throw new DomainInvariantError( - `Retained admission for ${run.id} conflicts with its provider session`, - ) - } + if (run.providerSessionId !== undefined && sessionId !== run.providerSessionId) { + throw new DomainInvariantError( + `Retained admission for ${run.id} conflicts with its provider session`, + ) } - if (current?.phase === 'environment' && next.phase === 'dispatched') { - assertEnvironmentMatchesDispatch(current, next) - } else if (current?.phase === 'dispatched' && next.phase === 'environment') { - assertEnvironmentMatchesDispatch(next, current) - return state - } else if (current !== undefined) { - if (!sameAdmission(current, next)) { - throw new DomainInvariantError(`Retained admission for ${run.id} changed after persistence`) - } - return state - } else if (next.phase === 'dispatched') { + if (current !== undefined && assertTransition(current, next) === 'replay') return state + if ( + current === undefined && + (next.phase === 'dispatched' || + next.phase === 'interactive_environment' || + next.phase === 'interactive_started') + ) { throw new DomainInvariantError( - `Retained dispatch for ${run.id} has no durable environment admission`, + `Retained ${next.phase} admission for ${run.id} has no prior durable admission`, ) } + const controlRef = + next.phase === 'dispatched' + ? next.controlRef + : next.phase === 'interactive_started' + ? next.ref.run + : undefined return { ...state, runs: upsert(state.runs, { ...run, - providerSessionId: next.phase === 'environment' ? next.sessionId : next.controlRef.sessionId, + providerSessionId: sessionId, retainedAdmission: next, - ...(next.phase === 'dispatched' ? { controlRef: structuredClone(next.controlRef) } : {}), + ...(controlRef === undefined ? {} : { controlRef: structuredClone(controlRef) }), updatedAt: at, }), } diff --git a/src/domain/run-contracts.ts b/src/domain/run-contracts.ts index e1b484b..db61798 100644 --- a/src/domain/run-contracts.ts +++ b/src/domain/run-contracts.ts @@ -4,30 +4,15 @@ import type { AgentProfile, RequestedInteractions, } from '@tangle-network/agent-interface' +import type { + RetainedInteractiveAdmission, + RetainedRunAdmission, +} from '@tangle-network/agent-runtime/kernel' export type { RequestedInteractions } from '@tangle-network/agent-interface' -export interface RetainedRunEnvironmentAdmissionRecord { - readonly phase: 'environment' - readonly provider: string - readonly environmentId: string - readonly idempotencyKey: string - readonly turnId: string - readonly sessionId: string - readonly executionId: string -} - -export interface RetainedRunDispatchedAdmissionRecord { - readonly phase: 'dispatched' - readonly controlRef: AgentExactRunControlRef - readonly idempotencyKey: string - readonly turnId: string -} - -/** Product-owned recovery data that Runtime requires Braid to persist before proceeding. */ -export type RetainedRunAdmissionRecord = - | RetainedRunEnvironmentAdmissionRecord - | RetainedRunDispatchedAdmissionRecord +/** Canonical Runtime recovery data that Braid persists before Runtime may proceed. */ +export type RetainedRunAdmissionRecord = RetainedRunAdmission | RetainedInteractiveAdmission export type RetainedRunAdmissionRecorder = (admission: RetainedRunAdmissionRecord) => Promise diff --git a/src/index.ts b/src/index.ts index c59fa1e..be1ecd3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,16 @@ export { type AgentTurnBackendResolver, } from './adapters/runtime/agent-runtime-execution.js' export { createNativeTerminalTransport } from './adapters/tui/native-terminal-transport.js' +export type { + NativeInteractiveAvailability, + NativeInteractiveCommand, + NativeInteractiveCommandResult, + NativeInteractiveUiActions, +} from './ports/native-interactive-ui.js' +export type { + NativeInteractiveExecutionControl, + NativeInteractiveRunOutcome, +} from './ports/native-interactive-execution.js' export { AppError, BraidApplication, diff --git a/src/ports/execution.ts b/src/ports/execution.ts index 304980f..2565fca 100644 --- a/src/ports/execution.ts +++ b/src/ports/execution.ts @@ -5,6 +5,7 @@ import type { InteractionResponseCommand, } from '@tangle-network/agent-interface' import type { TurnUsage } from '../domain/entities.js' +import type { RunAdmissionReceipt } from '../domain/receipts.js' import type { RequestedInteractions, RetainedRunAdmissionRecord, @@ -61,6 +62,13 @@ export interface ProviderRunSnapshot { readonly detail?: string } +/** Durable public data needed to reconstruct one retained execution after restart. */ +export interface RetainedExecutionRecoveryContext { + readonly retainedAdmission?: RetainedRunAdmissionRecord + readonly receipt?: RunAdmissionReceipt + readonly workspaceRoot?: string +} + export interface ControlAcknowledgement { readonly operationId: string readonly outcome: 'accepted' | 'already-applied' | 'rejected' | 'unknown' @@ -114,7 +122,7 @@ export interface ExecutionPort { readonly providerSessionId?: string readonly controlRef?: AgentExactRunControlRef readonly signal?: AbortSignal - }): Promise + } & RetainedExecutionRecoveryContext): Promise respondInteraction?(input: { readonly command: InteractionResponseCommand readonly signal?: AbortSignal @@ -126,7 +134,8 @@ export interface ExecutionPort { readonly providerSessionId?: string readonly controlRef?: AgentExactRunControlRef readonly signal: AbortSignal - }): AsyncIterable + readonly onRetainedAdmission?: RetainedRunAdmissionRecorder + } & RetainedExecutionRecoveryContext): AsyncIterable nativeBoundary?(input: { readonly runId: string readonly sessionId: string diff --git a/src/ports/native-interactive-execution.ts b/src/ports/native-interactive-execution.ts new file mode 100644 index 0000000..d2f06f6 --- /dev/null +++ b/src/ports/native-interactive-execution.ts @@ -0,0 +1,15 @@ +import type { RetainedInteractiveRunHandle } from '@tangle-network/agent-runtime/kernel' + +export type NativeInteractiveRunOutcome = + | { readonly kind: 'detached' } + | { readonly kind: 'exited'; readonly exitCode?: number; readonly exitSignal?: string } + | { readonly kind: 'failed'; readonly message: string } + +/** Rendezvous between Braid's durable run and the terminal-only native viewer. */ +export interface NativeInteractiveExecutionControl { + waitForHandle( + runId: string, + options?: { readonly signal?: AbortSignal }, + ): Promise + settle(runId: string, outcome: NativeInteractiveRunOutcome): void +} diff --git a/src/ports/native-interactive-ui.ts b/src/ports/native-interactive-ui.ts new file mode 100644 index 0000000..e78f0cc --- /dev/null +++ b/src/ports/native-interactive-ui.ts @@ -0,0 +1,35 @@ +export type NativeInteractiveCommand = + | { + readonly action: 'start' + readonly initialPrompt?: string + } + | { + readonly action: 'attach' + readonly runId?: string + } + +export interface NativeInteractiveAvailability { + readonly available: boolean + readonly reason?: string +} + +export type NativeInteractiveCommandResult = + | { + readonly kind: 'returned' + readonly runId: string + readonly outcome: 'detached' | 'exited' + } + | { + readonly kind: 'unavailable' + readonly reason: string + } + | { + readonly kind: 'error' + readonly message: string + } + +/** Terminal-only actions. Runtime owns admission and recovery; this port only requests them. */ +export interface NativeInteractiveUiActions { + availability(action: NativeInteractiveCommand['action']): NativeInteractiveAvailability + run(command: NativeInteractiveCommand): Promise +} diff --git a/src/views/shared/command-registry.ts b/src/views/shared/command-registry.ts index a9027fa..7e3378a 100644 --- a/src/views/shared/command-registry.ts +++ b/src/views/shared/command-registry.ts @@ -80,6 +80,8 @@ const INTENTS_FOR: Readonly> = { detach: runCommandIntent('detach'), reconnect: runCommandIntent('reconnect'), reconcile: runCommandIntent('reconcile'), + interactive: runCommandIntent('interactive'), + attach: runCommandIntent('attach'), activity: () => ({ type: 'open-surface', surface: 'activity' }), export: runCommandIntent('export'), import: runCommandIntent('import'), @@ -217,6 +219,22 @@ const DEFINITIONS: readonly CommandDefinition[] = [ 'run.reconcile', 'explicit', ], + [ + 'interactive', + [], + "Open the selected runner's native terminal", + '/interactive ', + 'run.interactive', + 'explicit', + ], + [ + 'attach', + [], + 'Attach to a retained native terminal', + '/attach [run-id]', + 'run.attach', + 'explicit', + ], [ 'activity', [], diff --git a/src/views/shared/command-table.ts b/src/views/shared/command-table.ts index 7bfc895..d4de129 100644 --- a/src/views/shared/command-table.ts +++ b/src/views/shared/command-table.ts @@ -161,6 +161,18 @@ export const SHARED_COMMAND_TABLE = [ headlessCommands: ['reconcile'], mutatingHeadlessCommands: ['reconcile'], }, + { + name: 'interactive', + requiresOperationId: false, + headlessCommands: [], + mutatingHeadlessCommands: [], + }, + { + name: 'attach', + requiresOperationId: false, + headlessCommands: [], + mutatingHeadlessCommands: [], + }, { name: 'activity', requiresOperationId: false, diff --git a/src/views/tui/terminal-app.ts b/src/views/tui/terminal-app.ts index 90d2b09..5eaa17f 100644 --- a/src/views/tui/terminal-app.ts +++ b/src/views/tui/terminal-app.ts @@ -22,6 +22,7 @@ import { TerminalInteractionController } from './terminal-interaction-controller import { TerminalOverlayController } from './terminal-overlays.js' import { BraidShell } from './terminal-shell.js' import type { BraidTheme } from './theme.js' +import type { NativeInteractiveUiActions } from '../../ports/native-interactive-ui.js' export interface BraidTerminalOptions { readonly controller: BraidUiController @@ -36,6 +37,7 @@ export interface BraidTerminalOptions { readonly onFrameTiming?: (timing: UiFrameTiming) => void readonly tuiStarted?: boolean readonly preinstalledOutputPolicyCleanup?: () => void + readonly nativeInteractive?: NativeInteractiveUiActions } export class BraidTerminalApp { @@ -96,7 +98,21 @@ export class BraidTerminalApp { const autocomplete = new GuardedAutocompleteProvider( new DynamicAutocompleteProvider({ commands: () => - commandItems(this.#controller.view().capabilities).map((item) => ({ + commandItems({ + ...this.#controller.view().capabilities, + ...(options.nativeInteractive === undefined + ? {} + : { + 'run.interactive': { + ...options.nativeInteractive.availability('start'), + source: 'runtime' as const, + }, + 'run.attach': { + ...options.nativeInteractive.availability('attach'), + source: 'runtime' as const, + }, + }), + }).map((item) => ({ name: item.value, description: item.description ?? '', })), @@ -174,6 +190,9 @@ export class BraidTerminalApp { isStopped: () => this.#stopped, stop: () => this.stop(), composerMode: () => this.#input.composerMode, + ...(options.nativeInteractive === undefined + ? {} + : { nativeInteractive: options.nativeInteractive }), }) this.#shell.editor.setAutocompleteProvider(autocomplete) options.tui.addChild(this.#shell) diff --git a/src/views/tui/terminal-command-controller.ts b/src/views/tui/terminal-command-controller.ts index c12659d..851f5f9 100644 --- a/src/views/tui/terminal-command-controller.ts +++ b/src/views/tui/terminal-command-controller.ts @@ -12,6 +12,7 @@ import { } from '../shared/command-registry.js' import type { BraidIntent, BraidUiController, UiDispatchResult } from '../shared/intents.js' import type { BraidViewModel } from '../shared/models.js' +import type { NativeInteractiveUiActions } from '../../ports/native-interactive-ui.js' import { executionTargetFor } from './execution-target.js' import type { TerminalDraftController } from './terminal-drafts.js' import type { TerminalOverlayController } from './terminal-overlays.js' @@ -27,6 +28,7 @@ export interface TerminalCommandControllerOptions { readonly isStopped: () => boolean readonly stop: () => void readonly composerMode: () => ComposerMode + readonly nativeInteractive?: NativeInteractiveUiActions } /** Owns prompt parsing and command routing; it never owns terminal layout. */ @@ -40,6 +42,7 @@ export class TerminalCommandController { readonly #isStopped: () => boolean readonly #stop: () => void readonly #composerMode: () => ComposerMode + readonly #nativeInteractive: NativeInteractiveUiActions | undefined constructor(options: TerminalCommandControllerOptions) { this.#controller = options.controller @@ -51,6 +54,7 @@ export class TerminalCommandController { this.#isStopped = options.isStopped this.#stop = options.stop this.#composerMode = options.composerMode + this.#nativeInteractive = options.nativeInteractive } submit(rawText: string): void { @@ -117,6 +121,10 @@ export class TerminalCommandController { } async #dispatchCommandValue(command: CommandName, args: readonly string[]): Promise { + if (command === 'interactive' || command === 'attach') { + await this.#runNativeInteractive(command, args) + return + } if (command === 'profile' && args.length === 0) { this.#overlays.openProfile() return @@ -209,6 +217,45 @@ export class TerminalCommandController { } }) } + + async #runNativeInteractive( + command: 'interactive' | 'attach', + args: readonly string[], + ): Promise { + const action = command === 'interactive' ? 'start' : 'attach' + const actions = this.#nativeInteractive + const availability = actions?.availability(action) ?? { + available: false, + reason: 'Native terminal mode is unavailable in this interface', + } + if (!availability.available) { + this.#overlays.openUnavailable(`/${command}`, availability.reason ?? 'Unavailable') + return + } + await this.#drafts.flush() + let result: Awaited> + try { + result = await actions!.run( + command === 'interactive' + ? { + action: 'start', + ...(args.length === 0 ? {} : { initialPrompt: args.join(' ') }), + } + : { action: 'attach', ...(args[0] === undefined ? {} : { runId: args[0] }) }, + ) + } catch (error) { + this.#overlays.openUnavailable( + `/${command}`, + error instanceof Error ? error.message : 'Native terminal operation failed', + ) + return + } + if (result.kind === 'unavailable') { + this.#overlays.openUnavailable(`/${command}`, result.reason) + } else if (result.kind === 'error') { + this.#overlays.openUnavailable(`/${command}`, result.message) + } + } } function steerIntent(operationId: string, text: string): Extract { diff --git a/test/domain-reducer.test.ts b/test/domain-reducer.test.ts index 08a7830..eba77af 100644 --- a/test/domain-reducer.test.ts +++ b/test/domain-reducer.test.ts @@ -392,6 +392,17 @@ test('incremental reduction and full replay produce the same complete projection }) test('retained admission survives the pre-dispatch crash window and binds one exact run', () => { + const intentAdmission = { + phase: 'intent' as const, + provider: 'cli-bridge', + idempotencyKey: 'environment-retained-admission', + turnId: 'turn-retained-admission', + sessionId: 'session-retained-admission', + executionId: 'execution-retained-admission', + runId: 'retained-intent-run', + requestedProfileDigest: `sha256:${'a'.repeat(64)}` as const, + requestDigest: `sha256:${'b'.repeat(64)}` as const, + } const environmentAdmission = { phase: 'environment' as const, provider: 'cli-bridge', @@ -432,10 +443,18 @@ test('retained admission survives the pre-dispatch crash window and binds one ex { kind: 'run.retained.admitted', runId: 'run-retained-admission', - admission: environmentAdmission, + admission: intentAdmission, }, 3, ), + envelope( + { + kind: 'run.retained.admitted', + runId: 'run-retained-admission', + admission: environmentAdmission, + }, + 4, + ), ] as const const interrupted = replayEvents(initialState(STARTER_PROFILE), initialEvents) @@ -450,7 +469,7 @@ test('retained admission survives the pre-dispatch crash window and binds one ex runId: 'run-retained-admission', admission: dispatchedAdmission, }, - 4, + 5, ), ) assert.deepEqual(dispatched.runs[0]?.retainedAdmission, dispatchedAdmission) @@ -478,7 +497,7 @@ test('retained admission survives the pre-dispatch crash window and binds one ex receivedAt: '2026-08-02T00:00:05.000Z', }, }, - 5, + 6, ), ) assert.equal(harnessSession.runs[0]?.providerSessionId, environmentAdmission.sessionId) @@ -494,7 +513,7 @@ test('retained admission survives the pre-dispatch crash window and binds one ex runId: 'run-retained-admission', admission: environmentAdmission, }, - 6, + 7, ), ) assert.deepEqual(retriedEnvironment.runs[0]?.retainedAdmission, dispatchedAdmission) @@ -512,7 +531,7 @@ test('retained admission survives the pre-dispatch crash window and binds one ex environmentId: 'environment-retained-conflict', }, }, - 7, + 8, ), ), /conflicts with its environment admission/u, diff --git a/test/native-interactive-actions.test.ts b/test/native-interactive-actions.test.ts new file mode 100644 index 0000000..da8614c --- /dev/null +++ b/test/native-interactive-actions.test.ts @@ -0,0 +1,278 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import type { + AgentInteractiveSessionControlClaimRequest, + AgentInteractiveSessionRef, + AgentInteractiveTerminalSession, + TerminalDetachAck, +} from '@tangle-network/agent-interface' +import { + agentExecutionPreparationReceiptSchema, + canonicalCandidateDigest, +} from '@tangle-network/agent-interface' +import type { RetainedInteractiveRunHandle } from '@tangle-network/agent-runtime/kernel' +import type { BraidApplication } from '../src/app/application.js' +import { createNativeInteractiveUiActions } from '../src/bin/native-interactive-actions.js' +import type { NativeInteractiveExecutionControl } from '../src/ports/native-interactive-execution.js' +import type { NativeTerminalHost, NativeTerminalSignalPort } from '../src/index.js' + +class ExitTerminalSession implements AgentInteractiveTerminalSession { + readonly ref = { + terminalSessionId: 'terminal-native-actions', + parentExecutionId: 'execution-native-actions', + name: 'native actions', + shell: '/bin/sh', + cwd: '/workspace', + cols: 100, + rows: 30, + createdAt: '2026-08-16T00:00:00.000Z', + lastActivityAt: '2026-08-16T00:00:00.000Z', + expiresAt: '2099-01-01T00:00:00.000Z', + isRunning: true, + attachCount: 1, + } + readonly cursors = { earliest: 0, latest: 1 } + readonly control = { + refDigest: `sha256:${'1'.repeat(64)}` as const, + generation: 1, + leaseId: 'lease-native-actions', + holderId: 'braid-native-actions', + expiresAt: '2099-01-01T00:00:00.000Z', + } + + input(): Promise { + return Promise.resolve() + } + + resize(): Promise { + return Promise.resolve() + } + + detach(): Promise { + return Promise.resolve({ + status: 'detached', + terminalSessionId: this.ref.terminalSessionId, + }) + } + + close(): Promise { + return Promise.resolve({ status: 'closed', terminalSessionId: this.ref.terminalSessionId }) + } + + async *events(): AsyncIterable<{ readonly type: 'exit'; readonly exitCode: number }> { + yield { type: 'exit', exitCode: 0 } + } +} + +class TestTerminal implements NativeTerminalHost { + readonly columns = 100 + readonly rows = 30 + starts = 0 + stops = 0 + + start(): void { + this.starts += 1 + } + + stop(): void { + this.stops += 1 + } + + write(): void {} +} + +const signals: NativeTerminalSignalPort = { + takeOver: () => () => {}, +} + +const preparationMaterial = { + kind: 'agent-execution-preparation' as const, + schemaVersion: 1 as const, + preparationId: 'preparation-native-actions', + requestDigest: `sha256:${'1'.repeat(64)}` as const, + authoredProfileDigest: `sha256:${'2'.repeat(64)}` as const, + effectiveProfileDigest: `sha256:${'2'.repeat(64)}` as const, + backend: 'test-backend', + harness: 'pi' as const, + harnessVersion: 'test-harness-1', + resolvedModel: { requested: 'test/model', resolved: 'test/model' }, + workspace: { + leaseId: 'workspace-lease-native-actions', + provider: 'test-provider', + identityDigest: `sha256:${'3'.repeat(64)}` as const, + isolation: 'per-run' as const, + sourceSnapshotDigest: `sha256:${'4'.repeat(64)}` as const, + sourceSnapshotPolicy: { + kind: 'provider-declared' as const, + name: 'test-snapshot', + version: 1, + digest: `sha256:${'5'.repeat(64)}` as const, + }, + preparedWorkspaceDigest: `sha256:${'6'.repeat(64)}` as const, + profileActivationDigest: `sha256:${'7'.repeat(64)}` as const, + }, + axisResults: [], + executionPlanDigest: `sha256:${'8'.repeat(64)}` as const, + materializer: { name: 'test-materializer', version: '1' }, + expiresAtMs: 4_102_444_800_000, +} + +const interactiveRef: AgentInteractiveSessionRef = { + run: { + provider: 'test-provider', + environmentId: 'environment-native-actions', + sessionId: 'session-native-actions', + executionId: 'execution-native-actions', + runId: 'provider-run-native-actions', + requestDigest: preparationMaterial.requestDigest, + }, + preparationReceipt: agentExecutionPreparationReceiptSchema.parse({ + ...preparationMaterial, + digest: canonicalCandidateDigest(preparationMaterial), + }), + incarnationId: 'incarnation-native-actions', + startedAt: '2026-08-16T00:00:00.000Z', +} + +function retainedHandle( + terminalSession: AgentInteractiveTerminalSession, + attached: AgentInteractiveSessionControlClaimRequest[], +): RetainedInteractiveRunHandle { + const ref = interactiveRef + return { + ref, + capabilities: {} as RetainedInteractiveRunHandle['capabilities'], + claimControl: async (request) => ({ + operationId: request.operationId, + requestDigest: request.requestDigest, + ref, + status: 'accepted', + control: { + refDigest: canonicalCandidateDigest(ref), + generation: 1, + leaseId: 'lease-native-actions', + holderId: request.holderId, + expiresAt: '2099-01-01T00:00:00.000Z', + }, + }), + status: async () => ({ state: 'running', ref }), + attach: async (request) => { + attached.push({ + operationId: 'attach-observation', + requestDigest: `sha256:${'2'.repeat(64)}`, + ref, + holderId: request.control.holderId, + expectedGeneration: request.control.generation, + }) + return terminalSession + }, + sendPrompt: async () => { + throw new Error('not used') + }, + stop: async () => { + throw new Error('not used') + }, + } +} + +test('starts one Runtime-owned native run and returns to Braid after remote exit', async () => { + const terminal = new TestTerminal() + const attached: AgentInteractiveSessionControlClaimRequest[] = [] + const handle = retainedHandle(new ExitTerminalSession(), attached) + const sends: Array<{ readonly text: string; readonly mode?: string }> = [] + const settlements: unknown[] = [] + let settleCompletion: () => void = () => {} + const completion = new Promise((resolve) => { + settleCompletion = resolve + }) + const app = { + state: () => ({ activeRunId: null, runs: [] }), + send: (input: { readonly text: string; readonly mode?: string }) => { + sends.push(input) + return { runId: 'run-native-actions', completion } + }, + reconnectRun: async () => ({}), + detachRun: async () => { + throw new Error('remote exit must not detach') + }, + } as unknown as Pick + const execution: NativeInteractiveExecutionControl = { + waitForHandle: async () => handle, + settle: (_runId, outcome) => { + settlements.push(outcome) + settleCompletion() + }, + } + let suspends = 0 + let resumes = 0 + let operation = 0 + const actions = createNativeInteractiveUiActions({ + current: () => ({ app, nativeInteractive: execution }), + terminal, + signals: () => signals, + suspend: () => { + suspends += 1 + }, + resume: () => { + resumes += 1 + }, + nextOperationId: () => `operation-${++operation}`, + holderId: 'braid-native-actions', + }) + + const result = await actions.run({ action: 'start', initialPrompt: 'inspect the failing tests' }) + + assert.deepEqual(result, { kind: 'returned', runId: 'run-native-actions', outcome: 'exited' }) + assert.deepEqual(sends, [ + { operationId: 'operation-1', text: 'inspect the failing tests', mode: 'interactive' }, + ]) + assert.deepEqual(settlements, [{ kind: 'exited', exitCode: 0 }]) + assert.equal(attached[0]?.holderId, 'braid-native-actions') + assert.equal(attached[0]?.expectedGeneration, 1) + assert.equal(terminal.starts, 1) + assert.equal(terminal.stops, 1) + assert.equal(suspends, 1) + assert.equal(resumes, 1) +}) + +test('requires a prompt and explains unavailable native providers', async () => { + const app = { + state: () => ({ activeRunId: null, runs: [] }), + } as unknown as Pick + const actions = createNativeInteractiveUiActions({ + current: () => ({ app }), + terminal: new TestTerminal(), + signals: () => signals, + suspend: () => {}, + resume: () => {}, + nextOperationId: () => 'operation-unused', + holderId: 'braid-native-actions', + }) + + assert.deepEqual(actions.availability('start'), { + available: false, + reason: 'Select a retained Tangle Sandbox connection with native terminal support', + }) + + const supported = createNativeInteractiveUiActions({ + current: () => ({ + app, + nativeInteractive: { + waitForHandle: async () => { + throw new Error('must not wait without a prompt') + }, + settle: () => {}, + }, + }), + terminal: new TestTerminal(), + signals: () => signals, + suspend: () => {}, + resume: () => {}, + nextOperationId: () => 'operation-unused', + holderId: 'braid-native-actions', + }) + assert.deepEqual(await supported.run({ action: 'start' }), { + kind: 'error', + message: 'Usage: /interactive ', + }) +}) diff --git a/test/native-interactive-command.test.ts b/test/native-interactive-command.test.ts new file mode 100644 index 0000000..28fd52a --- /dev/null +++ b/test/native-interactive-command.test.ts @@ -0,0 +1,91 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { TuiMainScreen } from '@earendil-works/pi-tui' +import { createApplicationUiController } from '../src/adapters/tui/application-ui-controller.js' +import { createBraidApplication } from '../src/app/composition.js' +import type { + NativeInteractiveCommand, + NativeInteractiveUiActions, +} from '../src/ports/native-interactive-ui.js' +import { BraidTerminalApp } from '../src/views/tui/terminal-app.js' +import { createBraidTheme } from '../src/views/tui/theme.js' +import { VirtualTerminal } from './support/virtual-terminal.js' + +async function waitUntil(predicate: () => boolean, timeoutMs = 1_000): Promise { + const deadline = Date.now() + timeoutMs + while (!predicate()) { + if (Date.now() >= deadline) throw new Error('Timed out waiting for native terminal command') + await new Promise((resolve) => setTimeout(resolve, 5)) + } +} + +function terminalWith(actions?: NativeInteractiveUiActions): { + readonly terminal: VirtualTerminal + readonly view: BraidTerminalApp + readonly done: Promise +} { + const app = createBraidApplication({ fixture: 'deterministic' }) + app.initialize('/workspace') + const terminal = new VirtualTerminal(80, 24) + const view = new BraidTerminalApp({ + controller: createApplicationUiController(app), + tui: new TuiMainScreen(terminal), + theme: createBraidTheme(false), + workspace: '/workspace', + nextOperationId: () => 'operation-native-command', + ...(actions === undefined ? {} : { nativeInteractive: actions }), + }) + return { terminal, view, done: view.start() } +} + +test('native terminal commands cross one typed terminal-only port', async () => { + const commands: NativeInteractiveCommand[] = [] + const actions: NativeInteractiveUiActions = { + availability: () => ({ available: true }), + run: async (command) => { + commands.push(command) + return { kind: 'returned', runId: 'run-native', outcome: 'detached' } + }, + } + for (const input of ['/interactive inspect the failing tests', '/attach run-native']) { + const { terminal, view, done } = terminalWith(actions) + const expectedCount = commands.length + 1 + try { + terminal.sendInput(input) + terminal.sendInput('\r') + await waitUntil(() => commands.length === expectedCount) + } finally { + view.stop() + await done + } + } + assert.deepEqual(commands, [ + { action: 'start', initialPrompt: 'inspect the failing tests' }, + { action: 'attach', runId: 'run-native' }, + ]) +}) + +test('native commands explain unavailable capability without calling the port', async () => { + let calls = 0 + const actions: NativeInteractiveUiActions = { + availability: (action) => ({ + available: false, + reason: action === 'start' ? 'This connection has no native terminal' : 'No retained session', + }), + run: async () => { + calls += 1 + return { kind: 'error', message: 'must not run' } + }, + } + const { terminal, view, done } = terminalWith(actions) + try { + terminal.sendInput('/interactive\r') + await waitUntil(() => + /This connection has no native terminal/u.test(terminal.getViewport().join('\n')), + ) + assert.equal(calls, 0) + } finally { + view.stop() + await done + } +}) diff --git a/test/native-interactive-run-broker.test.ts b/test/native-interactive-run-broker.test.ts new file mode 100644 index 0000000..0a786a4 --- /dev/null +++ b/test/native-interactive-run-broker.test.ts @@ -0,0 +1,36 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import type { RetainedInteractiveRunHandle } from '@tangle-network/agent-runtime/kernel' +import { NativeInteractiveRunBroker } from '../src/adapters/runtime/native-interactive-run-broker.js' + +const HANDLE = Object.freeze({ ref: Object.freeze({}) }) as unknown as RetainedInteractiveRunHandle + +test('native interactive broker joins UI and execution regardless of arrival order', async () => { + const broker = new NativeInteractiveRunBroker() + const waiting = broker.waitForHandle('run-native') + const lease = broker.open('run-native') + lease.publish(HANDLE) + assert.equal(await waiting, HANDLE) + + const outcome = lease.outcome() + broker.settle('run-native', { kind: 'exited', exitCode: 0 }) + assert.deepEqual(await outcome, { kind: 'exited', exitCode: 0 }) + lease.close() +}) + +test('native interactive broker rejects duplicate execution and caller-local aborts', async () => { + const broker = new NativeInteractiveRunBroker() + const lease = broker.open('run-native') + assert.throws(() => broker.open('run-native'), /already has an active execution/u) + + const abort = new AbortController() + const waiting = broker.waitForHandle('run-native', { signal: abort.signal }) + abort.abort(new Error('viewer stopped')) + await assert.rejects(waiting, /viewer stopped/u) + + lease.publish(HANDLE) + assert.equal(await broker.waitForHandle('run-native'), HANDLE) + lease.fail(new Error('execution failed')) + await assert.rejects(lease.outcome(), /execution failed/u) + lease.close() +}) diff --git a/test/scripts.test.ts b/test/scripts.test.ts index decaf3d..a3a66de 100644 --- a/test/scripts.test.ts +++ b/test/scripts.test.ts @@ -214,6 +214,8 @@ test('every scoped package alias forwards its declared file set', () => { 'domain-reducer.test.js', 'domain-text.test.js', 'eval.test.js', + 'native-interactive-actions.test.js', + 'native-interactive-run-broker.test.js', 'observability.test.js', 'plain-accessibility.test.js', 'property.test.js', @@ -264,6 +266,7 @@ test('every scoped package alias forwards its declared file set', () => { 'configuration-product-flow.test.js', 'intelligence-dispatch.test.js', 'keyboard.test.js', + 'native-interactive-command.test.js', 'terminal-responsive.test.js', 'terminal-usage-status.test.js', 'tui-autocomplete.test.js', From e3ed3d16f178839560ae4809c8c4df2914bab32e Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Sun, 16 Aug 2026 08:37:08 -0600 Subject: [PATCH 18/25] feat(runtime): add retained interactive execution adapters --- .../runtime/mode-routing-execution.ts | 200 +++++ .../runtime/native-interactive-run-broker.ts | 13 +- .../tangle-retained-interactive-execution.ts | 717 ++++++++++++++++++ test/interactive-execution-adapters.test.ts | 668 ++++++++++++++++ 4 files changed, 1591 insertions(+), 7 deletions(-) create mode 100644 src/adapters/runtime/mode-routing-execution.ts create mode 100644 src/adapters/runtime/tangle-retained-interactive-execution.ts create mode 100644 test/interactive-execution-adapters.test.ts diff --git a/src/adapters/runtime/mode-routing-execution.ts b/src/adapters/runtime/mode-routing-execution.ts new file mode 100644 index 0000000..b3080d6 --- /dev/null +++ b/src/adapters/runtime/mode-routing-execution.ts @@ -0,0 +1,200 @@ +import type { InteractionResponseCommand } from '@tangle-network/agent-interface' +import type { + ExecuteTurnInput, + ExecutionPort, + NormalizedExecutionEvent, + RunCapabilities, +} from '../../ports/execution.js' +import { UNKNOWN_RUN_CAPABILITIES } from '../../ports/execution.js' + +type StatusInput = Parameters>[0] +type ReconnectInput = Parameters>[0] +type ReconnectEvent = + Awaited>> extends AsyncIterable + ? Event + : never +type CancelInput = Parameters>[0] +type DetachInput = Parameters>[0] +type SteerInput = Parameters>[0] +type NativeBoundaryInput = Parameters>[0] + +export interface ModeRoutingExecutionOptions { + readonly headless: ExecutionPort + readonly interactive: ExecutionPort + /** Supplies durable mode state after Braid has restarted. */ + readonly isInteractiveRun?: (runId: string) => boolean +} + +/** Routes one run by its explicit mode or canonical retained admission. */ +export class ModeRoutingExecutionPort implements ExecutionPort { + readonly #headless: ExecutionPort + readonly #interactive: ExecutionPort + readonly #isInteractiveRun: (runId: string) => boolean + readonly #interactiveRuns = new Set() + readonly admissionMode: 'sync' | 'async' + readonly capabilities: NonNullable + readonly environmentCapabilities?: NonNullable + + constructor(options: ModeRoutingExecutionOptions) { + this.#headless = options.headless + this.#interactive = options.interactive + this.#isInteractiveRun = options.isInteractiveRun ?? (() => false) + this.admissionMode = + options.headless.admissionMode === 'async' || options.interactive.admissionMode === 'async' + ? 'async' + : 'sync' + this.capabilities = this.#capabilities() + if (options.headless.environmentCapabilities !== undefined) { + this.environmentCapabilities = options.headless.environmentCapabilities.bind(options.headless) + } + } + + async admit(input: ExecuteTurnInput) { + const port = this.#portForInput(input) + if (port.admit === undefined) { + throw new Error('The selected execution port does not support admission') + } + const admission = await port.admit(input) + if (this.#isInteractivePort(port)) this.#interactiveRuns.add(input.runId) + return admission + } + + async *streamTurn(input: ExecuteTurnInput): AsyncIterable { + const port = this.#portForInput(input) + yield* port.streamTurn(input) + } + + async cancelRun(input: CancelInput) { + const port = this.#portForRun(input.runId, input.controlRef) + if (port.cancelRun === undefined) { + throw new Error('The selected execution port does not support cancellation') + } + return port.cancelRun(input) + } + + async detachRun(input: DetachInput) { + const port = this.#portForRun(input.runId, input.controlRef) + if (port.detachRun === undefined) { + throw new Error('The selected execution port does not support detachment') + } + return port.detachRun(input) + } + + async steerRun(input: SteerInput) { + const port = this.#portForRun(input.runId) + if (port.steerRun === undefined) { + throw new Error('The selected execution port does not support steering') + } + return port.steerRun(input) + } + + async status(input: StatusInput) { + const port = this.#portForRecovery(input) + if (port.status === undefined) { + throw new Error('The selected execution port does not support status') + } + return port.status(input) + } + + async respondInteraction(input: { + readonly command: InteractionResponseCommand + readonly signal?: AbortSignal + }) { + const port = this.#portForRun(input.command.binding.runId) + if (port.respondInteraction === undefined) { + throw new Error('The selected execution port does not support interaction responses') + } + return port.respondInteraction(input) + } + + async *reconnect(input: ReconnectInput): AsyncIterable { + const port = this.#portForRecovery(input) + if (port.reconnect === undefined) { + throw new Error('The selected execution port does not support reconnection') + } + yield* port.reconnect(input) + } + + async nativeBoundary(input: NativeBoundaryInput) { + const port = this.#portForRun(input.runId) + if (port.nativeBoundary === undefined) return null + return port.nativeBoundary(input) + } + + #capabilities(): NonNullable { + return ((input) => { + const selected = this.#portForInput(input).capabilities + if (selected === undefined) return UNKNOWN_RUN_CAPABILITIES + if (typeof selected === 'function') return selected(input) + return legacyCapabilities(selected) + }) as (input: ExecuteTurnInput) => RunCapabilities | Promise + } + + #portForRecovery(input: StatusInput | ReconnectInput): ExecutionPort { + const port = this.#portForInput(input) + if (this.#isInteractivePort(port)) this.#interactiveRuns.add(input.runId) + return port + } + + #portForRun(runId: string, _controlRef?: unknown): ExecutionPort { + const known = this.#interactiveRuns.has(runId) || this.#isInteractiveRun(runId) + if (known) { + this.#interactiveRuns.add(runId) + return this.#interactive + } + return this.#headless + } + + #portForInput(input: { + readonly runId: string + readonly mode?: string + readonly retainedAdmission?: unknown + readonly receipt?: { readonly requested?: { readonly mode?: string } } + }): ExecutionPort { + const admissionMode = retainedAdmissionMode(input.retainedAdmission) + const receiptMode = input.receipt?.requested?.mode + if (input.mode === 'interactive' && admissionMode === 'headless') { + throw new Error('Interactive mode conflicts with a headless retained admission') + } + if ( + input.mode !== undefined && + input.mode !== 'interactive' && + admissionMode === 'interactive' + ) { + throw new Error('Headless mode conflicts with an interactive retained admission') + } + if ( + input.mode === 'interactive' || + admissionMode === 'interactive' || + receiptMode === 'interactive' + ) { + this.#interactiveRuns.add(input.runId) + return this.#interactive + } + if (this.#interactiveRuns.has(input.runId) || this.#isInteractiveRun(input.runId)) { + this.#interactiveRuns.add(input.runId) + return this.#interactive + } + return this.#headless + } + + #isInteractivePort(port: ExecutionPort): boolean { + return port === this.#interactive + } +} + +function legacyCapabilities(capabilities: { readonly cancel: boolean }): RunCapabilities { + return { + ...UNKNOWN_RUN_CAPABILITIES, + controls: { ...UNKNOWN_RUN_CAPABILITIES.controls, cancel: capabilities.cancel }, + } +} + +function retainedAdmissionMode(value: unknown): 'interactive' | 'headless' | undefined { + if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined + const phase = (value as { readonly phase?: unknown }).phase + if (typeof phase !== 'string') return undefined + if (phase.startsWith('interactive_')) return 'interactive' + if (phase === 'intent' || phase === 'environment' || phase === 'dispatched') return 'headless' + return undefined +} diff --git a/src/adapters/runtime/native-interactive-run-broker.ts b/src/adapters/runtime/native-interactive-run-broker.ts index 1b0361d..5d3db1f 100644 --- a/src/adapters/runtime/native-interactive-run-broker.ts +++ b/src/adapters/runtime/native-interactive-run-broker.ts @@ -17,6 +17,8 @@ interface BrokerEntry { opened: boolean } +export type NativeInteractiveRunSettlement = 'settled' | 'absent' | 'already-settled' + export interface NativeInteractiveRunLease { publish(handle: RetainedInteractiveRunHandle): void outcome(options?: { readonly signal?: AbortSignal }): Promise @@ -61,15 +63,12 @@ export class NativeInteractiveRunBroker implements NativeInteractiveExecutionCon return abortable(this.#entry(runId).handle.promise, options?.signal) } - settle(runId: string, outcome: NativeInteractiveRunOutcome): void { + settle(runId: string, outcome: NativeInteractiveRunOutcome): NativeInteractiveRunSettlement { const entry = this.#entries.get(runId) - if (entry === undefined || !entry.opened) { - throw new Error(`Interactive run ${runId} has no active execution`) - } - if (entry.outcome.settled) { - throw new Error(`Interactive run ${runId} already has a terminal outcome`) - } + if (entry === undefined || !entry.opened) return 'absent' + if (entry.outcome.settled) return 'already-settled' entry.outcome.resolve(structuredClone(outcome)) + return 'settled' } #entry(runId: string): BrokerEntry { diff --git a/src/adapters/runtime/tangle-retained-interactive-execution.ts b/src/adapters/runtime/tangle-retained-interactive-execution.ts new file mode 100644 index 0000000..1a30481 --- /dev/null +++ b/src/adapters/runtime/tangle-retained-interactive-execution.ts @@ -0,0 +1,717 @@ +import type { + AgentExactRunControlRef, + AgentInteractiveSessionStatus, + AgentProfile, +} from '@tangle-network/agent-interface' +import { + agentInteractiveSessionStopRequestDigest, + canonicalCandidateDigest, +} from '@tangle-network/agent-interface' +import type { + RetainedInteractiveAdmission, + RetainedInteractiveAdmissionHook, + RetainedInteractiveRunHandle, + RetainedInteractiveStartedAdmission, +} from '@tangle-network/agent-runtime/kernel' +import { + claimRetainedInteractiveControl, + reconnectRetainedInteractiveRun, + recoverRetainedInteractiveRun, + startRetainedInteractiveRun, +} from '@tangle-network/agent-runtime/kernel' +import { canonicalDigest } from '../../domain/canonical.js' +import { publicMaterializationReceipt } from '../../domain/materialization-receipt.js' +import type { RuntimeEventEnvelope } from '../../domain/runtime-events.js' +import type { RunAdmissionReceipt } from '../../domain/receipts.js' +import type { + CancelRunInput, + ControlAcknowledgement, + ExecuteTurnInput, + ExecutionAdmission, + ExecutionPort, + ProviderRunSnapshot, + RunCapabilities, +} from '../../ports/execution.js' +import type { NativeInteractiveRunOutcome } from '../../ports/native-interactive-execution.js' +import type { NativeInteractiveRunBroker } from './native-interactive-run-broker.js' +import { canonicalAgentProfileDigestHex } from '../agent-interface/profile-runtime.js' +import { safeExecutionId } from './production-backend-common.js' +import type { PreparedTangleRetainedConnection } from './production-tangle-sandbox-backend.js' + +type StatusInput = Parameters>[0] +type RecoveryInput = Omit & { + readonly after?: string + readonly afterSequence?: number + readonly retainedAdmission?: unknown + readonly receipt?: RunAdmissionReceipt + readonly workspaceRoot?: string + readonly onRetainedAdmission?: unknown +} + +export interface TangleRetainedInteractiveExecutionOptions { + readonly resolve: (input: ExecuteTurnInput) => Promise + readonly recover?: (input: ExecuteTurnInput) => Promise + readonly broker: Pick + readonly holderId?: string +} + +/** Runs one exact Tangle coding-agent TUI through Runtime's durable APIs. */ +export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { + readonly admissionMode = 'async' as const + readonly #resolve: TangleRetainedInteractiveExecutionOptions['resolve'] + readonly #recover: TangleRetainedInteractiveExecutionOptions['recover'] + readonly #broker: Pick + readonly #holderId: string + readonly #prepared = new Map() + readonly #handles = new Map() + readonly #activeRuns = new Set() + readonly #detachRequested = new Set() + readonly #cancelledRuns = new Set() + + constructor(options: TangleRetainedInteractiveExecutionOptions) { + this.#resolve = options.resolve + this.#recover = options.recover + this.#broker = options.broker + this.#holderId = options.holderId ?? 'braid' + } + + capabilities = (input: ExecuteTurnInput): RunCapabilities | Promise => + this.#resolve(input).then((prepared) => interactiveRunCapabilities(prepared)) + + async admit(input: ExecuteTurnInput): Promise { + const prepared = await this.#resolve(input) + assertInteractiveProvider(prepared) + this.#prepared.set(input.runId, prepared) + const capabilities = interactiveRunCapabilities(prepared) + const materializationReceipt = interactiveMaterializationReceipt(prepared) + return { + capabilities, + provider: prepared.provider.name, + materializationReceipt, + profileDigest: canonicalAgentProfileDigestHex(input.profile), + capabilitiesDigest: canonicalDigest(capabilities), + materializationDigest: canonicalDigest(materializationReceipt), + } + } + + async *streamTurn(input: ExecuteTurnInput): AsyncIterable { + const prepared = this.#prepared.get(input.runId) ?? (await this.#resolve(input)) + assertInteractiveProvider(prepared) + const lease = this.#broker.open(input.runId) + this.#activeRuns.add(input.runId) + let terminal = false + try { + const handle = this.#handles.get(input.runId) ?? (await this.#start(prepared, input)) + this.#rememberHandle(input.runId, handle) + lease.publish(handle) + if (this.#detachRequested.has(input.runId)) this.#settleDetached(input.runId) + yield await observedEnvelope(input.runId, handle, prepared, 1) + const providerOutcome = await terminalOutcome(handle, input.signal) + if (providerOutcome !== undefined) { + terminal = true + yield terminalEnvelope( + input.runId, + handle, + prepared, + providerOutcome, + 2, + this.#cancelledRuns.has(input.runId), + ) + return + } + const outcome = await lease.outcome( + input.signal === undefined ? undefined : { signal: input.signal }, + ) + if (outcome.kind === 'detached') return + terminal = true + yield terminalEnvelope( + input.runId, + handle, + prepared, + outcome, + 2, + this.#cancelledRuns.has(input.runId), + ) + } catch (error) { + lease.fail(error) + throw error + } finally { + this.#activeRuns.delete(input.runId) + if (terminal) this.#forgetHandle(input.runId) + lease.close() + } + } + + async *reconnect(input: RecoveryInput): AsyncIterable { + const admission = requireInteractiveAdmission(input.retainedAdmission) + const prepared = await this.#resolveRecovery(input, admission) + assertInteractiveProvider(prepared) + const lease = this.#broker.open(input.runId) + this.#activeRuns.add(input.runId) + let terminal = false + try { + const handle = await this.#recoverHandle(prepared, input, admission) + if (handle === null) return + this.#rememberHandle(input.runId, handle) + this.#detachRequested.delete(input.runId) + lease.publish(handle) + const replayedSequence = replayBoundary(input, input.runId, handle) + if (replayedSequence < 1) { + yield await observedEnvelope(input.runId, handle, prepared, 1) + } + if (replayedSequence >= 2) { + terminal = true + return + } + const providerOutcome = await terminalOutcome(handle, input.signal) + if (providerOutcome !== undefined) { + terminal = true + yield terminalEnvelope( + input.runId, + handle, + prepared, + providerOutcome, + 2, + this.#cancelledRuns.has(input.runId), + ) + return + } + const outcome = await lease.outcome( + input.signal === undefined ? undefined : { signal: input.signal }, + ) + if (outcome.kind === 'detached') return + terminal = true + yield terminalEnvelope( + input.runId, + handle, + prepared, + outcome, + 2, + this.#cancelledRuns.has(input.runId), + ) + } catch (error) { + lease.fail(error) + throw error + } finally { + this.#activeRuns.delete(input.runId) + if (terminal) this.#forgetHandle(input.runId) + lease.close() + } + } + + async status(input: RecoveryInput): Promise { + const partial = interactiveAdmissionOrUndefined(input.retainedAdmission) + if ( + this.#handles.get(input.runId) === undefined && + partial !== undefined && + partial.phase !== 'interactive_started' + ) { + return partialInteractiveStatus(input.runId, partial) + } + const handle = await this.#handleFor(input) + if (handle === null) return null + const status = await handle.status({ + ...(input.signal === undefined ? {} : { signal: input.signal }), + }) + const mapped = interactiveStatus(status, this.#detachRequested.has(input.runId)) + if (status.state === 'exited') this.#forgetHandle(input.runId) + return { + runId: input.runId, + status: mapped, + sessionId: handle.ref.run.sessionId, + ...(status.state === 'unknown' ? { error: status.message, detail: status.message } : {}), + ...(status.state === 'exited' ? { detail: interactiveStatusDetail(status) } : {}), + } + } + + async detachRun(input: { + readonly runId: string + readonly operationId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly cursor?: string + readonly signal?: AbortSignal + }): Promise { + this.#assertControl(input.runId, input.providerSessionId, input.controlRef) + if (this.#detachRequested.has(input.runId)) { + return { operationId: input.operationId, outcome: 'already-applied', detail: 'detached' } + } + this.#detachRequested.add(input.runId) + this.#settleDetached(input.runId) + return { operationId: input.operationId, outcome: 'accepted', detail: 'detached' } + } + + async cancelRun( + input: CancelRunInput & { readonly signal?: AbortSignal }, + ): Promise { + const handle = this.#handles.get(input.runId) + if (handle === undefined) { + return { + operationId: input.operationId, + outcome: 'unknown', + detail: 'interactive-run-missing', + } + } + this.#assertControl(input.runId, input.providerSessionId, input.controlRef) + const control = await claimRetainedInteractiveControl({ + handle, + holderId: this.#holderId, + ...(input.signal === undefined ? {} : { signal: input.signal }), + }) + const material = { operationId: input.operationId, ref: handle.ref, control } + const acknowledgement = await handle.stop( + { ...material, requestDigest: agentInteractiveSessionStopRequestDigest(material) }, + input.signal === undefined ? undefined : { signal: input.signal }, + ) + if (acknowledgement.status === 'accepted' || acknowledgement.status === 'replayed') { + this.#cancelledRuns.add(input.runId) + this.#settleCancelled(input.runId) + this.#forgetHandle(input.runId) + return { + operationId: input.operationId, + outcome: acknowledgement.status === 'replayed' ? 'already-applied' : 'accepted', + detail: acknowledgement.effect, + } + } + return { + operationId: input.operationId, + outcome: + acknowledgement.status === 'conflict' + ? 'rejected' + : acknowledgement.status === 'unknown' + ? 'unknown' + : 'rejected', + detail: acknowledgement.effect, + } + } + + async #start( + prepared: PreparedTangleRetainedConnection, + input: ExecuteTurnInput, + ): Promise { + const onAdmission = requireAdmissionRecorder(input.onRetainedAdmission) + return startRetainedInteractiveRun({ + provider: prepared.provider, + environment: interactiveEnvironment(prepared, input.runId), + interactiveIdempotencyKey: interactiveIdempotencyKey(input.runId), + ...(input.text.trim() === '' ? {} : { initialPrompt: input.text }), + ...(input.workspaceRoot === undefined ? {} : { cwd: input.workspaceRoot }), + onAdmission, + signal: input.signal, + }) + } + + async #recoverHandle( + prepared: PreparedTangleRetainedConnection, + input: RecoveryInput, + admission: RetainedInteractiveAdmission, + ): Promise { + if (admission.phase === 'interactive_started') { + assertStartedAdmissionMatchesInput(admission, input) + return reconnectRetainedInteractiveRun({ + provider: prepared.provider, + ref: admission.ref, + ...(input.signal === undefined ? {} : { signal: input.signal }), + }) + } + const onAdmission = requireAdmissionRecorder(input.onRetainedAdmission) + if (admission.phase === 'interactive_environment') { + return recoverRetainedInteractiveRun({ + provider: prepared.provider, + admission, + onAdmission, + ...(input.signal === undefined ? {} : { signal: input.signal }), + }) + } + const receipt = requireRecoveryReceipt(input.receipt) + const profile = receipt.requested.profile + return recoverRetainedInteractiveRun({ + provider: prepared.provider, + admission, + replay: { + environment: interactiveEnvironment( + prepared, + input.runId, + admission.idempotencyKey, + profile, + ), + interactiveIdempotencyKey: admission.interactiveIdempotencyKey, + ...(receipt.requested.text.trim() === '' ? {} : { initialPrompt: receipt.requested.text }), + ...(input.workspaceRoot === undefined ? {} : { cwd: input.workspaceRoot }), + }, + onAdmission, + ...(input.signal === undefined ? {} : { signal: input.signal }), + }) + } + + async #handleFor(input: RecoveryInput): Promise { + const active = this.#handles.get(input.runId) + if (active !== undefined) { + this.#assertControl(input.runId, input.providerSessionId, input.controlRef, active.ref.run) + return active + } + const admission = requireInteractiveAdmission(input.retainedAdmission) + const prepared = await this.#resolveRecovery(input, admission) + assertInteractiveProvider(prepared) + const handle = await this.#recoverHandle(prepared, input, admission) + if (handle !== null) this.#rememberHandle(input.runId, handle) + return handle + } + + async #resolveRecovery( + input: RecoveryInput, + admission: RetainedInteractiveAdmission, + ): Promise { + const receipt = input.receipt + const profile = ( + admission.phase === 'interactive_environment' + ? admission.request.profile + : receipt?.requested.profile + ) as Readonly | undefined + if (profile === undefined) { + throw new Error('Interactive recovery requires the original run receipt') + } + const text = + admission.phase === 'interactive_environment' + ? (admission.request.initialPrompt ?? '') + : (receipt?.requested.text ?? '') + const recoveredInput: ExecuteTurnInput = { + operationId: `recover-${safeExecutionId(input.runId)}`, + runId: input.runId, + text, + profile, + mode: 'interactive', + ...(receipt?.requested.connectionId === undefined + ? {} + : { connectionId: receipt.requested.connectionId }), + ...(input.workspaceRoot === undefined ? {} : { workspaceRoot: input.workspaceRoot }), + signal: input.signal ?? new AbortController().signal, + } + return (this.#recover ?? this.#resolve)(recoveredInput) + } + + #rememberHandle(runId: string, handle: RetainedInteractiveRunHandle): void { + const previous = this.#handles.get(runId) + if ( + previous !== undefined && + canonicalCandidateDigest(previous.ref) !== canonicalCandidateDigest(handle.ref) + ) { + throw new Error('Interactive run recovered with a different process reference') + } + this.#handles.set(runId, handle) + } + + #assertControl( + runId: string, + providerSessionId?: string, + controlRef?: AgentExactRunControlRef, + expected?: AgentExactRunControlRef, + ): void { + const actual = expected ?? this.#handles.get(runId)?.ref.run + if ( + providerSessionId !== undefined && + actual !== undefined && + providerSessionId !== actual.sessionId + ) { + throw new Error('Interactive provider session conflicts with the saved run') + } + if ( + controlRef !== undefined && + actual !== undefined && + canonicalDigest(controlRef) !== canonicalDigest(actual) + ) { + throw new Error('Interactive control reference conflicts with the saved run') + } + } + + #settleDetached(runId: string): void { + if (!this.#activeRuns.has(runId)) return + switch (this.#broker.settle(runId, { kind: 'detached' })) { + case 'settled': + case 'absent': + case 'already-settled': + return + } + } + + #settleCancelled(runId: string): void { + if (!this.#activeRuns.has(runId)) return + switch (this.#broker.settle(runId, { kind: 'exited', exitSignal: 'SIGTERM' })) { + case 'settled': + case 'absent': + case 'already-settled': + return + } + } + + #forgetHandle(runId: string): void { + this.#handles.delete(runId) + if (!this.#activeRuns.has(runId)) this.#cancelledRuns.delete(runId) + } +} + +function assertInteractiveProvider(prepared: PreparedTangleRetainedConnection): void { + const interactive = prepared.capabilities.interactiveAgent + if ( + interactive?.start !== true || + interactive.control !== true || + interactive.status !== true || + interactive.attach !== true || + interactive.reattach !== true || + interactive.stop !== true + ) { + throw new Error('Tangle retained connection does not support exact interactive agents') + } +} + +function interactiveRunCapabilities(prepared: PreparedTangleRetainedConnection): RunCapabilities { + return Object.freeze({ + streaming: { live: true, replay: true, detach: true, turnIdempotency: true }, + sessions: { continue: true, messages: false }, + controls: { cancel: true, steer: false, queue: false, status: true, recreate: true }, + events: { stableIdentity: true, sequence: true, cursor: true }, + usage: false, + environment: prepared.capabilities, + }) +} + +function interactiveMaterializationReceipt( + prepared: PreparedTangleRetainedConnection, +): Readonly> { + return publicMaterializationReceipt({ + provider: prepared.provider.name, + backend: 'environment-provider', + surface: 'interactive-agent', + lifecycle: 'retained', + execution: 'agent-runtime-retained-interactive', + cleanup: 'explicit', + continuity: 'session', + idleTtlSeconds: prepared.idleTtlSeconds, + model: prepared.model, + runner: prepared.runner, + }) +} + +function interactiveEnvironment( + prepared: PreparedTangleRetainedConnection, + _runId: string, + idempotencyKey = interactiveEnvironmentIdempotencyKey(_runId), + profile = prepared.profile, +) { + return { + profile, + backend: prepared.runner, + name: `braid-interactive-${safeExecutionId(_runId)}`, + metadata: { + owner: 'braid', + lifecycle: 'retained', + surface: 'interactive-agent', + }, + idempotencyKey, + } +} + +function interactiveIdempotencyKey(runId: string): string { + return `interactive-braid-${safeExecutionId(runId)}`.slice(0, 128) +} + +function interactiveEnvironmentIdempotencyKey(runId: string): string { + return `env-braid-interactive-${safeExecutionId(runId)}`.slice(0, 128) +} + +function requireAdmissionRecorder(recorder: unknown): RetainedInteractiveAdmissionHook { + if (typeof recorder !== 'function') { + throw new Error('Retained Tangle interactive execution requires a durable admission recorder') + } + return (admission) => + (recorder as (value: RetainedInteractiveAdmission) => Promise)(admission) +} + +function requireRecoveryReceipt(input: RunAdmissionReceipt | undefined): RunAdmissionReceipt { + if (input === undefined) + throw new Error('Interactive intent recovery requires the original run receipt') + return input +} + +function requireInteractiveAdmission(value: unknown): RetainedInteractiveAdmission { + if (value === undefined || typeof value !== 'object' || value === null || !('phase' in value)) { + throw new Error('Interactive recovery requires a canonical interactive admission') + } + const phase = (value as { readonly phase?: unknown }).phase + if (typeof phase !== 'string' || !phase.startsWith('interactive_')) { + throw new Error('Interactive recovery requires a canonical interactive admission') + } + return value as RetainedInteractiveAdmission +} + +function interactiveAdmissionOrUndefined(value: unknown): RetainedInteractiveAdmission | undefined { + if (value === undefined) return undefined + return requireInteractiveAdmission(value) +} + +function partialInteractiveStatus( + runId: string, + admission: Exclude, +): ProviderRunSnapshot { + const sessionId = interactiveSessionId(admission) + return sessionId === undefined + ? { runId, status: 'unknown', detail: `replayable:${admission.phase}` } + : { runId, status: 'unknown', sessionId, detail: `replayable:${admission.phase}` } +} + +function interactiveStatusDetail(status: AgentInteractiveSessionStatus): string { + if (status.state === 'unknown') return status.message + if (!('reason' in status)) return 'interactive session running' + return !('exitCode' in status) || status.exitCode === undefined + ? `interactive session ${status.reason}` + : `interactive session ${status.reason} with code ${status.exitCode}` +} + +function interactiveSessionId(admission: RetainedInteractiveAdmission): string | undefined { + if (admission.phase === 'interactive_intent') return admission.sessionId + return admission.phase === 'interactive_environment' + ? admission.request.run.sessionId + : admission.ref.run.sessionId +} + +function assertStartedAdmissionMatchesInput( + admission: RetainedInteractiveStartedAdmission, + input: RecoveryInput, +): void { + if ( + input.providerSessionId !== undefined && + input.providerSessionId !== admission.ref.run.sessionId + ) { + throw new Error('Interactive provider session conflicts with the saved process reference') + } + if ( + input.controlRef !== undefined && + canonicalDigest(input.controlRef) !== canonicalDigest(admission.ref.run) + ) { + throw new Error('Interactive control reference conflicts with the saved process reference') + } +} + +function interactiveStatus( + status: AgentInteractiveSessionStatus, + detached: boolean, +): ProviderRunSnapshot['status'] { + if (detached && status.state === 'running') return 'detached' + if (status.state === 'running') return 'streaming' + if (status.state === 'exited' && status.reason !== 'lost') return 'completed' + return 'unknown' +} + +async function terminalOutcome( + handle: RetainedInteractiveRunHandle, + signal?: AbortSignal, +): Promise | undefined> { + const status = await handle.status(signal === undefined ? undefined : { signal }) + if (status.state !== 'exited') return undefined + return { + kind: 'exited', + ...(status.exitCode === undefined ? {} : { exitCode: status.exitCode }), + ...(status.exitSignal === undefined ? {} : { exitSignal: status.exitSignal }), + } +} + +function replayBoundary( + input: RecoveryInput, + runId: string, + handle: RetainedInteractiveRunHandle, +): number { + const cursorSequence = + input.after === undefined + ? undefined + : sequenceFromCursor(input.after, runId, handle.ref.incarnationId) + if ( + cursorSequence !== undefined && + input.afterSequence !== undefined && + cursorSequence !== input.afterSequence + ) { + throw new Error('Interactive replay cursor conflicts with the saved sequence') + } + return input.afterSequence ?? cursorSequence ?? 0 +} + +function sequenceFromCursor(cursor: string, runId: string, incarnationId: string): number { + const prefix = `${runId}:interactive:${incarnationId}:` + if (!cursor.startsWith(prefix)) { + throw new Error('Interactive replay cursor belongs to another process') + } + const sequence = Number(cursor.slice(prefix.length)) + if (!Number.isSafeInteger(sequence) || sequence < 0) { + throw new Error('Interactive replay cursor is malformed') + } + return sequence +} + +async function observedEnvelope( + runId: string, + handle: RetainedInteractiveRunHandle, + prepared: PreparedTangleRetainedConnection, + sequence: number, +): Promise { + const observation = await prepared.observation.snapshot() + if (observation === undefined) throw new Error('Tangle interactive observation is unavailable') + const receivedAt = new Date().toISOString() + return { + runId, + eventId: `${runId}:interactive:${handle.ref.incarnationId}:observed`, + sequence, + cursor: interactiveCursor(runId, handle, sequence), + occurredAt: receivedAt, + receivedAt, + event: { + type: 'braid.execution.observed', + observation, + controlRef: handle.ref.run, + timestamp: receivedAt, + }, + } +} + +function terminalEnvelope( + runId: string, + handle: RetainedInteractiveRunHandle, + prepared: PreparedTangleRetainedConnection, + outcome: Exclude, + sequence: number, + cancelled: boolean, +): RuntimeEventEnvelope { + const timestamp = new Date().toISOString() + const failed = outcome.kind === 'failed' + const reason = cancelled + ? 'Interactive agent stopped' + : failed + ? outcome.message + : outcome.exitCode === undefined + ? 'Interactive agent exited' + : `Interactive agent exited with code ${outcome.exitCode}` + return { + runId, + eventId: `${runId}:interactive:${handle.ref.incarnationId}:final`, + sequence, + cursor: interactiveCursor(runId, handle, sequence), + occurredAt: timestamp, + receivedAt: timestamp, + event: { + type: 'final', + task: { id: runId, intent: 'Run the retained Tangle interactive agent' }, + status: cancelled ? 'cancelled' : failed ? 'failed' : 'completed', + reason, + text: '', + metadata: { model: prepared.model, tokensKnown: false, usdKnown: false }, + ...(failed ? { error: { kind: 'backend', message: outcome.message } } : {}), + timestamp, + }, + } +} + +function interactiveCursor( + runId: string, + handle: RetainedInteractiveRunHandle, + sequence: number, +): string { + return `${runId}:interactive:${handle.ref.incarnationId}:${sequence}` +} diff --git a/test/interactive-execution-adapters.test.ts b/test/interactive-execution-adapters.test.ts new file mode 100644 index 0000000..ffb72a5 --- /dev/null +++ b/test/interactive-execution-adapters.test.ts @@ -0,0 +1,668 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import type { + AgentEnvironment, + AgentEnvironmentCapabilities, + AgentEnvironmentProvider, +} from '@tangle-network/agent-interface/environment-provider' +import type { AgentInteractiveSessionRef, AgentProfile } from '@tangle-network/agent-interface' +import { + AgentInteractiveSessionRefSchema, + canonicalCandidateDigest, +} from '@tangle-network/agent-interface' +import { NativeInteractiveRunBroker } from '../src/adapters/runtime/native-interactive-run-broker.js' +import { ModeRoutingExecutionPort } from '../src/adapters/runtime/mode-routing-execution.js' +import type { PreparedTangleRetainedConnection } from '../src/adapters/runtime/production-tangle-sandbox-backend.js' +import { TangleRetainedInteractiveExecutionPort } from '../src/adapters/runtime/tangle-retained-interactive-execution.js' +import type { ExecuteTurnInput, ExecutionPort } from '../src/ports/execution.js' +import type { RuntimeEventEnvelope } from '../src/domain/runtime-events.js' +import type { RetainedInteractiveAdmission } from '@tangle-network/agent-runtime/kernel' +import type { RunAdmissionReceipt } from '../src/domain/receipts.js' + +const PROFILE: AgentProfile = { + name: 'Braid interactive test', + harness: 'pi', + model: { default: 'test-model', provider: 'test-provider' }, +} + +test('the broker reports typed settlement outcomes', () => { + const broker = new NativeInteractiveRunBroker() + assert.equal(broker.settle('missing', { kind: 'detached' }), 'absent') + + const lease = broker.open('run/broker') + assert.equal(broker.settle('run/broker', { kind: 'detached' }), 'settled') + assert.equal(broker.settle('run/broker', { kind: 'detached' }), 'already-settled') + lease.close() +}) + +test('mode routing is async when either branch is async and honors canonical interactive admissions', async () => { + const calls: string[] = [] + const headless = routingPort('headless', 'sync', calls) + const interactive = routingPort('interactive', 'async', calls) + const router = new ModeRoutingExecutionPort({ headless, interactive }) + + assert.equal(router.admissionMode, 'async') + await collect(router.streamTurn(input('run/interactive', { mode: 'interactive' }))) + await router.status({ + runId: 'run/recovered', + retainedAdmission: { phase: 'interactive_intent' }, + } as never) + await collect(router.streamTurn(input('run/headless', { mode: 'headless' }))) + + assert.deepEqual(calls, ['interactive:stream', 'interactive:status', 'headless:stream']) + await assert.rejects( + () => + collect( + router.streamTurn( + input('run/mismatch', { + mode: 'headless', + retainedAdmission: { phase: 'interactive_started' }, + }), + ), + ), + /conflicts with an interactive retained admission/u, + ) +}) + +test('starts one native process, records Runtime identity, and emits replayable envelopes', async () => { + const fixture = interactiveFixture() + const broker = new NativeInteractiveRunBroker() + const port = interactivePort(fixture, broker) + const admissions: RetainedInteractiveAdmission[] = [] + const input = executionInput('run/start', async (admission) => { + admissions.push(admission) + }) + + const admission = await port.admit(input) + assert.equal(admission.providerSessionId, undefined) + const iterator = port.streamTurn(input)[Symbol.asyncIterator]() + const observed = await next(iterator) + const handle = await broker.waitForHandle(input.runId) + + assert.equal(fixture.stats.dispatchCalls, 0) + assert.equal(fixture.stats.processStarts, 1) + assert.deepEqual( + admissions.map((entry) => entry.phase), + ['interactive_intent', 'interactive_environment', 'interactive_started'], + ) + assert.equal(admission.capabilities?.streaming.replay, true) + assert.equal(admission.capabilities?.events.cursor, true) + assert.equal(observed.cursor, `${input.runId}:interactive:${handle.ref.incarnationId}:1`) + assert.equal(observed.eventId, `${input.runId}:interactive:${handle.ref.incarnationId}:observed`) + assert.equal(fixture.lastCreateMetadata?.providerSessionId, undefined) + assert.equal(fixture.lastCreateMetadata?.surface, 'interactive-agent') + + await finish(iterator, broker, input.runId) + const cancelled = await port.cancelRun({ operationId: 'cancel-after-finish', runId: input.runId }) + assert.equal(cancelled.outcome, 'unknown') +}) + +test('detach ends the foreground stream while preserving the native handle for reattachment', async () => { + const fixture = interactiveFixture() + const broker = new NativeInteractiveRunBroker() + const port = interactivePort(fixture, broker) + const input = executionInput('run/detach', async () => {}) + const iterator = port.streamTurn(input)[Symbol.asyncIterator]() + await next(iterator) + const handle = await broker.waitForHandle(input.runId) + + const detached = await port.detachRun({ + runId: input.runId, + operationId: 'detach-1', + providerSessionId: handle.ref.run.sessionId, + controlRef: handle.ref.run, + }) + assert.equal(detached.outcome, 'accepted') + assert.equal((await iterator.next()).done, true) + + const status = await port.status({ runId: input.runId }) + assert.equal(status?.status, 'detached') + const stopped = await port.cancelRun({ operationId: 'cancel-detached', runId: input.runId }) + assert.equal(stopped.outcome, 'accepted') + const stoppedAgain = await port.cancelRun({ + operationId: 'cancel-detached-again', + runId: input.runId, + }) + assert.equal(stoppedAgain.outcome, 'unknown') +}) + +test('reattach reuses the Runtime ref, honors a replay cursor, and does not start a second process', async () => { + const fixture = interactiveFixture() + const broker = new NativeInteractiveRunBroker() + const first = interactivePort(fixture, broker) + const admissions: RetainedInteractiveAdmission[] = [] + const input = executionInput('run/reattach', async (admission) => { + admissions.push(admission) + }) + const firstIterator = first.streamTurn(input)[Symbol.asyncIterator]() + const observed = await next(firstIterator) + const handle = await broker.waitForHandle(input.runId) + await first.detachRun({ + runId: input.runId, + operationId: 'detach-before-reconnect', + providerSessionId: handle.ref.run.sessionId, + controlRef: handle.ref.run, + }) + assert.equal((await firstIterator.next()).done, true) + + const started = admissions.find((entry) => entry.phase === 'interactive_started') + assert.ok(started?.phase === 'interactive_started') + const second = interactivePort(fixture, broker) + const reconnectInput = { + runId: input.runId, + retainedAdmission: started, + receipt: receiptFor(input), + after: observed.cursor, + signal: input.signal, + } as Parameters[0] + const reconnectIterator = second.reconnect(reconnectInput)[Symbol.asyncIterator]() + const finalPromise = reconnectIterator.next() + const reattached = await broker.waitForHandle(input.runId) + assert.equal(reattached.ref.run.sessionId, handle.ref.run.sessionId) + assert.equal(fixture.stats.processStarts, 1) + assert.equal(fixture.stats.startCalls, 1) + + const settlement = broker.settle(input.runId, { kind: 'exited', exitCode: 0 }) + assert.equal(settlement, 'settled') + const final = await finalPromise + assert.equal(final.done, false) + assert.equal(final.value.sequence, 2) + assert.equal(final.value.cursor, `${input.runId}:interactive:${handle.ref.incarnationId}:2`) + assert.equal((await reconnectIterator.next()).done, true) +}) + +test('partial intent and environment admissions report replayable status without recovery', async () => { + for (const phase of ['interactive_intent', 'interactive_environment'] as const) { + const fixture = interactiveFixture() + const broker = new NativeInteractiveRunBroker() + const port = interactivePort(fixture, broker) + const admissions: RetainedInteractiveAdmission[] = [] + const input = executionInput(`run/partial-${phase}`, async (admission) => { + admissions.push(admission) + if (admission.phase === phase) throw new Error(`simulated ${phase} loss`) + }) + const iterator = port.streamTurn(input)[Symbol.asyncIterator]() + await assert.rejects( + () => iterator.next(), + (error: unknown) => causedBy(error, `simulated ${phase} loss`), + ) + const partial = admissions.find((admission) => admission.phase === phase) + assert.ok(partial) + const before = { ...fixture.stats } + const status = await port.status({ + runId: input.runId, + retainedAdmission: partial, + receipt: receiptFor(input), + } as Parameters[0]) + + assert.equal(status?.status, 'unknown') + assert.equal(status?.detail, `replayable:${phase}`) + assert.deepEqual(fixture.stats, before) + } +}) + +test('reconnect recovers a persisted interactive intent exactly once', async () => { + const fixture = interactiveFixture() + const broker = new NativeInteractiveRunBroker() + const initial = interactivePort(fixture, broker) + const admissions: RetainedInteractiveAdmission[] = [] + let failIntent = true + const input = executionInput('run/recover-intent', async (admission) => { + admissions.push(admission) + if (failIntent && admission.phase === 'interactive_intent') { + throw new Error('simulated intent loss') + } + }) + const initialIterator = initial.streamTurn(input)[Symbol.asyncIterator]() + await assert.rejects( + () => initialIterator.next(), + (error: unknown) => causedBy(error, 'simulated intent loss'), + ) + const intent = admissions.find((admission) => admission.phase === 'interactive_intent') + assert.ok(intent?.phase === 'interactive_intent') + assert.equal(fixture.stats.createCalls, 0) + + failIntent = false + const recovered = interactivePort(fixture, broker) + const reconnectIterator = recovered + .reconnect({ + runId: input.runId, + retainedAdmission: intent, + receipt: receiptFor(input), + onRetainedAdmission: input.onRetainedAdmission, + signal: input.signal, + } as Parameters[0]) + [Symbol.asyncIterator]() + await next(reconnectIterator) + const handle = await broker.waitForHandle(input.runId) + assert.equal(handle.ref.run.sessionId, intent.sessionId) + assert.equal(fixture.stats.createCalls, 1) + assert.equal(fixture.stats.processStarts, 1) + assert.equal(fixture.stats.dispatchCalls, 0) + assert.equal(fixture.resolveInputs.at(-1)?.sessionId, undefined) + await finish(reconnectIterator, broker, input.runId) +}) + +test('reconnect rejects a provider session mismatch before attaching', async () => { + const fixture = interactiveFixture() + const broker = new NativeInteractiveRunBroker() + const first = interactivePort(fixture, broker) + const admissions: RetainedInteractiveAdmission[] = [] + const input = executionInput('run/mismatch', async (admission) => { + admissions.push(admission) + }) + const iterator = first.streamTurn(input)[Symbol.asyncIterator]() + await next(iterator) + const handle = await broker.waitForHandle(input.runId) + await first.detachRun({ + runId: input.runId, + operationId: 'detach-mismatch', + providerSessionId: handle.ref.run.sessionId, + controlRef: handle.ref.run, + }) + assert.equal((await iterator.next()).done, true) + const started = admissions.find((entry) => entry.phase === 'interactive_started') + assert.ok(started?.phase === 'interactive_started') + + const second = interactivePort(fixture, broker) + const reconnect = second + .reconnect({ + runId: input.runId, + retainedAdmission: started, + receipt: receiptFor(input), + providerSessionId: 'wrong-native-session', + signal: input.signal, + } as Parameters[0]) + [Symbol.asyncIterator]() + await assert.rejects(() => reconnect.next(), /conflicts with the saved process reference/u) + assert.equal(fixture.stats.processStarts, 1) +}) + +test('a second foreground execution cannot duplicate an active native process', async () => { + const fixture = interactiveFixture() + const broker = new NativeInteractiveRunBroker() + const port = interactivePort(fixture, broker) + const input = executionInput('run/no-duplicate', async () => {}) + const first = port.streamTurn(input)[Symbol.asyncIterator]() + await next(first) + const duplicate = port.streamTurn(input)[Symbol.asyncIterator]() + await assert.rejects(() => duplicate.next(), /already has an active execution/u) + assert.equal(fixture.stats.processStarts, 1) + const handle = await broker.waitForHandle(input.runId) + await port.detachRun({ + runId: input.runId, + operationId: 'detach-no-duplicate', + providerSessionId: handle.ref.run.sessionId, + controlRef: handle.ref.run, + }) + assert.equal((await first.next()).done, true) +}) + +interface InteractiveFixture { + readonly provider: AgentEnvironmentProvider + readonly prepared: PreparedTangleRetainedConnection + readonly profile: AgentProfile + readonly resolveInputs: ExecuteTurnInput[] + readonly stats: { + createCalls: number + getCalls: number + startCalls: number + processStarts: number + dispatchCalls: number + } + readonly lastCreateMetadata: Readonly> | undefined +} + +function interactiveFixture(): InteractiveFixture { + const profile = PROFILE + const resolveInputs: ExecuteTurnInput[] = [] + const stats = { createCalls: 0, getCalls: 0, startCalls: 0, processStarts: 0, dispatchCalls: 0 } + const state: { + ref?: AgentInteractiveSessionRef + lastCreateMetadata: Readonly> | undefined + } = { lastCreateMetadata: undefined } + const capabilities = interactiveCapabilities() + const environment: AgentEnvironment = { + id: 'environment-test', + provider: 'test-provider', + status: async () => ({ state: 'ready' }) as never, + async *stream() {}, + dispatch: async () => { + stats.dispatchCalls += 1 + throw new Error('headless dispatch must not run') + }, + startInteractive: async (request) => { + stats.startCalls += 1 + if (state.ref === undefined) { + stats.processStarts += 1 + state.ref = interactiveRef(request) + } + return state.ref + }, + interactive: (ref) => interactiveSession(ref) as never, + } + const provider: AgentEnvironmentProvider = { + name: 'test-provider', + capabilities: async () => capabilities, + create: async (input) => { + stats.createCalls += 1 + state.lastCreateMetadata = input.metadata + return environment + }, + get: async () => { + stats.getCalls += 1 + return environment + }, + } + const prepared = { + profile, + model: 'test-model', + runner: 'pi', + provider, + capabilities, + observation: { + snapshot: async () => ({ + kind: 'sandbox', + provider: 'test-provider', + lifecycle: 'ready', + lifecycleMode: 'retained', + cleanup: 'explicit', + continuity: 'session', + location: 'remote', + createdAt: '2026-08-16T00:00:00.000Z', + observedAt: '2026-08-16T00:00:00.000Z', + unavailable: [], + }), + }, + providerSessionId: 'headless-session-must-not-leak', + environmentIdempotencyKey: 'headless-environment-key-must-not-leak', + environmentName: 'headless-name-must-not-leak', + environmentMetadata: { + headless: true, + providerSessionId: 'headless-session-must-not-leak', + }, + idleTtlSeconds: 3600, + discoverControlRef: async () => null, + materializationReceipt: { headless: true, providerSessionId: 'headless-session-must-not-leak' }, + } as PreparedTangleRetainedConnection + return { + provider, + prepared, + profile, + resolveInputs, + stats, + get lastCreateMetadata() { + return state.lastCreateMetadata + }, + } +} + +function interactivePort(fixture: InteractiveFixture, broker: NativeInteractiveRunBroker) { + const port = new TangleRetainedInteractiveExecutionPort({ + broker, + resolve: async (input) => { + fixture.resolveInputs.push(input) + return { ...fixture.prepared, profile: input.profile } + }, + }) + return port +} + +function executionInput( + runId: string, + onRetainedAdmission: (admission: RetainedInteractiveAdmission) => Promise, +): ExecuteTurnInput { + return { + operationId: `operation-${runId}`, + runId, + text: 'Inspect this workspace.', + profile: PROFILE, + mode: 'interactive', + signal: new AbortController().signal, + onRetainedAdmission: async (admission) => { + await onRetainedAdmission(admission as unknown as RetainedInteractiveAdmission) + }, + } +} + +function receiptFor(input: ExecuteTurnInput): RunAdmissionReceipt { + return { + version: 1, + runId: input.runId, + turnId: 'turn-test', + operationId: input.operationId, + conversationId: 'conversation-test', + branchId: 'branch-test', + admittedAt: '2026-08-16T00:00:00.000Z', + profileDigest: `sha256:${'1'.repeat(64)}`, + requested: { text: input.text, profile: input.profile }, + capabilities: {} as RunAdmissionReceipt['capabilities'], + requestDigest: `sha256:${'2'.repeat(64)}`, + capabilitiesDigest: `sha256:${'3'.repeat(64)}`, + digest: `sha256:${'4'.repeat(64)}`, + } +} + +function causedBy(error: unknown, message: string): boolean { + return error instanceof Error && error.cause instanceof Error && error.cause.message === message +} + +async function next(iterator: AsyncIterator): Promise { + const result = await iterator.next() + assert.equal(result.done, false) + return (result as IteratorYieldResult).value +} + +async function finish( + iterator: AsyncIterator, + broker: NativeInteractiveRunBroker, + runId: string, +): Promise { + assert.equal(broker.settle(runId, { kind: 'exited', exitCode: 0 }), 'settled') + const final = await next(iterator) + assert.equal(final.sequence, 2) + assert.equal((await iterator.next()).done, true) +} + +async function collect(iterable: AsyncIterable): Promise { + for await (const _event of iterable) { + return + } +} + +function routingPort( + label: string, + admissionMode: 'sync' | 'async', + calls: string[], +): ExecutionPort { + return { + admissionMode, + capabilities: () => ({ + streaming: { live: true, replay: false, detach: false, turnIdempotency: true }, + sessions: { continue: false, messages: false }, + controls: { cancel: false, steer: false, queue: false, status: false, recreate: false }, + events: { stableIdentity: false, sequence: true, cursor: false }, + usage: false, + }), + streamTurn: async function* () { + calls.push(`${label}:stream`) + yield* [] + }, + status: async () => { + calls.push(`${label}:status`) + return null + }, + } +} + +function input(runId: string, overrides: Record = {}): ExecuteTurnInput { + return { + operationId: `operation-${runId}`, + runId, + text: 'test', + profile: PROFILE, + signal: new AbortController().signal, + ...overrides, + } as ExecuteTurnInput +} + +function interactiveCapabilities(): AgentEnvironmentCapabilities { + return { + profile: { + namedProfiles: true, + systemPrompt: { replace: true, append: true }, + instructions: true, + tools: true, + permissions: true, + mcp: true, + subagents: true, + resources: { files: true, instructions: true }, + runtimeUpdate: true, + validation: true, + }, + streaming: { live: true, replay: true, detach: true, turnIdempotency: true }, + sessions: { continue: true, list: true, messages: true }, + retainedControl: { + exactRunIdentity: true, + resultIdentity: true, + eventIdentity: true, + cancellationIdempotency: true, + }, + workspace: { read: true, write: true, exec: true, git: true, upload: true, download: true }, + branching: { checkpoint: false, fork: false }, + placement: true, + usage: false, + confidential: false, + interactiveAgent: { + start: true, + control: true, + status: true, + attach: true, + reattach: true, + sendPrompt: true, + input: true, + resize: true, + stop: true, + }, + } +} + +function interactiveRef( + request: Parameters>[0], +): AgentInteractiveSessionRef { + const preparationReceipt = { + kind: 'agent-execution-preparation' as const, + schemaVersion: 1 as const, + preparationId: 'preparation-test', + requestDigest: request.run.requestDigest, + authoredProfileDigest: request.requestedProfileDigest, + effectiveProfileDigest: request.requestedProfileDigest, + backend: 'test-backend', + harness: request.profile.harness ?? 'pi', + harnessVersion: 'test-harness-1', + resolvedModel: { + requested: request.profile.model?.default ?? 'test-model', + resolved: request.profile.model?.default ?? 'test-model', + }, + workspace: { + leaseId: 'workspace-lease-test', + provider: 'test-provider', + identityDigest: digest('2'), + isolation: 'per-run' as const, + sourceSnapshotDigest: digest('3'), + sourceSnapshotPolicy: { + kind: 'provider-declared' as const, + name: 'test', + version: 1, + digest: digest('4'), + }, + preparedWorkspaceDigest: digest('5'), + profileActivationDigest: digest('6'), + }, + axisResults: [], + executionPlanDigest: digest('7'), + materializer: { name: 'test-materializer', version: '1' }, + expiresAtMs: 4102444800000, + } + return AgentInteractiveSessionRefSchema.parse({ + run: request.run, + preparationReceipt: { + ...preparationReceipt, + digest: canonicalCandidateDigest(preparationReceipt), + }, + incarnationId: 'incarnation-test', + startedAt: '2026-08-16T00:00:00.000Z', + }) +} + +function interactiveSession(ref: AgentInteractiveSessionRef) { + const control = (holderId: string) => ({ + refDigest: canonicalCandidateDigest(ref), + generation: 1, + leaseId: 'interactive-lease-test', + holderId, + expiresAt: '2026-08-17T00:00:00.000Z', + }) + return { + ref, + claimControl: async (request: { + operationId: string + requestDigest: string + holderId: string + }) => ({ + operationId: request.operationId, + requestDigest: request.requestDigest, + ref, + status: 'accepted' as const, + control: control(request.holderId), + }), + status: async () => ({ state: 'running' as const, ref }), + attach: async (request: { control: unknown }) => ({ + ref: { + terminalSessionId: 'terminal-test', + parentExecutionId: ref.run.executionId, + name: 'pi', + shell: '/bin/sh', + command: 'pi', + cwd: '/workspace', + cols: 120, + rows: 40, + createdAt: '2026-08-16T00:00:00.000Z', + lastActivityAt: '2026-08-16T00:00:00.000Z', + expiresAt: '2026-08-17T00:00:00.000Z', + isRunning: true, + attachCount: 1, + }, + control: request.control, + cursors: { earliest: 0, latest: 0 }, + input: async () => {}, + resize: async () => {}, + detach: async () => ({ status: 'detached' as const, terminalSessionId: 'terminal-test' }), + close: async () => ({ status: 'closed' as const, terminalSessionId: 'terminal-test' }), + async *events() {}, + }), + sendPrompt: async (command: { + operationId: string + requestDigest: string + control: unknown + }) => ({ + operationId: command.operationId, + requestDigest: command.requestDigest, + ref, + control: command.control, + status: 'accepted' as const, + }), + stop: async (command: { operationId: string; requestDigest: string; control: unknown }) => ({ + operationId: command.operationId, + requestDigest: command.requestDigest, + ref, + control: command.control, + status: 'accepted' as const, + effect: 'stopped' as const, + }), + } +} + +function digest(seed: string): `sha256:${string}` { + return `sha256:${seed.repeat(64).slice(0, 64)}` +} From d666640501245ee3dd87ab481ec7653243332c4c Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 19 Aug 2026 05:15:17 -0600 Subject: [PATCH 19/25] feat(runtime): unify durable retained interactions --- .../findings.jsonl | 8 + .../manifest.json | 25 + .../summary.md | 50 + .../2026-08-19-orchestrate-braid-launch.md | 31 + .agent/skill-runs.jsonl | 7 + docs/02-experience-specification.md | 29 +- scripts/live-bridge/bridge.mjs | 4 +- scripts/live-bridge/redaction.mjs | 39 +- .../release-proof-validation.test.mjs | 97 +- scripts/live-bridge/target-actions.mjs | 5 +- scripts/live-bridge/target-flow.mjs | 16 +- scripts/live-required.test.mjs | 17 + .../tangle-sandbox-braid-soak.mjs | 7 +- .../tangle-sandbox-braid-stress.mjs | 9 +- .../tangle-sandbox-interactive-continuity.mjs | 995 ++++++++++++++++++ ...le-sandbox-interactive-continuity.test.mjs | 312 ++++++ scripts/test-pty.mjs | 8 +- .../tangle-retained-control-lookup.ts | 7 +- .../runtime/cli-bridge-retained-execution.ts | 20 +- .../runtime/cli-bridge-retained-run.ts | 130 ++- .../runtime/mode-routing-execution.ts | 14 +- .../runtime/production-backend-common.ts | 14 +- .../runtime/production-cli-bridge-backend.ts | 4 +- .../production-tangle-sandbox-backend.ts | 15 +- .../runtime/retained-execution-contract.ts | 24 +- .../runtime/retained-execution-state.ts | 14 +- src/adapters/runtime/retained-execution.ts | 289 ++++- .../runtime/tangle-retained-execution.ts | 19 +- .../tangle-retained-interactive-contract.ts | 207 ++++ .../tangle-retained-interactive-execution.ts | 542 ++++------ .../tangle-retained-interactive-projection.ts | 154 +++ .../runtime/tangle-sandbox-retention.ts | 7 +- src/app/application-ports.ts | 7 +- src/app/composition.ts | 14 +- src/app/control-effects.ts | 12 +- src/app/interaction-controller.ts | 2 + src/app/interaction-effects.ts | 19 +- src/app/production-composition.ts | 84 +- src/app/run-admission-receipt.ts | 2 +- src/app/run-controls.ts | 3 + src/bin/braid-runtime.ts | 10 +- src/bin/native-interactive-actions.ts | 12 +- src/bin/production-application.ts | 5 +- src/domain/run-contracts.ts | 1 - src/{app => domain}/run-interactions.ts | 9 +- src/index.ts | 210 ++-- src/ports/execution.ts | 55 +- .../shared/native-interactive-actions.ts} | 0 src/views/tui/activity-browser.ts | 16 +- src/views/tui/profile-editor-rendering.ts | 4 +- src/views/tui/profile-editor.ts | 28 +- src/views/tui/terminal-app.ts | 2 +- src/views/tui/terminal-command-controller.ts | 16 +- src/views/tui/terminal-identity.ts | 88 +- src/views/tui/terminal-overlays.ts | 9 +- test/cli-bridge-interactions.test.ts | 170 ++- test/cli-bridge-retained-restart.test.ts | 75 +- test/configuration-product-flow.test.ts | 6 +- test/configuration-wizard.test.ts | 2 +- test/interactive-execution-adapters.test.ts | 306 +++++- test/native-interactive-command.test.ts | 2 +- test/production-composition.test.ts | 82 +- test/profiles.test.ts | 2 +- test/retained-execution-lifecycle.test.ts | 127 ++- test/run-interactions.test.ts | 2 +- test/support/tangle-retained-sandbox.ts | 12 + test/tangle-retained-lifecycle.test.ts | 82 +- test/tangle-retained-restart.test.ts | 2 +- test/terminal-responsive.test.ts | 19 +- test/terminal-usage-status.test.ts | 12 +- test/w6-ui.test.ts | 2 +- 71 files changed, 3881 insertions(+), 749 deletions(-) create mode 100644 .agent/critical-audit/2026-08-19-braid-durable-interaction/findings.jsonl create mode 100644 .agent/critical-audit/2026-08-19-braid-durable-interaction/manifest.json create mode 100644 .agent/critical-audit/2026-08-19-braid-durable-interaction/summary.md create mode 100644 .agent/pursuits/2026-08-19-orchestrate-braid-launch.md create mode 100644 scripts/live-required/tangle-sandbox-interactive-continuity.mjs create mode 100644 scripts/live-required/tangle-sandbox-interactive-continuity.test.mjs create mode 100644 src/adapters/runtime/tangle-retained-interactive-contract.ts create mode 100644 src/adapters/runtime/tangle-retained-interactive-projection.ts rename src/{app => domain}/run-interactions.ts (66%) rename src/{ports/native-interactive-ui.ts => views/shared/native-interactive-actions.ts} (100%) diff --git a/.agent/critical-audit/2026-08-19-braid-durable-interaction/findings.jsonl b/.agent/critical-audit/2026-08-19-braid-durable-interaction/findings.jsonl new file mode 100644 index 0000000..c9d546f --- /dev/null +++ b/.agent/critical-audit/2026-08-19-braid-durable-interaction/findings.jsonl @@ -0,0 +1,8 @@ +{"id":1,"priority":"P1","severity":"HIGH","file":"src/adapters/runtime/retained-execution-state.ts","line":15,"defect":"The retained execution key did not always include the canonical requested interaction map.","scenario":"The same run and operation are prepared with a changed plan, question, or approval set, then the process-local key reuses state for a different interaction contract.","status":"measured before patch · resolved","evidence":"src/adapters/runtime/retained-execution-state.ts:15-32; src/domain/run-interactions.ts; test/tangle-retained-lifecycle.test.ts:377-402","fix":"Derive the canonical interaction map from the retained plan capabilities when the request does not carry it.","verification":"Focused retained and interactive suites → 42/42 pass.","costIfShipped":"1 incompatible preparation can reuse the wrong interaction contract.","savedIfFixed":"1 of 1 interaction-key regression cases now rejects the mismatch.","claimLevel":"measured"} +{"id":2,"priority":"P1","severity":"HIGH","file":"src/app/production-composition.ts","line":192,"defect":"Production retained recovery did not preserve the persisted receipt, admission, session, and workspace identity across process restart.","scenario":"A process restarts after retained admission, then recovery reconstructs a weaker request and cannot attach to the exact admitted provider run.","status":"measured before patch · resolved","evidence":"src/app/production-composition.ts:192-246; src/adapters/runtime/tangle-retained-execution.ts:20-35; test/tangle-retained-restart.test.ts:62-225","fix":"Build recovery input from persisted receipt and admission data, and pass it through both retained provider adapters.","verification":"Focused retained and interactive suites → 42/42 pass; typecheck passes.","costIfShipped":"1 restart can lose exact retained-run attachment and replay.","savedIfFixed":"1 of 1 restart recovery cases now retains the saved identity.","claimLevel":"measured"} +{"id":3,"priority":"P1","severity":"HIGH","file":"src/adapters/runtime/production-backend-common.ts","line":105,"defect":"Provider execution identity used normalization and truncation that could collide for distinct opaque environment or session IDs.","scenario":"Two provider IDs share the retained readable prefix, then lookup or cleanup addresses the wrong environment.","status":"measured before patch · resolved","evidence":"src/adapters/runtime/production-backend-common.ts:105-121; src/adapters/connections/tangle-retained-control-lookup.ts:22-35; test/interactive-execution-adapters.test.ts:490-496; test/tangle-retained-lifecycle.test.ts:239-306","fix":"Preserve safe IDs and append a bounded digest for unsafe or long IDs through one shared identity helper.","verification":"Focused retained and interactive suites → 42/42 pass.","costIfShipped":"1 colliding provider identity can redirect control or cleanup.","savedIfFixed":"2 of 2 collision and length regression checks now pass.","claimLevel":"measured"} +{"id":4,"priority":"P1","severity":"HIGH","file":"src/adapters/runtime/tangle-retained-interactive-execution.ts","line":106,"defect":"Interactive cancellation and control races could forward an expired foreground signal or materialize work after a persisted cancellation.","scenario":"Cancellation overlaps start, restart recovery, or provider stop, then the adapter either aborts its own control call or creates provider work after the user requested cancellation.","status":"measured before patch · resolved","evidence":"src/adapters/runtime/tangle-retained-interactive-execution.ts:106-119,250-376,400-412; src/adapters/runtime/retained-execution.ts:203-300; test/interactive-execution-adapters.test.ts:327-471; test/retained-execution-lifecycle.test.ts:286-331","fix":"Coalesce one start promise, recheck cancellation before materialization, and strip an already-aborted foreground signal before native claim or stop.","verification":"Focused retained and interactive suites → 42/42 pass, including no-provider-after-cancel and stop-signal checks.","costIfShipped":"1 provider process or failed control call per affected cancellation race.","savedIfFixed":"4 of 4 cancellation and signal regression cases now pass.","claimLevel":"measured"} +{"id":5,"priority":"P1","severity":"HIGH","file":"src/adapters/runtime/retained-execution.ts","line":114,"defect":"Restarted retained controls did not consistently validate supplied provider session and control references against the persisted admission.","scenario":"A caller supplies a stale or foreign reference after restart, then detach, status, reconnect, or recovery can target a different process or materialize pre-dispatch work.","status":"measured before patch · resolved","evidence":"src/adapters/runtime/retained-execution.ts:114-191,406-435,565-602; src/adapters/runtime/tangle-retained-interactive-contract.ts:145-178; test/retained-execution-lifecycle.test.ts:209-272; test/interactive-execution-adapters.test.ts:190-229","fix":"Validate persisted session and exact control identity before recovery, while preserving the explicit rejected acknowledgement for persisted intent cancellation.","verification":"Focused retained and interactive suites → 42/42 pass.","costIfShipped":"1 stale control request can act on the wrong retained identity.","savedIfFixed":"3 of 3 session, control-reference, and pre-dispatch admission checks now pass.","claimLevel":"measured"} +{"id":6,"priority":"P1","severity":"HIGH","file":"src/adapters/runtime/tangle-retained-interactive-execution.ts","line":240,"defect":"Detaching a persisted partial native admission recovered and materialized a provider process.","scenario":"A process restarts after intent or environment admission but before provider start, then detach creates native work that the user asked to leave detached.","status":"measured before patch · resolved","evidence":"src/adapters/runtime/tangle-retained-interactive-execution.ts:240-274; test/interactive-execution-adapters.test.ts:379-423","fix":"Mark partial persisted admissions detached without materializing a native handle.","verification":"Focused retained and interactive suites → 42/42 pass, including the no-materialization regression.","costIfShipped":"1 unintended provider process per detached partial admission.","savedIfFixed":"1 of 1 detached-partial regression cases now avoids provider start.","claimLevel":"measured"} +{"id":7,"priority":"P1","severity":"HIGH","file":"src/adapters/runtime/tangle-retained-interactive-contract.ts","line":42,"defect":"The installed Runtime native interactive handle has no structured interaction response method, so Braid cannot safely advertise plan, question, or approval responses on that path.","scenario":"A native Tangle run exposes structured interaction actions, but the canonical response route has no provider operation and would require a second protocol or duplicate execution.","status":"measured · unresolved dependency boundary","evidence":"src/adapters/runtime/tangle-retained-interactive-contract.ts:42-53; installed @tangle-network/agent-runtime AgentInteractiveSession surface; pnpm run test:coordination → 66/67 with 1 failure; pnpm run test:contract → 195/196 with the same failure","fix":"Fail closed by removing unsupported structured interactions from native capabilities until the Runtime package adds the canonical response operation.","verification":"The local fail-closed behavior passes focused suites; the two broader suites retain the same dependency-only failure: provider cli-bridge rejects permission, question, and plan interactions.","costIfShipped":"1 native structured response request cannot complete on the current released dependency.","savedIfFixed":"1 unsupported action path is hidden instead of creating a duplicate or false control route.","claimLevel":"measured"} +{"id":8,"priority":"P2","severity":"MEDIUM","file":"src/adapters/runtime/tangle-retained-interactive-projection.ts","line":42,"defect":"Native PTY bytes are not part of Braid's durable logical event journal, so exact byte-transcript replay is not available after restart.","scenario":"A user detaches and later attaches a native session, then Braid replays synthetic observation and final envelopes but cannot replay every terminal byte from the prior attachment.","status":"measured · unresolved design boundary","evidence":"src/adapters/runtime/tangle-retained-interactive-projection.ts:42-154; src/ports/native-interactive-execution.ts:8-15; pnpm run test:virtual-terminal → 147/147 pass for the supported synthetic replay boundary","fix":"No safe local fix exists without adding a second terminal transport or changing the Runtime provider contract; retain the single native attachment path.","verification":"Virtual-terminal suite passes 147/147 and proves synthetic replay, not byte-for-byte PTY history.","costIfShipped":"1 native session lacks exact byte history after a process restart.","savedIfFixed":"No local savings claimed; a provider-level transcript contract is required.","claimLevel":"measured boundary"} diff --git a/.agent/critical-audit/2026-08-19-braid-durable-interaction/manifest.json b/.agent/critical-audit/2026-08-19-braid-durable-interaction/manifest.json new file mode 100644 index 0000000..e8db289 --- /dev/null +++ b/.agent/critical-audit/2026-08-19-braid-durable-interaction/manifest.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "scope": "Braid current uncommitted durable-interaction and TUI architecture", + "files": 70, + "base": "e3ed3d16f178839560ae4809c8c4df2914bab32e", + "head": "e3ed3d16f178839560ae4809c8c4df2914bab32e", + "workingTree": true, + "diffSha256": "b7eb2ad86f91f334caa6e5d916d36198f3683ed351ae4ff4884c99caeba24d74", + "projectType": "Node.js ESM package", + "reviewers": [ + "primary: retained lifecycle, identity, cancellation, replay, and TUI boundaries", + "independent pass attempted; no usable report returned" + ], + "mode": "current working-tree adversarial review with focused local checks", + "verdict": "REQUEST_CHANGES", + "counts": { + "critical": 0, + "high": 7, + "medium": 1, + "low": 0, + "resolved": 6, + "unresolved": 2, + "dropped": 0 + } +} diff --git a/.agent/critical-audit/2026-08-19-braid-durable-interaction/summary.md b/.agent/critical-audit/2026-08-19-braid-durable-interaction/summary.md new file mode 100644 index 0000000..b0f78d1 --- /dev/null +++ b/.agent/critical-audit/2026-08-19-braid-durable-interaction/summary.md @@ -0,0 +1,50 @@ +# Audit: Braid durable interaction and TUI architecture — e3ed3d1..e3ed3d1 — n=70 files, 8 findings + +**Verdict:** REQUEST_CHANGES — one P1 dependency boundary remains · 0 CRITICAL / 1 HIGH open / 6 HIGH fixed / 1 MEDIUM open +**Worst:** #7 `src/adapters/runtime/tangle-retained-interactive-contract.ts:42` — the released Runtime cannot answer structured native interactions. +**Next:** release the canonical native response operation, then rerun coordination and contract suites. + +## Scope + +| Field | Value | +|---|---| +| Files | n=70 source paths reviewed: 63 tracked changes plus 7 untracked paths; 3 audit files are excluded | +| Base..head | `e3ed3d16f178839560ae4809c8c4df2914bab32e..e3ed3d16f178839560ae4809c8c4df2914bab32e` | +| Project type | Node.js ESM package | +| Review focus | durable identity, restart recovery, interaction normalization, cancellation, control races, routing, ownership, TUI behavior | +| Not inspected | Provider changes not present in this worktree; package manifests were intentionally not edited. | + +## Findings — 8 total, ranked + +| # | Priority | file:line | Defect | Failure scenario | Status | Evidence | Fix | Verification | Cost if shipped | Saved if fixed | +|---:|---|---|---|---|---|---|---|---|---|---| +| 1 | P1 | `src/adapters/runtime/retained-execution-state.ts:15` | Retained key omitted the canonical interaction map. | Changed plan interactions reused incompatible prepared state. | fixed | key regression test | Derive the map from plan capabilities. | focused 42/42 | 1 incompatible preparation can reuse wrong state | 1/1 regression cases pass | +| 2 | P1 | `src/app/production-composition.ts:192` | Restart recovery dropped persisted identity data. | Recovery could not attach to the exact admitted provider run. | fixed | restart test | Preserve receipt, admission, session, and workspace. | focused 42/42 | 1 restart can lose exact attachment | 1/1 restart case passes | +| 3 | P1 | `src/adapters/runtime/production-backend-common.ts:105` | Opaque provider IDs could collide after normalization. | Lookup or cleanup could address the wrong environment. | fixed | identity and long-session tests | Use bounded readable IDs with a digest. | focused 42/42 | 1 collision can redirect control | 2/2 identity checks pass | +| 4 | P1 | `src/adapters/runtime/tangle-retained-interactive-execution.ts:106` | Cancellation races used stale signals or materialized late work. | Stop overlapped start or restart recovery could fail or create work after cancel. | fixed | cancellation and stop-signal tests | Coalesce start, recheck cancel, and strip expired signals. | focused 42/42 | 1 process or failed call per race | 4/4 regression cases pass | +| 5 | P1 | `src/adapters/runtime/retained-execution.ts:114` | Restarted controls did not fully validate saved identity. | A stale reference could target another retained process. | fixed | control identity tests | Validate session and exact persisted references. | focused 42/42 | 1 stale request can target wrong identity | 3/3 checks pass | +| 6 | P1 | `src/adapters/runtime/tangle-retained-interactive-execution.ts:240` | Partial native detach materialized provider work. | Detaching an intent after restart could start a process. | fixed | no-materialization test | Detach partial admission without recovery. | focused 42/42 | 1 unintended process per case | 1/1 case passes | +| 7 | P1 | `src/adapters/runtime/tangle-retained-interactive-contract.ts:42` | Native structured responses are unsupported by the released Runtime. | Plan, question, or approval response has no canonical provider operation. | open dependency | coordination 66/67 and contract 195/196 share one installed-Runtime failure | Hide unsupported actions until the Runtime release adds the operation. | local fail-closed tests pass | 1 native structured response cannot complete | 1 false action path hidden | +| 8 | P2 | `src/adapters/runtime/tangle-retained-interactive-projection.ts:42` | Native PTY bytes are outside the durable logical journal. | Restart replay returns synthetic envelopes, not every prior terminal byte. | open design | projection source and virtual-terminal 147/147 | Requires a provider-level transcript contract; no duplicate local terminal protocol. | supported synthetic boundary passes | 1 byte transcript is unavailable after restart | none claimed locally | + +No P0 defect was confirmed. +No TUI mode-specific execution path or duplicate provider execution was confirmed. + +## Proof + +- `pnpm run typecheck` passed. +- Biome checked 54 changed TypeScript files and passed. +- Focused retained, interactive, identity, restart, and cancellation tests passed 42/42. +- `pnpm run test:virtual-terminal` passed 147/147. +- `pnpm run boundaries` passed with zero cyclic strongly connected components. +- `pnpm run dependencies:check` passed with no high or critical vulnerability finding. +- `git diff --check` passed. +- No `package.json` or `pnpm-lock.yaml` path changed. +- No commit or push was performed. + +The coordination and contract suites each retain one dependency-only failure. +The installed Runtime rejects the fixture interaction map `permission, question, plan` for provider `cli-bridge`. + +## Self-gate + +9/9 passed — verdict has a number; every finding has file and line; every finding has a scenario; every finding has status; every finding has evidence; every finding has a fix or explicit dependency boundary; every finding has verification; every finding has cost on both sides; no P0 claim lacks a check. diff --git a/.agent/pursuits/2026-08-19-orchestrate-braid-launch.md b/.agent/pursuits/2026-08-19-orchestrate-braid-launch.md new file mode 100644 index 0000000..7333a8b --- /dev/null +++ b/.agent/pursuits/2026-08-19-orchestrate-braid-launch.md @@ -0,0 +1,31 @@ +# Braid launch workflow + +## Goal + +Ship one durable interaction path across CLI Bridge and Tangle Sandbox. + +## Structure + +Three source-package tracks run in parallel. +Package publication is the only barrier because Braid must consume released artifacts. + +1. Agent SDK: finish CLI Bridge discovery, replay, request forwarding, and process-restart proof. +2. Agent Runtime: merge exact retained event identity and publish it. +3. Sandbox: finish exact process control, browser attachment, and restart proof. +4. Braid: adopt the releases, remove temporary paths, and run both real recovery flows. +5. Release: capture the terminal flow, merge, publish, and verify a clean install. + +## Coordination + +- Four existing workers cover disjoint Agent SDK, Runtime, and Sandbox files. +- The operator owns integration, commits, package publication, and production claims. +- Each source-package change receives an independent adversarial review. +- A worker failure does not stop the other package tracks. + +## Acceptance + +- Pi survives Bridge process restart and resumes from a nonzero event cursor without duplicates. +- A Tangle cloud process survives client restart and rejects stale process identities. +- Questions, permissions, plans, and worker activity use canonical typed events. +- Braid contains no provider output parser or duplicate execution path. +- A clean published install reproduces both real flows and the recorded terminal UX. diff --git a/.agent/skill-runs.jsonl b/.agent/skill-runs.jsonl index 3fa2a6d..c05baa5 100644 --- a/.agent/skill-runs.jsonl +++ b/.agent/skill-runs.jsonl @@ -59,3 +59,10 @@ {"skill":"/reconcile","ts":"2026-08-13T21:45:28Z","project":"braid-goal-latest-wt","target":"cordiverse/cordis as a Braid foundation","operatorPrompt":"","durationMin":null,"verdict":"REJECT","dispatchedTo":"/stop","operatorOverride":null,"transcriptPath":null,"traceDir":null} {"skill":"/autopsy","ts":"2026-08-13T21:58:28Z","project":"braid-goal-latest-wt","target":"Sandbox isolated package smoke skipped prepack","operatorPrompt":"","durationMin":null,"verdict":"FIXED_INFRA_BUG","dispatchedTo":"/verify","operatorOverride":null,"transcriptPath":null,"traceDir":null} {"skill":"/deep-clean","ts":"2026-08-15T03:11:57Z","project":"braid-goal-latest-wt","target":"Braid release branch: removed stale generated artifacts and speculative release machinery","operatorPrompt":"","durationMin":null,"verdict":"GREEN","dispatchedTo":"/converge","operatorOverride":null,"transcriptPath":null,"traceDir":null} +{"skill":"/product-design-audit","ts":"2026-08-19T06:09:04Z","project":"braid-exact-interactive-20260816","target":"Braid bounded TUI route metadata, profile framing, activity header, and focused verification","operatorPrompt":"","durationMin":null,"verdict":"PASS","dispatchedTo":"/stop","operatorOverride":null,"transcriptPath":null,"traceDir":null} +{"skill":"/product-design","ts":"2026-08-19T06:09:04Z","project":"braid-exact-interactive-20260816","target":"Braid bounded TUI route metadata, profile framing, and responsive proof","operatorPrompt":"","durationMin":null,"verdict":"PASS","dispatchedTo":"/product-design-audit","operatorOverride":null,"transcriptPath":null,"traceDir":null} +{"skill":"/report","ts":"2026-08-19T07:02:22Z","project":"braid-exact-interactive-20260816","target":"Braid dependency on Sandbox UI","operatorPrompt":"","durationMin":null,"verdict":"PASS","dispatchedTo":"/stop","operatorOverride":null,"transcriptPath":null,"traceDir":null} +{"skill":"/diagnose","ts":"2026-08-19T08:55:46Z","project":"braid-exact-interactive-20260816","target":"Braid contract/headless/PTY baseline and retained interactive failures","operatorPrompt":"","durationMin":null,"verdict":"Braid-owned failures fixed; three pinned dependency failures remain","dispatchedTo":"/verify","operatorOverride":null,"transcriptPath":null,"traceDir":null} +{"skill":"/verify","ts":"2026-08-19T08:55:46Z","project":"braid-exact-interactive-20260816","target":"Braid retained/headless/native PTY verification","operatorPrompt":"","durationMin":null,"verdict":"HOLD: 761/766 full tests pass; 3 external failures remain","dispatchedTo":"upgrade the owning dependencies, then rerun contract and production native routing","operatorOverride":null,"transcriptPath":null,"traceDir":null} +{"skill":"/verify","ts":"2026-08-19T08:59:19Z","project":"braid-exact-interactive-20260816","target":"Braid retained/headless/native PTY verification (final)","operatorPrompt":"","durationMin":null,"verdict":"HOLD: 762/766 full tests pass; 2 pinned dependency failures remain","dispatchedTo":"upgrade the owning dependencies, then rerun contract and production native routing","operatorOverride":null,"transcriptPath":null,"traceDir":null} +{"skill":"/critical-audit","ts":"2026-08-19T11:05:46Z","project":"braid-exact-interactive-20260816","target":"Braid durable interaction and TUI architecture n=70 files","operatorPrompt":"","durationMin":null,"verdict":"REQUEST_CHANGES","dispatchedTo":"/stop","operatorOverride":null,"transcriptPath":null,"traceDir":null} diff --git a/docs/02-experience-specification.md b/docs/02-experience-specification.md index 77f076e..2976178 100644 --- a/docs/02-experience-specification.md +++ b/docs/02-experience-specification.md @@ -72,7 +72,7 @@ If a connection is unavailable, the conversation opens offline and retains full ## Main shell -### Standard layout from 80 to 119 columns +### Standard layout from 60 to 99 columns ```text user Explain the failing integration test. @@ -86,7 +86,7 @@ If a connection is unavailable, the conversation opens offline and retains full › _ - profile Release engineer · pi / glm-5.2 · backend CLI Bridge / commands + profile Release engineer · pi / glm-5.2 · via Local CLI Bridge in 1.2k · out 567 · $0.0312 · latency 120ms ``` @@ -94,15 +94,17 @@ The main shell has no persistent header. The transcript begins at the top of the viewport and remains visually primary. -The calm context rail uses one identity/status row from 60 through 99 columns. +The calm context rail uses one compact identity/status row from 60 through 99 columns. -At 100 columns and above, it uses a second row only for known sandbox facts and measured token, cost, or latency values. +At 100 columns and above, the first row labels the profile, harness, model, and backend. + +It adds a distinct connection, configured reasoning and caps, known sandbox facts, and measured values when they fit. Remote or sandbox execution appears there only when location changes the user's mental model. -The composer has no border during normal input and keeps at least three usable rows. +The composer has separators above and below normal input and keeps at least three usable rows. -Autocomplete adds one divider between input and results. +Autocomplete appears below the composer separator without adding another outer panel. The composer grows to at most 40% of terminal height, then scrolls internally. @@ -150,7 +152,7 @@ The physical machine IP, effective resource allocation, and per-sandbox CPU, RAM Headless state retains complete measurement status, including unavailable fields, for automation and audit. -### Wide layout at 120 columns and above +### Wide layout at 100 columns and above ```text user Fix the replay race and run the focused tests. │ live work @@ -161,18 +163,19 @@ Headless state retains complete measurement status, including unavailable fields › _ - profile reviewer · codex / openai/gpt-5.6 · sandbox · xhigh working · Ctrl+C cancel + profile reviewer · harness codex · model openai/gpt-5.6 · backend Sandbox · think xhigh + working · Ctrl+C cancel ``` -The right pane is hidden by default, including while a run is active. +The main shell has no activity pane, including while a run is active. -F2 toggles one live-work pane that contains only active, waiting, detached, or reconnecting work. +F2 opens the focused activity browser for active and historical work. -Completed history remains available through `/activity` instead of accumulating in the pane. +The activity browser uses one list/detail surface and keeps direct turns, analyses, and workers distinct. Graph, details, and workspace views use focused overlays. -The pane never reduces the transcript below 72 columns; below that boundary it becomes an overlay. +No secondary surface reduces the transcript below its minimum width because secondary surfaces replace the shell. ### Narrow layout below 80 columns @@ -317,7 +320,7 @@ Destructive or externally consequential commands show the resolved target before | `PageUp` / `PageDown` | Scroll the focused transcript or list by one viewport | | `Home` / `End` | Move within the editor or to list boundaries according to focus | | `Alt+Up` / `Alt+Down` | Navigate adjacent branches or graph nodes | -| `F2` | Toggle the wide activity pane | +| `F2` | Open the focused activity browser | | `?` | Open contextual help outside the composer, or type a question mark inside it | Keybindings are remappable from named actions rather than raw handler code. diff --git a/scripts/live-bridge/bridge.mjs b/scripts/live-bridge/bridge.mjs index 3a4b659..bb3ef19 100644 --- a/scripts/live-bridge/bridge.mjs +++ b/scripts/live-bridge/bridge.mjs @@ -11,7 +11,7 @@ import { } from './endpoint.mjs' import { LiveBridgeError } from './errors.mjs' import { managedSpawn, sleep, terminateProcess } from './process.mjs' -import { redactString } from './redaction.mjs' +import { redactString, withoutBraidLiveSecrets } from './redaction.mjs' const requiredRuntimeCapabilities = Object.freeze({ profileMaterialization: 'cli-bridge.profile-materialization.v2', @@ -27,7 +27,7 @@ export function bridgeLaunchEnvironment( endpoint, { environment = process.env, platform = process.platform } = {}, ) { - const childEnv = { ...environment } + const childEnv = withoutBraidLiveSecrets(environment) if (childEnv.BRIDGE_BACKENDS === undefined) { childEnv.BRIDGE_BACKENDS = [...new Set(definitions.map(({ backend }) => backend))].join(',') } diff --git a/scripts/live-bridge/redaction.mjs b/scripts/live-bridge/redaction.mjs index fc22cb7..b5f1c39 100644 --- a/scripts/live-bridge/redaction.mjs +++ b/scripts/live-bridge/redaction.mjs @@ -1,3 +1,5 @@ +import { collectCredentialSecrets } from '../release/redaction.mjs' + const secretKeys = new Set([ 'authorization', 'bearer', @@ -19,19 +21,36 @@ const bridgeSecretEnvironmentKeys = Object.freeze([ 'BRIDGE_BEARER', ]) +const braidLiveSecretEnvironmentKeys = Object.freeze([ + 'BRAID_ANALYSIS_AUTH', + 'BRAID_ANALYSIS_API_KEY', + 'BRAID_ANALYSIS_BEARER', + 'BRAID_CLI_BRIDGE_AUTH', + 'BRAID_CLI_BRIDGE_API_KEY', + 'BRAID_CLI_BRIDGE_BEARER', + 'BRAID_TANGLE_AUTH', + 'BRAID_TANGLE_API_KEY', + 'BRAID_TANGLE_BEARER', + 'BRAID_TANGLE_CREDENTIAL_REF', + 'BRAID_TANGLE_SANDBOX_AUTH', + 'BRAID_TANGLE_SANDBOX_API_KEY', + 'BRAID_TANGLE_SANDBOX_BEARER', + 'BRAID_TANGLE_SANDBOX_CLEANUP_API_KEY', + 'BRAID_TANGLE_SANDBOX_CREDENTIAL_REF', + 'BRAID_TANGLE_SANDBOX_MODEL_API_KEY', + 'TANGLE_API_KEY', +]) + function isSecretKey(key) { const normalized = key.replaceAll(/[-_]/gu, '').toLowerCase() return secretKeys.has(normalized) } export function secretValues(environment = process.env) { - return [ - ...new Set( - bridgeSecretEnvironmentKeys - .map((key) => environment?.[key]) - .filter((value) => typeof value === 'string' && value.length > 0), - ), - ] + const explicitSecrets = [...bridgeSecretEnvironmentKeys, ...braidLiveSecretEnvironmentKeys] + .map((key) => environment?.[key]) + .filter((value) => typeof value === 'string' && value.length > 0) + return collectCredentialSecrets(environment, explicitSecrets) } export function withoutBridgeSecrets(environment = process.env) { @@ -40,6 +59,12 @@ export function withoutBridgeSecrets(environment = process.env) { return childEnvironment } +export function withoutBraidLiveSecrets(environment = process.env) { + const childEnvironment = { ...environment } + for (const key of braidLiveSecretEnvironmentKeys) delete childEnvironment[key] + return childEnvironment +} + export function redactString(value, secrets = secretValues()) { const secretList = [...new Set(secrets)].filter( (secret) => typeof secret === 'string' && secret.length > 0, diff --git a/scripts/live-bridge/release-proof-validation.test.mjs b/scripts/live-bridge/release-proof-validation.test.mjs index 753729c..1dc410c 100644 --- a/scripts/live-bridge/release-proof-validation.test.mjs +++ b/scripts/live-bridge/release-proof-validation.test.mjs @@ -1,7 +1,13 @@ import assert from 'node:assert/strict' import test from 'node:test' +import { bridgeLaunchEnvironment } from './bridge.mjs' import { StreamingRedactor } from './capture.mjs' -import { evidenceValue, withoutBridgeSecrets } from './redaction.mjs' +import { + evidenceValue, + secretValues, + withoutBraidLiveSecrets, + withoutBridgeSecrets, +} from './redaction.mjs' import { assertContextTransfer, assertObservedUsage, @@ -11,7 +17,7 @@ import { assertUniqueRunIds, terminalReceipts, } from './release-proof-validation.mjs' -import { assertTargetSemantics } from './target-actions.mjs' +import { assertTargetSemantics, verifyInteraction } from './target-actions.mjs' const target = { key: 'pi-test', @@ -161,6 +167,36 @@ test('usage, replay, and cancellation unavailable states cannot pass strict conf ) }) +test('interaction conformance ignores a pending interaction from another run', async () => { + const result = { targetKey: 'pi-test', requests: [] } + const session = { + send() { + assert.fail('foreign interaction must not be answered') + }, + } + await verifyInteraction( + session, + result, + { interactions: { available: true } }, + { + type: 'state', + view: { + capabilities: { 'interaction.respond': true }, + interactions: [ + { + runId: 'foreign-run', + interactionId: 'foreign-interaction', + }, + ], + }, + state: { runs: [] }, + }, + { runId: 'target-run' }, + ) + assert.equal(result.interaction.status, 'advertised-but-not-emitted') + assert.equal(result.requests.length, 0) +}) + test('restart proof rejects process, timing, reconnect, replay, and terminal false positives', () => { const identity = { id: 'run-1', @@ -540,3 +576,60 @@ test('release operations reject reused run IDs and redact bridge bearers', () => ) assert.equal(withoutBridgeSecrets({ BRIDGE_BEARER: secret }).BRIDGE_BEARER, undefined) }) + +test('started CLI Bridge keeps local subscription settings but strips Braid live credentials', () => { + const environment = { + PATH: '/usr/bin', + TANGLE_API_KEY: 'tangle-secret-canary', + BRAID_TANGLE_SANDBOX_API_KEY: 'sandbox-secret-canary', + BRAID_TANGLE_SANDBOX_CLEANUP_API_KEY: 'cleanup-secret-canary', + BRAID_TANGLE_CREDENTIAL_REF: 'credential-ref-canary', + BRAID_CLI_BRIDGE_AUTH: 'braid-bridge-secret-canary', + BRIDGE_BEARER: 'bridge-server-secret-canary', + OPENAI_API_KEY: 'local-subscription-canary', + PI_CODING_AGENT_DIR: '/tmp/pi-agent', + } + const child = bridgeLaunchEnvironment([{ backend: 'pi' }], 'http://127.0.0.1:3344', { + environment, + platform: 'linux', + }) + + for (const key of [ + 'TANGLE_API_KEY', + 'BRAID_TANGLE_SANDBOX_API_KEY', + 'BRAID_TANGLE_SANDBOX_CLEANUP_API_KEY', + 'BRAID_TANGLE_CREDENTIAL_REF', + 'BRAID_CLI_BRIDGE_AUTH', + ]) { + assert.equal(child[key], undefined, `${key} must not enter the Bridge process`) + } + assert.equal(child.BRIDGE_BEARER, environment.BRIDGE_BEARER) + assert.equal(child.OPENAI_API_KEY, environment.OPENAI_API_KEY) + assert.equal(child.PI_CODING_AGENT_DIR, environment.PI_CODING_AGENT_DIR) + assert.equal(child.BRIDGE_BACKENDS, 'pi') + assert.equal(child.BRIDGE_JAIL_MODE, 'fs-jail') +}) + +test('Braid live credential filtering does not remove local CLI subscription settings', () => { + const child = withoutBraidLiveSecrets({ + TANGLE_API_KEY: 'tangle-secret-canary', + BRAID_TANGLE_API_KEY: 'tangle-secret-canary', + ANTHROPIC_API_KEY: 'local-subscription-canary', + CODEX_HOME: '/tmp/codex', + }) + assert.equal(child.TANGLE_API_KEY, undefined) + assert.equal(child.BRAID_TANGLE_API_KEY, undefined) + assert.equal(child.ANTHROPIC_API_KEY, 'local-subscription-canary') + assert.equal(child.CODEX_HOME, '/tmp/codex') +}) + +test('captured Bridge evidence redacts preserved local subscription credentials', () => { + const secret = 'local-subscription-secret-canary' + const evidence = evidenceValue( + { stderr: `provider startup printed ${secret}` }, + '', + 0, + secretValues({ OPENAI_API_KEY: secret }), + ) + assert.doesNotMatch(JSON.stringify(evidence), new RegExp(secret, 'u')) +}) diff --git a/scripts/live-bridge/target-actions.mjs b/scripts/live-bridge/target-actions.mjs index e4d5422..a3c1ac1 100644 --- a/scripts/live-bridge/target-actions.mjs +++ b/scripts/live-bridge/target-actions.mjs @@ -7,6 +7,7 @@ import { capabilityAdvertised, capabilityAvailability, exactMarker, + interactionFromResponse, requestBase, responseForRequest, runFromState, @@ -304,9 +305,9 @@ export async function verifyInteraction( result, providerCapabilities, terminal, - { operationPrefix = 'live' } = {}, + { operationPrefix = 'live', runId } = {}, ) { - const interaction = terminal.view?.interactions?.[0] + const interaction = interactionFromResponse(terminal, runId) const interactionCapability = terminal.view?.capabilities?.['interaction.respond'] const advertisedByBraid = capabilityAdvertised(interactionCapability) const availability = capabilityAvailability(providerCapabilities.interactions, advertisedByBraid) diff --git a/scripts/live-bridge/target-flow.mjs b/scripts/live-bridge/target-flow.mjs index d02fda7..7c1aa36 100644 --- a/scripts/live-bridge/target-flow.mjs +++ b/scripts/live-bridge/target-flow.mjs @@ -17,7 +17,12 @@ import { runFromState, stateForRun, } from './protocol.mjs' -import { evidenceValue, redactString, withoutBridgeSecrets } from './redaction.mjs' +import { + evidenceValue, + redactString, + withoutBraidLiveSecrets, + withoutBridgeSecrets, +} from './redaction.mjs' import { assertObservedUsage, assertTargetRunIdentity, @@ -47,7 +52,7 @@ export async function executeTarget( const config = await writeTargetConfig(root, endpoint, target, credential) const statePath = join(config.workspace, 'braid.sqlite') const env = { - ...withoutBridgeSecrets(), + ...withoutBridgeSecrets(withoutBraidLiveSecrets()), NO_COLOR: '1', NODE_NO_WARNINGS: '1', BRAID_STATE_PATH: statePath, @@ -98,7 +103,10 @@ export async function executeTarget( operationPrefix, timeoutMs, }) - await verifyInteraction(session, result, providerCapabilities, terminal, { operationPrefix }) + await verifyInteraction(session, result, providerCapabilities, terminal, { + operationPrefix, + runId, + }) assertTargetSemantics(result, { strict }) if (strict) { const targetProof = assertTargetRunIdentity(finalRun, target) @@ -232,7 +240,7 @@ function targetResult(config, target, providerCapabilities, credential, operatio function operationEnvironment(config) { return { - ...withoutBridgeSecrets(), + ...withoutBridgeSecrets(withoutBraidLiveSecrets()), NO_COLOR: '1', NODE_NO_WARNINGS: '1', BRAID_STATE_PATH: join(config.workspace, 'braid.sqlite'), diff --git a/scripts/live-required.test.mjs b/scripts/live-required.test.mjs index fe324b4..64fbcf3 100644 --- a/scripts/live-required.test.mjs +++ b/scripts/live-required.test.mjs @@ -29,6 +29,10 @@ import { } from './live-required/headless.mjs' import { runMatrixAdapter, runSandbox } from './live-required/tangle.mjs' import { executionLatencyDistribution } from './live-required/tangle-sandbox-braid-execution-soak.mjs' +import { + errorDetails, + MissingIntegrationError, +} from './live-required/tangle-sandbox-braid-stress-support.mjs' import { assertExactResumeEvidence, cancellationReplayDetected, @@ -647,6 +651,19 @@ test('nested credential fields and error text are redacted before public output' assert.match(nestedMessage, /\[REDACTED\]/u) }) +test('retained Sandbox error details are safe for direct proof output', () => { + const secret = 'retained-sandbox-error-secret-canary-4f8c' + const rawDetails = errorDetails( + new MissingIntegrationError('provider rejected the request', { + authorization: secret, + nested: { token: secret }, + }), + ) + const output = safeJson({ status: 'failed', failure: rawDetails }, { TANGLE_API_KEY: secret }) + assert.doesNotMatch(output, new RegExp(secret, 'u')) + assert.match(output, /\[REDACTED\]/u) +}) + test('configured supervisor failures stay unavailable and redact environment credentials', async () => { const root = await mkdtemp(join(tmpdir(), 'braid-live-required-supervisor-test-')) const missingRoot = join(root, 'missing-runtime-root') diff --git a/scripts/live-required/tangle-sandbox-braid-soak.mjs b/scripts/live-required/tangle-sandbox-braid-soak.mjs index 1ee6495..58eb77f 100644 --- a/scripts/live-required/tangle-sandbox-braid-soak.mjs +++ b/scripts/live-required/tangle-sandbox-braid-soak.mjs @@ -1,6 +1,7 @@ import { mkdir, writeFile } from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' +import { safeJson, safeMessage } from './contracts.mjs' import { runBraidSandboxStress } from './tangle-sandbox-braid-stress.mjs' import { resourceDelta } from './tangle-sandbox-braid-stress-support.mjs' @@ -923,7 +924,7 @@ export async function runBraidSandboxSoak({ async function writeOutput(path, value) { const resolved = resolve(path) await mkdir(dirname(resolved), { recursive: true, mode: 0o700 }) - await writeFile(resolved, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 }) + await writeFile(resolved, `${safeJson(value)}\n`, { mode: 0o600 }) } async function main() { @@ -938,13 +939,13 @@ async function main() { }) const output = argument('output') if (output) await writeOutput(output, result) - process.stdout.write(`${JSON.stringify(result, null, 2)}\n`) + process.stdout.write(`${safeJson(result)}\n`) if (result.status !== 'passed') process.exitCode = 1 } if (resolve(process.argv[1] ?? '') === scriptPath) { main().catch((error) => { - process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`) + process.stderr.write(`${safeMessage(error)}\n`) process.exitCode = 1 }) } diff --git a/scripts/live-required/tangle-sandbox-braid-stress.mjs b/scripts/live-required/tangle-sandbox-braid-stress.mjs index 96209ec..2f0052a 100644 --- a/scripts/live-required/tangle-sandbox-braid-stress.mjs +++ b/scripts/live-required/tangle-sandbox-braid-stress.mjs @@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url' import { Sandbox } from '@tangle-network/sandbox' import { sleep } from '../live-bridge/process.mjs' import { connectionConfiguration } from './configuration.mjs' +import { safeJson } from './contracts.mjs' import { closeSession, configEvidence, @@ -1801,22 +1802,20 @@ export async function runBraidSandboxStress({ async function writeOutput(path, value) { await mkdir(dirname(resolve(path)), { recursive: true }) - await writeFile(resolve(path), `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 }) + await writeFile(resolve(path), `${safeJson(value)}\n`, { mode: 0o600 }) } async function main() { const proof = await runBraidSandboxStress() const outputPath = argument('output') if (outputPath) await writeOutput(outputPath, proof) - process.stdout.write(`${JSON.stringify(proof, null, 2)}\n`) + process.stdout.write(`${safeJson(proof)}\n`) if (proof.status !== 'passed') process.exitCode = 1 } if (resolve(process.argv[1] ?? '') === scriptPath) { main().catch((error) => { - process.stdout.write( - `${JSON.stringify({ status: 'failed', failure: errorDetails(error) }, null, 2)}\n`, - ) + process.stdout.write(`${safeJson({ status: 'failed', failure: errorDetails(error) })}\n`) process.exitCode = 1 }) } diff --git a/scripts/live-required/tangle-sandbox-interactive-continuity.mjs b/scripts/live-required/tangle-sandbox-interactive-continuity.mjs new file mode 100644 index 0000000..cfeee60 --- /dev/null +++ b/scripts/live-required/tangle-sandbox-interactive-continuity.mjs @@ -0,0 +1,995 @@ +import assert from 'node:assert/strict' +import { randomUUID } from 'node:crypto' +import { resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +import { connectionConfiguration } from './configuration.mjs' +import { + EXIT_CODES, + endpointEvidence, + LiveRequiredError, + safeJson, + safeMessage, +} from './contracts.mjs' + +const OPERATION = 'tangle.sandbox.interactive-continuity' +const SANDBOX_PROVIDER = 'tangle-sandbox' +const DEFAULT_TIMEOUT_MS = 180_000 +const DEFAULT_COLS = 120 +const DEFAULT_ROWS = 36 +const EXACT_HANDLE_METHODS = [ + 'start', + 'attach', + 'status', + 'claimControl', + 'sendPrompt', + 'stop', + 'stopLifecycle', +] +const EXACT_STREAM_METHODS = ['write', 'close', 'reconnect'] +const EXACT_INTERFACE_FUNCTIONS = [ + 'agentInteractiveSessionRunRef', + 'agentInteractiveSessionRefMatchesStart', + 'agentInteractiveSessionStatusMatchesRef', + 'agentInteractiveSessionControlClaimMatchesRef', + 'agentInteractiveSessionPromptRequestDigest', + 'agentInteractiveSessionStopRequestDigest', + 'canonicalAgentProfileDigest', + 'canonicalCandidateDigest', + 'exactAgentInteractiveSessionStart', +] + +function hasMethod(value, name) { + return typeof value?.[name] === 'function' +} + +function capabilityUnavailable(code, message, details = {}) { + const error = new LiveRequiredError(code, message, { unavailable: true }) + error.details = details + return error +} + +function identityText(ref) { + return [ + ref?.run?.runId, + ref?.run?.provider, + ref?.run?.environmentId, + ref?.run?.sessionId, + ref?.run?.executionId, + ref?.incarnationId, + ] + .map((value) => (typeof value === 'string' ? value : '')) + .join('/') +} + +function directCredentialEnvironment(environment) { + const hasSandboxCredential = [ + 'BRAID_TANGLE_SANDBOX_AUTH', + 'BRAID_TANGLE_SANDBOX_API_KEY', + 'BRAID_TANGLE_SANDBOX_BEARER', + ].some((name) => typeof environment[name] === 'string' && environment[name].trim()) + if (!hasSandboxCredential && environment.TANGLE_API_KEY) { + return { + ...environment, + BRAID_TANGLE_SANDBOX_API_KEY: environment.TANGLE_API_KEY, + } + } + return environment +} + +function safeIdentifier(value, label) { + if ( + typeof value !== 'string' || + value.length === 0 || + value.length > 120 || + !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/u.test(value) + ) { + throw new Error(`${label} must be a bounded public identifier`) + } + return value +} + +function argument(name, argv = process.argv) { + const index = argv.indexOf(`--${name}`) + return index >= 0 && index + 1 < argv.length ? argv[index + 1] : undefined +} + +function positiveInteger(value, fallback) { + const parsed = Number(value) + return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback +} + +function sleep(milliseconds) { + return new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds)) +} + +async function bounded(label, task, timeoutMs) { + let timer + try { + return await Promise.race([ + Promise.resolve().then(task), + new Promise((_, reject) => { + timer = setTimeout(() => { + reject(new Error(`${label} exceeded ${timeoutMs}ms`)) + }, timeoutMs) + }), + ]) + } finally { + if (timer) clearTimeout(timer) + } +} + +async function waitFor(label, predicate, timeoutMs) { + const deadline = Date.now() + timeoutMs + while (Date.now() < deadline) { + const result = await predicate() + if (result) return result + await sleep(100) + } + throw new Error(`${label} timed out after ${timeoutMs}ms`) +} + +function requireExactMethods(value, methods, label) { + return methods.filter((method) => !hasMethod(value, method)).map((method) => `${label}.${method}`) +} + +/** + * Check the package-level public contract before creating a cloud resource. + * The old Sandbox release is intentionally rejected because it cannot carry + * exact process receipts or control claims. + */ +export function assertPublicInteractiveSurface(sandboxModule, interfaceModule) { + const missing = [ + ...(typeof sandboxModule?.Sandbox !== 'function' ? ['Sandbox'] : []), + ...(typeof sandboxModule?.TerminalStream !== 'function' ? ['TerminalStream'] : []), + ...requireExactMethods( + sandboxModule?.Sandbox?.prototype, + ['create', 'get'], + 'Sandbox.prototype', + ), + ...requireExactMethods( + sandboxModule?.InteractiveSessionHandle?.prototype, + EXACT_HANDLE_METHODS, + 'InteractiveSessionHandle.prototype', + ), + ...requireExactMethods( + sandboxModule?.TerminalStream?.prototype, + EXACT_STREAM_METHODS, + 'TerminalStream.prototype', + ), + ...(typeof sandboxModule?.TerminalStream?.connect !== 'function' + ? ['TerminalStream.connect'] + : []), + ...EXACT_INTERFACE_FUNCTIONS.filter( + (name) => typeof interfaceModule?.[name] !== 'function', + ).map((name) => `agent-interface.${name}`), + ] + if (missing.length > 0) { + throw capabilityUnavailable( + 'SANDBOX_INTERACTIVE_EXACT_SURFACE_UNAVAILABLE', + `The public Sandbox interactive continuity contract is unavailable: ${missing.join(', ')}`, + { missing }, + ) + } + return Object.freeze({ + sandbox: sandboxModule, + agentInterface: interfaceModule, + }) +} + +export function assertSandboxSurface(box) { + const missing = [ + ...requireExactMethods( + box, + ['session', 'capabilities', 'waitFor', 'delete'], + 'SandboxInstance', + ), + ...(box?.terminals === undefined ? ['SandboxInstance.terminals'] : []), + ...requireExactMethods(box?.terminals, ['attach', 'get'], 'SandboxInstance.terminals'), + ] + if (missing.length > 0) { + throw capabilityUnavailable( + 'SANDBOX_INTERACTIVE_RUNTIME_SURFACE_UNAVAILABLE', + `The deployed Sandbox does not expose the native terminal surface: ${missing.join(', ')}`, + { missing }, + ) + } +} + +function configuration(environment) { + const values = connectionConfiguration(directCredentialEnvironment(environment), { + prefix: 'BRAID_TANGLE_SANDBOX', + kind: 'tangle-sandbox-interactive-continuity', + endpointNames: ['BRAID_TANGLE_ENDPOINT'], + modelNames: ['BRAID_TANGLE_MODEL'], + runnerNames: ['BRAID_TANGLE_RUNNER'], + providerNames: ['BRAID_TANGLE_SANDBOX_PROVIDER'], + }) + if (!values.credentialValue?.trim()) { + throw capabilityUnavailable( + 'PROTECTED_CREDENTIAL_VALUE_REQUIRED', + 'The direct Sandbox continuity proof requires a raw API key for the public SDK client; a protected reference alone is insufficient.', + { required: 'BRAID_TANGLE_SANDBOX_API_KEY or TANGLE_API_KEY' }, + ) + } + return values +} + +async function loadPublicApis(environment) { + try { + const [sandboxModule, interfaceModule] = await Promise.all([ + import('@tangle-network/sandbox'), + import('@tangle-network/agent-interface'), + ]) + return assertPublicInteractiveSurface(sandboxModule, interfaceModule) + } catch (error) { + if (error?.unavailable === true) throw error + throw capabilityUnavailable( + 'SANDBOX_PUBLIC_PACKAGE_UNAVAILABLE', + `The public Sandbox or Agent Interface package could not be loaded: ${safeMessage(error, environment)}`, + ) + } +} + +function markers(proofId) { + const safe = safeIdentifier(proofId, 'proofId').replaceAll(':', '_') + return { + output: `BRAID_NATIVE_OUTPUT_${safe}`, + input: `BRAID_NATIVE_INPUT_${safe}`, + reconnect: `BRAID_NATIVE_RECONNECT_${safe}`, + } +} + +/** Build one exact AgentProfile-backed native start request. */ +export function buildExactInteractiveStart({ + interfaceModule, + environmentId, + sessionId, + executionId, + proofId, + runner, + model, + modelProvider = 'tangle', + cols = DEFAULT_COLS, + rows = DEFAULT_ROWS, +}) { + const exactEnvironmentId = safeIdentifier(environmentId, 'environmentId') + const exactSessionId = safeIdentifier(sessionId, 'sessionId') + const exactExecutionId = safeIdentifier(executionId, 'executionId') + const exactProofId = safeIdentifier(proofId, 'proofId') + const profile = { + name: `braid-native-continuity-${exactProofId}`, + harness: runner, + model: { + default: model, + provider: modelProvider, + }, + } + const requestedProfileDigest = interfaceModule.canonicalAgentProfileDigest(profile) + const input = { + profile, + requestedProfileDigest, + initialPrompt: `Reply with exactly ${markers(exactProofId).output}, then wait for my next terminal input.`, + cwd: '.', + cols, + rows, + } + const run = interfaceModule.agentInteractiveSessionRunRef( + { + provider: SANDBOX_PROVIDER, + environmentId: exactEnvironmentId, + sessionId: exactSessionId, + executionId: exactExecutionId, + }, + input, + ) + const start = interfaceModule.exactAgentInteractiveSessionStart({ + run, + ...input, + }) + return Object.freeze({ + start, + run, + profile, + requestedProfileDigest, + markers: markers(exactProofId), + }) +} + +export function assertSameInteractiveRun(interfaceModule, expected, observed, label) { + const context = `${label} [${expected?.runId ?? ''}/${expected?.sessionId ?? ''}/${expected?.executionId ?? ''}]` + assert.ok(observed, `${context} returned no run reference`) + assert.equal( + interfaceModule.canonicalCandidateDigest(observed), + interfaceModule.canonicalCandidateDigest(expected), + `${context} changed its exact run reference`, + ) + assert.equal(observed.runId, expected.runId, `${context} changed runId`) + assert.equal(observed.provider, expected.provider, `${context} changed provider`) + assert.equal(observed.environmentId, expected.environmentId, `${context} changed environmentId`) + assert.equal(observed.sessionId, expected.sessionId, `${context} changed sessionId`) + assert.equal(observed.executionId, expected.executionId, `${context} changed executionId`) + assert.equal(observed.requestDigest, expected.requestDigest, `${context} changed requestDigest`) +} + +export function assertSameInteractiveRef(interfaceModule, expected, observed, label) { + const context = `${label} [${identityText(expected)}]` + assert.ok(observed, `${context} returned no process reference`) + assert.equal( + interfaceModule.canonicalCandidateDigest(observed), + interfaceModule.canonicalCandidateDigest(expected), + `${context} changed its exact process reference`, + ) + assert.equal(observed.run.runId, expected.run.runId, `${context} changed runId`) + assert.equal(observed.run.provider, expected.run.provider, `${context} changed provider`) + assert.equal( + observed.run.environmentId, + expected.run.environmentId, + `${context} changed environmentId`, + ) + assert.equal(observed.run.sessionId, expected.run.sessionId, `${context} changed sessionId`) + assert.equal(observed.run.executionId, expected.run.executionId, `${context} changed executionId`) + assert.equal( + observed.run.requestDigest, + expected.run.requestDigest, + `${context} changed requestDigest`, + ) + assert.equal(observed.incarnationId, expected.incarnationId, `${context} changed incarnationId`) +} + +export function assertStatusForRef(interfaceModule, ref, status, label) { + const context = `${label} [${identityText(ref)}]` + assert.ok(status, `${context} returned no status`) + assert.equal(status.state, 'running', `${context} is not running`) + assert.equal( + interfaceModule.agentInteractiveSessionStatusMatchesRef(ref, status), + true, + `${context} returned a status for a different process`, + ) + assertSameInteractiveRef(interfaceModule, ref, status.ref, label) + return status +} + +export function assertControlForRef(interfaceModule, ref, control, label) { + const context = `${label} [${identityText(ref)}]` + assert.ok(control, `${context} returned no control claim`) + assert.equal( + interfaceModule.agentInteractiveSessionControlClaimMatchesRef(ref, control), + true, + `${context} returned a control claim for a different process`, + ) + assert.ok(control.generation > 0, `${context} returned an invalid control generation`) + assert.ok( + Date.parse(control.expiresAt) > Date.now(), + `${context} returned an expired control claim`, + ) + return control +} + +function checkRecord(name, boxId, ref, detail = {}) { + return { + name, + status: 'passed', + environmentId: boxId, + runId: ref.run.runId, + provider: ref.run.provider, + sessionId: ref.run.sessionId, + executionId: ref.run.executionId, + incarnationId: ref.incarnationId, + ...detail, + } +} + +function terminalCollector(environment) { + let text = '' + let bytes = 0 + const errors = [] + const decoder = new TextDecoder() + const handlers = { + onData(data) { + bytes += data.byteLength + text += decoder.decode(data, { stream: true }) + }, + onError(error) { + errors.push({ + code: typeof error?.code === 'string' ? error.code : 'UNKNOWN', + message: safeMessage(error, environment), + }) + }, + } + return { + handlers, + get text() { + return text + }, + get bytes() { + return bytes + }, + get errors() { + return [...errors] + }, + } +} + +async function waitForMarker(collector, marker, label, timeoutMs, from = 0) { + return waitFor( + label, + () => { + if (collector.errors.length > 0) { + throw new Error(`${label} terminal stream error ${collector.errors[0].code}`) + } + return collector.text.slice(from).includes(marker) + }, + timeoutMs, + ) +} + +function assertReady(stream, sessionId, label) { + const ready = stream.ready + const context = `${label} [${sessionId}]` + assert.equal(ready.connectionId, sessionId, `${context} changed terminal connectionId`) + assert.equal(ready.sessionId, sessionId, `${context} changed terminal sessionId`) + assert.equal(typeof ready.restored, 'boolean', `${context} omitted restored state`) + assert.ok( + Number.isSafeInteger(ready.detachTimeoutMs) && ready.detachTimeoutMs > 0, + `${context} omitted the bounded detach timeout`, + ) + return ready +} + +function ownedBox(box, options, proofId) { + return ( + box?.id && + box.name === options.name && + box.metadata?.owner === 'braid' && + box.metadata?.lifecycle === 'interactive-continuity' && + box.metadata?.proofId === proofId + ) +} + +async function waitForDeleted(client, boxId, timeoutMs) { + return waitFor( + `Sandbox ${boxId} deletion`, + async () => { + const current = await client.get(boxId) + if (current !== null) { + assert.equal(current.id, boxId, `deletion lookup returned a different Sandbox for ${boxId}`) + return false + } + return true + }, + timeoutMs, + ) +} + +async function waitForTerminalReaped(box, sessionId, ref, timeoutMs) { + return waitFor( + `PTY cleanup [${identityText(ref)}]`, + async () => { + const terminal = await box.terminals.get(sessionId) + if (terminal === null) return { terminal: null } + assert.equal( + terminal.sessionId, + sessionId, + `PTY cleanup [${identityText(ref)}] returned a different session`, + ) + assert.equal( + terminal.isRunning, + false, + `PTY cleanup [${identityText(ref)}] still reports a running terminal`, + ) + return { terminal } + }, + timeoutMs, + ) +} + +function createOptions(values, profile, proofId) { + const name = `braid-native-continuity-${proofId}` + return { + environment: 'universal', + agent: true, + backend: { + type: values.runner, + profile, + }, + name, + metadata: { + owner: 'braid', + lifecycle: 'interactive-continuity', + proofId, + provider: SANDBOX_PROVIDER, + }, + idempotencyKey: name, + maxLifetimeSeconds: 900, + idleTimeoutSeconds: 600, + } +} + +/** + * Run the real native Sandbox continuity proof. + * + * This function never falls back to a shell, headless turn, direct WebSocket, + * or private Sandbox route when the exact public contract is unavailable. + */ +export async function runInteractiveContinuityProof({ + environment = process.env, + proofId = `run-${Date.now()}-${process.pid}-${randomUUID().slice(0, 8)}`, + timeoutMs = positiveInteger( + environment.BRAID_TANGLE_SANDBOX_INTERACTIVE_TIMEOUT_MS, + DEFAULT_TIMEOUT_MS, + ), + sandboxModule, + interfaceModule, + clientFactory, +} = {}) { + const startedAt = new Date().toISOString() + const exactProofId = safeIdentifier(proofId, 'proofId') + const values = configuration(environment) + const apis = + sandboxModule && interfaceModule + ? assertPublicInteractiveSurface(sandboxModule, interfaceModule) + : await loadPublicApis(environment) + const client = clientFactory + ? clientFactory({ values, sandbox: apis.sandbox }) + : new apis.sandbox.Sandbox({ + baseUrl: values.endpoint, + apiKey: values.credentialValue, + }) + if (!client || !hasMethod(client, 'create') || !hasMethod(client, 'get')) { + throw capabilityUnavailable( + 'SANDBOX_CLIENT_SURFACE_UNAVAILABLE', + 'The public Sandbox client does not expose create() and get() required for exact resource ownership.', + ) + } + + const sessionId = safeIdentifier(`session-${exactProofId}`, 'sessionId') + const executionId = safeIdentifier(`execution-${exactProofId}`, 'executionId') + let box + let boxWasOwned = false + let boxWasDeleted = false + let handle + let stream + let startInfo + let failure + const checks = [] + const cleanupErrors = [] + const createProfile = { + name: `braid-native-continuity-${exactProofId}`, + harness: values.runner, + model: { + default: values.model, + provider: values.provider, + }, + } + const options = createOptions(values, createProfile, exactProofId) + try { + box = await bounded('Sandbox create', () => client.create(options), timeoutMs) + assertSandboxSurface(box) + if (!ownedBox(box, options, exactProofId)) { + throw new Error( + `Created Sandbox ${box.id} did not retain the exact Braid ownership metadata for ${exactProofId}`, + ) + } + boxWasOwned = true + await bounded('Sandbox waitFor running', () => box.waitFor('running', { timeoutMs }), timeoutMs) + + const capabilities = await bounded( + 'Sandbox capability document', + () => box.capabilities(), + timeoutMs, + ) + if (capabilities?.schema !== 1) { + throw capabilityUnavailable( + 'SANDBOX_CAPABILITIES_UNKNOWN', + `Sandbox ${box.id} did not provide a recognized runtime capability document; native interactive support is not proven.`, + { environmentId: box.id }, + ) + } + + const session = box.session(sessionId) + if (!session || !hasMethod(session, 'interactive')) { + throw capabilityUnavailable( + 'SANDBOX_INTERACTIVE_SESSION_UNAVAILABLE', + `Sandbox ${box.id} does not expose the public interactive session controller for ${sessionId}.`, + { environmentId: box.id, sessionId }, + ) + } + handle = session.interactive() + if (!handle || !EXACT_HANDLE_METHODS.every((method) => hasMethod(handle, method))) { + throw capabilityUnavailable( + 'SANDBOX_INTERACTIVE_HANDLE_UNAVAILABLE', + `Sandbox ${box.id} returned an incomplete interactive controller for ${sessionId}.`, + { environmentId: box.id, sessionId }, + ) + } + + const exact = buildExactInteractiveStart({ + interfaceModule: apis.agentInterface, + environmentId: box.id, + sessionId, + executionId, + proofId: exactProofId, + runner: values.runner, + model: values.model, + modelProvider: values.provider, + }) + startInfo = await bounded( + `Interactive start [${identityText(exact.start)}]`, + () => handle.start(exact.start), + timeoutMs, + ) + assert.equal( + startInfo.state, + 'running', + `Interactive start [${identityText(exact.start)}] did not remain running`, + ) + assert.equal( + typeof startInfo.streamUrl, + 'string', + `Interactive start [${identityText(exact.start)}] returned no terminal stream URL`, + ) + assert.equal( + apis.agentInterface.agentInteractiveSessionRefMatchesStart(exact.start, startInfo.ref), + true, + `Interactive start [${identityText(exact.start)}] returned an inexact process ref`, + ) + assertSameInteractiveRun(apis.agentInterface, exact.start.run, startInfo.ref.run, 'start run') + assertControlForRef(apis.agentInterface, startInfo.ref, startInfo.control, 'start control') + const ref = startInfo.ref + checks.push( + checkRecord('start-identify-exact-process', box.id, ref, { + refDigest: apis.agentInterface.canonicalCandidateDigest(ref), + controlGeneration: startInfo.control.generation, + preparationReceiptDigest: ref.preparationReceipt.digest, + }), + ) + + const initialStatus = await bounded( + `Interactive status after start [${identityText(ref)}]`, + () => handle.status(), + timeoutMs, + ) + assertStatusForRef(apis.agentInterface, ref, initialStatus, 'status after start') + + const firstOutput = terminalCollector(environment) + stream = await bounded( + `Interactive attach [${identityText(ref)}]`, + () => + handle.attach({ cols: DEFAULT_COLS, rows: DEFAULT_ROWS, handlers: firstOutput.handlers }), + timeoutMs, + ) + assert.ok( + stream && EXACT_STREAM_METHODS.every((method) => hasMethod(stream, method)), + `Interactive attach [${identityText(ref)}] returned an incomplete terminal stream`, + ) + const firstReady = assertReady(stream, sessionId, 'initial attach') + checks.push( + checkRecord('attach-exact-process', box.id, ref, { + connectionId: firstReady.connectionId, + restored: firstReady.restored, + controlGeneration: startInfo.control.generation, + }), + ) + + await waitForMarker( + firstOutput, + exact.markers.output, + `native output [${identityText(ref)}]`, + timeoutMs, + ) + checks.push( + checkRecord('receive-output', box.id, ref, { + marker: exact.markers.output, + bytes: firstOutput.bytes, + }), + ) + + const inputStart = firstOutput.text.length + stream.write(`${exact.markers.input}\r`) + await waitForMarker( + firstOutput, + exact.markers.input, + `native input echo [${identityText(ref)}]`, + timeoutMs, + inputStart, + ) + checks.push( + checkRecord('send-input', box.id, ref, { + marker: exact.markers.input, + inputBytes: Buffer.byteLength(`${exact.markers.input}\r`), + }), + ) + + await bounded(`Interactive detach [${identityText(ref)}]`, () => stream.close(), timeoutMs) + assert.equal( + stream.isOpen, + false, + `Interactive detach [${identityText(ref)}] left the terminal socket open`, + ) + const detachedStatus = await bounded( + `Interactive status after detach [${identityText(ref)}]`, + () => handle.status(), + timeoutMs, + ) + assertStatusForRef(apis.agentInterface, ref, detachedStatus, 'status after detach') + checks.push(checkRecord('detach-preserves-process', box.id, ref)) + + const reconnectedOutput = terminalCollector(environment) + const reconnected = await bounded( + `Interactive reconnect [${identityText(ref)}]`, + () => stream.reconnect({ handlers: reconnectedOutput.handlers }), + timeoutMs, + ) + stream = reconnected + const reconnectedReady = assertReady(stream, sessionId, 'reconnect') + assert.equal( + reconnectedReady.restored, + true, + `Interactive reconnect [${identityText(ref)}] created a new PTY instead of restoring the same one`, + ) + await waitForMarker( + reconnectedOutput, + exact.markers.output, + `reconnect replay [${identityText(ref)}]`, + timeoutMs, + ) + const reconnectInputStart = reconnectedOutput.text.length + stream.write(`${exact.markers.reconnect}\r`) + await waitForMarker( + reconnectedOutput, + exact.markers.reconnect, + `reconnect input [${identityText(ref)}]`, + timeoutMs, + reconnectInputStart, + ) + const reconnectedStatus = await bounded( + `Interactive status after reconnect [${identityText(ref)}]`, + () => handle.status(), + timeoutMs, + ) + assertStatusForRef(apis.agentInterface, ref, reconnectedStatus, 'status after reconnect') + checks.push( + checkRecord('reconnect-same-incarnation-control', box.id, ref, { + connectionId: reconnectedReady.connectionId, + restored: reconnectedReady.restored, + replayedMarker: exact.markers.output, + controlContinuity: 'TerminalStream.reconnect reused the attached exact control claim', + }), + ) + + const staleRef = { + ...ref, + incarnationId: `${ref.incarnationId}-stale`, + } + const staleHandle = session.interactive({ ref: staleRef, control: startInfo.control }) + const staleStatus = await bounded( + `Stale identity status [${identityText(staleRef)}]`, + () => staleHandle.status(), + timeoutMs, + ) + assert.equal( + staleStatus, + null, + `Stale identity [${identityText(staleRef)}] resolved to a live process`, + ) + await assert.rejects( + () => staleHandle.attach({ cols: DEFAULT_COLS, rows: DEFAULT_ROWS }), + (error) => { + const message = safeMessage(error, environment) + return /stale|identity|not running|exists/iu.test(message) + }, + ) + checks.push( + checkRecord('stale-identity-rejected', box.id, ref, { + rejectedIncarnationId: staleRef.incarnationId, + }), + ) + + await bounded( + `Interactive second detach [${identityText(ref)}]`, + () => stream.close(), + timeoutMs, + ) + const stopAcknowledgement = await bounded( + `Interactive lifecycle stop [${identityText(ref)}]`, + () => handle.stopLifecycle(), + timeoutMs, + ) + assert.ok( + stopAcknowledgement.status === 'accepted' || stopAcknowledgement.status === 'replayed', + `Interactive lifecycle stop [${identityText(ref)}] was not acknowledged`, + ) + assert.notEqual( + stopAcknowledgement.effect, + 'unknown', + `Interactive lifecycle stop [${identityText(ref)}] returned an unknown effect`, + ) + assertSameInteractiveRef( + apis.agentInterface, + ref, + stopAcknowledgement.ref, + 'lifecycle stop ref', + ) + assertControlForRef( + apis.agentInterface, + ref, + stopAcknowledgement.control, + 'lifecycle stop control', + ) + const exitedStatus = await waitFor( + `Interactive exit [${identityText(ref)}]`, + async () => { + const status = await handle.status() + if (!status) return false + assertSameInteractiveRef(apis.agentInterface, ref, status.ref, 'exit status ref') + return status.state === 'exited' ? status : false + }, + timeoutMs, + ) + assert.equal( + exitedStatus.reason, + 'stopped', + `Interactive exit [${identityText(ref)}] was not caused by the exact stop request`, + ) + checks.push( + checkRecord('stop-exact-process', box.id, ref, { + acknowledgementStatus: stopAcknowledgement.status, + effect: stopAcknowledgement.effect, + reason: exitedStatus.reason, + }), + ) + + const reaped = await waitForTerminalReaped(box, sessionId, ref, timeoutMs) + checks.push( + checkRecord('stop-reaps-pty', box.id, ref, { + terminalPresentAfterStop: reaped.terminal !== null, + }), + ) + + await bounded(`Sandbox delete ${box.id}`, () => box.delete(), timeoutMs) + boxWasDeleted = true + await waitForDeleted(client, box.id, timeoutMs) + checks.push(checkRecord('delete-exact-sandbox', box.id, ref)) + + return { + schema: 'braid.live-required.interactive-continuity.v1', + operation: OPERATION, + status: 'passed', + startedAt, + completedAt: new Date().toISOString(), + connection: { + endpoint: endpointEvidence(values.endpoint), + connectionKind: 'tangle-sandbox-public-sdk', + credentialConfigured: true, + model: values.model, + runner: values.runner, + provider: values.provider, + }, + run: { + environmentId: box.id, + runId: startInfo.ref.run.runId, + provider: startInfo.ref.run.provider, + sessionId, + executionId, + incarnationId: startInfo.ref.incarnationId, + refDigest: apis.agentInterface.canonicalCandidateDigest(startInfo.ref), + preparationReceiptDigest: startInfo.ref.preparationReceipt.digest, + }, + capabilities: { + schema: capabilities.schema, + agentInterface: capabilities.agentInterface, + sidecarVersion: capabilities.sidecarVersion, + image: capabilities.image, + }, + checks, + observations: { + outputMarker: exact.markers.output, + inputMarker: exact.markers.input, + reconnectMarker: exact.markers.reconnect, + ptyDeleted: reaped.terminal === null, + }, + } + } catch (error) { + failure = error + } finally { + if (stream?.isOpen) { + try { + await bounded('failure detach', () => stream.close(), timeoutMs) + } catch (error) { + cleanupErrors.push(safeMessage(error, environment)) + } + } + if (box && boxWasOwned && !boxWasDeleted) { + if (handle && startInfo) { + try { + await bounded( + `failure lifecycle stop [${identityText(startInfo.ref)}]`, + () => handle.stopLifecycle(), + timeoutMs, + ) + } catch (error) { + cleanupErrors.push(safeMessage(error, environment)) + } + } + try { + await bounded( + `failure PTY cleanup [${box.id}/${sessionId}]`, + () => + waitForTerminalReaped( + box, + sessionId, + startInfo?.ref ?? { run: { runId: '' }, incarnationId: '' }, + timeoutMs, + ), + timeoutMs, + ) + } catch (error) { + cleanupErrors.push(safeMessage(error, environment)) + } + try { + await bounded(`failure Sandbox delete ${box.id}`, () => box.delete(), timeoutMs) + boxWasDeleted = true + await waitForDeleted(client, box.id, timeoutMs) + } catch (error) { + cleanupErrors.push(safeMessage(error, environment)) + } + } + } + + if (failure) { + if (cleanupErrors.length > 0) { + failure.cleanupErrors = cleanupErrors + } + throw failure + } + throw new Error('Interactive continuity proof ended without a result') +} + +export function safeErrorRecord(error, environment = process.env) { + let details + if (error?.details && typeof error.details === 'object') { + try { + details = JSON.parse(safeJson(error.details, environment)) + } catch { + details = '[REDACTED]' + } + } + return { + name: error instanceof Error ? error.name : 'Error', + code: typeof error?.code === 'string' ? error.code : 'BRAID_INTERACTIVE_CONTINUITY_FAILED', + unavailable: error?.unavailable === true, + message: safeMessage(error, environment), + ...(details === undefined ? {} : { details }), + ...(Array.isArray(error?.cleanupErrors) ? { cleanupErrors: error.cleanupErrors } : {}), + } +} + +export async function main(argv = process.argv, environment = process.env) { + const proofId = argument('proof-id', argv) + try { + const result = await runInteractiveContinuityProof({ + environment, + ...(proofId === undefined ? {} : { proofId }), + }) + process.stdout.write(`${safeJson(result, environment)}\n`) + return EXIT_CODES.passed + } catch (error) { + const unavailable = error?.unavailable === true + const report = { + schema: 'braid.live-required.interactive-continuity.v1', + operation: OPERATION, + status: unavailable ? 'unavailable' : 'failed', + error: safeErrorRecord(error, environment), + } + process.stderr.write(`${safeJson(report, environment)}\n`) + return unavailable ? EXIT_CODES.unavailable : EXIT_CODES.failed + } +} + +const invokedPath = process.argv[1] ? resolve(process.argv[1]) : undefined +if (invokedPath === fileURLToPath(import.meta.url)) { + main().then((code) => { + process.exitCode = code + }) +} diff --git a/scripts/live-required/tangle-sandbox-interactive-continuity.test.mjs b/scripts/live-required/tangle-sandbox-interactive-continuity.test.mjs new file mode 100644 index 0000000..ec66493 --- /dev/null +++ b/scripts/live-required/tangle-sandbox-interactive-continuity.test.mjs @@ -0,0 +1,312 @@ +import assert from 'node:assert/strict' +import test from 'node:test' + +import { + assertControlForRef, + assertPublicInteractiveSurface, + assertSameInteractiveRef, + assertStatusForRef, + buildExactInteractiveStart, + safeErrorRecord, +} from './tangle-sandbox-interactive-continuity.mjs' + +function exactControl(refDigest, generation = 1) { + return { + refDigest, + generation, + leaseId: `lease-${generation}`, + holderId: `holder-${generation}`, + expiresAt: new Date(Date.now() + 60_000).toISOString(), + } +} + +function fakeSandboxModule({ exact = true } = {}) { + class Sandbox {} + class InteractiveSessionHandle {} + class TerminalStream {} + for (const name of ['create', 'get']) Sandbox.prototype[name] = () => {} + for (const name of exact + ? ['start', 'attach', 'status', 'claimControl', 'sendPrompt', 'stop', 'stopLifecycle'] + : ['start', 'attach', 'status', 'sendPrompt', 'stop']) { + InteractiveSessionHandle.prototype[name] = () => {} + } + for (const name of ['write', 'close', 'reconnect']) TerminalStream.prototype[name] = () => {} + TerminalStream.connect = () => {} + return { Sandbox, InteractiveSessionHandle, TerminalStream } +} + +function fakeInterfaceModule() { + return { + agentInteractiveSessionRunRef: () => {}, + agentInteractiveSessionRefMatchesStart: () => true, + agentInteractiveSessionStatusMatchesRef: () => true, + agentInteractiveSessionControlClaimMatchesRef: () => true, + agentInteractiveSessionPromptRequestDigest: () => `sha256:${'a'.repeat(64)}`, + agentInteractiveSessionStopRequestDigest: () => `sha256:${'b'.repeat(64)}`, + canonicalAgentProfileDigest: () => `sha256:${'c'.repeat(64)}`, + canonicalCandidateDigest: (value) => JSON.stringify(value), + exactAgentInteractiveSessionStart: (value) => value, + } +} + +class FakeTerminalWebSocket { + static OPEN = 1 + + static CLOSED = 3 + + static frames = [] + + static sockets = [] + + constructor(url, protocols) { + this.url = url + this.protocols = protocols + this.readyState = 0 + this.binaryType = 'blob' + this.listeners = new Map() + FakeTerminalWebSocket.sockets.push(this) + queueMicrotask(() => { + this.readyState = FakeTerminalWebSocket.OPEN + this.emit('open', {}) + }) + } + + addEventListener(type, listener) { + const listeners = this.listeners.get(type) ?? [] + listeners.push(listener) + this.listeners.set(type, listeners) + } + + emit(type, event) { + for (const listener of this.listeners.get(type) ?? []) listener(event) + } + + send(payload) { + const frame = JSON.parse(payload) + FakeTerminalWebSocket.frames.push({ socket: this, frame }) + if (frame.type === 'init') { + const initCount = FakeTerminalWebSocket.frames.filter( + ({ frame: candidate }) => candidate.type === 'init', + ).length + queueMicrotask(() => + this.emit('message', { + data: JSON.stringify({ + type: 'ready', + connectionId: frame.connectionId, + sessionId: frame.connectionId, + restored: initCount > 1, + detachTimeoutMs: 5_000, + }), + }), + ) + queueMicrotask(() => + this.emit('message', { + data: new TextEncoder().encode(`replay-${frame.connectionId}`).buffer, + }), + ) + } + if (frame.type === 'input') { + queueMicrotask(() => + this.emit('message', { + data: new TextEncoder().encode(`echo-${frame.data}`).buffer, + }), + ) + } + } + + close(code = 1000, reason = '') { + if (this.readyState === FakeTerminalWebSocket.CLOSED) return + this.readyState = FakeTerminalWebSocket.CLOSED + queueMicrotask(() => this.emit('close', { code, reason })) + } +} + +test('missing exact public methods are a hard unavailable result', () => { + assert.throws( + () => + assertPublicInteractiveSurface(fakeSandboxModule({ exact: false }), fakeInterfaceModule()), + (error) => + error.unavailable === true && + error.code === 'SANDBOX_INTERACTIVE_EXACT_SURFACE_UNAVAILABLE' && + error.details.missing.includes('InteractiveSessionHandle.prototype.claimControl'), + ) +}) + +test('the installed public package either satisfies the exact surface or reports its blocker', async () => { + const sandboxModule = await import('@tangle-network/sandbox') + const interfaceModule = await import('@tangle-network/agent-interface') + try { + const surface = assertPublicInteractiveSurface(sandboxModule, interfaceModule) + assert.equal(surface.sandbox, sandboxModule) + } catch (error) { + assert.equal(error.unavailable, true) + assert.equal(error.code, 'SANDBOX_INTERACTIVE_EXACT_SURFACE_UNAVAILABLE') + } +}) + +test('exact start material binds one run to one profile and session', () => { + const interfaceModule = { + ...fakeInterfaceModule(), + canonicalAgentProfileDigest: () => `sha256:${'1'.repeat(64)}`, + agentInteractiveSessionRunRef: (coordinates, _input) => ({ + ...coordinates, + runId: 'interactive-run-test', + requestDigest: `sha256:${'2'.repeat(64)}`, + }), + } + const exact = buildExactInteractiveStart({ + interfaceModule, + environmentId: 'sandbox-1', + sessionId: 'session-1', + executionId: 'execution-1', + proofId: 'proof-1', + runner: 'pi', + model: 'test-model', + }) + assert.equal(exact.start.run.environmentId, 'sandbox-1') + assert.equal(exact.start.run.sessionId, 'session-1') + assert.equal(exact.start.run.executionId, 'execution-1') + assert.equal(exact.start.profile.harness, 'pi') + assert.match(exact.start.initialPrompt, /BRAID_NATIVE_OUTPUT_proof-1/u) +}) + +test('same-ref assertions reject a changed incarnation and accept an exact replay', () => { + const interfaceModule = { + canonicalCandidateDigest: (value) => JSON.stringify(value), + } + const expected = { + run: { + runId: 'run-1', + provider: 'tangle-sandbox', + environmentId: 'sandbox-1', + sessionId: 'session-1', + executionId: 'execution-1', + requestDigest: `sha256:${'a'.repeat(64)}`, + }, + incarnationId: 'incarnation-1', + } + assert.doesNotThrow(() => + assertSameInteractiveRef(interfaceModule, expected, structuredClone(expected), 'reconnect'), + ) + assert.throws( + () => + assertSameInteractiveRef( + interfaceModule, + expected, + { ...structuredClone(expected), incarnationId: 'incarnation-stale' }, + 'stale identity', + ), + /changed its exact process reference/u, + ) +}) + +test('status and control assertions stay bound to the exact process', () => { + const ref = { + run: { + runId: 'run-2', + provider: 'tangle-sandbox', + environmentId: 'sandbox-2', + sessionId: 'session-2', + executionId: 'execution-2', + requestDigest: `sha256:${'b'.repeat(64)}`, + }, + incarnationId: 'incarnation-2', + } + const interfaceModule = { + canonicalCandidateDigest: (value) => JSON.stringify(value), + agentInteractiveSessionStatusMatchesRef: () => true, + agentInteractiveSessionControlClaimMatchesRef: () => true, + } + assertStatusForRef( + interfaceModule, + ref, + { state: 'running', ref: structuredClone(ref) }, + 'status', + ) + assertControlForRef(interfaceModule, ref, exactControl(`sha256:${'c'.repeat(64)}`), 'control') +}) + +test('error evidence does not expose a credential', () => { + const secret = 'sk-test-continuity-secret' + const record = safeErrorRecord(new Error(`upstream rejected ${secret}`), { + BRAID_TANGLE_SANDBOX_API_KEY: secret, + }) + assert.equal(record.message.includes(secret), false) +}) + +test('public TerminalStream proves input, detach, and same-connection replay with a fake server', async () => { + const { TerminalStream } = await import('@tangle-network/sandbox') + const previousWebSocket = globalThis.WebSocket + FakeTerminalWebSocket.frames = [] + FakeTerminalWebSocket.sockets = [] + globalThis.WebSocket = FakeTerminalWebSocket + const output = [] + const control = { + refDigest: `sha256:${'d'.repeat(64)}`, + generation: 1, + leaseId: 'lease-unit', + holderId: 'holder-unit', + expiresAt: new Date(Date.now() + 60_000).toISOString(), + } + try { + const first = await TerminalStream.connect({ + url: 'https://sandbox.test/terminals/session-unit/ws', + token: 'unit-token', + connectionId: 'session-unit', + incarnationId: 'incarnation-unit', + control, + handlers: { + onData(data) { + output.push(new TextDecoder().decode(data)) + }, + }, + }) + assert.equal(first.ready.connectionId, 'session-unit') + assert.equal(first.ready.restored, false) + first.write('input-unit\r') + await new Promise((resolve) => setTimeout(resolve, 0)) + await first.close() + + const second = await first.reconnect({ + handlers: { + onData(data) { + output.push(new TextDecoder().decode(data)) + }, + }, + }) + assert.equal(second.ready.connectionId, 'session-unit') + assert.equal(second.ready.restored, true) + second.write('reconnect-unit\r') + await new Promise((resolve) => setTimeout(resolve, 0)) + await second.close() + + const initFrames = FakeTerminalWebSocket.frames.filter(({ frame }) => frame.type === 'init') + assert.equal(initFrames.length, 2) + assert.deepEqual( + initFrames.map(({ frame }) => frame.connectionId), + ['session-unit', 'session-unit'], + ) + assert.deepEqual( + FakeTerminalWebSocket.frames + .filter(({ frame }) => frame.type === 'input') + .map(({ frame }) => frame.data), + ['input-unit\r', 'reconnect-unit\r'], + ) + assert.equal( + output.some((chunk) => chunk.includes('echo-input-unit')), + true, + ) + assert.equal( + output.some((chunk) => chunk.includes('replay-session-unit')), + true, + ) + if (Object.hasOwn(initFrames[0].frame, 'incarnationId')) { + assert.equal(initFrames[0].frame.incarnationId, 'incarnation-unit') + assert.deepEqual(initFrames[0].frame.control, control) + assert.equal(initFrames[1].frame.incarnationId, 'incarnation-unit') + assert.deepEqual(initFrames[1].frame.control, control) + } + } finally { + globalThis.WebSocket = previousWebSocket + } +}) diff --git a/scripts/test-pty.mjs b/scripts/test-pty.mjs index 191b4f5..ce9edb4 100644 --- a/scripts/test-pty.mjs +++ b/scripts/test-pty.mjs @@ -220,8 +220,10 @@ async function runAutocompleteRace() { session.write('profile\r') await waitFor( () => - normalizeScreen(screen).includes('profiles') && - normalizeScreen(screen).includes('^V valid'), + normalizeScreen(screen).includes('profile') && + normalizeScreen(screen).includes('Braid starter') && + normalizeScreen(screen).includes('runner pi · model fixture/deterministic') && + normalizeScreen(screen).includes('←/esc close'), 'exact /profile overlay', ) if (/unknown command \/profil(?:new|enew)/iu.test(output)) @@ -229,7 +231,7 @@ async function runAutocompleteRace() { session.write('\u001b') await waitFor( - () => !normalizeScreen(screen).includes('^V valid'), + () => !normalizeScreen(screen).includes('runner pi · model fixture/deterministic'), 'autocomplete race profile close', () => screen, ) diff --git a/src/adapters/connections/tangle-retained-control-lookup.ts b/src/adapters/connections/tangle-retained-control-lookup.ts index 04fdfe7..d492a65 100644 --- a/src/adapters/connections/tangle-retained-control-lookup.ts +++ b/src/adapters/connections/tangle-retained-control-lookup.ts @@ -1,5 +1,6 @@ import { AgentExactRunControlRefSchema } from '@tangle-network/agent-interface' import type { SandboxClientLike, SandboxInstanceLike } from '@tangle-network/agent-provider-tangle' +import { stableProviderId } from '../runtime/production-backend-common.js' import type { TangleRetainedControlLookup, TangleRetainedControlLookupInput, @@ -18,17 +19,13 @@ type RetainedList = (options?: { readonly signal?: AbortSignal }) => Promise -function safeIdentity(value: string): string { - return value.replace(/[^A-Za-z0-9._:-]/gu, '-').slice(0, 128) || 'run' -} - function matchesRetainedEnvironment( box: SandboxInstanceLike, input: TangleRetainedControlLookupInput, ): boolean { const metadata = box.metadata return ( - box.name === `braid-${safeIdentity(input.providerSessionId)}` && + box.name === stableProviderId('braid-', input.providerSessionId) && metadata?.owner === 'braid' && metadata.lifecycle === 'retained' && metadata.providerSessionId === input.providerSessionId && diff --git a/src/adapters/runtime/cli-bridge-retained-execution.ts b/src/adapters/runtime/cli-bridge-retained-execution.ts index b0aef66..0530862 100644 --- a/src/adapters/runtime/cli-bridge-retained-execution.ts +++ b/src/adapters/runtime/cli-bridge-retained-execution.ts @@ -1,16 +1,19 @@ import type { AgentExactRunControlRef } from '@tangle-network/agent-interface' -import type { ExecuteTurnInput } from '../../ports/execution.js' +import type { ExecuteTurnInput, RetainedExecutionRecoveryContext } from '../../ports/execution.js' import { createCliBridgeRetainedPlan } from './cli-bridge-retained-run.js' import type { PreparedCliBridgeConnection } from './production-cli-bridge-backend.js' import { RetainedExecutionPort } from './retained-execution.js' export interface CliBridgeRetainedExecutionOptions { readonly resolve: (input: ExecuteTurnInput) => Promise - readonly recover: (input: { - readonly runId: string - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - }) => Promise + readonly recover: ( + input: { + readonly runId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly signal?: AbortSignal + } & RetainedExecutionRecoveryContext, + ) => Promise } /** Braid's durable CLI-Bridge path. CLI-Bridge owns the job; the shared port owns readers. */ @@ -19,15 +22,18 @@ export class CliBridgeRetainedExecutionPort extends RetainedExecutionPort { super({ resolve: async (input) => createCliBridgeRetainedPlan(await options.resolve(input), input.runId), - recover: async ({ runId, providerSessionId, controlRef }) => + recover: async ({ runId, providerSessionId, controlRef, signal, ...recovery }) => createCliBridgeRetainedPlan( await options.recover({ runId, ...(providerSessionId === undefined ? {} : { providerSessionId }), ...(controlRef === undefined ? {} : { controlRef }), + ...(signal === undefined ? {} : { signal }), + ...recovery, }), runId, controlRef, + recovery, ), }) } diff --git a/src/adapters/runtime/cli-bridge-retained-run.ts b/src/adapters/runtime/cli-bridge-retained-run.ts index 0ce447a..7a20f06 100644 --- a/src/adapters/runtime/cli-bridge-retained-run.ts +++ b/src/adapters/runtime/cli-bridge-retained-run.ts @@ -7,13 +7,20 @@ import type { BridgeModelCredential } from '@tangle-network/agent-runtime/kernel import { type RetainedRunHandle, reconnectRetainedRun, + recoverRetainedRun, startRetainedRun, } from '@tangle-network/agent-runtime/kernel' +import { canonicalDigest } from '../../domain/canonical.js' import { publicMaterializationReceipt } from '../../domain/materialization-receipt.js' import type { RuntimeEventEnvelope } from '../../domain/runtime-events.js' -import type { ExecuteTurnInput } from '../../ports/execution.js' +import type { + ExecuteTurnInput, + RetainedExecutionRecoveryContext, + RetainedRunAdmissionRecord, + RetainedRunAdmissionRecorder, +} from '../../ports/execution.js' import { isLoopbackEndpoint } from '../connections/production-connection-endpoints.js' -import { safeExecutionId } from './production-backend-common.js' +import { safeExecutionId, stableProviderId } from './production-backend-common.js' import type { PreparedCliBridgeConnection } from './production-cli-bridge-backend.js' import type { RetainedExecutionPlan, @@ -33,14 +40,21 @@ const MAX_STATUS_BYTES = 64 * 1024 export interface CliBridgeRetainedPlan extends RetainedExecutionPlan { readonly prepared: PreparedCliBridgeConnection readonly provider: AgentEnvironmentProvider - readonly environmentId: string + readonly environmentId?: string + readonly environmentIdempotencyKey: string readonly executionId: string } +type HeadlessRetainedAdmission = Extract< + RetainedRunAdmissionRecord, + { readonly phase: 'intent' | 'environment' | 'dispatched' } +> + export async function createCliBridgeRetainedPlan( prepared: PreparedCliBridgeConnection, runId: string, controlRef?: AgentExactRunControlRef, + recovery?: RetainedExecutionRecoveryContext, ): Promise { const { createCliBridgeProvider } = await import('@tangle-network/agent-provider-cli-bridge') const provider = createCliBridgeProvider({ @@ -53,29 +67,56 @@ export async function createCliBridgeRetainedPlan( ? {} : { fetch: bridgeCredentialFetch(prepared) }), }) - const environmentId = controlRef?.environmentId ?? retainedEnvironmentId(runId) - const executionId = controlRef?.executionId ?? safeExecutionId(runId) + const admission = headlessRetainedAdmission(recovery?.retainedAdmission) + if (admission !== undefined && admissionProvider(admission) !== provider.name) { + throw new Error('retained CLI Bridge admission belongs to another provider') + } + const persistedControlRef = admission?.phase === 'dispatched' ? admission.controlRef : undefined + if ( + controlRef !== undefined && + persistedControlRef !== undefined && + canonicalDigest(controlRef) !== canonicalDigest(persistedControlRef) + ) { + throw new Error('retained CLI Bridge control reference conflicts with the persisted run') + } + const exactControlRef = controlRef ?? persistedControlRef + const environmentId = + exactControlRef?.environmentId ?? + (admission?.phase === 'environment' ? admission.environmentId : undefined) + const executionId = + exactControlRef?.executionId ?? + (admission?.phase === 'intent' || admission?.phase === 'environment' + ? admission.executionId + : safeExecutionId(runId)) + const environmentIdempotencyKey = + admission?.idempotencyKey ?? retainedEnvironmentIdempotencyKey(runId) const providerName = provider.name const capabilities = retainedCapabilities(prepared.capabilities) const materializationReceipt = publicMaterializationReceipt({ ...prepared.materializationReceipt, backend: 'environment-provider', - environmentId, - providerRunId: controlRef?.runId ?? executionId, + ...(environmentId === undefined ? {} : { environmentId }), + providerRunId: exactControlRef?.runId ?? executionId, retainedControl: 'exact-after-dispatch', }) const plan: CliBridgeRetainedPlan = { prepared, provider, - environmentId, + ...(environmentId === undefined ? {} : { environmentId }), + environmentIdempotencyKey, executionId, providerName, - providerSessionId: controlRef?.sessionId ?? prepared.providerSessionId, + providerSessionId: + exactControlRef?.sessionId ?? + (admission?.phase === 'intent' || admission?.phase === 'environment' + ? admission.sessionId + : prepared.providerSessionId), model: prepared.route, capabilities, materializationReceipt, start: (input) => startCliBridgeRetainedRun(plan, input), reconnect: (controlRef) => reconnectCliBridgeRetainedRun(plan, controlRef), + recover: (input) => recoverCliBridgeRetainedRun(plan, input), discover: (braidRunId, signal) => discoverCliBridgeControlRef(plan, braidRunId, signal), observe: () => prepared.observation.snapshot(), projectStatus: ({ status, detached }) => retainedStatus(status, detached), @@ -162,7 +203,7 @@ export async function startCliBridgeRetainedRun( profile: plan.prepared.profile, backend: plan.prepared.runner, workspace: { cwd: plan.prepared.workspace }, - idempotencyKey: plan.environmentId, + idempotencyKey: plan.environmentIdempotencyKey, }, turn: { prompt: input.text, @@ -185,12 +226,60 @@ export async function reconnectCliBridgeRetainedRun( return reconnectRetainedRun({ provider: plan.provider, controlRef }) } +async function recoverCliBridgeRetainedRun( + plan: CliBridgeRetainedPlan, + input: RetainedExecutionRecoveryContext & { + readonly admission: RetainedRunAdmissionRecord + readonly onRetainedAdmission?: RetainedRunAdmissionRecorder + readonly signal?: AbortSignal + }, +): Promise { + const admission = headlessRetainedAdmission(input.admission) + if (admission === undefined) return null + if (admission.phase === 'intent') { + if (input.receipt === undefined || input.onRetainedAdmission === undefined) return null + const result = await recoverRetainedRun({ + provider: plan.provider, + admission, + replay: { + environment: { + profile: plan.prepared.profile, + backend: plan.prepared.runner, + workspace: { cwd: plan.prepared.workspace }, + idempotencyKey: admission.idempotencyKey, + }, + turn: { + prompt: input.receipt.requested.text, + turnId: admission.turnId, + interactions: input.receipt.requested.interactions ?? {}, + ...(input.signal === undefined ? {} : { signal: input.signal }), + }, + identity: { + sessionId: admission.sessionId, + executionId: admission.executionId, + }, + }, + onAdmission: input.onRetainedAdmission, + }) + return result.outcome === 'recovered' ? result.handle : null + } + if (admission.phase !== 'environment') return null + const result = await recoverRetainedRun({ + provider: plan.provider, + environmentId: admission.environmentId, + sessionId: admission.sessionId, + executionId: admission.executionId, + }) + return result.outcome === 'recovered' ? result.handle : null +} + /** Recover the exact server-issued digest after a client crashed during dispatch. */ export async function discoverCliBridgeControlRef( plan: CliBridgeRetainedPlan, _braidRunId: string, signal?: AbortSignal, ): Promise { + if (plan.environmentId === undefined || plan.providerSessionId === undefined) return null const providerRunId = plan.executionId const response = await (plan.prepared.fetch ?? globalThis.fetch)( `${plan.prepared.bridgeUrl}/v1/runs/${encodeURIComponent(providerRunId)}`, @@ -228,8 +317,25 @@ export async function discoverCliBridgeControlRef( }) } -export function retainedEnvironmentId(runId: string): string { - return `environment-braid-${safeExecutionId(runId)}` +function retainedEnvironmentIdempotencyKey(runId: string): string { + return stableProviderId('environment-braid-', runId) +} + +function headlessRetainedAdmission( + admission: RetainedRunAdmissionRecord | undefined, +): HeadlessRetainedAdmission | undefined { + if ( + admission?.phase !== 'intent' && + admission?.phase !== 'environment' && + admission?.phase !== 'dispatched' + ) { + return undefined + } + return admission +} + +function admissionProvider(admission: HeadlessRetainedAdmission): string { + return admission.phase === 'dispatched' ? admission.controlRef.provider : admission.provider } async function boundedResponseText(response: Response): Promise { diff --git a/src/adapters/runtime/mode-routing-execution.ts b/src/adapters/runtime/mode-routing-execution.ts index b3080d6..0ea4840 100644 --- a/src/adapters/runtime/mode-routing-execution.ts +++ b/src/adapters/runtime/mode-routing-execution.ts @@ -3,6 +3,7 @@ import type { ExecuteTurnInput, ExecutionPort, NormalizedExecutionEvent, + RetainedExecutionRecoveryContext, RunCapabilities, } from '../../ports/execution.js' import { UNKNOWN_RUN_CAPABILITIES } from '../../ports/execution.js' @@ -65,7 +66,7 @@ export class ModeRoutingExecutionPort implements ExecutionPort { } async cancelRun(input: CancelInput) { - const port = this.#portForRun(input.runId, input.controlRef) + const port = this.#portForInput(input) if (port.cancelRun === undefined) { throw new Error('The selected execution port does not support cancellation') } @@ -73,7 +74,7 @@ export class ModeRoutingExecutionPort implements ExecutionPort { } async detachRun(input: DetachInput) { - const port = this.#portForRun(input.runId, input.controlRef) + const port = this.#portForInput(input) if (port.detachRun === undefined) { throw new Error('The selected execution port does not support detachment') } @@ -99,8 +100,15 @@ export class ModeRoutingExecutionPort implements ExecutionPort { async respondInteraction(input: { readonly command: InteractionResponseCommand readonly signal?: AbortSignal + readonly recovery?: RetainedExecutionRecoveryContext }) { - const port = this.#portForRun(input.command.binding.runId) + const port = this.#portForInput({ + runId: input.command.binding.runId, + ...(input.recovery?.retainedAdmission === undefined + ? {} + : { retainedAdmission: input.recovery.retainedAdmission }), + ...(input.recovery?.receipt === undefined ? {} : { receipt: input.recovery.receipt }), + }) if (port.respondInteraction === undefined) { throw new Error('The selected execution port does not support interaction responses') } diff --git a/src/adapters/runtime/production-backend-common.ts b/src/adapters/runtime/production-backend-common.ts index d74aabc..c02486d 100644 --- a/src/adapters/runtime/production-backend-common.ts +++ b/src/adapters/runtime/production-backend-common.ts @@ -1,6 +1,7 @@ import type { AgentProfile, HarnessType } from '@tangle-network/agent-interface' import { ConnectionError } from '../../app/connection-errors.js' import type { ConnectionCatalog, ConnectionSelectionInput } from '../../app/connections.js' +import { canonicalDigest } from '../../domain/canonical.js' import type { ConnectionRecord } from '../../domain/entities.js' import type { ConnectionId } from '../../domain/ids.js' import type { ExecuteTurnInput } from '../../ports/execution.js' @@ -103,7 +104,18 @@ export function requiredWorkspaceCwd( export function safeExecutionId(value: string): string { const safe = value.replace(/[^A-Za-z0-9._:-]/gu, '-') - return safe.slice(0, 128) || 'run' + if (value.length > 0 && safe === value && value.length <= 128) return value + const readable = safe || 'run' + const suffix = canonicalDigest(value).slice('sha256:'.length, 'sha256:'.length + 32) + return `${readable.slice(0, 95)}-${suffix}` +} + +/** Build a readable provider key without collisions or overlong truncation. */ +export function stableProviderId(prefix: string, value: string): string { + const readable = `${prefix}${safeExecutionId(value)}` + if (readable.length <= 128) return readable + const suffix = canonicalDigest({ prefix, value }).slice('sha256:'.length, 'sha256:'.length + 32) + return `${readable.slice(0, 95)}-${suffix}` } export function freezeExecution(value: T): T { diff --git a/src/adapters/runtime/production-cli-bridge-backend.ts b/src/adapters/runtime/production-cli-bridge-backend.ts index e65ef21..2fde4e1 100644 --- a/src/adapters/runtime/production-cli-bridge-backend.ts +++ b/src/adapters/runtime/production-cli-bridge-backend.ts @@ -25,7 +25,7 @@ import { requiredProfileModel, requiredProfileRunner, requiredWorkspaceCwd, - safeExecutionId, + stableProviderId, } from './production-backend-common.js' const LOCAL_BRIDGE_BEARER = 'braid-local-cli-bridge' @@ -114,7 +114,7 @@ export async function prepareCliBridgeConnection( const record = connectionRecord(connectionId, options) const credential = await readConnectionCredential(record, options, endpoint) - const providerSessionId = input.sessionId ?? `session-braid-${safeExecutionId(input.runId)}` + const providerSessionId = input.sessionId ?? stableProviderId('session-braid-', input.runId) const route = materializeBridgeModelRoute(runner, model, profile.model?.provider) const workspace = requiredWorkspaceCwd(input.workspaceRoot, options.workspaceCwd) const bridgeUrl = normalizeCliBridgeProviderBaseUrl(endpoint, connectionId) diff --git a/src/adapters/runtime/production-tangle-sandbox-backend.ts b/src/adapters/runtime/production-tangle-sandbox-backend.ts index 31589bb..3263324 100644 --- a/src/adapters/runtime/production-tangle-sandbox-backend.ts +++ b/src/adapters/runtime/production-tangle-sandbox-backend.ts @@ -11,6 +11,10 @@ import { canonicalDigest } from '../../domain/canonical.js' import type { ConnectionId } from '../../domain/ids.js' import type { ExecuteTurnInput } from '../../ports/execution.js' import { harnessSupportsModel, snapHarnessToModel } from '../agent-interface/harness-runtime.js' +import { + createTangleRetainedControlLookup, + supportsTangleRetainedControlLookup, +} from '../connections/tangle-retained-control-lookup.js' import type { ExecutionObservationSource, PreparedExecution, @@ -25,12 +29,9 @@ import { requiredProfileModel, requiredProfileRunner, safeExecutionId, + stableProviderId, } from './production-backend-common.js' import { observeSandboxClient } from './sandbox-observation.js' -import { - createTangleRetainedControlLookup, - supportsTangleRetainedControlLookup, -} from '../connections/tangle-retained-control-lookup.js' import { withSandboxResultProjection } from './sandbox-result-projection.js' import { retainedSandboxIdentity, @@ -68,7 +69,7 @@ export async function resolveTangleSandboxBackend( import('@tangle-network/agent-runtime/kernel'), ]) const lifecycle = sandboxLifecycle() - const idempotencyKey = `env-braid-${safeExecutionId(input.runId)}` + const idempotencyKey = stableProviderId('env-braid-', input.runId) const environmentRequestDigest = canonicalDigest({ kind: 'tangle-sandbox-environment-request', idempotencyKey, @@ -157,7 +158,7 @@ export async function resolveTangleSandboxRetainedConnection( ) } const { profile, model, runner } = await tangleExecutionIdentity(input, selection, connectionId) - const providerSessionId = input.sessionId ?? `session-braid-${safeExecutionId(input.runId)}` + const providerSessionId = input.sessionId ?? stableProviderId('session-braid-', input.runId) if (!providerSessionId.startsWith('session-braid-')) { throw new ConnectionError( 'CONNECTION_UNSUPPORTED', @@ -306,7 +307,7 @@ function providerSessionFor( capabilities: AgentEnvironmentCapabilities, ): string | undefined { if (!capabilities.sessions.continue) return undefined - return input.sessionId ?? `session-braid-${safeExecutionId(input.runId)}` + return input.sessionId ?? stableProviderId('session-braid-', input.runId) } async function tangleExecutionIdentity( diff --git a/src/adapters/runtime/retained-execution-contract.ts b/src/adapters/runtime/retained-execution-contract.ts index edfab1f..32cc3d5 100644 --- a/src/adapters/runtime/retained-execution-contract.ts +++ b/src/adapters/runtime/retained-execution-contract.ts @@ -7,6 +7,9 @@ import type { RuntimeEventEnvelope } from '../../domain/runtime-events.js' import type { ExecuteTurnInput, ProviderRunSnapshot, + RetainedExecutionRecoveryContext, + RetainedRunAdmissionRecord, + RetainedRunAdmissionRecorder, RunCapabilities, } from '../../ports/execution.js' @@ -32,6 +35,14 @@ export interface RetainedExecutionPlan { controlRef: AgentExactRunControlRef, signal?: AbortSignal, ) => Promise + /** Recover a persisted intent or pre-dispatch admission with Runtime. */ + readonly recover?: ( + input: RetainedExecutionRecoveryContext & { + readonly admission: RetainedRunAdmissionRecord + readonly onRetainedAdmission?: RetainedRunAdmissionRecorder + readonly signal?: AbortSignal + }, + ) => Promise readonly discover: ( braidRunId: string, signal?: AbortSignal, @@ -52,9 +63,12 @@ export interface RetainedExecutionPlan { export interface RetainedExecutionDriver { readonly resolve: (input: ExecuteTurnInput) => Promise - readonly recover: (input: { - readonly runId: string - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - }) => Promise + readonly recover: ( + input: { + readonly runId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly signal?: AbortSignal + } & RetainedExecutionRecoveryContext, + ) => Promise } diff --git a/src/adapters/runtime/retained-execution-state.ts b/src/adapters/runtime/retained-execution-state.ts index 5a8b291..3f0da19 100644 --- a/src/adapters/runtime/retained-execution-state.ts +++ b/src/adapters/runtime/retained-execution-state.ts @@ -4,13 +4,18 @@ import { } from '@tangle-network/agent-interface' import type { RetainedRunHandle } from '@tangle-network/agent-runtime/kernel' import { canonicalDigest } from '../../domain/canonical.js' +import type { RunCapabilities } from '../../domain/run-contracts.js' +import { requestedInteractionsForRun } from '../../domain/run-interactions.js' import type { ExecuteTurnInput } from '../../ports/execution.js' import { canonicalAgentProfileDigestHex } from '../agent-interface/profile-runtime.js' import type { RetainedExecutionPlan } from './retained-execution-contract.js' const MAX_RETAINED_CLIENTS = 128 -export function retainedExecutionKey(input: ExecuteTurnInput): string { +export function retainedExecutionKey( + input: ExecuteTurnInput, + capabilities?: Pick, +): string { return canonicalDigest({ runId: input.runId, operationId: input.operationId, @@ -18,6 +23,9 @@ export function retainedExecutionKey(input: ExecuteTurnInput): string { profile: canonicalAgentProfileDigestHex(input.profile), connectionId: input.connectionId ?? null, mode: input.mode ?? null, + interactions: + input.interactions ?? + (capabilities === undefined ? {} : requestedInteractionsForRun(input.mode, capabilities)), workspaceRoot: input.workspaceRoot ?? null, sessionId: input.sessionId ?? null, contextBoundary: input.contextBoundary ?? null, @@ -60,6 +68,10 @@ export class RetainedExecutionState { return this.#plans.get(runId) } + preparedPlan(runId: string): RetainedExecutionPlan | undefined { + return this.#prepared.has(runId) ? this.#plans.get(runId) : undefined + } + rememberPlan(runId: string, plan: RetainedExecutionPlan): void { this.#plans.set(runId, plan) this.#touch(runId) diff --git a/src/adapters/runtime/retained-execution.ts b/src/adapters/runtime/retained-execution.ts index 6c9d1cd..9ac1e9c 100644 --- a/src/adapters/runtime/retained-execution.ts +++ b/src/adapters/runtime/retained-execution.ts @@ -13,6 +13,9 @@ import type { ExecutionAdmission, ExecutionPort, ProviderRunSnapshot, + RetainedExecutionRecoveryContext, + RetainedRunAdmissionRecord, + RetainedRunAdmissionRecorder, } from '../../ports/execution.js' import { canonicalAgentProfileDigestHex } from '../agent-interface/profile-runtime.js' import type { @@ -46,7 +49,7 @@ export class RetainedExecutionPort implements ExecutionPort { async admit(input: ExecuteTurnInput): Promise { const plan = await this.#driver.resolve(input) - this.#state.rememberPrepared(input.runId, retainedExecutionKey(input), plan) + this.#state.rememberPrepared(input.runId, retainedExecutionKey(input, plan.capabilities), plan) return { capabilities: plan.capabilities, provider: plan.providerName, @@ -63,7 +66,11 @@ export class RetainedExecutionPort implements ExecutionPort { async *streamTurn(input: ExecuteTurnInput): AsyncGenerator { if (this.#state.isCancellationRequested(input.runId)) return - const plan = this.#state.takePrepared(input.runId, retainedExecutionKey(input)) + const prepared = this.#state.preparedPlan(input.runId) + const plan = this.#state.takePrepared( + input.runId, + retainedExecutionKey(input, prepared?.capabilities), + ) if (plan === undefined) { throw new Error('Retained run was not admitted with this exact request') } @@ -89,20 +96,56 @@ export class RetainedExecutionPort implements ExecutionPort { }) } - async *reconnect(input: { - readonly runId: string - readonly after?: string - readonly afterSequence?: number - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - readonly signal: AbortSignal - }): AsyncGenerator { + async *reconnect( + input: { + readonly runId: string + readonly after?: string + readonly afterSequence?: number + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly signal: AbortSignal + } & RetainedExecutionRecoveryContext & { + readonly onRetainedAdmission?: RetainedRunAdmissionRecorder + }, + ): AsyncGenerator { if (input.after !== undefined && input.afterSequence === undefined) { throw new Error('Retained reconnect requires the saved event sequence') } - const providerSessionId = this.#recoverySessionId(input.providerSessionId, input.controlRef) - const plan = await this.#planFor(input.runId, providerSessionId, input.controlRef) - const controlRef = await this.#controlRefFor(input.runId, plan, input.controlRef, input.signal) + assertRecoveryIdentity(input.retainedAdmission, input.providerSessionId, input.controlRef) + const persistedControlRef = controlRefFromAdmission(input.retainedAdmission) + const suppliedControlRef = input.controlRef ?? persistedControlRef + const providerSessionId = this.#recoverySessionId(input.providerSessionId, suppliedControlRef) + const plan = await this.#planFor( + input.runId, + providerSessionId, + suppliedControlRef, + input, + input.signal, + ) + const recovered = await this.#recoverHandle(plan, input, input.onRetainedAdmission) + if (recovered !== undefined) { + if (recovered === null) return + assertRecoveredControlRef(this.#state, plan, suppliedControlRef, recovered) + this.#state.rememberHandle(input.runId, plan, recovered) + this.#state.markDetached(input.runId, false) + yield* streamRetainedExecution({ + runId: input.runId, + handle: recovered, + plan, + state: this.#state, + signal: input.signal, + includeObservation: (input.afterSequence ?? 0) === 0, + afterSequence: input.afterSequence ?? 0, + ...(input.after === undefined ? {} : { after: input.after }), + }) + return + } + const controlRef = await this.#controlRefFor( + input.runId, + plan, + suppliedControlRef, + input.signal, + ) if (!controlRef) return const handle = await plan.reconnect(controlRef, input.signal) if (!handle) return @@ -120,15 +163,34 @@ export class RetainedExecutionPort implements ExecutionPort { }) } - async detachRun(input: { - readonly runId: string - readonly operationId: string - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - readonly cursor?: string - readonly signal?: AbortSignal - }): Promise { - this.#validateKnownControl(input.runId, input.providerSessionId, input.controlRef) + async detachRun( + input: { + readonly runId: string + readonly operationId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly cursor?: string + readonly signal?: AbortSignal + } & RetainedExecutionRecoveryContext, + ): Promise { + assertRecoveryIdentity(input.retainedAdmission, input.providerSessionId, input.controlRef) + const persistedControlRef = controlRefFromAdmission(input.retainedAdmission) + const suppliedControlRef = input.controlRef ?? persistedControlRef + const recoverySessionId = this.#recoverySessionId(input.providerSessionId, suppliedControlRef) + if ( + this.#state.plan(input.runId) === undefined && + (input.retainedAdmission !== undefined || recoverySessionId !== undefined) + ) { + const plan = await this.#planFor( + input.runId, + recoverySessionId, + suppliedControlRef, + input, + input.signal, + ) + if (suppliedControlRef !== undefined) this.#state.validateControlRef(plan, suppliedControlRef) + } + this.#validateKnownControl(input.runId, input.providerSessionId, suppliedControlRef) if (this.#state.isDetached(input.runId)) { return { operationId: input.operationId, outcome: 'already-applied', detail: 'detached' } } @@ -158,11 +220,35 @@ export class RetainedExecutionPort implements ExecutionPort { detail: 'cancelled-before-start', } } + const retainedIntent = + input.retainedAdmission?.phase === 'intent' ? input.retainedAdmission : undefined + const active = this.#state.handle(input.runId) + const starting = this.#state.startingHandle(input.runId) + if (active === undefined && starting === undefined && retainedIntent !== undefined) { + if ( + input.controlRef !== undefined || + (input.providerSessionId !== undefined && + input.providerSessionId !== retainedIntent.sessionId) + ) { + return { + operationId: input.operationId, + outcome: 'rejected', + detail: 'retained-intent-control-mismatch', + } + } + this.#state.markCancellationRequested(input.runId) + return { + operationId: input.operationId, + outcome: 'accepted', + detail: 'cancelled-before-start', + } + } const resolved = await this.#handleFor( input.runId, input.providerSessionId, input.controlRef, input.signal, + input, ) if (!resolved) { return { @@ -213,17 +299,20 @@ export class RetainedExecutionPort implements ExecutionPort { } } - async status(input: { - readonly runId: string - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - readonly signal?: AbortSignal - }): Promise { + async status( + input: { + readonly runId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly signal?: AbortSignal + } & RetainedExecutionRecoveryContext, + ): Promise { const resolved = await this.#handleFor( input.runId, input.providerSessionId, input.controlRef, input.signal, + input, ) if (!resolved) return null if (resolved.plan.exactStatus === false) return null @@ -262,6 +351,7 @@ export class RetainedExecutionPort implements ExecutionPort { async respondInteraction(input: { readonly command: InteractionResponseCommand readonly signal?: AbortSignal + readonly recovery?: RetainedExecutionRecoveryContext }): Promise { const { binding } = input.command const resolved = await this.#handleFor( @@ -269,6 +359,7 @@ export class RetainedExecutionPort implements ExecutionPort { binding.sessionId, undefined, input.signal, + input.recovery, ) if (!resolved) { return { @@ -312,7 +403,13 @@ export class RetainedExecutionPort implements ExecutionPort { providerSessionId: string | undefined, supplied: AgentExactRunControlRef | undefined, signal: AbortSignal | undefined, + recovery?: RetainedExecutionRecoveryContext & { + readonly onRetainedAdmission?: RetainedRunAdmissionRecorder + }, ): Promise { + assertRecoveryIdentity(recovery?.retainedAdmission, providerSessionId, supplied) + const persistedControlRef = controlRefFromAdmission(recovery?.retainedAdmission) + const suppliedControlRef = supplied ?? persistedControlRef const active = this.#state.handle(runId) const activePlan = this.#state.plan(runId) const starting = this.#state.startingHandle(runId) @@ -324,8 +421,8 @@ export class RetainedExecutionPort implements ExecutionPort { if (starting === undefined) throw new Error('Retained run state is incomplete') handle = await starting } - if (supplied !== undefined) { - const exact = this.#state.validateControlRef(activePlan, supplied) + if (suppliedControlRef !== undefined) { + const exact = this.#state.validateControlRef(activePlan, suppliedControlRef) this.#state.assertSameControlRef(handle.controlRef, exact) } return { handle, plan: activePlan, wasStarting: starting !== undefined } @@ -333,9 +430,16 @@ export class RetainedExecutionPort implements ExecutionPort { if (activePlan !== undefined) { if (this.#state.isCancellationRequested(runId)) return null } - const recoverySessionId = this.#recoverySessionId(providerSessionId, supplied) - const plan = await this.#planFor(runId, recoverySessionId, supplied) - const controlRef = await this.#controlRefFor(runId, plan, supplied, signal) + const recoverySessionId = this.#recoverySessionId(providerSessionId, suppliedControlRef) + const plan = await this.#planFor(runId, recoverySessionId, suppliedControlRef, recovery, signal) + const recovered = await this.#recoverHandle(plan, recovery, recovery?.onRetainedAdmission) + if (recovered !== undefined) { + if (recovered === null) return null + assertRecoveredControlRef(this.#state, plan, suppliedControlRef, recovered) + this.#state.rememberHandle(runId, plan, recovered) + return { handle: recovered, plan, wasStarting: false } + } + const controlRef = await this.#controlRefFor(runId, plan, suppliedControlRef, signal) if (!controlRef) return null const handle = await plan.reconnect(controlRef, signal) if (handle) this.#state.rememberHandle(runId, plan, handle) @@ -375,9 +479,11 @@ export class RetainedExecutionPort implements ExecutionPort { runId: string, providerSessionId?: string, controlRef?: AgentExactRunControlRef, + recovery?: RetainedExecutionRecoveryContext, + signal?: AbortSignal, ): Promise { const cached = this.#state.plan(runId) - if (cached !== undefined) { + if (cached !== undefined && !planNeedsRecoveryRefresh(cached, controlRef, recovery)) { this.#state.assertProviderSession(cached, providerSessionId) return cached } @@ -385,12 +491,42 @@ export class RetainedExecutionPort implements ExecutionPort { runId, ...(providerSessionId === undefined ? {} : { providerSessionId }), ...(controlRef === undefined ? {} : { controlRef }), + ...(signal === undefined ? {} : { signal }), + ...(recovery ?? {}), }) this.#state.assertProviderSession(plan, providerSessionId) this.#state.rememberPlan(runId, plan) return plan } + async #recoverHandle( + plan: RetainedExecutionPlan, + recovery: + | (RetainedExecutionRecoveryContext & { + readonly onRetainedAdmission?: RetainedRunAdmissionRecorder + }) + | undefined, + onRetainedAdmission: RetainedRunAdmissionRecorder | undefined, + ): Promise { + const admission = recovery?.retainedAdmission + if ( + admission === undefined || + plan.recover === undefined || + admission.phase === 'dispatched' || + admission.phase === 'interactive_intent' || + admission.phase === 'interactive_environment' || + admission.phase === 'interactive_started' + ) { + return undefined + } + const recovered = await plan.recover({ + ...recovery, + admission, + ...(onRetainedAdmission === undefined ? {} : { onRetainedAdmission }), + }) + return admission.phase === 'environment' && recovered === null ? undefined : recovered + } + #recoverySessionId( providerSessionId: string | undefined, controlRef: AgentExactRunControlRef | undefined, @@ -420,6 +556,91 @@ export class RetainedExecutionPort implements ExecutionPort { } } +function controlRefFromAdmission( + admission: RetainedRunAdmissionRecord | undefined, +): AgentExactRunControlRef | undefined { + return admission?.phase === 'dispatched' ? admission.controlRef : undefined +} + +function assertRecoveryIdentity( + admission: RetainedRunAdmissionRecord | undefined, + providerSessionId: string | undefined, + supplied: AgentExactRunControlRef | undefined, +): void { + if (admission === undefined) return + const persistedSessionId = admissionSessionId(admission) + if (providerSessionId !== undefined && providerSessionId !== persistedSessionId) { + throw new Error('retained provider session conflicts with the persisted admission') + } + if (admission.phase !== 'dispatched') { + if (supplied !== undefined) { + throw new Error('retained control reference conflicts with the pre-dispatch admission') + } + return + } + if ( + supplied !== undefined && + canonicalDigest(supplied) !== canonicalDigest(admission.controlRef) + ) { + throw new Error('retained control reference conflicts with the persisted run') + } +} + +function admissionSessionId(admission: RetainedRunAdmissionRecord): string { + switch (admission.phase) { + case 'intent': + case 'environment': + case 'interactive_intent': + return admission.sessionId + case 'dispatched': + return admission.controlRef.sessionId + case 'interactive_environment': + return admission.request.run.sessionId + case 'interactive_started': + return admission.ref.run.sessionId + } +} + +function environmentIdFromRecovery( + admission: RetainedRunAdmissionRecord | undefined, +): string | undefined { + if (admission?.phase === 'environment') return admission.environmentId + if (admission?.phase === 'dispatched') return admission.controlRef.environmentId + return undefined +} + +function planNeedsRecoveryRefresh( + plan: RetainedExecutionPlan, + controlRef: AgentExactRunControlRef | undefined, + recovery: RetainedExecutionRecoveryContext | undefined, +): boolean { + const admission = recovery?.retainedAdmission + if ( + admission !== undefined && + admission.phase !== 'dispatched' && + admission.phase !== 'interactive_intent' && + admission.phase !== 'interactive_environment' && + admission.phase !== 'interactive_started' && + plan.recover === undefined + ) { + return true + } + const environmentId = + controlRef?.environmentId ?? environmentIdFromRecovery(recovery?.retainedAdmission) + return environmentId !== undefined && plan.environmentId !== environmentId +} + +function assertRecoveredControlRef( + state: RetainedExecutionState, + plan: RetainedExecutionPlan, + supplied: AgentExactRunControlRef | undefined, + recovered: RetainedRunHandle, +): void { + if (supplied === undefined) return + const exact = state.validateControlRef(plan, supplied) + state.assertSameControlRef(recovered.controlRef, exact) +} + function interactionAcknowledgement( operationId: string, status: InteractionAcknowledgementStatus, diff --git a/src/adapters/runtime/tangle-retained-execution.ts b/src/adapters/runtime/tangle-retained-execution.ts index 44d6f44..43ceb38 100644 --- a/src/adapters/runtime/tangle-retained-execution.ts +++ b/src/adapters/runtime/tangle-retained-execution.ts @@ -1,16 +1,19 @@ import type { AgentExactRunControlRef } from '@tangle-network/agent-interface' -import type { ExecuteTurnInput } from '../../ports/execution.js' +import type { ExecuteTurnInput, RetainedExecutionRecoveryContext } from '../../ports/execution.js' import type { PreparedTangleRetainedConnection } from './production-tangle-sandbox-backend.js' import { RetainedExecutionPort } from './retained-execution.js' import { createTangleRetainedPlan } from './tangle-retained-run.js' export interface TangleRetainedExecutionOptions { readonly resolve: (input: ExecuteTurnInput) => Promise - readonly recover: (input: { - readonly runId: string - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - }) => Promise + readonly recover: ( + input: { + readonly runId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly signal?: AbortSignal + } & RetainedExecutionRecoveryContext, + ) => Promise } /** The cloud owns the retained sandbox; Braid owns readers and exact recovery state. */ @@ -18,12 +21,14 @@ export class TangleRetainedExecutionPort extends RetainedExecutionPort { constructor(options: TangleRetainedExecutionOptions) { super({ resolve: async (input) => createTangleRetainedPlan(await options.resolve(input), input.runId), - recover: async ({ runId, providerSessionId, controlRef }) => + recover: async ({ runId, providerSessionId, controlRef, signal, ...recovery }) => createTangleRetainedPlan( await options.recover({ runId, ...(providerSessionId === undefined ? {} : { providerSessionId }), ...(controlRef === undefined ? {} : { controlRef }), + ...(signal === undefined ? {} : { signal }), + ...recovery, }), runId, controlRef, diff --git a/src/adapters/runtime/tangle-retained-interactive-contract.ts b/src/adapters/runtime/tangle-retained-interactive-contract.ts new file mode 100644 index 0000000..6003bed --- /dev/null +++ b/src/adapters/runtime/tangle-retained-interactive-contract.ts @@ -0,0 +1,207 @@ +import type { AgentExactRunControlRef } from '@tangle-network/agent-interface' +import type { + RetainedInteractiveAdmission, + RetainedInteractiveAdmissionHook, + RetainedInteractiveStartedAdmission, +} from '@tangle-network/agent-runtime/kernel' +import { canonicalDigest } from '../../domain/canonical.js' +import { publicMaterializationReceipt } from '../../domain/materialization-receipt.js' +import type { RunAdmissionReceipt } from '../../domain/receipts.js' +import type { RetainedRunAdmissionRecord } from '../../domain/run-contracts.js' +import type { + ExecutionPort, + RetainedRunAdmissionRecorder, + RunCapabilities, +} from '../../ports/execution.js' +import { stableProviderId } from './production-backend-common.js' +import type { PreparedTangleRetainedConnection } from './production-tangle-sandbox-backend.js' + +type StatusInput = Parameters>[0] +type ReconnectInput = Parameters>[0] + +export type TangleInteractiveRecoveryInput = StatusInput & + Partial> + +export function assertInteractiveProvider(prepared: PreparedTangleRetainedConnection): void { + const interactive = prepared.capabilities.interactiveAgent + if ( + interactive?.start !== true || + interactive.control !== true || + interactive.status !== true || + interactive.attach !== true || + interactive.reattach !== true || + interactive.sendPrompt !== true || + interactive.input !== true || + interactive.resize !== true || + interactive.stop !== true + ) { + throw new Error('Tangle retained connection does not support exact interactive agents') + } +} + +export function interactiveRunCapabilities( + prepared: PreparedTangleRetainedConnection, +): RunCapabilities { + const { interactions: _interactions, ...environment } = prepared.capabilities + return Object.freeze({ + streaming: { live: true, replay: true, detach: true, turnIdempotency: true }, + sessions: { continue: true, messages: false }, + controls: { cancel: true, steer: false, queue: false, status: true, recreate: true }, + events: { stableIdentity: true, sequence: true, cursor: true }, + usage: false, + environment, + }) +} + +export function interactiveMaterializationReceipt( + prepared: PreparedTangleRetainedConnection, +): Readonly> { + return publicMaterializationReceipt({ + provider: prepared.provider.name, + backend: 'environment-provider', + surface: 'interactive-agent', + lifecycle: 'retained', + execution: 'agent-runtime-retained-interactive', + cleanup: 'explicit', + continuity: 'session', + idleTtlSeconds: prepared.idleTtlSeconds, + model: prepared.model, + runner: prepared.runner, + }) +} + +export function interactiveEnvironment( + prepared: PreparedTangleRetainedConnection, + runId: string, + idempotencyKey = interactiveEnvironmentIdempotencyKey(runId), + profile = prepared.profile, +) { + return { + profile, + backend: prepared.runner, + name: stableProviderId('braid-interactive-', runId), + metadata: { + owner: 'braid', + lifecycle: 'retained', + surface: 'interactive-agent', + }, + idempotencyKey, + } +} + +export function interactiveIdempotencyKey(runId: string): string { + return stableProviderId('interactive-braid-', runId) +} + +function interactiveEnvironmentIdempotencyKey(runId: string): string { + return stableProviderId('env-braid-interactive-', runId) +} + +export function requireAdmissionRecorder( + recorder: RetainedRunAdmissionRecorder | undefined, +): RetainedInteractiveAdmissionHook { + if (recorder === undefined) { + throw new Error('Retained Tangle interactive execution requires a durable admission recorder') + } + return (admission) => recorder(admission) +} + +export function requireRecoveryReceipt( + input: RunAdmissionReceipt | undefined, +): RunAdmissionReceipt { + if (input === undefined) { + throw new Error('Interactive intent recovery requires the original run receipt') + } + return input +} + +export function requireInteractiveAdmission( + value: RetainedRunAdmissionRecord | undefined, +): RetainedInteractiveAdmission { + switch (value?.phase) { + case 'interactive_intent': + case 'interactive_environment': + case 'interactive_started': + return value + default: + throw new Error('Interactive recovery requires a canonical interactive admission') + } +} + +export function interactiveAdmissionOrUndefined( + value: RetainedRunAdmissionRecord | undefined, +): RetainedInteractiveAdmission | undefined { + if (value === undefined) return undefined + return requireInteractiveAdmission(value) +} + +export function interactiveSessionId(admission: RetainedInteractiveAdmission): string | undefined { + if (admission.phase === 'interactive_intent') return admission.sessionId + return admission.phase === 'interactive_environment' + ? admission.request.run.sessionId + : admission.ref.run.sessionId +} + +export function assertInteractiveAdmissionMatchesInput( + admission: RetainedInteractiveAdmission, + input: Pick, +): void { + if (admission.phase === 'interactive_started') { + assertStartedAdmissionMatchesInput(admission, input) + return + } + const sessionId = interactiveSessionId(admission) + if (input.providerSessionId !== undefined && input.providerSessionId !== sessionId) { + throw new Error('Interactive provider session conflicts with the saved admission') + } + if (input.controlRef !== undefined) { + throw new Error('Interactive control reference conflicts with the saved admission') + } +} + +export function assertStartedAdmissionMatchesInput( + admission: RetainedInteractiveStartedAdmission, + input: Pick, +): void { + if ( + input.providerSessionId !== undefined && + input.providerSessionId !== admission.ref.run.sessionId + ) { + throw new Error('Interactive provider session conflicts with the saved process reference') + } + if ( + input.controlRef !== undefined && + canonicalDigest(input.controlRef) !== canonicalDigest(admission.ref.run) + ) { + throw new Error('Interactive control reference conflicts with the saved process reference') + } +} + +export function assertExactControl( + input: { + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + }, + actual: AgentExactRunControlRef | undefined, +): void { + if ( + (input.providerSessionId !== undefined || input.controlRef !== undefined) && + actual === undefined + ) { + throw new Error('Interactive exact control reference is unavailable') + } + if ( + input.providerSessionId !== undefined && + actual !== undefined && + input.providerSessionId !== actual.sessionId + ) { + throw new Error('Interactive provider session conflicts with the saved run') + } + if ( + input.controlRef !== undefined && + actual !== undefined && + canonicalDigest(input.controlRef) !== canonicalDigest(actual) + ) { + throw new Error('Interactive control reference conflicts with the saved run') + } +} diff --git a/src/adapters/runtime/tangle-retained-interactive-execution.ts b/src/adapters/runtime/tangle-retained-interactive-execution.ts index 1a30481..30c4cb5 100644 --- a/src/adapters/runtime/tangle-retained-interactive-execution.ts +++ b/src/adapters/runtime/tangle-retained-interactive-execution.ts @@ -1,17 +1,11 @@ -import type { - AgentExactRunControlRef, - AgentInteractiveSessionStatus, - AgentProfile, -} from '@tangle-network/agent-interface' +import type { AgentExactRunControlRef, AgentProfile } from '@tangle-network/agent-interface' import { agentInteractiveSessionStopRequestDigest, canonicalCandidateDigest, } from '@tangle-network/agent-interface' import type { RetainedInteractiveAdmission, - RetainedInteractiveAdmissionHook, RetainedInteractiveRunHandle, - RetainedInteractiveStartedAdmission, } from '@tangle-network/agent-runtime/kernel' import { claimRetainedInteractiveControl, @@ -20,9 +14,7 @@ import { startRetainedInteractiveRun, } from '@tangle-network/agent-runtime/kernel' import { canonicalDigest } from '../../domain/canonical.js' -import { publicMaterializationReceipt } from '../../domain/materialization-receipt.js' import type { RuntimeEventEnvelope } from '../../domain/runtime-events.js' -import type { RunAdmissionReceipt } from '../../domain/receipts.js' import type { CancelRunInput, ControlAcknowledgement, @@ -32,21 +24,35 @@ import type { ProviderRunSnapshot, RunCapabilities, } from '../../ports/execution.js' -import type { NativeInteractiveRunOutcome } from '../../ports/native-interactive-execution.js' -import type { NativeInteractiveRunBroker } from './native-interactive-run-broker.js' import { canonicalAgentProfileDigestHex } from '../agent-interface/profile-runtime.js' +import type { NativeInteractiveRunBroker } from './native-interactive-run-broker.js' import { safeExecutionId } from './production-backend-common.js' import type { PreparedTangleRetainedConnection } from './production-tangle-sandbox-backend.js' - -type StatusInput = Parameters>[0] -type RecoveryInput = Omit & { - readonly after?: string - readonly afterSequence?: number - readonly retainedAdmission?: unknown - readonly receipt?: RunAdmissionReceipt - readonly workspaceRoot?: string - readonly onRetainedAdmission?: unknown -} +import { retainedExecutionKey } from './retained-execution-state.js' +import { + assertExactControl, + assertInteractiveAdmissionMatchesInput, + assertInteractiveProvider, + assertStartedAdmissionMatchesInput, + interactiveAdmissionOrUndefined, + interactiveEnvironment, + interactiveIdempotencyKey, + interactiveMaterializationReceipt, + interactiveRunCapabilities, + requireAdmissionRecorder, + requireInteractiveAdmission, + requireRecoveryReceipt, + type TangleInteractiveRecoveryInput, +} from './tangle-retained-interactive-contract.js' +import { + interactiveStatus, + interactiveStatusDetail, + observedEnvelope, + partialInteractiveStatus, + replayBoundary, + terminalEnvelope, + terminalOutcome, +} from './tangle-retained-interactive-projection.js' export interface TangleRetainedInteractiveExecutionOptions { readonly resolve: (input: ExecuteTurnInput) => Promise @@ -55,6 +61,11 @@ export interface TangleRetainedInteractiveExecutionOptions { readonly holderId?: string } +interface PreparedInteractiveConnection { + readonly key: string + readonly prepared: PreparedTangleRetainedConnection +} + /** Runs one exact Tangle coding-agent TUI through Runtime's durable APIs. */ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { readonly admissionMode = 'async' as const @@ -62,7 +73,8 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { readonly #recover: TangleRetainedInteractiveExecutionOptions['recover'] readonly #broker: Pick readonly #holderId: string - readonly #prepared = new Map() + readonly #prepared = new Map() + readonly #starting = new Map>() readonly #handles = new Map() readonly #activeRuns = new Set() readonly #detachRequested = new Set() @@ -76,12 +88,10 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { } capabilities = (input: ExecuteTurnInput): RunCapabilities | Promise => - this.#resolve(input).then((prepared) => interactiveRunCapabilities(prepared)) + this.#prepare(input).then((prepared) => interactiveRunCapabilities(prepared)) async admit(input: ExecuteTurnInput): Promise { - const prepared = await this.#resolve(input) - assertInteractiveProvider(prepared) - this.#prepared.set(input.runId, prepared) + const prepared = await this.#prepare(input) const capabilities = interactiveRunCapabilities(prepared) const materializationReceipt = interactiveMaterializationReceipt(prepared) return { @@ -95,13 +105,14 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { } async *streamTurn(input: ExecuteTurnInput): AsyncIterable { - const prepared = this.#prepared.get(input.runId) ?? (await this.#resolve(input)) - assertInteractiveProvider(prepared) + if (this.#cancelledRuns.has(input.runId)) return + const prepared = await this.#prepare(input) + if (this.#cancelledRuns.has(input.runId)) return const lease = this.#broker.open(input.runId) this.#activeRuns.add(input.runId) let terminal = false try { - const handle = this.#handles.get(input.runId) ?? (await this.#start(prepared, input)) + const handle = this.#handles.get(input.runId) ?? (await this.#startOnce(prepared, input)) this.#rememberHandle(input.runId, handle) lease.publish(handle) if (this.#detachRequested.has(input.runId)) this.#settleDetached(input.runId) @@ -142,8 +153,9 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { } } - async *reconnect(input: RecoveryInput): AsyncIterable { + async *reconnect(input: TangleInteractiveRecoveryInput): AsyncIterable { const admission = requireInteractiveAdmission(input.retainedAdmission) + assertInteractiveAdmissionMatchesInput(admission, input) const prepared = await this.#resolveRecovery(input, admission) assertInteractiveProvider(prepared) const lease = this.#broker.open(input.runId) @@ -199,8 +211,9 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { } } - async status(input: RecoveryInput): Promise { + async status(input: TangleInteractiveRecoveryInput): Promise { const partial = interactiveAdmissionOrUndefined(input.retainedAdmission) + if (partial !== undefined) assertInteractiveAdmissionMatchesInput(partial, input) if ( this.#handles.get(input.runId) === undefined && partial !== undefined && @@ -224,15 +237,35 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { } } - async detachRun(input: { - readonly runId: string - readonly operationId: string - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - readonly cursor?: string - readonly signal?: AbortSignal - }): Promise { - this.#assertControl(input.runId, input.providerSessionId, input.controlRef) + async detachRun( + input: { + readonly runId: string + readonly operationId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly cursor?: string + readonly signal?: AbortSignal + } & TangleInteractiveRecoveryInput, + ): Promise { + const admission = interactiveAdmissionOrUndefined(input.retainedAdmission) + if (admission !== undefined) assertInteractiveAdmissionMatchesInput(admission, input) + let handle = this.#handles.get(input.runId) + if ( + handle === undefined && + !this.#prepared.has(input.runId) && + !this.#starting.has(input.runId) && + admission !== undefined && + admission.phase !== 'interactive_started' + ) { + this.#detachRequested.add(input.runId) + return { operationId: input.operationId, outcome: 'accepted', detail: 'detached' } + } + if (handle === undefined && !this.#prepared.has(input.runId)) { + handle = (await this.#handleFor(input)) ?? undefined + } else if (handle === undefined && this.#starting.has(input.runId)) { + handle = (await this.#handleFor(input)) ?? undefined + } + this.#assertControl(input.runId, input.providerSessionId, input.controlRef, handle?.ref.run) if (this.#detachRequested.has(input.runId)) { return { operationId: input.operationId, outcome: 'already-applied', detail: 'detached' } } @@ -244,7 +277,85 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { async cancelRun( input: CancelRunInput & { readonly signal?: AbortSignal }, ): Promise { - const handle = this.#handles.get(input.runId) + if (this.#cancelledRuns.has(input.runId) && !this.#activeRuns.has(input.runId)) { + return { operationId: input.operationId, outcome: 'already-applied', detail: 'cancelled' } + } + const startInFlight = this.#starting.has(input.runId) + const controlSignal = startInFlight || input.signal?.aborted ? undefined : input.signal + const { signal: _foregroundSignal, ...recoveryInputBase } = input + const recoveryInput = { + ...recoveryInputBase, + ...(controlSignal === undefined ? {} : { signal: controlSignal }), + } + let handle = this.#handles.get(input.runId) + const admissionPhase = input.retainedAdmission?.phase + const interactiveIntent = + input.retainedAdmission?.phase === 'interactive_intent' ? input.retainedAdmission : undefined + if ( + handle === undefined && + !this.#starting.has(input.runId) && + interactiveIntent !== undefined && + input.controlRef === undefined + ) { + if ( + input.providerSessionId !== undefined && + input.providerSessionId !== interactiveIntent.sessionId + ) { + return { + operationId: input.operationId, + outcome: 'rejected', + detail: 'interactive-intent-provider-session-mismatch', + } + } + this.#cancelledRuns.add(input.runId) + this.#prepared.delete(input.runId) + this.#settleCancelled(input.runId) + return { + operationId: input.operationId, + outcome: 'accepted', + detail: 'cancelled-before-start', + } + } + if ( + handle === undefined && + this.#prepared.has(input.runId) && + !this.#starting.has(input.runId) && + input.providerSessionId === undefined && + input.controlRef === undefined && + admissionPhase !== 'interactive_started' + ) { + this.#cancelledRuns.add(input.runId) + this.#prepared.delete(input.runId) + this.#settleCancelled(input.runId) + return { + operationId: input.operationId, + outcome: 'accepted', + detail: 'cancelled-before-start', + } + } + if (handle === undefined && this.#starting.has(input.runId)) { + this.#cancelledRuns.add(input.runId) + try { + handle = (await this.#handleFor(recoveryInput)) ?? undefined + } catch { + return { + operationId: input.operationId, + outcome: 'unknown', + detail: 'interactive-start-could-not-be-cancelled', + } + } + } + if (handle === undefined) { + try { + handle = (await this.#handleFor(recoveryInput)) ?? undefined + } catch { + return { + operationId: input.operationId, + outcome: 'unknown', + detail: 'interactive-run-missing', + } + } + } if (handle === undefined) { return { operationId: input.operationId, @@ -256,12 +367,12 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { const control = await claimRetainedInteractiveControl({ handle, holderId: this.#holderId, - ...(input.signal === undefined ? {} : { signal: input.signal }), + ...(controlSignal === undefined ? {} : { signal: controlSignal }), }) const material = { operationId: input.operationId, ref: handle.ref, control } const acknowledgement = await handle.stop( { ...material, requestDigest: agentInteractiveSessionStopRequestDigest(material) }, - input.signal === undefined ? undefined : { signal: input.signal }, + controlSignal === undefined ? undefined : { signal: controlSignal }, ) if (acknowledgement.status === 'accepted' || acknowledgement.status === 'replayed') { this.#cancelledRuns.add(input.runId) @@ -301,9 +412,43 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { }) } + async #startOnce( + prepared: PreparedTangleRetainedConnection, + input: ExecuteTurnInput, + ): Promise { + const current = this.#starting.get(input.runId) + if (current !== undefined) return current + const starting = this.#start(prepared, input) + this.#starting.set(input.runId, starting) + starting.then( + () => this.#clearStarting(input.runId, starting), + () => this.#clearStarting(input.runId, starting), + ) + return starting + } + + async #prepare(input: ExecuteTurnInput): Promise { + const current = this.#prepared.get(input.runId) + if (current !== undefined) { + if ( + current.key !== retainedExecutionKey(input, interactiveRunCapabilities(current.prepared)) + ) { + throw new Error('Interactive run admission received a different request') + } + return current.prepared + } + const prepared = await this.#resolve(input) + assertInteractiveProvider(prepared) + this.#prepared.set(input.runId, { + key: retainedExecutionKey(input, interactiveRunCapabilities(prepared)), + prepared, + }) + return prepared + } + async #recoverHandle( prepared: PreparedTangleRetainedConnection, - input: RecoveryInput, + input: TangleInteractiveRecoveryInput, admission: RetainedInteractiveAdmission, ): Promise { if (admission.phase === 'interactive_started') { @@ -344,12 +489,25 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { }) } - async #handleFor(input: RecoveryInput): Promise { + async #handleFor( + input: TangleInteractiveRecoveryInput, + ): Promise { + const admissionForInput = interactiveAdmissionOrUndefined(input.retainedAdmission) + if (admissionForInput !== undefined) { + assertInteractiveAdmissionMatchesInput(admissionForInput, input) + } const active = this.#handles.get(input.runId) if (active !== undefined) { this.#assertControl(input.runId, input.providerSessionId, input.controlRef, active.ref.run) return active } + const starting = this.#starting.get(input.runId) + if (starting !== undefined) { + const handle = await starting + this.#rememberHandle(input.runId, handle) + this.#assertControl(input.runId, input.providerSessionId, input.controlRef, handle.ref.run) + return handle + } const admission = requireInteractiveAdmission(input.retainedAdmission) const prepared = await this.#resolveRecovery(input, admission) assertInteractiveProvider(prepared) @@ -359,7 +517,7 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { } async #resolveRecovery( - input: RecoveryInput, + input: TangleInteractiveRecoveryInput, admission: RetainedInteractiveAdmission, ): Promise { const receipt = input.receipt @@ -401,6 +559,10 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { this.#handles.set(runId, handle) } + #clearStarting(runId: string, starting: Promise): void { + if (this.#starting.get(runId) === starting) this.#starting.delete(runId) + } + #assertControl( runId: string, providerSessionId?: string, @@ -408,20 +570,13 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { expected?: AgentExactRunControlRef, ): void { const actual = expected ?? this.#handles.get(runId)?.ref.run - if ( - providerSessionId !== undefined && - actual !== undefined && - providerSessionId !== actual.sessionId - ) { - throw new Error('Interactive provider session conflicts with the saved run') - } - if ( - controlRef !== undefined && - actual !== undefined && - canonicalDigest(controlRef) !== canonicalDigest(actual) - ) { - throw new Error('Interactive control reference conflicts with the saved run') - } + assertExactControl( + { + ...(providerSessionId === undefined ? {} : { providerSessionId }), + ...(controlRef === undefined ? {} : { controlRef }), + }, + actual, + ) } #settleDetached(runId: string): void { @@ -446,272 +601,7 @@ export class TangleRetainedInteractiveExecutionPort implements ExecutionPort { #forgetHandle(runId: string): void { this.#handles.delete(runId) + this.#prepared.delete(runId) if (!this.#activeRuns.has(runId)) this.#cancelledRuns.delete(runId) } } - -function assertInteractiveProvider(prepared: PreparedTangleRetainedConnection): void { - const interactive = prepared.capabilities.interactiveAgent - if ( - interactive?.start !== true || - interactive.control !== true || - interactive.status !== true || - interactive.attach !== true || - interactive.reattach !== true || - interactive.stop !== true - ) { - throw new Error('Tangle retained connection does not support exact interactive agents') - } -} - -function interactiveRunCapabilities(prepared: PreparedTangleRetainedConnection): RunCapabilities { - return Object.freeze({ - streaming: { live: true, replay: true, detach: true, turnIdempotency: true }, - sessions: { continue: true, messages: false }, - controls: { cancel: true, steer: false, queue: false, status: true, recreate: true }, - events: { stableIdentity: true, sequence: true, cursor: true }, - usage: false, - environment: prepared.capabilities, - }) -} - -function interactiveMaterializationReceipt( - prepared: PreparedTangleRetainedConnection, -): Readonly> { - return publicMaterializationReceipt({ - provider: prepared.provider.name, - backend: 'environment-provider', - surface: 'interactive-agent', - lifecycle: 'retained', - execution: 'agent-runtime-retained-interactive', - cleanup: 'explicit', - continuity: 'session', - idleTtlSeconds: prepared.idleTtlSeconds, - model: prepared.model, - runner: prepared.runner, - }) -} - -function interactiveEnvironment( - prepared: PreparedTangleRetainedConnection, - _runId: string, - idempotencyKey = interactiveEnvironmentIdempotencyKey(_runId), - profile = prepared.profile, -) { - return { - profile, - backend: prepared.runner, - name: `braid-interactive-${safeExecutionId(_runId)}`, - metadata: { - owner: 'braid', - lifecycle: 'retained', - surface: 'interactive-agent', - }, - idempotencyKey, - } -} - -function interactiveIdempotencyKey(runId: string): string { - return `interactive-braid-${safeExecutionId(runId)}`.slice(0, 128) -} - -function interactiveEnvironmentIdempotencyKey(runId: string): string { - return `env-braid-interactive-${safeExecutionId(runId)}`.slice(0, 128) -} - -function requireAdmissionRecorder(recorder: unknown): RetainedInteractiveAdmissionHook { - if (typeof recorder !== 'function') { - throw new Error('Retained Tangle interactive execution requires a durable admission recorder') - } - return (admission) => - (recorder as (value: RetainedInteractiveAdmission) => Promise)(admission) -} - -function requireRecoveryReceipt(input: RunAdmissionReceipt | undefined): RunAdmissionReceipt { - if (input === undefined) - throw new Error('Interactive intent recovery requires the original run receipt') - return input -} - -function requireInteractiveAdmission(value: unknown): RetainedInteractiveAdmission { - if (value === undefined || typeof value !== 'object' || value === null || !('phase' in value)) { - throw new Error('Interactive recovery requires a canonical interactive admission') - } - const phase = (value as { readonly phase?: unknown }).phase - if (typeof phase !== 'string' || !phase.startsWith('interactive_')) { - throw new Error('Interactive recovery requires a canonical interactive admission') - } - return value as RetainedInteractiveAdmission -} - -function interactiveAdmissionOrUndefined(value: unknown): RetainedInteractiveAdmission | undefined { - if (value === undefined) return undefined - return requireInteractiveAdmission(value) -} - -function partialInteractiveStatus( - runId: string, - admission: Exclude, -): ProviderRunSnapshot { - const sessionId = interactiveSessionId(admission) - return sessionId === undefined - ? { runId, status: 'unknown', detail: `replayable:${admission.phase}` } - : { runId, status: 'unknown', sessionId, detail: `replayable:${admission.phase}` } -} - -function interactiveStatusDetail(status: AgentInteractiveSessionStatus): string { - if (status.state === 'unknown') return status.message - if (!('reason' in status)) return 'interactive session running' - return !('exitCode' in status) || status.exitCode === undefined - ? `interactive session ${status.reason}` - : `interactive session ${status.reason} with code ${status.exitCode}` -} - -function interactiveSessionId(admission: RetainedInteractiveAdmission): string | undefined { - if (admission.phase === 'interactive_intent') return admission.sessionId - return admission.phase === 'interactive_environment' - ? admission.request.run.sessionId - : admission.ref.run.sessionId -} - -function assertStartedAdmissionMatchesInput( - admission: RetainedInteractiveStartedAdmission, - input: RecoveryInput, -): void { - if ( - input.providerSessionId !== undefined && - input.providerSessionId !== admission.ref.run.sessionId - ) { - throw new Error('Interactive provider session conflicts with the saved process reference') - } - if ( - input.controlRef !== undefined && - canonicalDigest(input.controlRef) !== canonicalDigest(admission.ref.run) - ) { - throw new Error('Interactive control reference conflicts with the saved process reference') - } -} - -function interactiveStatus( - status: AgentInteractiveSessionStatus, - detached: boolean, -): ProviderRunSnapshot['status'] { - if (detached && status.state === 'running') return 'detached' - if (status.state === 'running') return 'streaming' - if (status.state === 'exited' && status.reason !== 'lost') return 'completed' - return 'unknown' -} - -async function terminalOutcome( - handle: RetainedInteractiveRunHandle, - signal?: AbortSignal, -): Promise | undefined> { - const status = await handle.status(signal === undefined ? undefined : { signal }) - if (status.state !== 'exited') return undefined - return { - kind: 'exited', - ...(status.exitCode === undefined ? {} : { exitCode: status.exitCode }), - ...(status.exitSignal === undefined ? {} : { exitSignal: status.exitSignal }), - } -} - -function replayBoundary( - input: RecoveryInput, - runId: string, - handle: RetainedInteractiveRunHandle, -): number { - const cursorSequence = - input.after === undefined - ? undefined - : sequenceFromCursor(input.after, runId, handle.ref.incarnationId) - if ( - cursorSequence !== undefined && - input.afterSequence !== undefined && - cursorSequence !== input.afterSequence - ) { - throw new Error('Interactive replay cursor conflicts with the saved sequence') - } - return input.afterSequence ?? cursorSequence ?? 0 -} - -function sequenceFromCursor(cursor: string, runId: string, incarnationId: string): number { - const prefix = `${runId}:interactive:${incarnationId}:` - if (!cursor.startsWith(prefix)) { - throw new Error('Interactive replay cursor belongs to another process') - } - const sequence = Number(cursor.slice(prefix.length)) - if (!Number.isSafeInteger(sequence) || sequence < 0) { - throw new Error('Interactive replay cursor is malformed') - } - return sequence -} - -async function observedEnvelope( - runId: string, - handle: RetainedInteractiveRunHandle, - prepared: PreparedTangleRetainedConnection, - sequence: number, -): Promise { - const observation = await prepared.observation.snapshot() - if (observation === undefined) throw new Error('Tangle interactive observation is unavailable') - const receivedAt = new Date().toISOString() - return { - runId, - eventId: `${runId}:interactive:${handle.ref.incarnationId}:observed`, - sequence, - cursor: interactiveCursor(runId, handle, sequence), - occurredAt: receivedAt, - receivedAt, - event: { - type: 'braid.execution.observed', - observation, - controlRef: handle.ref.run, - timestamp: receivedAt, - }, - } -} - -function terminalEnvelope( - runId: string, - handle: RetainedInteractiveRunHandle, - prepared: PreparedTangleRetainedConnection, - outcome: Exclude, - sequence: number, - cancelled: boolean, -): RuntimeEventEnvelope { - const timestamp = new Date().toISOString() - const failed = outcome.kind === 'failed' - const reason = cancelled - ? 'Interactive agent stopped' - : failed - ? outcome.message - : outcome.exitCode === undefined - ? 'Interactive agent exited' - : `Interactive agent exited with code ${outcome.exitCode}` - return { - runId, - eventId: `${runId}:interactive:${handle.ref.incarnationId}:final`, - sequence, - cursor: interactiveCursor(runId, handle, sequence), - occurredAt: timestamp, - receivedAt: timestamp, - event: { - type: 'final', - task: { id: runId, intent: 'Run the retained Tangle interactive agent' }, - status: cancelled ? 'cancelled' : failed ? 'failed' : 'completed', - reason, - text: '', - metadata: { model: prepared.model, tokensKnown: false, usdKnown: false }, - ...(failed ? { error: { kind: 'backend', message: outcome.message } } : {}), - timestamp, - }, - } -} - -function interactiveCursor( - runId: string, - handle: RetainedInteractiveRunHandle, - sequence: number, -): string { - return `${runId}:interactive:${handle.ref.incarnationId}:${sequence}` -} diff --git a/src/adapters/runtime/tangle-retained-interactive-projection.ts b/src/adapters/runtime/tangle-retained-interactive-projection.ts new file mode 100644 index 0000000..ae904df --- /dev/null +++ b/src/adapters/runtime/tangle-retained-interactive-projection.ts @@ -0,0 +1,154 @@ +import type { AgentInteractiveSessionStatus } from '@tangle-network/agent-interface' +import type { + RetainedInteractiveAdmission, + RetainedInteractiveRunHandle, + RetainedInteractiveStartedAdmission, +} from '@tangle-network/agent-runtime/kernel' +import type { RuntimeEventEnvelope } from '../../domain/runtime-events.js' +import type { ProviderRunSnapshot } from '../../ports/execution.js' +import type { NativeInteractiveRunOutcome } from '../../ports/native-interactive-execution.js' +import type { PreparedTangleRetainedConnection } from './production-tangle-sandbox-backend.js' +import type { TangleInteractiveRecoveryInput } from './tangle-retained-interactive-contract.js' +import { interactiveSessionId } from './tangle-retained-interactive-contract.js' + +export function partialInteractiveStatus( + runId: string, + admission: Exclude, +): ProviderRunSnapshot { + const sessionId = interactiveSessionId(admission) + return sessionId === undefined + ? { runId, status: 'unknown', detail: `replayable:${admission.phase}` } + : { runId, status: 'unknown', sessionId, detail: `replayable:${admission.phase}` } +} + +export function interactiveStatusDetail(status: AgentInteractiveSessionStatus): string { + if (status.state === 'unknown') return status.message + if (!('reason' in status)) return 'interactive session running' + return !('exitCode' in status) || status.exitCode === undefined + ? `interactive session ${status.reason}` + : `interactive session ${status.reason} with code ${status.exitCode}` +} + +export function interactiveStatus( + status: AgentInteractiveSessionStatus, + detached: boolean, +): ProviderRunSnapshot['status'] { + if (detached && status.state === 'running') return 'detached' + if (status.state === 'running') return 'streaming' + if (status.state === 'exited' && status.reason !== 'lost') return 'completed' + return 'unknown' +} + +export async function terminalOutcome( + handle: RetainedInteractiveRunHandle, + signal?: AbortSignal, +): Promise | undefined> { + const status = await handle.status(signal === undefined ? undefined : { signal }) + if (status.state !== 'exited') return undefined + return { + kind: 'exited', + ...(status.exitCode === undefined ? {} : { exitCode: status.exitCode }), + ...(status.exitSignal === undefined ? {} : { exitSignal: status.exitSignal }), + } +} + +export function replayBoundary( + input: TangleInteractiveRecoveryInput, + runId: string, + handle: RetainedInteractiveRunHandle, +): number { + const cursorSequence = + input.after === undefined + ? undefined + : sequenceFromCursor(input.after, runId, handle.ref.incarnationId) + if ( + cursorSequence !== undefined && + input.afterSequence !== undefined && + cursorSequence !== input.afterSequence + ) { + throw new Error('Interactive replay cursor conflicts with the saved sequence') + } + return input.afterSequence ?? cursorSequence ?? 0 +} + +function sequenceFromCursor(cursor: string, runId: string, incarnationId: string): number { + const prefix = `${runId}:interactive:${incarnationId}:` + if (!cursor.startsWith(prefix)) { + throw new Error('Interactive replay cursor belongs to another process') + } + const sequence = Number(cursor.slice(prefix.length)) + if (!Number.isSafeInteger(sequence) || sequence < 0) { + throw new Error('Interactive replay cursor is malformed') + } + return sequence +} + +export async function observedEnvelope( + runId: string, + handle: RetainedInteractiveRunHandle, + prepared: PreparedTangleRetainedConnection, + sequence: number, +): Promise { + const observation = await prepared.observation.snapshot() + if (observation === undefined) throw new Error('Tangle interactive observation is unavailable') + const receivedAt = new Date().toISOString() + return { + runId, + eventId: `${runId}:interactive:${handle.ref.incarnationId}:observed`, + sequence, + cursor: interactiveCursor(runId, handle, sequence), + occurredAt: receivedAt, + receivedAt, + event: { + type: 'braid.execution.observed', + observation, + controlRef: handle.ref.run, + timestamp: receivedAt, + }, + } +} + +export function terminalEnvelope( + runId: string, + handle: RetainedInteractiveRunHandle, + prepared: PreparedTangleRetainedConnection, + outcome: Exclude, + sequence: number, + cancelled: boolean, +): RuntimeEventEnvelope { + const timestamp = new Date().toISOString() + const failed = outcome.kind === 'failed' + const reason = cancelled + ? 'Interactive agent stopped' + : failed + ? outcome.message + : outcome.exitCode === undefined + ? 'Interactive agent exited' + : `Interactive agent exited with code ${outcome.exitCode}` + return { + runId, + eventId: `${runId}:interactive:${handle.ref.incarnationId}:final`, + sequence, + cursor: interactiveCursor(runId, handle, sequence), + occurredAt: timestamp, + receivedAt: timestamp, + event: { + type: 'final', + task: { id: runId, intent: 'Run the retained Tangle interactive agent' }, + status: cancelled ? 'cancelled' : failed ? 'failed' : 'completed', + reason, + text: '', + metadata: { model: prepared.model, tokensKnown: false, usdKnown: false }, + ...(failed ? { error: { kind: 'backend', message: outcome.message } } : {}), + timestamp, + }, + } +} + +function interactiveCursor( + runId: string, + handle: RetainedInteractiveRunHandle, + sequence: number, +): string { + return `${runId}:interactive:${handle.ref.incarnationId}:${sequence}` +} diff --git a/src/adapters/runtime/tangle-sandbox-retention.ts b/src/adapters/runtime/tangle-sandbox-retention.ts index e34698b..8379c32 100644 --- a/src/adapters/runtime/tangle-sandbox-retention.ts +++ b/src/adapters/runtime/tangle-sandbox-retention.ts @@ -5,7 +5,7 @@ import { MIN_RETAINED_IDLE_TTL_SECONDS, } from '../../domain/entities-core.js' import type { SandboxLifecyclePolicy } from './prepared-execution.js' -import { safeExecutionId } from './production-backend-common.js' +import { stableProviderId } from './production-backend-common.js' import type { ObservableSandboxClient } from './sandbox-observation-types.js' export { MAX_RETAINED_IDLE_TTL_SECONDS, MIN_RETAINED_IDLE_TTL_SECONDS } @@ -22,11 +22,10 @@ export interface RetainedSandboxIdentity { } export function retainedSandboxIdentity(providerSessionId: string): RetainedSandboxIdentity { - const suffix = safeExecutionId(providerSessionId) return Object.freeze({ providerSessionId, - environmentIdempotencyKey: `env-braid-${suffix}`, - name: `braid-${suffix}`, + environmentIdempotencyKey: stableProviderId('env-braid-', providerSessionId), + name: stableProviderId('braid-', providerSessionId), metadata: Object.freeze({ owner: 'braid', lifecycle: 'retained', providerSessionId }), }) } diff --git a/src/app/application-ports.ts b/src/app/application-ports.ts index 1807d2c..dd4a930 100644 --- a/src/app/application-ports.ts +++ b/src/app/application-ports.ts @@ -4,7 +4,11 @@ import type { RunAdmissionReceipt } from '../domain/receipts.js' import type { BraidRun, BraidState, RunStatus } from '../domain/state.js' import type { Clock } from '../ports/clock.js' import type { EffectRecord } from '../ports/effect-storage.js' -import type { ControlAcknowledgement, ExecutionPort } from '../ports/execution.js' +import type { + ControlAcknowledgement, + ExecutionPort, + RetainedExecutionRecoveryContext, +} from '../ports/execution.js' import type { IdSource } from '../ports/ids.js' import type { SendInput, SendReceipt } from './application-types.js' import type { RunExecutionSnapshot } from './run-execution-snapshot.js' @@ -157,6 +161,7 @@ export interface ControlEffectRequest { readonly reason?: string readonly text?: string readonly cursor?: string + readonly recovery?: RetainedExecutionRecoveryContext } export type RuntimeEventEnvelopeLike = import('../domain/runtime-events.js').RuntimeEventEnvelope diff --git a/src/app/composition.ts b/src/app/composition.ts index 3effb62..bbfbadc 100644 --- a/src/app/composition.ts +++ b/src/app/composition.ts @@ -1,5 +1,5 @@ -import type { AgentProfile } from '@tangle-network/agent-interface' import { performance } from 'node:perf_hooks' +import type { AgentProfile } from '@tangle-network/agent-interface' import { defineAgentProfile } from '../adapters/agent-interface/profile-runtime.js' import type { HeadlessKeySource } from '../adapters/credentials/headless-key.js' import { createOperatingSystemCredentialStore } from '../adapters/credentials/os.js' @@ -18,8 +18,10 @@ import { type CredentialPort, credentialRef } from '../ports/credentials.js' import type { EffectStoragePort, JournalPort } from '../ports/effect-storage.js' import type { ExecutionPort } from '../ports/execution.js' import { type IdSource, RandomIds, SequenceIds } from '../ports/ids.js' +import type { NativeInteractiveExecutionControl } from '../ports/native-interactive-execution.js' import { deterministicBackend } from '../testing/deterministic-backend.js' import { BraidApplication } from './application.js' +import type { ConnectionRegistry } from './connections.js' import type { SerializedEffectCoordinator } from './effect-coordinator.js' import { FailClosedJournal } from './fail-closed-journal.js' import type { IntelligenceActionsOptions } from './intelligence-actions.js' @@ -29,7 +31,6 @@ import { type ProductionCompositionConfig, ProductionCompositionError, } from './production-composition.js' -import type { ConnectionRegistry } from './connections.js' import { StorageJournal } from './storage-journal.js' import { UnavailableAnalyst } from './unavailable-analyst.js' @@ -97,6 +98,7 @@ export interface DurableStartupStage { export interface DurableBraidApplication { readonly app: BraidApplication readonly storage: SqliteStorage + readonly nativeInteractive?: NativeInteractiveExecutionControl } export type ProductionBraidApplicationOptions = Omit @@ -277,7 +279,13 @@ export async function createDurableBraidApplication( : { interactionResponseTimeoutMs: options.interactionResponseTimeoutMs }), }) reportStartupStage(options.startupObserver, 'application-create', stageStarted) - return { app, storage } + return { + app, + storage, + ...(production?.nativeInteractive === undefined + ? {} + : { nativeInteractive: production.nativeInteractive }), + } } catch (error) { await storage.close().catch(() => undefined) throw error diff --git a/src/app/control-effects.ts b/src/app/control-effects.ts index 16fd34e..52463b2 100644 --- a/src/app/control-effects.ts +++ b/src/app/control-effects.ts @@ -27,7 +27,7 @@ export async function executeControlEffect(input: { operationId: request.operationId, effectKind: `run.control.${request.control}`, request: { - ...request, + ...durableControlRequest(request), providerSessionId: request.providerSessionId ?? null, reason: request.reason ?? null, text: request.text ?? null, @@ -91,6 +91,7 @@ async function dispatchControl( ? {} : { providerSessionId: request.providerSessionId }), ...(request.controlRef === undefined ? {} : { controlRef: request.controlRef }), + ...(request.recovery ?? {}), signal, ...(request.reason === undefined ? {} : { reason: request.reason }), }), @@ -113,6 +114,7 @@ async function dispatchControl( ? {} : { providerSessionId: request.providerSessionId }), ...(request.controlRef === undefined ? {} : { controlRef: request.controlRef }), + ...(request.recovery ?? {}), signal, ...(request.cursor === undefined ? {} : { cursor: request.cursor }), }) @@ -134,6 +136,7 @@ async function reconcileControl( ? {} : { providerSessionId: request.providerSessionId }), ...(request.controlRef === undefined ? {} : { controlRef: request.controlRef }), + ...(request.recovery ?? {}), }) } catch { return undefined @@ -151,6 +154,13 @@ async function reconcileControl( return { status: 'terminal', detail: 'CONTROL_RECONCILED_TERMINAL' } } +function durableControlRequest( + request: ControlEffectRequest, +): Omit { + const { recovery: _recovery, ...durable } = request + return durable +} + function effectResult(value: ControlAcknowledgement) { if (value.outcome === 'accepted') return { diff --git a/src/app/interaction-controller.ts b/src/app/interaction-controller.ts index bef49ff..11e6624 100644 --- a/src/app/interaction-controller.ts +++ b/src/app/interaction-controller.ts @@ -24,6 +24,7 @@ import { recordedInteractionOwner, } from './interaction-response-replay.js' import type { RunLedger } from './run-ledger.js' +import { retainedExecutionRecoveryContext } from './run-recovery-context.js' import { findRun } from './run-status.js' export interface InteractionControllerInput { @@ -159,6 +160,7 @@ export async function respondInteraction( owner: input.owner, timeoutMs: input.responseTimeoutMs, whenDurable: input.whenDurable, + recovery: retainedExecutionRecoveryContext(run, input.state.currentState().workspace), }) const completion = effectCompletion.then(async (result) => { await input.commitAndWait({ diff --git a/src/app/interaction-effects.ts b/src/app/interaction-effects.ts index 05aeca2..58bbf3b 100644 --- a/src/app/interaction-effects.ts +++ b/src/app/interaction-effects.ts @@ -1,5 +1,9 @@ import type { InteractionResponseCommand } from '@tangle-network/agent-interface' -import type { ControlAcknowledgement, ExecutionPort } from '../ports/execution.js' +import type { + ControlAcknowledgement, + ExecutionPort, + RetainedExecutionRecoveryContext, +} from '../ports/execution.js' import type { SerializedEffectCoordinator } from './effect-coordinator.js' export type InteractionEffectRequest = InteractionResponseCommand @@ -11,6 +15,7 @@ export async function executeInteractionEffect(input: { readonly owner: string readonly timeoutMs: number readonly whenDurable: () => Promise + readonly recovery?: RetainedExecutionRecoveryContext }): Promise { const { request } = input const effect = input.effects.start( @@ -27,9 +32,10 @@ export async function executeInteractionEffect(input: { }, { dispatch: async () => { - return dispatchResponse(input.execution, request, input.timeoutMs) + return dispatchResponse(input.execution, request, input.timeoutMs, input.recovery) }, - reconcile: async () => dispatchResponse(input.execution, request, input.timeoutMs), + reconcile: async () => + dispatchResponse(input.execution, request, input.timeoutMs, input.recovery), }, ) const record = await effect.completion @@ -59,6 +65,7 @@ async function dispatchResponse( execution: ExecutionPort, request: InteractionEffectRequest, timeoutMs: number, + recovery?: RetainedExecutionRecoveryContext, ): Promise<{ readonly status: 'acknowledged' | 'failed' | 'unknown' readonly detail: string @@ -68,7 +75,11 @@ async function dispatchResponse( try { const controller = new AbortController() const result = await interactionResponseDeadline( - execution.respondInteraction({ command: request, signal: controller.signal }), + execution.respondInteraction({ + command: request, + signal: controller.signal, + ...(recovery === undefined ? {} : { recovery }), + }), controller, request.operationId, timeoutMs, diff --git a/src/app/production-composition.ts b/src/app/production-composition.ts index e4ee309..d0bdc0c 100644 --- a/src/app/production-composition.ts +++ b/src/app/production-composition.ts @@ -6,6 +6,8 @@ import { type AgentTurnBackendResolver, } from '../adapters/runtime/agent-runtime-execution.js' import { CliBridgeRetainedExecutionPort } from '../adapters/runtime/cli-bridge-retained-execution.js' +import { ModeRoutingExecutionPort } from '../adapters/runtime/mode-routing-execution.js' +import { NativeInteractiveRunBroker } from '../adapters/runtime/native-interactive-run-broker.js' import { createProductionBackendResolver, type ProductionBackendResolverOptions, @@ -13,8 +15,15 @@ import { resolveProductionTangleRetainedConnection, } from '../adapters/runtime/production-backend-resolver.js' import { TangleRetainedExecutionPort } from '../adapters/runtime/tangle-retained-execution.js' +import { TangleRetainedInteractiveExecutionPort } from '../adapters/runtime/tangle-retained-interactive-execution.js' import type { ConnectionRecord } from '../domain/entities.js' -import type { ExecutionPort } from '../ports/execution.js' +import type { + ExecuteTurnInput, + ExecutionPort, + RetainedExecutionRecoveryContext, + RetainedRunAdmissionRecord, +} from '../ports/execution.js' +import type { NativeInteractiveExecutionControl } from '../ports/native-interactive-execution.js' import { ConnectionError } from './connection-errors.js' import { ConnectionRegistry } from './connections.js' import { assertValidProfile } from './profile-validation.js' @@ -58,6 +67,7 @@ export interface ProductionComposition { readonly connections: ConnectionRegistry readonly connection: ConnectionRecord readonly execution: ExecutionPort + readonly nativeInteractive?: NativeInteractiveExecutionControl readonly backendResolver: AgentTurnBackendResolver } @@ -179,24 +189,38 @@ export function createProductionComposition( }), } const backendResolver = createProductionBackendResolver(resolverOptions) - const recoveryInput = (runId: string, providerSessionId?: string) => ({ - operationId: `recover-${runId}`, - runId, - text: '', - profile, - connectionId: connection.id, - ...(providerSessionId === undefined ? {} : { sessionId: providerSessionId }), - ...(config.workspaceRoot === undefined ? {} : { workspaceRoot: config.workspaceRoot }), - signal: new AbortController().signal, - }) + const recoveryInput = ( + runId: string, + providerSessionId: string | undefined, + recovery: RetainedExecutionRecoveryContext, + signal?: AbortSignal, + ): ExecuteTurnInput => { + const requested = recovery.receipt?.requested + const admissionSessionId = retainedAdmissionSessionId(recovery.retainedAdmission) + const sessionId = providerSessionId ?? admissionSessionId + const workspaceRoot = recovery.workspaceRoot ?? config.workspaceRoot + return { + operationId: recovery.receipt?.operationId ?? `recover-${runId}`, + runId, + text: requested?.text ?? '', + profile: requested?.profile ?? profile, + ...(requested?.mode === undefined ? {} : { mode: requested.mode }), + ...(requested?.interactions === undefined ? {} : { interactions: requested.interactions }), + connectionId: requested?.connectionId ?? connection.id, + ...(sessionId === undefined ? {} : { sessionId }), + ...(workspaceRoot === undefined ? {} : { workspaceRoot }), + signal: signal ?? new AbortController().signal, + } + } + let nativeInteractive: NativeInteractiveExecutionControl | undefined const execution = (() => { if (connection.kind === 'cli-bridge') { return new CliBridgeRetainedExecutionPort({ resolve: (input) => resolveProductionCliBridgeConnection(resolverOptions, input), - recover: ({ runId, providerSessionId }) => + recover: ({ runId, providerSessionId, signal, ...recovery }) => resolveProductionCliBridgeConnection( resolverOptions, - recoveryInput(runId, providerSessionId), + recoveryInput(runId, providerSessionId, recovery, signal), ), }) } @@ -204,14 +228,22 @@ export function createProductionComposition( connection.kind === 'tangle-sandbox' && connection.providerOptions.lifecycle === 'retained' ) { - return new TangleRetainedExecutionPort({ + const headless = new TangleRetainedExecutionPort({ resolve: (input) => resolveProductionTangleRetainedConnection(resolverOptions, input), - recover: ({ runId, providerSessionId }) => + recover: ({ runId, providerSessionId, signal, ...recovery }) => resolveProductionTangleRetainedConnection( resolverOptions, - recoveryInput(runId, providerSessionId), + recoveryInput(runId, providerSessionId, recovery, signal), ), }) + const broker = new NativeInteractiveRunBroker() + const interactive = new TangleRetainedInteractiveExecutionPort({ + resolve: (input) => resolveProductionTangleRetainedConnection(resolverOptions, input), + recover: (input) => resolveProductionTangleRetainedConnection(resolverOptions, input), + broker, + }) + nativeInteractive = broker + return new ModeRoutingExecutionPort({ headless, interactive }) } return new AgentRuntimeExecutionPort(backendResolver) })() @@ -221,6 +253,26 @@ export function createProductionComposition( connections, connection, execution, + ...(nativeInteractive === undefined ? {} : { nativeInteractive }), backendResolver, }) } + +function retainedAdmissionSessionId( + admission: RetainedRunAdmissionRecord | undefined, +): string | undefined { + switch (admission?.phase) { + case 'intent': + case 'environment': + case 'interactive_intent': + return admission.sessionId + case 'dispatched': + return admission.controlRef.sessionId + case 'interactive_environment': + return admission.request.run.sessionId + case 'interactive_started': + return admission.ref.run.sessionId + default: + return undefined + } +} diff --git a/src/app/run-admission-receipt.ts b/src/app/run-admission-receipt.ts index ae94228..2d6e382 100644 --- a/src/app/run-admission-receipt.ts +++ b/src/app/run-admission-receipt.ts @@ -5,6 +5,7 @@ import type { RunAdmissionReceipt, } from '../domain/receipts.js' import { createAdmissionReceipt } from '../domain/receipts.js' +import { requestedInteractionsForRun } from '../domain/run-interactions.js' import type { ExecuteTurnInput } from '../ports/execution.js' import { UNKNOWN_RUN_CAPABILITIES } from '../ports/execution.js' import type { AdmissionPort, AsyncAdmissionPort } from './application-ports.js' @@ -20,7 +21,6 @@ import { validateProfile, } from './run-admission-validation.js' import type { RunExecutionSnapshot } from './run-execution-snapshot.js' -import { requestedInteractionsForRun } from './run-interactions.js' export function admitRun( context: AdmissionPort, diff --git a/src/app/run-controls.ts b/src/app/run-controls.ts index dae8097..0f9ceda 100644 --- a/src/app/run-controls.ts +++ b/src/app/run-controls.ts @@ -5,6 +5,7 @@ import type { ControlAcknowledgement } from '../ports/execution.js' import type { ControlEffectRequest, ControlPort, QueuePort } from './application-ports.js' import type { ControlOperationRecord, ControlReceipt, QueueReceipt } from './application-types.js' import { AppError } from './errors.js' +import { retainedExecutionRecoveryContext } from './run-recovery-context.js' import { isTerminal } from './run-status.js' export function queueRunInput( @@ -89,6 +90,7 @@ export async function cancelRun( control: 'cancel', ...(run.providerSessionId === undefined ? {} : { providerSessionId: run.providerSessionId }), ...(run.controlRef === undefined ? {} : { controlRef: run.controlRef }), + recovery: retainedExecutionRecoveryContext(run, context.currentState().workspace), ...(input.reason === undefined ? {} : { reason: input.reason }), } const receipt = await control(context, request, 'cancel', input.terminalStatus ?? 'cancelled') @@ -113,6 +115,7 @@ export async function detachRun( ...(run.providerSessionId === undefined ? {} : { providerSessionId: run.providerSessionId }), ...(run.controlRef === undefined ? {} : { controlRef: run.controlRef }), ...(run.lastCursor === undefined ? {} : { cursor: run.lastCursor }), + recovery: retainedExecutionRecoveryContext(run, context.currentState().workspace), } return control(context, request, 'detach') } diff --git a/src/bin/braid-runtime.ts b/src/bin/braid-runtime.ts index 36be042..08e017e 100644 --- a/src/bin/braid-runtime.ts +++ b/src/bin/braid-runtime.ts @@ -34,6 +34,9 @@ export async function runBraid(options: CliOptions): Promise { app: opened.app, close: opened.close, ...(opened.connections === undefined ? {} : { connections: opened.connections }), + ...(opened.nativeInteractive === undefined + ? {} + : { nativeInteractive: opened.nativeInteractive }), }, } let startupPreview: StartupPreview | undefined @@ -76,6 +79,7 @@ async function openApplication( readonly app: BraidApplication readonly close: () => Promise readonly connections?: ConnectionRegistry + readonly nativeInteractive?: import('../ports/native-interactive-execution.js').NativeInteractiveExecutionControl readonly setup?: ProductionStartupSetup readonly startupOptions?: ProductionStartupLoadOptions readonly profileConnectionOptions?: ProfileConnectionDispatchOptions @@ -177,11 +181,7 @@ async function openApplication( async function openConfiguredApplication( startupOptions: ProductionStartupLoadOptions, production?: import('../app/production-composition.js').ProductionCompositionConfig, -): Promise<{ - readonly app: BraidApplication - readonly connections: ConnectionRegistry - readonly close: () => Promise -}> { +): ReturnType { const configured = production ?? (await loadProductionStartup(startupOptions)) const effectiveStartupOptions = startupOptions.databaseKeyFile === undefined && configured.databaseKeyFile !== undefined diff --git a/src/bin/native-interactive-actions.ts b/src/bin/native-interactive-actions.ts index 790b5b8..d8104a3 100644 --- a/src/bin/native-interactive-actions.ts +++ b/src/bin/native-interactive-actions.ts @@ -4,17 +4,17 @@ import { createNativeTerminalTransport } from '../adapters/tui/native-terminal-t import type { BraidApplication } from '../app/application.js' import type { BraidRun } from '../domain/state.js' import type { NativeInteractiveExecutionControl } from '../ports/native-interactive-execution.js' -import type { - NativeInteractiveAvailability, - NativeInteractiveCommand, - NativeInteractiveCommandResult, - NativeInteractiveUiActions, -} from '../ports/native-interactive-ui.js' import type { NativeTerminalHost, NativeTerminalSignalPort, NativeTerminalTransportResult, } from '../ports/native-terminal-transport.js' +import type { + NativeInteractiveAvailability, + NativeInteractiveCommand, + NativeInteractiveCommandResult, + NativeInteractiveUiActions, +} from '../views/shared/native-interactive-actions.js' interface InteractiveApplicationHandle { readonly app: Pick diff --git a/src/bin/production-application.ts b/src/bin/production-application.ts index 9133316..28afdb8 100644 --- a/src/bin/production-application.ts +++ b/src/bin/production-application.ts @@ -17,6 +17,7 @@ import { import { profileModelSettings } from '../app/profile-model-settings.js' import { canonicalDigest } from '../domain/canonical.js' import type { CredentialPort } from '../ports/credentials.js' +import type { NativeInteractiveExecutionControl } from '../ports/native-interactive-execution.js' import { createDurableBraidApplication } from '../startup/durable-runtime.js' import { createProductionCredentialContext, @@ -157,6 +158,7 @@ export async function openProductionApplication( ): Promise<{ readonly app: BraidApplication readonly connections: ConnectionRegistry + readonly nativeInteractive?: NativeInteractiveExecutionControl readonly close: () => Promise }> { const keyFile = options.startupOptions.databaseKeyFile ?? options.production.databaseKeyFile @@ -177,7 +179,7 @@ export async function openProductionApplication( const connections = new ConnectionRegistry(prepared.production.connections) try { const intelligence = await productionIntelligence(prepared.production) - const { app, storage } = await createDurableBraidApplication({ + const { app, storage, nativeInteractive } = await createDurableBraidApplication({ path: options.statePath, storageRoot: dirname(resolve(options.statePath)), workspaceRoot: resolve(options.workspace), @@ -200,6 +202,7 @@ export async function openProductionApplication( return { app, connections, + ...(nativeInteractive === undefined ? {} : { nativeInteractive }), close: async () => { try { await app.close() diff --git a/src/domain/run-contracts.ts b/src/domain/run-contracts.ts index db61798..488600e 100644 --- a/src/domain/run-contracts.ts +++ b/src/domain/run-contracts.ts @@ -1,6 +1,5 @@ import type { AgentEnvironmentCapabilities, - AgentExactRunControlRef, AgentProfile, RequestedInteractions, } from '@tangle-network/agent-interface' diff --git a/src/app/run-interactions.ts b/src/domain/run-interactions.ts similarity index 66% rename from src/app/run-interactions.ts rename to src/domain/run-interactions.ts index 65ee27f..e94e4df 100644 --- a/src/app/run-interactions.ts +++ b/src/domain/run-interactions.ts @@ -1,11 +1,6 @@ -import type { RequestedInteractions, RunCapabilities } from '../domain/run-contracts.js' +import type { RequestedInteractions, RunCapabilities } from './run-contracts.js' -/** - * Select the interaction posture for one admitted turn. - * - * The provider capability document is the only authority. A response is - * enabled only when the provider records idempotent responses for retries. - */ +/** Select the interaction posture for one admitted turn from provider capabilities. */ export function requestedInteractionsForRun( mode: string | undefined, capabilities: Pick, diff --git a/src/index.ts b/src/index.ts index be1ecd3..57da55f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,18 +1,34 @@ +export { + closeHeadlessKeyFile, + openHeadlessKeyFile, + readHeadlessKey, + rejectEnvironmentKeySource, +} from './adapters/credentials/headless-key.js' +export { MemoryCredentialStore } from './adapters/credentials/memory.js' +export { + createOperatingSystemCredentialStore, + LinuxSecretServiceCredentialStore, + MacOsKeychainCredentialStore, + WindowsCredentialManagerStore, +} from './adapters/credentials/os.js' export { AgentRuntimeExecutionPort, type AgentTurnBackendResolver, } from './adapters/runtime/agent-runtime-execution.js' +export { MemoryStorage } from './adapters/storage/memory.js' +export type { DurableBoundaryHook, SqliteStorageOptions } from './adapters/storage/sqlite.js' +export { + openSqliteStorage, + SqliteStorage, +} from './adapters/storage/sqlite.js' +export { SQLITE_DRIVER_PACKAGE, SQLITE_DRIVER_VERSION } from './adapters/storage/sqlite-driver.js' +export { StorageError } from './adapters/storage/sqlite-errors.js' +export { + ApplicationUiController, + buildBraidViewModel, + createApplicationUiController, +} from './adapters/tui/application-ui-controller.js' export { createNativeTerminalTransport } from './adapters/tui/native-terminal-transport.js' -export type { - NativeInteractiveAvailability, - NativeInteractiveCommand, - NativeInteractiveCommandResult, - NativeInteractiveUiActions, -} from './ports/native-interactive-ui.js' -export type { - NativeInteractiveExecutionControl, - NativeInteractiveRunOutcome, -} from './ports/native-interactive-execution.js' export { AppError, BraidApplication, @@ -20,56 +36,46 @@ export { type SendReceipt, } from './app/application.js' export { + type CompositionOptions, createBraidApplication, createDurableBraidApplication, - type CompositionOptions, type DurableBraidApplication, type DurableCompositionOptions, STARTER_PROFILE, } from './app/composition.js' -export { MemoryJournal } from './app/journal.js' export { + type EffectContext, EffectCoordinator, EffectCoordinatorError, - effectRequestDigest, - SerializedEffectCoordinator, - type EffectContext, type EffectDispatchResult, type EffectHandle, type EffectHandler, type EffectIntent, + effectRequestDigest, + SerializedEffectCoordinator, } from './app/effect-coordinator.js' -export type { - BraidEvent, - BraidEventEnvelope, - DomainBraidEventMap, - JournalEventEnvelope, - LegacyBraidEvent, - TurnUsage, -} from './domain/events.js' -export { - DuplicateEventConflictError, - initialDomainState, - reduceEvent, - replayEvents, - replayJournal, - SequenceGapError, -} from './domain/reducer.js' +export { FailClosedJournal } from './app/fail-closed-journal.js' +export { MemoryJournal } from './app/journal.js' +export { StorageJournal } from './app/storage-journal.js' export { canonicalDigest, canonicalJson, } from './domain/canonical.js' -export { canonicalProjectionChecksum } from './domain/projection-checksum.js' -export type { - BraidMessage, - BraidRun, - BraidState, -} from './domain/state.js' export type * from './domain/entities.js' export type { EffectRecord as DomainEffectRecord, OperationRecord as DomainOperationRecord, } from './domain/entities.js' +export type { + BraidEvent, + BraidEventEnvelope, + DomainBraidEventMap, + JournalEventEnvelope, + LegacyBraidEvent, + ProviderEventMeta, + RunTerminalStatus, + TurnUsage, +} from './domain/events.js' export * from './domain/ids.js' export { assertBraidState, @@ -77,64 +83,7 @@ export { assertJsonValue, DomainInvariantError, } from './domain/invariants.js' -export type { - EffectOutcomeStatus, - EffectRecord, - EffectStatus, - EffectStoragePort, - JournalPort, -} from './ports/effect-storage.js' -export type { - CredentialPort, - CredentialRef, - CredentialStoreInput, - SecretHandle, -} from './ports/credentials.js' -export { CredentialError, credentialRef } from './ports/credentials.js' -export type { - AppendResult, - BackupReport, - DestructionReport, - IntegrityReport, - JournalEvent, - MigrationReport, - MissingHistory, - OperationIntent, - OperationRecord, - ProjectionSnapshot, - RedactionReport, - ReplayResult, - RetentionReport, - StoragePort, - StorageArtifacts, - StoredJournalEvent, - RestoreReport, -} from './ports/storage.js' -export { MemoryStorage } from './adapters/storage/memory.js' -export { - SqliteStorage, - openSqliteStorage, -} from './adapters/storage/sqlite.js' -export type { DurableBoundaryHook, SqliteStorageOptions } from './adapters/storage/sqlite.js' -export { SQLITE_DRIVER_PACKAGE, SQLITE_DRIVER_VERSION } from './adapters/storage/sqlite-driver.js' -export { StorageError } from './adapters/storage/sqlite-errors.js' -export { MemoryCredentialStore } from './adapters/credentials/memory.js' -export { - createOperatingSystemCredentialStore, - LinuxSecretServiceCredentialStore, - MacOsKeychainCredentialStore, - WindowsCredentialManagerStore, -} from './adapters/credentials/os.js' -export { - closeHeadlessKeyFile, - openHeadlessKeyFile, - readHeadlessKey, - rejectEnvironmentKeySource, -} from './adapters/credentials/headless-key.js' -export type { - ProviderEventMeta, - RunTerminalStatus, -} from './domain/events.js' +export { canonicalProjectionChecksum } from './domain/projection-checksum.js' export { type ContextTransferReceipt, createAdmissionReceipt, @@ -145,6 +94,14 @@ export { type RunAdmissionReceipt, type RunCapabilities, } from './domain/receipts.js' +export { + DuplicateEventConflictError, + initialDomainState, + reduceEvent, + replayEvents, + replayJournal, + SequenceGapError, +} from './domain/reducer.js' export type { BraidRuntimeEvent, RuntimeEventEnvelope, @@ -153,9 +110,26 @@ export type { export type { BraidActivity, BraidInteraction, + BraidMessage, BraidMessagePart, + BraidRun, + BraidState, QueuedInput, } from './domain/state.js' +export type { + CredentialPort, + CredentialRef, + CredentialStoreInput, + SecretHandle, +} from './ports/credentials.js' +export { CredentialError, credentialRef } from './ports/credentials.js' +export type { + EffectOutcomeStatus, + EffectRecord, + EffectStatus, + EffectStoragePort, + JournalPort, +} from './ports/effect-storage.js' export type { ControlAcknowledgement, ExecuteTurnInput, @@ -163,6 +137,15 @@ export type { ExecutionPort, ProviderRunSnapshot, } from './ports/execution.js' +export { + capabilitiesFromEnvironment, + DEFAULT_RUN_CAPABILITIES, + UNKNOWN_RUN_CAPABILITIES, +} from './ports/execution.js' +export type { + NativeInteractiveExecutionControl, + NativeInteractiveRunOutcome, +} from './ports/native-interactive-execution.js' export type { NativeTerminalCleanup, NativeTerminalCleanupIssue, @@ -175,23 +158,30 @@ export type { NativeTerminalTransportPhase, NativeTerminalTransportResult, } from './ports/native-terminal-transport.js' -export { - capabilitiesFromEnvironment, - DEFAULT_RUN_CAPABILITIES, - UNKNOWN_RUN_CAPABILITIES, -} from './ports/execution.js' +export type { + AppendResult, + BackupReport, + DestructionReport, + IntegrityReport, + JournalEvent, + MigrationReport, + MissingHistory, + OperationIntent, + OperationRecord, + ProjectionSnapshot, + RedactionReport, + ReplayResult, + RestoreReport, + RetentionReport, + StorageArtifacts, + StoragePort, + StoredJournalEvent, +} from './ports/storage.js' export { BRAID_PROTOCOL_VERSION, type BraidRequest, type BraidResponse, } from './views/headless/protocol.js' -export { StorageJournal } from './app/storage-journal.js' -export { FailClosedJournal } from './app/fail-closed-journal.js' -export { - createApplicationUiController, - ApplicationUiController, - buildBraidViewModel, -} from './adapters/tui/application-ui-controller.js' export { COMMAND_DEFINITIONS, COMMAND_NAMES, @@ -217,6 +207,12 @@ export type { InteractionView, ViewStatus, } from './views/shared/models.js' +export type { + NativeInteractiveAvailability, + NativeInteractiveCommand, + NativeInteractiveCommandResult, + NativeInteractiveUiActions, +} from './views/shared/native-interactive-actions.js' export { sanitizeClipboardText, sanitizeDiff, diff --git a/src/ports/execution.ts b/src/ports/execution.ts index 2565fca..ecfd60f 100644 --- a/src/ports/execution.ts +++ b/src/ports/execution.ts @@ -75,7 +75,7 @@ export interface ControlAcknowledgement { readonly detail?: string } -export interface CancelRunInput { +export interface CancelRunInput extends RetainedExecutionRecoveryContext { readonly operationId: string readonly runId: string readonly providerSessionId?: string @@ -103,39 +103,46 @@ export interface ExecutionPort { cancelRun?( input: CancelRunInput & { readonly reason?: string; readonly signal?: AbortSignal }, ): Promise - detachRun?(input: { - readonly runId: string - readonly operationId: string - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - readonly cursor?: string - readonly signal?: AbortSignal - }): Promise + detachRun?( + input: { + readonly runId: string + readonly operationId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly cursor?: string + readonly signal?: AbortSignal + } & RetainedExecutionRecoveryContext, + ): Promise steerRun?(input: { readonly runId: string readonly operationId: string readonly text: string readonly signal?: AbortSignal }): Promise - status?(input: { - readonly runId: string - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - readonly signal?: AbortSignal - } & RetainedExecutionRecoveryContext): Promise + status?( + input: { + readonly runId: string + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly signal?: AbortSignal + } & RetainedExecutionRecoveryContext, + ): Promise respondInteraction?(input: { readonly command: InteractionResponseCommand readonly signal?: AbortSignal + readonly recovery?: RetainedExecutionRecoveryContext }): Promise - reconnect?(input: { - readonly runId: string - readonly after?: string - readonly afterSequence?: number - readonly providerSessionId?: string - readonly controlRef?: AgentExactRunControlRef - readonly signal: AbortSignal - readonly onRetainedAdmission?: RetainedRunAdmissionRecorder - } & RetainedExecutionRecoveryContext): AsyncIterable + reconnect?( + input: { + readonly runId: string + readonly after?: string + readonly afterSequence?: number + readonly providerSessionId?: string + readonly controlRef?: AgentExactRunControlRef + readonly signal: AbortSignal + readonly onRetainedAdmission?: RetainedRunAdmissionRecorder + } & RetainedExecutionRecoveryContext, + ): AsyncIterable nativeBoundary?(input: { readonly runId: string readonly sessionId: string diff --git a/src/ports/native-interactive-ui.ts b/src/views/shared/native-interactive-actions.ts similarity index 100% rename from src/ports/native-interactive-ui.ts rename to src/views/shared/native-interactive-actions.ts diff --git a/src/views/tui/activity-browser.ts b/src/views/tui/activity-browser.ts index 67dadf8..89ca610 100644 --- a/src/views/tui/activity-browser.ts +++ b/src/views/tui/activity-browser.ts @@ -8,8 +8,7 @@ import { type EntityBrowserDocument, type EntityBrowserRow, } from './entity-browser.js' -import { executionTargetFor, executionTargetForEntity } from './execution-target.js' -import { metricsFor } from './terminal-usage.js' +import { executionTargetFor } from './execution-target.js' import type { BraidTheme } from './theme.js' export type ActivityBrowserScope = 'all' | 'runs' | 'analyses' | 'workers' @@ -34,14 +33,13 @@ export class ActivityBrowserPanel extends EntityBrowser { constructor(theme: BraidTheme, options: ActivityBrowserOptions) { const scopeState: { scope: ActivityBrowserScope } = { scope: options.scope ?? 'all' } super(theme, { - document: (selectedId) => + document: () => activityDocument( options.view(), scopeState.scope, options.notice?.(), options.emptyMessage, options.pinned, - selectedId, ), rows: options.rows, onClose: options.onClose, @@ -68,7 +66,6 @@ export function activityDocument( notice?: string, emptyMessage?: string, pinned?: string, - selectedId?: string, ): EntityBrowserDocument { const details = new Map( (view.entityDetails ?? []).map((detail) => [detailKey(detail), detail] as const), @@ -78,17 +75,8 @@ export function activityDocument( .items.filter((item) => included(item, scope)) .slice() .reverse() - const selected = items.find((item) => item.id === selectedId) - const target = - selected?.runId !== undefined - ? executionTargetFor(view, selected.runId) - : selected?.source?.entityType !== undefined && selected.source.entityId !== undefined - ? executionTargetForEntity(view, selected.source.entityType, selected.source.entityId) - : executionTargetFor(view) - const usage = metricsFor(view) return { title: scope === 'all' ? 'activity' : scope, - context: [target.profileName, target.runner, target.model, ...usage].join(' · '), filterHint: `tab filter: ${scope}`, ...(pinned === undefined ? {} : { pinned }), ...(notice === undefined ? {} : { notice }), diff --git a/src/views/tui/profile-editor-rendering.ts b/src/views/tui/profile-editor-rendering.ts index 6a57dc9..55547e0 100644 --- a/src/views/tui/profile-editor-rendering.ts +++ b/src/views/tui/profile-editor-rendering.ts @@ -1,4 +1,4 @@ -import { type Component, Spacer, Text } from '@earendil-works/pi-tui' +import { type Component, Text } from '@earendil-works/pi-tui' import type { BraidViewModel } from '../shared/models.js' import { sanitizeTerminalText } from '../shared/sanitize.js' import { safeFieldValue } from './configuration-presenters.js' @@ -8,7 +8,7 @@ export function profileEditorChildren( theme: BraidTheme, view: BraidViewModel, ): readonly Component[] { - const children: Component[] = [new Text(theme.brand('profile'), 1, 0), new Spacer(1)] + const children: Component[] = [] const editor = view.profileEditor if (editor === undefined) { children.push(new Text(theme.muted('No profile details loaded.'), 1, 0)) diff --git a/src/views/tui/profile-editor.ts b/src/views/tui/profile-editor.ts index 3d5c69e..f02f646 100644 --- a/src/views/tui/profile-editor.ts +++ b/src/views/tui/profile-editor.ts @@ -14,6 +14,7 @@ import { within, } from './configuration-presenters.js' import { ResponsiveText } from './configuration-responsive-text.js' +import { focusedSurfaceLines } from './focused-surface.js' import { profileCompatibilityTextLines } from './profile-compatibility.js' import { profileErrorMessage, @@ -32,6 +33,7 @@ interface ProfileEditorOptions { readonly nextOperationId?: () => string readonly query?: string readonly onCancel?: () => void + readonly rows?: () => number } const PROFILE_REFRESH_TIMEOUT_MS = 2_000 @@ -41,9 +43,9 @@ export class ProfileEditorViewPanel extends Container implements Focusable { readonly #controller: BraidUiController | undefined readonly #nextOperationId: (() => string) | undefined readonly #onCancel: (() => void) | undefined + readonly #rows: () => number readonly #status = new ResponsiveText('', 1, 0) readonly #detail = new ResponsiveText('', 1, 0) - readonly #footer = new ResponsiveText('', 1, 0) #selector: SearchableSelector | undefined #profiles: readonly ProfileSummary[] = [] #focused = false @@ -57,6 +59,7 @@ export class ProfileEditorViewPanel extends Container implements Focusable { this.#controller = options.controller this.#nextOperationId = options.nextOperationId this.#onCancel = options.onCancel + this.#rows = options.rows ?? (() => 12) if (this.#controller !== undefined) { this.#buildSelector(options.query ?? '') void this.#refresh().catch((error: unknown) => { @@ -86,6 +89,18 @@ export class ProfileEditorViewPanel extends Container implements Focusable { this.#selector?.handleInput(data) } + override render(width: number): string[] { + return focusedSurfaceLines({ + theme: this.#theme, + title: 'profile', + body: super.render(width), + footer: profileEditorFooter(this.#controller !== undefined, this.#profiles.length, width), + width, + rows: this.#rows(), + preserveTailRows: 5, + }) + } + setView(view: BraidViewModel): void { if (this.#controller !== undefined) return this.clear() @@ -101,6 +116,7 @@ export class ProfileEditorViewPanel extends Container implements Focusable { query, maxVisible: 5, footer: 'enter select · ^V validate · ←/esc close', + embedded: true, theme: this.#theme, onSelect: (item) => void this.#select(item), onAction: (key, item) => { @@ -253,10 +269,6 @@ export class ProfileEditorViewPanel extends Container implements Focusable { this.addChild(this.#status) this.addChild(this.#detail) if (this.#selector && this.#profiles.length !== 1) this.addChild(this.#selector) - if (this.#profiles.length === 1) { - this.#footer.setText(this.#theme.muted('←/esc close')) - this.addChild(this.#footer) - } this.invalidate() } @@ -273,3 +285,9 @@ export class ProfileEditorViewPanel extends Container implements Focusable { this.#renderController() } } + +function profileEditorFooter(controller: boolean, profileCount: number, width: number): string { + if (!controller || profileCount === 1) return '←/esc close' + if (width < 60) return 'enter · ^V validate · ←/esc close' + return 'enter select · ^V validate · ←/esc close' +} diff --git a/src/views/tui/terminal-app.ts b/src/views/tui/terminal-app.ts index 5eaa17f..e3777b7 100644 --- a/src/views/tui/terminal-app.ts +++ b/src/views/tui/terminal-app.ts @@ -8,6 +8,7 @@ import type { UiFrameTiming, } from '../shared/intents.js' import type { BraidViewModel } from '../shared/models.js' +import type { NativeInteractiveUiActions } from '../shared/native-interactive-actions.js' import { sanitizeTitle } from '../shared/sanitize.js' import { GuardedAutocompleteProvider } from './autocomplete-guard.js' import type { TerminalConfigurationOptions } from './configuration-wizard.js' @@ -22,7 +23,6 @@ import { TerminalInteractionController } from './terminal-interaction-controller import { TerminalOverlayController } from './terminal-overlays.js' import { BraidShell } from './terminal-shell.js' import type { BraidTheme } from './theme.js' -import type { NativeInteractiveUiActions } from '../../ports/native-interactive-ui.js' export interface BraidTerminalOptions { readonly controller: BraidUiController diff --git a/src/views/tui/terminal-command-controller.ts b/src/views/tui/terminal-command-controller.ts index 851f5f9..06cf055 100644 --- a/src/views/tui/terminal-command-controller.ts +++ b/src/views/tui/terminal-command-controller.ts @@ -12,11 +12,11 @@ import { } from '../shared/command-registry.js' import type { BraidIntent, BraidUiController, UiDispatchResult } from '../shared/intents.js' import type { BraidViewModel } from '../shared/models.js' -import type { NativeInteractiveUiActions } from '../../ports/native-interactive-ui.js' +import type { NativeInteractiveUiActions } from '../shared/native-interactive-actions.js' +import type { ComposerMode } from './composer-view.js' import { executionTargetFor } from './execution-target.js' import type { TerminalDraftController } from './terminal-drafts.js' import type { TerminalOverlayController } from './terminal-overlays.js' -import type { ComposerMode } from './composer-view.js' export interface TerminalCommandControllerOptions { readonly controller: BraidUiController @@ -224,10 +224,14 @@ export class TerminalCommandController { ): Promise { const action = command === 'interactive' ? 'start' : 'attach' const actions = this.#nativeInteractive - const availability = actions?.availability(action) ?? { - available: false, - reason: 'Native terminal mode is unavailable in this interface', + if (actions === undefined) { + this.#overlays.openUnavailable( + `/${command}`, + 'Native terminal mode is unavailable in this interface', + ) + return } + const availability = actions.availability(action) if (!availability.available) { this.#overlays.openUnavailable(`/${command}`, availability.reason ?? 'Unavailable') return @@ -235,7 +239,7 @@ export class TerminalCommandController { await this.#drafts.flush() let result: Awaited> try { - result = await actions!.run( + result = await actions.run( command === 'interactive' ? { action: 'start', diff --git a/src/views/tui/terminal-identity.ts b/src/views/tui/terminal-identity.ts index 1baa56a..e434b51 100644 --- a/src/views/tui/terminal-identity.ts +++ b/src/views/tui/terminal-identity.ts @@ -54,43 +54,49 @@ export function renderTerminalContext( theme, mode === 'narrow' ? identity.profileName : `profile ${identity.profileName}`, ) - const route = - mode === 'wide' - ? terminalValuePart( - theme, - [identity.runner, model].filter((part) => part.length > 0).join(' / '), - ) - : terminalValuePart(theme, model ? `${identity.runner} / ${model}` : identity.runner) - const connection = terminalValuePart( + if (mode === 'narrow') return fitTerminalColumns([profile], right, safeWidth, priority) + + const compactRoute = terminalValuePart( theme, - mode === 'standard' - ? `via ${executionConnectionLabel(identity.backend, identity.connection)}` - : executionConnectionLabel(identity.backend, identity.connection), + model ? `${identity.runner} / ${model}` : identity.runner, ) - const effortValue = synthetic ? '' : cleanTerminalField(identity.effort) - const effort = - mode === 'wide' && effortValue ? terminalValuePart(theme, `think ${effortValue}`) : '' - const configuredLimits = synthetic - ? '' - : mode === 'wide' - ? configuredLimitGroup(theme, identity) + if (mode === 'standard') { + return fitTerminalColumns( + [ + profile, + compactRoute, + terminalValuePart( + theme, + `via ${executionConnectionLabel(identity.backend, identity.connection)}`, + ), + ], + right, + safeWidth, + priority, + ) + } + + const route = terminalValuePart(theme, `harness ${identity.runner}`) + const modelPart = model ? terminalValuePart(theme, `model ${model}`) : '' + const backendLabel = executionBackendLabel(identity.backend, identity.connection) + const backend = terminalValuePart(theme, `backend ${backendLabel}`) + const connectionValue = cleanTerminalField(identity.connection) + const connection = + !synthetic && + connectionValue && + connectionValue.toLocaleLowerCase() !== backendLabel.toLocaleLowerCase() + ? terminalValuePart(theme, `connection ${connectionValue}`) : '' - const execution = terminalValuePart(theme, identity.execution ?? '') - const executionFacts = - mode === 'wide' - ? (identity.executionFacts ?? []).map((fact) => terminalValuePart(theme, fact)) - : [] + const effortValue = synthetic ? '' : cleanTerminalField(identity.effort) + const effort = effortValue ? terminalValuePart(theme, `think ${effortValue}`) : '' + const configuredLimits = synthetic ? '' : configuredLimitGroup(theme, identity) const branchValue = cleanTerminalField(identity.branch) const branch = - mode === 'wide' && branchValue && branchValue !== 'main' && branchValue !== 'branch-1' + branchValue && branchValue !== 'main' && branchValue !== 'branch-1' ? terminalValuePart(theme, branchValue) : '' return fitTerminalColumns( - mode === 'wide' - ? [profile, route, connection, effort, configuredLimits, execution, ...executionFacts, branch] - : mode === 'narrow' - ? [profile] - : [profile, route, connection, effort, execution, branch], + [profile, route, modelPart, backend, connection, effort, configuredLimits, branch], right, safeWidth, priority, @@ -122,7 +128,7 @@ function compactModelName(value: string): string { return segments.at(-1) ?? safe } -function executionConnectionLabel(backend: string | undefined, connection: string): string { +function executionBackendLabel(backend: string | undefined, connection: string): string { const provider = cleanTerminalField(backend).toLocaleLowerCase() const human = cleanTerminalField(connection) const normalizedHuman = human.toLocaleLowerCase() @@ -133,12 +139,32 @@ function executionConnectionLabel(backend: string | undefined, connection: strin normalizedHuman === 'deterministic fixture' ) return 'local' - if (provider === 'cli-bridge' || /cli bridge/iu.test(human)) return human || 'CLI Bridge' + if (provider === 'cli-bridge') return 'CLI Bridge' + if (/cli bridge/iu.test(human)) return human || 'CLI Bridge' if (provider === 'tangle-sandbox' || /tangle sandbox/iu.test(human)) return 'Sandbox' if (provider === 'tangle-inference' || /tangle inference/iu.test(human)) return 'Tangle inference' return human || cleanTerminalField(backend) || 'local' } +function executionConnectionLabel(backend: string | undefined, connection: string): string { + const provider = cleanTerminalField(backend).toLocaleLowerCase() + const human = cleanTerminalField(connection) + const normalizedHuman = human.toLocaleLowerCase() + if ( + provider === 'fixture' || + provider === 'deterministic' || + provider === 'deterministic fixture' || + normalizedHuman === 'deterministic fixture' + ) + return 'local' + if (provider === 'cli-bridge' || /cli bridge/iu.test(human)) return human || 'CLI Bridge' + if (provider === 'tangle-sandbox' || /tangle sandbox/iu.test(human)) return 'Sandbox' + if (provider === 'tangle-inference' || /tangle inference/iu.test(human)) { + return 'Tangle inference' + } + return human || executionBackendLabel(backend, connection) +} + export function cleanTerminalField(value: string | null | undefined): string { return value === undefined || value === null ? '' diff --git a/src/views/tui/terminal-overlays.ts b/src/views/tui/terminal-overlays.ts index 4ee5616..f75081e 100644 --- a/src/views/tui/terminal-overlays.ts +++ b/src/views/tui/terminal-overlays.ts @@ -121,8 +121,15 @@ export class TerminalOverlayController { nextOperationId: this.#nextOperationId, query, onCancel: () => this.#modals.closeTop(), + rows: this.#rows, + }) + this.#modals.open(panel, { + anchor: 'top-left', + width: '100%', + maxHeight: '100%', + margin: 0, + fullScreenBelow: Number.MAX_SAFE_INTEGER, }) - this.#modals.open(panel, { anchor: 'center', width: '88%', minWidth: 44, maxHeight: '90%' }) } openConnectionEditor(): void { diff --git a/test/cli-bridge-interactions.test.ts b/test/cli-bridge-interactions.test.ts index 273f4e9..d203e21 100644 --- a/test/cli-bridge-interactions.test.ts +++ b/test/cli-bridge-interactions.test.ts @@ -1,6 +1,6 @@ import assert from 'node:assert/strict' import test from 'node:test' -import { defineAgentProfile } from '@tangle-network/agent-interface' +import { type AgentExactRunControlRef, defineAgentProfile } from '@tangle-network/agent-interface' import { createCliBridgeRetainedPlan, startCliBridgeRetainedRun, @@ -9,11 +9,177 @@ import { prepareCliBridgeConnection } from '../src/adapters/runtime/production-c import { ConnectionRegistry } from '../src/app/connections.js' import type { ConnectionRecord } from '../src/domain/entities.js' import { createConnectionId } from '../src/domain/ids.js' -import type { ExecuteTurnInput, RetainedRunAdmissionRecord } from '../src/ports/execution.js' +import type { RunAdmissionReceipt } from '../src/domain/run-contracts.js' +import { + DEFAULT_RUN_CAPABILITIES, + type ExecuteTurnInput, + type RetainedRunAdmissionRecord, +} from '../src/ports/execution.js' import { startRuntimeBridgeServer } from './support/runtime-bridge-server.js' const createdAt = '2026-08-15T00:00:00.000Z' +test('fresh CLI Bridge plans keep provider identity unknown until Runtime admission', async () => { + const bridge = await startRuntimeBridgeServer() + const connection: ConnectionRecord = { + id: createConnectionId('connection-cli-identity'), + kind: 'cli-bridge', + name: 'CLI Bridge identity test', + endpoint: bridge.endpoint, + providerOptions: { transport: 'local' }, + createdAt, + updatedAt: createdAt, + lastHealth: { status: 'unknown' }, + } + const profile = defineAgentProfile({ + name: 'CLI Bridge identity test', + harness: 'pi', + model: { provider: 'openai', default: 'openai/gpt-5' }, + }) + const input: ExecuteTurnInput = { + operationId: 'operation-cli-identity', + runId: 'run-cli-identity', + text: 'Retain this exact provider identity.', + profile, + connectionId: connection.id, + workspaceRoot: '/workspace', + signal: new AbortController().signal, + } + const options = { + connections: new ConnectionRegistry([connection]), + workspaceCwd: '/workspace', + select: () => ({ connection: { connectionId: connection.id } }), + } + + try { + const prepared = await prepareCliBridgeConnection( + options, + input, + { connection: { connectionId: connection.id } }, + connection.id, + bridge.endpoint, + ) + const fresh = await createCliBridgeRetainedPlan(prepared, input.runId) + assert.equal(fresh.environmentId, undefined) + assert.match(fresh.environmentIdempotencyKey, /^environment-braid-/u) + assert.equal(fresh.materializationReceipt.environmentId, undefined) + + const exact: AgentExactRunControlRef = { + runId: 'provider-run-cli-identity', + provider: 'cli-bridge', + environmentId: 'cb1.opaque-cli-identity', + sessionId: 'session-cli-identity', + executionId: 'execution-cli-identity', + requestDigest: `sha256:${'d'.repeat(64)}`, + } + const recovered = await createCliBridgeRetainedPlan(prepared, input.runId, exact) + assert.equal(recovered.environmentId, exact.environmentId) + assert.equal(recovered.environmentIdempotencyKey, 'environment-braid-run-cli-identity') + assert.notEqual(recovered.environmentId, recovered.environmentIdempotencyKey) + } finally { + await bridge.close() + } +}) + +test('retained CLI Bridge replays a persisted intent through Runtime', async () => { + const bridge = await startRuntimeBridgeServer({ responseText: 'CLI_BRIDGE_REPLAY_OK' }) + const connection: ConnectionRecord = { + id: createConnectionId('connection-cli-replay'), + kind: 'cli-bridge', + name: 'CLI Bridge replay test', + endpoint: bridge.endpoint, + providerOptions: { transport: 'local' }, + createdAt, + updatedAt: createdAt, + lastHealth: { status: 'unknown' }, + } + const profile = defineAgentProfile({ + name: 'CLI Bridge replay test', + harness: 'pi', + model: { provider: 'openai', default: 'openai/gpt-5' }, + }) + const input: ExecuteTurnInput = { + operationId: 'operation-cli-replay', + runId: 'run-cli-replay', + text: 'Replay this retained intent exactly.', + profile, + connectionId: connection.id, + workspaceRoot: '/workspace', + signal: new AbortController().signal, + onRetainedAdmission: async () => {}, + } + const options = { + connections: new ConnectionRegistry([connection]), + workspaceCwd: '/workspace', + select: () => ({ connection: { connectionId: connection.id } }), + } + + try { + const prepared = await prepareCliBridgeConnection( + options, + input, + { connection: { connectionId: connection.id } }, + connection.id, + bridge.endpoint, + ) + const plan = await createCliBridgeRetainedPlan(prepared, input.runId) + const admissions: RetainedRunAdmissionRecord[] = [] + await assert.rejects( + startCliBridgeRetainedRun(plan, { + ...input, + onRetainedAdmission: async (admission) => { + admissions.push(structuredClone(admission)) + if (admission.phase === 'intent') throw new Error('simulated process death') + }, + }), + (error: unknown) => + error instanceof Error && + error.cause instanceof Error && + error.cause.message === 'simulated process death', + ) + const intent = admissions[0] + if (intent?.phase !== 'intent') throw new Error('the retained intent was not persisted') + + const receipt: RunAdmissionReceipt = { + version: 1, + runId: input.runId, + turnId: input.operationId, + operationId: input.operationId, + conversationId: 'conversation-cli-replay', + branchId: 'branch-cli-replay', + admittedAt: createdAt, + profileDigest: `sha256:${'a'.repeat(64)}`, + requested: { + text: input.text, + profile, + connectionId: connection.id, + interactions: {}, + }, + capabilities: DEFAULT_RUN_CAPABILITIES, + requestDigest: `sha256:${'b'.repeat(64)}`, + capabilitiesDigest: `sha256:${'c'.repeat(64)}`, + digest: `sha256:${'d'.repeat(64)}`, + } + const recoveredAdmissions: RetainedRunAdmissionRecord[] = [] + const recovered = await plan.recover?.({ + admission: intent, + receipt, + onRetainedAdmission: async (admission) => { + recoveredAdmissions.push(structuredClone(admission)) + }, + }) + assert.ok(recovered) + assert.deepEqual( + recoveredAdmissions.map((admission) => admission.phase), + ['environment', 'dispatched'], + ) + assert.equal(bridge.requests.length, 1) + assert.equal(recovered.controlRef.sessionId, prepared.providerSessionId) + } finally { + await bridge.close() + } +}) + test('retained CLI Bridge receives the exact admitted interaction map', async () => { const bridge = await startRuntimeBridgeServer({ responseText: 'CLI_BRIDGE_INTERACTION_OK' }) const connection: ConnectionRecord = { diff --git a/test/cli-bridge-retained-restart.test.ts b/test/cli-bridge-retained-restart.test.ts index 69dcad2..c6dcf16 100644 --- a/test/cli-bridge-retained-restart.test.ts +++ b/test/cli-bridge-retained-restart.test.ts @@ -12,7 +12,6 @@ import { } from '../src/adapters/runtime/retained-execution.js' import { finalRetainedEnvelope } from '../src/adapters/runtime/retained-execution-projection.js' import { createApplicationUiController } from '../src/adapters/tui/application-ui-controller.js' -import { providerEventFor } from '../src/app/run-event-mapper.js' import { createDurableBraidApplication, type DurableBraidApplication, @@ -21,6 +20,7 @@ import { createProductionComposition, type ProductionCompositionConfig, } from '../src/app/production-composition.js' +import { providerEventFor } from '../src/app/run-event-mapper.js' import type { ConnectionRecord } from '../src/domain/entities.js' import { createConnectionId } from '../src/domain/ids.js' import { isFinalRuntimeEvent, isRuntimeEventEnvelope } from '../src/domain/runtime-events.js' @@ -220,6 +220,57 @@ test('retained recovery passes the exact provider reference into plan constructi assert.equal(snapshot?.sessionId, controlRef.sessionId) }) +test('retained recovery carries the persisted opaque environment identity through discovery', async () => { + const runId = 'braid/opaque-environment-recovery' + const retainedAdmission: RetainedRunAdmissionRecord = { + phase: 'environment', + provider: 'cloud-provider', + environmentId: 'cb1.persisted-opaque-environment', + idempotencyKey: 'environment-braid-opaque-environment-recovery', + turnId: 'turn-opaque-environment-recovery', + sessionId: 'session-opaque-environment-recovery', + executionId: 'execution-opaque-environment-recovery', + } + const exact: AgentExactRunControlRef = { + runId: 'cloud-provider-run-opaque-environment-recovery', + provider: retainedAdmission.provider, + environmentId: retainedAdmission.environmentId, + sessionId: retainedAdmission.sessionId, + executionId: retainedAdmission.executionId, + requestDigest: `sha256:${'e'.repeat(64)}`, + } + let receivedAdmission: RetainedRunAdmissionRecord | undefined + let receivedControlRef: AgentExactRunControlRef | undefined + const execution = new RetainedExecutionPort({ + resolve: async () => { + throw new Error('fresh admission is not part of this recovery test') + }, + recover: async ({ retainedAdmission: admission }) => { + receivedAdmission = admission + if (admission?.phase !== 'environment') { + throw new Error('recovery lost the retained environment admission') + } + return { + ...recoveryPlan(exact), + reconnect: async (controlRef) => { + receivedControlRef = controlRef + return recoveryPlan(exact).reconnect(controlRef) + }, + } + }, + }) + + const snapshot = await execution.status({ + runId, + providerSessionId: retainedAdmission.sessionId, + retainedAdmission, + }) + assert.deepEqual(receivedAdmission, retainedAdmission) + assert.deepEqual(receivedControlRef, exact) + assert.equal(snapshot?.runId, runId) + assert.equal(snapshot?.sessionId, retainedAdmission.sessionId) +}) + test('durable Braid detaches, restarts, and resumes one retained CLI Bridge job exactly once', async () => { const root = await mkdtemp(join(tmpdir(), 'braid-retained-restart-')) const bridge = await startRuntimeBridgeServer({ @@ -363,7 +414,7 @@ test('restart discovery preserves a continued provider session before the contro assert.equal(bridge.requests[0]?.sessionId, providerSessionId) assert.deepEqual( admissions.map((entry) => entry.phase), - ['environment', 'dispatched'], + ['intent', 'environment', 'dispatched'], ) await stream.return?.() @@ -371,7 +422,15 @@ test('restart discovery preserves a continued provider session before the contro if (restarted.execution.status === undefined || restarted.execution.cancelRun === undefined) { throw new Error('Retained recovery controls are unavailable') } - const snapshot = await restarted.execution.status({ runId, providerSessionId }) + const environmentAdmission = admissions.find((entry) => entry.phase === 'environment') + if (environmentAdmission === undefined) { + throw new Error('The environment admission was not retained') + } + const snapshot = await restarted.execution.status({ + runId, + providerSessionId, + retainedAdmission: environmentAdmission, + }) assert.equal(snapshot?.runId, runId) assert.equal(snapshot?.sessionId, providerSessionId) assert.equal(snapshot?.status, 'streaming') @@ -380,6 +439,7 @@ test('restart discovery preserves a continued provider session before the contro operationId: 'operation-retained-crash-window-cancel', runId, providerSessionId, + retainedAdmission: environmentAdmission, }) assert.equal('outcome' in cancellation ? cancellation.outcome : cancellation.status, 'accepted') assert.equal(bridge.cancellations.length, 1) @@ -423,7 +483,14 @@ test('restart discovery rejects a status response for another CLI Bridge run', a if (restarted.execution.status === undefined) { throw new Error('Retained recovery controls are unavailable') } - await assert.rejects(restarted.execution.status({ runId }), /another run identity/u) + const environmentAdmission = admissions.find((entry) => entry.phase === 'environment') + if (environmentAdmission === undefined) { + throw new Error('The environment admission was not retained') + } + await assert.rejects( + restarted.execution.status({ runId, retainedAdmission: environmentAdmission }), + /another run identity/u, + ) assert.equal(bridge.requests.length, 1) } finally { bridge.complete() diff --git a/test/configuration-product-flow.test.ts b/test/configuration-product-flow.test.ts index a7d5bf8..8366ebb 100644 --- a/test/configuration-product-flow.test.ts +++ b/test/configuration-product-flow.test.ts @@ -292,6 +292,8 @@ test('profile editor uses canonical summaries and validates without advertising panel.focused = true await settle() const initial = panel.render(80).join('\n') + assert.match(initial, /profile/u) + assert.match(initial, /─{20,}/u) assert.match(initial, /Reviewer/u) assert.doesNotMatch(initial, /Active profile/u) assert.match(initial, /pi/u) @@ -299,7 +301,7 @@ test('profile editor uses canonical summaries and validates without advertising assert.doesNotMatch(initial, /secret-canary|secret-profile\.json/u) const narrow = panel.render(40) assert.ok(narrow.length <= 12) - assert.match(narrow.join('\n'), /enter select · \^V validate · ←\/esc/u) + assert.match(narrow.join('\n'), /enter · \^V validate · ←\/esc close/u) assert.match(narrow.join('\n'), /close/u) assert.doesNotMatch(narrow.join('\n'), /save/iu) @@ -325,6 +327,8 @@ test('one profile renders a focused summary without a redundant switch list', as panel.focused = true await settle() const rendered = panel.render(80).join('\n') + assert.match(rendered, /^ profile/mu) + assert.match(rendered, /─{20,}/u) assert.match(rendered, /Reviewer/u) assert.match(rendered, /runner pi · model provider\/reviewer/u) assert.doesNotMatch(rendered, /switch profile|profiles/u) diff --git a/test/configuration-wizard.test.ts b/test/configuration-wizard.test.ts index bf12523..314ddec 100644 --- a/test/configuration-wizard.test.ts +++ b/test/configuration-wizard.test.ts @@ -310,7 +310,7 @@ test('mounted first-run setup preserves choices and fits keyboard guidance at na } assert.match(frame('profile'), /choose an AgentProfile/u) - assert.match(frame('profile'), /filter · enter choose · esc cancel/u) + assert.match(frame('profile'), /filter · enter choose · ←\/esc cancel/u) terminal.sendInput('\u001b[B') terminal.sendInput('\r') await terminal.waitForRender() diff --git a/test/interactive-execution-adapters.test.ts b/test/interactive-execution-adapters.test.ts index ffb72a5..d8a2c3d 100644 --- a/test/interactive-execution-adapters.test.ts +++ b/test/interactive-execution-adapters.test.ts @@ -1,23 +1,28 @@ import assert from 'node:assert/strict' import test from 'node:test' -import type { - AgentEnvironment, - AgentEnvironmentCapabilities, - AgentEnvironmentProvider, -} from '@tangle-network/agent-interface/environment-provider' import type { AgentInteractiveSessionRef, AgentProfile } from '@tangle-network/agent-interface' import { AgentInteractiveSessionRefSchema, canonicalCandidateDigest, } from '@tangle-network/agent-interface' -import { NativeInteractiveRunBroker } from '../src/adapters/runtime/native-interactive-run-broker.js' +import type { + AgentEnvironment, + AgentEnvironmentCapabilities, + AgentEnvironmentProvider, +} from '@tangle-network/agent-interface/environment-provider' +import type { RetainedInteractiveAdmission } from '@tangle-network/agent-runtime/kernel' import { ModeRoutingExecutionPort } from '../src/adapters/runtime/mode-routing-execution.js' +import { NativeInteractiveRunBroker } from '../src/adapters/runtime/native-interactive-run-broker.js' +import { + safeExecutionId, + stableProviderId, +} from '../src/adapters/runtime/production-backend-common.js' import type { PreparedTangleRetainedConnection } from '../src/adapters/runtime/production-tangle-sandbox-backend.js' +import { assertInteractiveProvider } from '../src/adapters/runtime/tangle-retained-interactive-contract.js' import { TangleRetainedInteractiveExecutionPort } from '../src/adapters/runtime/tangle-retained-interactive-execution.js' -import type { ExecuteTurnInput, ExecutionPort } from '../src/ports/execution.js' -import type { RuntimeEventEnvelope } from '../src/domain/runtime-events.js' -import type { RetainedInteractiveAdmission } from '@tangle-network/agent-runtime/kernel' import type { RunAdmissionReceipt } from '../src/domain/receipts.js' +import type { RuntimeEventEnvelope } from '../src/domain/runtime-events.js' +import type { ExecuteTurnInput, ExecutionPort } from '../src/ports/execution.js' const PROFILE: AgentProfile = { name: 'Braid interactive test', @@ -47,9 +52,19 @@ test('mode routing is async when either branch is async and honors canonical int runId: 'run/recovered', retainedAdmission: { phase: 'interactive_intent' }, } as never) + await router.cancelRun({ + runId: 'run/recovered-control', + operationId: 'operation-recovered-control', + retainedAdmission: { phase: 'interactive_started' }, + } as never) await collect(router.streamTurn(input('run/headless', { mode: 'headless' }))) - assert.deepEqual(calls, ['interactive:stream', 'interactive:status', 'headless:stream']) + assert.deepEqual(calls, [ + 'interactive:stream', + 'interactive:status', + 'interactive:cancel', + 'headless:stream', + ]) await assert.rejects( () => collect( @@ -81,6 +96,7 @@ test('starts one native process, records Runtime identity, and emits replayable assert.equal(fixture.stats.dispatchCalls, 0) assert.equal(fixture.stats.processStarts, 1) + assert.equal(fixture.resolveInputs.length, 1) assert.deepEqual( admissions.map((entry) => entry.phase), ['interactive_intent', 'interactive_environment', 'interactive_started'], @@ -188,6 +204,16 @@ test('partial intent and environment admissions report replayable status without ) const partial = admissions.find((admission) => admission.phase === phase) assert.ok(partial) + await assert.rejects( + () => + port.status({ + runId: input.runId, + providerSessionId: 'wrong-native-session', + retainedAdmission: partial, + receipt: receiptFor(input), + } as Parameters[0]), + /conflicts with the saved admission/u, + ) const before = { ...fixture.stats } const status = await port.status({ runId: input.runId, @@ -298,6 +324,221 @@ test('a second foreground execution cannot duplicate an active native process', assert.equal((await first.next()).done, true) }) +test('cancellation between admission and start cannot create a native process', async () => { + const fixture = interactiveFixture() + const port = interactivePort(fixture, new NativeInteractiveRunBroker()) + const input = executionInput('run/cancel-before-start', async () => {}) + await port.admit(input) + const iterator = port.streamTurn(input)[Symbol.asyncIterator]() + const nextResult = iterator.next() + const cancelled = await port.cancelRun({ + operationId: 'cancel-before-native-start', + runId: input.runId, + }) + + assert.equal(cancelled.outcome, 'accepted') + assert.deepEqual(await nextResult, { done: true, value: undefined }) + assert.equal(fixture.stats.processStarts, 0) +}) + +test('cancelling a persisted interactive intent after restart does not materialize it', async () => { + const fixture = interactiveFixture() + const first = interactivePort(fixture, new NativeInteractiveRunBroker()) + const admissions: RetainedInteractiveAdmission[] = [] + const input = executionInput('run/cancel-intent', async (admission) => { + admissions.push(admission) + if (admission.phase === 'interactive_intent') throw new Error('simulated intent loss') + }) + const initial = first.streamTurn(input)[Symbol.asyncIterator]() + await assert.rejects( + () => initial.next(), + (error: unknown) => causedBy(error, 'simulated intent loss'), + ) + const intent = admissions.find((admission) => admission.phase === 'interactive_intent') + assert.ok(intent?.phase === 'interactive_intent') + + const restarted = interactivePort(fixture, new NativeInteractiveRunBroker()) + const cancelled = await restarted.cancelRun({ + operationId: 'cancel-persisted-interactive-intent', + runId: input.runId, + providerSessionId: intent.sessionId, + retainedAdmission: intent, + receipt: receiptFor(input), + }) + + assert.deepEqual(cancelled, { + operationId: 'cancel-persisted-interactive-intent', + outcome: 'accepted', + detail: 'cancelled-before-start', + }) + assert.equal(fixture.stats.createCalls, 0) + assert.equal(fixture.stats.processStarts, 0) + assert.equal(fixture.stats.stopCalls, 0) +}) + +test('detaching a persisted interactive intent does not materialize it', async () => { + const fixture = interactiveFixture() + const first = interactivePort(fixture, new NativeInteractiveRunBroker()) + const admissions: RetainedInteractiveAdmission[] = [] + const input = executionInput('run/detach-intent', async (admission) => { + admissions.push(admission) + if (admission.phase === 'interactive_intent') throw new Error('simulated detach intent loss') + }) + const initial = first.streamTurn(input)[Symbol.asyncIterator]() + await assert.rejects( + () => initial.next(), + (error: unknown) => causedBy(error, 'simulated detach intent loss'), + ) + const intent = admissions.find((admission) => admission.phase === 'interactive_intent') + assert.ok(intent?.phase === 'interactive_intent') + + const restarted = interactivePort(fixture, new NativeInteractiveRunBroker()) + const detached = await restarted.detachRun({ + operationId: 'detach-persisted-interactive-intent', + runId: input.runId, + providerSessionId: intent.sessionId, + retainedAdmission: intent, + receipt: receiptFor(input), + }) + + assert.deepEqual(detached, { + operationId: 'detach-persisted-interactive-intent', + outcome: 'accepted', + detail: 'detached', + }) + assert.equal(fixture.stats.createCalls, 0) + assert.equal(fixture.stats.processStarts, 0) + assert.equal(fixture.stats.stopCalls, 0) +}) + +test('cancellation recovers the exact native process after a process restart', async () => { + const fixture = interactiveFixture() + const firstBroker = new NativeInteractiveRunBroker() + const first = interactivePort(fixture, firstBroker) + const admissions: RetainedInteractiveAdmission[] = [] + const input = executionInput('run/restart-cancel', async (admission) => { + admissions.push(admission) + }) + const iterator = first.streamTurn(input)[Symbol.asyncIterator]() + await next(iterator) + const handle = await firstBroker.waitForHandle(input.runId) + await first.detachRun({ + runId: input.runId, + operationId: 'detach-before-restart-cancel', + providerSessionId: handle.ref.run.sessionId, + controlRef: handle.ref.run, + }) + assert.equal((await iterator.next()).done, true) + const started = admissions.find((entry) => entry.phase === 'interactive_started') + assert.ok(started?.phase === 'interactive_started') + + const restarted = interactivePort(fixture, new NativeInteractiveRunBroker()) + const cancelled = await restarted.cancelRun({ + operationId: 'cancel-after-restart', + runId: input.runId, + providerSessionId: started.ref.run.sessionId, + controlRef: started.ref.run, + retainedAdmission: started, + receipt: receiptFor(input), + workspaceRoot: '/workspace', + }) + + assert.equal(cancelled.outcome, 'accepted') + assert.equal(fixture.stats.processStarts, 1) + assert.equal(fixture.stats.stopCalls, 1) +}) + +test('native cancellation omits an expired foreground signal from provider stop', async () => { + const fixture = interactiveFixture() + const broker = new NativeInteractiveRunBroker() + const port = interactivePort(fixture, broker) + const input = executionInput('run/expired-cancel', async () => {}) + const iterator = port.streamTurn(input)[Symbol.asyncIterator]() + await next(iterator) + const handle = await broker.waitForHandle(input.runId) + const controller = new AbortController() + controller.abort(new Error('foreground deadline elapsed')) + + const cancelled = await port.cancelRun({ + operationId: 'cancel-expired-foreground', + runId: input.runId, + providerSessionId: handle.ref.run.sessionId, + controlRef: handle.ref.run, + signal: controller.signal, + }) + + assert.equal(cancelled.outcome, 'accepted') + assert.equal(fixture.stats.stopSignals.at(-1), undefined) + const final = await next(iterator) + assert.equal(final.sequence, 2) + assert.equal((await iterator.next()).done, true) +}) + +test('interactive admission rejects a changed request for the same run identity', async () => { + const fixture = interactiveFixture() + const port = interactivePort(fixture, new NativeInteractiveRunBroker()) + const input = executionInput('run/request-integrity', async () => {}) + await port.admit(input) + + await assert.rejects( + () => collect(port.streamTurn({ ...input, text: 'Use a different prompt.' })), + /different request/u, + ) + assert.equal(fixture.stats.processStarts, 0) +}) + +test('provider identity keys preserve uniqueness after normalization and truncation', () => { + assert.notEqual(safeExecutionId('run/a'), safeExecutionId('run-a')) + const first = 'x'.repeat(140) + const second = `${'x'.repeat(139)}y` + assert.notEqual(stableProviderId('env-braid-', first), stableProviderId('env-braid-', second)) + assert.ok(stableProviderId('env-braid-', first).length <= 128) +}) + +test('interactive provider admission requires terminal and prompt capabilities', () => { + const fixture = interactiveFixture() + const incomplete = { + ...fixture.prepared, + capabilities: { + ...fixture.prepared.capabilities, + interactiveAgent: { + ...fixture.prepared.capabilities.interactiveAgent, + input: false, + }, + }, + } as PreparedTangleRetainedConnection + assert.throws(() => assertInteractiveProvider(incomplete), /exact interactive agents/u) +}) + +test('native interactive admission does not advertise structured responses it cannot route', async () => { + const fixture = interactiveFixture() + const port = new TangleRetainedInteractiveExecutionPort({ + broker: new NativeInteractiveRunBroker(), + resolve: async (input) => ({ + ...fixture.prepared, + profile: input.profile, + capabilities: { + ...fixture.prepared.capabilities, + interactions: { + kinds: ['question'], + answerFieldTypes: ['text'], + responseScopes: ['interaction'], + secretAnswers: false, + concurrentRequests: false, + replay: true, + responseIdempotency: true, + }, + }, + }), + }) + + const admission = await port.admit( + executionInput('run/native-interaction-capability', async () => {}), + ) + + assert.equal(admission.capabilities?.environment?.interactions, undefined) +}) + interface InteractiveFixture { readonly provider: AgentEnvironmentProvider readonly prepared: PreparedTangleRetainedConnection @@ -309,6 +550,8 @@ interface InteractiveFixture { startCalls: number processStarts: number dispatchCalls: number + stopCalls: number + stopSignals: (AbortSignal | undefined)[] } readonly lastCreateMetadata: Readonly> | undefined } @@ -316,7 +559,15 @@ interface InteractiveFixture { function interactiveFixture(): InteractiveFixture { const profile = PROFILE const resolveInputs: ExecuteTurnInput[] = [] - const stats = { createCalls: 0, getCalls: 0, startCalls: 0, processStarts: 0, dispatchCalls: 0 } + const stats = { + createCalls: 0, + getCalls: 0, + startCalls: 0, + processStarts: 0, + dispatchCalls: 0, + stopCalls: 0, + stopSignals: [], + } const state: { ref?: AgentInteractiveSessionRef lastCreateMetadata: Readonly> | undefined @@ -339,7 +590,7 @@ function interactiveFixture(): InteractiveFixture { } return state.ref }, - interactive: (ref) => interactiveSession(ref) as never, + interactive: (ref) => interactiveSession(ref, stats) as never, } const provider: AgentEnvironmentProvider = { name: 'test-provider', @@ -492,6 +743,10 @@ function routingPort( calls.push(`${label}:status`) return null }, + cancelRun: async (control) => { + calls.push(`${label}:cancel`) + return { operationId: control.operationId, outcome: 'accepted' } + }, } } @@ -595,13 +850,13 @@ function interactiveRef( }) } -function interactiveSession(ref: AgentInteractiveSessionRef) { +function interactiveSession(ref: AgentInteractiveSessionRef, stats: InteractiveFixture['stats']) { const control = (holderId: string) => ({ refDigest: canonicalCandidateDigest(ref), generation: 1, leaseId: 'interactive-lease-test', holderId, - expiresAt: '2026-08-17T00:00:00.000Z', + expiresAt: '2099-01-01T00:00:00.000Z', }) return { ref, @@ -652,14 +907,21 @@ function interactiveSession(ref: AgentInteractiveSessionRef) { control: command.control, status: 'accepted' as const, }), - stop: async (command: { operationId: string; requestDigest: string; control: unknown }) => ({ - operationId: command.operationId, - requestDigest: command.requestDigest, - ref, - control: command.control, - status: 'accepted' as const, - effect: 'stopped' as const, - }), + stop: async ( + command: { operationId: string; requestDigest: string; control: unknown }, + options?: { signal?: AbortSignal }, + ) => { + stats.stopCalls += 1 + stats.stopSignals.push(options?.signal) + return { + operationId: command.operationId, + requestDigest: command.requestDigest, + ref, + control: command.control, + status: 'accepted' as const, + effect: 'stopped' as const, + } + }, } } diff --git a/test/native-interactive-command.test.ts b/test/native-interactive-command.test.ts index 28fd52a..f617492 100644 --- a/test/native-interactive-command.test.ts +++ b/test/native-interactive-command.test.ts @@ -6,7 +6,7 @@ import { createBraidApplication } from '../src/app/composition.js' import type { NativeInteractiveCommand, NativeInteractiveUiActions, -} from '../src/ports/native-interactive-ui.js' +} from '../src/views/shared/native-interactive-actions.js' import { BraidTerminalApp } from '../src/views/tui/terminal-app.js' import { createBraidTheme } from '../src/views/tui/theme.js' import { VirtualTerminal } from './support/virtual-terminal.js' diff --git a/test/production-composition.test.ts b/test/production-composition.test.ts index ab42796..08615d4 100644 --- a/test/production-composition.test.ts +++ b/test/production-composition.test.ts @@ -72,6 +72,7 @@ import { FixedClock } from '../src/ports/clock.js' import { credentialRef } from '../src/ports/credentials.js' import { SequenceIds } from '../src/ports/ids.js' import { startRuntimeBridgeServer } from './support/runtime-bridge-server.js' +import { FakeTangleRetainedSandbox } from './support/tangle-retained-sandbox.js' const at = '2026-08-03T12:00:00.000Z' @@ -428,6 +429,80 @@ test('production rejects remote cleartext endpoints unless an explicit policy ac assert.equal(accepted.connection.id, remote.id) }) +test('retained Tangle composition exposes one native control through durable startup', async () => { + const root = await mkdtemp(join(tmpdir(), 'braid-production-native-control-')) + const record: ConnectionRecord = { + ...connection('tangle-sandbox', 'native-control', 'https://sandbox.tangle.tools'), + providerOptions: { + transport: 'https', + lifecycle: 'retained', + idleTtlSeconds: 1_800, + }, + } + const selected = composition( + record, + {}, + defineAgentProfile({ + name: 'native production profile', + harness: 'opencode', + model: { default: 'openai/gpt-5', provider: 'openai' }, + }), + ) + const composed = createProductionComposition(selected) + assert.notEqual(composed.nativeInteractive, undefined) + + const durable = await createDurableBraidApplication({ + path: join(root, 'braid.db'), + workspaceRoot: root, + credentialStore: new MemoryCredentialStore(), + production: selected, + }) + try { + assert.notEqual(durable.nativeInteractive, undefined) + } finally { + await durable.app.close() + await durable.storage.close() + } +}) + +test('retained Tangle composition routes interactive admission without creating a sandbox', async () => { + const sandbox = new FakeTangleRetainedSandbox() + const record: ConnectionRecord = { + ...connection('tangle-sandbox', 'interactive-routing', 'https://sandbox.tangle.tools', true), + providerOptions: { + transport: 'https', + lifecycle: 'retained', + idleTtlSeconds: 1_800, + }, + } + const credentials = new MemoryCredentialStore() + await credentials.store({ + ref: credentialRef('cred:v1:credential-interactive-routing'), + value: Buffer.from('test-only-sandbox-key'), + }) + const selectedProfile = defineAgentProfile({ + name: 'interactive routing profile', + harness: 'opencode', + model: { default: 'openai/gpt-5', provider: 'openai' }, + }) + const composed = createProductionComposition( + composition(record, { credentials, sandboxClient: sandbox.client() }, selectedProfile), + ) + const admission = await composed.execution.admit?.({ + operationId: 'operation-interactive-routing', + runId: 'run-interactive-routing', + text: 'Inspect this workspace.', + profile: selectedProfile, + mode: 'interactive', + connectionId: record.id, + signal: new AbortController().signal, + }) + + assert.equal(admission?.materializationReceipt?.surface, 'interactive-agent') + assert.equal(admission?.capabilities?.streaming.replay, true) + assert.equal(sandbox.createCalls.length, 0) +}) + test('bin startup loads a canonical profile and exact connection from a bounded config file', async () => { const root = await mkdtemp(join(tmpdir(), 'braid-production-startup-')) const profilePath = join(root, 'profile.json') @@ -1098,8 +1173,13 @@ test('protected Bridge auth survives setup, restart, and a real turn without per assert.notEqual(secondBody.session_id, firstBody.session_id) for (const body of [firstBody, secondBody]) { const runId = String(body.run_id) - assert.deepEqual(body.metadata, { + const metadata = body.metadata as Record + const retainedIntentDigest = String(metadata.retainedIntentDigest) + assert.match(retainedIntentDigest, /^sha256:[0-9a-f]{64}$/u) + assert.deepEqual(metadata, { retainedIdempotencyKey: `environment-braid-${runId}`, + retainedIntentDigest, + retainedRunId: `retained-intent-run:${retainedIntentDigest.slice('sha256:'.length)}`, sessionId: `session-braid-${runId}`, executionId: runId, }) diff --git a/test/profiles.test.ts b/test/profiles.test.ts index a5c6b01..7390634 100644 --- a/test/profiles.test.ts +++ b/test/profiles.test.ts @@ -217,7 +217,7 @@ test('the installed canonical profile schema round-trips every field and extensi assert.equal(canonicalCandidateJson(imported.profile), json) assert.deepEqual(imported.profile.extensions, fullProfile.extensions) assert.deepEqual(imported.profile.resources, fullProfile.resources) - assert.equal(AGENT_INTERFACE_PACKAGE_VERSION, '0.52.0') + assert.equal(AGENT_INTERFACE_PACKAGE_VERSION, '1.0.0') }) test('unknown canonical fields fail closed while namespaced extensions remain opaque', () => { diff --git a/test/retained-execution-lifecycle.test.ts b/test/retained-execution-lifecycle.test.ts index 0e083e9..64264fe 100644 --- a/test/retained-execution-lifecycle.test.ts +++ b/test/retained-execution-lifecycle.test.ts @@ -10,7 +10,11 @@ import { type RetainedExecutionPlan, RetainedExecutionPort, } from '../src/adapters/runtime/retained-execution.js' -import { DEFAULT_RUN_CAPABILITIES, type ExecuteTurnInput } from '../src/ports/execution.js' +import { + DEFAULT_RUN_CAPABILITIES, + type ExecuteTurnInput, + type RetainedRunAdmissionRecord, +} from '../src/ports/execution.js' import { RETAINED_RUN_HANDLE_CAPABILITIES } from './support/retained-run-capabilities.js' const now = '2026-08-12T12:00:00.000Z' @@ -166,6 +170,119 @@ test('pre-start cancellation prevents the retained plan from starting', async () assert.equal(replayed.outcome, 'already-applied') }) +test('restart cancellation of a persisted retained intent does not recover provider work', async () => { + const exact = controlRef('restart-intent') + const execution = new RetainedExecutionPort({ + resolve: async () => { + throw new Error('a cancelled intent must not resolve a new plan') + }, + recover: async () => { + throw new Error('a cancelled intent must not recover provider work') + }, + }) + const admission: RetainedRunAdmissionRecord = { + phase: 'intent', + provider: exact.provider, + idempotencyKey: 'environment-restart-intent', + turnId: 'turn-restart-intent', + sessionId: exact.sessionId, + executionId: exact.executionId, + runId: 'runtime-restart-intent', + requestedProfileDigest: `sha256:${'1'.repeat(64)}`, + requestDigest: `sha256:${'2'.repeat(64)}`, + } + + const acknowledgement = await execution.cancelRun({ + operationId: 'operation-restart-intent-cancel', + runId: 'run-restart-intent', + providerSessionId: exact.sessionId, + retainedAdmission: admission, + }) + + assert.deepEqual(acknowledgement, { + operationId: 'operation-restart-intent-cancel', + outcome: 'accepted', + detail: 'cancelled-before-start', + }) +}) + +test('restart detach validates the persisted retained control reference', async () => { + const exact = controlRef('restart-detach') + let recoveries = 0 + const recoveredPlan = plan(exact, async () => handle(exact)) + const admission: RetainedRunAdmissionRecord = { + phase: 'dispatched', + idempotencyKey: 'environment-restart-detach', + turnId: 'turn-restart-detach', + controlRef: exact, + } + const execution = new RetainedExecutionPort({ + resolve: async () => { + throw new Error('restart detach must not resolve a fresh run') + }, + recover: async ({ controlRef }) => { + recoveries += 1 + assert.deepEqual(controlRef, exact) + return recoveredPlan + }, + }) + + await assert.rejects( + execution.detachRun({ + operationId: 'operation-restart-detach-conflict', + runId: 'run-restart-detach', + providerSessionId: exact.sessionId, + controlRef: { ...exact, requestDigest: `sha256:${'3'.repeat(64)}` }, + retainedAdmission: admission, + }), + /conflicts with the persisted run/u, + ) + const detached = await execution.detachRun({ + operationId: 'operation-restart-detach', + runId: 'run-restart-detach', + providerSessionId: exact.sessionId, + retainedAdmission: admission, + }) + assert.equal(detached.outcome, 'accepted') + assert.equal(recoveries, 1) +}) + +test('restart controls reject a process reference against a pre-dispatch admission', async () => { + const exact = controlRef('pre-dispatch-control') + const conflicting = { ...exact, environmentId: 'environment-other' } + const admission: RetainedRunAdmissionRecord = { + phase: 'environment', + provider: exact.provider, + environmentId: exact.environmentId, + idempotencyKey: 'environment-pre-dispatch-control', + turnId: 'turn-pre-dispatch-control', + sessionId: exact.sessionId, + executionId: exact.executionId, + } + let recoveries = 0 + const execution = new RetainedExecutionPort({ + resolve: async () => { + throw new Error('pre-dispatch control must not resolve a fresh run') + }, + recover: async () => { + recoveries += 1 + return plan(exact, async () => handle(exact)) + }, + }) + + await assert.rejects( + execution.detachRun({ + operationId: 'operation-pre-dispatch-control', + runId: 'run-pre-dispatch-control', + providerSessionId: exact.sessionId, + controlRef: conflicting, + retainedAdmission: admission, + }), + /pre-dispatch admission/u, + ) + assert.equal(recoveries, 0) +}) + test('in-flight start cancellation omits an expired foreground signal', async () => { const exact = controlRef('in-flight') let resolveStart: (value: RetainedRunHandle) => void = () => undefined @@ -358,6 +475,7 @@ test('a reconciled cancelled snapshot confirms an ambiguous cancellation', async test('interaction response recovers the retained handle and preserves retry acknowledgement', async () => { const exact = controlRef('interaction') let responses = 0 + let recoverySignal: AbortSignal | undefined const retainedHandle = handle(exact, { respondToInteraction: async (command) => { responses += 1 @@ -380,9 +498,10 @@ test('interaction response recovers the retained handle and preserves retry ackn resolve: async () => { throw new Error('a recovered interaction must not resolve a new run') }, - recover: async ({ runId, providerSessionId }) => { + recover: async ({ runId, providerSessionId, signal }) => { assert.equal(runId, 'run-interaction') assert.equal(providerSessionId, exact.sessionId) + recoverySignal = signal return recoveredPlan }, }) @@ -401,11 +520,13 @@ test('interaction response recovers the retained handle and preserves retry ackn response: { id: 'interaction-retained', outcome: 'accepted' }, } - assert.deepEqual(await execution.respondInteraction({ command }), { + const signal = new AbortController().signal + assert.deepEqual(await execution.respondInteraction({ command, signal }), { operationId: command.operationId, outcome: 'accepted', detail: 'INTERACTION_RESPONSE_ACCEPTED', }) + assert.equal(recoverySignal, signal) assert.deepEqual(await execution.respondInteraction({ command }), { operationId: command.operationId, outcome: 'already-applied', diff --git a/test/run-interactions.test.ts b/test/run-interactions.test.ts index 5ce08cb..2c34c31 100644 --- a/test/run-interactions.test.ts +++ b/test/run-interactions.test.ts @@ -7,9 +7,9 @@ import { createBraidApplication } from '../src/app/composition.js' import { MemoryJournal } from '../src/app/journal.js' import { runEffectRequest } from '../src/app/run-admission-request.js' import { snapshotRunExecution } from '../src/app/run-execution-snapshot.js' -import { requestedInteractionsForRun } from '../src/app/run-interactions.js' import { canonicalDigest } from '../src/domain/canonical.js' import { createAdmissionReceipt } from '../src/domain/receipts.js' +import { requestedInteractionsForRun } from '../src/domain/run-interactions.js' import type { BraidRuntimeEvent } from '../src/domain/runtime-events.js' import { initialState } from '../src/domain/state.js' import { FixedClock } from '../src/ports/clock.js' diff --git a/test/support/tangle-retained-sandbox.ts b/test/support/tangle-retained-sandbox.ts index f6df585..cee2187 100644 --- a/test/support/tangle-retained-sandbox.ts +++ b/test/support/tangle-retained-sandbox.ts @@ -3,6 +3,7 @@ import type { AgentProfile, AgentRunCancellationAcknowledgement, AgentRunCancellationRequest, + InteractionResponseCommand, RequestedInteractions, } from '@tangle-network/agent-interface' import { @@ -128,6 +129,7 @@ export class FakeTangleRetainedSandbox { dispatch: { runControlRef: true, executionIdOnAdmission: true }, cancel: { canonicalRunCancellation: true, digestBound: true, idempotent: true }, runs: { executionScopedStatus: true, eventReplay: true }, + interactions: { responseDedupe: true }, } }, async refresh() {}, @@ -257,6 +259,16 @@ export class FakeTangleRetainedSandbox { async prompt() { throw new Error('Fake Tangle prompt is not used by retained dispatch') }, + async respondToInteraction(command: InteractionResponseCommand) { + return { + acknowledgement: { + operationId: command.operationId, + binding: command.binding, + commandDigest: command.commandDigest, + status: 'accepted', + }, + } + }, async interrupt(options) { const executionId = options?.executionId if (typeof executionId !== 'string') return { cancelled: false } diff --git a/test/tangle-retained-lifecycle.test.ts b/test/tangle-retained-lifecycle.test.ts index 312cba9..6edb7b8 100644 --- a/test/tangle-retained-lifecycle.test.ts +++ b/test/tangle-retained-lifecycle.test.ts @@ -1,7 +1,10 @@ import assert from 'node:assert/strict' import test from 'node:test' -import { defineAgentProfile } from '@tangle-network/agent-interface' +import { type AgentExactRunControlRef, defineAgentProfile } from '@tangle-network/agent-interface' +import type { SandboxClientLike, SandboxInstanceLike } from '@tangle-network/agent-provider-tangle' import { capabilitiesForConnection } from '../src/adapters/connections/production-connection-providers.js' +import { createTangleRetainedControlLookup } from '../src/adapters/connections/tangle-retained-control-lookup.js' +import { safeExecutionId } from '../src/adapters/runtime/production-backend-common.js' import { resolveTangleSandboxBackend, resolveTangleSandboxRetainedConnection, @@ -11,7 +14,10 @@ import { createTangleRetainedPlan, startTangleRetainedRun, } from '../src/adapters/runtime/tangle-retained-run.js' -import { withRetainedSandboxPolicy } from '../src/adapters/runtime/tangle-sandbox-retention.js' +import { + retainedSandboxIdentity, + withRetainedSandboxPolicy, +} from '../src/adapters/runtime/tangle-sandbox-retention.js' import { ConnectionRegistry } from '../src/app/connections.js' import type { ConnectionRecord, ConnectionTransportOptions } from '../src/domain/entities.js' import { createConnectionId } from '../src/domain/ids.js' @@ -230,6 +236,62 @@ test('published Sandbox methods recover the exact retained dispatch without an i assert.deepEqual(await prepared.discoverControlRef(input.runId), handle.controlRef) }) +test('retained control lookup uses the hashed identity for long provider sessions', async () => { + const providerSessionId = `session-${'x'.repeat(220)}` + const executionId = safeExecutionId('run/long-provider-session') + const identity = retainedSandboxIdentity(providerSessionId) + const controlRef: AgentExactRunControlRef = { + runId: 'provider-run-long-session', + provider: 'tangle-sandbox', + environmentId: 'sandbox-long-provider-session', + sessionId: providerSessionId, + executionId, + requestDigest: `sha256:${'a'.repeat(64)}`, + } + const box = { + id: controlRef.environmentId, + name: identity.name, + metadata: { + ...identity.metadata, + retainedIdempotencyKey: identity.environmentIdempotencyKey, + sessionId: providerSessionId, + executionId, + }, + async *streamPrompt() {}, + session(sessionId: string) { + assert.equal(sessionId, providerSessionId) + return { + async status() { + return { runControlRef: controlRef } + }, + } as never + }, + } as unknown as SandboxInstanceLike + const client = { + async create() { + return box + }, + async list() { + return [box] + }, + async get(id: string) { + assert.equal(id, box.id) + return box + }, + } as SandboxClientLike + + const lookup = createTangleRetainedControlLookup(client) + const recovered = await lookup({ + connectionId: createConnectionId('connection-tangle-long-session'), + braidRunId: 'run/long-provider-session', + providerSessionId, + executionId, + environmentIdempotencyKey: identity.environmentIdempotencyKey, + }) + + assert.deepEqual(recovered, controlRef) +}) + test('retained resolution admits exact control when provider lookup is configured', async () => { const sandbox = new FakeTangleRetainedSandbox() const { connection, options, input, selection } = setup(sandbox) @@ -262,19 +324,27 @@ test('one retained plan uses exact tags, bounded idle expiry, replay, and result assert.equal(sandbox.createCalls[0]?.name, prepared.environmentName) assert.equal(sandbox.createCalls[0]?.idleTimeoutSeconds, 1_800) assert.equal(sandbox.createCalls[0]?.ephemeral, false) - assert.deepEqual(sandbox.createCalls[0]?.metadata, { + const metadata = sandbox.createCalls[0]?.metadata + assert.ok(metadata) + const { retainedIntentDigest, retainedRunId, ...stableMetadata } = metadata + assert.deepEqual(stableMetadata, { ...prepared.environmentMetadata, retainedIdempotencyKey: prepared.environmentIdempotencyKey, sessionId: prepared.providerSessionId, - executionId: 'run-tangle-retained', + executionId: safeExecutionId('run/tangle-retained'), }) + assert.match(String(retainedIntentDigest), /^sha256:[0-9a-f]{64}$/u) + assert.equal( + retainedRunId, + `retained-intent-run:${String(retainedIntentDigest).slice('sha256:'.length)}`, + ) assert.equal(handle.controlRef.environmentId, sandbox.boxes[0]?.id) assert.equal(handle.controlRef.sessionId, prepared.providerSessionId) - assert.equal(handle.controlRef.executionId, 'run-tangle-retained') + assert.equal(handle.controlRef.executionId, safeExecutionId('run/tangle-retained')) assert.match(handle.controlRef.requestDigest, /^sha256:[0-9a-f]{64}$/u) assert.deepEqual( admissions.map((admission) => admission.phase), - ['environment', 'dispatched'], + ['intent', 'environment', 'dispatched'], ) sandbox.complete(handle.controlRef.executionId, 'RETAINED_OK') diff --git a/test/tangle-retained-restart.test.ts b/test/tangle-retained-restart.test.ts index be4e3c7..1c60394 100644 --- a/test/tangle-retained-restart.test.ts +++ b/test/tangle-retained-restart.test.ts @@ -270,7 +270,7 @@ test('provider lookup recovers the pre-journal crash window without a saved refe assert.equal(controlRef?.runId, providerRunId) assert.deepEqual( admissions.map((admission) => admission.phase), - ['environment', 'dispatched'], + ['intent', 'environment', 'dispatched'], ) await stream.return?.(undefined) diff --git a/test/terminal-responsive.test.ts b/test/terminal-responsive.test.ts index 7fdab5e..c3dacfe 100644 --- a/test/terminal-responsive.test.ts +++ b/test/terminal-responsive.test.ts @@ -113,10 +113,12 @@ test('chrome uses complete responsive groups at every reference width', () => { const wideLines = plainLines(chrome, 120) const wide = wideLines.join('\n') assert.match(wide, /Release engineer/u) - assert.match(wide, /profile Release engineer · pi \/ openai-codex\/gpt-5\.6-luna/u) - assert.match(wide, /Local CLI Bridge/u) + assert.match( + wide, + /profile Release engineer · harness pi · model openai-codex\/gpt-5\.6-luna · backend Local CLI Bridge/u, + ) assert.match(wide, / · think high/u) - assert.doesNotMatch(wide, /backend CLI Bridge|caps/u) + assert.doesNotMatch(wide, /caps/u) assert.match(wide, /in 1\.2k/u) assert.match(wide, /out 567/u) assert.match(wide, /\$0\.0312/u) @@ -129,7 +131,10 @@ test('chrome uses complete responsive groups at every reference width', () => { const spaciousLines = plainLines(chrome, 200) assert.equal(spaciousLines.length, 2) - assert.match(spaciousLines[0] ?? '', /^profile Release engineer/u) + assert.match( + spaciousLines[0] ?? '', + /^profile Release engineer · harness pi · model openai-codex\/gpt-5\.6-luna · backend Local CLI Bridge · think high · caps vis 8\.2k · reas 4\.1k · total 12k$/u, + ) assert.match(spaciousLines[1] ?? '', /^in 1\.2k · out 567 · \$0\.0312 · latency 842ms$/u) assert.doesNotMatch(spaciousLines.join('\n'), /(?:^|\n)rofile\b/u) @@ -361,8 +366,10 @@ test('completed notices preserve the persistent route and measured context', () assert.doesNotMatch(standard, /\/ commands|Ctrl\+P/u) const wide = chrome.render(120).join('\n') - assert.match(wide, /profile Release engineer · pi \/ openai-codex\/gpt-5\.6-luna/u) - assert.match(wide, /Local CLI Bridge/u) + assert.match( + wide, + /profile Release engineer · harness pi · model openai-codex\/gpt-5\.6-luna · backend Local CLI Bridge/u, + ) assert.match(wide, /Prepared markdown export/u) assert.match(wide, /in 1\.2k/u) assert.match(wide, /out 567/u) diff --git a/test/terminal-usage-status.test.ts b/test/terminal-usage-status.test.ts index b72e1b7..da5b9e0 100644 --- a/test/terminal-usage-status.test.ts +++ b/test/terminal-usage-status.test.ts @@ -25,10 +25,7 @@ test('terminal usage keeps direct, analysis, and worker measurements separate an 'workers in 0 · out 0 · $0.0000 · calls 0 · latency 0ms', ]) - const context = activityDocument(view).context ?? '' - assert.match(context, /in ≥10.*calls ≥2.*latency ≥120ms/u) - assert.doesNotMatch(context, /analysis|unknown|missing/u) - assert.match(context, /workers .*calls 0.*latency 0ms/u) + assert.equal(activityDocument(view).context, undefined) assert.deepEqual(footerMetricsFor(view), ['in ≥10', 'out ≥20', '≥$0.0100', 'latency ≥120ms']) }) @@ -168,14 +165,17 @@ test('execution identity comes from one active run receipt instead of current pr }) const rendered = chrome.render(120).join('\n') assert.match(rendered, /Exact run profile/u) - assert.match(rendered, /pi \/ tangle-router\/glm-5\.2/u) + assert.match(rendered, /harness pi · model tangle-router\/glm-5\.2/u) assert.match(rendered, /CLI Bridge/u) assert.doesNotMatch(rendered, /backend cli-bridge|pi · tangle-router/u) assert.doesNotMatch(rendered, /exec local CLI|active/u) assert.doesNotMatch(rendered, /Next profile|openai\/gpt-next|Next connection/u) + const spacious = chrome.render(200).join('\n') + assert.match(spacious, /backend CLI Bridge · connection Local CLI Bridge/u) + const activity = activityDocument(view) - assert.match(activity.context ?? '', /Exact run profile · pi · tangle-router\/glm-5\.2/u) + assert.equal(activity.context, undefined) const detail = activity.rows[0]?.detailLines.join('\n') ?? '' assert.match(detail, /profile digest: digest-run/u) assert.match(detail, /max visible output tokens: 16384/u) diff --git a/test/w6-ui.test.ts b/test/w6-ui.test.ts index 7eea193..434c61a 100644 --- a/test/w6-ui.test.ts +++ b/test/w6-ui.test.ts @@ -323,7 +323,7 @@ test('stable chrome keeps identity and status outside transcript history', () => assert.doesNotMatch(standard[0] ?? '', /\/ commands/u) assert.doesNotMatch(standard[0] ?? '', /Ctrl\+P/u) const wide = chrome.render(120).join('\n') - assert.match(wide, /reviewer · pi · local/u) + assert.match(wide, /profile reviewer · harness pi · backend local/u) assert.doesNotMatch(wide, /fixture|deterministic|50ms|in 6|out 12/u) for (const line of standard) assert.ok(visibleWidth(line) <= 80) }) From 7e19843217b9d1c9233fb1c5cdc93f54aa8552ff Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 19 Aug 2026 12:31:34 -0600 Subject: [PATCH 20/25] fix(runtime): use public CLI Bridge retained lookup --- package.json | 12 +- pnpm-lock.yaml | 150 ++++++++---------- pnpm-workspace.yaml | 14 +- .../runtime/cli-bridge-retained-run.ts | 137 +--------------- .../runtime/production-cli-bridge-backend.ts | 132 ++++++++++----- test/cli-bridge-retained-restart.test.ts | 2 +- 6 files changed, 180 insertions(+), 267 deletions(-) diff --git a/package.json b/package.json index 71d5b28..5a70193 100644 --- a/package.json +++ b/package.json @@ -99,12 +99,12 @@ "@dataiku/uv": "0.12.0", "@earendil-works/pi-tui": "0.84.2", "@napi-rs/keyring": "1.3.0", - "@tangle-network/agent-eval": "0.145.21", - "@tangle-network/agent-interface": "1.0.0", - "@tangle-network/agent-provider-cli-bridge": "0.7.6", - "@tangle-network/agent-provider-tangle": "0.12.2", - "@tangle-network/agent-runtime": "file:/tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz", - "@tangle-network/sandbox": "0.27.0", + "@tangle-network/agent-eval": "0.149.0", + "@tangle-network/agent-interface": "1.3.0", + "@tangle-network/agent-provider-cli-bridge": "0.9.2", + "@tangle-network/agent-provider-tangle": "0.12.3", + "@tangle-network/agent-runtime": "0.142.3", + "@tangle-network/sandbox": "0.30.0", "better-sqlite3-multiple-ciphers": "13.0.3", "chalk": "6.0.0", "koffi": "3.1.4" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4adccac..1e01a4d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,23 +22,23 @@ importers: specifier: 1.3.0 version: 1.3.0 '@tangle-network/agent-eval': - specifier: 0.145.21 - version: 0.145.21 + specifier: 0.149.0 + version: 0.149.0 '@tangle-network/agent-interface': - specifier: 1.0.0 - version: 1.0.0 + specifier: 1.3.0 + version: 1.3.0 '@tangle-network/agent-provider-cli-bridge': - specifier: 0.7.6 - version: 0.7.6 + specifier: 0.9.2 + version: 0.9.2 '@tangle-network/agent-provider-tangle': - specifier: 0.12.2 - version: 0.12.2(@tangle-network/sandbox@0.27.0) + specifier: 0.12.3 + version: 0.12.3(@tangle-network/sandbox@0.30.0) '@tangle-network/agent-runtime': - specifier: file:/tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz - version: file:../../../../../tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz(@tangle-network/agent-eval@0.145.21)(@tangle-network/agent-interface@1.0.0)(@tangle-network/sandbox@0.27.0) + specifier: 0.142.3 + version: 0.142.3(@tangle-network/agent-eval@0.149.0)(@tangle-network/agent-interface@1.3.0)(@tangle-network/sandbox@0.30.0) '@tangle-network/sandbox': - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.30.0 + version: 0.30.0 better-sqlite3-multiple-ciphers: specifier: 13.0.3 version: 13.0.3 @@ -503,14 +503,6 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} - '@tangle-network/agent-core@0.9.0': - resolution: {integrity: sha512-AStqQ8EERP4B/vHThs+ZfdD784ZKHsv/GmwVwv2N3XEVztGVVr0xTApc30U1hmTrkKkBK6jFAb+b/uG+Y7vH5A==} - peerDependencies: - '@modelcontextprotocol/sdk': ^1.30.0 - peerDependenciesMeta: - '@modelcontextprotocol/sdk': - optional: true - '@tangle-network/agent-core@0.9.4': resolution: {integrity: sha512-2iSPCHPKI/9A4t1XXPTbpaJTzf3BkwNzXOJfb3M7AMjpIGR1SKNiRHKpDTTEUVbfx4tRny5qDDMhCnFmKgPsHA==} peerDependencies: @@ -519,47 +511,43 @@ packages: '@modelcontextprotocol/sdk': optional: true - '@tangle-network/agent-eval@0.145.21': - resolution: {integrity: sha512-BeNIO8/+AJwQ8KYeJ1juqZT9gqQkaWwfLhX7KLQUo7LkRF++tBfulvARGesOpVHorx0fEkheJiyGMM5Tsx8IGQ==} + '@tangle-network/agent-eval@0.149.0': + resolution: {integrity: sha512-zCU+hhfAhQOPOBCHCErQfFaKTEMdtUWlUR/ZfHqQw6gPPBhHk/+VaFiP4reCca3RfBkUnJtTQyoocqOH+L449w==} engines: {node: '>=20'} hasBin: true - '@tangle-network/agent-interface@0.53.0': - resolution: {integrity: sha512-XWH+4t9vPkVog9C9P+094USuoO//TJwaI+P6ntAm32wHqZ/kh5a9r6kSkHYMKsXgQjkY3IA5NO21w3rZ7M6U+g==} - - '@tangle-network/agent-interface@1.0.0': - resolution: {integrity: sha512-rhXoscOE1TwkLvHg3tfqdumz++kcDRf7c5GRSTBnJkKLVypwvXB5yQJCB4aTUTrOCJxJMqowm2VPOmlTrUszOQ==} + '@tangle-network/agent-interface@1.3.0': + resolution: {integrity: sha512-FsuSUkWyEvpGIjp9ENX3yrcXD8G7QhnVIoepknRYaPaaCaDPlHJzF483mBNix1GZ2bTU3aCr2KgHDSUdcjn1kg==} - '@tangle-network/agent-knowledge@8.0.5': - resolution: {integrity: sha512-QMY16NSdy7aLxZZDejrb17hlUb6ejh4rg5Keg1TfA+FDMeIbyCaTSx6I/CFmK27TQq5aZ0RoIgaa1lZVc5rDRg==} + '@tangle-network/agent-knowledge@8.0.10': + resolution: {integrity: sha512-QOEIXt1t8iCjSNX7do6wqqUoZ8SQYjg5wIgX+Yi4877tnwEHZAQ41g6ibmtoYfPebBFtos2EU4jctJv7oK6T7w==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: - '@tangle-network/agent-eval': '>=0.145.21 <0.146.0' - '@tangle-network/agent-interface': ^1.0.0 + '@tangle-network/agent-eval': '>=0.149.0 <0.150.0' + '@tangle-network/agent-interface': ^1.1.0 - '@tangle-network/agent-profile-materialize@0.15.2': - resolution: {integrity: sha512-j9ld23ADJRbAIJEkQ0xk49+RYt47WzARquN5S3W5Pyb3rbD++gxf1AKJQ3O613wmkwdcc0V10a5jHruX0SZ1Vg==} + '@tangle-network/agent-profile-materialize@0.16.0': + resolution: {integrity: sha512-jNBkA91yTYtmdtWxqvGI9wgKsykp9fiRbWmgvlm7Kimi0Fjz7MiAXZnX1RW5yaqLSdPvzKVBOycVXjqk1/dSmQ==} peerDependencies: - '@tangle-network/agent-interface': '>=0.47.0 <0.54.0' + '@tangle-network/agent-interface': ^1.0.0 - '@tangle-network/agent-provider-cli-bridge@0.7.6': - resolution: {integrity: sha512-/UlWHwBRcFVfIZUlZHrcr1PYEl+Uz7ldYi/NU5VLCi/SmcIeCpqJKgRXDXvtzI79YtyBjfBfjom6tVEDU8pZbQ==} + '@tangle-network/agent-provider-cli-bridge@0.9.2': + resolution: {integrity: sha512-MIMjU5+YPOD37g1BChjvtYXsy5SYV1mo4O1jF0mOIrG/CajOQPLvbZAV3FpvmIijxUBChAkzYxU+JVq1sbGFKw==} - '@tangle-network/agent-provider-tangle@0.12.2': - resolution: {integrity: sha512-+cQscgYrUANqAFdOEXGvqC9WMQu3BJtlreYWGVtPseYQGOzZAOl+MyCzA9NR4wVQOgGrDxG/lkSazTRtlvPDKg==} + '@tangle-network/agent-provider-tangle@0.12.3': + resolution: {integrity: sha512-tOTEF5z0C39474b0PU3gCU60yHKXZIKfEitB3O8xvXrafaOaVpR1WuQcYi3Cypj42hFZJ+A5kazbzSCPv0ZMeg==} peerDependencies: '@tangle-network/sandbox': '>=0.23.0 <1.0.0' - '@tangle-network/agent-runtime@file:../../../../../tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz': - resolution: {integrity: sha512-QIb6bzfb5gn9qGeHKkjTHm24qyCtLXRJDVwNeR2NNmH0udf5LaZlmasD1ZOslrdXzCc2XaUOEljaHA/cLZqTwg==, tarball: file:../../../../../tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz} - version: 0.137.0 + '@tangle-network/agent-runtime@0.142.3': + resolution: {integrity: sha512-5Sm5dG+TunyY6N+CdNFPs4mYjT39wdtRMfXB8N7DjAnn2YGsepPFvwEGDItaFdABcppZ2aqxJqrm6dc7njBnzA==} engines: {node: '>=22.13.0'} hasBin: true peerDependencies: - '@tangle-network/agent-eval': '>=0.145.21 <0.146.0' - '@tangle-network/agent-interface': '>=1.0.0 <2.0.0' - '@tangle-network/sandbox': '>=0.27.0 <0.29.0' + '@tangle-network/agent-eval': '>=0.149.0 <0.150.0' + '@tangle-network/agent-interface': ^1.1.0 + '@tangle-network/sandbox': '>=0.29.0 <0.31.0' peerDependenciesMeta: '@tangle-network/sandbox': optional: true @@ -567,8 +555,8 @@ packages: '@tangle-network/agent-trace-contract@1.0.2': resolution: {integrity: sha512-v7uMh56jkEp4vckevEU9xKsIatbs5dqzGPp69dFLSSXUVit0RP6VD6EANMXVlTCUk+6wVKBLHJx23XspVCEiIA==} - '@tangle-network/sandbox@0.27.0': - resolution: {integrity: sha512-a7qOi7yD/a40FNYrQG8kabaGUV3ACDl5Mb8Fh+WXR3C4dCgQmY2K7kZwhkbZBSr3gINaGO/LZR9Hjddl5yakZg==} + '@tangle-network/sandbox@0.30.0': + resolution: {integrity: sha512-QDqVoT2AM/Or/okZ86agZN1rlSHc/E1fugnR2k3oEJKDdgQyuwuikfED2WVLZChu2idkc7gcg4JEEVwzeBSoUw==} peerDependencies: '@mastra/core': ^1.36.0 '@modelcontextprotocol/sdk': ^1.30.0 @@ -590,6 +578,12 @@ packages: '@types/node@26.2.0': resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} + '@types/proper-lockfile@4.1.4': + resolution: {integrity: sha512-uo2ABllncSqg9F1D4nugVl9v93RmjxF6LJzQLMLDdPaXCUIDPeOJ21Gbqi43xNKzBi/WQ0Q0dICqufzQbMjipQ==} + + '@types/retry@0.12.5': + resolution: {integrity: sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==} + '@typescript/typescript-aix-ppc64@7.0.2': resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} engines: {node: '>=16.20.0'} @@ -1153,22 +1147,17 @@ snapshots: '@noble/hashes@1.8.0': {} - '@tangle-network/agent-core@0.9.0': - dependencies: - '@tangle-network/agent-interface': 0.53.0 - zod: 4.4.3 - '@tangle-network/agent-core@0.9.4': dependencies: - '@tangle-network/agent-interface': 1.0.0 + '@tangle-network/agent-interface': 1.3.0 zod: 4.4.3 - '@tangle-network/agent-eval@0.145.21': + '@tangle-network/agent-eval@0.149.0': dependencies: '@asteasolutions/zod-to-openapi': 9.1.0(zod@4.4.3) '@hono/node-server': 2.1.1(hono@4.13.0) '@tangle-network/agent-core': 0.9.4 - '@tangle-network/agent-interface': 1.0.0 + '@tangle-network/agent-interface': 1.3.0 '@tangle-network/agent-trace-contract': 1.0.2 hono: 4.13.0 linear-sum-assignment: 1.0.9 @@ -1177,50 +1166,45 @@ snapshots: transitivePeerDependencies: - '@modelcontextprotocol/sdk' - '@tangle-network/agent-interface@0.53.0': - dependencies: - '@noble/hashes': 1.8.0 - spdx-expression-parse: 5.0.0 - zod: 4.4.3 - - '@tangle-network/agent-interface@1.0.0': + '@tangle-network/agent-interface@1.3.0': dependencies: '@noble/hashes': 1.8.0 spdx-expression-parse: 5.0.0 zod: 4.4.3 - '@tangle-network/agent-knowledge@8.0.5(@tangle-network/agent-eval@0.145.21)(@tangle-network/agent-interface@1.0.0)': + '@tangle-network/agent-knowledge@8.0.10(@tangle-network/agent-eval@0.149.0)(@tangle-network/agent-interface@1.3.0)': dependencies: - '@tangle-network/agent-eval': 0.145.21 - '@tangle-network/agent-interface': 1.0.0 + '@tangle-network/agent-eval': 0.149.0 + '@tangle-network/agent-interface': 1.3.0 + '@types/proper-lockfile': 4.1.4 proper-lockfile: 4.1.2 zod: 4.4.3 - '@tangle-network/agent-profile-materialize@0.15.2(@tangle-network/agent-interface@1.0.0)': + '@tangle-network/agent-profile-materialize@0.16.0(@tangle-network/agent-interface@1.3.0)': dependencies: - '@tangle-network/agent-interface': 1.0.0 + '@tangle-network/agent-interface': 1.3.0 - '@tangle-network/agent-provider-cli-bridge@0.7.6': + '@tangle-network/agent-provider-cli-bridge@0.9.2': dependencies: - '@tangle-network/agent-interface': 1.0.0 + '@tangle-network/agent-interface': 1.3.0 undici: 7.29.0 - '@tangle-network/agent-provider-tangle@0.12.2(@tangle-network/sandbox@0.27.0)': + '@tangle-network/agent-provider-tangle@0.12.3(@tangle-network/sandbox@0.30.0)': dependencies: - '@tangle-network/agent-interface': 1.0.0 - '@tangle-network/sandbox': 0.27.0 + '@tangle-network/agent-interface': 1.3.0 + '@tangle-network/sandbox': 0.30.0 - '@tangle-network/agent-runtime@file:../../../../../tmp/braid-runtime-pack-UUBQAJ/tangle-network-agent-runtime-0.137.0.tgz(@tangle-network/agent-eval@0.145.21)(@tangle-network/agent-interface@1.0.0)(@tangle-network/sandbox@0.27.0)': + '@tangle-network/agent-runtime@0.142.3(@tangle-network/agent-eval@0.149.0)(@tangle-network/agent-interface@1.3.0)(@tangle-network/sandbox@0.30.0)': dependencies: '@tangle-network/agent-core': 0.9.4 - '@tangle-network/agent-eval': 0.145.21 - '@tangle-network/agent-interface': 1.0.0 - '@tangle-network/agent-knowledge': 8.0.5(@tangle-network/agent-eval@0.145.21)(@tangle-network/agent-interface@1.0.0) - '@tangle-network/agent-profile-materialize': 0.15.2(@tangle-network/agent-interface@1.0.0) + '@tangle-network/agent-eval': 0.149.0 + '@tangle-network/agent-interface': 1.3.0 + '@tangle-network/agent-knowledge': 8.0.10(@tangle-network/agent-eval@0.149.0)(@tangle-network/agent-interface@1.3.0) + '@tangle-network/agent-profile-materialize': 0.16.0(@tangle-network/agent-interface@1.3.0) '@tangle-network/agent-trace-contract': 1.0.2 tar-stream: 3.2.0 optionalDependencies: - '@tangle-network/sandbox': 0.27.0 + '@tangle-network/sandbox': 0.30.0 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - bare-abort-controller @@ -1229,16 +1213,22 @@ snapshots: '@tangle-network/agent-trace-contract@1.0.2': {} - '@tangle-network/sandbox@0.27.0': + '@tangle-network/sandbox@0.30.0': dependencies: - '@tangle-network/agent-core': 0.9.0 - '@tangle-network/agent-interface': 0.53.0 + '@tangle-network/agent-core': 0.9.4 + '@tangle-network/agent-interface': 1.3.0 zod: 4.4.3 '@types/node@26.2.0': dependencies: undici-types: 8.3.0 + '@types/proper-lockfile@4.1.4': + dependencies: + '@types/retry': 0.12.5 + + '@types/retry@0.12.5': {} + '@typescript/typescript-aix-ppc64@7.0.2': optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ac8970a..9e0530c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,14 +9,14 @@ allowBuilds: node-pty: true ignoreScripts: false minimumReleaseAgeExclude: - - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5 || 0.134.9 || 0.135.0 || 0.135.3' - - '@tangle-network/agent-eval@0.143.0 || 0.144.0 || 0.144.1 || 0.144.3 || 0.144.4 || 0.144.6 || 0.144.8 || 0.144.10 || 0.144.11 || 0.144.13 || 0.145.0 || 0.145.1 || 0.145.2 || 0.145.3 || 0.145.9 || 0.145.10 || 0.145.11 || 0.145.14 || 0.145.15 || 0.145.21' - - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0 || 0.53.0 || 0.54.0 || 1.0.0' - - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0 || 8.0.1 || 8.0.5' + - '@tangle-network/agent-runtime@0.126.0 || 0.128.0 || 0.131.0 || 0.131.1 || 0.131.2 || 0.131.3 || 0.131.4 || 0.131.5 || 0.131.6 || 0.131.7 || 0.132.0 || 0.132.4 || 0.132.6 || 0.132.9 || 0.132.10 || 0.132.11 || 0.132.12 || 0.133.6 || 0.134.2 || 0.134.4 || 0.134.5 || 0.134.9 || 0.135.0 || 0.135.3 || 0.142.0 || 0.142.1 || 0.142.3' + - '@tangle-network/agent-eval@0.143.0 || 0.144.0 || 0.144.1 || 0.144.3 || 0.144.4 || 0.144.6 || 0.144.8 || 0.144.10 || 0.144.11 || 0.144.13 || 0.145.0 || 0.145.1 || 0.145.2 || 0.145.3 || 0.145.9 || 0.145.10 || 0.145.11 || 0.145.14 || 0.145.15 || 0.145.21 || 0.149.0' + - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0 || 0.53.0 || 0.54.0 || 1.0.0 || 1.1.0 || 1.3.0' + - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0 || 8.0.1 || 8.0.5 || 8.0.10' - '@tangle-network/agent-profile-materialize@0.10.2 || 0.13.1 || 0.14.0 || 0.14.2 || 0.15.1 || 0.15.2' - - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2 || 0.7.3 || 0.7.6' - - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0 || 0.11.0 || 0.11.1 || 0.11.2 || 0.12.2' - - '@tangle-network/sandbox@0.17.3 || 0.18.0 || 0.19.2 || 0.19.3 || 0.19.4 || 0.19.5 || 0.19.6 || 0.21.0 || 0.21.1 || 0.26.1 || 0.27.0' + - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2 || 0.7.3 || 0.7.6 || 0.8.0 || 0.8.1 || 0.9.0 || 0.9.2' + - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0 || 0.11.0 || 0.11.1 || 0.11.2 || 0.12.2 || 0.12.3' + - '@tangle-network/sandbox@0.17.3 || 0.18.0 || 0.19.2 || 0.19.3 || 0.19.4 || 0.19.5 || 0.19.6 || 0.21.0 || 0.21.1 || 0.26.1 || 0.27.0 || 0.29.0 || 0.30.0' - hono@4.13.0 - '@esbuild/aix-ppc64@0.28.2' - '@esbuild/android-arm64@0.28.2' diff --git a/src/adapters/runtime/cli-bridge-retained-run.ts b/src/adapters/runtime/cli-bridge-retained-run.ts index 7a20f06..c8ad7cb 100644 --- a/src/adapters/runtime/cli-bridge-retained-run.ts +++ b/src/adapters/runtime/cli-bridge-retained-run.ts @@ -1,9 +1,5 @@ -import { - type AgentExactRunControlRef, - AgentExactRunControlRefSchema, -} from '@tangle-network/agent-interface' -import type { AgentEnvironmentProvider } from '@tangle-network/agent-interface/environment-provider' -import type { BridgeModelCredential } from '@tangle-network/agent-runtime/kernel' +import type { AgentExactRunControlRef } from '@tangle-network/agent-interface' +import type { CliBridgeProvider } from '@tangle-network/agent-provider-cli-bridge' import { type RetainedRunHandle, reconnectRetainedRun, @@ -19,7 +15,6 @@ import type { RetainedRunAdmissionRecord, RetainedRunAdmissionRecorder, } from '../../ports/execution.js' -import { isLoopbackEndpoint } from '../connections/production-connection-endpoints.js' import { safeExecutionId, stableProviderId } from './production-backend-common.js' import type { PreparedCliBridgeConnection } from './production-cli-bridge-backend.js' import type { @@ -35,11 +30,9 @@ import { retainedTurnUsage, } from './retained-execution-projection.js' -const MAX_STATUS_BYTES = 64 * 1024 - export interface CliBridgeRetainedPlan extends RetainedExecutionPlan { readonly prepared: PreparedCliBridgeConnection - readonly provider: AgentEnvironmentProvider + readonly provider: CliBridgeProvider readonly environmentId?: string readonly environmentIdempotencyKey: string readonly executionId: string @@ -56,17 +49,7 @@ export async function createCliBridgeRetainedPlan( controlRef?: AgentExactRunControlRef, recovery?: RetainedExecutionRecoveryContext, ): Promise { - const { createCliBridgeProvider } = await import('@tangle-network/agent-provider-cli-bridge') - const provider = createCliBridgeProvider({ - baseUrl: prepared.bridgeUrl, - bearerToken: prepared.bearerToken, - defaultModel: prepared.route, - capabilities: prepared.capabilities, - ...(prepared.fetch === undefined ? {} : { fetch: prepared.fetch }), - ...(prepared.bridgeModelCredential === undefined - ? {} - : { fetch: bridgeCredentialFetch(prepared) }), - }) + const provider = prepared.provider const admission = headlessRetainedAdmission(recovery?.retainedAdmission) if (admission !== undefined && admissionProvider(admission) !== provider.name) { throw new Error('retained CLI Bridge admission belongs to another provider') @@ -91,7 +74,7 @@ export async function createCliBridgeRetainedPlan( const environmentIdempotencyKey = admission?.idempotencyKey ?? retainedEnvironmentIdempotencyKey(runId) const providerName = provider.name - const capabilities = retainedCapabilities(prepared.capabilities) + const capabilities = retainedCapabilities(await provider.capabilities()) const materializationReceipt = publicMaterializationReceipt({ ...prepared.materializationReceipt, backend: 'environment-provider', @@ -138,58 +121,6 @@ export async function createCliBridgeRetainedPlan( return Object.freeze(plan) } -function bridgeCredentialFetch(prepared: PreparedCliBridgeConnection): typeof fetch { - const credential = prepared.bridgeModelCredential - if (credential === undefined) return prepared.fetch ?? globalThis.fetch - if (!isLoopbackEndpoint(prepared.bridgeUrl)) { - throw new Error('A request-scoped CLI Bridge model credential requires a loopback endpoint') - } - const fetcher = prepared.fetch ?? globalThis.fetch - return async (input, init) => { - const url = new URL( - typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url, - ) - if (url.pathname !== '/v1/chat/completions') return fetcher(input, init) - const [token, baseUrl] = await Promise.all([ - credentialValue(credential, credential.key), - credentialValue(credential, credential.baseUrlKey), - ]) - const upstream = safeModelBaseUrl(baseUrl) - const headers = new Headers(init?.headers) - headers.set('x-cli-bridge-model-credential', token) - headers.set('x-cli-bridge-model-base-url', upstream) - return fetcher(input, { ...init, headers }) - } -} - -async function credentialValue(credential: BridgeModelCredential, key: string): Promise { - let value: string | undefined - try { - value = await credential.provider.get(key) - } catch { - throw new Error(`The CLI Bridge model credential provider failed for ${key}`) - } - if (typeof value !== 'string' || value.length === 0 || /[\r\n\0]/u.test(value)) { - throw new Error(`The CLI Bridge model credential provider has no usable value for ${key}`) - } - return value -} - -function safeModelBaseUrl(value: string): string { - let url: URL - try { - url = new URL(value) - } catch { - throw new Error('The CLI Bridge model credential base URL is invalid') - } - if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) { - throw new Error( - 'The CLI Bridge model credential base URL must be an HTTPS URL without credentials', - ) - } - return url.toString().replace(/\/$/u, '') -} - export async function startCliBridgeRetainedRun( plan: CliBridgeRetainedPlan, input: ExecuteTurnInput, @@ -280,40 +211,12 @@ export async function discoverCliBridgeControlRef( signal?: AbortSignal, ): Promise { if (plan.environmentId === undefined || plan.providerSessionId === undefined) return null - const providerRunId = plan.executionId - const response = await (plan.prepared.fetch ?? globalThis.fetch)( - `${plan.prepared.bridgeUrl}/v1/runs/${encodeURIComponent(providerRunId)}`, - { - method: 'GET', - headers: { authorization: `Bearer ${plan.prepared.bearerToken}` }, - ...(signal === undefined ? {} : { signal }), - }, - ) - if (response.status === 404) return null - if (!response.ok) { - throw new Error(`cli-bridge run discovery returned HTTP ${response.status}`) - } - const body = await boundedResponseText(response) - let value: unknown - try { - value = JSON.parse(body) - } catch { - throw new Error('cli-bridge run discovery returned invalid JSON') - } - if (value === null || typeof value !== 'object' || Array.isArray(value)) { - throw new Error('cli-bridge run discovery returned an invalid run snapshot') - } - const snapshot = value as Record - if (snapshot.id !== providerRunId) { - throw new Error('cli-bridge run discovery returned another run identity') - } - return AgentExactRunControlRefSchema.parse({ - runId: snapshot.id, - provider: plan.provider.name, + return plan.provider.lookupRun({ + runId: plan.executionId, environmentId: plan.environmentId, sessionId: plan.providerSessionId, executionId: plan.executionId, - requestDigest: snapshot.requestDigest, + ...(signal === undefined ? {} : { signal }), }) } @@ -337,27 +240,3 @@ function headlessRetainedAdmission( function admissionProvider(admission: HeadlessRetainedAdmission): string { return admission.phase === 'dispatched' ? admission.controlRef.provider : admission.provider } - -async function boundedResponseText(response: Response): Promise { - if (response.body === null) return '' - const reader = response.body.getReader() - const decoder = new TextDecoder() - const chunks: string[] = [] - let byteLength = 0 - try { - while (true) { - const next = await reader.read() - if (next.done) break - byteLength += next.value.byteLength - if (byteLength > MAX_STATUS_BYTES) { - await reader.cancel('CLI Bridge run discovery response exceeded 64 KiB') - throw new Error('cli-bridge run discovery response exceeded 64 KiB') - } - chunks.push(decoder.decode(next.value, { stream: true })) - } - chunks.push(decoder.decode()) - return chunks.join('') - } finally { - reader.releaseLock() - } -} diff --git a/src/adapters/runtime/production-cli-bridge-backend.ts b/src/adapters/runtime/production-cli-bridge-backend.ts index 2fde4e1..8da82b8 100644 --- a/src/adapters/runtime/production-cli-bridge-backend.ts +++ b/src/adapters/runtime/production-cli-bridge-backend.ts @@ -3,6 +3,7 @@ import type { AgentProfile, HarnessType, } from '@tangle-network/agent-interface' +import type { CliBridgeProvider } from '@tangle-network/agent-provider-cli-bridge' import type { BridgeModelCredential } from '@tangle-network/agent-runtime/kernel' import { ConnectionError } from '../../app/connection-errors.js' import type { ConnectionId } from '../../domain/ids.js' @@ -13,7 +14,10 @@ import { materializeBridgeModelRoute, } from '../connections/cli-bridge-model-route.js' import { readConnectionCredential } from '../connections/production-connection-credentials.js' -import { normalizeCliBridgeProviderBaseUrl } from '../connections/production-connection-endpoints.js' +import { + isLoopbackEndpoint, + normalizeCliBridgeProviderBaseUrl, +} from '../connections/production-connection-endpoints.js' import { endpointLocation, staticExecutionObservation } from './execution-observation-source.js' import type { PreparedExecution } from './prepared-execution.js' import { @@ -41,52 +45,12 @@ export interface PreparedCliBridgeConnection { readonly bridgeModelCredential?: BridgeModelCredential readonly fetch?: typeof fetch readonly providerSessionId: string + readonly provider: CliBridgeProvider readonly capabilities: AgentEnvironmentCapabilities readonly observation: NonNullable readonly materializationReceipt: Readonly> } -export async function resolveCliBridgeBackend( - options: ProductionBackendResolverOptions, - input: ExecuteTurnInput, - selection: ProductionExecutionSelection, - connectionId: ConnectionId, - endpoint: string, -): Promise { - const prepared = await prepareCliBridgeConnection( - options, - input, - selection, - connectionId, - endpoint, - ) - const { createExecutor } = await import('@tangle-network/agent-runtime/kernel') - const backend = Object.freeze({ - kind: 'executor' as const, - factory: createExecutor({ - backend: 'bridge', - bridgeUrl: prepared.bridgeUrl, - bridgeBearer: prepared.bearerToken, - ...(options.bridgeModelCredential === undefined - ? {} - : { modelCredential: options.bridgeModelCredential }), - cwd: prepared.workspace, - sessionId: prepared.providerSessionId, - }), - profile: prepared.profile, - agentRunName: prepared.route, - }) - return freezeExecution({ - kind: 'prepared-execution' as const, - backend, - capabilities: prepared.capabilities, - providerSessionId: prepared.providerSessionId, - cancellation: { kind: 'runtime-executor-teardown' }, - observation: prepared.observation, - materializationReceipt: prepared.materializationReceipt, - }) -} - export async function prepareCliBridgeConnection( options: ProductionBackendResolverOptions, input: ExecuteTurnInput, @@ -120,7 +84,23 @@ export async function prepareCliBridgeConnection( const bridgeUrl = normalizeCliBridgeProviderBaseUrl(endpoint, connectionId) const bridgeLocation = endpointLocation(bridgeUrl) const createdAt = new Date().toISOString() - const { defaultCliBridgeCapabilities } = await import('@tangle-network/agent-provider-cli-bridge') + const { createCliBridgeProvider } = await import('@tangle-network/agent-provider-cli-bridge') + const providerFetch = + options.bridgeModelCredential === undefined + ? options.fetch + : bridgeCredentialFetch( + bridgeUrl, + options.bridgeModelCredential, + options.fetch ?? globalThis.fetch, + ) + const providerOptions = { + baseUrl: bridgeUrl, + bearerToken: credential ?? LOCAL_BRIDGE_BEARER, + defaultModel: route, + ...(providerFetch === undefined ? {} : { fetch: providerFetch }), + } + const provider = createCliBridgeProvider(providerOptions) + const capabilities = await provider.capabilities() return freezeExecution({ profile, model, @@ -133,7 +113,8 @@ export async function prepareCliBridgeConnection( ? {} : { bridgeModelCredential: options.bridgeModelCredential }), ...(options.fetch === undefined ? {} : { fetch: options.fetch }), - capabilities: defaultCliBridgeCapabilities(runner), + provider, + capabilities, providerSessionId, observation: staticExecutionObservation({ kind: bridgeLocation.location === 'local' ? 'local-process' : 'remote-service', @@ -166,3 +147,66 @@ export async function prepareCliBridgeConnection( }, }) } + +function bridgeCredentialFetch( + bridgeUrl: string, + credential: BridgeModelCredential, + fetcher: typeof fetch, +): typeof fetch { + if (!isLoopbackEndpoint(bridgeUrl)) { + throw new Error('A request-scoped CLI Bridge model credential requires a loopback endpoint') + } + return async (input, init) => { + const url = new URL( + typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url, + ) + if (!usesBridgeModelCredential(url, init)) return fetcher(input, init) + const [token, baseUrl] = await Promise.all([ + credentialValue(credential, credential.key), + credentialValue(credential, credential.baseUrlKey), + ]) + const upstream = safeModelBaseUrl(baseUrl) + const headers = new Headers(init?.headers) + headers.set('x-cli-bridge-model-credential', token) + headers.set('x-cli-bridge-model-base-url', upstream) + return fetcher(input, { ...init, headers }) + } +} + +function usesBridgeModelCredential(url: URL, init?: RequestInit): boolean { + const method = init?.method?.toUpperCase() ?? 'GET' + if (method !== 'POST') return false + return ( + url.pathname === '/v1/chat/completions' || + url.pathname === '/v1/sessions' || + /^\/v1\/sessions\/[^/]+\/(?:turns|continue)$/u.test(url.pathname) + ) +} + +async function credentialValue(credential: BridgeModelCredential, key: string): Promise { + let value: string | undefined + try { + value = await credential.provider.get(key) + } catch { + throw new Error(`The CLI Bridge model credential provider failed for ${key}`) + } + if (typeof value !== 'string' || value.length === 0 || /[\r\n\0]/u.test(value)) { + throw new Error(`The CLI Bridge model credential provider has no usable value for ${key}`) + } + return value +} + +function safeModelBaseUrl(value: string): string { + let url: URL + try { + url = new URL(value) + } catch { + throw new Error('The CLI Bridge model credential base URL is invalid') + } + if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) { + throw new Error( + 'The CLI Bridge model credential base URL must be an HTTPS URL without credentials', + ) + } + return url.toString().replace(/\/$/u, '') +} diff --git a/test/cli-bridge-retained-restart.test.ts b/test/cli-bridge-retained-restart.test.ts index c6dcf16..4d112c6 100644 --- a/test/cli-bridge-retained-restart.test.ts +++ b/test/cli-bridge-retained-restart.test.ts @@ -489,7 +489,7 @@ test('restart discovery rejects a status response for another CLI Bridge run', a } await assert.rejects( restarted.execution.status({ runId, retainedAdmission: environmentAdmission }), - /another run identity/u, + /another (?:retained )?run identity/u, ) assert.equal(bridge.requests.length, 1) } finally { From 938b0d1359890aaf3a32ee68acf76da881374764 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Thu, 20 Aug 2026 04:27:10 -0600 Subject: [PATCH 21/25] test(live): tighten Braid cloud proof assertions --- .../2026-08-20T10-24-46Z/findings.jsonl | 9 + .../2026-08-20T10-24-46Z/manifest.json | 39 + .../2026-08-20T10-24-46Z/summary.md | 43 + scripts/live-required/contracts.mjs | 97 +- scripts/live-required/headless.mjs | 4 +- .../tangle-sandbox-braid-interactive.mjs | 991 ++++++++++++++++++ test/tangle-live07-wiring.test.mjs | 106 +- 7 files changed, 1283 insertions(+), 6 deletions(-) create mode 100644 .agent/critical-audit/2026-08-20T10-24-46Z/findings.jsonl create mode 100644 .agent/critical-audit/2026-08-20T10-24-46Z/manifest.json create mode 100644 .agent/critical-audit/2026-08-20T10-24-46Z/summary.md create mode 100644 scripts/live-required/tangle-sandbox-braid-interactive.mjs diff --git a/.agent/critical-audit/2026-08-20T10-24-46Z/findings.jsonl b/.agent/critical-audit/2026-08-20T10-24-46Z/findings.jsonl new file mode 100644 index 0000000..3fe6abc --- /dev/null +++ b/.agent/critical-audit/2026-08-20T10-24-46Z/findings.jsonl @@ -0,0 +1,9 @@ +{"id":1,"severity":"HIGH","status":"fixed","file":"scripts/live-required/contracts.mjs:490-501","defect":"A passed interactive receipt accepted status-only observations.","scenario":"A caller supplied valid-looking identity and true facts with observations {status: 'passed'}; proofReceipt returned passed without structured runtime evidence.","evidence":"Before fix: Luna inline proofReceipt probe exited 0 with status=passed. After fix: node --test scripts/live-required.test.mjs test/tangle-live07-wiring.test.mjs -> 28/28, including status-only rejection.","fix":"Require checks, configuration, run, sandbox, identityContinuity, and processCleanup records.","verification":"test/tangle-live07-wiring.test.mjs:217-226"} +{"id":2,"severity":"HIGH","status":"open-live-boundary","file":"scripts/live-bridge/process-tree.mjs:9-35","defect":"POSIX cleanup proves only the original process group, not escaped descendants.","scenario":"A PTY child starts a detached setsid child; the parent exits, processGroupStatus returns gone=true, and cleanup can remove HOME/workspace while the detached child remains alive.","evidence":"Luna PTY probe: gone=true, aliveAfterParentExit=true; process-tree smoke only proves group status.","fix":"Use a cgroup, job object, or supervised descendant registry before deleting runtime state.","verification":"Add a real detached-descendant test and require zero owned processes before cleanup.","costIfShipped":"1 workspace deletion with a live owned child per affected run","savedIfFixed":"1 unsafe cleanup prevented per affected run"} +{"id":3,"severity":"MEDIUM","status":"open","file":"scripts/live-required/tangle-sandbox-braid-interactive.mjs:442-447","defect":"Interactive cleanup verifies and deletes one control-reference resource, not the complete Braid-owned retained resource set.","scenario":"The run creates a second Braid-owned retained Sandbox with the same session metadata but another environment ID; exact control-ref deletion passes while the second resource remains.","evidence":"Code performs one observe/get/delete/get through cleanupRetainedResourceByControlRef; soak has the broader owned-set census, but LIVE-08 does not.","fix":"Reuse a shared owned-resource census and require exactly one match before deletion and zero remaining matches after deletion.","verification":"Add a live cleanup test that creates two owned retained resources and expects LIVE-08 failure.","costIfShipped":"1 retained resource leak per duplicate-resource run","savedIfFixed":"1 duplicate-resource leak prevented per duplicate-resource run"} +{"id":4,"severity":"MEDIUM","status":"open","file":"scripts/live-required/tangle-sandbox-braid-interactive.mjs:778-784","defect":"The interactive input assertion counts raw PTY echo, not provider acceptance or response.","scenario":"The local terminal echoes input while Pi or the provider ignores it; occurrence count increases and the input check passes.","evidence":"Code waits only for occurrences(runtime.output, markers.input); no provider-bound event or response contains the marker.","fix":"Require a run-bound provider event or response for each input marker.","verification":"Add a live fault test that forces local echo without provider delivery and expects failure.","costIfShipped":"1 false input-success claim per ignored input","savedIfFixed":"1 false input-success claim prevented per ignored input"} +{"id":5,"severity":"MEDIUM","status":"open-live-boundary","file":"scripts/live-required/tangle-sandbox-braid-soak.mjs:399-454","defect":"Replay checks prove no duplicate visible delivery, not provider-side exactly-once execution.","scenario":"A provider executes one executionId twice but emits one deduplicated event stream; event IDs, cursors, and local run count remain valid, so the proof passes.","evidence":"Code validates visible event uniqueness and cursor progress; no provider execution-attempt receipt or side-effect counter exists.","fix":"Require a provider execution receipt or an idempotent side-effect counter for exactly-once claims.","verification":"Run a provider fault test that duplicates execution and verify the proof fails.","costIfShipped":"1 hidden duplicate execution per provider retry fault","savedIfFixed":"1 hidden duplicate execution detected per provider retry fault"} +{"id":6,"severity":"MEDIUM","status":"open","file":"scripts/live-required/tangle-sandbox-braid-interactive.mjs:383-389","defect":"Interactive event order is now required, but input and terminal attach causality remain live-only.","scenario":"A local TUI accepts /attach or input while the remote session ignores the operation; identity and terminal geometry still look stable.","evidence":"The script checks ordered lifecycle events and remote geometry, but input waits on PTY output and attach has no provider acknowledgement field.","fix":"Require provider-bound input acknowledgement and an attach acknowledgement tied to the same control reference.","verification":"Run the real Pi Sandbox path with injected ignored input/attach responses.","costIfShipped":"1 false interactive-success claim per ignored remote operation","savedIfFixed":"1 false interactive-success claim prevented per ignored remote operation"} +{"id":7,"severity":"MEDIUM","status":"open","file":"scripts/live-required/tangle-sandbox-braid-interactive.mjs:896-934","defect":"LIVE-08 does not collect token, cost, latency, account-usage, or resource-usage telemetry.","scenario":"The interactive run passes with model and resource identity but its usage and spend remain unknown; the receipt has no metric fields.","evidence":"Returned proof contains configuration, run, sandbox identity, and process cleanup; soak-only telemetryDisclosure and sessionSpend are absent from LIVE-08.","fix":"Reuse the existing telemetry and spend disclosure helpers, or label LIVE-08 partial until those fields are observed or explicitly unavailable.","verification":"Require a live interactive receipt with token, cost, latency, and resource metadata statuses.","costIfShipped":"1 interactive run with unreported spend per LIVE-08 run","savedIfFixed":"1 interactive spend gap closed per LIVE-08 run"} +{"id":8,"severity":"MEDIUM","status":"open","file":"scripts/live-required/tangle-sandbox-braid-soak.mjs:855-910","defect":"The soak passes requireZeroActiveResourceDelta=false for the canary and parallel attempts.","scenario":"Another account user creates or deletes resources during the cohort; account-wide active delta is shared and cannot attribute a leak to one proof.","evidence":"test/tangle-sandbox-braid-soak-script.test.mjs explicitly accepts shared account churn; exact per-attempt resource cleanup remains checked.","fix":"Keep shared deltas as non-ownership telemetry and require the final exact owned-resource census for every attempt, or run an exclusive cohort.","verification":"Run an exclusive cohort and assert active delta zero, then run a shared cohort and mark attribution unavailable.","costIfShipped":"1 leak attribution ambiguity per shared cohort","savedIfFixed":"1 leak attribution ambiguity removed per shared cohort"} +{"id":9,"severity":"MEDIUM","status":"open-live-boundary","file":"test/tangle-live07-wiring.test.mjs:129-158","defect":"The local wiring test injects a synthetic LIVE-08 receipt and does not execute runInteractiveProof.","scenario":"A regression in PTY input, attach, resize, or cloud cleanup leaves the wiring test green because the injected runner returns a fabricated passed receipt.","evidence":"node --test test/tangle-live07-wiring.test.mjs -> 5/5; the interactive runner is injected at lines 154-157.","fix":"Add one real provider-backed Pi interactive test; keep the synthetic test for dispatch contract coverage.","verification":"Run the real staging Sandbox proof with credentials and capture a passed receipt.","costIfShipped":"1 undetected LIVE-08 regression per release","savedIfFixed":"1 LIVE-08 regression detected per release"} diff --git a/.agent/critical-audit/2026-08-20T10-24-46Z/manifest.json b/.agent/critical-audit/2026-08-20T10-24-46Z/manifest.json new file mode 100644 index 0000000..c043b0c --- /dev/null +++ b/.agent/critical-audit/2026-08-20T10-24-46Z/manifest.json @@ -0,0 +1,39 @@ +{ + "skill": "critical-audit", + "scope": [ + "scripts/live-required/tangle-sandbox-braid-soak.mjs", + "scripts/live-required/tangle-sandbox-braid-interactive.mjs", + "scripts/live-required/contracts.mjs", + "scripts/live-required/headless.mjs", + "scripts/live-required/tangle-sandbox-braid-stress.mjs", + "scripts/live-required/tangle-sandbox-braid-stress-support.mjs", + "scripts/live-bridge/process.mjs", + "scripts/live-bridge/process-tree.mjs", + "scripts/live-bridge/protocol.mjs", + "scripts/packed-binary.mjs", + "scripts/live-required/configuration.mjs", + "test/tangle-live07-wiring.test.mjs", + "test/tangle-sandbox-braid-soak-script.test.mjs", + "test/tangle-sandbox-braid-stress-script.test.mjs", + "test/tangle-sandbox-braid-stress-runtime.test.mjs", + "scripts/live-bridge/process.test.mjs", + "scripts/live-required.test.mjs" + ], + "base": "3d7b79f6f4f3270821b1b2fcbd777fb411f1ded9", + "head": "7e19843217b9d1c9233fb1c5cdc93f54aa8552ff", + "workingTree": "dirty; audit includes uncommitted Braid changes", + "reviewers": ["operator", "codex-gpt-5.6-luna"], + "liveBoundary": { + "status": "unavailable", + "reason": "Sandbox endpoint/profile and protected credential environment variables were absent" + }, + "checks": [ + "node --check scripts/live-required/tangle-sandbox-braid-interactive.mjs scripts/live-required/tangle-sandbox-braid-soak.mjs scripts/live-required/contracts.mjs scripts/live-required/headless.mjs", + "pnpm exec biome check on the five changed proof files", + "node --test scripts/live-required.test.mjs test/tangle-live07-wiring.test.mjs -> 28/28", + "node --test test/tangle-sandbox-braid-soak-script.test.mjs test/tangle-sandbox-braid-stress-script.test.mjs test/tangle-sandbox-braid-stress-runtime.test.mjs scripts/live-bridge/process.test.mjs -> 41/41", + "node scripts/live-required/tangle-sandbox-braid-interactive.mjs -> unavailable, exit 2", + "node scripts/live-required/tangle-sandbox-braid-soak.mjs -> unavailable, exit 2", + "PTY process-tree smoke -> supported:true, gone:true" + ] +} diff --git a/.agent/critical-audit/2026-08-20T10-24-46Z/summary.md b/.agent/critical-audit/2026-08-20T10-24-46Z/summary.md new file mode 100644 index 0000000..9ad6058 --- /dev/null +++ b/.agent/critical-audit/2026-08-20T10-24-46Z/summary.md @@ -0,0 +1,43 @@ +# Audit: Braid cloud proof path — 3d7b79f..7e19843 — n=17 files, 8 findings + +**Verdict:** REQUEST_CHANGES — no live provider run, and LIVE-08 lacks full telemetry · 0 CRITICAL / 2 HIGH / 6 MEDIUM / 0 LOW + +**Worst:** #2 `scripts/live-bridge/process-tree.mjs:9-35` — process-group exit does not cover escaped descendants · cost if shipped 1 unsafe workspace cleanup/run + +**Next:** run with staging Sandbox credentials, then address #2, #3, #4, and #7 before calling LIVE-08 complete. + +## Scope + +| Field | Value | +|---|---| +| Files | n=17, two requested scripts, direct helpers, and proof tests | +| Base..head | `3d7b79f6f4f3270821b1b2fcbd777fb411f1ded9..7e19843217b9d1c9233fb1c5cdc93f54aa8552ff` plus dirty working tree | +| Project type | Node package with live release scripts | +| Reviewers | operator + codex `gpt-5.6-luna`, serial review | +| Not inspected | agent-dev-container and unrelated Braid production code | + +## Findings — 8 of 9, ranked + +| # | Sev | file:line | Defect | Failure scenario (input/state → wrong result) | Status | Evidence | Fix | Verification | Cost if shipped | Saved if fixed | +|---:|---|---|---|---|---|---|---|---:|---:|---:| +| 1 | HIGH | `scripts/live-required/contracts.mjs:490-501` | Status-only interactive receipts passed. | True facts plus `{status:'passed'}` → passed receipt without runtime sections. | resolved | `node --test ... -> 28/28`; new rejection test at `test/tangle-live07-wiring.test.mjs:217` | Require six structured observation sections. | 28/28 self-tests. | 1 false proof/run | 1 false proof/run | +| 2 | HIGH | `scripts/live-bridge/process-tree.mjs:9-35` | Group status misses escaped descendants. | Detached child survives parent exit → group gone, workspace cleanup runs. | open-live-boundary | Luna PTY probe: `gone:true`, `aliveAfterParentExit:true`. | Use cgroup/job/supervisor ownership. | Add detached-child test and cleanup refusal. | 1 unsafe cleanup/run | 1 unsafe cleanup prevented/run | +| 3 | MEDIUM | `scripts/live-required/tangle-sandbox-braid-interactive.mjs:442-447` | LIVE-08 deletes one exact resource, not the complete owned set. | Second owned Sandbox remains → exact target deletion still passes. | open | One `get/delete/get`; soak has broader census. | Shared owned-resource census. | Live duplicate-resource test. | 1 leak/run | 1 leak prevented/run | +| 4 | MEDIUM | `scripts/live-required/tangle-sandbox-braid-interactive.mjs:778-784` | Input check accepts local PTY echo. | Provider ignores input → echo count advances → input passes. | open | No provider-bound marker check. | Require provider event/response. | Ignored-input live fault test. | 1 false input pass/run | 1 false input pass prevented/run | +| 5 | MEDIUM | `scripts/live-required/tangle-sandbox-braid-soak.mjs:399-454` | Replay does not prove hidden provider exactly-once execution. | Provider runs same execution twice but deduplicates events → proof passes. | open-live-boundary | No execution-attempt receipt. | Provider receipt or side-effect counter. | Duplicate-execution fault test. | 1 hidden duplicate/run | 1 duplicate detected/run | +| 6 | MEDIUM | `scripts/live-required/tangle-sandbox-braid-interactive.mjs:383-389` | Attach/input causality is not provider-bound. | Local operations succeed while remote operation is ignored → stable identity looks valid. | open-live-boundary | Ordered lifecycle events now exist; attach ack/input response absent. | Require provider-bound acknowledgements. | Real Pi Sandbox fault test. | 1 false interactive pass/run | 1 false pass prevented/run | +| 7 | MEDIUM | `scripts/live-required/tangle-sandbox-braid-interactive.mjs:896-934` | LIVE-08 omits spend and resource telemetry. | Run passes with unknown tokens/cost/latency/account usage. | open | Soak has telemetry; interactive does not. | Reuse disclosures or mark partial. | Live receipt metric-status check. | 1 spend gap/run | 1 spend gap closed/run | +| 8 | MEDIUM | `scripts/live-required/tangle-sandbox-braid-soak.mjs:855-910` | Shared cohort delta cannot attribute account churn. | Concurrent external resource activity → account delta is ambiguous. | open | Canary/cohort pass `false`; exact owned cleanup still runs. | Exclusive cohort or explicit unattributed status. | Shared plus exclusive cohort checks. | 1 ambiguous cohort | 1 ambiguity removed/cohort | + +## Assumptions & unverified + +| Assumption | Finding it would flip | Check that settles it | +|---|---:|---| +| Sandbox staging/prod is reachable with current credentials. | 2,3,4,5,6,7,8 | Run both scripts with endpoint, model, runner, and protected credential. | +| Provider event records include causal attach/input acknowledgements. | 4,6 | Inspect one live `--record-state` frame and Sandbox terminal event stream. | +| `tangle-sandbox` resource ownership is unique by control reference. | 3 | List all retained resources before and after LIVE-08. | + +## Self-gate + +9/9 passed — failed: none. +1 verdict = decision + 1 number · 2 every finding has file:line · 3 concrete failure scenario · 4 status label · 5 evidence is a pointer · 6 cost both sides · 7 fix + verification per row · 8 zero adjectives standing in for counts · 9 words ≤600 outside tables. diff --git a/scripts/live-required/contracts.mjs b/scripts/live-required/contracts.mjs index c58121e..8c3f170 100644 --- a/scripts/live-required/contracts.mjs +++ b/scripts/live-required/contracts.mjs @@ -13,6 +13,7 @@ export const PUBLIC_EVIDENCE_SCHEMA = 'braid.live-required.evidence.v1' export const PROOF_OPERATIONS = Object.freeze({ tangleInference: 'tangle.inference.turn', tangleSandbox: 'tangle.sandbox.turn', + tangleSandboxInteractive: 'tangle.sandbox.interactive', traceAnalysis: 'trace.analysis.ask-promote', supervisor: 'supervisor.snapshot-reconnect-steer', }) @@ -33,6 +34,22 @@ const PROOF_OPERATION_CHECKS = Object.freeze({ 'cancel-retry-conflict', 'exact-resource-cleanup', ]), + [PROOF_OPERATIONS.tangleSandboxInteractive]: Object.freeze([ + 'packed-binary', + 'interactive-command', + 'input', + 'detach', + 'reconnect', + 'terminal-resize', + 'same-local-run', + 'same-provider-control-ref', + 'sandbox-observed-before-stop', + 'stop-through-braid', + 'sandbox-observed-stopped', + 'exact-resource-cleanup', + 'process-exited-before-cleanup', + 'process-group-exited-before-cleanup', + ]), [PROOF_OPERATIONS.traceAnalysis]: Object.freeze([ 'source-frozen', 'cited-finding', @@ -55,6 +72,16 @@ const PROOF_OPERATION_FACT_KEYS = Object.freeze({ 'exactResource', 'activeResourceDelta', ]), + [PROOF_OPERATIONS.tangleSandboxInteractive]: Object.freeze([ + 'environmentId', + 'localRunId', + 'stoppedStatus', + 'cloudControl', + 'exactResource', + 'processExitedBeforeWorkspaceCleanup', + 'terminalResize', + 'processGroupExitedBeforeWorkspaceCleanup', + ]), [PROOF_OPERATIONS.traceAnalysis]: Object.freeze([ 'analysisId', 'findingCount', @@ -268,6 +295,10 @@ function validRequiredString(value, label) { throw new Error(`${label} must be a non-empty string`) } +function record(value) { + return value !== null && typeof value === 'object' && !Array.isArray(value) +} + function validateCloudControl(value) { if (value === null) return if (typeof value !== 'object' || Array.isArray(value)) @@ -336,7 +367,13 @@ function validateProofFacts(operation, status, facts) { throw new Error('Live proof usage costUsd must be a non-negative finite number') continue } - if (key === 'promoted' || key === 'cancellationAvailable') { + if ( + key === 'promoted' || + key === 'cancellationAvailable' || + key === 'processExitedBeforeWorkspaceCleanup' || + key === 'terminalResize' || + key === 'processGroupExitedBeforeWorkspaceCleanup' + ) { if (typeof value !== 'boolean') throw new Error(`Live proof ${key} must be boolean`) continue } @@ -412,6 +449,59 @@ function validatePassedTangleSandboxReceipt(receipt) { throw new Error('Passed Tangle Sandbox proof requires redacted observations') } +function validatePassedTangleSandboxInteractiveReceipt(receipt) { + if (receipt.run.ids.length !== 1) + throw new Error('Passed Tangle interactive proof requires one local run ID') + validRequiredString(receipt.run.environmentId, 'Passed Tangle interactive local environmentId') + + const requiredConnectionFields = ['endpoint', 'connectionId', 'connectionKind', 'model', 'runner'] + for (const field of requiredConnectionFields) + validRequiredString(receipt.connection[field], `Passed Tangle interactive connection.${field}`) + if (receipt.connection.connectionKind !== 'tangle-sandbox') + throw new Error('Passed Tangle interactive proof requires a tangle-sandbox connection') + if (receipt.connection.runner !== 'pi') + throw new Error('Passed Tangle interactive proof requires the native Pi harness') + if (receipt.connection.credentialConfigured !== true) + throw new Error('Passed Tangle interactive proof requires configured credentials') + + if (receipt.facts.localRunId !== receipt.run.ids[0]) + throw new Error('Passed Tangle interactive local run identity is inconsistent') + if (receipt.facts.environmentId !== receipt.run.environmentId) + throw new Error('Passed Tangle interactive environment identity is inconsistent') + if (!['aborted', 'cancelled'].includes(receipt.facts.stoppedStatus)) + throw new Error('Passed Tangle interactive proof requires a terminal stopped status') + const cloudControl = receipt.facts.cloudControl + if (cloudControl === null) + throw new Error('Passed Tangle interactive proof requires exact cloud control identity') + for (const field of CLOUD_CONTROL_KEYS) + validRequiredString(cloudControl[field], `Passed Tangle interactive cloudControl.${field}`) + if (cloudControl.provider !== 'tangle-sandbox') + throw new Error('Passed Tangle interactive cloud control identity has the wrong provider') + if (!/^sha256:[0-9a-f]{64}$/u.test(cloudControl.requestDigest)) + throw new Error('Passed Tangle interactive cloud control requestDigest is not a SHA-256 digest') + if (receipt.facts.exactResource !== true) + throw new Error('Passed Tangle interactive proof requires exact resource cleanup') + if (receipt.facts.processExitedBeforeWorkspaceCleanup !== true) + throw new Error('Passed Tangle interactive proof requires process exit before cleanup') + if (receipt.facts.terminalResize !== true) + throw new Error('Passed Tangle interactive proof requires terminal resize evidence') + if (receipt.facts.processGroupExitedBeforeWorkspaceCleanup !== true) + throw new Error('Passed Tangle interactive proof requires process-group exit before cleanup') + if (!record(receipt.observations) || Object.keys(receipt.observations).length === 0) + throw new Error('Passed Tangle interactive proof requires redacted observations') + for (const field of [ + 'checks', + 'configuration', + 'run', + 'sandbox', + 'identityContinuity', + 'processCleanup', + ]) { + if (!record(receipt.observations[field])) + throw new Error(`Passed Tangle interactive proof requires observations.${field}`) + } +} + export function proofInvocation(scope) { if (typeof scope !== 'string' || scope.trim().length === 0) throw new Error('Live proof scope must be a non-empty string') @@ -479,6 +569,11 @@ export function assertProofReceipt(receipt, { invocationId, operation } = {}) { throw new Error('Passed live proof must include every check for the named operation') if (receipt.operation === PROOF_OPERATIONS.tangleSandbox && receipt.status === 'passed') validatePassedTangleSandboxReceipt(receipt) + if ( + receipt.operation === PROOF_OPERATIONS.tangleSandboxInteractive && + receipt.status === 'passed' + ) + validatePassedTangleSandboxInteractiveReceipt(receipt) return receipt } diff --git a/scripts/live-required/headless.mjs b/scripts/live-required/headless.mjs index 61a6b3f..18991d5 100644 --- a/scripts/live-required/headless.mjs +++ b/scripts/live-required/headless.mjs @@ -449,12 +449,14 @@ export async function initializedSession(binary, config, fixture) { } export async function closeSession(session) { + let closed try { if (!session.closed) await rpcRequest(session, 'shutdown', {}, `op-live-required-shutdown-${randomUUID()}`) } finally { - await session.close().catch(() => undefined) + closed = await session.close().catch(() => undefined) } + return closed } export async function rpcState(session, projection = 'full') { diff --git a/scripts/live-required/tangle-sandbox-braid-interactive.mjs b/scripts/live-required/tangle-sandbox-braid-interactive.mjs new file mode 100644 index 0000000..18d4d84 --- /dev/null +++ b/scripts/live-required/tangle-sandbox-braid-interactive.mjs @@ -0,0 +1,991 @@ +import assert from 'node:assert/strict' +import { randomUUID } from 'node:crypto' +import { readFile, rm, writeFile } from 'node:fs/promises' +import { dirname, join, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { + AgentExactRunControlRefSchema, + AgentInteractiveSessionRefSchema, +} from '@tangle-network/agent-interface' +import { Sandbox } from '@tangle-network/sandbox' +import xterm from '@xterm/headless' +import * as pty from 'node-pty' +import { sleep } from '../live-bridge/process.mjs' +import { waitForTreeGone } from '../live-bridge/process-tree.mjs' +import { runFromState, stateForRun } from '../live-bridge/protocol.mjs' +import { installPackedBraid } from '../packed-binary.mjs' +import { connectionConfiguration } from './configuration.mjs' +import { + EXIT_CODES, + PROOF_OPERATIONS, + proofInvocation, + proofReceipt, + protectedUnavailable, + safeJson, + safeMessage, + scalarMeasurement, +} from './contracts.mjs' +import { + closeSession, + configEvidence, + initializedSession, + prepareProductionWorkspace, + rpcRequest, + rpcState, +} from './headless.mjs' +import { + assertVerifiedProcessCleanup, + cleanupRetainedResourceByControlRef, + observeRetainedResource, +} from './tangle-sandbox-braid-stress.mjs' + +const scriptPath = fileURLToPath(import.meta.url) +const repository = resolve(dirname(scriptPath), '../..') +const DEFAULT_TIMEOUT_MS = 180_000 +const DEFAULT_IDLE_TTL_SECONDS = 1_800 +const DEFAULT_PROCESS_EXIT_TIMEOUT_MS = 10_000 +const DETACH = '\u001d' +const RUN_STATUS_AFTER_STOP = new Set(['aborted', 'cancelled']) +const CONTROL_REF_FIELDS = Object.freeze([ + 'provider', + 'environmentId', + 'sessionId', + 'executionId', + 'runId', + 'requestDigest', +]) +const INTERACTIVE_PROOF_CHECKS = Object.freeze([ + 'packed-binary', + 'interactive-command', + 'input', + 'detach', + 'reconnect', + 'terminal-resize', + 'same-local-run', + 'same-provider-control-ref', + 'sandbox-observed-before-stop', + 'stop-through-braid', + 'sandbox-observed-stopped', + 'exact-resource-cleanup', + 'process-exited-before-cleanup', + 'process-group-exited-before-cleanup', +]) +const SECRET_ENVIRONMENT_NAMES = [ + 'BRAID_TANGLE_SANDBOX_AUTH', + 'BRAID_TANGLE_SANDBOX_API_KEY', + 'BRAID_TANGLE_SANDBOX_BEARER', + 'BRAID_TANGLE_SANDBOX_CLEANUP_API_KEY', + 'TANGLE_API_KEY', +] + +function argument(name, argv = process.argv) { + const index = argv.indexOf(`--${name}`) + return index >= 0 && index + 1 < argv.length ? argv[index + 1] : undefined +} + +function positiveEnvironment(environment, name, fallback) { + const value = Number(environment[name]) + return Number.isFinite(value) && value > 0 ? value : fallback +} + +function configurationEnvironment(environment) { + if ( + !environment.BRAID_TANGLE_SANDBOX_CREDENTIAL_REF && + !environment.BRAID_TANGLE_SANDBOX_AUTH && + !environment.BRAID_TANGLE_SANDBOX_API_KEY && + !environment.BRAID_TANGLE_SANDBOX_BEARER && + environment.TANGLE_API_KEY + ) { + return { ...environment, BRAID_TANGLE_SANDBOX_API_KEY: environment.TANGLE_API_KEY } + } + return environment +} + +function sanitizedEnvironment(environment) { + const child = { ...environment } + for (const name of SECRET_ENVIRONMENT_NAMES) delete child[name] + return child +} + +export function sandboxConfiguration(environment) { + return connectionConfiguration(configurationEnvironment(environment), { + prefix: 'BRAID_TANGLE_SANDBOX', + kind: 'tangle-sandbox', + endpointNames: ['BRAID_TANGLE_ENDPOINT'], + modelNames: ['BRAID_TANGLE_MODEL'], + runnerNames: ['BRAID_TANGLE_RUNNER'], + providerNames: ['BRAID_TANGLE_SANDBOX_PROVIDER'], + fallbackEndpoint: 'https://sandbox.tangle.tools', + fallbackModel: 'tangle-router/glm-5.2', + fallbackRunner: 'pi', + fallbackProvider: 'tangle', + }) +} + +export function interactiveProofCommandSequence(markers) { + const input = markers.input ?? markers.inputSeed?.toUpperCase() + const reconnect = markers.reconnect ?? markers.reconnectSeed?.toUpperCase() + return [ + `/interactive Reply with exactly the uppercase version of ${markers.outputSeed}.`, + input, + DETACH, + '/help', + '/attach', + reconnect, + DETACH, + '/help', + ] +} + +function occurrences(value, marker) { + if (!marker) return 0 + let count = 0 + let offset = 0 + while (offset >= 0) { + offset = value.indexOf(marker, offset) + if (offset < 0) break + count += 1 + offset += marker.length + } + return count +} + +function terminalText(terminal) { + let text = '' + for (let row = 0; row < terminal.rows; row += 1) { + text += terminal.buffer.active.getLine(row)?.translateToString(true) ?? '' + text += '\n' + } + return text +} + +async function waitFor(label, predicate, timeoutMs) { + const deadline = performance.now() + timeoutMs + for (;;) { + const value = await predicate() + if (value) return value + if (performance.now() >= deadline) throw new Error(`${label} timed out after ${timeoutMs}ms`) + await sleep(50) + } +} + +function createPty(binary, config, statePath, exitTimeoutMs) { + const terminal = new xterm.Terminal({ cols: 120, rows: 36, allowProposedApi: true }) + const child = pty.spawn(process.execPath, [binary, '--inline', '--record-state', statePath], { + cwd: config.workspace, + env: { + ...config.environment, + BRAID_SHUTDOWN_MODE: 'detach', + NO_COLOR: '1', + NODE_NO_WARNINGS: '1', + }, + name: 'xterm-256color', + cols: 120, + rows: 36, + }) + let output = '' + let exited = false + let exitResult + let processCleanup + const waitForProcessCleanup = async () => { + processCleanup ??= await waitForTreeGone(child, exitTimeoutMs) + return processCleanup + } + child.onData((chunk) => { + output += chunk + terminal.write(chunk) + }) + child.onExit((result) => { + exited = true + exitResult = result + }) + return { + child, + terminal, + get output() { + return output + }, + get screen() { + return terminalText(terminal) + }, + get exited() { + return exited + }, + get processCleanup() { + return processCleanup + }, + write(value) { + child.write(value) + }, + resize(columns, rows) { + assert.ok(Number.isInteger(columns) && columns > 0, 'PTY columns must be positive') + assert.ok(Number.isInteger(rows) && rows > 0, 'PTY rows must be positive') + child.resize(columns, rows) + terminal.resize(columns, rows) + }, + async close() { + if (exited) return { ...exitResult, processCleanup: await waitForProcessCleanup() } + child.write('\u0003') + await waitFor( + 'Braid terminal quit prompt', + () => /Ctrl\+C again to quit/iu.test(this.screen), + exitTimeoutMs, + ) + child.write('\u0003') + const result = await waitFor('Braid terminal exit', () => exited && exitResult, exitTimeoutMs) + return { ...result, processCleanup: await waitForProcessCleanup() } + }, + async forceClose() { + if (!exited) child.kill() + const result = await waitFor( + 'forced Braid terminal exit', + () => exited && exitResult, + exitTimeoutMs, + ) + return { ...result, processCleanup: await waitForProcessCleanup() } + }, + dispose() { + terminal.dispose() + }, + } +} + +async function captureStateFrame(runtime, recordPath, timeoutMs) { + await rm(`${recordPath}.frame`, { force: true }) + process.kill(runtime.child.pid, 'SIGUSR2') + return waitFor( + 'atomic Braid interactive state frame', + async () => { + try { + return JSON.parse(await readFile(`${recordPath}.frame`, 'utf8')) + } catch { + return undefined + } + }, + timeoutMs, + ) +} + +async function proveTuiReturned(runtime, timeoutMs, label) { + const before = runtime.output.length + runtime.write('/help\r') + await waitFor(`${label} returned to Braid`, () => /Commands/iu.test(runtime.screen), timeoutMs) + runtime.write('\u001b') + await waitFor( + `${label} closed the Braid help surface`, + () => !/Commands/iu.test(runtime.screen), + timeoutMs, + ) + return { outputBytes: runtime.output.length - before } +} + +function eventKind(event) { + return event?.kind ?? event?.event?.kind ?? event?.type +} + +function eventRunId(event) { + return event?.runId ?? event?.event?.runId +} + +function assertOrderedRunEvents(events, runId, required) { + let nextIndex = 0 + for (const kind of required) { + const found = events.findIndex( + (event, index) => + index >= nextIndex && + eventKind(event) === kind && + (eventRunId(event) === undefined || eventRunId(event) === runId), + ) + assert.ok(found >= nextIndex, `interactive record omitted ordered ${kind}`) + nextIndex = found + 1 + } +} + +function exactControlRef(value, label) { + const parsed = AgentExactRunControlRefSchema.safeParse(value) + assert.ok(parsed.success, `${label} is not a valid exact Braid control reference`) + return parsed.data +} + +function assertControlRefsEqual(expected, actual, label) { + const expectedRef = exactControlRef(expected, `${label} expected`) + const actualRef = exactControlRef(actual, `${label} actual`) + for (const field of CONTROL_REF_FIELDS) { + assert.equal(actualRef[field], expectedRef[field], `${label}.${field} mismatch`) + } + return actualRef +} + +function interactiveAdmissionIdentity(run) { + const admission = run?.retainedAdmission + assert.equal( + admission?.phase, + 'interactive_started', + 'interactive proof requires the canonical interactive_started admission phase', + ) + assert.equal( + typeof admission?.interactiveIdempotencyKey, + 'string', + 'interactive_started admission omitted interactiveIdempotencyKey', + ) + assert.ok( + admission.interactiveIdempotencyKey.length > 0, + 'interactive_started admission has an empty interactiveIdempotencyKey', + ) + const parsedRef = AgentInteractiveSessionRefSchema.safeParse(admission.ref) + assert.ok(parsedRef.success, 'interactive_started admission ref is invalid') + const controlRef = assertControlRefsEqual( + run.controlRef, + parsedRef.data.run, + 'interactive admission control reference', + ) + if (run.providerSessionId !== undefined) { + assert.equal( + parsedRef.data.run.sessionId, + run.providerSessionId, + 'interactive admission session differs from the stored provider session', + ) + } + return { admission, ref: parsedRef.data, controlRef } +} + +export function recoverInteractiveIdentity(record) { + const runs = Array.isArray(record?.state?.runs) ? record.state.runs : [] + if (runs.length !== 1 || typeof runs[0]?.id !== 'string' || runs[0].id.length === 0) + return undefined + const run = runs[0] + try { + const { admission, ref, controlRef } = interactiveAdmissionIdentity(run) + return { + run, + admission, + ref, + controlRef, + eventKinds: (Array.isArray(record?.events) ? record.events : []).map(eventKind), + } + } catch { + return undefined + } +} + +export function assertInteractiveRecord(record) { + const runs = Array.isArray(record?.state?.runs) ? record.state.runs : [] + assert.equal(runs.length, 1, 'interactive proof must retain exactly one local run') + const run = runs[0] + const { controlRef } = interactiveAdmissionIdentity(run) + assert.equal(controlRef.provider, 'tangle-sandbox') + const events = Array.isArray(record?.events) ? record.events : [] + const kinds = events.map(eventKind) + for (const required of ['run.control.requested', 'run.control.acknowledged', 'run.detached']) { + assert.ok(kinds.includes(required), `interactive record omitted ${required}`) + } + assert.ok(kinds.includes('run.reconnecting'), 'interactive record omitted run.reconnecting') + assertOrderedRunEvents(events, run.id, [ + 'run.control.requested', + 'run.control.acknowledged', + 'run.detached', + 'run.reconnecting', + 'run.detached', + ]) + assert.equal(run.status, 'detached', 'TUI must leave the retained run detached before stop') + return { run, controlRef, eventKinds: kinds } +} + +export function assertStoppedTerminal(terminal) { + if (terminal === null) return { terminal: null, stopped: true } + assert.ok(terminal && typeof terminal === 'object', 'Sandbox terminal observation was invalid') + assert.equal(terminal.isRunning, false, 'Sandbox terminal remained active after Braid stop') + return { terminal, stopped: true } +} + +async function observeSandbox(client, controlRef, timeoutMs, expectedRunning, expectedGeometry) { + const resource = await observeRetainedResource(client, controlRef) + const box = await client.get(controlRef.environmentId) + assert.equal(box?.id, resource.id, 'Sandbox observation changed environment identity') + assert.ok(box.terminals && typeof box.terminals.get === 'function') + let terminal + await waitFor( + expectedRunning ? 'retained interactive terminal' : 'stopped retained interactive terminal', + async () => { + terminal = await box.terminals.get(controlRef.sessionId) + if (terminal !== null) assert.equal(terminal.sessionId, controlRef.sessionId) + if (expectedRunning) { + return ( + terminal?.isRunning === true && + (expectedGeometry === undefined || + (terminal.cols === expectedGeometry.cols && terminal.rows === expectedGeometry.rows)) + ) + } + return terminal === null || terminal?.isRunning === false + }, + timeoutMs, + ) + const stopped = expectedRunning ? undefined : assertStoppedTerminal(terminal) + if (expectedGeometry !== undefined) { + assert.equal( + terminal?.cols, + expectedGeometry.cols, + 'Sandbox terminal columns were not retained', + ) + assert.equal(terminal?.rows, expectedGeometry.rows, 'Sandbox terminal rows were not retained') + } + return { + resource, + terminal, + ...(terminal === null + ? {} + : { geometry: { cols: terminal.cols ?? null, rows: terminal.rows ?? null } }), + ...(stopped ?? {}), + } +} + +async function cleanupExactSandbox(client, identity) { + const observed = await observeRetainedResource(client, identity.controlRef) + const cleanup = await cleanupRetainedResourceByControlRef(client, identity.controlRef) + assert.equal(cleanup.id, observed.id, 'Sandbox cleanup changed the exact Braid resource') + assert.equal(cleanup.id, identity.controlRef.environmentId) + return cleanup +} + +function cleanupFailure(label, error) { + return new Error(`${label}: ${safeMessage(error)}`, { cause: error }) +} + +function assertStopResultMatchesIdentity(stopResult, identity) { + assert.ok(stopResult && typeof stopResult === 'object', 'Braid stop returned no result') + const controlRef = assertControlRefsEqual( + identity.controlRef, + stopResult.controlRef, + 'Braid stop result control reference', + ) + assert.ok( + RUN_STATUS_AFTER_STOP.has(stopResult.run?.status), + 'Braid stop result did not prove a terminal stopped status', + ) + assert.equal( + stopResult.run?.id, + identity.run.id, + 'Braid stop result returned a different local run', + ) + return controlRef +} + +async function attemptCleanup(errors, label, operation) { + try { + return { ok: true, value: await operation() } + } catch (error) { + errors.push(cleanupFailure(label, error)) + return { ok: false, value: undefined } + } +} + +export async function finalizeInteractiveProof({ + packed, + config, + runtime, + recordPath, + identity, + client, + timeoutMs = DEFAULT_TIMEOUT_MS, + exitTimeoutMs = DEFAULT_PROCESS_EXIT_TIMEOUT_MS, + executionStarted = runtime !== undefined, + stopped = false, + stopResult, + stop = ({ binary, targetConfig, runId, timeout }) => + stopThroughBraid(binary, targetConfig, runId, timeout), + observe = (targetClient, controlRef, timeout) => + observeSandbox(targetClient, controlRef, timeout, false), + cleanupSandbox = cleanupExactSandbox, +} = {}) { + const errors = [] + let processExited = runtime === undefined || runtime.exited === true + let processGroupExited = + runtime === undefined || + (runtime.processCleanup?.supported === true && runtime.processCleanup.gone === true) + if (runtime !== undefined && !processExited) { + await attemptCleanup(errors, 'PTY process exit', () => runtime.forceClose(exitTimeoutMs)) + processExited = runtime.exited === true + processGroupExited = + runtime.processCleanup?.supported === true && runtime.processCleanup.gone === true + } + if (runtime !== undefined && processExited) { + await attemptCleanup(errors, 'PTY terminal disposal', () => runtime.dispose?.()) + } + if (runtime !== undefined && !processExited) { + errors.push(new Error('PTY process did not exit; workspace cleanup was refused')) + } + if (runtime !== undefined && processExited && !processGroupExited) { + errors.push(new Error('PTY process group did not exit; workspace cleanup was refused')) + } + + let resolvedIdentity = identity + if (resolvedIdentity === undefined && recordPath !== undefined) { + const recovered = await attemptCleanup(errors, 'recorded Braid identity recovery', async () => { + const record = JSON.parse(await readFile(recordPath, 'utf8')) + const recoveredIdentity = recoverInteractiveIdentity(record) + if (recoveredIdentity === undefined) + throw new Error('recorded state did not contain one exact Braid run identity') + return recoveredIdentity + }) + if (recovered.ok) resolvedIdentity = recovered.value + } + if (executionStarted && resolvedIdentity === undefined) { + errors.push(new Error('Braid run identity was unavailable; exact cloud cleanup was refused')) + } + + let resolvedStop = stopResult + let didStop = false + if (resolvedIdentity !== undefined && resolvedStop !== undefined) { + const verifiedStop = await attemptCleanup(errors, 'Braid stop identity', () => + assertStopResultMatchesIdentity(resolvedStop, resolvedIdentity), + ) + didStop = verifiedStop.ok + } + if (resolvedIdentity !== undefined && resolvedStop === undefined && stopped) { + errors.push(new Error('Braid stop result was unavailable; exact cloud cleanup was refused')) + } else if (resolvedIdentity !== undefined && resolvedStop === undefined) { + if (packed?.binary === undefined || config === undefined) { + errors.push(new Error('Braid stop was unavailable; exact cloud cleanup was refused')) + } else { + const stoppedResult = await attemptCleanup(errors, 'Braid stop', () => + stop({ + binary: packed.binary, + targetConfig: config, + runId: resolvedIdentity.run.id, + timeout: timeoutMs, + }), + ) + if (stoppedResult.ok) { + resolvedStop = stoppedResult.value + const verifiedStop = await attemptCleanup(errors, 'Braid stop identity', () => + assertStopResultMatchesIdentity(resolvedStop, resolvedIdentity), + ) + didStop = verifiedStop.ok + } + } + } + + let afterStop + let cleanup + if (resolvedIdentity !== undefined && didStop && processExited && processGroupExited) { + if (client === undefined) { + errors.push( + new Error('Sandbox observation client was unavailable; exact deletion was refused'), + ) + } else { + const observed = await attemptCleanup(errors, 'stopped Sandbox observation', () => + observe(client, resolvedIdentity.controlRef, timeoutMs), + ) + if (observed.ok) { + afterStop = observed.value + const deleted = await attemptCleanup(errors, 'exact Sandbox deletion', () => + cleanupSandbox(client, resolvedIdentity), + ) + if (deleted.ok) { + cleanup = deleted.value + if ( + cleanup?.confirmed !== true || + cleanup.id !== resolvedIdentity.controlRef.environmentId + ) + errors.push(new Error('exact Sandbox deletion did not return confirmed identity')) + } + } + } + } else if (resolvedIdentity !== undefined && didStop) { + errors.push(new Error('PTY process group did not exit; exact cloud deletion was refused')) + } else if (resolvedIdentity !== undefined) { + errors.push(new Error('Braid stop was not proven; exact cloud cleanup was refused')) + } + + if (config !== undefined) { + if (!processExited || !processGroupExited) { + errors.push( + new Error('Braid workspace cleanup was refused while the PTY process group remained'), + ) + } else { + const workspace = await attemptCleanup(errors, 'Braid workspace cleanup', () => + config.cleanup(), + ) + if ( + workspace.ok && + (workspace.value?.credentialRemoved !== true || + workspace.value?.temporaryRootRemoved !== true) + ) + errors.push(new Error('Braid workspace cleanup returned incomplete evidence')) + } + } + if (packed !== undefined) { + if (processExited && processGroupExited) { + await attemptCleanup(errors, 'packed Braid cleanup', () => packed.cleanup()) + } else { + errors.push( + new Error('packed Braid cleanup was refused while the PTY process group remained alive'), + ) + } + } + + if (errors.length > 0) { + const failure = new AggregateError(errors, 'Braid interactive proof cleanup incomplete') + failure.code = 'BRAID_INTERACTIVE_CLEANUP_INCOMPLETE' + throw failure + } + return { + processExited, + processGroupExited, + processCleanup: runtime?.processCleanup, + identity: resolvedIdentity, + stop: resolvedStop, + afterStop, + cleanup, + } +} + +async function stopThroughBraid(binary, config, runId, timeoutMs) { + const initialized = await initializedSession(binary, config) + let result + try { + const before = await rpcState(initialized.session) + const beforeRun = runFromState(before.state, runId) + if (RUN_STATUS_AFTER_STOP.has(beforeRun?.status)) { + result = { + operationId: undefined, + acknowledgement: { outcome: 'already-applied' }, + run: beforeRun, + controlRef: exactControlRef(beforeRun.controlRef, 'already-stopped Braid run'), + } + } else { + assert.equal(beforeRun?.status, 'detached', 'Braid stop must target the detached run') + const operationId = `live-interactive-stop-${randomUUID()}` + const acknowledgement = await rpcRequest( + initialized.session, + 'cancel_run', + { runId, reason: 'Braid packed-binary interactive live proof complete' }, + operationId, + ) + assert.ok( + acknowledgement.outcome === 'accepted' || acknowledgement.outcome === 'replayed', + 'Braid stop did not return an accepted or replayed outcome', + ) + const terminal = await initialized.session.waitFor( + 'Braid interactive stop state', + (candidate) => { + const run = stateForRun(candidate, runId) + return run !== undefined && RUN_STATUS_AFTER_STOP.has(run.status) + }, + timeoutMs, + ) + const stoppedRun = runFromState(terminal.state, runId) + assert.ok(stoppedRun, 'Braid stop did not return the target run') + assert.ok(RUN_STATUS_AFTER_STOP.has(stoppedRun.status)) + const controlRef = assertControlRefsEqual( + beforeRun.controlRef, + stoppedRun.controlRef, + 'Braid stop state control reference', + ) + result = { operationId, acknowledgement, run: stoppedRun, controlRef } + } + } finally { + const closed = await closeSession(initialized.session) + const processCleanup = assertVerifiedProcessCleanup( + closed?.termination, + 'Braid interactive stop RPC process', + ) + if (result !== undefined) result = { ...result, processCleanup } + } + return result +} + +async function runProof({ + repository: targetRepository = repository, + environment = process.env, +} = {}) { + const timeoutMs = positiveEnvironment( + environment, + 'BRAID_TANGLE_SANDBOX_INTERACTIVE_TIMEOUT_MS', + DEFAULT_TIMEOUT_MS, + ) + const exitTimeoutMs = Math.min(DEFAULT_PROCESS_EXIT_TIMEOUT_MS, timeoutMs) + const idleTtlSeconds = positiveEnvironment( + environment, + 'BRAID_TANGLE_SANDBOX_INTERACTIVE_IDLE_TTL_SECONDS', + DEFAULT_IDLE_TTL_SECONDS, + ) + const values = sandboxConfiguration(environment) + assert.equal(values.runner, 'pi', 'LIVE-08 native interactive proof must run the Pi harness') + if (!values.credentialValue) { + throw protectedUnavailable( + 'SANDBOX_OBSERVATION_CREDENTIAL_REQUIRED', + 'The packed interactive proof needs a raw Sandbox credential to observe and clean its exact Braid resource', + ) + } + + let packed + let config + let runtime + let recordPath + let identity + let client + let proofData + let proofError + let stopped = false + try { + packed = await installPackedBraid(targetRepository) + config = await prepareProductionWorkspace({ + repository: targetRepository, + environment: sanitizedEnvironment(configurationEnvironment(environment)), + kind: values.kind, + endpoint: values.endpoint, + model: values.model, + runner: values.runner, + provider: values.provider, + providerOptions: { lifecycle: 'retained', idleTtlSeconds }, + credentialRef: values.credentialRef, + credentialValue: values.credentialValue, + }) + client = new Sandbox({ baseUrl: values.endpoint, apiKey: values.credentialValue }) + recordPath = join(config.root, 'interactive-state.json') + runtime = createPty(packed.binary, config, recordPath, exitTimeoutMs) + await waitFor('packed Braid TUI startup', () => /Braid/iu.test(runtime.screen), timeoutMs) + + const markers = { + outputSeed: `braid_interactive_output_${randomUUID().replaceAll('-', '')}`, + inputSeed: `braid_interactive_input_${randomUUID().replaceAll('-', '')}`, + reconnectSeed: `braid_interactive_reconnect_${randomUUID().replaceAll('-', '')}`, + } + markers.output = markers.outputSeed.toUpperCase() + markers.input = markers.inputSeed.toUpperCase() + markers.reconnect = markers.reconnectSeed.toUpperCase() + + const [interactiveCommand, inputMarker, detach, , attach, reconnectMarker] = + interactiveProofCommandSequence(markers) + const promptCount = occurrences(runtime.output, markers.output) + runtime.write(`${interactiveCommand}\r`) + await waitFor( + 'native interactive output', + () => occurrences(runtime.output, markers.output) > promptCount, + timeoutMs, + ) + const initialFrame = await captureStateFrame(runtime, recordPath, timeoutMs) + const initialIdentity = recoverInteractiveIdentity(initialFrame) + assert.ok(initialIdentity, 'interactive frame did not contain one exact Braid run identity') + const initialAttach = await observeSandbox( + client, + initialIdentity.controlRef, + timeoutMs, + true, + { cols: 120, rows: 36 }, + ) + const inputCount = occurrences(runtime.output, markers.input) + runtime.write(`${inputMarker}\r`) + await waitFor( + 'native interactive input', + () => occurrences(runtime.output, markers.input) > inputCount, + timeoutMs, + ) + + runtime.write(detach) + await proveTuiReturned(runtime, timeoutMs, 'native interactive detach') + runtime.write(`${attach}\r`) + await sleep(250) + runtime.resize(100, 30) + const resized = await observeSandbox(client, initialIdentity.controlRef, timeoutMs, true, { + cols: 100, + rows: 30, + }) + const reconnectedFrame = await captureStateFrame(runtime, recordPath, timeoutMs) + const reconnectedIdentity = recoverInteractiveIdentity(reconnectedFrame) + assert.ok(reconnectedIdentity, 'reconnected frame did not contain one exact Braid run identity') + assert.equal( + reconnectedIdentity.run.id, + initialIdentity.run.id, + 'native reconnect changed the local run identity', + ) + assertControlRefsEqual( + initialIdentity.controlRef, + reconnectedIdentity.controlRef, + 'native reconnect provider control reference', + ) + const reconnectCount = occurrences(runtime.output, markers.reconnect) + runtime.write(`${reconnectMarker}\r`) + await waitFor( + 'native interactive reconnect input', + () => occurrences(runtime.output, markers.reconnect) > reconnectCount, + timeoutMs, + ) + runtime.write(detach) + await proveTuiReturned(runtime, timeoutMs, 'native interactive reconnect detach') + const exit = await runtime.close() + assert.equal(exit.exitCode, 0, 'packed Braid TUI exited with a non-zero status') + + const record = JSON.parse(await readFile(recordPath, 'utf8')) + identity = assertInteractiveRecord(record) + assert.equal( + identity.run.id, + initialIdentity.run.id, + 'final TUI state changed the local run identity', + ) + assertControlRefsEqual( + initialIdentity.controlRef, + identity.controlRef, + 'final TUI state provider control reference', + ) + const sameLocalRun = + initialIdentity.run.id === reconnectedIdentity.run.id && + initialIdentity.run.id === identity.run.id + const sameProviderControlRef = CONTROL_REF_FIELDS.every( + (field) => + initialIdentity.controlRef[field] === reconnectedIdentity.controlRef[field] && + initialIdentity.controlRef[field] === identity.controlRef[field], + ) + const beforeStop = await observeSandbox(client, identity.controlRef, timeoutMs, true, { + cols: 100, + rows: 30, + }) + const stop = await stopThroughBraid(packed.binary, config, identity.run.id, timeoutMs) + stopped = true + proofData = { + markers, + initialAttach, + resized, + beforeStop, + stop, + sameLocalRun, + sameProviderControlRef, + identityContinuity: { + initialLocalRunId: initialIdentity.run.id, + reconnectedLocalRunId: reconnectedIdentity.run.id, + finalLocalRunId: identity.run.id, + initialControlRef: initialIdentity.controlRef, + reconnectedControlRef: reconnectedIdentity.controlRef, + finalControlRef: identity.controlRef, + }, + } + } catch (error) { + proofError = error + } + + let cleanup + let cleanupError + try { + cleanup = await finalizeInteractiveProof({ + packed, + config, + runtime, + recordPath, + identity, + client, + timeoutMs, + exitTimeoutMs, + executionStarted: runtime !== undefined, + stopped, + stopResult: proofData?.stop, + }) + } catch (error) { + cleanupError = error + } + + if (proofError !== undefined && cleanupError !== undefined) + throw new AggregateError( + [proofError, cleanupError], + 'Braid interactive proof failed and cleanup was incomplete', + ) + if (cleanupError !== undefined) throw cleanupError + if (proofError !== undefined) throw proofError + assert.ok(proofData && cleanup, 'interactive proof completed without proof and cleanup evidence') + + return { + status: 'passed', + proof: 'braid-packed-binary-native-interactive', + checks: { + packedBinary: true, + interactiveCommand: true, + input: true, + detach: true, + reconnect: true, + terminalResize: + proofData.resized.geometry?.cols === 100 && proofData.resized.geometry?.rows === 30, + sameLocalRun: proofData.sameLocalRun === true, + sameProviderControlRef: proofData.sameProviderControlRef === true, + sandboxObservedBeforeStop: proofData.beforeStop.terminal?.isRunning === true, + stopThroughBraid: RUN_STATUS_AFTER_STOP.has(proofData.stop.run.status), + sandboxObservedStopped: cleanup.afterStop?.stopped === true, + exactSandboxCleanup: cleanup.cleanup?.confirmed === true, + processExitedBeforeWorkspaceCleanup: cleanup.processExited === true, + processGroupExitedBeforeWorkspaceCleanup: cleanup.processGroupExited === true, + }, + binary: { tarballSha256: packed.tarballSha256 }, + configuration: configEvidence(config), + run: { + localRunId: proofData.stop.run.id, + controlRef: identity.controlRef, + eventKinds: identity.eventKinds, + stoppedStatus: proofData.stop.run.status, + }, + sandbox: { + initialAttach: proofData.initialAttach, + resized: proofData.resized, + beforeStop: proofData.beforeStop.resource, + afterStop: cleanup.afterStop.resource, + cleanup: cleanup.cleanup, + }, + identityContinuity: proofData.identityContinuity, + processCleanup: cleanup.processCleanup, + markers: proofData.markers, + } +} + +export async function runInteractiveProof({ + repository: targetRepository = repository, + environment = process.env, + invocationId = proofInvocation('live-tangle'), +} = {}) { + const startedAt = new Date().toISOString() + const proof = await runProof({ repository: targetRepository, environment }) + const evidence = proofReceipt({ + invocationId, + operation: PROOF_OPERATIONS.tangleSandboxInteractive, + startedAt, + completedAt: new Date().toISOString(), + config: proof.configuration, + runIds: [proof.run.localRunId], + environmentId: proof.run.controlRef.environmentId, + facts: { + environmentId: proof.run.controlRef.environmentId, + localRunId: proof.run.localRunId, + stoppedStatus: proof.run.stoppedStatus, + cloudControl: proof.run.controlRef, + exactResource: proof.checks.exactSandboxCleanup, + processExitedBeforeWorkspaceCleanup: proof.checks.processExitedBeforeWorkspaceCleanup, + terminalResize: proof.checks.terminalResize, + processGroupExitedBeforeWorkspaceCleanup: + proof.checks.processGroupExitedBeforeWorkspaceCleanup, + }, + checks: INTERACTIVE_PROOF_CHECKS, + observations: proof, + environment, + }) + return { + status: 'passed', + measurement: scalarMeasurement('LIVE-08'), + evidence, + } +} + +export async function main(argv = process.argv, environment = process.env) { + const outputPath = argument('output', argv) + try { + if (outputPath) await rm(outputPath, { force: true }) + const result = await runProof({ environment }) + if (outputPath) await writeFile(outputPath, `${safeJson(result, environment)}\n`) + process.stdout.write(`${safeJson(result, environment)}\n`) + return EXIT_CODES.passed + } catch (error) { + const status = error?.unavailable === true ? 'unavailable' : 'failed' + process.stderr.write( + `${safeJson({ status, error: safeMessage(error, environment) }, environment)}\n`, + ) + return status === 'unavailable' ? EXIT_CODES.unavailable : EXIT_CODES.failed + } +} + +if (process.argv[1] === scriptPath) process.exitCode = await main() diff --git a/test/tangle-live07-wiring.test.mjs b/test/tangle-live07-wiring.test.mjs index c06b64e..75fc716 100644 --- a/test/tangle-live07-wiring.test.mjs +++ b/test/tangle-live07-wiring.test.mjs @@ -1,6 +1,7 @@ import assert from 'node:assert/strict' import { resolve } from 'node:path' import test from 'node:test' +import { PROOF_OPERATIONS, proofReceipt } from '../scripts/live-required/contracts.mjs' import { runSandbox, runTangleFlows } from '../scripts/live-required/tangle.mjs' import { cleanupRetainedResourceByRunId } from '../scripts/live-required/tangle-sandbox-braid-stress.mjs' @@ -67,8 +68,80 @@ function passedStressCohort() { } } -test('built-in LIVE-07 wiring emits evidence and one measurement with deduped run IDs', async () => { +function passedInteractiveProof( + invocationId, + { + runner = 'pi', + observations = { + checks: {}, + configuration: {}, + run: {}, + sandbox: {}, + identityContinuity: {}, + processCleanup: {}, + }, + } = {}, +) { + const cloudControl = { + provider: 'tangle-sandbox', + environmentId: 'environment-cloud-interactive', + sessionId: 'session-cloud-interactive', + executionId: 'execution-cloud-interactive', + runId: 'run-cloud-interactive', + requestDigest: `sha256:${'b'.repeat(64)}`, + } + return { + status: 'passed', + measurement: { kind: 'scalar', name: 'LIVE-08', unit: 'verified-flow', value: 1 }, + evidence: proofReceipt({ + invocationId, + operation: PROOF_OPERATIONS.tangleSandboxInteractive, + startedAt: '2026-08-19T00:00:00.000Z', + completedAt: '2026-08-19T00:01:00.000Z', + config: { + endpoint: 'https://sandbox.tangle.tools', + connectionId: 'connection-live-08', + connectionKind: 'tangle-sandbox', + credentialConfigured: true, + model: 'tangle-router/glm-5.2', + runner, + }, + runIds: ['run-interactive'], + environmentId: 'environment-cloud-interactive', + facts: { + environmentId: 'environment-cloud-interactive', + localRunId: 'run-interactive', + stoppedStatus: 'aborted', + cloudControl, + exactResource: true, + processExitedBeforeWorkspaceCleanup: true, + terminalResize: true, + processGroupExitedBeforeWorkspaceCleanup: true, + }, + checks: [ + 'packed-binary', + 'interactive-command', + 'input', + 'detach', + 'reconnect', + 'terminal-resize', + 'same-local-run', + 'same-provider-control-ref', + 'sandbox-observed-before-stop', + 'stop-through-braid', + 'sandbox-observed-stopped', + 'exact-resource-cleanup', + 'process-exited-before-cleanup', + 'process-group-exited-before-cleanup', + ], + observations, + }), + } +} + +test('built-in LIVE-07 and LIVE-08 wiring emits evidence and deduped dispatch', async () => { const stressRunner = async () => passedStressCohort() + const dispatches = [] const sandbox = await runSandbox({ repository, environment: {}, @@ -91,17 +164,25 @@ test('built-in LIVE-07 wiring emits evidence and one measurement with deduped ru evidence: null, }), sandboxRunner: (input) => runSandbox({ ...input, stressRunner }), - matrixRunner: async () => ({ status: 'unavailable', reason: 'not in LIVE-07 scope' }), + interactiveRunner: async (input) => { + dispatches.push(input) + return passedInteractiveProof(input.invocationId) + }, + matrixRunner: async () => ({ status: 'unavailable', reason: 'not in LIVE-09 scope' }), }) assert.deepEqual( flows.measurements.map((measurement) => measurement.name), - ['LIVE-06', 'LIVE-07'], + ['LIVE-06', 'LIVE-07', 'LIVE-08'], ) assert.equal(flows.flows.find((flow) => flow.row === 'LIVE-07')?.evidence?.status, 'passed') + assert.equal(flows.flows.find((flow) => flow.row === 'LIVE-08')?.evidence?.status, 'passed') + assert.equal(dispatches.length, 1) + assert.equal(dispatches[0]?.repository, repository) + assert.equal(typeof dispatches[0]?.invocationId, 'string') assert.deepEqual( flows.unavailable.map((entry) => entry.row), - ['LIVE-08', 'LIVE-09', 'LIVE-10'], + ['LIVE-09', 'LIVE-10'], ) }) @@ -126,6 +207,23 @@ test('LIVE-07 rejects a passing canary presented as a stress cohort', async () = ) }) +test('LIVE-08 rejects a non-Pi runner from the native interactive proof', () => { + assert.throws( + () => passedInteractiveProof('live-required-non-pi-runner', { runner: 'codex' }), + /native Pi harness/u, + ) +}) + +test('LIVE-08 rejects status-only observations from a passed receipt', () => { + assert.throws( + () => + passedInteractiveProof('live-required-status-only-observations', { + observations: { status: 'passed' }, + }), + /observations\.checks/u, + ) +}) + test('fail-safe cleanup derives one exact Braid resource from the first local run ID', async () => { const firstRunId = 'local/run-1' const box = { From d0ffe1e10237c1875e701c17184172026a6c4b80 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Thu, 20 Aug 2026 04:39:30 -0600 Subject: [PATCH 22/25] fix(runtime): route CLI Bridge through retained execution --- .../runtime/cli-bridge-retained-execution.ts | 2 ++ src/adapters/runtime/production-backend-resolver.ts | 12 +++--------- .../runtime/production-cli-bridge-backend.ts | 8 ++++++++ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/adapters/runtime/cli-bridge-retained-execution.ts b/src/adapters/runtime/cli-bridge-retained-execution.ts index 0530862..6e447f4 100644 --- a/src/adapters/runtime/cli-bridge-retained-execution.ts +++ b/src/adapters/runtime/cli-bridge-retained-execution.ts @@ -22,6 +22,8 @@ export class CliBridgeRetainedExecutionPort extends RetainedExecutionPort { super({ resolve: async (input) => createCliBridgeRetainedPlan(await options.resolve(input), input.runId), + continue: async (input, controlRef) => + createCliBridgeRetainedPlan(await options.resolve(input), input.runId, controlRef), recover: async ({ runId, providerSessionId, controlRef, signal, ...recovery }) => createCliBridgeRetainedPlan( await options.recover({ diff --git a/src/adapters/runtime/production-backend-resolver.ts b/src/adapters/runtime/production-backend-resolver.ts index 5131f9d..d358cb2 100644 --- a/src/adapters/runtime/production-backend-resolver.ts +++ b/src/adapters/runtime/production-backend-resolver.ts @@ -8,7 +8,6 @@ import type { import { type PreparedCliBridgeConnection, prepareCliBridgeConnection, - resolveCliBridgeBackend, } from './production-cli-bridge-backend.js' import { resolveTangleInferenceBackend } from './production-tangle-inference-backend.js' import { @@ -43,16 +42,11 @@ export async function resolveProductionBackend( selection: ProductionExecutionSelection, ): Promise { const record = options.connections.select(selection.connection).record + if (record.kind === 'cli-bridge') { + throw new Error('CLI Bridge execution is owned by CliBridgeRetainedExecutionPort') + } switch (record.kind) { - case 'cli-bridge': - return resolveCliBridgeBackend( - options, - input, - selection, - record.id, - connectionEndpoint(record, options), - ) case 'tangle-inference': return resolveTangleInferenceBackend( options, diff --git a/src/adapters/runtime/production-cli-bridge-backend.ts b/src/adapters/runtime/production-cli-bridge-backend.ts index 8da82b8..24849e4 100644 --- a/src/adapters/runtime/production-cli-bridge-backend.ts +++ b/src/adapters/runtime/production-cli-bridge-backend.ts @@ -97,6 +97,14 @@ export async function prepareCliBridgeConnection( baseUrl: bridgeUrl, bearerToken: credential ?? LOCAL_BRIDGE_BEARER, defaultModel: route, + ...(runner === 'pi' + ? { + defaultExecution: { + kind: 'host' as const, + jail: { mode: 'fs-jail' as const }, + }, + } + : {}), ...(providerFetch === undefined ? {} : { fetch: providerFetch }), } const provider = createCliBridgeProvider(providerOptions) From 93c710d4bad09db42b51abb5ec87a2aeed6d1d56 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Thu, 20 Aug 2026 04:42:38 -0600 Subject: [PATCH 23/25] fix(runtime): keep CLI Bridge sidecar on stable driver --- src/adapters/runtime/cli-bridge-retained-execution.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/adapters/runtime/cli-bridge-retained-execution.ts b/src/adapters/runtime/cli-bridge-retained-execution.ts index 6e447f4..0530862 100644 --- a/src/adapters/runtime/cli-bridge-retained-execution.ts +++ b/src/adapters/runtime/cli-bridge-retained-execution.ts @@ -22,8 +22,6 @@ export class CliBridgeRetainedExecutionPort extends RetainedExecutionPort { super({ resolve: async (input) => createCliBridgeRetainedPlan(await options.resolve(input), input.runId), - continue: async (input, controlRef) => - createCliBridgeRetainedPlan(await options.resolve(input), input.runId, controlRef), recover: async ({ runId, providerSessionId, controlRef, signal, ...recovery }) => createCliBridgeRetainedPlan( await options.recover({ From 254fa991b42981610f4147edd6a856afb70398cd Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Thu, 20 Aug 2026 04:45:34 -0600 Subject: [PATCH 24/25] chore(deps): refresh license inventory --- THIRD_PARTY_LICENSES.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/THIRD_PARTY_LICENSES.json b/THIRD_PARTY_LICENSES.json index 49614bd..c380ad5 100644 --- a/THIRD_PARTY_LICENSES.json +++ b/THIRD_PARTY_LICENSES.json @@ -77,6 +77,14 @@ "license": "MIT", "name": "@tangle-network/sandbox" }, + { + "license": "MIT", + "name": "@types/proper-lockfile" + }, + { + "license": "MIT", + "name": "@types/retry" + }, { "license": "Apache-2.0", "name": "b4a" From e7b498ce97748c9a101c154e26b7d46d2a924be3 Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Thu, 20 Aug 2026 04:49:23 -0600 Subject: [PATCH 25/25] chore(deps): update runtime provider cohort --- package.json | 9 ++++---- pnpm-lock.yaml | 51 ++++++++++++++++++++++++--------------------- pnpm-workspace.yaml | 6 +++--- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index 5a70193..050d209 100644 --- a/package.json +++ b/package.json @@ -71,9 +71,10 @@ "test:live:bridge": "node scripts/live-bridge.mjs", "test:live:bridge:release": "node scripts/live-bridge-release.mjs", "test:live:bridge:matrix": "node scripts/live-bridge/matrix.mjs", - "test:live:required:self": "pnpm run build && node --test scripts/live-required.test.mjs", + "test:live:required:self": "pnpm run build && node --test scripts/live-required.test.mjs test/tangle-live07-wiring.test.mjs", "test:live:tangle": "node scripts/live-required.mjs live-tangle", "test:live:tangle:sandbox:stress": "pnpm run build && node scripts/live-required/tangle-sandbox-braid-soak.mjs", + "test:live:tangle:sandbox:interactive": "pnpm run build && node scripts/live-required/tangle-sandbox-braid-interactive.mjs", "test:live:tangle:sandbox:execution": "pnpm run build && node scripts/live-required/tangle-sandbox-braid-execution-soak.mjs", "test:live:supervisor": "node scripts/live-required.mjs live-supervisor", "test:live:analysis": "node scripts/live-required.mjs live-analysis", @@ -101,10 +102,10 @@ "@napi-rs/keyring": "1.3.0", "@tangle-network/agent-eval": "0.149.0", "@tangle-network/agent-interface": "1.3.0", - "@tangle-network/agent-provider-cli-bridge": "0.9.2", - "@tangle-network/agent-provider-tangle": "0.12.3", + "@tangle-network/agent-provider-cli-bridge": "0.9.4", + "@tangle-network/agent-provider-tangle": "0.13.0", "@tangle-network/agent-runtime": "0.142.3", - "@tangle-network/sandbox": "0.30.0", + "@tangle-network/sandbox": "0.30.1", "better-sqlite3-multiple-ciphers": "13.0.3", "chalk": "6.0.0", "koffi": "3.1.4" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e01a4d..a5ab110 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,17 +28,17 @@ importers: specifier: 1.3.0 version: 1.3.0 '@tangle-network/agent-provider-cli-bridge': - specifier: 0.9.2 - version: 0.9.2 + specifier: 0.9.4 + version: 0.9.4 '@tangle-network/agent-provider-tangle': - specifier: 0.12.3 - version: 0.12.3(@tangle-network/sandbox@0.30.0) + specifier: 0.13.0 + version: 0.13.0(@tangle-network/sandbox@0.30.1) '@tangle-network/agent-runtime': specifier: 0.142.3 - version: 0.142.3(@tangle-network/agent-eval@0.149.0)(@tangle-network/agent-interface@1.3.0)(@tangle-network/sandbox@0.30.0) + version: 0.142.3(@tangle-network/agent-eval@0.149.0)(@tangle-network/agent-interface@1.3.0)(@tangle-network/sandbox@0.30.1) '@tangle-network/sandbox': - specifier: 0.30.0 - version: 0.30.0 + specifier: 0.30.1 + version: 0.30.1 better-sqlite3-multiple-ciphers: specifier: 13.0.3 version: 13.0.3 @@ -78,6 +78,7 @@ packages: '@biomejs/biome@2.5.7': resolution: {integrity: sha512-zr8K/DcY5tYsQOQwqMJ0AWElo6QgmgNI7idXgXLhevVszlt8RGVpesEJPqx3ThazLaOwjJ5Y8fz3BtH5fGZNsw==} engines: {node: '>=14.21.3'} + hasBin: true '@biomejs/cli-darwin-arm64@2.5.7': resolution: {integrity: sha512-vxo/Ls3/PYdQWyLhYYcgMOCzQypAjcY+iihS8M0wW03l16TCLW4zqZzGo75gm1VdCMj38hTVZ31KBWrZ4G9dJw==} @@ -532,13 +533,13 @@ packages: peerDependencies: '@tangle-network/agent-interface': ^1.0.0 - '@tangle-network/agent-provider-cli-bridge@0.9.2': - resolution: {integrity: sha512-MIMjU5+YPOD37g1BChjvtYXsy5SYV1mo4O1jF0mOIrG/CajOQPLvbZAV3FpvmIijxUBChAkzYxU+JVq1sbGFKw==} + '@tangle-network/agent-provider-cli-bridge@0.9.4': + resolution: {integrity: sha512-QxpeSO0ZH1wya7z+v5FXw4vQLUHNWiwoelYnBeDFB+tzuFjhyMJRhAb86sleeBLK6ojfKJGNGArVCeQeWcgU3A==} - '@tangle-network/agent-provider-tangle@0.12.3': - resolution: {integrity: sha512-tOTEF5z0C39474b0PU3gCU60yHKXZIKfEitB3O8xvXrafaOaVpR1WuQcYi3Cypj42hFZJ+A5kazbzSCPv0ZMeg==} + '@tangle-network/agent-provider-tangle@0.13.0': + resolution: {integrity: sha512-SV8/1Op8qYcXKX+P6700UzhsKrW2yq8Py2p5NwoW6rQObBimIkKVPDcMi7fJkGi+/2CTfxGMCbSJPW+pL4d/OA==} peerDependencies: - '@tangle-network/sandbox': '>=0.23.0 <1.0.0' + '@tangle-network/sandbox': '>=0.30.1 <1.0.0' '@tangle-network/agent-runtime@0.142.3': resolution: {integrity: sha512-5Sm5dG+TunyY6N+CdNFPs4mYjT39wdtRMfXB8N7DjAnn2YGsepPFvwEGDItaFdABcppZ2aqxJqrm6dc7njBnzA==} @@ -555,8 +556,8 @@ packages: '@tangle-network/agent-trace-contract@1.0.2': resolution: {integrity: sha512-v7uMh56jkEp4vckevEU9xKsIatbs5dqzGPp69dFLSSXUVit0RP6VD6EANMXVlTCUk+6wVKBLHJx23XspVCEiIA==} - '@tangle-network/sandbox@0.30.0': - resolution: {integrity: sha512-QDqVoT2AM/Or/okZ86agZN1rlSHc/E1fugnR2k3oEJKDdgQyuwuikfED2WVLZChu2idkc7gcg4JEEVwzeBSoUw==} + '@tangle-network/sandbox@0.30.1': + resolution: {integrity: sha512-EuftQgxTRktWScjIU+BQTPcQNgXb4Yt8YCGA28yLt1uTKJI3NvUemJ28Z58W230Tsl43VOv/KTpURKBph3/+tA==} peerDependencies: '@mastra/core': ^1.36.0 '@modelcontextprotocol/sdk': ^1.30.0 @@ -769,6 +770,7 @@ packages: esbuild@0.28.2: resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} + hasBin: true events-universal@1.0.1: resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} @@ -825,8 +827,8 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-addon-api@8.9.1: - resolution: {integrity: sha512-4eUQWVPCUUUiBjLnHS3cXWeC6ryoPUc0U3rP7IuzapoGbzMqd/r6KKO0clr0b+snQhsrueFEhCZDdK+LK7hxKg==} + node-addon-api@8.9.2: + resolution: {integrity: sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg==} engines: {node: ^18 || ^20 || >= 21} node-pty@1.1.0: @@ -873,6 +875,7 @@ packages: typescript@7.0.2: resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} engines: {node: '>=16.20.0'} + hasBin: true undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} @@ -1184,17 +1187,17 @@ snapshots: dependencies: '@tangle-network/agent-interface': 1.3.0 - '@tangle-network/agent-provider-cli-bridge@0.9.2': + '@tangle-network/agent-provider-cli-bridge@0.9.4': dependencies: '@tangle-network/agent-interface': 1.3.0 undici: 7.29.0 - '@tangle-network/agent-provider-tangle@0.12.3(@tangle-network/sandbox@0.30.0)': + '@tangle-network/agent-provider-tangle@0.13.0(@tangle-network/sandbox@0.30.1)': dependencies: '@tangle-network/agent-interface': 1.3.0 - '@tangle-network/sandbox': 0.30.0 + '@tangle-network/sandbox': 0.30.1 - '@tangle-network/agent-runtime@0.142.3(@tangle-network/agent-eval@0.149.0)(@tangle-network/agent-interface@1.3.0)(@tangle-network/sandbox@0.30.0)': + '@tangle-network/agent-runtime@0.142.3(@tangle-network/agent-eval@0.149.0)(@tangle-network/agent-interface@1.3.0)(@tangle-network/sandbox@0.30.1)': dependencies: '@tangle-network/agent-core': 0.9.4 '@tangle-network/agent-eval': 0.149.0 @@ -1204,7 +1207,7 @@ snapshots: '@tangle-network/agent-trace-contract': 1.0.2 tar-stream: 3.2.0 optionalDependencies: - '@tangle-network/sandbox': 0.30.0 + '@tangle-network/sandbox': 0.30.1 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - bare-abort-controller @@ -1213,7 +1216,7 @@ snapshots: '@tangle-network/agent-trace-contract@1.0.2': {} - '@tangle-network/sandbox@0.30.0': + '@tangle-network/sandbox@0.30.1': dependencies: '@tangle-network/agent-core': 0.9.4 '@tangle-network/agent-interface': 1.3.0 @@ -1324,7 +1327,7 @@ snapshots: better-sqlite3-multiple-ciphers@13.0.3: dependencies: - node-addon-api: 8.9.1 + node-addon-api: 8.9.2 binary-search@1.3.6: {} @@ -1437,7 +1440,7 @@ snapshots: node-addon-api@7.1.1: {} - node-addon-api@8.9.1: {} + node-addon-api@8.9.2: {} node-pty@1.1.0: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 9e0530c..9b6574f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -14,9 +14,9 @@ minimumReleaseAgeExclude: - '@tangle-network/agent-interface@0.46.0 || 0.46.1 || 0.47.0 || 0.51.0 || 0.52.0 || 0.53.0 || 0.54.0 || 1.0.0 || 1.1.0 || 1.3.0' - '@tangle-network/agent-knowledge@7.0.8 || 7.1.2 || 7.1.3 || 7.2.0 || 7.2.2 || 7.2.3 || 7.2.4 || 7.2.6 || 8.0.0 || 8.0.1 || 8.0.5 || 8.0.10' - '@tangle-network/agent-profile-materialize@0.10.2 || 0.13.1 || 0.14.0 || 0.14.2 || 0.15.1 || 0.15.2' - - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2 || 0.7.3 || 0.7.6 || 0.8.0 || 0.8.1 || 0.9.0 || 0.9.2' - - '@tangle-network/agent-provider-tangle@0.6.0 || 0.6.1 || 0.6.2 || 0.6.3 || 0.7.0 || 0.9.0 || 0.10.0 || 0.11.0 || 0.11.1 || 0.11.2 || 0.12.2 || 0.12.3' - - '@tangle-network/sandbox@0.17.3 || 0.18.0 || 0.19.2 || 0.19.3 || 0.19.4 || 0.19.5 || 0.19.6 || 0.21.0 || 0.21.1 || 0.26.1 || 0.27.0 || 0.29.0 || 0.30.0' + - '@tangle-network/agent-provider-cli-bridge@0.4.2 || 0.4.3 || 0.5.0 || 0.6.0 || 0.6.4 || 0.7.1 || 0.7.2 || 0.7.3 || 0.7.6 || 0.8.0 || 0.8.1 || 0.9.0 || 0.9.2 || 0.9.3 || 0.9.4' + - '@tangle-network/agent-provider-tangle@0.13.0' + - '@tangle-network/sandbox@0.30.1' - hono@4.13.0 - '@esbuild/aix-ppc64@0.28.2' - '@esbuild/android-arm64@0.28.2'

    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 literal 62279 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 wK^M|i$q4+Qbf}d}sAr(RzgIx$CqBO3M?!A;I?X against another frozen run - ── model use - Model calls were not reported. ── run receipt source complete: yes + findings: 2 + analysis cost: $0.0048 ──────────────────────────────────────────────────────────────────────────────── - ↑↓ previous/next · PgUp/PgDn page · ←/esc back · page 1/2 · tab filter: analys… + ↑↓ previous/next · PgUp/PgDn page · ←/esc back · page 1/2 · tab: analyses diff --git a/artifacts/verification/w6/states/automation.json b/artifacts/verification/w6/states/automation.json index e691d9d..c287236 100644 --- a/artifacts/verification/w6/states/automation.json +++ b/artifacts/verification/w6/states/automation.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 80, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -30,7 +30,7 @@ }, "capturePhase": "atomic-signal-frame", "captureRevision": 1, - "frame": "\n Ask Braid starter anything.\n\n\n\n\n\n\n\n automation rules\n ──────────────────────────────────────────────────────────────────────\n No saved automation rules\n ──────────────────────────────────────────────────────────────────────\n create from a pending request with Alt+A · esc close\n\n\n\n\n\n\n\n\n\nNo automation rules\n", + "frame": "\n\n\n\n\n\n\n\n\n automation rules\n ──────────────────────────────────────────────────────────────────────\n No saved automation rules\n ──────────────────────────────────────────────────────────────────────\n create from a pending request with Alt+A · ←/esc close\n", "packedState": { "schemaVersion": 2, "capturePhase": "atomic-signal-frame", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 1, "sequence": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [], "runs": [], @@ -113,12 +120,13 @@ }, "view": { "revision": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -202,9 +210,13 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [], "capabilities": { "conversation.create": { @@ -216,19 +228,16 @@ "source": "application" }, "run.runner": { - "available": false, - "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "available": true, + "source": "application" }, "run.model": { - "available": false, - "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "run.effort": { - "available": false, - "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "conversation.branch": { "available": true, @@ -359,7 +368,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } } diff --git a/artifacts/verification/w6/states/automation.png b/artifacts/verification/w6/states/automation.png index 5e922cead4be8c0fc1d53cf5a5a52dde5bfe6f6e..f708fb97b819579dfd9fb8b7565927f8cf797589 100644 GIT binary patch delta 3741 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 literal 6137 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\n→ /new Create an empty conversation\n /open Search and open conversations\n /profile Inspect, select, import, or edit a profile\n /connection Inspect and manage connections\n /runner Set the runner for this branch\n /model Set the model for this branch\n /effort Set reasoning effort for this branch\n /branch Create a branch at a message boundary\n (1/29)\n────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n type to filter · enter to choose · ←/esc close\n", + "packedState": { + "schemaVersion": 2, + "capturePhase": "atomic-signal-frame", + "state": { + "schemaVersion": 2, + "revision": 1, + "sequence": 1, + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", + "conversationId": "conv-1", + "branchId": "branch-1", + "conversations": [ + { + "id": "conv-1", + "title": "New conversation", + "branchId": "branch-1", + "archived": false, + "updatedAt": "2026-08-01T00:00:00.000Z" + } + ], + "profile": { + "name": "Braid starter", + "description": "A portable starter profile for the Braid terminal", + "harness": "pi", + "model": { + "default": "fixture/deterministic", + "provider": "fixture", + "reasoningEffort": "none" + } + }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, + "draft": "", + "messages": [], + "runs": [], + "sessionUsage": { + "turns": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "analyses": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "delegated": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "attribution": "complete" + }, + "environments": [], + "interactions": [], + "queue": [], + "activeRunId": null, + "lastError": null + }, + "view": { + "revision": 1, + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", + "profileName": "Braid starter", + "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "runOverrides": {}, + "connection": "deterministic fixture", + "conversationId": "conv-1", + "conversationTitle": "New conversation", + "conversations": [ + { + "id": "conv-1", + "title": "New conversation", + "branchId": "branch-1", + "archived": false, + "active": true, + "updatedAt": "2026-08-01T00:00:00.000Z" + } + ], + "branch": "branch-1", + "status": "empty", + "statusText": "ready for a message", + "queueCount": 0, + "queue": [], + "messages": [], + "hiddenMessageCount": 0, + "runs": [], + "sessionUsage": { + "turns": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "analyses": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "delegated": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "attribution": "complete" + }, + "environments": [], + "interactions": [], + "activity": [], + "graph": [ + { + "id": "conv-1", + "type": "conversation", + "title": "New conversation", + "status": "complete", + "depth": 0, + "edgeLabel": "attached", + "startedAt": "2026-08-01T00:00:00.000Z" + }, + { + "id": "branch-1", + "type": "branch", + "title": "Main", + "status": "complete", + "depth": 1, + "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], + "startedAt": "2026-08-01T00:00:00.000Z" + } + ], + "graphQuery": "", + "entityDetails": [], + "capabilities": { + "conversation.create": { + "available": true, + "source": "application" + }, + "conversation.open": { + "available": true, + "source": "application" + }, + "run.runner": { + "available": true, + "source": "application" + }, + "run.model": { + "available": true, + "source": "application" + }, + "run.effort": { + "available": true, + "source": "application" + }, + "conversation.branch": { + "available": true, + "source": "application" + }, + "conversation.clone": { + "available": true, + "source": "application" + }, + "conversation.fork": { + "available": true, + "source": "application" + }, + "analysis.ask": { + "available": false, + "source": "application", + "reason": "Complete or fail a run before analyzing it" + }, + "analysis.recipe": { + "available": false, + "source": "application", + "reason": "Complete or fail a run before analyzing it" + }, + "analysis.compare": { + "available": false, + "source": "application", + "reason": "Two completed or failed runs are required for comparison" + }, + "interaction.respond": { + "available": false, + "source": "runtime", + "reason": "Interaction response is not exposed by the current runtime adapter" + }, + "interaction.automation": { + "available": false, + "source": "application", + "reason": "Interaction automation requires the shared response contract" + }, + "export.create": { + "available": true, + "source": "application" + }, + "application.quit": { + "available": true, + "source": "local" + }, + "help.read": { + "available": true, + "source": "local" + }, + "profile.select": { + "available": true, + "source": "application" + }, + "connection.select": { + "available": true, + "source": "application" + }, + "settings.open": { + "available": true, + "source": "application" + }, + "activity.read": { + "available": true, + "source": "local" + }, + "graph.read": { + "available": true, + "source": "local" + }, + "details.read": { + "available": true, + "source": "local" + }, + "draft.write": { + "available": true, + "source": "application" + }, + "run.send": { + "available": true, + "source": "provider" + }, + "run.cancel": { + "available": false, + "source": "runtime", + "reason": "There is no active run to cancel" + }, + "run.queue": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.steer": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.detach": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.reconnect": { + "available": false, + "source": "provider", + "reason": "There is no detached run to reconnect" + }, + "run.reconcile": { + "available": false, + "source": "provider", + "reason": "There is no detached run to reconcile" + } + }, + "draft": "", + "selectedSurface": "transcript", + "appearance": { + "color": "256", + "highContrast": false, + "reducedMotion": false + } + }, + "events": [ + { + "sequence": 1, + "revision": 1, + "kind": "workspace.opened", + "payload": { + "value": { + "kind": "workspace.opened", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" + } + } + } + ] + } +} diff --git a/artifacts/verification/w6/states/command-palette-120.png b/artifacts/verification/w6/states/command-palette-120.png new file mode 100644 index 0000000000000000000000000000000000000000..85b3885ead4fd23f3113319f9305af832d0687d4 GIT binary patch literal 36717 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 literal 0 HcmV?d00001 diff --git a/artifacts/verification/w6/states/command-palette-120.txt b/artifacts/verification/w6/states/command-palette-120.txt new file mode 100644 index 0000000..558cc1d --- /dev/null +++ b/artifacts/verification/w6/states/command-palette-120.txt @@ -0,0 +1,14 @@ + Commands +──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +> +→ /new Create an empty conversation + /open Search and open conversations + /profile Inspect, select, import, or edit a profile + /connection Inspect and manage connections + /runner Set the runner for this branch + /model Set the model for this branch + /effort Set reasoning effort for this branch + /branch Create a branch at a message boundary + (1/29) +──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── + type to filter · enter to choose · ←/esc close diff --git a/artifacts/verification/w6/states/command-palette-40.json b/artifacts/verification/w6/states/command-palette-40.json new file mode 100644 index 0000000..c15be1b --- /dev/null +++ b/artifacts/verification/w6/states/command-palette-40.json @@ -0,0 +1,376 @@ +{ + "schemaVersion": 2, + "state": "command-palette-40", + "source": { + "binary": "packed real binary from clean npm install", + "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" + }, + "dimensions": { + "columns": 40, + "rows": 12 + }, + "terminal": "node-pty/xterm-256color", + "provenance": { + "renderer": { + "package": "@earendil-works/pi-tui@0.84.2", + "pty": "node-pty@1.1.0", + "emulator": "@xterm/headless@6.0.0", + "node": "v24.13.0", + "terminal": "xterm-256color" + }, + "raster": { + "agg": "agg 1.9.0", + "imagemagick": "Version: ImageMagick 6.9.12-98 Q16 x86_64 18038 https://legacy.imagemagick.org", + "fontFamily": "DejaVu Sans Mono", + "font": "DejaVu Sans Mono | Book | /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", + "colorMode": "sRGB 8-bit" + } + }, + "capturePhase": "atomic-signal-frame", + "captureRevision": 1, + "frame": " Commands\n────────────────────────────────────────\n>\n→ /new\n /open\n /profile\n /connection\n /runner\n /model\n (1/29)\n────────────────────────────────────────\n enter choose · ←/esc close\n", + "packedState": { + "schemaVersion": 2, + "capturePhase": "atomic-signal-frame", + "state": { + "schemaVersion": 2, + "revision": 1, + "sequence": 1, + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", + "conversationId": "conv-1", + "branchId": "branch-1", + "conversations": [ + { + "id": "conv-1", + "title": "New conversation", + "branchId": "branch-1", + "archived": false, + "updatedAt": "2026-08-01T00:00:00.000Z" + } + ], + "profile": { + "name": "Braid starter", + "description": "A portable starter profile for the Braid terminal", + "harness": "pi", + "model": { + "default": "fixture/deterministic", + "provider": "fixture", + "reasoningEffort": "none" + } + }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, + "draft": "", + "messages": [], + "runs": [], + "sessionUsage": { + "turns": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "analyses": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "delegated": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "attribution": "complete" + }, + "environments": [], + "interactions": [], + "queue": [], + "activeRunId": null, + "lastError": null + }, + "view": { + "revision": 1, + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", + "profileName": "Braid starter", + "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "runOverrides": {}, + "connection": "deterministic fixture", + "conversationId": "conv-1", + "conversationTitle": "New conversation", + "conversations": [ + { + "id": "conv-1", + "title": "New conversation", + "branchId": "branch-1", + "archived": false, + "active": true, + "updatedAt": "2026-08-01T00:00:00.000Z" + } + ], + "branch": "branch-1", + "status": "empty", + "statusText": "ready for a message", + "queueCount": 0, + "queue": [], + "messages": [], + "hiddenMessageCount": 0, + "runs": [], + "sessionUsage": { + "turns": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "analyses": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "delegated": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "attribution": "complete" + }, + "environments": [], + "interactions": [], + "activity": [], + "graph": [ + { + "id": "conv-1", + "type": "conversation", + "title": "New conversation", + "status": "complete", + "depth": 0, + "edgeLabel": "attached", + "startedAt": "2026-08-01T00:00:00.000Z" + }, + { + "id": "branch-1", + "type": "branch", + "title": "Main", + "status": "complete", + "depth": 1, + "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], + "startedAt": "2026-08-01T00:00:00.000Z" + } + ], + "graphQuery": "", + "entityDetails": [], + "capabilities": { + "conversation.create": { + "available": true, + "source": "application" + }, + "conversation.open": { + "available": true, + "source": "application" + }, + "run.runner": { + "available": true, + "source": "application" + }, + "run.model": { + "available": true, + "source": "application" + }, + "run.effort": { + "available": true, + "source": "application" + }, + "conversation.branch": { + "available": true, + "source": "application" + }, + "conversation.clone": { + "available": true, + "source": "application" + }, + "conversation.fork": { + "available": true, + "source": "application" + }, + "analysis.ask": { + "available": false, + "source": "application", + "reason": "Complete or fail a run before analyzing it" + }, + "analysis.recipe": { + "available": false, + "source": "application", + "reason": "Complete or fail a run before analyzing it" + }, + "analysis.compare": { + "available": false, + "source": "application", + "reason": "Two completed or failed runs are required for comparison" + }, + "interaction.respond": { + "available": false, + "source": "runtime", + "reason": "Interaction response is not exposed by the current runtime adapter" + }, + "interaction.automation": { + "available": false, + "source": "application", + "reason": "Interaction automation requires the shared response contract" + }, + "export.create": { + "available": true, + "source": "application" + }, + "application.quit": { + "available": true, + "source": "local" + }, + "help.read": { + "available": true, + "source": "local" + }, + "profile.select": { + "available": true, + "source": "application" + }, + "connection.select": { + "available": true, + "source": "application" + }, + "settings.open": { + "available": true, + "source": "application" + }, + "activity.read": { + "available": true, + "source": "local" + }, + "graph.read": { + "available": true, + "source": "local" + }, + "details.read": { + "available": true, + "source": "local" + }, + "draft.write": { + "available": true, + "source": "application" + }, + "run.send": { + "available": true, + "source": "provider" + }, + "run.cancel": { + "available": false, + "source": "runtime", + "reason": "There is no active run to cancel" + }, + "run.queue": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.steer": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.detach": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.reconnect": { + "available": false, + "source": "provider", + "reason": "There is no detached run to reconnect" + }, + "run.reconcile": { + "available": false, + "source": "provider", + "reason": "There is no detached run to reconcile" + } + }, + "draft": "", + "selectedSurface": "transcript", + "appearance": { + "color": "256", + "highContrast": false, + "reducedMotion": false + } + }, + "events": [ + { + "sequence": 1, + "revision": 1, + "kind": "workspace.opened", + "payload": { + "value": { + "kind": "workspace.opened", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" + } + } + } + ] + } +} diff --git a/artifacts/verification/w6/states/command-palette-40.png b/artifacts/verification/w6/states/command-palette-40.png new file mode 100644 index 0000000000000000000000000000000000000000..f1eebab74141ac391f7f937c695f0146270f369b GIT binary patch literal 9718 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 U{fqUo39t%KQP7mHfWCV7Ulu6~4*&oF literal 0 HcmV?d00001 diff --git a/artifacts/verification/w6/states/command-palette-40.txt b/artifacts/verification/w6/states/command-palette-40.txt new file mode 100644 index 0000000..6781fac --- /dev/null +++ b/artifacts/verification/w6/states/command-palette-40.txt @@ -0,0 +1,12 @@ + Commands +──────────────────────────────────────── +> +→ /new + /open + /profile + /connection + /runner + /model + (1/29) +──────────────────────────────────────── + enter choose · ←/esc close diff --git a/artifacts/verification/w6/states/command-palette-80.json b/artifacts/verification/w6/states/command-palette-80.json new file mode 100644 index 0000000..6889abd --- /dev/null +++ b/artifacts/verification/w6/states/command-palette-80.json @@ -0,0 +1,376 @@ +{ + "schemaVersion": 2, + "state": "command-palette-80", + "source": { + "binary": "packed real binary from clean npm install", + "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" + }, + "dimensions": { + "columns": 80, + "rows": 24 + }, + "terminal": "node-pty/xterm-256color", + "provenance": { + "renderer": { + "package": "@earendil-works/pi-tui@0.84.2", + "pty": "node-pty@1.1.0", + "emulator": "@xterm/headless@6.0.0", + "node": "v24.13.0", + "terminal": "xterm-256color" + }, + "raster": { + "agg": "agg 1.9.0", + "imagemagick": "Version: ImageMagick 6.9.12-98 Q16 x86_64 18038 https://legacy.imagemagick.org", + "fontFamily": "DejaVu Sans Mono", + "font": "DejaVu Sans Mono | Book | /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", + "colorMode": "sRGB 8-bit" + } + }, + "capturePhase": "atomic-signal-frame", + "captureRevision": 1, + "frame": " Commands\n────────────────────────────────────────────────────────────────────────────────\n>\n→ /new Create an empty conversation\n /open Search and open conversations\n /profile Inspect, select, import, or edit a profile\n /connection Inspect and manage connections\n /runner Set the runner for this branch\n /model Set the model for this branch\n /effort Set reasoning effort for this branch\n /branch Create a branch at a message boundary\n (1/29)\n────────────────────────────────────────────────────────────────────────────────\n type to filter · enter to choose · ←/esc close\n", + "packedState": { + "schemaVersion": 2, + "capturePhase": "atomic-signal-frame", + "state": { + "schemaVersion": 2, + "revision": 1, + "sequence": 1, + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", + "conversationId": "conv-1", + "branchId": "branch-1", + "conversations": [ + { + "id": "conv-1", + "title": "New conversation", + "branchId": "branch-1", + "archived": false, + "updatedAt": "2026-08-01T00:00:00.000Z" + } + ], + "profile": { + "name": "Braid starter", + "description": "A portable starter profile for the Braid terminal", + "harness": "pi", + "model": { + "default": "fixture/deterministic", + "provider": "fixture", + "reasoningEffort": "none" + } + }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, + "draft": "", + "messages": [], + "runs": [], + "sessionUsage": { + "turns": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "analyses": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "delegated": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "attribution": "complete" + }, + "environments": [], + "interactions": [], + "queue": [], + "activeRunId": null, + "lastError": null + }, + "view": { + "revision": 1, + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", + "profileName": "Braid starter", + "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "runOverrides": {}, + "connection": "deterministic fixture", + "conversationId": "conv-1", + "conversationTitle": "New conversation", + "conversations": [ + { + "id": "conv-1", + "title": "New conversation", + "branchId": "branch-1", + "archived": false, + "active": true, + "updatedAt": "2026-08-01T00:00:00.000Z" + } + ], + "branch": "branch-1", + "status": "empty", + "statusText": "ready for a message", + "queueCount": 0, + "queue": [], + "messages": [], + "hiddenMessageCount": 0, + "runs": [], + "sessionUsage": { + "turns": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "analyses": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "delegated": { + "sourceCount": 0, + "input": 0, + "output": 0, + "tokenStatus": "unknown", + "costStatus": "unknown", + "unknownTokenSources": 0, + "unknownCostSources": 0, + "callStatus": "unknown", + "latencyStatus": "unknown", + "unknownCallSources": 0, + "unknownLatencySources": 0 + }, + "attribution": "complete" + }, + "environments": [], + "interactions": [], + "activity": [], + "graph": [ + { + "id": "conv-1", + "type": "conversation", + "title": "New conversation", + "status": "complete", + "depth": 0, + "edgeLabel": "attached", + "startedAt": "2026-08-01T00:00:00.000Z" + }, + { + "id": "branch-1", + "type": "branch", + "title": "Main", + "status": "complete", + "depth": 1, + "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], + "startedAt": "2026-08-01T00:00:00.000Z" + } + ], + "graphQuery": "", + "entityDetails": [], + "capabilities": { + "conversation.create": { + "available": true, + "source": "application" + }, + "conversation.open": { + "available": true, + "source": "application" + }, + "run.runner": { + "available": true, + "source": "application" + }, + "run.model": { + "available": true, + "source": "application" + }, + "run.effort": { + "available": true, + "source": "application" + }, + "conversation.branch": { + "available": true, + "source": "application" + }, + "conversation.clone": { + "available": true, + "source": "application" + }, + "conversation.fork": { + "available": true, + "source": "application" + }, + "analysis.ask": { + "available": false, + "source": "application", + "reason": "Complete or fail a run before analyzing it" + }, + "analysis.recipe": { + "available": false, + "source": "application", + "reason": "Complete or fail a run before analyzing it" + }, + "analysis.compare": { + "available": false, + "source": "application", + "reason": "Two completed or failed runs are required for comparison" + }, + "interaction.respond": { + "available": false, + "source": "runtime", + "reason": "Interaction response is not exposed by the current runtime adapter" + }, + "interaction.automation": { + "available": false, + "source": "application", + "reason": "Interaction automation requires the shared response contract" + }, + "export.create": { + "available": true, + "source": "application" + }, + "application.quit": { + "available": true, + "source": "local" + }, + "help.read": { + "available": true, + "source": "local" + }, + "profile.select": { + "available": true, + "source": "application" + }, + "connection.select": { + "available": true, + "source": "application" + }, + "settings.open": { + "available": true, + "source": "application" + }, + "activity.read": { + "available": true, + "source": "local" + }, + "graph.read": { + "available": true, + "source": "local" + }, + "details.read": { + "available": true, + "source": "local" + }, + "draft.write": { + "available": true, + "source": "application" + }, + "run.send": { + "available": true, + "source": "provider" + }, + "run.cancel": { + "available": false, + "source": "runtime", + "reason": "There is no active run to cancel" + }, + "run.queue": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.steer": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.detach": { + "available": false, + "source": "provider", + "reason": "There is no active run" + }, + "run.reconnect": { + "available": false, + "source": "provider", + "reason": "There is no detached run to reconnect" + }, + "run.reconcile": { + "available": false, + "source": "provider", + "reason": "There is no detached run to reconcile" + } + }, + "draft": "", + "selectedSurface": "transcript", + "appearance": { + "color": "256", + "highContrast": false, + "reducedMotion": false + } + }, + "events": [ + { + "sequence": 1, + "revision": 1, + "kind": "workspace.opened", + "payload": { + "value": { + "kind": "workspace.opened", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" + } + } + } + ] + } +} diff --git a/artifacts/verification/w6/states/command-palette-80.png b/artifacts/verification/w6/states/command-palette-80.png new file mode 100644 index 0000000000000000000000000000000000000000..680e8f4970034bb383fe847588a1e432c09c6559 GIT binary patch literal 35536 zcmb@u1z1$w+Bc4(gmj1k0uKrUNJ%TH14x&23rLrA45bVpASERXAvp|PLx)Ot*U$|^ zcf+@N&N<)vp6@*8`oHJ5y=V4bd+oLE`~Jn+!ODtK1P`blU|?Vn$Vf}P!@$6# zz`(fs0_QHUC&s|a9@zY0BK=MQ1H%)9f#CsF+gV0I5*v*}jCY>|V;3n8d>KPV;*FX+YHQj}k8G6= zdzT3+jRO@S$7v@f&wWWutg<0Ne&5ad456;Ok&i-+T8)faM`yGT;8ART+E-*t`fNy}ffkt{COpy8vs zU>x4P>7nNG5Iq|A>+A!JFS9aM(^9cfZxBf=DL9?;iAwUXA-Mf`xn#v%&44;?mgCle zt=R_VPDUuuLRgJ^(|SD&)1N6Omi)uXN3iuk>OL%8}SOK;sQ0*>oYRAWq?fyseo# z{-h>1m+NIRN4m8qG{@Ja3c0GXq5BO!zEBA@*;wU~kr5ky7;(B+WNe%}*Ft=2qDJ47 zH#mEA!e*WD4YZB*NH^DnB~cD(Ze96!^Y4&E1D0s^ggH5V7@y@pjo%Nh;X^dqDnY`g zSwP(YPu&-}9?rON#6V&pl{YKbncJ7^8 zw<9KK^K{LrgGGEmhF66z-|AU(<|ys$5O$XY9yXF|j(_yS;+(P3bU3l&X8aCg`ru|c zwi_oM6SN9)!Me)Q+0*UwO#+97z5QW5vyV!Q_0Q!&-V!Y~u(XcX*8rE=1Vh_%QS`5x zCa!RrIvjd44cpi}1*Iz8m;+v+tv3PE(l}iF$UmUpCtZGs_6Y7>oGd)pJM*8+(a737 zWB`Bp;jh_8zxY*Nen(%(We&bvAR-8~Z8u~v7wV}JBZb3-EH9XCUQSRU>I^AEU<1RM z1T5cEFnlkw&8{xEX>jP`<5pqHl{j1eqzWTRz)e zLk!U|Dn#A+_l7ZbgN~uZ^PvmbZMmA0GaV%bKLdyz7b3#&q|Uk@uX&wx$|%G=#FZSz zY^Y|Zhqf5+^{}a%=M*4bT~D4%E_(U^kLyZw3xPeK}&$~?LATf*9)okO0TIw z`E?~%e8@o7^F-Ls3%%&}-F*y}oY^UNDL>ai?K-@kFy$&!DIL&;_OsU&JI5|;<9hd1IoT-$Ub(AUyZoxgjQ z@jdT>2P3Sf!j7q59}PsUxmme97!~=lut@zXoFsY`a(1uqa*>p8Z*CFkSZ?hA=^PzNpeq9Fd2~Hs%3$d%`MCImLRdNGZLoq>xG{+#FWSo@Z$wPC58 zYi-b4Ibf}&BzXfXEIC^ToGetVs-_`3{YaL+sJlyEtbUaV&7lEwH-?Laiy<@8%Gw%H zG;kZS>lDjtC}i1(m2RJf&Y7{4) zcz@KhQ?Kg)yhnsIqRu-rnCFrot$|tq!#&JW4P2k3u2kgPD4Ov$Y<;ZA-ch#mbdSu! z?CqZqqlgO>A3Zkud}+TkS2h4VfHDFG5JovD%;#BOb-k*^cuo{Oz1fP{BM!aqT#Hw= zB`3NN<9Z&-^l(zP5of>Cr2D?Xa%b63ahJmCwhjlR9+|18T7jVKV@p2EQ7l>A?c0>804 zuxYdF?5}4q?t9zyxRpoMXlYPH?iuWYVt4#S|4 zCmL;!A1B)A^sBfm)6@jvr=FW^w$S*}USuN=aCbT9gq#gtw|fQDS+%YD5H#fBCZE-o zY0h3~`oxFG)?HlpjduqUgRh*dHpdyD#jgUVFO*z1s6N;YrL2|6IlkLAJc|{~3F|>A z+?<eT4rRUaJdAJo_0`M{{Vx(C;HJF5@l=xMg#)0FGQKxh%-TW}@& zabBF<2niw&J&0zQoRtA z*LPDX^Nb+cYuPR3#d3h{1x`4U5w!z95ayoe$;@%GcI- z#2$pE3`At3uB7H>Al-G-o$FFQmxjq#@Dc`#vS^GK*W@8RTxt;EF(aGN-i)>{F%YJh zwt{z%KA*QB4QM34-r}!$>r&d;oR|lQM=Z<2cins;0<-N3(PgUkaVv1VsVjy2Ctaas zF+5sGCnhNQYG%1B_nm7R8=Bcapi3h4N;imNsR&~9u3Gvleq4H5(Pxl|OX&$zZ?$#t zQ0xA;&ClI0&)wHF<&?JGQhP-WaHpiaDLXto{3@USws$-Y4wu4N=kvOw4pxbA5r^>y zV$SMlYeXKVGpCw`QaY?=Jv0q`YgRZT{wGvbk*Q{^6Qo%V213*gsDYlh8Z!y0>;2aIEl#!T z2ldO;i^HSId*SE#PCxJ67#)35wB^q}-tP<<4;31uP2%WP;G3fg?7f^G-6Mz> zz@qrj8r-#?LqwllP}d@0pLe{mKEJWK%@h&5h3Ba;g%)^6PE znRKOlp>Sj^LXgcYvR&tv8XQgoflrHdm{peS^hXnaOK{gXpwBD2QO-FM4sLX}8v|2> z+Rpy!L#P@eGdwPau@W~)z(D8OB`y9ot4z2MpZ2|%$na@h@$PFCRWKzC$y0gOhFJc+ zDkJJY^9*XCB}w@>v0(u6JG#m#>;C$YZkcKZVtrWX#WPi1xmv~H+E1bx6epC(@5JDG zmtxm7pr-BhkjLSwbeM-t0!3xPlZhwdd9K@he0-eyLwv#57`%sv16fe9ljo^}bU?_e z`wHQ($A7#x!=Dm7(&csu{jMe0Z!fuJwT_s!06KhYk%U5&wF4rL!@}7U6(aY%GqlGR zRi*_1PaUhk;R|@E(>EM?Tmhnc&~CUW3p}2jW}yCt9Ip5&ur*FG`F!08MZTJydxa4} zywLwEmH1r}ESC*uJ7rd0w+?#TO)6w#WcY4h|9 zsXyqOdy(eAoEi)%U0o;Qqbn7>Aj*2NL4y1J{l<7p6B94fRxi*wlzXdubUmPc23&bJ zQjCy9(%k4Bi;)QRSTC&llU?-Aky7`_nD@_eep`GKPCNTzb&$uIk);Civ*&w@4~inn zv|^l?woT8VF-uvb;BK2FT>6%3gof+3>y}WW7Ow2UP%P8+9lsO_HK23(t>wgEIr*=T zSguMsj7xr-U749`R%*O28L4aUFN#Y6Q5W1i&B$;+Jbc-yNxv5wUlcYRnweG-fZC#1 zWq9~Oq}0W$sbHi3IOPh5KDd&|n)F5AcoOk``kc%ah@&sYQ`ulY$@7orJ@n9zVclxx z)-NO{It21^GqdB4vq!gR1W!r8+@u^TeCdHKxxiSXot`qcvATG>1C;k3>5tCFo@uJC zK7iHX4GjIGJM?*O)(c>5H(V`)GZ`ikk(Glb?TI4s)7y(OGx>`{iC_D zhxWM!yAr@OE-dfsZAwd?lDufL}jHXyd{oa87I2X$b~w!MEpw;juI7h^>?~$0;qB>uk*EU zXhsR%6u2ZAIDd1>JE)iE1uq}J^;p3TFZy`OG(bs`b03%fx`_fPM^J(uZu^48^c+-vWaJ>fyXTAW@R>$X$z7*8l4Iru@Xv3eZNQ5n+7sF3{1-9 z?_v?|rJue;v)aTry$niSNa^vo8L2YPKh?86O>MbJ96OajiqP^TUWc^att@rPfj!1Duk+HVy4czAC5P zQ`z2)Typ1O+F+b0jhHC@Ko^a7kyq_g+4Vq>o$&^JYix*7^lcyN|CsSL#~XK0LIL^I zYj4)@tJ39xz&XCM0)Wz@gI05VcY_B=sO(s;ej$<$ZzgJw@Np98h`Cb}-EF#f!8oBU zHMG^9r^9qWdwcax{H#dp+sAe(+LY+@a}kKNLiIky287qd7)Vkt1!1`Rq;c+5Cks%H zE+lPeD2<^{te!2|dyBuj?Sv z>nT>xs7aGK2r$ZtMO-}`j)7@JRCM(QNwJ*iyhg#s)&Wd}kknZ?Xko)0<7;!$RY~1a zwcG4RpsuXWe=4%=^$qK$%rd+Ojm{;ToY~>=MATcmdBn0E|K<;MwM)iC&q$v4wcF!Y zfovz;xL)w87|4kKt&8OOUeRU+Y2GN;-;R6CbA0BkDWQQ50r|tHVm#})fs?rf1tK*b zvPJU;LeA7?AB@>OqhRFT3_@qi)MMorOcAWPmw~+{Hme*(-#&nD&diqts8Z?+VjegR zn&gnmdQd2Jkx$o_>w`#KHz}>`h8k*gR1)JUyw9c3AzTV?qeUTM10Y-sUS}6;1&UC< z^-#Hyklg9K&suC6)^21NKNyuON9$ZajQF#D684}cJg7PU6c1z< zG^ipc6$4{9v602!Q<;&hP5-7I*>nfvNM}u8AApzaMl!vz;#~|+!y0~JV-(~C_&g&5 z@X4G@`uei_EmHXb{SVknt*%&QZ%j;5I!1TbeT!SvK!s2?9z*^J$;3x#4`uqOf zAPszw#jam!gW*sO?)v6(waX9|D{I#%0cLsm`4^!);w`#36b zSa-0um%#tfo)AN4Hu94_2%eeJ=pNwd$^4XCtnmlZ|E>kr?9Hi@br8l4J-ZrMA(fw9 zl%8G?q~VgDntF42b|5@8o%L=#j9Or{P+#{v{VOrI{dQ6?8Iv9A@?e-nwY$4#VPT>1 z(y^tin{D|s2L}h>4FI@Wg!kL$D*WVliMe89) z1o*{BBuQNSY*@Y9`R4tA^h7K4<}xLP;1sGe_eb%^o$IFDAYp>U$j?|rIFuCS-m7$B z1^ho}1>D!(^QcCzzN+5C#W!FEdIBtk?^axymzygq@A-tpLyv(}RpFUKey*Oo72vq6PINbA)-7>ruQ^hN6Chqe68sW2%qZJDnPr zHhZfJa3l3gp-LiZF8R6lO!2JWXqo7Q9CVo3G=&nyyc+|X=9SBAr^`QizPMRz;np@y z4klV8jd_zx160ZIV2U4%ic200BE=etuf6ryurfRRgiGS;_ZpCo9Vi4Fb_i%;S}AN~Y?j7Ft^U{eMK|c(omG0raoc z$k-SW5mD+ZrLJaaOC9wC}Fm*$U4pEu^y=(%+wEH1u` zpV9O-oQB48y%X6NSE$wK5G~E%>f&)moovGod3_@atK8Ho^)fXzT^{b(u^4}J9%-Sm zF~7~va#_%&S;VPRw>cHSDjtMC_%ZbEr>43Io)l9v?+WLZKstWBdxTDA4RAsKw6wHF z!#)Bro9l%x^#=jQ+nbbZ6rrLeI-pOW5~~c`j~S%Fyj(03aERteJ@}8}Mrw%RmLl+A zcHIM=%oY1OdUR`yM>PfGkO;0bVRP)Z zF}Aw093K<2J#!Tl9UZM-TTzhw!B4YmK0~F2F-uPDVl6u0;B7!)xtpV!EzK+A@A;+Z z6Maa)Z^tOZYA5*%N*3={t8yng2TfCkfTIG;vYnEjgEaje$wf22}GrzvRE-8`1?5zSK4KC8F zH!?A?HL}Z=FC=;Oj1vteP zEMlTFel|7fzrqY{5%gNpa&QP%*7DiiRk3F6+Sae_XVQQ%0KaU@!)$qvuf-pkGnrzD z)VLMo=ZDC-XSy<_%@S;GZn_K4YzetBk|L_WUING02%c5GCq1AHrMn8K^^E)dXTids ze$u~uc^aCPs=Ct@Q&(S4*V+P9Aj(QR)3r)Cd&k>etBSmQj2s*(p1W*3atx#%&Yp|i z)uGVHpELEGhQh4zT?h?_fS0U1LqkJ6=u?MVSmKY6Go&FB|B_P1m&cMfdm2&Rk zI}MOty_r7@mS^5ZNFyQ)#F#1?nuCk&tKm23iGjs8dUgA}k@6r`Ha16Ra%HB4ixWKj zwPkZ#(~f0F1Z9<;zu<=N<9KD?jBT1JfGMD|c?umK9$s2msmE8+QpA}*I2%szMp}T= zwF`d!;yCt6a%7~W?Bl)k`!zAKzFyXSn*c3!JhAATv+7M`Wpf=<;C%)uxX;<1$4O@r z5+0w>HV-gWbjbWr%0~f#%EIe+MrUU(?R2d{m2)idU_H!D&+9X{JJQ?IMu3@vLxY*z zL@G?!cW*!Xt2uXq{K0??_c=pGkt(QbUK14+1t<$=YM^M~ zX2{4ykJO&WvJfePzZBO^jdp$|{%u@x>gBVR6jtLcM3N``}hPc4`mtUN$Gh^H}sh8f>>y)&NaaES>;oM!f|pf*(}xS(%S9|j)sZ~ji*slRg^Tq zbiGb$5P?hu2iKp>Ee8oun3)k27T09gTuaDE-luOKZkBi&#c#4p6{waf&9JcN-U$~L zFAT(!&3tF_?Afv^VNga@C3wxcC#^=pe{{L+{ccxH@&coM@Y0 z;4a*hzxwJhcm&Jam@l}3D}t0P>z!r9wm!sp$MeQ02`y!fI+5gv7yBC8=y+5U5Kzr6 zjLgv1*3P;#NLeYDxvNl)A;^|?>b1DH$h0|A4=*jv_1Q=ff%NqBh+Qm^sj89*2#hIF zu*=HJ)_AXSjOgg}KDbB7&p#>`&*7aC?Q~qk*?fIE1k%(Td)O5}IXUT2Jta_A z7sshf!TaI;pExK(&b%n%QMZGO!|0g#q?WD%jMP9|n-a2fXN1aSU%s}YV%|QYvb=om z<4eWx&%tD^u1DKo92t49&5a@PKR(Vm5&*h|^ZI7i*;_fo82uVYTZ{f57`}$Ief{0t z<@WFWf@)!L-j zV?ZZaW$~-cxF+}SVtad66cmINDMhq(AUfa4Z&`@;bs&)?u1+pyYHhr)a1RIWuI)+~ zoC?kJjf`L))7cassTePGC-AIvU+s1-cd4tZj{(JMtzEL?7FOdt>509i5q)7! zyZgD#);V3Qz!3{Gv);ip(X&7z{W^;~Z~`U)fgRVwX{b~%H1bP3v$ywg-NcU5;nC0_ zkL#A`3kb-6GEwS@h=H0K_s7?bl}ukr;zI4EW~)6e!vE}57Q}kv4objFtADMSq|eE* zFQxIZpz(JQo|&1cJ*w2?gY<5qI_r{SOGb01IEhN`jRr6Zo#i*B4pynCDb0j?E*%au z(6U&G%~mjID_I`Dj;Gs>$lCIbu7N>H;<1E_XY|Flm?UE}Gpg(3stQ|M*5-#1q;x=a zDSI$b2ecw1qv>J@ba3WH5t>!Usdn1DmphB~W1GZfWvV5I433n!3sf})Uqe8_>)+dAja(d0Q z8{m5jp<10?p8g4{_yYeEWo>;I+W@^r{kYh4qXGzbAQ8oZqYA9Uos;>XgXE;7mrr`9 zs+~9ttFuw(lSPdo66qdvK3eAKMfOVQk}>L@OSv43q8K0Vi#ib>wd7zrpF?ebF>_oO zw(kORXL!zZ-P+@*`4>34&tvVT_jIkX_fY^acm-KG%wpAe_$Z#4=~`-Vrn+n_C#ngE z3WrBW0`?b-^z(FLN2+4DH-r8;4gUqu*pi}Du7yZz4#^&1_w&I!QnD|DmN4Nh)-4dMkfQMbr#yrN)Bz`D_X>vj8y*tI;) z`i)sCu8EXoeW_+8Oz?~ zl_Pd4epa9+P>=WAx!jDY@=|lGa53f@{mwJn}yjbNS zxI(Cs^q25pb;UFvIrpKJRJdY-v6&skqenN(@vJ~Ktx{lTSE$k!-jm3er+Y%1@f(aw zUwg7SQGM_zccib+_xjR6*YXiQ&GYHdw(AgLlsl&U)STEuV3&zAq+}12UO=_ z|1&zyxQ^$@O%?^9c+EP=by2OZ0OD0HlWKlGTcbe<1L*h~AUpRD@X}3;{euWqn3r_j zF5{x3^IUmF{u(9%xrjq|zhi}6NM8?ivb`*aQ|)}zT73}jj8aH+UlSiRrWux{4`V2vu<;d3{fXf#RO`C`+`~%eykrrshMmP_B^50y7Pia}@CYht z^uxks=8ACIoRszqna})|zAohwxXbg~$1AX_mEL4k^O};9y)Pv6(X+|#w6&|z8%342 zv!cB2TDA&dj)6pGy>(7ZW|vT0Xr$W=?&`;vj@46T(QOq4VsygpYyL!{#T69>H`8vq z6?Vxl=GnpRy@o#1XI(`A;F{nuH|t51OwLu7)L%LTW+8XTY==s*{Z5LQ{R}<kW zDw|HZ$;C0rGjYDlW`Mp6>M9a(qj3x{ZarjCWoj(j%(KU#7fzXG5=YXpfzLW!xZ^OVFA<71L) z01yiNEVe?uUqV{lD z|M8TgFI@^cK6{i=*?3_lDc}=Ql^=}hA7-!+zwCyIETY16 zVHGw4JbcNbE`v!4J0rM4?rU=~!{sB^jZDzPoiX4xH8nLia$t$gLt4@bv(614;V~-S+yD1(e>=YuB9~ zeE$6V+qc13R?Ug=@j!gKnY#!~i-(?`o+MFBvW79i5(})F_T%GPy5C_W;D3Q%4OUkY zI7TH}K@m?_IXFljbP>^tTG^UT)LTEwwOsmQRN9$4>$dgqL6_vyy#`E@?CfkG(P>CuUiAm@z>Cp`D6bF?Zko1zKFnT+qbAE ze(dtAj4`k0h@U*U1iT&qJ9#x)RppNU1+ZdK(n|yD1S6w(k2ppRn{L{!%@f7RxYIj7RuLyCuT4DYb9A!vlT6i_v>bh45I{b6Jjm672`yfE`i zK}l)HNDnM`9F@(hlp0t{TTap zybr+>AVhC-3?6A|t7o0}Hh`aU@$k_@i?!Hj`-Hj+ zj!Q}!`h#S59&UnEkw`wa(XPtTurLrk)ZBu(Fh`jm0IUJvUyGEZ9Unsj3S@-k#oyI3 z?VfoBOQa`pM0Gk(_xv^F6gb_J@aD~sNu?ujn$#8N1b1d@W z;)M;Oy4sQniQmb|;}N|-EY?&Km&?mFp6URz{xDbqn~)Y&<&dH1 zbbq%fGV*&&i zdgivS_Vx0kGyM8i;aLm_eRD4_FHL*e&YfpGxyA}bRP)YPm?T?SeB_#$m&g%zBNo7=CEzW%@^(!kYsowj+2t+Upw!sui z!3bgmio8l~JvmucxyJ z=SGGnx||lEC3iphH;7J-j<$}$+ZLD9Ml@@HD?6C{25Jxm1qIMoYJI)^g=@o|?-`0I zmSdy*ms@*raTHGo+d5QUIQ$+joYBXj2iQCg{c3(*3uV7X&Iof0Gc%OHi`O0p#+?UA zdO)-k&|Jk*(gm0fT>)FIdPnWD!vK(4*5Ow;FxvnX1KoT8#0qNO439H3fr&{5aCLWK z@mg2gws69pPM?&dZ`t#SuzHwI>(JwKk@$#uHREGrkYl9PV2R#E{&GMGwc-Q~%9QkKBXM^ci8Y>6Q(avjXvJ2IOJYo(q3>Bs4%cF=5&|NzHGUR~rmWfATH*I6>({Tr_Kkezy;A_WO7-~T(BRP1h_?m}j{0s0%zhTYXNily zON776lz8=1?ww;uLW1S#D0l%W{Ah{@PCW@jyzB~PMYX93{& z+4{pXtJr2M*`>sQBObE85YR*-MO6#^QiII)E%F=f#lYYtLLYnI;=p~_@kck^7xtq- z!E*C(OzD!fCV0RrxqQK*VaEB0B}N{!K{F0VLa;Gza5;LnmL1PpJOxrAJwIRoREw)Z zf-w9PtE+3K!W&p~PY5!`@M~~)Wd}xrZx=oIjXf3(_@A#F$Zn!@M`YN){~1>>2|yFr z;ma%}q=2mP>O4=HArZik1vEH*RJmfi>6slwb(aDz$NNblPUnLU^Fl)9bc87SJAq;_ z^WFL=O(W9vkKIIzYEmoI;fdXJ&CyOlYQvQovMjUY9 z-DZ)xLNcHAC;-4HIP{o_akx`N^-H_}9zo(96cQTR_4(`oa(p;2w%Xj>oUc>=oQX-( zR`_J6h3fHRWgZ4m*&np0XGf%(UpD0H0K|4h<`H%zXUrE%!ka+^+gbv`IH3}z2 zN6nlqzCf@wMfipI_^y7=XD~8mb&meEVn@6`bYlJT2_YZRk;x8}SixsBrN`{z;_M#Q z>Er}5TC)Qv0V8O{vc3j2!0uc({1V58B_slaJWQ$oFsHn<^wP8C+xPJcdw18)K28AZ z63_}tq(#~Ts9#aBkbkeAb8-lN(H?oL_ib(_RY9dPz~X93LWA&R0~3ER4j|#;(Qr-u znkmf9ea^M+AhG0tX3}000?+2wCQH291BxpE)`q!AL|a%AVxMwa1b1}+Kyb#ZY&Lvr z5-o37^>Mx}RP@?ptWe2UB3X6vAAtgmlyeLOsMKh@`j`8-fYbmwmpt*~WY4+DBxWH>EN(!I~q5F!q}@()Le zM}XvaJ(Z9fZ`ob{6{#O5bRU$v!lxD zYL8!U{L6!be6)dNhKQc6_E}s>Z|Ukws+G2t3l`lvw7`=5l>3Dw{Y z8Qxo5UQVyO{44@FR;E+E+VPEsg6Au(#~uVMudgeO7V4e^#>c15&enopJ=bAehYphMECaI(TMmOiWx%96+;oeJK5Eo>0L*ifR^bwCSJwq&?BcsaNwnx`UK7 z+IUAyjUW)Tb-0FY`tM{vTd6f&T_2{j9USj+DmchPQ`?oA2kn_@s zO(3@q{~b!{*(wkm9nREWK#A>ldfm1qR8@2H@>GWmXkP_LWZW1*3qozKxDZ#guXD`(2x z*Wz6qoqq(!0Xd z7_3(==f4nF@;ZfCE8zTENIwsK{5PPrU;GcCwM-rWPGgg0W~-p}CJSv@I5-1TxPWjf zI4UtVIg6jxw*Mp``x!<-&aGgk6mTn;fjc{)ldhMv!p^&!MA<-H1y|xZq5Y~{|D(7x zH~02)<^SK%>)`n5ON;(~dVklgiPY1V+MvAh%E}Aly|&z)WvUHOYG1rGLuW84LgR)C zxLqwa5!;0{!wSXnr@@CiEtW%y5kAW9fq@Gl50+J{^$L}lfr1oClV)ifn+$DucId4F zdHK^?sgf}!HrCW)t=(m#Ay1W=7%bb>{3lVgzh4t1At`x(w)@>#OxLpG%cS!%u7A?h zu*`o1OHtRX;k{-BB&@$su~aIk$}NFPEml2-Btnyelne|kn_(pF2!jnosW5F6slHQr zgTuwg6_s;&F_vQAM+=w)5Pd&!=mG3R#lcJ(>@J+L&(aq;Sp(!9T_&A|&PLz!@}Uem z@?bS9n-7^@o%0_7t{M5HL1RLud=uwt9-~NP+GmB!wDUuhmNW0Z#Z`8#n+Y(?vGHx@ z1ba?TPYY*eI^}Tw0k5RW$!KV{R#$abub`kk<;-`KV?X^~WM(vAlyg+;T?6WS=g0;y ztzCKtgeu)KX#whH&plAP&nXAq!D0y*Z>WVafP89gWmV(pmOWu?Y8t!Gs!7HD;zdsW z`NijjLVY3Ys`qB22gi!xop270Ef}MvLU@qRM0fsb;d7GFKL_m^Hse3xFSW+pQC{}O zXkIxf3qox7`t@Sy!a-PDL~1eQBn8XfBMBDY2w7O>sUOi9*xGIZ zQWl`cW@m%QTEjRvJREL{h!oTRLvZ!8X_Fb#kkC<7RcJX3~@U{@4v2%Tz#PH)lq4 zUEU<#j*plwP5Z~x)M3qIk`WTqv0__A19ALCr zh#z4a+{L^^*OuAipN7+NK7UU6^2h8XSu0Lg zOJ&B+RGqh!OOJs4tb?<&yD#d4XevM>@d9pLi4QRiqL7)*lUL{GK;*1-rTZ@8R0BGb zkx{tu9&4Cy`usL1%snLe#704!|d(r6f&CPIg+E3gF6k z`<(oN!eF6UMi`OoUxTeHR#>>}x82}Hb-F`}`Oy}St6FuGa*ZOe{LOyP~rXFA6Rt6L}}HSdp|t+iUf z-l+4s>#7@AD9$UCAWs1(^Uam5!07haOW(BHtmj$fK)NaefU8C@3LC&tyHrhKPi|NF z{YOi#^Ot3Ffbkm~K`JcdQSKUl$Ird0)|=P&I1riFaOT-E%rbxXlQ=6D8L#_KrP(6O zt(Z$8=j~0TO$QT2^HaD?7X4u#SDF?p}mE!aJKkfm%yv^k3 zF$_5?U^Ikc!~5_0*g6`GrWk+Pis$zhkh%Whg+xxwL}9#+CZIeubCgA&g=*%&gPuM; zIKa~pVpi^(>IRZRcDATx!nusx-<^>^bpH=$Bn)OfTw+pY)`K3cZ_6oG2DfjEKwP&k zP0z~_w|i%rf)WdKEA1ezJD%1H&Ct_(V4RVfe>FcwH3S3Z$1VK${D-$)Am`Crg+d@rCWs%hCwKnFQeZ~FrqZ%6b z0|EfljEL#sM@WZxtR>>aE*_)3k8Zas;$cedLsu`)2fHGuo)`w~} zXMbYo>QWndoK25I0Be&n^EHQ&<*}~&7P1+sOuKDo-!Ng{c5F*f;q$@?ME?O0xfYq^ zUvP1$)0XoBX|}1U$-Fn|m3upJf?AF17L`IG5PdI>w-NcdfO-Y!P7I{6JL3(>J!aN) zL_ZtlG&EdS1%$V@wy127{{{#tMG$iXoe0Rw?o1$l9@Y#0S9l091vC?~3n*UiTwU1A zl$vzx12tbPAbn-X2va?v75q+I3K${*Ut}K-Z@%yFm=syW@c=)4iqj(wUjR4(qy#`M zRBmRLN{uM}8=s>$>2Nro0%=Zy>bs$hqPRAmBq1kHMY|c`yBdYp94xQ+Ui>s{a$ctWnY}4;KK%SSk5c(L4npJ4CfF0!lO3=Cr_MWby z!a@#j71!fSMm#*Hw#EkVn;{ZBr?NMg=P9CYw-)QCQGf_lq<5i;fQ`Y4`;jUw+CC5K*ByK^!?#Ud;@-4_0CEzCmQf|(3^L(Mpeg$E8AX4!B!{CE%J zvNk3bSF>oM_&O*xT2&Pwy?rVyu9tQzZx?lI^o7$#M61TYp93J~PhsdaoPOk=eS|#^ z`m#mPICjOSJDP zYk2}MWhiS_)d1NPx+gNCK+WR*f75zIW4o3g1blAe85YGwW#(}GJ9Q~qR-7X~&j6~X zqGDuYlPM$M?~g@5!)-B^aupmA4MbfCq?VJyH{VNBX^12xiiBQ*ft1hw_Q6h)c6N4h z^ExlpxXg~QSgWz1eN*)El)cR?`tdcNjf{>0&J|2-BHO8|C?Ca^#`!!BjGncB>*_-; zK7~e_1;cByKl#_Jq;ksIqIml@zJdn$A1g)60Oq}nMpoQE&3k~c(WOSkmVp7p$N+M9 z`Gm7iaj`A1=R3d0gyyV8=^wY+k2z}|^Rs8q(u(bV4Zj!gh8$OskwJFeJUJTv-7Vjw z{C5E<`uyzPA2p&;0{_4u%o$lBAzgrKa_VJ*wrmUE{z_pl@9bQjnrffyhL3Uc=1+ef z;n@H7=e>LRr$3LiCkikij4Tyt^BQR*_jtpk8CE{N>~xYL4Aax=iwRH9ib_b>nwpV0 zOOVADcm$Sq^5&F>m1Hx;cLAJ(VYTP<@85MLUBYNpgHBsh(+&at-j0r;4=k9N{++pv zoX{N400 z^>jFMhO3lr?@?SV>bc6VQ=!A843@>5M0#?L&&|ApBuUGLIEv9KTv z3Ck;6xj8G>*02>;h(2b>sHyQB@2AJYvQ3&4I@%hl)ppFwu&~r?@N60%x0w3=0&w5~ zs~So&#LG%knc$gxU7bkE4Xj&&`d_ijL5Nd#P81-Nfk2mlVJNnNx%OgAQI3;qucSzc z=+nx z5OM3jU}8Gih&5D%*uOm$A_J_^CkHF3nnea#-opPLA8d1D>{^}w8w=eD$Mb(@q4S+J z+*;WZ3J)jTQG#`^9%!@01)c<0?U!0DS|$P%nm0CJyQA4Ro1IbO=2lD=6)+u?*mAn< zv=4u2mg_m<(jseR^;&Qrxgb|Q`6B4FZ9E)21daS_6heiis;zyr+Ou|cV5V{saBg|P zPtd6On1nK`s4qp}!aKadN5`|Za2h-2Wb|F*=D?z)BqJvFAq4XKu~GG@>tQmW%MY@gpupa?tO}R&$Pr_fOAETb#N*BH~`muk${HUnpPn83B$%i%8|Hb={kb1Zy z0x$m9Q~7Mp6tSXj+t}a@tTn>9M`*Qrxiw};M#re^%RXxDrx_hoJ1KQwZm(5~h81bb zCzBR-kYozI@yEVA{9o;zXH-@9w)RPkL_ttdK|mlNO=(J%9+4uw_onoY^bRUb1VlwZ z%BJ@!O{9aM^xnJlvgy5TxDzosCc!(-x$l?v!^y~qNru37@3sDG&iOpgZ=%AwC4}QR zoE*%C@+#}=WdcL-8pHD;gEW`r6OQ~##qRIcl+kB+hZ=LLY4=O1UAS=^Oj})*4o!`1 z3hRU)AJP&X2x<^@B$nGDyEEczZe(u$L%9@%kW@9y}13S-?t5VDzP zak#2fkv#4gHs+;9;{bs~4%!3|mlMTJ-?P!6wd&kMFAI%$?RYSDWo|a+S?&J*({5~x zGo;mj7WLUs)XUYKSsv;9UR_B^I<_%2M{pDN7Tdwp7hJnMZ*Skz$au?Ut|20FleGFo zms_IR0L;6Y^qOb@Au z>FquA^F$_kMyp&@Y&@jd&Gq3I0#xA2@Wa50A#RCeM>xK77+^T-W{RLx0hu*~ZbxS= z7y*MGr>#{A549r4@xdKY4x-DG`w&HXzql=Kli%FDP$hWo(w*MA$>;Gkbu|(ZxEKvA zk^+)Ziy)wb{K4*7Fht>Rt?3lQZGO{uwPD|W; z&)^m@Rdst2;Jd{8pkm^NEQifpo-R^hQpVNwfTmm{A4X4QE+hLk)0;4N((Ie~K^Cg` zYf7!IzJ77vE2*?p-8}X8?r66t=(}i@%W`sZEaxWdn0K9K#K{+J*GRW#F_Mt%pe}b7KH&v-*d92qcLrrjvO!C3M3T@q)Rx=?97pX8XFXb#E;^u^7|~H~ZSJAlb}t ze5#?145K~MibK%}x>kEf2ZMT8DIhpk7=LnL=m%7Wg>p0wmu3ZKurC#SPgyFH=i-WQrF@xVEA?Ww!F z8%pBuD^ zAst!!vQEd-Q{csmpAlYiva*5U;aiMc57|jQTBeOjBz1KuNaJ&Io;xbPY`CIEA7W%_ zYYTx&**;|6`Z>O5qE145&nhYxXLHLXyLEK9WYzW4CcG(C61**%_SLn+?#4*}A=!XK zPCC?7Fj9vLWh_rYmi5*E5J#dat#N%f z)(xkI-7kh|2Hp&5kk7i8nw)%#l~rco2gbFuGIR5E2CnPZ`JUY;HyS3daP#=yxR$hk zU-;6MD_5Lz%grl4PFk{GlW^E+P%nwktM0Al>#Ls*mpTuPrT|&n6L)V`v%y}OzEk!@ zgWzxEM5wm2vR-rK5qT!<~UCznadZW}oaXTSEMtc+))?Za^p zi869@gd`zP!POvEJ~h)pzN|XrAKteKT}_v`(VT18kTuRoj|Fp&$49qLF)Z7T0{sBa z+u2(O95)_5)Jq(lB0o041#;B=(&}L*IUyd(s7#JaJ79Rk0sT$(DC^bLvCzE<%xB zX!j_A{RK1_Z#2iXQqMM|`X?DOGUXx$IB)PK&wQEUI}=l85)`_jwy}E)FJx0}{M9$d z8r_AA%{+W50?WevhidylX+3nbjY!SfyZ0Pe3W9sb74BDdmQxm~QX__1t_CFLf_-g+lkgNoVeq!;V;vP4Idu62J zF=hNS!@T|uz2A{Y2yIw=RC-czS2GG|Yvag{aSO|vaTxahY>Og=um5Ll5pBul-`b+( zAB2ro&-lIYLG7J|8+u<|e3xV~3fi`n7`gV9RRT?g{b9~`=lUaC=5QF=ym6HGj+ z#Ro!@2!9L=j2`E$s%NA3@EBAo46DE;TukJ`Hrh6_C0O*gT+gUWOjt>JzkL`b6OB_x zFwymUPkYi;NJD6dDJY4aKa17Smyzjk8_74{eiz;L@OtF*L?pM{ZR_e=f-9HtLgt5^ zUaCMCS7o~nhpy#P8-H3UUKr3ftfvAUt>{_9d6Fd5s3_rbRBK)0?T0rQ74UlWr?y(iZ$}ZhzjS+ za+}3@7NdzrgvK;3E~usfSK<5jJL6~NG4nl7V-a6qq%~N4Drq=nIGhbF5wmq|^m*Rh z^!%bhk8{6Y%2PYba;${3m$+)p&bk!qEsR!qfA%9vlagaHGR-kBS6-MOV|@5gl`a_f zad6MS*<>xa?oYo{N;d?fjK$h!>Ua`zf16%BkTr~}o8!5VP}|SU;@_zy8|qDXhWf_Z z)#INAeGK36#hRZ+BRHwgnv-8g1@IQwo;iGArdK~{DJvV*$sl47rjakDDW27@R8`K0 ziE3P)5)Y@Pr5kp2ik;)f!wWgRHoY}J8<*AMPP>&TQKoh36#p=^WAOg| znTNT32d+F%embzVU6_zx1yizijU-s{X%vwsCzV!D=*DIyFN!1jd&|}W{wCE37GuwH6Yy+WUlt&jh?;-Y0!eX>_O*eKQm3otE#G+b-2i> zteY^W%np24$@?E5cXW8*@-=sKIGYqTVad*NN@AkYt>B$a@OtRhqj-8-D45)P5o(!^}8Bdu+c#3D3z zNzD;d9xzmia@ilvCoGVNfaia&BZ_S)j>!qNDb zZ0QPcDLHj29PUGa9qMm?Decr*$(oZ6Jw0I?C> zH_&CP1AUjP%g>u6e$U+A^d^djn++o%^#URgOC1{XT~X)j=5w8fAdH02Ysw?;*bQ?D zd+Mx=wP0dkh>D0PW~%9GYZEd$e_$ot9XX^t>-o{VClm5G9UW2W>II8f3=D7!a^(8_ zP1I55{b^t58V`ZInoQApZUB$+9dkK@`%Y9sUEQy)d)3`ca~;W7q^8C5soulpe;XFI zyJKyhnE^NP_c9Df8|$iKVj{zKx5(HS%8QDM)&=_d)^711^!PulEyo(O8a6H^6F9Xtq zzkj}GVJM|~wDK*3<%;zAX*_!MpgJ9h?PqV17`??MN>De&As~D+MX;zy9+~LR(lnd^ zYyl1&hZ692QPYmN%{=ogRBj<2>O8thl9u4V`l5ewk&G(7Ky(T8Adr(3Gf|vlfEDLB7#EU6Tr9Gw+}3sTv$NeqLqn zmey=L`cXiAi{OjA!oR_cxOp#BOhHL$Vul*rtfs*kyndp|OacqIf5AuGP+M&1SOk14 zAW!C#UrjS;xV~Ni|JMyTqUP7vmGw+b={A_ZrG0KwPy~g^d~3<5j!kfi+#4fT!%icv z5os;e+?Z~xwZ{c#sI6y_Xfe3LS*bbNRaTfy(+xN2#kuP2cY7Q~__ZuhZ6@!+nVmRY zga*HQ;8=o-D3=y~zc&p-fIsve1sk&OEoU6uG^%N`xnG;Ca$dTSIvq$5RC{RZzkmAF zSr2*Ip6K5fd^+V7DCJyIZGAg+DT+7eC7mN^1LgY%23)eYwI@|`09W#!sQlOSL|l9B zv$VL#*^b82U#}-$dIKyP3jt3{&wsHW;OeYDoMdos+pFO${oG1hJH1AM<6~KLpR7yg z+goslx~Suiw;&&^JaYwzn>TOz`TKvnV$OWyPK4b)_4{8;X|mi1$ulY6MSQfG%rawR zpPK8XIK$)fsJ(I+LJ6-h?0B8|z2Sq)^ddMq*x5O_{Cu-AGJ@`tvzZAB2_ib%rc#X$ zEYMPiVvmhxOWgK5Z7)1Sl@a)0x`e;)Tze6spR}S~r6(3HranRXO2ps);2`PKSC1J* zSQoQ6;99;q(#ka~T7Mf#P_H8I#J@b`&^0EVmR%}Jccdh>C@4t7hr{=9=xK^8Ti4Q6lMUu76yN$NR*3e@x$OxPuB$R1`_5D!K;*;h5$pF3 zw$9?s#zvFrO^JHD<*yKjq66F`!h>SSCK%Ih2ILF#b&R*spKapl<{)~b7od=GFr08! zF(hQ98%A&wgoM)*6DjKaRi&kOQw(PzI;viZPy4gV-`lAT)gL!U;dG0Axjln}`?-=l zw^>*$tgKKvZL!ty@i5OZD)Z{>l%t|bBIYhKbbX1oj|AAl#>!K67>n)hnm}&VQ1&C( zu(g-Cqg8&G;(6oC`v(BQEVIhP)z`--z{SN8o=$3+ccEaVN0iEiES%T_$v^v{q%_N1 zFio#vVR`u+@it|Macf^gu9M=Do-kjaVW@{5i7^6OBv(i@*UnJupIsEGpgSCgir^1! z4>G>zjt&FmReLWzy+nu%0VXSq;!5jpM3J?aZd4_SMY|OT?pW{jbacd=_c8z`1*yH( zipSx>k+=@btE)lCev_4xJ1U|$JDb0G%{=$`Dvf6g)c4Rgm+*KjN)kLhKg5!a&*tVM z-Q??yUJs|5_>v=HDYkE1kyH_h*2oywZD7A${FOeX9`Y`c=TE#GSygb zuzzZ7WZqw}FdgVucm~}P50CBG<*qlOL8XQbFJ6&W8Y^VLkSYKt5L%tRszsy*(cKHkZ_P#!L{bu#6Oh)m1F|CYe#k(iSrNUg&^Zk^yEbG z!oz+Do@v0P5J3I1tYTCcg^!MAzfh->1A#xPG8SNQH2LD`+G#H#*zJV(x_+*pN&b_N z*N(%xeAIX?hu!^m!0_K|SLf$u_m;}>F0Ek<*}Fo?59yQlwwKZ9s47Ob)+F%`-W@=e ze4h*&Q6dx%l7uKnOVYmr*}{qA=q5r;L@8&$KeqWm(W2!HOyc`xOPZ z#8>h+{uP3Dws$>|F5Y7}#C`q!64-8O$;sOa)_$15^jEV=d-#^vu}qVfOs=qh9K;plZ~pe5b7+y$%xLbrYy%F8guf;XHJzT(fY&RpaT zh>FZtoyQ9c4W}R{Pv74~0>h}&`o|3mzh)FShsgwF*f>7eB&WX_Ds|d|_ok(>p3*}s ziq)n&T^Sl8r4Nr{e*X<*hp?hiwcFu8VkbnskxFm4+=+#Rt7WXLtAezxM z(|TbGJJZp`*2rl0NtF;(hbaj^!0vsLLxRUoI+AAaJKNb2LVP4y<)~A^z#1haEv41UO1`uQZo(gH*nguCc(!6)$26^aVcaO`k>n5q*q?w z){Gq~h~QAu6U{HArl#Tq5)1JYL+P5zSqH%t8A)~Z2t2xoy#+hMDDDQC;=^D5qM(hE z9LCH9w)WCDjXvsjS(}8&Nnp#)mR+5Uca;93T#2VK=TYh!YcYZXR#I$Qsq6b+W7W-<3kJ6%8#Cyyc+8(B*nI+edUL5>H-1nvoSN3 zVFFgIFZrW`!?(+$r8ao&+@E@5Q+lLp?4dv%g4fb#ax}?HB54YwxlB{0k!!uvBNI9g zd*TfkdMQwsvYOrjCv)LSO;kvx zlDs@c6cZA~f!W>im{L{epIIcKK4!QNdfQ?`GS&7>W}j~mvib09!IV)P*TfRtpgps= zn#V0N*Qm+yNky66FY&H#t;si6jpI8y*zT_>z&A>Te+=9R zq%s{T^&6I!DoD>ul1Fqc`Q&8U6%Pi%4 zSa_d&*zUKFfRt-V;$(3Fpbv2UU7~@Oj4k$jT?)Eu2eu4xjl80Pz4;QL7Vletc|c zxVXi-mS8a9umm4Sg;S%8f=wMAHA(N^Z%Uji(@cnLmYg{I3wC8?r6w&Z;*(aFxyuDS zN$%QaR}BS)sjto4hn$U%p1xR_Ok7;f)=F>P<0_uj#3e2}cy+pi`M5JLghBXQ3Q2S> zunSziKy93CP$a+%(o=ri1G-~IzXS1Siq6onzGD>NIL#kzomAPC*%5|Y(IHX!K@=ek z35iD*I<|OQpkTk3t`GD}>U19)!+E8orXRP#6kUf4X^p?dm!`ggAF{G-+G&$J&dq4$ z!-)PkWaN?s!I{h_uIawMzE?0l^-5oF(Ja{~9}hK(k%Zxq3YCy|@18|HI}>B%4c^Lj z%aQB;^L)+C62Qmk?k?l1Z*ONhLrT9uBr7A+mHASS?ZTa2mhOvK-szP?OUiHvtX*@{ zBuS0lLiTaflS-4lGJ5;ukP#6gB|Cx$3yE^u@9f(ZhZh4vMST)fLye7cM>GiZ`jD*= zwFHJQu@uE<`wTIc7w)`NFEX|=re$Pg zJj`ByhOVvt1JK{aE8_6X*>Nrd*o2wHx}rt&WSJ1bi09Yn(sQ@w#MX)E>v_d@5ijn? zA0}UC!OuarGvuqyn0X7{=q)0yBh_YX-g>Mvl=9rV+sp5zIK?F9n5##B!tz{;IJ41kplc6CRrhhO53uQ-fjui)Wn0(|_lhdcSz9Qdu4zOSES z@I6cM5nd}R@1Z;fqDxb4sT7(Pln%m$C# zu-prs*Z}+JSW$78p!xiAQIQQ5P<4}CL%{PXH@q1vcubbyFn<+vjDaYVC%^0 zJ=N{JB%FL5I&sWz6s=U1l~?`!tt?lq3qF0LPz*PcnFQMth!wvm5|*sW4sMu)qXqD% zW)B}~Ok2G{51)x^YIIzjYuDK66qw9r-6Kw@RHr_UMlqIPo6&n*n8ZW!lil{Nl8!XC zdRNf#NHtWsWq^~NwfADaa5UAc`y|yA+dG@fYa4|&dsm8(8#EH%BPo(2Gt#snT@1E$ z7+m`Ds;a%zd^ERyBR{Rw7Pb5Aq(RLxn^O<*W?|_`pnv;O1LU6{`N5h zcV0R;C7$a2W5C1|^Tk)vySwuaxg*mv$fN}Q`F@uNn~k$J-H+BbiG+l_x01xC)^^}f zEV_FUWi)G;)Am_TK>_8!}Bo&nqzJ$>L1rhTO`YEZSJzD))2|Rz2DUR$1{Vu=2@~jli5gu(J&qmelP}b=s z4PJ=$jijq>HkcO&Dat-kDcZd(LK(P$J>St^dJ66FA;*szN)Kt6n!XbCUK(kM?U2@-f*zVxyZl|f6_ATS0d2`b4bS=1+VD4n}PL<<(T z>A)4nl5@15E6XQ%`!eJambW(89d;w;_~G~Lzm-0UbZe9emT$L`o`R@D%C66a)#ib5 zNIC*~a(yL9^O`Tm6;{THg%$1O#AZY(rDwU#WPe5guj(d}#OajNUI0FejEy{w&w6_h z5>Nr}m0XWjh~;;JMeNHH^F&?;6(yy34k#Kj)eo!u!wV>6ZZze9yAbjWfUZ|&r(mbB z8S;t(V-MK&VU!PrGk)(tR1Fik$1mrJ-@aOz2jvOMLJ08fV212%oQ)291H432m~+6v zAgXt?*i3_ogCPb?IDnJ}I<9H|81P_f?ZZ+WhZmrxgaPnQUWrce-e z4#=9g%rfaM3&AJz#!=;P%LOcDNHK@kuiDzG01G@@v;<$iT-5Gxc5;R~IrTLj?iIF& zeLy+@Ls?A?uaOD5BHlC%_{;|VGSk7?H!+RJ(K~QM6@mE0;{u#@%`)ul4qzki&(H6& z8990OIWWNMEr&ybIhZpiBS?p|`h20O)$ffmN6om_R^_O^hhF?)sGA0`_lU zCIR0OwYMS7J()zFnf#l_vbdP_kR7}-d-d76St3V?5nSuz4`|*6Zc! zm+^L0JYE}5r0W!t@^}e8H&A-c5wx1`_rCiWI|czR7+wgIXBya_5`X@6(_7x}XXPnr zrwIum^1xWMSzGO~v@~tCeP0e`98L|WTC2-vSP$|Nns0nWx(yc{Ow-L}gMb5ktHPUj zZ)N@b{mzg=q^!pUGK`OVf}lJHD!kR5YrruQ6vZOmPL#V@>N0KSo%fU&B+$l^$!)5Bay7C&XPcrwuesVPM$py&DT*2@RPxGDfeN;FI021{g z$GA$G(0vyduV2sim2N%Y(~?0@!nhVD1W>e}JJ$~b0Bk~zZ7F^oR7*C;heBAaz`D5u z8-39pt8nnXf`|4Juiq9tv9A!xCK+zj>q47UU*qu-GbHnx4_8~c<^zZu11^S8ZM5P5 zr9|8PM)*>aSXgqz_V|=3?0UfPecm7t3v6GO(KRc}wf9T=ajv1dP!rCLmFNy+(S>Lq zeL4$YnLMRfPbx-p19FeGDN~*I+r1|isC?8*}5%Nz+ zP*>;-^pM;K51K!AFa9(m()#5mxDvq+oR@#f!4vA?2u>tQ-k4QKpVxdriQuvJCA7TG za}=G$ft2q}jrW@RmsE=xiu}DlX^DsLH^bSdNW`nIuAVU}14&dS()h!07fL^(uGej4 zMk)#6hpz_9a=ftd-@bjbZ`3Wx?+)MYF)@#4`07eog?&>hQbbh0^YKYFd`q8gW#V}8+j<31+sz!h;yT1!s z_ggoaJsi25rmW|l%=vIlzCUV!*7z+~b} zGJ$R`Pu0#ZIwHQC$L3IC&>GNFZY_lt?T`%stb8>A?Ih8UR4=yXJ6F~i%3>oy_%K#< zbC~G$fx*HBK0&W@Sl9#+K`7^%tYQG#fo7irn7GZ!IRNp)3DSbwBq<`n4Z97*#hZXP zut0RWpzd2%MQ{|tEr8&#(x{rx$AxEI1COTMwBy|{gV|!?z)i}45KAxg0P)?G z-4JXHNTd_FUSDbnZ#y~yFj834ekX;TY;d1Wmug`Jnp@$3Z z2mXN`#>gKHco5Scgqek(%H8zmuqa9wQ&OPx^W#WyK8GkRA4pZRd`F8D0n**1MP4S@J{Ue&b;$*3=R!K zan+3UcstJZqx6KilUX-W6 z4rEC8#}rjEX%_VBgbpZ1{JUk*{vlyR^e`cn$kqTFlswvZ^T=>xM-{>$8iw0WF-;}ZZ zb6nC%p-{vrLvWPBeDK%}u0pZWhMk7Po3dhJ+u%6!4&d)fq3jYIP-4p$DK`6z3?jIU zW+2e?h%757M`ULqiGv(x*8RgTyd%V}WjqCDT~DxKi8BU?F#lb-krZC{HO(l0xP6a_ zFK0-Pi7&{KU%-B^cf1gx&hzV7qH9TP_Jtf7g$GQU+PGBc0$b;;nW;Gz^xO%%^w{oy zi&zeY8j`OQc9DZK>R)7;dUjQNs*66=ppt26eWdb;hp{$FHnM;KI`kAdN5JFl`WoYy zy2HWU&!YUUQd_nPF(H5T>z_l4kNXd~JJV|R)Z|pgj06#PIxXE?h!o(S0qzWo7J&aL zc9pH@!^9_uBzU|`4%CMV7|YG6Bq8CncNM7GViC9Ar`h4rjTioCOM&qd+9Z9hjLghM z!mCoe0{#MNx;SBo7w7^>Lne>n;9@(Oow?(Amf+|vI#F;>T^+G%SRyBTW#42+2=Xt~ z$&;3Q>x(wCb6ACH8s$NhD!XQ^>14%v49gDw*N);qO!EH&)A}l3K9vnOl2nZ;gYw|CBc-rf+h$t*NQdIg+{I zO8*Wo$Wz#H?k+YB*fH-D<3JPw(knyVRtN5`_M3#l1gc_v7Cvz!*i>mytxr> za6b+U6`SYfSuM*C?fLmyc17YL00n>==zF!e{R(WLIX3@ygtXu4>WylAD&o|K_pdb2kMm^ zsKf19)B&X%H#n8d73lXS3x+_HO_4|vN&X5^IfwQ;6YRT4Q*>Q{I46fWl!qFMMWqoD zf9c>CZ=lV*RHN5i@5_O;&Ctff$xOgxR1L-W>MG{@g?%hMMJO;Uko?nBup2QNnn zCp-L01rp=`klKv#_od#|6Wc1UtCR_ZXtFJYn?UjRd5`fw-!*c);2da)itw5(>K(kw=y=An@aCKIx2(( LB=|G=9z6XY;PJf% literal 0 HcmV?d00001 diff --git a/artifacts/verification/w6/states/command-palette-80.txt b/artifacts/verification/w6/states/command-palette-80.txt new file mode 100644 index 0000000..a130612 --- /dev/null +++ b/artifacts/verification/w6/states/command-palette-80.txt @@ -0,0 +1,14 @@ + Commands +──────────────────────────────────────────────────────────────────────────────── +> +→ /new Create an empty conversation + /open Search and open conversations + /profile Inspect, select, import, or edit a profile + /connection Inspect and manage connections + /runner Set the runner for this branch + /model Set the model for this branch + /effort Set reasoning effort for this branch + /branch Create a branch at a message boundary + (1/29) +──────────────────────────────────────────────────────────────────────────────── + type to filter · enter to choose · ←/esc close diff --git a/artifacts/verification/w6/states/comparison.json b/artifacts/verification/w6/states/comparison.json index a50e2be..b696bb6 100644 --- a/artifacts/verification/w6/states/comparison.json +++ b/artifacts/verification/w6/states/comparison.json @@ -4,8 +4,8 @@ "source": { "binary": "packed real binary from clean npm install", "binarySha256": "141288e0fe917635d723b4b70d464dc49baff14cc356f54de1d3f8faa5d8254f", - "tarball": "tangle-network-braid-0.1.1.tgz", - "tarballSha256": "9bbd7b5b9f78b3d202dbb09d4375970edfd4965ffc5ad94b04bd7fa6ce01c4c7" + "tarball": "tangle-network-braid-0.2.0.tgz", + "tarballSha256": "50e56ffd482a1cdd0ecd6c2a9630a4d9171fe8bacee35cfdbc58977695e815b1" }, "dimensions": { "columns": 80, @@ -14,7 +14,7 @@ "terminal": "node-pty/xterm-256color", "provenance": { "renderer": { - "package": "@earendil-works/pi-tui@0.84.1", + "package": "@earendil-works/pi-tui@0.84.2", "pty": "node-pty@1.1.0", "emulator": "@xterm/headless@6.0.0", "node": "v24.13.0", @@ -30,7 +30,7 @@ }, "capturePhase": "atomic-signal-frame", "captureRevision": 1, - "frame": " activity · analyses › /compare · frozen runs · complete · 1/1\n────────────────────────────────────────────────────────────────────────────────\n saved result: replayed from the local journal\n baseline run: run-route-serial\n baseline source: 9ee7d219c8b0092…8c519924\n baseline outcome: completed · cost: 0.014 · source: frozen run field\n run.cost_usd\n candidate run: run-route-parallel\n candidate source: 0328e6889082b14…86b0ff3d\n candidate outcome: completed · cost: 0.009 · source: frozen run field\n run.cost_usd\n sample: 1 paired · 0 baseline-only · 0 candidate-only\n ! One pair is descriptive; it cannot support a reliable general conclusion.\n captured fields · baseline | candidate | availability\n run.status: completed | completed | none\n run.cost_usd: 0.014 | 0.009 | none\n run.wall_time_ms: 18200 | 12100 | none\n run.input_tokens: 7420 | 6910 | none\n paired measurements · candidate minus baseline where applicable\n paired.correctness.b01: 0\n paired.correctness.b10: 0\n paired.correctness.mcnemar.b: 0\n────────────────────────────────────────────────────────────────────────────────\n ↑↓ previous/next · PgUp/PgDn page · ←/esc back · page 1/4 · tab filter: analys…\n", + "frame": " analyses › /compare · frozen runs Braid starter · pi · fixture/deterministic\n────────────────────────────────────────────────────────────────────────────────\n saved result: replayed from the local journal\n baseline run: run-route-serial\n baseline source: 9ee7d219c8b0092…8c519924\n baseline outcome: completed · cost: 0.014 · source: frozen run field\n run.cost_usd\n candidate run: run-route-parallel\n candidate source: 0328e6889082b14…86b0ff3d\n candidate outcome: completed · cost: 0.009 · source: frozen run field\n run.cost_usd\n sample: 1 paired · 0 baseline-only · 0 candidate-only\n ! One pair is descriptive; it cannot support a reliable general conclusion.\n captured fields · baseline | candidate | availability\n run.status: completed | completed | none\n run.cost_usd: 0.014 | 0.009 | none\n run.wall_time_ms: 18200 | 12100 | none\n run.input_tokens: 7420 | 6910 | none\n paired measurements · candidate minus baseline where applicable\n paired.correctness.b01: 0\n paired.correctness.b10: 0\n paired.correctness.mcnemar.b: 0\n────────────────────────────────────────────────────────────────────────────────\n ↑↓ previous/next · PgUp/PgDn page · ←/esc back · page 1/4 · tab: analyses\n", "packedState": { "schemaVersion": 2, "capturePhase": "atomic-signal-frame", @@ -38,7 +38,7 @@ "schemaVersion": 2, "revision": 1, "sequence": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "conversationId": "conv-1", "branchId": "branch-1", "conversations": [ @@ -60,6 +60,13 @@ "reasoningEffort": "none" } }, + "runConfiguration": { + "profileName": "Braid starter", + "runner": "pi", + "model": "fixture/deterministic", + "effort": "none", + "overrides": {} + }, "draft": "", "messages": [], "runs": [], @@ -113,12 +120,13 @@ }, "view": { "revision": 1, - "workspace": "/home/drew/code/braid-transcript-first-wt", + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816", "profileName": "Braid starter", "profileDigest": "44ed91c937fd4079fe01c49f6bc76413656886e5aa8b2351590d3a888cfa0a14", "runner": "pi", "model": "fixture/deterministic", "effort": "none", + "runOverrides": {}, "connection": "deterministic fixture", "conversationId": "conv-1", "conversationTitle": "New conversation", @@ -211,9 +219,13 @@ "status": "complete", "depth": 1, "edgeLabel": "attached", + "parentIds": [ + "conversation:conv-1" + ], "startedAt": "2026-08-01T00:00:00.000Z" } ], + "graphQuery": "", "entityDetails": [ { "entityType": "analysis", @@ -304,19 +316,16 @@ "source": "application" }, "run.runner": { - "available": false, - "source": "application", - "reason": "Runner overrides require the current profile compatibility helpers" + "available": true, + "source": "application" }, "run.model": { - "available": false, - "source": "application", - "reason": "Model overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "run.effort": { - "available": false, - "source": "application", - "reason": "Effort overrides require provider capabilities from the current connection" + "available": true, + "source": "application" }, "conversation.branch": { "available": true, @@ -446,7 +455,7 @@ "payload": { "value": { "kind": "workspace.opened", - "workspace": "/home/drew/code/braid-transcript-first-wt" + "workspace": "/home/drew/code/.worktrees/braid-exact-interactive-20260816" } } } diff --git a/artifacts/verification/w6/states/comparison.png b/artifacts/verification/w6/states/comparison.png index b31c3d2366550ca2c1449a2b8e873ca1c32bfb47..4fa1535112f1ab0a6f6c486529477a9f060f2167 100644 GIT binary patch literal 68314 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 E#d_#SUb4TvfSjJ^kDMHagU4yg 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 -;TQkqTK9r?+~gyE$ZLs&f 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