agentenv-framework-protocol 0.1.269__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,165 @@
1
+ """Wire types for the v1 data-plane protocol."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Annotated, Literal, Optional, Union
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+
9
+ def error_body(code: str, message: str) -> dict:
10
+ return {"ok": False, "error": {"code": code, "message": message}}
11
+
12
+
13
+ PROTOCOL_VERSION = "1.0"
14
+
15
+ WELL_KNOWN_PATH = "/.well-known/agent-env.json"
16
+ RPC_PATH = "/agentenv"
17
+
18
+ # A card declares its MCP endpoint as an `additionalInterfaces` entry with this transport; a card
19
+ # without one is reached at MCP_PATH by convention.
20
+ MCP_TRANSPORT = "mcp"
21
+ MCP_PATH = "/mcp"
22
+
23
+ METHOD_RESET = "data/reset"
24
+ METHOD_ADD = "data/add"
25
+ METHOD_GET = "data/get"
26
+
27
+ # The vehicle for the data-plane intake declaration: a declaration-only extension
28
+ # whose `params` carry an `IntakeDeclaration`. No endpoint — it only describes what `data/add`
29
+ # accepts and what `data/get` returns, for discoverability + pre-deploy fit checks. Absence of the
30
+ # extension means "no claim" (skip fit-checks), matching the `supports_v1` 404->legacy precedent.
31
+ INTAKE_EXTENSION_URI = "urn:agentenv:intake/v1"
32
+
33
+
34
+ class FileWithBytes(BaseModel):
35
+ bytes: str
36
+ mimeType: Optional[str] = None
37
+ name: Optional[str] = None
38
+
39
+
40
+ class FileWithUri(BaseModel):
41
+ uri: str
42
+ mimeType: Optional[str] = None
43
+ name: Optional[str] = None
44
+
45
+
46
+ class TextPart(BaseModel):
47
+ kind: Literal["text"] = "text"
48
+ text: str
49
+ metadata: Optional[dict] = None
50
+
51
+
52
+ class FilePart(BaseModel):
53
+ kind: Literal["file"] = "file"
54
+ file: Union[FileWithBytes, FileWithUri]
55
+ metadata: Optional[dict] = None
56
+
57
+
58
+ class DataPart(BaseModel):
59
+ kind: Literal["data"] = "data"
60
+ data: dict
61
+ metadata: Optional[dict] = None
62
+
63
+
64
+ Part = Annotated[Union[TextPart, FilePart, DataPart], Field(discriminator="kind")]
65
+
66
+
67
+ class AddDataRequest(BaseModel):
68
+ parts: list[Part] = Field(min_length=1)
69
+
70
+
71
+ class ResetDataResponse(BaseModel):
72
+ pass
73
+
74
+
75
+ class AddDataResponse(BaseModel):
76
+ pass
77
+
78
+
79
+ class GetDataResponse(BaseModel):
80
+ parts: list[Part]
81
+
82
+
83
+ class EnvironmentInterface(BaseModel):
84
+ url: str
85
+ transport: str
86
+
87
+
88
+ class EnvironmentExtension(BaseModel):
89
+ uri: str
90
+ description: Optional[str] = None
91
+ params: Optional[dict] = None
92
+ required: Optional[bool] = None
93
+
94
+
95
+ class IntakeFormat(BaseModel):
96
+ """One accepted (on `data/add`) or returned (on `data/get`) content shape.
97
+
98
+ Describes a single way data crosses the fixed `AddDataRequest` envelope: which `Part` `kind`
99
+ carries it (`data`/`file`/`text`), the content `format` (e.g. `"json"`, `"zip-bundle"`,
100
+ `"csv"`), the `mimeTypes` that select it, and whether loading `replace`s existing data or is
101
+ `additive`. `bundleLayout` names a non-schema-able file-tree convention (e.g.
102
+ `"data-json+root/v1"`); `tables` optionally carries per-table JSON-Schemas of the loadable
103
+ shape (layer 4 — populate only where derivable, e.g. from a server's SQLAlchemy models).
104
+ """
105
+
106
+ part: Literal["data", "file", "text"]
107
+ format: str
108
+ mimeTypes: Optional[list[str]] = None
109
+ load: Optional[Literal["additive", "replace"]] = None
110
+ bundleLayout: Optional[str] = None
111
+ tables: Optional[dict[str, dict]] = None
112
+
113
+
114
+ class IntakeDeclaration(BaseModel):
115
+ """What a server's v1 data plane accepts on `data/add` and returns on `data/get`.
116
+
117
+ Advertised on the `EnvironmentCard` under `INTAKE_EXTENSION_URI`. Layers 1-3 (part
118
+ kind, format + mimeTypes, load semantics) are enough for fit-checks; layer 4 (`tables`) is
119
+ optional and highest value. Absence of the whole declaration = "no claim".
120
+ """
121
+
122
+ add: Optional[list[IntakeFormat]] = None
123
+ get: Optional[list[IntakeFormat]] = None
124
+
125
+
126
+ def intake_extension(
127
+ declaration: IntakeDeclaration, description: Optional[str] = None
128
+ ) -> "EnvironmentExtension":
129
+ """Wrap an `IntakeDeclaration` as the declaration-only `INTAKE_EXTENSION_URI` extension.
130
+
131
+ `None` params are dropped so the advertised card stays terse; read it back with
132
+ `client.intake_declaration(card)`.
133
+ """
134
+ return EnvironmentExtension(
135
+ uri=INTAKE_EXTENSION_URI,
136
+ description=description
137
+ or "Declares what the v1 data plane accepts on data/add and returns on data/get.",
138
+ params=declaration.model_dump(exclude_none=True),
139
+ )
140
+
141
+
142
+ class EnvironmentTool(BaseModel):
143
+ name: str
144
+ description: Optional[str] = None
145
+ inputSchema: Optional[dict] = None
146
+
147
+
148
+ class EnvironmentCapabilities(BaseModel):
149
+ extensions: Optional[list[EnvironmentExtension]] = None
150
+ tools: Optional[list[EnvironmentTool]] = None
151
+ # Wire methods served at /agentenv. [] = none; absent = pre-advertisement card (full data trio).
152
+ operations: Optional[list[str]] = None
153
+
154
+
155
+ class EnvironmentCard(BaseModel):
156
+ name: str
157
+ protocolVersion: str = PROTOCOL_VERSION
158
+ url: str = RPC_PATH
159
+ preferredTransport: str = "JSONRPC"
160
+ additionalInterfaces: list[EnvironmentInterface] = Field(default_factory=list)
161
+ capabilities: EnvironmentCapabilities = Field(default_factory=EnvironmentCapabilities)
162
+ children_environments: Optional[list[EnvironmentCard]] = None
163
+
164
+
165
+ EnvironmentCard.model_rebuild()