bma-executor-sdk 0.4.0__py3-none-any.whl

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.
@@ -0,0 +1,1155 @@
1
+ # Code generated by tools/contract/gen-python.mjs from contracts/bma (executor protocol 1.1.0). DO NOT EDIT.
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from enum import Enum, IntEnum
7
+ from typing import TYPE_CHECKING, Any, Literal, TypedDict
8
+
9
+ # Annotations stay strings (PEP 563), so NotRequired is only needed by type
10
+ # checkers and Python 3.10 works without typing_extensions at runtime.
11
+ if TYPE_CHECKING:
12
+ from typing_extensions import NotRequired
13
+
14
+ class Ack(TypedDict):
15
+ """Generic acknowledgement returned by executor RPC methods."""
16
+ accepted: bool
17
+
18
+ class AgentCapability(TypedDict):
19
+ """agent capability. Present with enabled=true when the executor runs a complete agent and accepts turn.start, turn.input, turn.cancel, session.close and interaction.response."""
20
+ enabled: bool
21
+ models: NotRequired[list[AgentModel]]
22
+ permission_modes: NotRequired[list[str]]
23
+ interaction_kinds: NotRequired[list[InteractionKind]]
24
+ file_inputs: NotRequired[bool]
25
+ max_sessions: NotRequired[int]
26
+
27
+ class AgentErrorInfo(TypedDict):
28
+ """Typed session error."""
29
+ type: str
30
+ message: NotRequired[str]
31
+
32
+ class AgentEventType(str, Enum):
33
+ """Durable events an agent executor emits with session.event. Names and members follow Anthropic Managed Agents session events. user.* events are written by the platform, never by the executor."""
34
+ AgentMessage = "agent.message"
35
+ AgentThinking = "agent.thinking"
36
+ AgentToolUse = "agent.tool_use"
37
+ AgentToolResult = "agent.tool_result"
38
+ AgentMcpToolUse = "agent.mcp_tool_use"
39
+ AgentMcpToolResult = "agent.mcp_tool_result"
40
+ SessionStatusRunning = "session.status_running"
41
+ SessionStatusIdle = "session.status_idle"
42
+ SessionError = "session.error"
43
+
44
+ class AgentInputBlock(TypedDict):
45
+ """One block of user input. A file block references a platform session file by file_id; the executor downloads it through the executor files API. File bytes never travel on the control channel."""
46
+ type: AgentInputBlockType
47
+ text: NotRequired[str]
48
+ file_id: NotRequired[str]
49
+ name: NotRequired[str]
50
+ mime_type: NotRequired[str]
51
+ size_bytes: NotRequired[int]
52
+
53
+ class AgentInputBlockType(str, Enum):
54
+ """Agent input block type."""
55
+ Text = "text"
56
+ File = "file"
57
+
58
+ class AgentMcpToolResultEvent(TypedDict):
59
+ """Result of an agent.mcp_tool_use."""
60
+ type: Literal["agent.mcp_tool_result"]
61
+ mcp_tool_use_id: str
62
+ content: NotRequired[list[ContentBlock]]
63
+ is_error: NotRequired[bool]
64
+
65
+ class AgentMcpToolUseEvent(TypedDict):
66
+ """An MCP tool the local agent is calling. Its event_id is the mcp_tool_use_id."""
67
+ type: Literal["agent.mcp_tool_use"]
68
+ mcp_server_name: str
69
+ name: str
70
+ input: dict[str, Any]
71
+ evaluated_permission: NotRequired[EvaluatedPermission]
72
+
73
+ class AgentMessageEvent(TypedDict):
74
+ """Final assistant text. Streaming previews for the same event_id arrive earlier as session.event_delta."""
75
+ type: Literal["agent.message"]
76
+ content: list[ContentBlock]
77
+
78
+ class AgentModel(TypedDict):
79
+ """One model the local agent can run."""
80
+ id: str
81
+ display_name: NotRequired[str]
82
+ thinking_levels: NotRequired[list[str]]
83
+ default_thinking_level: NotRequired[str]
84
+
85
+ class AgentThinkingEvent(TypedDict):
86
+ """Model thinking. content may be empty when the model only reports that it thought."""
87
+ type: Literal["agent.thinking"]
88
+ content: NotRequired[list[ContentBlock]]
89
+
90
+ class AgentToolResultEvent(TypedDict):
91
+ """Result of an agent.tool_use."""
92
+ type: Literal["agent.tool_result"]
93
+ tool_use_id: str
94
+ content: NotRequired[list[ContentBlock]]
95
+ is_error: NotRequired[bool]
96
+
97
+ class AgentToolUseEvent(TypedDict):
98
+ """A built-in or custom tool the local agent is calling. Its event_id is the tool_use_id."""
99
+ type: Literal["agent.tool_use"]
100
+ name: str
101
+ input: dict[str, Any]
102
+ evaluated_permission: NotRequired[EvaluatedPermission]
103
+
104
+ class AgentTurnConfig(TypedDict):
105
+ """Requested (turn.start) or effective (TurnStartResult.effective) turn configuration. Every member is optional in a request; the executor reports the values it actually applied."""
106
+ model: NotRequired[str]
107
+ thinking_level: NotRequired[str]
108
+ permission_mode: NotRequired[str]
109
+ cwd: NotRequired[str]
110
+ system: NotRequired[str]
111
+
112
+ class ArtifactCapability(TypedDict):
113
+ """v1.1 artifact upload (POST /v1/executors/artifacts). Environment-scoped executors only."""
114
+ upload: bool
115
+ max_bytes: NotRequired[int]
116
+
117
+ class ArtifactRef(TypedDict):
118
+ """Artifact reference returned by POST /v1/executors/artifacts and listed in tool.result artifacts (v1.1 §6.5)."""
119
+ artifact_id: str
120
+ name: NotRequired[str]
121
+ mime_type: str
122
+ size_bytes: int
123
+ digest: str
124
+ created_at: NotRequired[str]
125
+
126
+ class Capabilities(TypedDict):
127
+ """Executor capability object. The server only sends a method to an executor that advertised its capability; otherwise the executor answers -32012 capability_unavailable."""
128
+ shell: NotRequired[ShellCapability]
129
+ files: NotRequired[FilesCapability]
130
+ mcp: NotRequired[McpCapability]
131
+ chrome: NotRequired[bool]
132
+ computer_use: NotRequired[bool]
133
+ display: NotRequired[bool | DisplayCapability]
134
+ process: NotRequired[ProcessCapability]
135
+ artifacts: NotRequired[ArtifactCapability]
136
+ terminal: NotRequired[TerminalCapability]
137
+ skills: NotRequired[SkillsCapability]
138
+ workspace: NotRequired[WorkspaceCapability]
139
+ agent: NotRequired[AgentCapability]
140
+
141
+ class ChannelScope(str, Enum):
142
+ """Channels a short-lived executor JWT may open."""
143
+ Control = "control"
144
+ Mcp = "mcp"
145
+
146
+ class ComputerAction(str, Enum):
147
+ """Input actions accepted by the computer_action tool."""
148
+ Click = "click"
149
+ Type = "type"
150
+ Key = "key"
151
+ Scroll = "scroll"
152
+ Drag = "drag"
153
+
154
+ class ConnectionState(str, Enum):
155
+ """Executor control channel state machine."""
156
+ Disconnected = "disconnected"
157
+ Connecting = "connecting"
158
+ Registered = "registered"
159
+ Ready = "ready"
160
+ Draining = "draining"
161
+ Closed = "closed"
162
+
163
+ class ContentBlock(TypedDict):
164
+ """Tool result content block. An artifact block carries artifact_id and mime_type instead of text (v1.1 §6.5)."""
165
+ type: ContentBlockType
166
+ text: NotRequired[str]
167
+ data: NotRequired[str]
168
+ mime_type: NotRequired[str]
169
+ url: NotRequired[str]
170
+ artifact_id: NotRequired[str]
171
+
172
+ class ContentBlockType(str, Enum):
173
+ """Tool result content block type."""
174
+ Text = "text"
175
+ Image = "image"
176
+ Resource = "resource"
177
+ Artifact = "artifact"
178
+
179
+ class Cursors(TypedDict):
180
+ """Per-stream byte cursors."""
181
+ stdout: int
182
+ stderr: int
183
+
184
+ class DisplayCapability(TypedDict):
185
+ """v1.1 display object. v1 sent a boolean; the server accepts both."""
186
+ rfb: NotRequired[bool]
187
+
188
+ class EvaluatedPermission(TypedDict):
189
+ """Permission decision the executor applied to a tool use. ask means the executor opened an interaction.request for it."""
190
+ type: Literal["allow", "ask", "deny"]
191
+
192
+ class EventDeltaType(str, Enum):
193
+ """Durable event type a streaming preview belongs to."""
194
+ AgentMessage = "agent.message"
195
+ AgentThinking = "agent.thinking"
196
+
197
+ class ExecutorDrainResult(TypedDict):
198
+ """executor.drain result."""
199
+ accepted: bool
200
+ active_sessions: list[str]
201
+
202
+ class ExecutorHeartbeatResult(TypedDict):
203
+ """executor.heartbeat result."""
204
+ server_time: str
205
+ lease_ttl_ms: int
206
+ drain: bool
207
+
208
+ class ExecutorInfo(TypedDict):
209
+ """Executor identity reported at token bootstrap and registration."""
210
+ name: str
211
+ os: str
212
+ arch: str
213
+ version: str
214
+
215
+ class ExecutorLoad(TypedDict):
216
+ """Advisory executor load reported with executor.heartbeat. The server does not act on it."""
217
+ cpu_percent: NotRequired[float]
218
+ memory_percent: NotRequired[float]
219
+
220
+ class ExecutorRegisterResult(TypedDict):
221
+ """executor.register result. protocol and limits are v1.1 only."""
222
+ executor_id: str
223
+ connection_id: str
224
+ server_time: str
225
+ heartbeat_interval_ms: int
226
+ lease_ttl_ms: int
227
+ max_control_frame_bytes: int
228
+ max_mcp_frame_bytes: int
229
+ drain: bool
230
+ protocol: NotRequired[ProtocolVersion]
231
+ limits: NotRequired[Limits]
232
+
233
+ class ExecutorResume(TypedDict):
234
+ """Reattach state sent on reconnect."""
235
+ executor_id: NotRequired[str]
236
+ last_connection_id: NotRequired[str]
237
+ active_sessions: NotRequired[list[str]]
238
+
239
+ class ExecutorTokenRequest(TypedDict):
240
+ """POST /v1/executors/token body. The bearer is an environment key, or a machine daemon token. An empty environment_id with a machine token requests a machine-scoped executor: its executor_id is exec_<machine_id>, stable across refreshes, and the JWT carries machine_id and daemon_token_id."""
241
+ environment_id: str
242
+ executor: ExecutorInfo
243
+
244
+ class ExecutorTokenResponse(TypedDict):
245
+ """POST /v1/executors/token response."""
246
+ executor_id: str
247
+ token: str
248
+ expires_in: int
249
+ ws_url: str
250
+ channel_scope: list[ChannelScope]
251
+
252
+ class FileTransferDirection(str, Enum):
253
+ """File transfer direction relative to the machine."""
254
+ Upload = "upload"
255
+ Download = "download"
256
+
257
+ class FileTransferError(TypedDict):
258
+ """Failed file transfer."""
259
+ code: str
260
+ error: str
261
+ current_digest: NotRequired[str]
262
+
263
+ class FileTransferResult(TypedDict):
264
+ """Ended file transfer outcome: the uploaded path and digest, the downloaded digest, or an error."""
265
+ path: NotRequired[str]
266
+ digest: NotRequired[str]
267
+ error: NotRequired[FileTransferError]
268
+
269
+ class FilesCapability(TypedDict):
270
+ """v1 file tools."""
271
+ enabled: bool
272
+ read_roots: NotRequired[list[str]]
273
+ write_roots: NotRequired[list[str]]
274
+
275
+ class IOMode(str, Enum):
276
+ """process.start io_mode. "pty" runs the command on a 24x80 pseudo-terminal: stdout is the PTY output, stdin writes go to the PTY and close_stdin is rejected. Requires process.pty."""
277
+ Pty = "pty"
278
+
279
+ class InteractionCancelReason(str, Enum):
280
+ """Why the executor withdrew an open interaction."""
281
+ ResolvedLocally = "resolved_locally"
282
+ TurnCanceled = "turn_canceled"
283
+ Expired = "expired"
284
+ ToolCanceled = "tool_canceled"
285
+
286
+ class InteractionKind(str, Enum):
287
+ """Interaction kinds; they map 1:1 to platform agent interactions."""
288
+ Permission = "permission"
289
+ Question = "question"
290
+
291
+ class InteractionOutcome(str, Enum):
292
+ """How the platform resolved an interaction. allow/deny answer permission, answered answers question, expired and canceled close either kind without an answer."""
293
+ Allow = "allow"
294
+ Deny = "deny"
295
+ Answered = "answered"
296
+ Expired = "expired"
297
+ Canceled = "canceled"
298
+
299
+ class InteractionQuestion(TypedDict):
300
+ """Question shown to the user."""
301
+ prompt: str
302
+ options: NotRequired[list[InteractionQuestionOption]]
303
+ multi_select: NotRequired[bool]
304
+ allow_free_text: NotRequired[bool]
305
+
306
+ class InteractionQuestionOption(TypedDict):
307
+ """One answer option of a question interaction."""
308
+ id: str
309
+ label: str
310
+
311
+ class InteractionRequestResult(TypedDict):
312
+ """interaction.request result. Idempotent by interaction_id: a repeat returns the same platform interaction."""
313
+ accepted: bool
314
+ platform_interaction_id: str
315
+
316
+ class InteractionResponder(TypedDict):
317
+ """Who answered, for local audit. surface is the client that resolved it, for example desktop, mobile, web, slack."""
318
+ actor_id: NotRequired[str]
319
+ surface: NotRequired[str]
320
+
321
+ class InteractionResponseResult(TypedDict):
322
+ """interaction.response result. accepted=false when the interaction is unknown or already resolved (first answer wins); the platform then marks its copy stale."""
323
+ accepted: bool
324
+
325
+ class InteractionScope(str, Enum):
326
+ """How long a permission grant lasts on the executor: this tool use only, or the rest of the session."""
327
+ Once = "once"
328
+ Session = "session"
329
+
330
+ class JsonRpcError(TypedDict):
331
+ """JSON-RPC 2.0 error object."""
332
+ code: JsonRpcErrorCode
333
+ message: str
334
+ data: NotRequired[JsonRpcErrorData]
335
+
336
+ class JsonRpcErrorCode(IntEnum):
337
+ """Executor protocol JSON-RPC error codes. -32011..-32013 are v1.1 additions."""
338
+ ParseError = -32700
339
+ InvalidRequest = -32600
340
+ MethodNotFound = -32601
341
+ InvalidParams = -32602
342
+ InternalError = -32603
343
+ Unauthorized = -32000
344
+ Forbidden = -32001
345
+ NotFound = -32002
346
+ LeaseExpired = -32003
347
+ Timeout = -32004
348
+ Canceled = -32005
349
+ PayloadTooLarge = -32006
350
+ SessionNotActive = -32007
351
+ McpUnavailable = -32008
352
+ ExecutorBusy = -32009
353
+ UnsupportedProtocol = -32010
354
+ ResourceUnavailable = -32011
355
+ CapabilityUnavailable = -32012
356
+ Conflict = -32013
357
+
358
+ class JsonRpcErrorData(TypedDict):
359
+ """JSON-RPC error.data. Members are code-specific; unknown members are ignored."""
360
+ retryable: NotRequired[bool]
361
+ detail: NotRequired[str]
362
+ capability: NotRequired[str]
363
+ reason: NotRequired[str]
364
+ terminal_code: NotRequired[str]
365
+ expected_sequence: NotRequired[int]
366
+
367
+ class JsonRpcErrorResponse(TypedDict):
368
+ """JSON-RPC 2.0 error response envelope."""
369
+ jsonrpc: Literal["2.0"]
370
+ id: JsonRpcId
371
+ error: JsonRpcError
372
+
373
+ class JsonRpcNotification(TypedDict):
374
+ """JSON-RPC 2.0 notification envelope (no id)."""
375
+ jsonrpc: Literal["2.0"]
376
+ method: str
377
+ params: dict[str, Any]
378
+
379
+ class JsonRpcRequest(TypedDict):
380
+ """JSON-RPC 2.0 request envelope."""
381
+ jsonrpc: Literal["2.0"]
382
+ id: JsonRpcId
383
+ method: str
384
+ params: dict[str, Any]
385
+
386
+ class JsonRpcSuccessResponse(TypedDict):
387
+ """JSON-RPC 2.0 success response envelope."""
388
+ jsonrpc: Literal["2.0"]
389
+ id: JsonRpcId
390
+ result: Any
391
+
392
+ class Lease(TypedDict):
393
+ """Fencing lease for a session assignment."""
394
+ token: str
395
+ fencing_token: int
396
+
397
+ class Limits(TypedDict):
398
+ """Limits the executor must enforce, advertised in the v1.1 executor.register result (v1.1 §1.3)."""
399
+ max_inflight_requests: int
400
+ max_concurrent_process_reads: int
401
+ max_process_read_bytes: int
402
+ max_process_write_bytes: int
403
+ max_processes_per_session: int
404
+ max_artifact_bytes: int
405
+
406
+ class McpCapability(TypedDict):
407
+ """Environment-origin MCP servers."""
408
+ stdio: NotRequired[bool]
409
+ http: NotRequired[bool]
410
+ max_servers: NotRequired[int]
411
+
412
+ class McpConnectionOrigin(str, Enum):
413
+ """Who connects the MCP server. environment means the executor starts/connects it; service means the harness connects."""
414
+ Service = "service"
415
+ Environment = "environment"
416
+
417
+ class McpContentBlock(TypedDict):
418
+ """MCP tool content block. Large binary content must go to artifact storage."""
419
+ type: Literal["text", "image", "resource"]
420
+ text: NotRequired[str]
421
+ data: NotRequired[str]
422
+ mimeType: NotRequired[str]
423
+ resource: NotRequired[Any]
424
+
425
+ class McpImplementation(TypedDict):
426
+ name: str
427
+ version: str
428
+
429
+ class McpInitializeParams(TypedDict):
430
+ protocolVersion: str
431
+ capabilities: dict[str, Any]
432
+ clientInfo: McpImplementation
433
+
434
+ class McpInitializeResult(TypedDict):
435
+ protocolVersion: str
436
+ capabilities: dict[str, Any]
437
+ serverInfo: McpImplementation
438
+
439
+ class McpJsonRpcError(TypedDict):
440
+ code: int
441
+ message: str
442
+ data: NotRequired[Any]
443
+
444
+ class McpJsonRpcErrorResponse(TypedDict):
445
+ jsonrpc: Literal["2.0"]
446
+ id: McpJsonRpcId
447
+ error: McpJsonRpcError
448
+
449
+ class McpJsonRpcNotification(TypedDict):
450
+ jsonrpc: Literal["2.0"]
451
+ method: str
452
+ params: NotRequired[dict[str, Any]]
453
+
454
+ class McpJsonRpcRequest(TypedDict):
455
+ jsonrpc: Literal["2.0"]
456
+ id: McpJsonRpcId
457
+ method: str
458
+ params: NotRequired[dict[str, Any]]
459
+
460
+ class McpJsonRpcSuccessResponse(TypedDict):
461
+ jsonrpc: Literal["2.0"]
462
+ id: McpJsonRpcId
463
+ result: Any
464
+
465
+ class McpProgressParams(TypedDict):
466
+ progressToken: str | int
467
+ progress: float
468
+ total: NotRequired[float]
469
+
470
+ class McpServerConfig(TypedDict):
471
+ server_key: str
472
+ connection_origin: McpConnectionOrigin
473
+ transport: McpServerTransport
474
+
475
+ class McpServerTransport(TypedDict):
476
+ """Transport for one MCP server. stdio requires command; http requires url. Fields for the other transport are omitted."""
477
+ type: McpTransportType
478
+ command: NotRequired[str]
479
+ args: NotRequired[list[str]]
480
+ cwd: NotRequired[str]
481
+ env: NotRequired[dict[str, str]]
482
+ timeout_ms: NotRequired[int]
483
+ command_sha256: NotRequired[str]
484
+ url: NotRequired[str]
485
+
486
+ class McpTool(TypedDict):
487
+ name: str
488
+ description: NotRequired[str]
489
+ inputSchema: dict[str, Any]
490
+
491
+ class McpToolsCallParams(TypedDict):
492
+ name: str
493
+ arguments: dict[str, Any]
494
+
495
+ class McpToolsCallResult(TypedDict):
496
+ content: list[McpContentBlock]
497
+ isError: NotRequired[bool]
498
+ structuredContent: NotRequired[Any]
499
+
500
+ class McpToolsListParams(TypedDict):
501
+ cursor: NotRequired[str]
502
+
503
+ class McpToolsListResult(TypedDict):
504
+ tools: list[McpTool]
505
+ nextCursor: NotRequired[str | None]
506
+
507
+ class McpTransportType(str, Enum):
508
+ Stdio = "stdio"
509
+ Http = "http"
510
+
511
+ class PermissionMode(str, Enum):
512
+ """Tool permission mode; always_ask means the harness already resolved approval."""
513
+ AlwaysAllow = "always_allow"
514
+ AlwaysAsk = "always_ask"
515
+
516
+ class ProcessCapability(TypedDict):
517
+ """v1.1 process.* support. pty, file_transfer and git_credentials are additive: the harness only sends the matching process.start fields to an executor that set them, and fails the process explicitly otherwise."""
518
+ enabled: bool
519
+ max_processes: NotRequired[int]
520
+ buffer_bytes: NotRequired[int]
521
+ pty: NotRequired[bool]
522
+ file_transfer: NotRequired[bool]
523
+ git_credentials: NotRequired[bool]
524
+
525
+ class ProcessFileTransfer(TypedDict):
526
+ """Replaces argv: the executor moves one file between the machine and the process BMA file endpoint and reports the outcome in ProcessState.file_transfer. Requires process.file_transfer."""
527
+ direction: FileTransferDirection
528
+ local_path: str
529
+
530
+ class ProcessListResult(TypedDict):
531
+ """process.list result."""
532
+ processes: list[ProcessState]
533
+
534
+ class ProcessReadResult(TypedDict):
535
+ """process.read result."""
536
+ process_id: str
537
+ stream: ProcessStream
538
+ data: str
539
+ from_cursor: int
540
+ next_cursor: int
541
+ earliest_cursor: int
542
+ gap: bool
543
+ truncated: bool
544
+ eof: bool
545
+ state: ProcessStateName
546
+ ended_at: NotRequired[str]
547
+ reason: NotRequired[str]
548
+ exit_code: int | None
549
+ exit_signal: str | None
550
+ file_transfer: NotRequired[FileTransferResult]
551
+
552
+ class ProcessState(TypedDict):
553
+ """Result of process.start/interrupt/terminate and one process.list entry. ended_at (RFC 3339, executor clock) is set once the process is no longer running; reason explains a "failed" state (for example "timeout"). A spawn failure never creates a state: it is the process.start error with data.reason "spawn_failed"."""
554
+ process_id: str
555
+ state: ProcessStateName
556
+ pid: NotRequired[int]
557
+ started_at: NotRequired[str]
558
+ ended_at: NotRequired[str]
559
+ reason: NotRequired[str]
560
+ cursors: Cursors
561
+ exit_code: int | None
562
+ exit_signal: str | None
563
+ stderr: NotRequired[str]
564
+ accepted: NotRequired[bool]
565
+ file_transfer: NotRequired[FileTransferResult]
566
+
567
+ class ProcessStateName(str, Enum):
568
+ """Process state (v1.1 §3.3)."""
569
+ Running = "running"
570
+ Exited = "exited"
571
+ Failed = "failed"
572
+ Killed = "killed"
573
+
574
+ class ProcessStream(str, Enum):
575
+ """Process output stream (v1.1 §3.2)."""
576
+ Stdout = "stdout"
577
+ Stderr = "stderr"
578
+
579
+ class ProcessWriteResult(TypedDict):
580
+ """process.write result."""
581
+ accepted: bool
582
+
583
+ class ProtocolVersion(str, Enum):
584
+ """Value of both the WebSocket subprotocol and executor.register protocol. A v1.1 server serves v1 executors and never sends them v1.1 methods."""
585
+ BmaExecutorV1 = "bma.executor.v1"
586
+ BmaExecutorV11 = "bma.executor.v1.1"
587
+
588
+ class SessionAssignResult(TypedDict):
589
+ """session.assign result."""
590
+ accepted: bool
591
+ session_id: str
592
+
593
+ class SessionCloseResult(TypedDict):
594
+ """session.close result."""
595
+ closed: bool
596
+
597
+ class SessionErrorEvent(TypedDict):
598
+ """A turn-level error. A failed turn still ends with session.status_idle turn_outcome=failed."""
599
+ type: Literal["session.error"]
600
+ error: AgentErrorInfo
601
+
602
+ class SessionEvent(TypedDict):
603
+ """Durable session event emitted by the executor."""
604
+ type: SessionEventType
605
+ tool_use_id: NotRequired[str]
606
+ content: NotRequired[list[ContentBlock]]
607
+ is_error: NotRequired[bool]
608
+
609
+ class SessionEventResult(TypedDict):
610
+ """session.event result."""
611
+ accepted: bool
612
+ event_id: str
613
+ acked_sequence: NotRequired[int]
614
+
615
+ class SessionEventType(str, Enum):
616
+ """Durable event types an executor may emit. Event names follow Anthropic Managed Agents; the executor must not invent new names. A tool executor emits agent.tool_result only; an agent executor (capability agent) emits every type, shaped as schemas/agent.json AgentEvent."""
617
+ AgentToolResult = "agent.tool_result"
618
+ AgentMessage = "agent.message"
619
+ AgentThinking = "agent.thinking"
620
+ AgentToolUse = "agent.tool_use"
621
+ AgentMcpToolUse = "agent.mcp_tool_use"
622
+ AgentMcpToolResult = "agent.mcp_tool_result"
623
+ SessionStatusRunning = "session.status_running"
624
+ SessionStatusIdle = "session.status_idle"
625
+ SessionError = "session.error"
626
+
627
+ class SessionMemoryResource(TypedDict):
628
+ """A memory store mounted into the session workspace."""
629
+ type: Literal["memory_store"]
630
+ memory_store_id: str
631
+ mount_path: str
632
+
633
+ class SessionStatus(str, Enum):
634
+ """Lifecycle status reported by the executor."""
635
+ Starting = "starting"
636
+ Running = "running"
637
+ Idle = "idle"
638
+ Stopping = "stopping"
639
+ Stopped = "stopped"
640
+ Error = "error"
641
+
642
+ class SessionStatusIdleEvent(TypedDict):
643
+ """The turn ended. It is the last event of its turn_id; the platform publishes the turn as finished only after it accepted this event and every lower sequence."""
644
+ type: Literal["session.status_idle"]
645
+ stop_reason: StopReason
646
+ turn_outcome: TurnOutcome
647
+
648
+ class SessionStatusRunningEvent(TypedDict):
649
+ """The local agent started working on the turn."""
650
+ type: Literal["session.status_running"]
651
+
652
+ class SessionStopResult(TypedDict):
653
+ """session.stop result."""
654
+ stopped: bool
655
+
656
+ class ShellCapability(TypedDict):
657
+ """v1 one-shot shell tools."""
658
+ enabled: bool
659
+
660
+ class SkillInstallResult(TypedDict):
661
+ """skill.install result. state is "ready", or "failed" with error_code and error."""
662
+ state: Literal["ready", "failed"]
663
+ error_code: NotRequired[str]
664
+ error: NotRequired[str]
665
+
666
+ class SkillsCapability(TypedDict):
667
+ """skill.install support. Machine-scoped executors only."""
668
+ install: bool
669
+
670
+ class StderrMode(str, Enum):
671
+ """process.start stderr mode. "merge" redirects stderr into stdout at the OS level so one cursor covers both."""
672
+ Merge = "merge"
673
+
674
+ class StdinMode(str, Enum):
675
+ """process.start stdin mode. Empty or "closed" closes stdin at start; "open" keeps it open for process.write."""
676
+ Open = "open"
677
+ Closed = "closed"
678
+
679
+ class StopReason(TypedDict):
680
+ """Why the turn stopped."""
681
+ type: StopReasonType
682
+
683
+ class StopReasonType(str, Enum):
684
+ """Anthropic stop_reason types an executor may report. requires_action is not in the list: the platform projects it from open interactions."""
685
+ EndTurn = "end_turn"
686
+ RetriesExhausted = "retries_exhausted"
687
+
688
+ class TerminalAttachResult(TypedDict):
689
+ """terminal.attach result, returned after the host socket is connected and the attached frame was written on it."""
690
+ accepted: bool
691
+ writer_epoch: int
692
+
693
+ class TerminalCapability(TypedDict):
694
+ """v1.1 terminal.* support. Machine-scoped executors only."""
695
+ enabled: bool
696
+ kinds: NotRequired[list[str]]
697
+ max_sessions: NotRequired[int]
698
+
699
+ class TerminalCloseResult(TypedDict):
700
+ """terminal.close result. Idempotent: closing an unknown or closed terminal returns closed=true."""
701
+ closed: bool
702
+ exit_code: NotRequired[int | None]
703
+
704
+ class TerminalErrorData(TypedDict):
705
+ """JSON-RPC error.data of a failed terminal.* call. terminal_code is the bma.terminal.v1 code the harness relays to the attach (for example terminal_writer_busy)."""
706
+ terminal_code: NotRequired[str]
707
+
708
+ class TerminalHost(TypedDict):
709
+ """Outbound host socket for one attach. The ticket is a single-use, short-lived bearer credential sent only in the Authorization header, never in the URL."""
710
+ url: str
711
+ ticket: str
712
+
713
+ class TerminalOpenResult(TypedDict):
714
+ """terminal.open result. epoch starts at 1 and increments when the executor recreates the PTY under the same terminal_id; attach is fenced by it."""
715
+ terminal_id: str
716
+ epoch: int
717
+ pid: int
718
+ rows: int
719
+ cols: int
720
+ earliest_seq: int
721
+ latest_seq: int
722
+ created_at: str
723
+
724
+ class ToolCancelResult(TypedDict):
725
+ """tool.cancel result."""
726
+ canceled: bool
727
+
728
+ class ToolInput(TypedDict):
729
+ """Built-in tool input. The selected tool decides which members are meaningful; unknown members are ignored."""
730
+ command: NotRequired[str]
731
+ cwd: NotRequired[str]
732
+ timeout_ms: NotRequired[int]
733
+ env: NotRequired[dict[str, str]]
734
+ path: NotRequired[str]
735
+ offset: NotRequired[int]
736
+ limit: NotRequired[int]
737
+ content: NotRequired[str]
738
+ old_string: NotRequired[str]
739
+ new_string: NotRequired[str]
740
+ pattern: NotRequired[str]
741
+ glob: NotRequired[str]
742
+ display: NotRequired[str]
743
+ action: NotRequired[ComputerAction]
744
+
745
+ class ToolName(str, Enum):
746
+ """Built-in tool names. bmad serves bash only and answers -32012 for the rest."""
747
+ Bash = "bash"
748
+ Read = "read"
749
+ Write = "write"
750
+ Edit = "edit"
751
+ Glob = "glob"
752
+ Grep = "grep"
753
+ ListFiles = "list_files"
754
+ ComputerObserve = "computer_observe"
755
+ ComputerAction = "computer_action"
756
+
757
+ class ToolOutcome(str, Enum):
758
+ """Tool outcome."""
759
+ Succeeded = "succeeded"
760
+ Failed = "failed"
761
+ Canceled = "canceled"
762
+
763
+ class ToolPermission(TypedDict):
764
+ """Tool permission resolved by the harness."""
765
+ mode: PermissionMode
766
+
767
+ class TurnCancelResult(TypedDict):
768
+ """turn.cancel result. canceled=false when the turn is unknown or already ended; the turn still ends with its own session.status_idle event."""
769
+ canceled: bool
770
+
771
+ class TurnOutcome(str, Enum):
772
+ """BMA extension on session.status_idle: how the turn ended."""
773
+ Completed = "completed"
774
+ Canceled = "canceled"
775
+ Failed = "failed"
776
+
777
+ class TurnStartResult(TypedDict):
778
+ """turn.start result. Idempotent by turn_id: a repeated turn.start for a turn the executor already accepted returns the same result without starting a second run."""
779
+ accepted: bool
780
+ turn_id: str
781
+ executor_session_ref: str
782
+ resumed: bool
783
+ effective: AgentTurnConfig
784
+
785
+ class WorkspaceBackupResult(TypedDict):
786
+ """workspace.backup result. digest and size_bytes describe the archive as the server stored it; skipped counts entries that could not be read (missing from the archive)."""
787
+ state: Literal["uploaded", "unchanged", "failed"]
788
+ fingerprint: NotRequired[str]
789
+ digest: NotRequired[str]
790
+ size_bytes: NotRequired[int]
791
+ entries: NotRequired[int]
792
+ skipped: NotRequired[int]
793
+ error: NotRequired[str]
794
+
795
+ class WorkspaceCapability(TypedDict):
796
+ """workspace.backup support and the startup restore of a pending backup. Machine-scoped executors only."""
797
+ backup: bool
798
+
799
+ AgentEvent = AgentMessageEvent | AgentThinkingEvent | AgentToolUseEvent | AgentToolResultEvent | AgentMcpToolUseEvent | AgentMcpToolResultEvent | SessionStatusRunningEvent | SessionStatusIdleEvent | SessionErrorEvent
800
+
801
+ JsonRpcId = str
802
+
803
+ McpJsonRpcId = str | int
804
+
805
+ class ExecutorRegisterParams(TypedDict):
806
+ "Params object of executor.register."
807
+ protocol: ProtocolVersion
808
+ environment_id: str
809
+ executor: ExecutorInfo
810
+ capabilities: Capabilities
811
+ resume: NotRequired[ExecutorResume]
812
+
813
+ class ExecutorHeartbeatParams(TypedDict):
814
+ "Params object of executor.heartbeat."
815
+ connection_id: str
816
+ active_sessions: list[str]
817
+ load: NotRequired[ExecutorLoad]
818
+
819
+ class ExecutorCapabilitiesUpdateParams(TypedDict):
820
+ "Params object of executor.capabilities.update."
821
+ capabilities: Capabilities
822
+
823
+ class ExecutorDrainParams(TypedDict):
824
+ "Params object of executor.drain."
825
+ reason: str
826
+ deadline_ms: NotRequired[int]
827
+
828
+ class ExecutorCloseParams(TypedDict):
829
+ "Params object of executor.close."
830
+ reason: str
831
+
832
+ class SessionAssignParams(TypedDict):
833
+ "Params object of session.assign."
834
+ session_id: str
835
+ work_id: str
836
+ agent_id: NotRequired[str]
837
+ environment_id: str
838
+ deadline_ms: NotRequired[int]
839
+ lease: Lease
840
+ resources: NotRequired[list[SessionMemoryResource]]
841
+ mcp_servers: NotRequired[list[McpServerConfig]]
842
+ metadata: NotRequired[dict[str, str]]
843
+
844
+ class SessionReadyParams(TypedDict):
845
+ "Params object of session.ready."
846
+ session_id: str
847
+ work_id: str
848
+ lease_token: str
849
+
850
+ class SessionEventParams(TypedDict):
851
+ "Params object of session.event."
852
+ session_id: str
853
+ turn_id: NotRequired[str]
854
+ event_id: NotRequired[str]
855
+ sequence: NotRequired[int]
856
+ event: SessionEvent
857
+
858
+ class SessionStatusParams(TypedDict):
859
+ "Params object of session.status."
860
+ session_id: str
861
+ status: SessionStatus
862
+ detail: NotRequired[str]
863
+
864
+ class SessionStopParams(TypedDict):
865
+ "Params object of session.stop."
866
+ session_id: str
867
+ reason: str
868
+ deadline_ms: NotRequired[int]
869
+
870
+ class SessionEndedParams(TypedDict):
871
+ "Params object of session.ended."
872
+ session_id: str
873
+ reason: str
874
+
875
+ class ToolCallParams(TypedDict):
876
+ "Params object of tool.call."
877
+ session_id: str
878
+ tool_call_id: str
879
+ tool: ToolName
880
+ input: ToolInput
881
+ deadline_ms: NotRequired[int]
882
+ permission: NotRequired[ToolPermission]
883
+
884
+ class ToolResultParams(TypedDict):
885
+ "Params object of tool.result."
886
+ session_id: str
887
+ tool_call_id: str
888
+ outcome: ToolOutcome
889
+ is_error: bool
890
+ content: list[ContentBlock]
891
+ duration_ms: NotRequired[int]
892
+ artifacts: NotRequired[list[ArtifactRef]]
893
+
894
+ class ToolCancelParams(TypedDict):
895
+ "Params object of tool.cancel."
896
+ session_id: str
897
+ tool_call_id: str
898
+ reason: NotRequired[str]
899
+
900
+ class ToolProgressParams(TypedDict):
901
+ "Params object of tool.progress."
902
+ session_id: str
903
+ tool_call_id: str
904
+ message: str
905
+
906
+ class ProcessStartParams(TypedDict):
907
+ "Params object of process.start."
908
+ session_id: str
909
+ process_id: str
910
+ argv: list[str]
911
+ cwd: NotRequired[str]
912
+ env: NotRequired[dict[str, str]]
913
+ stdin: NotRequired[StdinMode]
914
+ stderr: NotRequired[StderrMode]
915
+ wait_ms: NotRequired[int]
916
+ timeout_ms: NotRequired[int]
917
+ metadata: NotRequired[dict[str, str]]
918
+ io_mode: NotRequired[IOMode]
919
+ file_transfer: NotRequired[ProcessFileTransfer]
920
+ git_credentials: NotRequired[bool]
921
+
922
+ class ProcessReadParams(TypedDict):
923
+ "Params object of process.read."
924
+ session_id: str
925
+ process_id: str
926
+ stream: ProcessStream
927
+ cursor: int
928
+ max_bytes: NotRequired[int]
929
+ wait_ms: NotRequired[int]
930
+
931
+ class ProcessWriteParams(TypedDict):
932
+ "Params object of process.write."
933
+ session_id: str
934
+ process_id: str
935
+ data: NotRequired[str]
936
+ close_stdin: NotRequired[bool]
937
+
938
+ class ProcessSignalParams(TypedDict):
939
+ "Params object of process.interrupt and process.terminate."
940
+ session_id: str
941
+ process_id: str
942
+ grace_ms: NotRequired[int | None]
943
+
944
+ class ProcessListParams(TypedDict):
945
+ "Params object of process.list."
946
+ session_id: str
947
+
948
+ class ProcessStatusParams(TypedDict):
949
+ "Params object of process.status."
950
+ session_id: str
951
+ process_id: str
952
+ state: ProcessStateName
953
+ exit_code: NotRequired[int | None]
954
+ exit_signal: NotRequired[str | None]
955
+ ended_at: NotRequired[str]
956
+ reason: NotRequired[str]
957
+ observed_at: str
958
+
959
+ class TerminalOpenParams(TypedDict):
960
+ "Params object of terminal.open."
961
+ terminal_id: str
962
+ kind: str
963
+ shell: NotRequired[str]
964
+ argv: NotRequired[list[str]]
965
+ cwd: NotRequired[str]
966
+ env: NotRequired[dict[str, str]]
967
+ rows: NotRequired[int]
968
+ cols: NotRequired[int]
969
+
970
+ class TerminalAttachParams(TypedDict):
971
+ "Params object of terminal.attach."
972
+ terminal_id: str
973
+ epoch: int
974
+ stream_id: str
975
+ can_write: bool
976
+ from_seq: int
977
+ ack_seq: int
978
+ host: TerminalHost
979
+
980
+ class TerminalCloseParams(TypedDict):
981
+ "Params object of terminal.close."
982
+ terminal_id: str
983
+ reason: NotRequired[str]
984
+
985
+ class SkillInstallParams(TypedDict):
986
+ "Params object of skill.install."
987
+ machine_id: str
988
+ skill_id: str
989
+ revision_id: str
990
+ digest: str
991
+ download_token: str
992
+ download_expires_at: int
993
+
994
+ class WorkspaceBackupParams(TypedDict):
995
+ "Params object of workspace.backup."
996
+ backup_id: str
997
+ paths: list[str]
998
+ exclude: NotRequired[list[str]]
999
+ skip_if_fingerprint: NotRequired[str]
1000
+
1001
+ class TurnStartParams(TypedDict):
1002
+ "Params object of turn.start."
1003
+ session_id: str
1004
+ turn_id: str
1005
+ input_id: str
1006
+ input: list[AgentInputBlock]
1007
+ executor_session_ref: NotRequired[str]
1008
+ config: NotRequired[AgentTurnConfig]
1009
+ deadline_ms: NotRequired[int]
1010
+ metadata: NotRequired[dict[str, str]]
1011
+
1012
+ class TurnInputParams(TypedDict):
1013
+ "Params object of turn.input."
1014
+ session_id: str
1015
+ turn_id: str
1016
+ input_id: str
1017
+ input: list[AgentInputBlock]
1018
+
1019
+ class TurnCancelParams(TypedDict):
1020
+ "Params object of turn.cancel."
1021
+ session_id: str
1022
+ turn_id: str
1023
+ reason: NotRequired[str]
1024
+
1025
+ class SessionCloseParams(TypedDict):
1026
+ "Params object of session.close."
1027
+ session_id: str
1028
+ reason: str
1029
+
1030
+ class SessionEventDeltaParams(TypedDict):
1031
+ "Params object of session.event_delta."
1032
+ session_id: str
1033
+ turn_id: str
1034
+ event_id: str
1035
+ event_type: EventDeltaType
1036
+ index: int
1037
+ text: str
1038
+
1039
+ class InteractionRequestParams(TypedDict):
1040
+ "Params object of interaction.request."
1041
+ session_id: str
1042
+ turn_id: str
1043
+ interaction_id: str
1044
+ kind: InteractionKind
1045
+ tool_use_id: NotRequired[str]
1046
+ tool_name: NotRequired[str]
1047
+ tool_input: NotRequired[dict[str, Any]]
1048
+ scopes: NotRequired[list[InteractionScope]]
1049
+ question: NotRequired[InteractionQuestion]
1050
+ expires_at: NotRequired[str]
1051
+
1052
+ class InteractionResponseParams(TypedDict):
1053
+ "Params object of interaction.response."
1054
+ session_id: str
1055
+ interaction_id: str
1056
+ outcome: InteractionOutcome
1057
+ scope: NotRequired[InteractionScope]
1058
+ deny_message: NotRequired[str]
1059
+ answers: NotRequired[list[str]]
1060
+ responder: NotRequired[InteractionResponder]
1061
+
1062
+ class InteractionCancelParams(TypedDict):
1063
+ "Params object of interaction.cancel."
1064
+ session_id: str
1065
+ interaction_id: str
1066
+ reason: InteractionCancelReason
1067
+
1068
+
1069
+ @dataclass(frozen=True, slots=True)
1070
+ class MethodSpec:
1071
+ "since is the first protocol that has the method; result_type is the Python type expression of a request result; capability is the capability bit the harness checks before sending it."
1072
+
1073
+ name: str
1074
+ direction: str
1075
+ kind: str
1076
+ since: str
1077
+ params_type: str
1078
+ result_type: str | None = None
1079
+ capability: str | None = None
1080
+ idempotent_by: str | None = None
1081
+
1082
+
1083
+ METHOD_EXECUTOR_REGISTER = "executor.register"
1084
+ METHOD_EXECUTOR_HEARTBEAT = "executor.heartbeat"
1085
+ METHOD_EXECUTOR_CAPABILITIES_UPDATE = "executor.capabilities.update"
1086
+ METHOD_EXECUTOR_DRAIN = "executor.drain"
1087
+ METHOD_EXECUTOR_CLOSE = "executor.close"
1088
+ METHOD_SESSION_ASSIGN = "session.assign"
1089
+ METHOD_SESSION_READY = "session.ready"
1090
+ METHOD_SESSION_EVENT = "session.event"
1091
+ METHOD_SESSION_STATUS = "session.status"
1092
+ METHOD_SESSION_STOP = "session.stop"
1093
+ METHOD_SESSION_ENDED = "session.ended"
1094
+ METHOD_TOOL_CALL = "tool.call"
1095
+ METHOD_TOOL_RESULT = "tool.result"
1096
+ METHOD_TOOL_CANCEL = "tool.cancel"
1097
+ METHOD_TOOL_PROGRESS = "tool.progress"
1098
+ METHOD_PROCESS_START = "process.start"
1099
+ METHOD_PROCESS_READ = "process.read"
1100
+ METHOD_PROCESS_WRITE = "process.write"
1101
+ METHOD_PROCESS_INTERRUPT = "process.interrupt"
1102
+ METHOD_PROCESS_TERMINATE = "process.terminate"
1103
+ METHOD_PROCESS_LIST = "process.list"
1104
+ METHOD_PROCESS_STATUS = "process.status"
1105
+ METHOD_TERMINAL_OPEN = "terminal.open"
1106
+ METHOD_TERMINAL_ATTACH = "terminal.attach"
1107
+ METHOD_TERMINAL_CLOSE = "terminal.close"
1108
+ METHOD_SKILL_INSTALL = "skill.install"
1109
+ METHOD_WORKSPACE_BACKUP = "workspace.backup"
1110
+ METHOD_TURN_START = "turn.start"
1111
+ METHOD_TURN_INPUT = "turn.input"
1112
+ METHOD_TURN_CANCEL = "turn.cancel"
1113
+ METHOD_SESSION_CLOSE = "session.close"
1114
+ METHOD_SESSION_EVENT_DELTA = "session.event_delta"
1115
+ METHOD_INTERACTION_REQUEST = "interaction.request"
1116
+ METHOD_INTERACTION_RESPONSE = "interaction.response"
1117
+ METHOD_INTERACTION_CANCEL = "interaction.cancel"
1118
+
1119
+ METHODS: dict[str, MethodSpec] = {
1120
+ "executor.register": MethodSpec(name="executor.register", direction="executor-to-harness", kind="request", since="bma.executor.v1", params_type="ExecutorRegisterParams", result_type="ExecutorRegisterResult", capability=None, idempotent_by=None),
1121
+ "executor.heartbeat": MethodSpec(name="executor.heartbeat", direction="executor-to-harness", kind="request", since="bma.executor.v1", params_type="ExecutorHeartbeatParams", result_type="ExecutorHeartbeatResult", capability=None, idempotent_by=None),
1122
+ "executor.capabilities.update": MethodSpec(name="executor.capabilities.update", direction="executor-to-harness", kind="notification", since="bma.executor.v1", params_type="ExecutorCapabilitiesUpdateParams", result_type=None, capability=None, idempotent_by=None),
1123
+ "executor.drain": MethodSpec(name="executor.drain", direction="harness-to-executor", kind="request", since="bma.executor.v1", params_type="ExecutorDrainParams", result_type="ExecutorDrainResult", capability=None, idempotent_by=None),
1124
+ "executor.close": MethodSpec(name="executor.close", direction="bidirectional", kind="notification", since="bma.executor.v1", params_type="ExecutorCloseParams", result_type=None, capability=None, idempotent_by=None),
1125
+ "session.assign": MethodSpec(name="session.assign", direction="harness-to-executor", kind="request", since="bma.executor.v1", params_type="SessionAssignParams", result_type="SessionAssignResult", capability=None, idempotent_by=None),
1126
+ "session.ready": MethodSpec(name="session.ready", direction="executor-to-harness", kind="request", since="bma.executor.v1", params_type="SessionReadyParams", result_type="Ack", capability=None, idempotent_by=None),
1127
+ "session.event": MethodSpec(name="session.event", direction="executor-to-harness", kind="request", since="bma.executor.v1", params_type="SessionEventParams", result_type="SessionEventResult", capability=None, idempotent_by="jsonrpc_id"),
1128
+ "session.status": MethodSpec(name="session.status", direction="executor-to-harness", kind="notification", since="bma.executor.v1", params_type="SessionStatusParams", result_type=None, capability=None, idempotent_by=None),
1129
+ "session.stop": MethodSpec(name="session.stop", direction="harness-to-executor", kind="request", since="bma.executor.v1", params_type="SessionStopParams", result_type="SessionStopResult", capability=None, idempotent_by=None),
1130
+ "session.ended": MethodSpec(name="session.ended", direction="executor-to-harness", kind="request", since="bma.executor.v1", params_type="SessionEndedParams", result_type="Ack", capability=None, idempotent_by=None),
1131
+ "tool.call": MethodSpec(name="tool.call", direction="harness-to-executor", kind="request", since="bma.executor.v1", params_type="ToolCallParams", result_type="Ack", capability=None, idempotent_by=None),
1132
+ "tool.result": MethodSpec(name="tool.result", direction="executor-to-harness", kind="request", since="bma.executor.v1", params_type="ToolResultParams", result_type="Ack", capability=None, idempotent_by="tool_call_id"),
1133
+ "tool.cancel": MethodSpec(name="tool.cancel", direction="harness-to-executor", kind="request", since="bma.executor.v1", params_type="ToolCancelParams", result_type="ToolCancelResult", capability=None, idempotent_by=None),
1134
+ "tool.progress": MethodSpec(name="tool.progress", direction="executor-to-harness", kind="notification", since="bma.executor.v1", params_type="ToolProgressParams", result_type=None, capability=None, idempotent_by=None),
1135
+ "process.start": MethodSpec(name="process.start", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="ProcessStartParams", result_type="ProcessState", capability="process.enabled", idempotent_by="session_id+process_id"),
1136
+ "process.read": MethodSpec(name="process.read", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="ProcessReadParams", result_type="ProcessReadResult", capability="process.enabled", idempotent_by=None),
1137
+ "process.write": MethodSpec(name="process.write", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="ProcessWriteParams", result_type="ProcessWriteResult", capability="process.enabled", idempotent_by=None),
1138
+ "process.interrupt": MethodSpec(name="process.interrupt", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="ProcessSignalParams", result_type="ProcessState", capability="process.enabled", idempotent_by=None),
1139
+ "process.terminate": MethodSpec(name="process.terminate", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="ProcessSignalParams", result_type="ProcessState", capability="process.enabled", idempotent_by=None),
1140
+ "process.list": MethodSpec(name="process.list", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="ProcessListParams", result_type="ProcessListResult", capability="process.enabled", idempotent_by=None),
1141
+ "process.status": MethodSpec(name="process.status", direction="executor-to-harness", kind="notification", since="bma.executor.v1.1", params_type="ProcessStatusParams", result_type=None, capability="process.enabled", idempotent_by=None),
1142
+ "terminal.open": MethodSpec(name="terminal.open", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="TerminalOpenParams", result_type="TerminalOpenResult", capability="terminal.enabled", idempotent_by="terminal_id"),
1143
+ "terminal.attach": MethodSpec(name="terminal.attach", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="TerminalAttachParams", result_type="TerminalAttachResult", capability="terminal.enabled", idempotent_by=None),
1144
+ "terminal.close": MethodSpec(name="terminal.close", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="TerminalCloseParams", result_type="TerminalCloseResult", capability="terminal.enabled", idempotent_by="terminal_id"),
1145
+ "skill.install": MethodSpec(name="skill.install", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="SkillInstallParams", result_type="SkillInstallResult", capability="skills.install", idempotent_by="skill_id+revision_id+digest"),
1146
+ "workspace.backup": MethodSpec(name="workspace.backup", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="WorkspaceBackupParams", result_type="WorkspaceBackupResult", capability="workspace.backup", idempotent_by="backup_id"),
1147
+ "turn.start": MethodSpec(name="turn.start", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="TurnStartParams", result_type="TurnStartResult", capability="agent", idempotent_by="turn_id"),
1148
+ "turn.input": MethodSpec(name="turn.input", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="TurnInputParams", result_type="Ack", capability="agent", idempotent_by="input_id"),
1149
+ "turn.cancel": MethodSpec(name="turn.cancel", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="TurnCancelParams", result_type="TurnCancelResult", capability="agent", idempotent_by=None),
1150
+ "session.close": MethodSpec(name="session.close", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="SessionCloseParams", result_type="SessionCloseResult", capability="agent", idempotent_by=None),
1151
+ "session.event_delta": MethodSpec(name="session.event_delta", direction="executor-to-harness", kind="notification", since="bma.executor.v1.1", params_type="SessionEventDeltaParams", result_type=None, capability="agent", idempotent_by=None),
1152
+ "interaction.request": MethodSpec(name="interaction.request", direction="executor-to-harness", kind="request", since="bma.executor.v1.1", params_type="InteractionRequestParams", result_type="InteractionRequestResult", capability="agent", idempotent_by="interaction_id"),
1153
+ "interaction.response": MethodSpec(name="interaction.response", direction="harness-to-executor", kind="request", since="bma.executor.v1.1", params_type="InteractionResponseParams", result_type="InteractionResponseResult", capability="agent", idempotent_by="interaction_id"),
1154
+ "interaction.cancel": MethodSpec(name="interaction.cancel", direction="executor-to-harness", kind="request", since="bma.executor.v1.1", params_type="InteractionCancelParams", result_type="Ack", capability="agent", idempotent_by="interaction_id"),
1155
+ }