@robota-sdk/agent-framework 3.0.0-beta.78 → 3.0.0-beta.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # @robota-sdk/agent-framework
2
2
 
3
+ Runtime hosts are owned by this package: import `createHeadlessTransport`,
4
+ `HeadlessInteractionChannel`, `createProgrammaticAgent`, `ProgrammaticInteractionChannel`,
5
+ `TransportRegistry`, and its file/memory settings repositories from the root. Their implementation
6
+ lives in `src/transport-host/`; terminal `PrintTerminal` and `promptInput` are local to the CLI.
7
+
3
8
  Programmatic SDK for building AI agents with Robota. Provides `InteractiveSession` as the central client-facing API, `createQuery()` for one-shot use, `createAgentRuntime()` as a composition factory for headless and multi-session consumers, session management, SDK-owned command/common APIs, permissions, hooks, streaming, context loading, bounded prompt file references, and context reference inventory.
4
9
 
5
10
  This is the **assembly layer** of the Robota ecosystem — it composes lower-level packages (`agent-core`, `agent-tools`, `agent-session`, `agent-provider`) into a cohesive SDK.
@@ -16,7 +21,7 @@ pnpm add @robota-sdk/agent-framework
16
21
 
17
22
  ```typescript
18
23
  import { createQuery } from '@robota-sdk/agent-framework';
19
- import { AnthropicProvider } from '@robota-sdk/agent-provider/anthropic';
24
+ import { AnthropicProvider } from '@robota-sdk/agent-provider-anthropic';
20
25
 
21
26
  const provider = new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY });
22
27
  const query = createQuery({ provider });
@@ -28,6 +33,8 @@ const response = await query('Show me the file list');
28
33
  const queryWithOptions = createQuery({
29
34
  provider,
30
35
  cwd: '/path/to/project',
36
+ // A bare cwd is provenance only. Pass a host-issued TWorkspaceProjectAccess decision
37
+ // when this query may consume project context or settings.
31
38
  permissionMode: 'acceptEdits',
32
39
  maxTurns: 10,
33
40
  onTextDelta: (delta) => process.stdout.write(delta),
@@ -44,7 +51,7 @@ store, transports):
44
51
 
45
52
  ```typescript
46
53
  import { createAgentRuntime } from '@robota-sdk/agent-framework';
47
- import { AnthropicProvider } from '@robota-sdk/agent-provider/anthropic';
54
+ import { AnthropicProvider } from '@robota-sdk/agent-provider-anthropic';
48
55
 
49
56
  const runtime = createAgentRuntime({
50
57
  cwd: process.cwd(),
@@ -55,31 +62,81 @@ const runtime = createAgentRuntime({
55
62
  const session = runtime.createSession({});
56
63
  ```
57
64
 
65
+ Without `projectAccess`, the runtime exposes an observable Restricted decision and does not construct
66
+ project context, settings, memory, session, or log adapters. A host that has inspected or granted a
67
+ workspace through `WorkspaceTrustService` passes that exact `TWorkspaceProjectAccess` decision.
68
+ Project persistence is then composed explicitly from its named state facets; a bare `cwd` never
69
+ creates a project store. A per-session `sessionStore` replaces the runtime store, while an explicit
70
+ `sessionStore: undefined` disables persistence. Trusted runtime/query construction accepts the frozen
71
+ workspace root and its real descendants while rejecting a working directory outside that identity; a
72
+ completed revoke makes the previously issued authority and all of its facets unusable. Explicit host
73
+ contribution sources also remain root-bounded and refuse links at every path component.
74
+
75
+ Authority-backed project mutations share one stable-root boundary: on Linux, open root and parent
76
+ directory descriptors prevent parent renames or symlink swaps from redirecting writes, replacements,
77
+ appends, or deletes. Hosts without equivalent stable handle semantics fail closed with
78
+ `WorkspaceAuthorityRequiredError` instead of falling back to pathname mutation.
79
+
80
+ Replay-only project recovery validates the versioned JSONL before reconstructing a session. Loads and
81
+ listings report malformed logs as `corrupt` and unsupported versions as `unsupported`, rather than
82
+ hiding them as missing sessions. Snapshot encoding is unchanged; unversioned legacy logs are not replayed.
83
+
84
+ The maintained offline examples verify explicit persist→resume composition and the workspace
85
+ authority boundary with no provider credentials:
86
+
87
+ ```bash
88
+ pnpm --filter @robota-sdk/agent-framework scenario:verify
89
+ ```
90
+
91
+ ### Runtime host (`robota --serve`)
92
+
93
+ `buildRuntimeSession()` is the single session-construction seam: every presentation — the TUI channel
94
+ and the headless `robota --serve` entry — builds its `InteractiveSession` from resolved options through
95
+ it, instead of calling `new InteractiveSession` directly. `startRuntimeHost()` adds the transport
96
+ `startAll`/`stopAll` lifecycle plus a bounded shutdown handle on top, and is used by the headless
97
+ `--serve` path (which the desktop GUI spawns as a loopback-WS sidecar). It lives in `agent-framework`,
98
+ not the product shell — it takes already-resolved options and is presentation-neutral (RUNTIME-001).
99
+
100
+ ```typescript
101
+ import { startRuntimeHost } from '@robota-sdk/agent-framework';
102
+ import type { IRuntimeHostOptions, IRuntimeHostHandle } from '@robota-sdk/agent-framework';
103
+
104
+ // `session` holds the resolved session options; `transportRegistry` is the loopback WS sidecar.
105
+ declare const options: IRuntimeHostOptions;
106
+ const host: IRuntimeHostHandle = await startRuntimeHost(options);
107
+ // host.session — the live runtime session every presentation drives
108
+ // await host.shutdown() — bounded transport teardown + session shutdown
109
+ ```
110
+
58
111
  ## Features
59
112
 
60
113
  - **InteractiveSession** — Event-driven session wrapper (composition over Session). Central client-facing API for CLI, web, API server, or any other client
61
114
  - **SystemCommandExecutor + ISystemCommand** — SDK-level command execution infrastructure for product-composed command modules
62
115
  - **CommandRegistry, BuiltinCommandSource, SkillCommandSource** — Command registry and SDK common discovery APIs. User-visible built-ins are composed through `agent-command` packages.
63
116
  - **Model Command Common APIs** — Provider-neutral `/model` helpers that resolve active provider catalogs and optionally invoke provider-owned refresh hooks
117
+ - **Model effort selection** — A typed provider-neutral selection record and command-host adapter keep source and provisional display state consistent across startup, live commands, and headless output; `auto` remains unpinned until the provider adapter reports its outcome
64
118
  - **createQuery()** — Provider-bound factory for one-shot AI agent interactions with streaming support
119
+ - **Runtime host (RUNTIME-001)** — `startRuntimeHost()` builds and serves a headless session over a loopback WS (used by `robota --serve` and the desktop GUI sidecar); `buildRuntimeSession()` is the shared session-construction seam every presentation builds its `InteractiveSession` through
65
120
  - **Session assembly** — Internal factory wires tools, provider, config, and context for `InteractiveSession`
66
- - **Built-in Tools** — Bash, Read, Write, Edit, Glob, Grep, WebFetch, WebSearch are assembled for SDK sessions; direct tool usage imports from `@robota-sdk/agent-tools`
121
+ - **Built-in Tools** — Shell/Bash, Read, Write, Edit, Glob, Grep, WebFetch, WebSearch, AskUserQuestion are assembled for SDK sessions. The set itself lives in `@robota-sdk/agent-tool-defaults` (a composition leaf, ARCH-035) and is loaded lazily; import it from there to compose your own tier, or `@robota-sdk/agent-tools` for individual tools
67
122
  - **Sandbox Execution** — Optional `sandboxClient` injection routes Bash and core file tools through a provider-backed execution plane; `workspaceManifest` can prepare a fresh sandbox workspace before session creation
68
123
  - **Sandbox Hydration** — Snapshot-capable sandbox clients persist `sandboxSnapshotId` on shutdown and restore it before saved message replay on non-fork resume
69
124
  - **Agent Tool** — Sub-agent session creation for multi-agent workflows
70
- - **Permissions** — 3-step evaluation (deny list, allow list, mode policy) with four modes: `plan`, `default`, `acceptEdits`, `bypassPermissions`
125
+ - **Permissions** — one evaluation order for every caller (deny, ask and allow lists, never-auto-approved calls, mode policy) with four modes: `plan`, `default`, `acceptEdits`, `bypassPermissions`
71
126
  - **Hooks** — `PreToolUse`, `PostToolUse`, `PreCompact`, `PostCompact`, `SessionStart`, `UserPromptSubmit`, `Stop` events with shell command execution
72
127
  - **Streaming** — Real-time text delta callbacks via `onTextDelta`
73
128
  - **Context Loading** — AGENTS.md / CLAUDE.md walk-up discovery and system prompt assembly
74
129
  - **Prompt File References** — Path-like `@file` prompt references are resolved by the SDK under the session `cwd`, bounded by size/recursion limits, recorded as structured history events, and registered as observed context references
130
+ - **Stable Project Reads** — Project byte and text reads use a bounded retained-root authority on qualified Linux, macOS, and Windows hosts; unsafe link/reparse replacement fails closed while project purpose, liveness, generation, and identity checks remain framework-owned
75
131
  - **Context Reference Inventory** — Manual `/context add` references are stored by `InteractiveSession`, included in future prompt model input, and exposed through SDK command common APIs
76
132
  - **Config Loading** — 6-file settings merge with provider profiles, legacy provider compatibility, and `$ENV:VAR` substitution for provider credentials
77
133
  - **Context Window Management** — Token tracking, configurable auto-compaction (default ~83.5%), manual `session.compact()`
78
134
  - **Background Jobs** — Runtime-managed subagent tasks with transcripts and task snapshots
79
- - **Agent Batch Jobs** — `Agent({ jobs: [...] })` starts explicit parallel subagent requests deterministically
135
+ - **Agent Batch Jobs** — the model-facing Agent tool's `jobs` argument (`Agent` invoked with `{ jobs: [...] }`) starts explicit parallel subagent requests deterministically
80
136
  - **Edit Checkpoints** — Checkpoint/rewind support for safer edit workflows
81
137
  - **Project Memory** — Command-driven memory capture and retrieval surfaces
82
138
  - **Replay Events** — Session execution can forward provider/tool boundary events and provider-native raw payload events into append-only logs
139
+ - **Usage observations** — Each accepted top-level turn records one content-free outcome observation, including the active model and driver surface when known, even when token usage is absent
83
140
  - **Bundle Plugin System** — Install and manage reusable extensions packaged as bundle plugins
84
141
 
85
142
  ## Architecture
@@ -95,8 +152,9 @@ agent-framework (assembly layer)
95
152
  ├── createQuery() ← one-shot entry point factory
96
153
  ├── createSession() ← internal assembly factory
97
154
  └── deps:
98
- agent-session (Session, SessionStore)
99
- agent-tools (tool infrastructure + 8 built-in tools)
155
+ agent-session (Session, neutral session ports, explicit Node host adapters)
156
+ agent-file-authority (stable bounded project byte reads over retained native handles)
157
+ agent-tools (tool infrastructure + 9 built-in tools)
100
158
  agent-provider (consolidated AI providers: /anthropic, /openai, /gemini, …)
101
159
  agent-core (Robota engine, providers, permissions, hooks)
102
160
 
@@ -104,7 +162,7 @@ agent-cli (TUI layer — bridges InteractiveSession events to React/Ink state)
104
162
  → agent-framework
105
163
  ```
106
164
 
107
- The SDK is **pure TypeScript with no React dependency**. The CLI is a thin TUI-only layer that consumes `InteractiveSession` events and maps them to React state. Any other client (web app, API server, worker) can do the same.
165
+ The SDK is **pure TypeScript with no React dependency**. The CLI is a thin presentation layer (TUI, plus the `--serve` runtime host) that consumes `InteractiveSession` events and maps them to React state. Any other client (web app, API server, worker) can do the same.
108
166
 
109
167
  ## API
110
168
 
@@ -113,17 +171,33 @@ The SDK is **pure TypeScript with no React dependency**. The CLI is a thin TUI-o
113
171
  `InteractiveSession` wraps `Session` (composition over inheritance) to provide event-driven interaction for any client. It manages streaming text accumulation, tool execution state tracking, prompt queuing, abort orchestration, and message history. Logic that was previously embedded in CLI React hooks now lives here.
114
172
 
115
173
  ```typescript
116
- import { InteractiveSession, createProjectSessionStore } from '@robota-sdk/agent-framework';
174
+ import {
175
+ InteractiveSession,
176
+ createProjectSessionStore,
177
+ getWorkspaceProjectStateStorage,
178
+ } from '@robota-sdk/agent-framework';
117
179
  import type { IAIProvider } from '@robota-sdk/agent-core';
180
+ import type { TWorkspaceProjectAccess } from '@robota-sdk/agent-framework';
118
181
 
119
182
  declare const provider: IAIProvider;
183
+ // Supplied by a host-owned WorkspaceTrustService configured with projectStateDirectories
184
+ // after identity/trust validation.
185
+ declare const projectAccess: TWorkspaceProjectAccess;
120
186
  const cwd = process.cwd();
121
- const sessionStore = createProjectSessionStore(cwd);
187
+
188
+ const sessionStore =
189
+ projectAccess.status === 'trusted'
190
+ ? createProjectSessionStore(
191
+ getWorkspaceProjectStateStorage(projectAccess.authority, 'sessions'),
192
+ getWorkspaceProjectStateStorage(projectAccess.authority, 'session-logs'),
193
+ )
194
+ : undefined;
122
195
 
123
196
  const session = new InteractiveSession({
124
197
  cwd,
125
198
  provider,
126
- sessionStore, // SDK-owned project-local persistence facade
199
+ projectAccess,
200
+ sessionStore,
127
201
  resumeSessionId: 'sess_123', // Session ID to restore, incl. sandbox snapshot (optional)
128
202
  forkSession: false, // Fork the resumed session into a new one (optional)
129
203
  permissionMode: 'default',
@@ -156,8 +230,11 @@ session.on('interrupted', (result) => {
156
230
  // abort completed
157
231
  });
158
232
 
159
- // Submit a prompt (queues if already executing, max 1 queued)
160
- await session.submit('Explain this code');
233
+ // Submit a prompt. The handle identifies this accepted turn even if it waits in the queue.
234
+ const handle = await session.submit('Explain this code', undefined, undefined, {
235
+ driverId: 'owner',
236
+ });
237
+ await handle.completed;
161
238
 
162
239
  // Path-like @file references are expanded into model-only prompt context by the SDK.
163
240
  // The user-visible history keeps the original prompt plus a structured file-reference event.
@@ -199,6 +276,22 @@ session.setName('my-task'); // sets the session name
199
276
  session.getSession(); // Session
200
277
  ```
201
278
 
279
+ `WorkspaceTrustService` accepts host-owned identity and trust-store adapters. Its authority is opaque,
280
+ runtime-registered, root-bound, and cannot be reconstructed from a path or serialized marker. See the
281
+ maintained offline `verify-workspace-project-authority.ts` example for a complete inspect/grant/revoke
282
+ composition and Restricted-versus-trusted observable.
283
+
284
+ The Node host supplies the production lifecycle through
285
+ `createNodeWorkspaceTrustService(trustStorePath, projectStateDirectories)`. The caller chooses the
286
+ user-owned store path and all four project-state directories; the Robota CLI uses
287
+ `~/.robota/workspace-trust.json` for the trust store. Omitting project-state directories still permits
288
+ trust inspection, but deriving project-state storage then fails closed.
289
+ The service binds grants to the canonical Git worktree and repository common-directory identity,
290
+ stores only owner-readable generation records, and treats non-Git paths, repository replacement,
291
+ revocation, and trust-store errors as Restricted. A later provider settings layer that changes `baseURL`
292
+ without its own credential also clears inherited `apiKey` and `apiKeyEnv` fields; endpoint provenance
293
+ diagnostics can report the quarantine without exposing the credential.
294
+
202
295
  ### SystemCommandExecutor — SDK-Level Commands
203
296
 
204
297
  `SystemCommandExecutor` executes named system commands against an `InteractiveSession`. Commands are pure TypeScript — no React, no TUI dependency. The CLI wraps them as slash commands with UI chrome.
@@ -206,7 +299,7 @@ session.getSession(); // Session
206
299
  ```typescript
207
300
  import { SystemCommandExecutor, createSystemCommands } from '@robota-sdk/agent-framework';
208
301
  import type { ICommandHostContext } from '@robota-sdk/agent-framework';
209
- import type { ICommandResult } from '@robota-sdk/agent-interface-transport';
302
+ import type { ICommandResult } from '@robota-sdk/agent-interface-command';
210
303
 
211
304
  declare const session: ICommandHostContext;
212
305
  const executor = new SystemCommandExecutor(); // starts empty unless commands are supplied
@@ -253,11 +346,15 @@ validate the current JSONL session log. Hosts may override `validateCurrentSessi
253
346
  These classes provide slash command discovery and aggregation for clients that expose a command palette or autocomplete UI.
254
347
 
255
348
  ```typescript
256
- import { CommandRegistry } from '@robota-sdk/agent-framework';
349
+ import { CommandRegistry, createNodeHostContributionSource } from '@robota-sdk/agent-framework';
257
350
  import { createSkillsCommandModule } from '@robota-sdk/agent-command';
258
351
 
259
352
  const registry = new CommandRegistry();
260
- registry.addModule(createSkillsCommandModule({ cwd: process.cwd() }));
353
+ registry.addModule(
354
+ createSkillsCommandModule({
355
+ contributionSources: [createNodeHostContributionSource(process.cwd())],
356
+ }),
357
+ );
261
358
 
262
359
  // Get all commands (returns ICommand[])
263
360
  const commands = registry.getCommands();
@@ -269,25 +366,33 @@ const filtered = registry.getCommands('mod'); // matches "mode", "model"
269
366
  registry.resolveQualifiedName('audit'); // "my-plugin:audit"
270
367
  ```
271
368
 
272
- `SkillCommandSource` is the SDK common API used by the skills command module. It discovers skills from (highest priority first):
273
-
274
- - `<cwd>/.claude/skills/*/SKILL.md`
275
- - `<cwd>/.claude/commands/*.md` (Claude Code compatible)
276
- - `~/.robota/skills/*/SKILL.md`
277
- - `<cwd>/.agents/skills/*/SKILL.md`
369
+ `SkillCommandSource` is the SDK common API used by the skills command module. The host supplies both
370
+ the contribution sources and ordered root descriptors; absent sources or roots means no skill file
371
+ discovery. This keeps product directory choices out of the framework and lets inspection use the same
372
+ roots as activation.
278
373
 
279
374
  Model-invocable skills are exposed to the model as metadata only when the session has a composed
280
375
  model-invocable `skills` command descriptor. `@robota-sdk/agent-command` owns `skills` and
281
- activates skills through the SDK host API. Models use the SDK-projected `robota_command_skills`
282
- tool with skill arguments in `args`. Mentioning a skill in ordinary prose,
376
+ activates skills through the SDK host API. Models use the SDK-projected `command_skills`
377
+ tool by default, with skill arguments in `args`. A product host can set
378
+ `modelCommandToolPrefix` on its session options to choose another prefix; Robota sets
379
+ `robota_command_`. Mentioning a skill in ordinary prose,
283
380
  recommending a skill in assistant text, or matching a natural-language phrase in SDK/TUI code does
284
381
  not activate the skill.
285
382
 
383
+ The framework's default prompt enclosure for attached `@file` content is
384
+ `<file_references>`. Product hosts can set `promptFileReferenceTag` on session options to
385
+ choose a different enclosure; Robota sets `robota_file_references`. SDK consumers that
386
+ need the previous identifiers should pass `modelCommandToolPrefix: 'robota_command_'`
387
+ and `promptFileReferenceTag: 'robota_file_references'` explicitly. Direct calls to
388
+ `createProviderSafeModelCommandToolName`, `createModelCommandToolProjection`, and
389
+ `buildPromptWithFileReferences` can pass the same values as their optional arguments.
390
+
286
391
  ### createQuery()
287
392
 
288
393
  ```typescript
289
394
  import { createQuery } from '@robota-sdk/agent-framework';
290
- import { AnthropicProvider } from '@robota-sdk/agent-provider/anthropic';
395
+ import { AnthropicProvider } from '@robota-sdk/agent-provider-anthropic';
291
396
 
292
397
  const provider = new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY });
293
398
  const query = createQuery({ provider });
@@ -316,19 +421,39 @@ one-shot calls.
316
421
  `@robota-sdk/agent-framework` assembles built-in tools for SDK sessions, but direct tool usage imports
317
422
  from the owner package:
318
423
 
424
+ Each file tool is a FACTORY that requires the containment root it operates in (ARCH-010) — there is
425
+ no ready-made instance, because one bound at import time can carry no root, and a file tool without a
426
+ root has no boundary:
427
+
319
428
  ```typescript
320
429
  import {
321
- bashTool,
322
- editTool,
323
- globTool,
324
- grepTool,
325
- readTool,
430
+ createShellTool,
431
+ createBashTool,
432
+ createEditTool,
433
+ createGlobTool,
434
+ createGrepTool,
435
+ createReadTool,
436
+ createWriteTool,
326
437
  webFetchTool,
327
438
  webSearchTool,
328
- writeTool,
439
+ askUserQuestionTool,
329
440
  } from '@robota-sdk/agent-tools';
441
+
442
+ const cwd = process.cwd();
443
+ const fileTools = [
444
+ createShellTool({ cwd }),
445
+ createBashTool({ cwd }),
446
+ createEditTool({ cwd }),
447
+ createGlobTool({ cwd }),
448
+ createGrepTool({ cwd }),
449
+ createReadTool({ cwd }),
450
+ createWriteTool({ cwd }),
451
+ ];
330
452
  ```
331
453
 
454
+ `webFetchTool`, `webSearchTool` and `askUserQuestionTool` remain instances: they touch no filesystem,
455
+ so there is no root for them to be contained by.
456
+
332
457
  ### Sandbox Execution
333
458
 
334
459
  SDK sessions can receive a provider-neutral sandbox client. When provided, Bash, Read, Write, and Edit use the sandbox execution plane instead of the host process/filesystem:
@@ -337,7 +462,7 @@ SDK sessions can receive a provider-neutral sandbox client. When provided, Bash,
337
462
 
338
463
  ```typescript
339
464
  import { InteractiveSession } from '@robota-sdk/agent-framework';
340
- import { AnthropicProvider } from '@robota-sdk/agent-provider/anthropic';
465
+ import { AnthropicProvider } from '@robota-sdk/agent-provider-anthropic';
341
466
  import { E2BSandboxClient } from '@robota-sdk/agent-tools';
342
467
  import type { IWorkspaceManifest } from '@robota-sdk/agent-tools';
343
468
  import { Sandbox } from 'e2b';
@@ -367,7 +492,7 @@ When `sessionStore` and a snapshot-capable `sandboxClient` are both provided, `I
367
492
 
368
493
  ## Subagent Sessions
369
494
 
370
- `createSubagentSession()` creates an isolated child session for delegating subtasks. The subagent receives pre-resolved config and context from the parent — it does not load config files or context from disk. Callers may provide a stable `sessionId` and `sessionLogger` so the child session writes a durable transcript.
495
+ `createSubagentSession()` creates an isolated child session for delegating subtasks. The subagent receives pre-resolved config and context from the parent — it does not load config files or context from disk. Callers may provide a stable `sessionId`, `sessionLogger`, and `sessionStore` so the child session writes durable state.
371
496
 
372
497
  ```typescript
373
498
  import { createSubagentSession } from '@robota-sdk/agent-framework';
@@ -389,6 +514,13 @@ Built-in agents: `general-purpose` (full tool access), `Explore` (read-only, Hai
389
514
 
390
515
  `createAgentTool()` wraps subagent creation into a tool the AI can invoke directly. The parent session's hooks, permissions, and context are forwarded to the child.
391
516
 
517
+ When a background job resumes a forked record, the runner passes the record's `resumeSessionId` as
518
+ both the child session ID and the persistence key, together with the same session store that holds
519
+ the copied record. Each completed child turn then updates that copied record, so `attach` sees the
520
+ conversation after the fork as well as the conversation copied at fork time. Ordinary subagent jobs
521
+ remain transient when they do not carry `resumeSessionId`; attaching is still a view switch, never a
522
+ merge with the parent record.
523
+
392
524
  Background subagent lifecycle events are persisted through `InteractiveSession` when an SDK session persistence facade is configured. Streaming chunks are written to append-only JSONL logs/transcripts rather than rewriting the main session JSON per token.
393
525
 
394
526
  ## Replay-Grade Session Events
@@ -397,6 +529,17 @@ Background subagent lifecycle events are persisted through `InteractiveSession`
397
529
 
398
530
  Provider-native payload events are emitted by concrete provider packages through `IChatOptions.onProviderNativeRawPayload`, then redacted and externalized by the session logger before they are written to disk. The SDK exposes session command APIs so command modules such as `/validate-session` can validate replay coverage without adding file-log logic to CLI/TUI hosts.
399
531
 
532
+ ## Interactive Prompt Settlement
533
+
534
+ `InteractiveSession` emits transport-neutral `permission_request` and `ask_request` events. Attached
535
+ surfaces answer through `resolvePermission()` and `resolveAsk()`; the first answer wins and produces one
536
+ `prompt_resolved` event. Session construction does not expose parallel `permissionHandler` or `askHandler`
537
+ options, so local and remote surfaces share the same request/settlement path.
538
+
539
+ Persisted checkpoint operations emit `branch_event` only after the transition and session save succeed.
540
+ Transport-owned listeners must isolate their own delivery failures without changing arbitrary SDK listener
541
+ exception behavior.
542
+
400
543
  ## Hook Executors (SDK-Specific)
401
544
 
402
545
  `agent-framework` provides two `IHookTypeExecutor` implementations beyond the `command` and `http` executors in `agent-core`:
@@ -513,19 +656,25 @@ Settings are merged from lowest to highest priority:
513
656
 
514
657
  ## Dependencies
515
658
 
516
- | Package | Purpose |
517
- | -------------------------------------- | ------------------------------------- |
518
- | `@robota-sdk/agent-core` | Engine, providers, permissions, hooks |
519
- | `@robota-sdk/agent-session` | Session, SessionStore |
520
- | `@robota-sdk/agent-tools` | Tool infrastructure + built-in tools |
521
- | `@robota-sdk/agent-provider/anthropic` | Anthropic LLM provider |
522
- | `chalk` | Terminal colors (permission prompt) |
523
- | `zod` | Settings schema validation |
659
+ | Package | Purpose |
660
+ | -------------------------------------- | ------------------------------------------------------------- |
661
+ | `@robota-sdk/agent-core` | Engine, providers, permissions, hooks |
662
+ | `@robota-sdk/agent-session` | Session, neutral log/store ports, explicit Node host adapters |
663
+ | `@robota-sdk/agent-tools` | Tool infrastructure + built-in tools |
664
+ | `@robota-sdk/agent-provider-anthropic` | Anthropic LLM provider |
665
+ | `chalk` | Terminal colors (permission prompt) |
666
+ | `zod` | Settings schema validation |
524
667
 
525
668
  ## Documentation
526
669
 
527
670
  See [docs/SPEC.md](./docs/SPEC.md) for the full specification, architecture details, and design decisions.
528
671
 
672
+ From `packages/agent-framework` in a built repository, run
673
+ `pnpm exec tsx examples/verify-goal-cassette-replay.mts` for offline goal replay through the public
674
+ testing SDK. The credentialed recorder now lives at `scripts/record-goal-cassette.mts`; it is
675
+ non-published development tooling, not a runtime provider dependency. Recording is an explicit
676
+ live-provider operation; replay needs no credentials and preserves the committed cassette.
677
+
529
678
  ## License
530
679
 
531
680
  Robota is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a [commercial license](../../COMMERCIAL.md). See [LICENSING.md](../../LICENSING.md).