agentic-runner 3.28.1__tar.gz → 3.29.0__tar.gz

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 (81) hide show
  1. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/PKG-INFO +2 -2
  2. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/pyproject.toml +1 -1
  3. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/__init__.py +1 -1
  4. agentic_runner-3.29.0/src/agentic_runner/organisation_name.py +30 -0
  5. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/service.py +15 -1
  6. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workstation.py +20 -5
  7. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/.gitignore +0 -0
  8. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/LICENSE +0 -0
  9. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/README.md +0 -0
  10. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/activities.py +0 -0
  11. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/attempts.py +0 -0
  12. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/auth_mode.py +0 -0
  13. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/build.py +0 -0
  14. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/callback.py +0 -0
  15. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/child_watcher.py +0 -0
  16. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/cli.py +0 -0
  17. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/cli_floor.py +0 -0
  18. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/config.py +0 -0
  19. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/credentials.py +0 -0
  20. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/egress.py +0 -0
  21. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/harness_self_test.py +0 -0
  22. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/heartbeat_link.py +0 -0
  23. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/hooks.py +0 -0
  24. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/host_store.py +0 -0
  25. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/__init__.py +0 -0
  26. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/git/__init__.py +0 -0
  27. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/git/contracts.py +0 -0
  28. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/git/evidence.py +0 -0
  29. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/git/fake_workspace.py +0 -0
  30. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/git/workspace.py +0 -0
  31. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/github/__init__.py +0 -0
  32. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/github/auth.py +0 -0
  33. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/github/fake_client.py +0 -0
  34. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/github/gh_client.py +0 -0
  35. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/oauth/__init__.py +0 -0
  36. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/integrations/oauth/fake_provider.py +0 -0
  37. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/launch.py +0 -0
  38. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/lifecycle.py +0 -0
  39. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/llm_contracts.py +0 -0
  40. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/llm_proxy.py +0 -0
  41. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/mcp.py +0 -0
  42. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/message_store.py +0 -0
  43. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/oauth_connectors.py +0 -0
  44. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/pool_key.py +0 -0
  45. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/private_state.py +0 -0
  46. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/py.typed +0 -0
  47. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/recipient_key_secret.py +0 -0
  48. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/registration.py +0 -0
  49. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/runner_limit.py +0 -0
  50. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/runtime/__init__.py +0 -0
  51. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/runtime/verifier_command.py +0 -0
  52. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/sealed_box.py +0 -0
  53. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/sign_in.py +0 -0
  54. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/skill.py +0 -0
  55. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/skills/agentic-runner-setup/SKILL.md +0 -0
  56. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/testing/__init__.py +0 -0
  57. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/testing/__main__.py +0 -0
  58. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/testing/control_plane.py +0 -0
  59. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/testing/plugin.py +0 -0
  60. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/testing/test_conformance.py +0 -0
  61. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/testing/workflow.py +0 -0
  62. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/tiny_http.py +0 -0
  63. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/triage_activities.py +0 -0
  64. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/usage_windows.py +0 -0
  65. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/user_sources.py +0 -0
  66. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/__init__.py +0 -0
  67. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/_runtime_support.py +0 -0
  68. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/acp_runtime.py +0 -0
  69. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/agent_runtime.py +0 -0
  70. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/claude_runtime.py +0 -0
  71. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/claude_sign_in.py +0 -0
  72. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/codex_runtime.py +0 -0
  73. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/command_policy.py +0 -0
  74. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/contract_isolation.py +0 -0
  75. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/fastapi_client.py +0 -0
  76. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/harness_logins.py +0 -0
  77. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/harness_outcome.py +0 -0
  78. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/harness_usage.py +0 -0
  79. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/mcp_config.py +0 -0
  80. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/settings.py +0 -0
  81. {agentic_runner-3.28.1 → agentic_runner-3.29.0}/src/agentic_runner/workers/skills.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentic-runner
3
- Version: 3.28.1
3
+ Version: 3.29.0
4
4
  Summary: The Agentic OS Runner: an activity-only Temporal executor for workspaces, Agent Runtimes and verb seams
5
5
  License-Expression: AGPL-3.0-only
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.12
8
- Requires-Dist: agentic-runner-contracts==3.28.1
8
+ Requires-Dist: agentic-runner-contracts==3.29.0
9
9
  Requires-Dist: cryptography<51,>=50
10
10
  Requires-Dist: httpx<1.0,>=0.27
11
11
  Requires-Dist: pydantic-settings<3.0,>=2.0
@@ -10,7 +10,7 @@ dependencies = [
10
10
  # Exactly this release's contracts: the two ship as one version, and an unpinned
11
11
  # requirement let `uv tool upgrade` keep an older contracts wheel the Runner cannot
12
12
  # import from (QTS-1473). `scripts/set-version.py` moves it with the version.
13
- "agentic-runner-contracts==3.28.1",
13
+ "agentic-runner-contracts==3.29.0",
14
14
  # Imported directly by `registration.py` (the Ed25519 identity that signs every
15
15
  # heartbeat); already present transitively through pyjwt[crypto], declared because
16
16
  # we import it.
@@ -7,6 +7,6 @@ stay on the platform; this package imports none of them, and a CI partition test
7
7
  (``tests/test_package_partition.py``) fails the build if that changes.
8
8
  """
9
9
 
10
- __version__ = "3.28.1"
10
+ __version__ = "3.29.0"
11
11
 
12
12
  __all__ = ["__version__"]
@@ -0,0 +1,30 @@
1
+ """The Organisation this Runner serves, by the name the last heartbeat ack gave (QTS-1909).
2
+
3
+ ``agentic-runner list`` is a separate process and reads it from this file, which the
4
+ running Runner rewrites whenever an ack changes it. Absent while the control plane names
5
+ no Organisation -- one below contracts 3.29 -- so ``list`` shows the id instead.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from pathlib import Path
11
+ from typing import Final
12
+
13
+ from agentic_runner.private_state import private_read, private_write
14
+
15
+ __all__ = ["ORGANISATION_NAME_FILENAME", "load_organisation_name", "save_organisation_name"]
16
+
17
+ ORGANISATION_NAME_FILENAME: Final[str] = "organisation-name"
18
+
19
+
20
+ def save_organisation_name(state_dir: Path, name: str | None) -> None:
21
+ path = state_dir / ORGANISATION_NAME_FILENAME
22
+ if name is None:
23
+ path.unlink(missing_ok=True)
24
+ else:
25
+ private_write(path, name.encode("utf-8"))
26
+
27
+
28
+ def load_organisation_name(state_dir: Path) -> str | None:
29
+ raw = private_read(state_dir / ORGANISATION_NAME_FILENAME)
30
+ return None if raw is None else raw.decode("utf-8", errors="replace")
@@ -33,7 +33,7 @@ from collections.abc import AsyncIterator, Awaitable, Callable, Mapping, Sequenc
33
33
  from dataclasses import dataclass, field
34
34
  from datetime import UTC, datetime, timedelta
35
35
  from pathlib import Path
36
- from typing import Any, Final, Protocol
36
+ from typing import Any, Final, Literal, Protocol
37
37
  from uuid import UUID
38
38
 
39
39
  import httpx
@@ -85,6 +85,7 @@ from agentic_runner.llm_proxy import (
85
85
  from agentic_runner.mcp import ToolServerHealthLog
86
86
  from agentic_runner.message_store import MESSAGES_DIR, MessageStore, TemporalWorkflowSignaller
87
87
  from agentic_runner.oauth_connectors import OAuthConnectors
88
+ from agentic_runner.organisation_name import save_organisation_name
88
89
  from agentic_runner.pool_key import (
89
90
  POOL_KEY_ENV,
90
91
  POOL_KEY_FILENAME,
@@ -852,6 +853,9 @@ class ControlPlaneStream:
852
853
  # QTS-1773: the control plane's contracts version, from its ack; None until an ack from
853
854
  # one on 3.27 or later, the first to send it and to parse `RunnerInstall.name`.
854
855
  _control_plane_contracts: str | None = None
856
+ # QTS-1909: the name in the copy `list` reads, None while there is none. "unwritten"
857
+ # until this process first writes it, so the first ack replaces what a previous one left.
858
+ _organisation_name: str | None | Literal["unwritten"] = "unwritten"
855
859
  _last_seen: tuple[float, datetime] | None = None
856
860
 
857
861
  def _observe_sleep(self, now: datetime) -> None:
@@ -1081,6 +1085,7 @@ class ControlPlaneStream:
1081
1085
  self._take_pool(ack.pool)
1082
1086
  if ack.contracts_version is not None:
1083
1087
  self._control_plane_contracts = ack.contracts_version
1088
+ self._take_organisation_name(ack.organisation_name)
1084
1089
  await self._sync_llm_slots()
1085
1090
  if ack.runner_token is not None:
1086
1091
  self.runner_token = ack.runner_token
@@ -1139,6 +1144,15 @@ class ControlPlaneStream:
1139
1144
  if self.state_dir is not None:
1140
1145
  save_llm_contracts(self.state_dir, terms)
1141
1146
 
1147
+ def _take_organisation_name(self, name: str | None) -> None:
1148
+ """Keep the copy ``list`` reads when the ack's name changes. Unlike the Contract
1149
+ terms, an ack without one clears it: only the name, never the id, can go stale."""
1150
+
1151
+ if self.state_dir is None or name == self._organisation_name:
1152
+ return
1153
+ save_organisation_name(self.state_dir, name)
1154
+ self._organisation_name = name
1155
+
1142
1156
  def _take_pool(self, pool: PoolTerms | None) -> None:
1143
1157
  """Keep the ack's pool. An ack without one (a personal Runner, or a control plane
1144
1158
  below 3.26) leaves what is held."""
@@ -55,6 +55,7 @@ from agentic_runner.config import CONFIG_FILE_ENV
55
55
  from agentic_runner.host_store import open_workstation_store
56
56
  from agentic_runner.lifecycle import LifecycleOutbox
57
57
  from agentic_runner.llm_contracts import load_llm_contracts
58
+ from agentic_runner.organisation_name import load_organisation_name
58
59
  from agentic_runner.pool_key import parse_pool_key, save_pool_key
59
60
  from agentic_runner.private_state import UnsafeStateError
60
61
  from agentic_runner.registration import load_state
@@ -64,6 +65,7 @@ from agentic_runner_contracts.public_metadata import NAMESPACE_PREFIX
64
65
  from agentic_runner_contracts.runner_registration import (
65
66
  RUNNER_NAME_PATTERN,
66
67
  CliVersion,
68
+ ContractLlmTerms,
67
69
  EgressPosture,
68
70
  HostAttestation,
69
71
  InstallChannel,
@@ -670,9 +672,9 @@ _LIST_HEADER: Final = (
670
672
  def list_lines(root: Path) -> list[str]:
671
673
  """``list``: one row per Runner installed here (QTS-1774).
672
674
 
673
- Ids, not names: the Runner is told neither the Organisation's nor the Contract's name.
674
- Eight characters, as the console shows a Runner's id beside its name (Spec: Runners
675
- rev 7).
675
+ The Organisation's and the Contract's names once an ack from a control plane on 3.29
676
+ named them (QTS-1909); before that, the first eight characters of their ids, as the
677
+ console shows a Runner's id beside its name (Spec: Runners rev 7).
676
678
  """
677
679
 
678
680
  names = installed_names(root)
@@ -705,17 +707,21 @@ def _list_row_or_reason(paths: RunnerPaths) -> tuple[str, str, str, str, str, st
705
707
  def _list_row(paths: RunnerPaths) -> tuple[str, str, str, str, str, str]:
706
708
  state = load_state(paths.state_dir)
707
709
  contracts = load_llm_contracts(paths.state_dir)
710
+ organisation_name = _printable(load_organisation_name(paths.state_dir))
708
711
  try:
709
712
  version = paths.started_version.read_text(encoding="utf-8").strip() or "-"
710
713
  except OSError:
711
714
  version = "-"
712
715
  return (
713
716
  paths.name,
714
- state.temporal_namespace.removeprefix(NAMESPACE_PREFIX)[:8] if state else "-",
717
+ (
718
+ organisation_name
719
+ or (state.temporal_namespace.removeprefix(NAMESPACE_PREFIX)[:8] if state else "-")
720
+ ),
715
721
  (
716
722
  "-"
717
723
  if not contracts
718
- else str(contracts[0].contract_id)[:8]
724
+ else _contract_label(contracts[0])
719
725
  if len(contracts) == 1
720
726
  else f"{len(contracts)} Contracts"
721
727
  ),
@@ -725,6 +731,15 @@ def _list_row(paths: RunnerPaths) -> tuple[str, str, str, str, str, str]:
725
731
  )
726
732
 
727
733
 
734
+ def _contract_label(terms: ContractLlmTerms) -> str:
735
+ return _printable(terms.contract_name) or str(terms.contract_id)[:8]
736
+
737
+
738
+ def _printable(name: str | None) -> str:
739
+ # A name someone typed in the console: an escape sequence in it would reach the terminal.
740
+ return "".join(character for character in name or "" if character.isprintable())
741
+
742
+
728
743
  def next_step_lines(host_party: str) -> list[str]:
729
744
  """Where to go once the Runner is live (QTS-1314): the dogfood install ended at
730
745
  ``started`` and left the person with no idea what the console wanted next.
File without changes