agentenv-framework-protocol 0.1.281__tar.gz → 0.1.283__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 (38) hide show
  1. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/PKG-INFO +46 -18
  2. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/README.md +43 -17
  3. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/THIRD_PARTY_NOTICES.md +7 -0
  4. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/pyproject.toml +3 -1
  5. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/a2a_agent/__init__.py +5 -0
  6. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/a2a_agent/framework.py +14 -0
  7. agentenv_framework_protocol-0.1.283/src/agentenv_protocol/a2a_agent/staging.py +512 -0
  8. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/transfers.py +2 -2
  9. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/tests/test_a2a_agent.py +9 -21
  10. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/tests/test_a2a_agent_examples.py +0 -1
  11. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/tests/test_a2a_object_transfers.py +1 -1
  12. agentenv_framework_protocol-0.1.283/tests/test_a2a_staging.py +275 -0
  13. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/.gitignore +0 -0
  14. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/LICENSE +0 -0
  15. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/NOTICE +0 -0
  16. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/examples/__init__.py +0 -0
  17. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/examples/advanced_agent.py +0 -0
  18. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/examples/basic_agent.py +0 -0
  19. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/examples/custom_extensions_agent.py +0 -0
  20. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/examples/multimodal_agent.py +0 -0
  21. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/examples/reference_model.py +0 -0
  22. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/examples/streaming_agent.py +0 -0
  23. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/__init__.py +0 -0
  24. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/a2a_agent/_triggers.py +0 -0
  25. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/a2a_agent/extensions.py +0 -0
  26. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/a2a_agent/registry.py +0 -0
  27. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/a2a_agent/tasks/__init__.py +0 -0
  28. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/a2a_agent/tasks/v1.py +0 -0
  29. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/agent_env_environment.py +0 -0
  30. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/client.py +0 -0
  31. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/manifest.py +0 -0
  32. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/preflight.py +0 -0
  33. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/src/agentenv_protocol/types.py +0 -0
  34. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/tests/test_agent_env_environment.py +0 -0
  35. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/tests/test_client.py +0 -0
  36. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/tests/test_intake.py +0 -0
  37. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/tests/test_manifest.py +0 -0
  38. {agentenv_framework_protocol-0.1.281 → agentenv_framework_protocol-0.1.283}/tests/test_preflight.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentenv-framework-protocol
3
- Version: 0.1.281
3
+ Version: 0.1.283
4
4
  Summary: Open data-plane protocol and server SDK for agent environments.
5
5
  Project-URL: Homepage, https://www.agentenvframework.com
6
6
  Project-URL: Documentation, https://www.agentenvframework.com/docs
@@ -30,6 +30,7 @@ Requires-Dist: pydantic>=2.11
30
30
  Requires-Dist: starlette>=0.37
31
31
  Provides-Extra: agent
32
32
  Requires-Dist: a2a-sdk[http-server]<0.4,>=0.3.26; extra == 'agent'
33
+ Requires-Dist: python-multipart>=0.0.13; extra == 'agent'
33
34
  Requires-Dist: regex>=2023.12.25; extra == 'agent'
34
35
  Requires-Dist: uvicorn>=0.30; extra == 'agent'
35
36
  Provides-Extra: dev
@@ -37,6 +38,7 @@ Requires-Dist: a2a-sdk[http-server]<0.4,>=0.3.26; extra == 'dev'
37
38
  Requires-Dist: mcp<2,>=1.25; extra == 'dev'
38
39
  Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
39
40
  Requires-Dist: pytest>=9.0; extra == 'dev'
41
+ Requires-Dist: python-multipart>=0.0.13; extra == 'dev'
40
42
  Requires-Dist: regex>=2023.12.25; extra == 'dev'
41
43
  Description-Content-Type: text/markdown
42
44
 
@@ -519,9 +521,8 @@ tools with (agent-env relays the env card's name: the MultiEnv's declared name,
519
521
  `ATTRIBUTION_PROBE_V1.probe` lets a caller check that an agent forwards attribution
520
522
  upstream. Attribution is an open map of string dimensions, like AgentEnv's cost
521
523
  attribution: the SDK assigns no keys, and each deployment uses whatever dimensions
522
- its model gateway understands (the AgentEnv control plane configures `project_id`
523
- and `task_id` on agents that declare those config fields). An agent records the
524
- dimensions it last sent with a model request and returns them from a bodyless
524
+ its model gateway understands. An agent records the dimensions it last sent with a
525
+ model request and returns them from a bodyless
525
526
  `POST /ext/attribution-probe` as an `AttributionProbeResponse`:
526
527
  `{"last_seen_attribution": {<dimension>: <value>, ...}, "last_seen_at_utc": ...}`.
527
528
  The SDK does not record attribution itself, because only the agent knows what it sent.
@@ -611,17 +612,44 @@ that is by the uploading agent. AgentEnv accepts a trajectory upload response
611
612
  without reading the object back, and registers a snapshot only once both its
612
613
  objects are in the store.
613
614
 
614
- SDK agents advertise only these shapes. AgentEnv reads each Agent Card, sends
615
- the object variants when the agent advertises them and its object store issues
616
- grants (the S3 store does, and namespace grants for changelog capture only when
617
- it signs with long-term credentials), and keeps the older `s3_prefix`, `skill_s3_url` and
618
- `trajectory_s3_prefix` shapes for agents that advertise those instead. An SDK
619
- agent built on this protocol therefore needs an agent-env release that includes
620
- it: an older release sends the older shapes, which such an agent refuses apart
621
- from inline skills and trajectories. Roll out in this
622
- order: release agent-env and `agentenv-framework-protocol` together, move every service
623
- that embeds agent-env to that release, and only then build agents on the new
624
- SDK. A snapshot or changelog is restored in the form it was captured in: one
625
- captured as objects only through the object variants, an older one only
626
- through `s3_prefix`. Do not roll agent-env back once portable snapshots or
627
- changelogs exist, because older releases cannot load them.
615
+ SDK agents advertise only these shapes, and AgentEnv sends no others. It moves
616
+ a skill bundle, snapshot or changelog only through grants, so the call needs an
617
+ agent that advertises the object variant and an object store that issues grants
618
+ (the S3 store does, and namespace grants for changelog capture only when it
619
+ signs with long-term credentials); otherwise it fails before anything is sent.
620
+ Skills given as SKILL.md text and trajectories returned inline need no grants.
621
+ A snapshot is restored only from the snapshot objects in the table above; one
622
+ that holds the runtime's own files instead cannot be. An
623
+ agent-env release without the object variants sends other shapes, which SDK
624
+ agents refuse apart from inline skills and trajectories, and cannot load
625
+ portable snapshots or changelogs, so do not run one alongside these agents.
626
+
627
+ #### Staging
628
+
629
+ When the object store's grants cannot reach the agent, as with a local store
630
+ and an agent on a remote sandbox, AgentEnv moves the objects through the agent
631
+ itself. Every SDK agent serves the staging extension, `urn:agentenv:staging/v1`,
632
+ a small object store at `/ext/staging` on its own server. Before a call
633
+ AgentEnv pushes what the agent will read into it; after the call it pulls what
634
+ the agent wrote. The grants it sends are the ordinary ones above, with URLs
635
+ naming staged paths on the agent's own URL, so handlers and helpers are
636
+ unchanged.
637
+
638
+ | Route | Does |
639
+ | --- | --- |
640
+ | `PUT /ext/staging/{path}` | stores the body |
641
+ | `GET /ext/staging/{path}` | returns it, with an `ETag` |
642
+ | `POST /ext/staging/{prefix}` | stores a multipart upload's `file` at `{prefix}/{key}`, `key` being a form field sent before it |
643
+ | `GET /ext/staging/{prefix}/` | lists `{objects: [{path, size_bytes, etag}]}` below the prefix |
644
+ | `DELETE /ext/staging/{path}` | removes the object, only while it still matches an `If-Match` tag when one is given |
645
+ | `DELETE /ext/staging/{prefix}/` | removes everything below the prefix |
646
+
647
+ A path's first segment is an id AgentEnv generates, at least 22 characters, and
648
+ never shares, which is what keeps staged objects private on a public agent URL.
649
+ Everything staged counts against `AGENTENV_STAGING_MAX_BYTES` (16 GiB unless
650
+ set; `0` turns staging off) and lives until AgentEnv removes it or the server
651
+ process ends, in a directory of the process's own (or under
652
+ `AGENTENV_STAGING_DIR` when set) that only the server's user can read. One
653
+ server process owns a staging directory. An agent that doesn't use the SDK can serve the same routes
654
+ and add `{uri: "urn:agentenv:staging/v1", params: {endpoint: "/ext/staging"}}`
655
+ to its card.
@@ -477,9 +477,8 @@ tools with (agent-env relays the env card's name: the MultiEnv's declared name,
477
477
  `ATTRIBUTION_PROBE_V1.probe` lets a caller check that an agent forwards attribution
478
478
  upstream. Attribution is an open map of string dimensions, like AgentEnv's cost
479
479
  attribution: the SDK assigns no keys, and each deployment uses whatever dimensions
480
- its model gateway understands (the AgentEnv control plane configures `project_id`
481
- and `task_id` on agents that declare those config fields). An agent records the
482
- dimensions it last sent with a model request and returns them from a bodyless
480
+ its model gateway understands. An agent records the dimensions it last sent with a
481
+ model request and returns them from a bodyless
483
482
  `POST /ext/attribution-probe` as an `AttributionProbeResponse`:
484
483
  `{"last_seen_attribution": {<dimension>: <value>, ...}, "last_seen_at_utc": ...}`.
485
484
  The SDK does not record attribution itself, because only the agent knows what it sent.
@@ -569,17 +568,44 @@ that is by the uploading agent. AgentEnv accepts a trajectory upload response
569
568
  without reading the object back, and registers a snapshot only once both its
570
569
  objects are in the store.
571
570
 
572
- SDK agents advertise only these shapes. AgentEnv reads each Agent Card, sends
573
- the object variants when the agent advertises them and its object store issues
574
- grants (the S3 store does, and namespace grants for changelog capture only when
575
- it signs with long-term credentials), and keeps the older `s3_prefix`, `skill_s3_url` and
576
- `trajectory_s3_prefix` shapes for agents that advertise those instead. An SDK
577
- agent built on this protocol therefore needs an agent-env release that includes
578
- it: an older release sends the older shapes, which such an agent refuses apart
579
- from inline skills and trajectories. Roll out in this
580
- order: release agent-env and `agentenv-framework-protocol` together, move every service
581
- that embeds agent-env to that release, and only then build agents on the new
582
- SDK. A snapshot or changelog is restored in the form it was captured in: one
583
- captured as objects only through the object variants, an older one only
584
- through `s3_prefix`. Do not roll agent-env back once portable snapshots or
585
- changelogs exist, because older releases cannot load them.
571
+ SDK agents advertise only these shapes, and AgentEnv sends no others. It moves
572
+ a skill bundle, snapshot or changelog only through grants, so the call needs an
573
+ agent that advertises the object variant and an object store that issues grants
574
+ (the S3 store does, and namespace grants for changelog capture only when it
575
+ signs with long-term credentials); otherwise it fails before anything is sent.
576
+ Skills given as SKILL.md text and trajectories returned inline need no grants.
577
+ A snapshot is restored only from the snapshot objects in the table above; one
578
+ that holds the runtime's own files instead cannot be. An
579
+ agent-env release without the object variants sends other shapes, which SDK
580
+ agents refuse apart from inline skills and trajectories, and cannot load
581
+ portable snapshots or changelogs, so do not run one alongside these agents.
582
+
583
+ #### Staging
584
+
585
+ When the object store's grants cannot reach the agent, as with a local store
586
+ and an agent on a remote sandbox, AgentEnv moves the objects through the agent
587
+ itself. Every SDK agent serves the staging extension, `urn:agentenv:staging/v1`,
588
+ a small object store at `/ext/staging` on its own server. Before a call
589
+ AgentEnv pushes what the agent will read into it; after the call it pulls what
590
+ the agent wrote. The grants it sends are the ordinary ones above, with URLs
591
+ naming staged paths on the agent's own URL, so handlers and helpers are
592
+ unchanged.
593
+
594
+ | Route | Does |
595
+ | --- | --- |
596
+ | `PUT /ext/staging/{path}` | stores the body |
597
+ | `GET /ext/staging/{path}` | returns it, with an `ETag` |
598
+ | `POST /ext/staging/{prefix}` | stores a multipart upload's `file` at `{prefix}/{key}`, `key` being a form field sent before it |
599
+ | `GET /ext/staging/{prefix}/` | lists `{objects: [{path, size_bytes, etag}]}` below the prefix |
600
+ | `DELETE /ext/staging/{path}` | removes the object, only while it still matches an `If-Match` tag when one is given |
601
+ | `DELETE /ext/staging/{prefix}/` | removes everything below the prefix |
602
+
603
+ A path's first segment is an id AgentEnv generates, at least 22 characters, and
604
+ never shares, which is what keeps staged objects private on a public agent URL.
605
+ Everything staged counts against `AGENTENV_STAGING_MAX_BYTES` (16 GiB unless
606
+ set; `0` turns staging off) and lives until AgentEnv removes it or the server
607
+ process ends, in a directory of the process's own (or under
608
+ `AGENTENV_STAGING_DIR` when set) that only the server's user can read. One
609
+ server process owns a staging directory. An agent that doesn't use the SDK can serve the same routes
610
+ and add `{uri: "urn:agentenv:staging/v1", params: {endpoint: "/ext/staging"}}`
611
+ to its card.
@@ -191,6 +191,13 @@ The runtime dependencies of `agentenv-protocol` and its `agent` extra, at the ve
191
191
  - Source: <https://github.com/pydantic/pydantic-core>
192
192
  - [License text 2](#license-text-2)
193
193
 
194
+ ### python-multipart 0.0.32
195
+
196
+ - License: Apache-2.0
197
+ - Author: Andrew Dunham <andrew@du.nham.ca>
198
+ - Source: <https://github.com/Kludex/python-multipart>
199
+ - [License text 1](#license-text-1)
200
+
194
201
  ### regex 2026.6.28
195
202
 
196
203
  - License: Apache-2.0 AND CNRI-Python
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentenv-framework-protocol"
3
- version = "0.1.281"
3
+ version = "0.1.283"
4
4
  description = "Open data-plane protocol and server SDK for agent environments."
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -30,11 +30,13 @@ dependencies = [
30
30
  [project.optional-dependencies]
31
31
  agent = [
32
32
  "a2a-sdk[http-server]>=0.3.26,<0.4",
33
+ "python-multipart>=0.0.13", # the staging extension's upload forms
33
34
  "regex>=2023.12.25",
34
35
  "uvicorn>=0.30",
35
36
  ]
36
37
  dev = [
37
38
  "a2a-sdk[http-server]>=0.3.26,<0.4",
39
+ "python-multipart>=0.0.13",
38
40
  "regex>=2023.12.25",
39
41
  "pytest>=9.0",
40
42
  "pytest-asyncio>=0.23.0",
@@ -76,6 +76,7 @@ from .registry import (
76
76
  RegisteredOperation,
77
77
  build_registry,
78
78
  )
79
+ from .staging import STAGING_ENDPOINT, STAGING_V1_URI, StagingStore, staging_routes
79
80
  from .tasks.v1 import (
80
81
  AgentConfig,
81
82
  AgentRunResult,
@@ -116,6 +117,8 @@ __all__ = [
116
117
  "PEER_AGENTS_V1",
117
118
  "SKILL_CONFIG_V1",
118
119
  "SNAPSHOT_V1",
120
+ "STAGING_ENDPOINT",
121
+ "STAGING_V1_URI",
119
122
  "STANDARD_EXTENSIONS",
120
123
  "TRAJECTORY_V1",
121
124
  "TRIGGERS_V1",
@@ -172,6 +175,7 @@ __all__ = [
172
175
  "SnapshotReadObjects",
173
176
  "SnapshotUploadedObjects",
174
177
  "SnapshotWriteObjects",
178
+ "StagingStore",
175
179
  "TaskError",
176
180
  "TaskObjectTrajectoryRequest",
177
181
  "TaskOutcome",
@@ -204,5 +208,6 @@ __all__ = [
204
208
  "extension",
205
209
  "request_fields",
206
210
  "serve",
211
+ "staging_routes",
207
212
  "upload",
208
213
  ]
@@ -45,6 +45,7 @@ from .extensions import (
45
45
  enable,
46
46
  )
47
47
  from .registry import RegisteredOperation, build_registry
48
+ from .staging import STAGING_ENDPOINT, StagingStore, staging_routes
48
49
  from .tasks.v1 import (
49
50
  AgentConfig,
50
51
  AgentRunResult,
@@ -873,6 +874,15 @@ class A2AAgentApplication:
873
874
  ("/.well-known/agent-card.json", "GET"): "Agent Card",
874
875
  }
875
876
  )
877
+ # Objects agent-env moves through the agent when its object store's grants cannot reach it.
878
+ self.staging = StagingStore()
879
+ for extension in self.registry.extensions if self.staging.max_bytes else ():
880
+ for operation in extension.operations.values():
881
+ if operation.definition.path.startswith(STAGING_ENDPOINT + "/"):
882
+ raise ValueError(
883
+ f"extension operation {extension.definition.uri}.{operation.definition.name} "
884
+ f"conflicts with the staging routes below {STAGING_ENDPOINT}"
885
+ )
876
886
  conformance = self.registry.conformance()
877
887
  for override in conformance["standard_operation_overrides"]:
878
888
  logger.warning(
@@ -906,6 +916,8 @@ class A2AAgentApplication:
906
916
  methods=[operation.definition.method],
907
917
  )
908
918
  )
919
+ if self.staging.max_bytes:
920
+ routes.extend(staging_routes(self.staging))
909
921
  kwargs = {"routes": routes}
910
922
  if definition.lifespan is not None:
911
923
  kwargs["lifespan"] = definition.lifespan
@@ -953,6 +965,8 @@ class A2AAgentApplication:
953
965
  AgentExtension.model_validate(item)
954
966
  for item in self.registry.card_extensions()
955
967
  ]
968
+ if self.staging.max_bytes:
969
+ extensions.append(AgentExtension.model_validate(self.staging.card_extension()))
956
970
  resolved_capabilities = AgentCapabilities(
957
971
  streaming=self.streaming,
958
972
  push_notifications=False,