agentic-runner 3.18.3__tar.gz → 3.20.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.
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/PKG-INFO +2 -2
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/pyproject.toml +1 -1
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/__init__.py +1 -1
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/activities.py +41 -12
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/credentials.py +49 -4
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/heartbeat_link.py +14 -1
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/service.py +34 -3
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/.gitignore +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/LICENSE +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/README.md +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/attempts.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/auth_mode.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/build.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/callback.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/child_watcher.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/cli.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/cli_floor.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/config.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/device_login_activities.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/egress.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/harness_self_test.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/hooks.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/host_store.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/__init__.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/__init__.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/contracts.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/evidence.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/fake_workspace.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/workspace.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/github/__init__.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/github/auth.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/github/fake_client.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/github/gh_client.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/oauth/__init__.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/oauth/fake_provider.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/launch.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/lifecycle.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/llm_proxy.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/mcp.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/message_store.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/oauth_connectors.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/private_state.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/py.typed +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/recipient_key_secret.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/registration.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/runtime/__init__.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/runtime/verifier_command.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/sealed_box.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/skill.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/skills/agentic-runner-setup/SKILL.md +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/testing/__init__.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/testing/__main__.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/testing/control_plane.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/testing/plugin.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/testing/test_conformance.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/testing/workflow.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/tiny_http.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/triage_activities.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/usage_windows.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/user_sources.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/__init__.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/_runtime_support.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/acp_runtime.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/agent_runtime.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/claude_runtime.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/claude_sign_in.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/codex_runtime.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/command_policy.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/contract_device_login.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/contract_isolation.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/fastapi_client.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/harness_outcome.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/harness_usage.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/mcp_config.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/settings.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/skills.py +0 -0
- {agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workstation.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentic-runner
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.20.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.
|
|
8
|
+
Requires-Dist: agentic-runner-contracts==3.20.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.
|
|
13
|
+
"agentic-runner-contracts==3.20.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.
|
|
@@ -267,6 +267,7 @@ from agentic_runner_contracts.grants.seam import VerbDecision, decide_verb
|
|
|
267
267
|
from agentic_runner_contracts.questions import WORK_ASK_VERB
|
|
268
268
|
from agentic_runner_contracts.redaction import redact_secret_like_text
|
|
269
269
|
from agentic_runner_contracts.routing import (
|
|
270
|
+
DirectiveRouting,
|
|
270
271
|
RoutingRefusedError,
|
|
271
272
|
RunnerRoutingIdentity,
|
|
272
273
|
assert_routed,
|
|
@@ -1709,8 +1710,9 @@ class RunnerRalphActivities:
|
|
|
1709
1710
|
self._workspace_root = workspace_root
|
|
1710
1711
|
self._contract_isolation = contract_isolation
|
|
1711
1712
|
# What this process is, as the control plane registered it (PRD issue 42): its
|
|
1712
|
-
# Runner id, its host party and its config-declared Tags
|
|
1713
|
-
#
|
|
1713
|
+
# Runner id, its host party and its config-declared Tags, which the last heartbeat
|
|
1714
|
+
# ack's Tags replace (`_current_routing_identity`). Every activity payload is
|
|
1715
|
+
# checked against it before the body runs, so a stolen or misrouted task costs
|
|
1714
1716
|
# no verb. ``None`` in a process that never registered -- it polls no
|
|
1715
1717
|
# ``runner.{runner_id}`` queue, so nothing routes to it and there is nothing to
|
|
1716
1718
|
# assert against; the fail-closed check is on every Runner the router can pick.
|
|
@@ -1790,10 +1792,11 @@ class RunnerRalphActivities:
|
|
|
1790
1792
|
poller into a visible intra-Organisation incident rather than silence (17 A11).
|
|
1791
1793
|
"""
|
|
1792
1794
|
|
|
1793
|
-
|
|
1795
|
+
identity = self._current_routing_identity()
|
|
1796
|
+
if identity is not None:
|
|
1794
1797
|
routing = getattr(request, "routing", None)
|
|
1795
1798
|
try:
|
|
1796
|
-
assert_routed(routing,
|
|
1799
|
+
assert_routed(routing, identity)
|
|
1797
1800
|
except RoutingRefusedError as refusal:
|
|
1798
1801
|
work_record_id = getattr(request, "work_record_id", "")
|
|
1799
1802
|
if not work_record_id:
|
|
@@ -1803,11 +1806,11 @@ class RunnerRalphActivities:
|
|
|
1803
1806
|
self._fastapi_client,
|
|
1804
1807
|
str(work_record_id),
|
|
1805
1808
|
source=_ROUTING_EVIDENCE_SOURCE,
|
|
1806
|
-
actor=f"runner:{
|
|
1809
|
+
actor=f"runner:{identity.runner_id}",
|
|
1807
1810
|
payload={
|
|
1808
1811
|
"event": "directive.routing_refused",
|
|
1809
1812
|
"reason": refusal.reason,
|
|
1810
|
-
"runner_id":
|
|
1813
|
+
"runner_id": identity.runner_id,
|
|
1811
1814
|
"routed_runner_id": None if routing is None else routing.runner_id,
|
|
1812
1815
|
"detail": str(refusal),
|
|
1813
1816
|
},
|
|
@@ -1817,6 +1820,19 @@ class RunnerRalphActivities:
|
|
|
1817
1820
|
self._token_source, self._fastapi_client, request, actor=self._actor()
|
|
1818
1821
|
)
|
|
1819
1822
|
|
|
1823
|
+
def _current_routing_identity(self) -> RunnerRoutingIdentity | None:
|
|
1824
|
+
"""The registered identity, with the Tags the last heartbeat ack carried.
|
|
1825
|
+
|
|
1826
|
+
The console edits a Runner's Tags after registration and the control plane routes
|
|
1827
|
+
on the edit at once (ADR-0022 §13); checking the bootstrap set instead would
|
|
1828
|
+
refuse work routed on an added Tag on every retry.
|
|
1829
|
+
"""
|
|
1830
|
+
|
|
1831
|
+
acked = self._heartbeat_link.tags if self._heartbeat_link is not None else None
|
|
1832
|
+
if self._routing_identity is None or acked is None:
|
|
1833
|
+
return self._routing_identity
|
|
1834
|
+
return replace(self._routing_identity, tags=acked)
|
|
1835
|
+
|
|
1820
1836
|
def _actor(self) -> str:
|
|
1821
1837
|
return (
|
|
1822
1838
|
f"runner:{self._routing_identity.runner_id}"
|
|
@@ -2028,6 +2044,7 @@ class RunnerRalphActivities:
|
|
|
2028
2044
|
state=runtime_state,
|
|
2029
2045
|
workspace_path=workspace_path,
|
|
2030
2046
|
directive_number=request.directive_number,
|
|
2047
|
+
routing=request.routing,
|
|
2031
2048
|
sandbox=self._contract_sandbox(runtime_state),
|
|
2032
2049
|
mcp_plan=mcp_plan,
|
|
2033
2050
|
asked=asked,
|
|
@@ -2595,6 +2612,7 @@ class RunnerRalphActivities:
|
|
|
2595
2612
|
mcp_plan: McpPlan | None = None,
|
|
2596
2613
|
asked: list[QuestionAsked] | None = None,
|
|
2597
2614
|
bound: list[ProductBinding] | None = None,
|
|
2615
|
+
routing: DirectiveRouting | None = None,
|
|
2598
2616
|
) -> AsyncIterator[_DirectiveAttempt]:
|
|
2599
2617
|
"""Open one attempt's hook lifecycle and its callback socket (PRD issue 45).
|
|
2600
2618
|
|
|
@@ -2623,7 +2641,9 @@ class RunnerRalphActivities:
|
|
|
2623
2641
|
)
|
|
2624
2642
|
|
|
2625
2643
|
await self._refuse_skill_digest_mismatch(work_record_id, state)
|
|
2626
|
-
credentials = await self._resolve_credentials(
|
|
2644
|
+
credentials = await self._resolve_credentials(
|
|
2645
|
+
work_record_id, state, funding_party=routing.funding_party if routing else None
|
|
2646
|
+
)
|
|
2627
2647
|
if credentials is not None:
|
|
2628
2648
|
# Names only, at the moment they resolved (22 A1's Evidence): a support read
|
|
2629
2649
|
# of "which credentials did this Directive have" must not be answerable by
|
|
@@ -2969,7 +2989,11 @@ class RunnerRalphActivities:
|
|
|
2969
2989
|
return (tuple(entries) if state.mcp_servers else None), allow_list
|
|
2970
2990
|
|
|
2971
2991
|
async def _resolve_credentials(
|
|
2972
|
-
self,
|
|
2992
|
+
self,
|
|
2993
|
+
work_record_id: str,
|
|
2994
|
+
state: _RuntimeContextState,
|
|
2995
|
+
*,
|
|
2996
|
+
funding_party: str | None = None,
|
|
2973
2997
|
) -> DirectiveCredentials | None:
|
|
2974
2998
|
"""Resolve this Contract's Credential References, or fail the Directive closed.
|
|
2975
2999
|
|
|
@@ -2985,7 +3009,9 @@ class RunnerRalphActivities:
|
|
|
2985
3009
|
resolver = self._credentials or CredentialResolver(store=EmptyCredentialStore())
|
|
2986
3010
|
try:
|
|
2987
3011
|
return resolver.resolve(
|
|
2988
|
-
contract_id=state.contract_id,
|
|
3012
|
+
contract_id=state.contract_id,
|
|
3013
|
+
manifest=state.credential_references,
|
|
3014
|
+
funding_party=funding_party,
|
|
2989
3015
|
)
|
|
2990
3016
|
except UnresolvableCredentialReferenceError as error:
|
|
2991
3017
|
await self._fastapi_client.append_evidence(
|
|
@@ -3876,10 +3902,11 @@ class RunnerRalphActivities:
|
|
|
3876
3902
|
"remedy": "work.open",
|
|
3877
3903
|
},
|
|
3878
3904
|
)
|
|
3879
|
-
|
|
3905
|
+
identity = self._current_routing_identity()
|
|
3906
|
+
if state.repository or identity is None:
|
|
3880
3907
|
return None
|
|
3881
3908
|
selector = snapshot.runner_selector_of(product_id)
|
|
3882
|
-
if selector is not None and selector_satisfied(selector,
|
|
3909
|
+
if selector is not None and selector_satisfied(selector, identity.tags):
|
|
3883
3910
|
return None
|
|
3884
3911
|
return (
|
|
3885
3912
|
f"this Runner's tags do not satisfy the Runner selector of Product {product_id}, "
|
|
@@ -3887,7 +3914,7 @@ class RunnerRalphActivities:
|
|
|
3887
3914
|
{
|
|
3888
3915
|
"event": "directive.repository_refused",
|
|
3889
3916
|
"product_id": product_id,
|
|
3890
|
-
"runner_id": str(
|
|
3917
|
+
"runner_id": str(identity.runner_id),
|
|
3891
3918
|
"selector": [requirement.as_payload() for requirement in selector or ()],
|
|
3892
3919
|
},
|
|
3893
3920
|
)
|
|
@@ -5055,6 +5082,7 @@ class RunnerRalphActivities:
|
|
|
5055
5082
|
state=state,
|
|
5056
5083
|
workspace_path=workspace,
|
|
5057
5084
|
directive_number=request.directive_number,
|
|
5085
|
+
routing=request.routing,
|
|
5058
5086
|
sandbox=self._contract_sandbox(state),
|
|
5059
5087
|
reserve_max_tokens=request.reserve_max_tokens or None,
|
|
5060
5088
|
mcp_plan=learning_plan,
|
|
@@ -5301,6 +5329,7 @@ class RunnerRalphActivities:
|
|
|
5301
5329
|
state=state,
|
|
5302
5330
|
workspace_path=state.workspace_path,
|
|
5303
5331
|
directive_number=request.directive_number,
|
|
5332
|
+
routing=request.routing,
|
|
5304
5333
|
sandbox=self._contract_sandbox(state),
|
|
5305
5334
|
mcp_plan=mcp_plan,
|
|
5306
5335
|
asked=asked,
|
|
@@ -204,6 +204,13 @@ class CredentialResolver:
|
|
|
204
204
|
in memory only. It is consulted before the host store because a funder who delivered a
|
|
205
205
|
value is stating it is theirs to state; the host's own install is the fallback, which
|
|
206
206
|
is exactly the hand-over default.
|
|
207
|
+
|
|
208
|
+
The fallback is a loan of the host's own values, so it is made only to work the host
|
|
209
|
+
pays for (ADR-0022 §36): an Organisation or Account Runner lends its store to a
|
|
210
|
+
Contract whose ``funding_party`` is its own ``host_party``, and a contractor-funded
|
|
211
|
+
Contract in that pool brings sealed values or finds the reference unusable. A
|
|
212
|
+
personal Runner lends to every Contract it runs, because it runs only its person's
|
|
213
|
+
own (§2, §42). A blank ``host_party`` -- a Runner not yet registered -- lends nothing.
|
|
207
214
|
"""
|
|
208
215
|
|
|
209
216
|
def __init__(
|
|
@@ -211,9 +218,14 @@ class CredentialResolver:
|
|
|
211
218
|
*,
|
|
212
219
|
store: HostCredentialStore,
|
|
213
220
|
delivered: Mapping[tuple[str, str], str] | None = None,
|
|
221
|
+
host_party: str | None = None,
|
|
214
222
|
) -> None:
|
|
215
223
|
self._store = store
|
|
216
224
|
self._delivered = dict(delivered or {})
|
|
225
|
+
self._host_party = host_party
|
|
226
|
+
# The funding party the last ack named per Contract, for the readers that have no
|
|
227
|
+
# Directive to carry one: the heartbeat's report and an OAuth Connector's secret.
|
|
228
|
+
self._funding: dict[str, str] = {}
|
|
217
229
|
|
|
218
230
|
@property
|
|
219
231
|
def host_store(self) -> HostCredentialStore:
|
|
@@ -231,22 +243,55 @@ class CredentialResolver:
|
|
|
231
243
|
|
|
232
244
|
self._delivered.pop((str(contract_id), slot), None)
|
|
233
245
|
|
|
234
|
-
def
|
|
246
|
+
def fund(self, funding: Mapping[str, str]) -> None:
|
|
247
|
+
"""Replace the per-Contract funding parties with the last ack's (ADR-0022 §7)."""
|
|
248
|
+
|
|
249
|
+
self._funding = dict(funding)
|
|
250
|
+
|
|
251
|
+
def resolve(
|
|
252
|
+
self,
|
|
253
|
+
*,
|
|
254
|
+
contract_id: str | None,
|
|
255
|
+
manifest: Iterable[str],
|
|
256
|
+
funding_party: str | None = None,
|
|
257
|
+
) -> DirectiveCredentials:
|
|
235
258
|
"""Every reference the Contract declares, or the first failure, named.
|
|
236
259
|
|
|
260
|
+
``funding_party`` is the Directive's own (``DirectiveRouting.funding_party``); a
|
|
261
|
+
reader without a Directive leaves it out and the last ack's word for the Contract
|
|
262
|
+
stands in, and with neither the host store is not lent.
|
|
263
|
+
|
|
237
264
|
Fails on the *first* unresolvable reference rather than collecting them: a
|
|
238
265
|
Directive that cannot have one of its credentials is not going to run, and a
|
|
239
266
|
partial resolution left lying around is a value held for no reason.
|
|
240
267
|
"""
|
|
241
268
|
|
|
269
|
+
lends = self._lends_host_store(contract_id, funding_party)
|
|
242
270
|
values: dict[str, str] = {}
|
|
243
271
|
for reference in manifest:
|
|
244
|
-
value = self.
|
|
245
|
-
if value is None:
|
|
246
|
-
value = self._store.get(reference)
|
|
272
|
+
value = self._value(contract_id, reference, lends=lends)
|
|
247
273
|
if value is None:
|
|
248
274
|
raise UnresolvableCredentialReferenceError(
|
|
249
275
|
reference, contract_id=contract_id, reason="not_installed"
|
|
250
276
|
)
|
|
251
277
|
values[reference] = value
|
|
252
278
|
return DirectiveCredentials(contract_id=contract_id, _values=values)
|
|
279
|
+
|
|
280
|
+
def usable(self, contract_id: str, reference: str) -> bool:
|
|
281
|
+
"""Whether a Directive of this Contract would resolve ``reference`` now (§7)."""
|
|
282
|
+
|
|
283
|
+
lends = self._lends_host_store(contract_id, None)
|
|
284
|
+
return self._value(contract_id, reference, lends=lends) is not None
|
|
285
|
+
|
|
286
|
+
def _value(self, contract_id: str | None, reference: str, *, lends: bool) -> str | None:
|
|
287
|
+
value = self._delivered.get((str(contract_id), reference))
|
|
288
|
+
if value is None and lends:
|
|
289
|
+
value = self._store.get(reference)
|
|
290
|
+
return value
|
|
291
|
+
|
|
292
|
+
def _lends_host_store(self, contract_id: str | None, funding_party: str | None) -> bool:
|
|
293
|
+
if self._host_party == "user":
|
|
294
|
+
return True
|
|
295
|
+
if funding_party is None:
|
|
296
|
+
funding_party = self._funding.get(str(contract_id), "")
|
|
297
|
+
return bool(self._host_party) and funding_party == self._host_party
|
|
@@ -121,6 +121,7 @@ class HeartbeatLink:
|
|
|
121
121
|
# finished is never read again, while one under a running Directive is read at
|
|
122
122
|
# every verb -- and `max_concurrent_directives` is itself bounded by this number.
|
|
123
123
|
self._held: OrderedDict[str, _Held] = OrderedDict()
|
|
124
|
+
self._tags: dict[str, str] | None = None
|
|
124
125
|
self._last_ack: float | None = None
|
|
125
126
|
self._seen_monotonic, self._seen_wall = self._clock()
|
|
126
127
|
self._woke = False
|
|
@@ -147,6 +148,16 @@ class HeartbeatLink:
|
|
|
147
148
|
self._held.move_to_end(agent_id)
|
|
148
149
|
return held
|
|
149
150
|
|
|
151
|
+
@property
|
|
152
|
+
def tags(self) -> dict[str, str] | None:
|
|
153
|
+
"""This Runner's Tags as the last ack carried them (ADR-0022 §13).
|
|
154
|
+
|
|
155
|
+
``None`` until an ack carries them, from a control plane below contracts 3.20 or
|
|
156
|
+
before the first beat: routing then checks the Tags this Runner bootstrapped with.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
return None if self._tags is None else dict(self._tags)
|
|
160
|
+
|
|
150
161
|
def applied(self) -> list[AppliedSnapshot]:
|
|
151
162
|
return [
|
|
152
163
|
AppliedSnapshot(agent_id=UUID(agent_id), version=held.version)
|
|
@@ -154,13 +165,15 @@ class HeartbeatLink:
|
|
|
154
165
|
]
|
|
155
166
|
|
|
156
167
|
def apply(self, ack: HeartbeatAck) -> None:
|
|
157
|
-
"""Apply one ack's pushes: snapshots per Agent, ceilings per Contract.
|
|
168
|
+
"""Apply one ack's pushes: snapshots per Agent, ceilings per Contract, the Tags.
|
|
158
169
|
|
|
159
170
|
Replacement, never a merge. A narrowed Grant that merged into what it narrowed
|
|
160
171
|
would leave the wider entry standing, which is the one mistake this whole layer
|
|
161
172
|
exists to prevent.
|
|
162
173
|
"""
|
|
163
174
|
|
|
175
|
+
if ack.tags is not None:
|
|
176
|
+
self._tags = dict(ack.tags)
|
|
164
177
|
for push in ack.grant_pushes:
|
|
165
178
|
agent_id = str(push.agent_id)
|
|
166
179
|
self._held[agent_id] = _Held(
|
|
@@ -127,6 +127,8 @@ from agentic_runner_contracts.runner_registration import (
|
|
|
127
127
|
RECENT_OUTCOMES_MAX,
|
|
128
128
|
AcpBridgeVersion,
|
|
129
129
|
CliVersion,
|
|
130
|
+
CredentialManifest,
|
|
131
|
+
CredentialValidity,
|
|
130
132
|
DirectiveOutcome,
|
|
131
133
|
EgressPosture,
|
|
132
134
|
HarnessVersion,
|
|
@@ -379,7 +381,10 @@ def build_hook_runner(config: RunnerConfig) -> HookRunner:
|
|
|
379
381
|
|
|
380
382
|
|
|
381
383
|
def build_credential_resolver(
|
|
382
|
-
config: RunnerConfig,
|
|
384
|
+
config: RunnerConfig,
|
|
385
|
+
*,
|
|
386
|
+
host_store: HostCredentialStore | None = None,
|
|
387
|
+
host_party: str | None = None,
|
|
383
388
|
) -> CredentialResolver:
|
|
384
389
|
"""The host store a Directive resolves its Credential References from (22 A1).
|
|
385
390
|
|
|
@@ -393,7 +398,7 @@ def build_credential_resolver(
|
|
|
393
398
|
if config.credential_store is not None
|
|
394
399
|
else EmptyCredentialStore()
|
|
395
400
|
)
|
|
396
|
-
return CredentialResolver(store=store)
|
|
401
|
+
return CredentialResolver(store=store, host_party=host_party)
|
|
397
402
|
|
|
398
403
|
|
|
399
404
|
def build_socket_dir(config: RunnerConfig) -> Path:
|
|
@@ -731,6 +736,8 @@ class ControlPlaneStream:
|
|
|
731
736
|
# Console-v2 issue 30: the OAuth Connectors whose code, tokens and verifier stay here.
|
|
732
737
|
oauth: OAuthConnectors | None = None
|
|
733
738
|
_delivered: set[tuple[str, str]] = field(default_factory=set)
|
|
739
|
+
# ADR-0022 §7: the Contracts the last ack asked this Runner to report references for.
|
|
740
|
+
_manifests: list[CredentialManifest] = field(default_factory=list)
|
|
734
741
|
_offered_to_proxy: dict[tuple[str, str], str] = field(default_factory=dict)
|
|
735
742
|
_last_seen: tuple[float, datetime] | None = None
|
|
736
743
|
|
|
@@ -802,6 +809,23 @@ class ControlPlaneStream:
|
|
|
802
809
|
),
|
|
803
810
|
)
|
|
804
811
|
|
|
812
|
+
def _credential_report(self) -> list[CredentialValidity]:
|
|
813
|
+
"""Per Contract the last ack named, whether each reference would resolve (§7).
|
|
814
|
+
|
|
815
|
+
Asked of the same resolver a Directive resolves through, so the report and the
|
|
816
|
+
Directive cannot disagree on what a funder sealed or what the host lends (§36).
|
|
817
|
+
"""
|
|
818
|
+
|
|
819
|
+
return [
|
|
820
|
+
CredentialValidity(
|
|
821
|
+
contract_id=manifest.contract_id,
|
|
822
|
+
reference=reference,
|
|
823
|
+
valid=self.credentials.usable(str(manifest.contract_id), reference),
|
|
824
|
+
)
|
|
825
|
+
for manifest in self._manifests
|
|
826
|
+
for reference in manifest.references
|
|
827
|
+
]
|
|
828
|
+
|
|
805
829
|
async def directive_token(self, directive_id: str) -> str:
|
|
806
830
|
"""One activity execution's control-plane token, by Directive id (PRD issue 63)."""
|
|
807
831
|
|
|
@@ -821,6 +845,7 @@ class ControlPlaneStream:
|
|
|
821
845
|
max_concurrent_directives=self.state.max_concurrent_directives,
|
|
822
846
|
current_load=self.load.in_flight,
|
|
823
847
|
recent_outcomes=list(self.load.outcomes),
|
|
848
|
+
credentials=self._credential_report(),
|
|
824
849
|
slots=self.proxy.slots.statuses(),
|
|
825
850
|
usage=self.proxy.outbox.pending(),
|
|
826
851
|
egress_posture=self.egress_posture,
|
|
@@ -865,6 +890,10 @@ class ControlPlaneStream:
|
|
|
865
890
|
refused.slot,
|
|
866
891
|
)
|
|
867
892
|
self._sync_delivered()
|
|
893
|
+
self._manifests = list(ack.credential_manifests)
|
|
894
|
+
self.credentials.fund(
|
|
895
|
+
{str(manifest.contract_id): manifest.funding_party for manifest in self._manifests}
|
|
896
|
+
)
|
|
868
897
|
await self._sync_llm_slots()
|
|
869
898
|
if ack.runner_token is not None:
|
|
870
899
|
self.runner_token = ack.runner_token
|
|
@@ -1261,7 +1290,9 @@ async def _serve_registered(
|
|
|
1261
1290
|
) -> int:
|
|
1262
1291
|
load = _LoadInterceptor()
|
|
1263
1292
|
proxy = LlmProxy(slots=SlotStore(), ceilings=CeilingStore(), outbox=UsageOutbox())
|
|
1264
|
-
credentials = build_credential_resolver(
|
|
1293
|
+
credentials = build_credential_resolver(
|
|
1294
|
+
config, host_store=host_store, host_party=state.host_party
|
|
1295
|
+
)
|
|
1265
1296
|
isolation = build_contract_isolation(settings, can_separate_uids=can_change_uid)
|
|
1266
1297
|
runtimes = build_agent_runtimes(settings, attestation.clis if attestation is not None else [])
|
|
1267
1298
|
in_flight = DirectivesInFlight()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/device_login_activities.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/__init__.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/contracts.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/evidence.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/git/workspace.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/github/__init__.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/github/auth.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/github/gh_client.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/integrations/oauth/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/runtime/verifier_command.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/testing/test_conformance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/_runtime_support.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/claude_runtime.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/claude_sign_in.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/command_policy.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/contract_device_login.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/contract_isolation.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/fastapi_client.py
RENAMED
|
File without changes
|
{agentic_runner-3.18.3 → agentic_runner-3.20.0}/src/agentic_runner/workers/harness_outcome.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|