@steerable/runtime-win32-x64 0.9.1 → 0.10.0

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.
Files changed (68) hide show
  1. package/bin/steerable-egress-proxy.exe +0 -0
  2. package/bin/win-spawn-helper.exe +0 -0
  3. package/package.json +1 -1
  4. package/python-runtime/manifest.json +1 -1
  5. package/python-runtime/python/Lib/site-packages/cffi-2.1.1.dist-info/RECORD +1 -1
  6. package/python-runtime/python/Lib/site-packages/httpx-0.28.1.dist-info/RECORD +1 -1
  7. package/python-runtime/python/Lib/site-packages/idna-3.20.dist-info/RECORD +1 -1
  8. package/python-runtime/python/Lib/site-packages/jsonschema-4.26.0.dist-info/RECORD +1 -1
  9. package/python-runtime/python/Lib/site-packages/mcp-1.30.0.dist-info/RECORD +1 -1
  10. package/python-runtime/python/Lib/site-packages/python_dotenv-1.2.4.dist-info/RECORD +1 -1
  11. package/python-runtime/python/Lib/site-packages/pywin32-312.dist-info/RECORD +2 -2
  12. package/python-runtime/python/Lib/site-packages/{steerable_agent_harness-0.9.1.dist-info → steerable_agent_harness-0.10.0.dist-info}/METADATA +1 -1
  13. package/python-runtime/python/Lib/site-packages/{steerable_agent_harness-0.9.1.dist-info → steerable_agent_harness-0.10.0.dist-info}/RECORD +7 -7
  14. package/python-runtime/python/Lib/site-packages/{steerable_agent_protocol-0.9.1.dist-info → steerable_agent_protocol-0.10.0.dist-info}/METADATA +1 -1
  15. package/python-runtime/python/Lib/site-packages/steerable_agent_protocol-0.10.0.dist-info/RECORD +11 -0
  16. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/__init__.py +48 -0
  17. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/budget.py +124 -0
  18. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/child_notice.py +84 -0
  19. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/child_record.py +174 -0
  20. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/engines.py +499 -0
  21. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/history.py +114 -1
  22. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/orchestration.py +496 -33
  23. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/pool.py +662 -16
  24. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/registry.py +345 -0
  25. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/storage/__init__.py +52 -0
  26. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/storage/in_memory.py +74 -0
  27. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/storage/sqlalchemy_store.py +153 -0
  28. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/storage/sqlite_store.py +117 -1
  29. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime/subagent.py +157 -6
  30. package/python-runtime/python/Lib/site-packages/{steerable_agent_runtime-0.9.1.dist-info → steerable_agent_runtime-0.10.0.dist-info}/METADATA +39 -4
  31. package/python-runtime/python/Lib/site-packages/{steerable_agent_runtime-0.9.1.dist-info → steerable_agent_runtime-0.10.0.dist-info}/RECORD +26 -16
  32. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime_native/steerable_agent_runtime_native.pyd +0 -0
  33. package/python-runtime/python/Lib/site-packages/{steerable_agent_runtime_native-1.0.7.dist-info → steerable_agent_runtime_native-1.0.8.dist-info}/METADATA +1 -1
  34. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime_native-1.0.8.dist-info/RECORD +9 -0
  35. package/python-runtime/python/Lib/site-packages/steerable_sidecar/sidecar.py +545 -6
  36. package/python-runtime/python/Lib/site-packages/steerable_sidecar-0.10.0.dist-info/METADATA +97 -0
  37. package/python-runtime/python/Lib/site-packages/{steerable_sidecar-0.9.1.dist-info → steerable_sidecar-0.10.0.dist-info}/RECORD +12 -12
  38. package/python-runtime/python/Lib/site-packages/uvicorn-0.54.0.dist-info/RECORD +1 -1
  39. package/python-runtime/python/Scripts/cffi-gen-src.exe +0 -0
  40. package/python-runtime/python/Scripts/dotenv.exe +0 -0
  41. package/python-runtime/python/Scripts/httpx.exe +0 -0
  42. package/python-runtime/python/Scripts/idna.exe +0 -0
  43. package/python-runtime/python/Scripts/jsonschema.exe +0 -0
  44. package/python-runtime/python/Scripts/mcp.exe +0 -0
  45. package/python-runtime/python/Scripts/pip.exe +0 -0
  46. package/python-runtime/python/Scripts/pip3.12.exe +0 -0
  47. package/python-runtime/python/Scripts/pip3.exe +0 -0
  48. package/python-runtime/python/Scripts/pywin32_postinstall.exe +0 -0
  49. package/python-runtime/python/Scripts/pywin32_testall.exe +0 -0
  50. package/python-runtime/python/Scripts/steerable-sidecar-acp.exe +0 -0
  51. package/python-runtime/python/Scripts/steerable-sidecar-headless.exe +0 -0
  52. package/python-runtime/python/Scripts/steerable-sidecar.exe +0 -0
  53. package/python-runtime/python/Scripts/uvicorn.exe +0 -0
  54. package/runtime.json +94 -70
  55. package/python-runtime/python/Lib/site-packages/steerable_agent_protocol-0.9.1.dist-info/RECORD +0 -11
  56. package/python-runtime/python/Lib/site-packages/steerable_agent_runtime_native-1.0.7.dist-info/RECORD +0 -9
  57. package/python-runtime/python/Lib/site-packages/steerable_sidecar-0.9.1.dist-info/METADATA +0 -58
  58. /package/python-runtime/python/Lib/site-packages/{steerable_agent_harness-0.9.1.dist-info → steerable_agent_harness-0.10.0.dist-info}/INSTALLER +0 -0
  59. /package/python-runtime/python/Lib/site-packages/{steerable_agent_harness-0.9.1.dist-info → steerable_agent_harness-0.10.0.dist-info}/WHEEL +0 -0
  60. /package/python-runtime/python/Lib/site-packages/{steerable_agent_protocol-0.9.1.dist-info → steerable_agent_protocol-0.10.0.dist-info}/INSTALLER +0 -0
  61. /package/python-runtime/python/Lib/site-packages/{steerable_agent_protocol-0.9.1.dist-info → steerable_agent_protocol-0.10.0.dist-info}/WHEEL +0 -0
  62. /package/python-runtime/python/Lib/site-packages/{steerable_agent_runtime-0.9.1.dist-info → steerable_agent_runtime-0.10.0.dist-info}/INSTALLER +0 -0
  63. /package/python-runtime/python/Lib/site-packages/{steerable_agent_runtime-0.9.1.dist-info → steerable_agent_runtime-0.10.0.dist-info}/WHEEL +0 -0
  64. /package/python-runtime/python/Lib/site-packages/{steerable_agent_runtime_native-1.0.7.dist-info → steerable_agent_runtime_native-1.0.8.dist-info}/INSTALLER +0 -0
  65. /package/python-runtime/python/Lib/site-packages/{steerable_agent_runtime_native-1.0.7.dist-info → steerable_agent_runtime_native-1.0.8.dist-info}/WHEEL +0 -0
  66. /package/python-runtime/python/Lib/site-packages/{steerable_sidecar-0.9.1.dist-info → steerable_sidecar-0.10.0.dist-info}/INSTALLER +0 -0
  67. /package/python-runtime/python/Lib/site-packages/{steerable_sidecar-0.9.1.dist-info → steerable_sidecar-0.10.0.dist-info}/WHEEL +0 -0
  68. /package/python-runtime/python/Lib/site-packages/{steerable_sidecar-0.9.1.dist-info → steerable_sidecar-0.10.0.dist-info}/entry_points.txt +0 -0
@@ -41,11 +41,26 @@ from steerable_agent_protocol.generated import (
41
41
  TraceSpan,
42
42
  )
43
43
 
44
+ from ..child_record import (
45
+ TERMINAL_CHILD_STATUSES,
46
+ ChildRecord,
47
+ record_from_columns,
48
+ record_to_values,
49
+ )
44
50
  from ..errors import StorageError, StorageUpgradeBlockedError, StoreAlreadyOwnedError
45
51
  from .write_lease import WriteLease, acquire_shared_lease, acquire_write_lease
46
52
 
47
- SCHEMA_VERSION = 1
53
+ SCHEMA_VERSION = 2
48
54
  _BUSY_TIMEOUT_MS = 5000
55
+
56
+ #: The terminal status set, as a SQL ``IN`` list. Kept next to the schema so a
57
+ #: status added to ``child_record.TERMINAL_CHILD_STATUSES`` without this list
58
+ #: fails ``test_child_record_statuses_match_sql`` instead of silently making
59
+ #: ``include_finished=False`` return finished rows.
60
+ _TERMINAL_CHILD_STATUS_SQL = (
61
+ " (" + ", ".join(f"'{s}'" for s in sorted(TERMINAL_CHILD_STATUSES)) + ")"
62
+ )
63
+
49
64
  # A second process can observe version 0 while the first still holds the
50
65
  # exclusive lease to create the schema. The hold is the migration itself,
51
66
  # not a live sidecar, so wait out that window before refusing.
@@ -109,6 +124,30 @@ CREATE TABLE IF NOT EXISTS history (
109
124
  data TEXT NOT NULL,
110
125
  PRIMARY KEY (record_id, seq)
111
126
  );
127
+
128
+ -- Child-agent index (schema v2). Only the edge and the state: whose child
129
+ -- this is, how deep, what profile and engine build it, and where it ended.
130
+ -- Task text and answers live in the child's own ``history`` record, so each
131
+ -- has one authoritative copy; ``profile`` and ``depth`` are duplicated here
132
+ -- because resume must rebuild the child's tool domain and nesting from what
133
+ -- it was created with, never from current settings.
134
+ CREATE TABLE IF NOT EXISTS children (
135
+ record_id TEXT PRIMARY KEY,
136
+ parent_record_id TEXT NOT NULL,
137
+ child_id TEXT NOT NULL,
138
+ depth INTEGER NOT NULL,
139
+ profile TEXT,
140
+ engine TEXT NOT NULL,
141
+ status TEXT NOT NULL,
142
+ resumable INTEGER NOT NULL DEFAULT 0,
143
+ prompt_tokens INTEGER,
144
+ completion_tokens INTEGER,
145
+ usage_known INTEGER NOT NULL DEFAULT 1,
146
+ created_at TEXT NOT NULL,
147
+ updated_at TEXT NOT NULL
148
+ );
149
+ CREATE INDEX IF NOT EXISTS idx_children_parent ON children(parent_record_id, created_at);
150
+ CREATE INDEX IF NOT EXISTS idx_children_child ON children(parent_record_id, child_id);
112
151
  """
113
152
 
114
153
 
@@ -495,3 +534,80 @@ class SqliteStorage:
495
534
  async with self._lock:
496
535
  rows = self._db.execute(sql, params).fetchall()
497
536
  return [r["record_id"] for r in rows]
537
+
538
+ # ------------------------------------------------------------------
539
+ # Child-agent index
540
+ # ------------------------------------------------------------------
541
+
542
+ async def upsert_child(self, record: ChildRecord) -> None:
543
+ async with self._lock:
544
+ self._db.execute(
545
+ "INSERT OR REPLACE INTO children ("
546
+ " record_id, parent_record_id, child_id, depth, profile,"
547
+ " engine, status, resumable, prompt_tokens, completion_tokens,"
548
+ " usage_known, created_at, updated_at"
549
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
550
+ record_to_values(record),
551
+ )
552
+ self._db.commit()
553
+
554
+ async def finish_child(
555
+ self,
556
+ record_id: str,
557
+ *,
558
+ status: str,
559
+ prompt_tokens: int | None = None,
560
+ completion_tokens: int | None = None,
561
+ usage_known: bool = True,
562
+ resumable: bool = False,
563
+ updated_at: str,
564
+ ) -> bool:
565
+ async with self._lock:
566
+ cursor = self._db.execute(
567
+ "UPDATE children SET"
568
+ " status = ?, resumable = ?, prompt_tokens = ?,"
569
+ " completion_tokens = ?, usage_known = ?, updated_at = ?"
570
+ " WHERE record_id = ?",
571
+ (
572
+ status,
573
+ int(resumable),
574
+ prompt_tokens,
575
+ completion_tokens,
576
+ int(usage_known),
577
+ updated_at,
578
+ record_id,
579
+ ),
580
+ )
581
+ self._db.commit()
582
+ return cursor.rowcount > 0
583
+
584
+ async def get_child(self, record_id: str) -> ChildRecord | None:
585
+ async with self._lock:
586
+ row = self._db.execute(
587
+ "SELECT * FROM children WHERE record_id = ?", (record_id,)
588
+ ).fetchone()
589
+ return record_from_columns(dict(row)) if row else None
590
+
591
+ async def list_children(
592
+ self, parent_record_id: str, *, include_finished: bool = True
593
+ ) -> list[ChildRecord]:
594
+ sql = "SELECT * FROM children WHERE parent_record_id = ?"
595
+ if not include_finished:
596
+ sql += " AND status NOT IN" + _TERMINAL_CHILD_STATUS_SQL
597
+ sql += " ORDER BY created_at, rowid"
598
+ async with self._lock:
599
+ rows = self._db.execute(sql, (parent_record_id,)).fetchall()
600
+ return [record_from_columns(dict(r)) for r in rows]
601
+
602
+ async def list_all_children(
603
+ self, *, prefix: str | None = None
604
+ ) -> list[ChildRecord]:
605
+ sql = "SELECT * FROM children"
606
+ params: list[Any] = []
607
+ if prefix is not None:
608
+ sql += " WHERE parent_record_id LIKE ?"
609
+ params.append(f"{prefix}%")
610
+ sql += " ORDER BY created_at, rowid"
611
+ async with self._lock:
612
+ rows = self._db.execute(sql, params).fetchall()
613
+ return [record_from_columns(dict(r)) for r in rows]
@@ -52,6 +52,7 @@ Design:
52
52
  from __future__ import annotations
53
53
 
54
54
  import json
55
+ import logging
55
56
  from collections.abc import Callable
56
57
  from dataclasses import dataclass
57
58
  from typing import Any
@@ -64,8 +65,10 @@ from .ask_user import (
64
65
  normalize_ask_user_questions,
65
66
  )
66
67
  from .errors import ToolDispatchError
67
- from .llm import LLMProvider
68
+ from .history import completed_turn_prefix
69
+ from .llm import LLMMessage, LLMProvider
68
70
  from .loop import CoreLoop, LoopConfig, LoopContext, LoopHooks, ToolExecutor
71
+ from .engines import AcpEngineSpec, AcpPermissionPolicy, AcpToolBridge
69
72
  from .pool import (
70
73
  AgentPool,
71
74
  LoopFactory,
@@ -78,6 +81,7 @@ from .pool import (
78
81
  #: profile" wording.
79
82
  DEFAULT_PROFILE_LABEL = "general-purpose"
80
83
 
84
+ logger = logging.getLogger(__name__)
81
85
  #: Child-only coordination tool. A child reports missing user-owned input to
82
86
  #: its parent instead of opening an interactive question card itself.
83
87
  PARENT_INPUT_TOOL_NAME = "request_parent_input"
@@ -134,12 +138,30 @@ class SubagentConfig:
134
138
  allow_tools: bool = True
135
139
  tool_filter: frozenset[str] | None = None
136
140
  model: str | None = None
141
+ #: Reasoning effort for this profile's children (CC Agent-tool parity with
142
+ #: the chat picker's per-request knob). ``None`` inherits the parent's
143
+ #: request, which is what an unpinned profile must do: a role that did not
144
+ #: ask for a level should reason exactly like the agent that spawned it.
145
+ #: Honoring it needs the host's ``provider_factory``, same as ``model``.
146
+ reasoning_effort: str | None = None
137
147
  concurrent: bool = False
138
148
  max_parallel: int = 4
139
149
  #: Profile system prompt (CC ``.claude/agents`` body parity): seeded as
140
150
  #: the child loop's first message, ahead of the task. ``None`` runs the
141
151
  #: child with no system prompt at all — the legacy behavior.
142
152
  system_prompt: str | None = None
153
+ #: Seed this profile's children with the parent's answered transcript
154
+ #: instead of a bare task. A profile is the right place for this default
155
+ #: because "this kind of work continues the conversation" is a property of
156
+ #: the role (a reviewer verifying findings), not of one call. The tool's
157
+ #: ``context`` argument overrides it per call.
158
+ fork_context: bool = False
159
+ #: Run this profile's children on an external agent process instead of a
160
+ #: local loop. ``None`` keeps the local engine. The spec carries the
161
+ #: command; the policy and bridge say what that process may reach.
162
+ acp_engine: AcpEngineSpec | None = None
163
+ acp_permission: AcpPermissionPolicy | None = None
164
+ acp_tool_bridge: AcpToolBridge | None = None
143
165
  description: str = (
144
166
  "Delegate a self-contained subtask to a sub-agent with its own "
145
167
  "reasoning loop. Good for parallelizable or context-heavy subtasks; "
@@ -179,12 +201,17 @@ def subagent_tool_descriptor(
179
201
  config: SubagentConfig | None = None,
180
202
  *,
181
203
  registry: SubagentRegistry | None = None,
204
+ fork_available: bool = False,
182
205
  ) -> dict[str, Any]:
183
206
  """OpenAI tool schema to append to the parent loop's tools list.
184
207
 
185
208
  With a ``registry``, the schema gains a ``subagent_type`` enum of the
186
209
  registered profile names (CC ``subagent_type`` parity); without one the
187
210
  tool takes only ``task`` and runs the default profile.
211
+
212
+ ``fork_available`` advertises the ``context`` parameter; the caller sets
213
+ it only when the executor was given the parent transcript, so the schema
214
+ never offers a mode that would fail.
188
215
  """
189
216
  config = config or SubagentConfig()
190
217
  properties: dict[str, Any] = {
@@ -192,11 +219,25 @@ def subagent_tool_descriptor(
192
219
  "type": "string",
193
220
  "description": (
194
221
  "Complete, self-contained instructions for the "
195
- "sub-agent — it sees none of this conversation."
222
+ "sub-agent — it sees none of this conversation unless "
223
+ "context is \"fork\"."
196
224
  ),
197
225
  },
198
226
  }
199
227
  description = config.description
228
+ # Advertise `context` only when a fork is actually reachable: the executor
229
+ # cannot seed a child without the parent transcript, and offering a
230
+ # parameter that always fails is worse than omitting it.
231
+ if fork_available:
232
+ properties["context"] = {
233
+ "type": "string",
234
+ "enum": ["fresh", "fork"],
235
+ "description": (
236
+ "\"fresh\" (default) starts the child with only the task. "
237
+ "\"fork\" seeds it with this conversation's completed turns so "
238
+ "it can continue an investigation without being retold."
239
+ ),
240
+ }
200
241
  if registry is not None and registry.names():
201
242
  properties["subagent_type"] = {
202
243
  "type": "string",
@@ -381,6 +422,9 @@ class SubagentExecutor:
381
422
  pool: AgentPool | None = None,
382
423
  history_store: Any = None,
383
424
  record_id_prefix: str | None = None,
425
+ child_registry: Any = None,
426
+ parent_projection: Callable[[], list[LLMMessage]] | None = None,
427
+ acp_tool_bridge: AcpToolBridge | None = None,
384
428
  ) -> None:
385
429
  self._inner = inner
386
430
  self._provider = provider
@@ -391,12 +435,31 @@ class SubagentExecutor:
391
435
  self._parent_tools = list(tools or [])
392
436
  self._history_store = history_store
393
437
  self._record_id_prefix = record_id_prefix
438
+ #: Kept for the needs-input notice: the pool owns the sink that lands
439
+ #: `child_spawned`/`child_completed`, and a child asking its parent for
440
+ #: input has to surface on that same channel or the panel cannot say
441
+ #: which row is waiting on the user.
442
+ self._event_sink = event_sink
443
+ #: Where an external child's file and terminal requests land. ``None``
444
+ #: means this host grants none (a bridge with no capabilities refuses
445
+ #: everything), which is the safe default for a spawned process.
446
+ self._acp_tool_bridge = acp_tool_bridge
447
+ #: The parent's model-visible transcript, read at delegation time.
448
+ #: ``None`` means this host cannot fork, and the tool schema omits the
449
+ #: parameter rather than offering one that always fails.
450
+ self._parent_projection = parent_projection
394
451
  self._parent_input_requests: dict[str, dict[str, Any]] = {}
452
+ #: Delegation-only hosts (orchestration off) never attach a pool that
453
+ #: already knows about the index, so the executor's own pool needs it
454
+ #: too — otherwise a delegated child leaves no durable row and cannot
455
+ #: be listed or resumed after the turn.
395
456
  self._pool = pool or AgentPool(
396
457
  config=OrchestrationConfig(max_parallel=self._config.max_parallel),
397
458
  depth=0,
398
459
  lineage="0",
399
460
  event_sink=event_sink,
461
+ registry=child_registry,
462
+ parent_record_id=record_id_prefix,
400
463
  )
401
464
 
402
465
  def attach_pool(self, pool: AgentPool) -> None:
@@ -409,6 +472,12 @@ class SubagentExecutor:
409
472
  """
410
473
  self._pool = pool
411
474
 
475
+ @property
476
+ def pool(self) -> AgentPool:
477
+ """This executor's child pool — exposed so a host can report the
478
+ children's usage alongside the turn's own bill."""
479
+ return self._pool
480
+
412
481
  async def execute(self, call: ToolCall, ctx: LoopContext) -> ToolResult:
413
482
  if call.name != self._config.tool_name:
414
483
  return await self._inner.execute(call, ctx)
@@ -435,6 +504,32 @@ class SubagentExecutor:
435
504
  needsFollowup=True,
436
505
  )
437
506
  config = profile
507
+ raw_context = str(call.arguments.get("context") or "").strip().lower()
508
+ if raw_context and raw_context not in ("fresh", "fork"):
509
+ return ToolResult(
510
+ success=False,
511
+ error=f'unknown context {raw_context!r}; expected "fresh" or "fork"',
512
+ needsFollowup=True,
513
+ )
514
+ # The call's explicit choice wins; otherwise the profile decides. A
515
+ # profile declares `fork_context` because "this role continues the
516
+ # conversation" is a property of the role, not of one call.
517
+ want_fork = (raw_context == "fork") if raw_context else config.fork_context
518
+ seed: list[LLMMessage] | None = None
519
+ if want_fork:
520
+ if self._parent_projection is None:
521
+ return ToolResult(
522
+ success=False,
523
+ error=(
524
+ 'context="fork" needs the parent transcript, which this '
525
+ "host did not wire; use \"fresh\""
526
+ ),
527
+ needsFollowup=True,
528
+ )
529
+ fork_seed = completed_turn_prefix(self._parent_projection())
530
+ # The profile's own system prompt replaces the parent's, so two
531
+ # instructions never compete for the child's role definition.
532
+ seed = [m for m in fork_seed if m.role != "system"] or None
438
533
  if config.model is not None and self._provider_factory is None:
439
534
  return ToolResult(
440
535
  success=False,
@@ -443,6 +538,15 @@ class SubagentExecutor:
443
538
  "but this host has no provider factory"
444
539
  ),
445
540
  )
541
+ if config.reasoning_effort is not None and self._provider_factory is None:
542
+ return ToolResult(
543
+ success=False,
544
+ error=(
545
+ f"sub-agent profile requests reasoning effort "
546
+ f"{config.reasoning_effort!r} but this host has no "
547
+ "provider factory"
548
+ ),
549
+ )
446
550
  try:
447
551
  outcome = await self._pool.run(
448
552
  task,
@@ -450,6 +554,24 @@ class SubagentExecutor:
450
554
  loop_factory=self._loop_factory_for(config),
451
555
  event_extra={"profile": type_name or DEFAULT_PROFILE_LABEL},
452
556
  system_prompt=config.system_prompt,
557
+ # The durable index records the resolved profile so a resumed
558
+ # child is rebuilt with the domain it was created under. The
559
+ # label matches what ``child_spawned`` reports, so the event
560
+ # stream and the index never disagree about which profile ran.
561
+ profile=type_name or DEFAULT_PROFILE_LABEL,
562
+ seed=seed,
563
+ **(
564
+ {
565
+ "engine": "acp",
566
+ "acp_engine": config.acp_engine,
567
+ # A profile may pin its own policy; otherwise the
568
+ # engine runs under the reject-by-default one.
569
+ "acp_permission": config.acp_permission,
570
+ "acp_tool_bridge": self._acp_tool_bridge,
571
+ }
572
+ if config.acp_engine is not None
573
+ else {}
574
+ ),
453
575
  )
454
576
  except OrchestrationBudgetExceeded as exc:
455
577
  return ToolResult(
@@ -459,6 +581,10 @@ class SubagentExecutor:
459
581
  )
460
582
  parent_input = self._parent_input_requests.pop(outcome.child_id, None)
461
583
  if parent_input is not None:
584
+ # R7-3: the panel marks the row 「等待你的回答」, and the question
585
+ # card names the child it came from. Both read this event; neither
586
+ # has to correlate a delegation result with a question card.
587
+ self._emit_child_needs_input(outcome.child_id, parent_input)
462
588
  return ToolResult(
463
589
  success=True,
464
590
  message=json.dumps(parent_input, ensure_ascii=False),
@@ -480,6 +606,29 @@ class SubagentExecutor:
480
606
  message=outcome.answer or "(sub-agent returned no text)",
481
607
  )
482
608
 
609
+ def _emit_child_needs_input(
610
+ self, child_id: str, request: dict[str, Any]
611
+ ) -> None:
612
+ """Announce that a child is blocked on the user.
613
+
614
+ Carries the child's intro so the question card can say which agent is
615
+ asking, without the host having to join a tool result against a card
616
+ by position. Best-effort: a host without a sink still gets the
617
+ `needs_input` tool result, which is the functional path.
618
+ """
619
+ if self._event_sink is None:
620
+ return
621
+ try:
622
+ self._event_sink(
623
+ "child_needs_input",
624
+ {
625
+ "childId": child_id,
626
+ "intro": str(request.get("intro") or ""),
627
+ },
628
+ )
629
+ except Exception as exc: # noqa: BLE001 — an event never fails a run
630
+ logger.warning("child needs-input event failed: %s", exc)
631
+
483
632
  def _loop_factory_for(self, config: SubagentConfig) -> LoopFactory:
484
633
  """Per-spawn child builder resolving the profile's provider, tool
485
634
  domain, and round bound (profiles differ per call, so the pool's
@@ -489,10 +638,12 @@ class SubagentExecutor:
489
638
  child_id: str, tool_filter: frozenset[str] | None
490
639
  ) -> tuple[CoreLoop, list[dict[str, Any]] | None]:
491
640
  provider = self._provider
492
- if config.model is not None:
493
- # execute() fails closed before the spawn when a
494
- # model-bearing profile has no provider factory.
495
- provider = self._provider_factory(config.model)
641
+ if config.model is not None or config.reasoning_effort is not None:
642
+ # execute() fails closed before the spawn when a pinned
643
+ # profile has no provider factory, so both are reachable here.
644
+ provider = self._provider_factory(
645
+ config.model, config.reasoning_effort
646
+ )
496
647
  schemas: list[dict[str, Any]] = []
497
648
  if config.allow_tools:
498
649
  schemas = [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steerable-agent-runtime
3
- Version: 0.9.1
3
+ Version: 0.10.0
4
4
  Summary: Steerable agent runtime: LLM, tool, storage, and transport adapters.
5
5
  License: Apache-2.0
6
6
  Requires-Python: >=3.10
@@ -10,7 +10,7 @@ Requires-Dist: mcp<2.0.0,>=1.13.0
10
10
  Requires-Dist: pydantic>=2.10.0
11
11
  Requires-Dist: steerable-agent-protocol<1.0.0,>=0.1.0
12
12
  Requires-Dist: steerable-agent-harness<1.0.0,>=0.1.0
13
- Requires-Dist: steerable-agent-runtime-native==1.0.7
13
+ Requires-Dist: steerable-agent-runtime-native==1.0.8
14
14
  Provides-Extra: sqlalchemy
15
15
  Requires-Dist: sqlalchemy>=2.0; extra == "sqlalchemy"
16
16
  Provides-Extra: fastapi
@@ -38,8 +38,10 @@ Provides four orthogonal pluggable adapters:
38
38
  `ToolMode`s using `steerable_agent_harness.policy`, supports per-tool
39
39
  permission overrides, and dispatches `ToolCall` → `ToolResult`.
40
40
  - `StorageAdapter` — persistence interface for `AgentSession`, `ChatMessage`,
41
- `ChatAgent`, and `HarnessTrace + spans + events`. Reference impls: in-memory
42
- (default for sidecar/dev) and SQLAlchemy (for hosted backends).
41
+ `ChatAgent`, `HarnessTrace + spans + events`, the durable history record,
42
+ and the child-agent index. Reference impls: in-memory (default for
43
+ sidecar/dev) and SQLite (zero-dependency, the sidecar's own store).
44
+ SQLAlchemy remains available for hosted backends.
43
45
  - `TransportAdapter` — wire format. `FastAPISseTransport` exports SSE for
44
46
  hosted setups; `StdioJsonRpcTransport` powers the steerable-sidecar.
45
47
 
@@ -53,6 +55,39 @@ directly. Browsers/Electron consume runtime output via either the SSE transport
53
55
  pip install steerable-agent-runtime[all]
54
56
  ```
55
57
 
58
+ ## Upgrading from 0.9
59
+
60
+ The multi-agent layer became "sub-agents as persistent objects" in this
61
+ release. Nothing in the single-agent path changed.
62
+
63
+ - **`SCHEMA_VERSION` 1 → 2.** The new `children` table is created with
64
+ `CREATE TABLE IF NOT EXISTS`, so an existing database upgrades in place on
65
+ first open — no migration function, no data rewrite. A database written by a
66
+ newer build still refuses to open.
67
+ - **`budgetTokens` now bounds the whole turn tree.** It used to limit each
68
+ loop separately; a parent plus three children could each spend the full
69
+ allowance. Every agent in the tree now debits one counter, and the first to
70
+ cross it fails there. A host that relied on per-child allowances gets a
71
+ tighter (correct) limit.
72
+ - **New `TreeBudget` / `SessionBudgetExceeded`** in `steerable_agent_runtime`.
73
+ `AgentPool(budget=...)` shares one counter across the pool; the parent loop's
74
+ usage is charged to the same counter by the host.
75
+ - **`provider_factory` for sub-agent profiles now takes `(model, effort)`**
76
+ instead of `(model)`. `None` for either knob means "inherit the parent's",
77
+ never "clear it". A profile pinning neither does not rebuild the provider at
78
+ all.
79
+ - **New: `AgentPool.spawn(..., engine="acp", acp_engine=...)`** runs a child as
80
+ an external process over the Agent Client Protocol instead of a local loop.
81
+ Such a child has `loop=None`, reports **no** token bill (`usage` unknown, not
82
+ zero), and refuses a mid-run `agent_send` (`child_not_steerable`) — a peer
83
+ runs one prompt, so there is no round boundary to steer at.
84
+ - **`HistorySeed.source_model`** records which model produced a forked
85
+ prefix. Additive; a seed written before this release simply lacks the key.
86
+ `completed_turn_prefix()` remains the fork primitive and now backs
87
+ `agent_spawn`'s `context: "fork"`.
88
+ - **`SubagentExecutor.attach_pool()` / `.pool`** expose the shared pool so a
89
+ host can report children's usage alongside the turn's own bill.
90
+
56
91
  Selectively install just the bits you need:
57
92
 
58
93
  ```bash
@@ -1,23 +1,27 @@
1
- steerable_agent_runtime-0.9.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
- steerable_agent_runtime-0.9.1.dist-info/METADATA,sha256=iH8nZVtllttRUBFGRi6KMCH1EhPGCA60ie3N1YEIlMA,2803
3
- steerable_agent_runtime-0.9.1.dist-info/RECORD,,
4
- steerable_agent_runtime-0.9.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- steerable_agent_runtime-0.9.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
6
- steerable_agent_runtime-0.9.1.dist-info/direct_url.json,sha256=de5cBYhP9h_udbmeRJJf6qCwvDkIkKOmiEbPPgpxE_k,289
7
- steerable_agent_runtime-0.9.1.dist-info/top_level.txt,sha256=oH6AX0Sbye_DmFcu-JFEwuu-yXwyCkkdquPt8t0pFJE,24
8
- steerable_agent_runtime/__init__.py,sha256=HS8RIPyYAcSfFszoX2xytjuOX4xf8qV0zRA1E5chzE8,12239
1
+ steerable_agent_runtime-0.10.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ steerable_agent_runtime-0.10.0.dist-info/METADATA,sha256=lqp7ybXr_6joQ2dCClJGoQQ9I4b8MU9uO7WYIfyoY2k,4931
3
+ steerable_agent_runtime-0.10.0.dist-info/RECORD,,
4
+ steerable_agent_runtime-0.10.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ steerable_agent_runtime-0.10.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
6
+ steerable_agent_runtime-0.10.0.dist-info/direct_url.json,sha256=Vo-WxnaUp5_j5ujLjRB9pyt3hyybEIzNLp_BncWQBF4,290
7
+ steerable_agent_runtime-0.10.0.dist-info/top_level.txt,sha256=oH6AX0Sbye_DmFcu-JFEwuu-yXwyCkkdquPt8t0pFJE,24
8
+ steerable_agent_runtime/__init__.py,sha256=lgvWntuMpJUldnGi0oOhS4Sc6qInx29gPbM1DtHgTZE,13414
9
9
  steerable_agent_runtime/__pycache__/__init__.cpython-312.pyc,,
10
10
  steerable_agent_runtime/__pycache__/antihallucination.cpython-312.pyc,,
11
11
  steerable_agent_runtime/__pycache__/approval.cpython-312.pyc,,
12
12
  steerable_agent_runtime/__pycache__/approval_policy.cpython-312.pyc,,
13
13
  steerable_agent_runtime/__pycache__/ask_user.cpython-312.pyc,,
14
14
  steerable_agent_runtime/__pycache__/branch.cpython-312.pyc,,
15
+ steerable_agent_runtime/__pycache__/budget.cpython-312.pyc,,
15
16
  steerable_agent_runtime/__pycache__/cache_control.cpython-312.pyc,,
16
17
  steerable_agent_runtime/__pycache__/calibration.cpython-312.pyc,,
18
+ steerable_agent_runtime/__pycache__/child_notice.cpython-312.pyc,,
19
+ steerable_agent_runtime/__pycache__/child_record.cpython-312.pyc,,
17
20
  steerable_agent_runtime/__pycache__/compaction.cpython-312.pyc,,
18
21
  steerable_agent_runtime/__pycache__/compaction_policy.cpython-312.pyc,,
19
22
  steerable_agent_runtime/__pycache__/config.cpython-312.pyc,,
20
23
  steerable_agent_runtime/__pycache__/delegation_gate.cpython-312.pyc,,
24
+ steerable_agent_runtime/__pycache__/engines.cpython-312.pyc,,
21
25
  steerable_agent_runtime/__pycache__/errors.cpython-312.pyc,,
22
26
  steerable_agent_runtime/__pycache__/gateway_catalog.cpython-312.pyc,,
23
27
  steerable_agent_runtime/__pycache__/handoff.cpython-312.pyc,,
@@ -41,6 +45,7 @@ steerable_agent_runtime/__pycache__/pool.cpython-312.pyc,,
41
45
  steerable_agent_runtime/__pycache__/pricing.cpython-312.pyc,,
42
46
  steerable_agent_runtime/__pycache__/pseudo.cpython-312.pyc,,
43
47
  steerable_agent_runtime/__pycache__/recording.cpython-312.pyc,,
48
+ steerable_agent_runtime/__pycache__/registry.cpython-312.pyc,,
44
49
  steerable_agent_runtime/__pycache__/reminders.cpython-312.pyc,,
45
50
  steerable_agent_runtime/__pycache__/replay.cpython-312.pyc,,
46
51
  steerable_agent_runtime/__pycache__/resume.cpython-312.pyc,,
@@ -62,20 +67,24 @@ steerable_agent_runtime/approval.py,sha256=l9VaKSqG1w_w0TSKFI6FwBLzwAs-MaqyKpXde
62
67
  steerable_agent_runtime/approval_policy.py,sha256=sI9vI6_5alBwnLKmXvVrvwXSXdxXUctHTvcyFAJwLyI,8917
63
68
  steerable_agent_runtime/ask_user.py,sha256=CauR-qDm3F69yQT5B1sekZ0_L0E6Qgsa4YD2T03UaFg,13803
64
69
  steerable_agent_runtime/branch.py,sha256=i7kSm6DwecvZy0Q3PP1YZS6S5cZ2qTfHZ_tpZTGDbvM,15450
70
+ steerable_agent_runtime/budget.py,sha256=ELS0a2iVgsBIYv-_s2ln2fthvaCcKmR7c2L03wX35rw,4559
65
71
  steerable_agent_runtime/cache_control.py,sha256=iyni538DY7Q4A-ctAsbrLHTo4ztODYzBEJoA5RsBOt0,9651
66
72
  steerable_agent_runtime/calibration.py,sha256=vrWGGhEPnJRDyU1J273S7TeOrcTB7Lgvmrr4n_upegY,12200
73
+ steerable_agent_runtime/child_notice.py,sha256=Dfg5qRo8xxhpFeWO2YJtY2QW6CN3TVQaUMqYKTDcX4Q,3252
74
+ steerable_agent_runtime/child_record.py,sha256=3AdGmlW3TiXLG0L5fYzMjhdkm6QbjcO6uAlisCph-qw,5772
67
75
  steerable_agent_runtime/compaction.py,sha256=er5KbPOs6LHX2krc8E2Ewie8dR95zcTKV7NLr4qmx1w,34710
68
76
  steerable_agent_runtime/compaction_policy.py,sha256=R7Vs074fSeQGI7Hwdt9_gArfBmS4GrHs9Ozp0hnTTHA,3789
69
77
  steerable_agent_runtime/config.py,sha256=vOyraSr-vuRY8jSuBe5n6VvAvvwpkzQSdw1kp4dxHJE,8868
70
78
  steerable_agent_runtime/default.harness.json,sha256=5RYE-1SQIsArcTcQvJmTAH2PjEZQABr4UVFYXKF-o_Y,555
71
79
  steerable_agent_runtime/default.harness.yaml,sha256=6NRwCzMgrip5pXBI41t6Ej2rm2_O0C7uzoPbVT3PNLE,1769
72
80
  steerable_agent_runtime/delegation_gate.py,sha256=pAyebumyKnheTcmkEYeB-pW8tAHbLWW-XsYl1DMIV0o,4083
81
+ steerable_agent_runtime/engines.py,sha256=6SSocnrCbTwNbcdlnmrc5VoslVHOilYzwFedMTOULNk,18952
73
82
  steerable_agent_runtime/errors.py,sha256=9NQiStURRcMPxnxwfIYjut9iAQMetegMjSn5OwQi_PA,1749
74
83
  steerable_agent_runtime/gateway_catalog.py,sha256=ml04q_jTkIJm_QitT-fV4WAfsZ4Dbi8g-G-pajLi-M0,15488
75
84
  steerable_agent_runtime/handoff.py,sha256=O_2JtUuZVlCvbEvlCbBd4qf2BdqXRZ54kaaP5OMZZcM,5506
76
85
  steerable_agent_runtime/harness.py,sha256=wuJR4CSznq6iy31YmJbm5oSGRVTadS_UQ69lDxxTsgc,32846
77
86
  steerable_agent_runtime/harness_spec.py,sha256=GYmV1isa3WljKNDkxMEAER7iv3-YyQPaS12Ma5jqbOA,12626
78
- steerable_agent_runtime/history.py,sha256=HVMLUhKc6N6IQau1-AQkgwaR6sD_wXwRXtFQGu0VWig,37882
87
+ steerable_agent_runtime/history.py,sha256=Z1rn9NiItlBCJUr9G2IZmo-3XkhcQ0UWzU_C0FX4rqE,42541
79
88
  steerable_agent_runtime/hooks.py,sha256=vuIpTUlGDhwuZOF4kCIkXZkhm2BKYSzl3WIv7EF_dd0,22170
80
89
  steerable_agent_runtime/llm/__init__.py,sha256=HUr0hovIBbQTdWOyL5KkLNSwE_-tZD6QZ_et-TZKdaA,6215
81
90
  steerable_agent_runtime/llm/__pycache__/__init__.cpython-312.pyc,,
@@ -106,13 +115,14 @@ steerable_agent_runtime/model_info.py,sha256=yLiA8uWzPv7fHO7mUlgd0NlpbT1PBXKWX-u
106
115
  steerable_agent_runtime/model_resolve.py,sha256=vcKDvfLiBcTr99dj1FDsiKiA16o0IC6trm-yRFdlgQY,10332
107
116
  steerable_agent_runtime/native_bridge.py,sha256=Mu9CeTBHyjwU6Q2Yn-4sW1JGNW6H4dSVfYuuX4W212k,38582
108
117
  steerable_agent_runtime/observation_aging.py,sha256=4ajPHONvyh46LIRLTNqJGmJtSeDX6kJe1-1zhDuRaG8,8129
109
- steerable_agent_runtime/orchestration.py,sha256=WKIaTwclgvD30GsmAiyd5x3bWbUPLlBd53XHXGmofwo,18229
118
+ steerable_agent_runtime/orchestration.py,sha256=ONHk7OqKj-uyFQX6npzuNtirUTUeax_OCCXRDq_KEKw,39999
110
119
  steerable_agent_runtime/otel.py,sha256=idBWSnIbXowF7fzfFS9rkhPFZTf0e1SdSuNMJJw0aRg,14471
111
120
  steerable_agent_runtime/plugins.py,sha256=VCProcLnWzVxr7WRI5ndRbkdX-fXh1CTa-YCg-q60Xc,18444
112
- steerable_agent_runtime/pool.py,sha256=CigY9ADoGejDEu5k-iTf4repwLaLYsDXYba_y0W9MjQ,18546
121
+ steerable_agent_runtime/pool.py,sha256=luAViiyMB7EzFu0AzNsHK1yzKEoG_pmvH9J4btqpuO4,47600
113
122
  steerable_agent_runtime/pricing.py,sha256=EsciOP14OFnP5m0UIOF9uNV_DTCBE4OIEDSGCiZhGbM,3081
114
123
  steerable_agent_runtime/pseudo.py,sha256=K3bIpjacetNqfBmK30gzquS7pZ-xYXgluDE8mHSG_d0,24200
115
124
  steerable_agent_runtime/recording.py,sha256=y7iRHJD_NzlxpZvFvtqy94mYfCVagp9bJCK_BfJIp7w,16796
125
+ steerable_agent_runtime/registry.py,sha256=HVBaKKLeACStnDSjQQs3IDJtWmyNFgzlsKrthq8u7d8,13736
116
126
  steerable_agent_runtime/reminders.py,sha256=x5dZw96LipkcUUASDcVBykvozyBg362byJgai0yoCjA,12467
117
127
  steerable_agent_runtime/replay.py,sha256=RN6hD79OhmgeGKxSCuJ6rHkFUatf_rbqWAYPZnr8Te4,7571
118
128
  steerable_agent_runtime/resume.py,sha256=N-eoWgMDq2VrdIB3QUMRLQQuT7bZptJRHFkD_--gwHA,12839
@@ -120,17 +130,17 @@ steerable_agent_runtime/retry.py,sha256=ymHO2LTnYpGN0AU6gh906WR4lCDXIKfg47SPndDy
120
130
  steerable_agent_runtime/sandboxed.py,sha256=7b_piqmlkkgd-G584JOZ-sEQA_Gk1A_HNZwWJMrV660,7888
121
131
  steerable_agent_runtime/skills.py,sha256=_mR9lntMfm8juBvMoPWLReItedcvQJ9Mv6FxLkB1kRc,26810
122
132
  steerable_agent_runtime/spill.py,sha256=0IyqaKoYflBvfKox4ps-XFQoPfQGVmWywCmB1J_2Eck,4291
123
- steerable_agent_runtime/storage/__init__.py,sha256=_3AvkBKSbW7trAnUbFWzWHU7Lq7p9iZox5W3OCMUnL8,4800
133
+ steerable_agent_runtime/storage/__init__.py,sha256=a8UVian9fXR2JiEix1OLoob1C_ZlgTR6ycJrWzFPN6E,6567
124
134
  steerable_agent_runtime/storage/__pycache__/__init__.cpython-312.pyc,,
125
135
  steerable_agent_runtime/storage/__pycache__/in_memory.cpython-312.pyc,,
126
136
  steerable_agent_runtime/storage/__pycache__/sqlalchemy_store.cpython-312.pyc,,
127
137
  steerable_agent_runtime/storage/__pycache__/sqlite_store.cpython-312.pyc,,
128
138
  steerable_agent_runtime/storage/__pycache__/write_lease.cpython-312.pyc,,
129
- steerable_agent_runtime/storage/in_memory.py,sha256=0CHpwnBYVFKEyeMy11x31DHuEKmzz04tvsZo3An5Skw,8397
130
- steerable_agent_runtime/storage/sqlalchemy_store.py,sha256=obXN-6b8aHJ83ZTioTJtghVw8SNzrUEYNyZakocUlpE,18733
131
- steerable_agent_runtime/storage/sqlite_store.py,sha256=hwHmx4qAxhhFey97pg4-7b4pJYsS_2BJS_qDVA_DbBY,18710
139
+ steerable_agent_runtime/storage/in_memory.py,sha256=6MgDanAiVqpYagTeMcljhk62GCGZC0qaIz72Um0jyaI,11303
140
+ steerable_agent_runtime/storage/sqlalchemy_store.py,sha256=RagEhi1bLXS7_ET-UsN8SWvNr2NbnXF_2yNe6CXjYTE,24337
141
+ steerable_agent_runtime/storage/sqlite_store.py,sha256=qBepGs82s6nRiUO92DtleuGFDQQHiFpCNTyib9T3zaY,23324
132
142
  steerable_agent_runtime/storage/write_lease.py,sha256=Yzwe0ggIfVPlJaRwGUYr_dOHVBC9R4842ALLoc3iQO8,6115
133
- steerable_agent_runtime/subagent.py,sha256=MU47PeQvyZmse3-JkTtvqWK0aIAXSxS-FysTkNP84zc,23894
143
+ steerable_agent_runtime/subagent.py,sha256=LufKJazOEOf4ce6XJ9s_GY22uPY5w-dzbdiW5ECr1lg,31791
134
144
  steerable_agent_runtime/todo.py,sha256=59uuGm_a8kqAJ0vIS0IWg1GbEXL9OBBkPqUkv2-G2B0,13255
135
145
  steerable_agent_runtime/tokens.py,sha256=6WKyxf5dYP98UoLa6ONUbwQubUaLfw6yyr6z98zJuX0,6480
136
146
  steerable_agent_runtime/tool_presentation.py,sha256=k4K4Zva1by75l3HDpNUMSbVQeuvB7BYM3gI9Mtunw-g,6850
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steerable-agent-runtime-native
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Classifier: License :: Other/Proprietary License
5
5
  License-File: LICENSE
6
6
  Summary: PyO3 bindings for the Rust CoreLoop.
@@ -0,0 +1,9 @@
1
+ steerable_agent_runtime_native-1.0.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ steerable_agent_runtime_native-1.0.8.dist-info/METADATA,sha256=uPPeEGyUDo4qYyeuLqFQ0xVUw-U8aZBj2cxAi2rzJt8,215
3
+ steerable_agent_runtime_native-1.0.8.dist-info/RECORD,,
4
+ steerable_agent_runtime_native-1.0.8.dist-info/WHEEL,sha256=TzjyIyBUptJHnlQyOymQYLWjtXe7MGI0m3QvmcG7PpI,96
5
+ steerable_agent_runtime_native-1.0.8.dist-info/licenses/LICENSE,sha256=FdTjCPRsKOqLTVzMsyQrVakaw9XTm_r7Aj8DzRNwOs0,2977
6
+ steerable_agent_runtime_native-1.0.8.dist-info/sboms/steerable-agent-runtime.cyclonedx.json,sha256=nEVOoe_liPsvcC8D0I5-E5ayAW51JvCDb3-1p4FxVr4,166328
7
+ steerable_agent_runtime_native/__init__.py,sha256=L1E50J4M0mq0O0BYB-nWrmFJc8SGHBanKCG45bW2lwc,203
8
+ steerable_agent_runtime_native/__pycache__/__init__.cpython-312.pyc,,
9
+ steerable_agent_runtime_native/steerable_agent_runtime_native.pyd,sha256=_SlO3bVZRQdxTf08vZMSg10X9PP0d9qZtU6b6TUNvbc,1636352