meshagent-api 0.22.0__tar.gz → 0.22.2__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.
- {meshagent_api-0.22.0/meshagent_api.egg-info → meshagent_api-0.22.2}/PKG-INFO +2 -1
- meshagent_api-0.22.2/meshagent/api/service_template_test.py +181 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/specs/service.py +50 -10
- meshagent_api-0.22.2/meshagent/api/version.py +1 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2/meshagent_api.egg-info}/PKG-INFO +2 -1
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent_api.egg-info/SOURCES.txt +1 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent_api.egg-info/requires.txt +1 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/pyproject.toml +2 -1
- meshagent_api-0.22.0/meshagent/api/version.py +0 -1
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/LICENSE +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/MANIFEST.in +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/README.md +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/__init__.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/chan.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/client.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/crdt.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/entrypoint.js +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/helpers.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/keys.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/messaging.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/oauth.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/participant.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/participant_token.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/participant_token_test.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/port_forward.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/protocol.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/protocol_test.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/py.typed +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/reasoning_schema.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/room_server_client.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/runtime.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/runtime_test.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/schema.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/schema_document.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/schema_document_test.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/schema_registry.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/schema_test.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/schema_util.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/services.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/token_test.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/urls.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/webhooks.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent/api/websocket_protocol.py +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent_api.egg-info/dependency_links.txt +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/meshagent_api.egg-info/top_level.txt +0 -0
- {meshagent_api-0.22.0 → meshagent_api-0.22.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshagent-api
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.2
|
|
4
4
|
Summary: Python Server API for Meshagent
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Documentation, https://docs.meshagent.com
|
|
@@ -15,6 +15,7 @@ Requires-Dist: jsonschema~=4.23
|
|
|
15
15
|
Requires-Dist: pycrdt~=0.12.26
|
|
16
16
|
Requires-Dist: opentelemetry-distro~=0.54b1
|
|
17
17
|
Requires-Dist: pydantic~=2.11.7
|
|
18
|
+
Requires-Dist: jinja2~=3.1.6
|
|
18
19
|
Provides-Extra: all
|
|
19
20
|
Provides-Extra: sync
|
|
20
21
|
Provides-Extra: stpyv8
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from pydantic_yaml import parse_yaml_raw_as
|
|
4
|
+
|
|
5
|
+
from meshagent.api.specs.service import (
|
|
6
|
+
AgentSpec,
|
|
7
|
+
ContainerTemplateSpec,
|
|
8
|
+
EnvironmentVariable,
|
|
9
|
+
ExternalServiceTemplateSpec,
|
|
10
|
+
ServiceTemplateMetadata,
|
|
11
|
+
ServiceTemplateSpec,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_service_template_spec_renders_jinja_values():
|
|
16
|
+
template = ServiceTemplateSpec(
|
|
17
|
+
version="v1",
|
|
18
|
+
kind="ServiceTemplate",
|
|
19
|
+
metadata=ServiceTemplateMetadata(
|
|
20
|
+
name="!template {{service_name}}",
|
|
21
|
+
description="!template Hello {{user}}",
|
|
22
|
+
repo="https://example.com/{{service_name}}",
|
|
23
|
+
annotations={"greeting": "!template hi {{user}}"},
|
|
24
|
+
),
|
|
25
|
+
agents=[
|
|
26
|
+
AgentSpec(
|
|
27
|
+
name="!template agent-{{service_name}}",
|
|
28
|
+
description="!template handles {{role}}",
|
|
29
|
+
annotations={"role": "!template {{role}}"},
|
|
30
|
+
)
|
|
31
|
+
],
|
|
32
|
+
external=ExternalServiceTemplateSpec(url="!template https://{{host}}/api"),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
values = {
|
|
36
|
+
"service_name": "Concierge",
|
|
37
|
+
"user": "Rina",
|
|
38
|
+
"role": "support",
|
|
39
|
+
"host": "meshagent.dev",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
service = template.to_service_spec(values=values)
|
|
43
|
+
|
|
44
|
+
assert service.metadata.annotations is not None
|
|
45
|
+
assert service.agents is not None
|
|
46
|
+
assert service.external is not None
|
|
47
|
+
assert service.metadata.name == "Concierge"
|
|
48
|
+
assert service.metadata.description == "Hello Rina"
|
|
49
|
+
assert service.metadata.repo == "https://example.com/{{service_name}}"
|
|
50
|
+
assert service.metadata.annotations["greeting"] == "hi Rina"
|
|
51
|
+
assert service.external.url == "https://meshagent.dev/api"
|
|
52
|
+
assert service.agents[0].name == "agent-Concierge"
|
|
53
|
+
assert service.agents[0].description == "handles support"
|
|
54
|
+
assert service.agents[0].annotations is not None
|
|
55
|
+
assert service.agents[0].annotations["role"] == "support"
|
|
56
|
+
|
|
57
|
+
source = service.metadata.annotations["meshagent.service.template.source"]
|
|
58
|
+
values_json = service.metadata.annotations["meshagent.service.template.values"]
|
|
59
|
+
assert json.loads(values_json) == values
|
|
60
|
+
assert "ServiceTemplate" in source
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_service_template_spec_from_yaml():
|
|
64
|
+
yaml_spec = """
|
|
65
|
+
version: v1
|
|
66
|
+
kind: ServiceTemplate
|
|
67
|
+
metadata:
|
|
68
|
+
name: "!template {{service_name}}"
|
|
69
|
+
description: "!template Hello {{user}}"
|
|
70
|
+
repo: null
|
|
71
|
+
annotations:
|
|
72
|
+
greeting: "!template hi {{user}}"
|
|
73
|
+
agents:
|
|
74
|
+
- name: "!template agent-{{service_name}}"
|
|
75
|
+
description: "!template handles {{role}}"
|
|
76
|
+
external:
|
|
77
|
+
url: "!template https://{{host}}/api"
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
template = parse_yaml_raw_as(ServiceTemplateSpec, yaml_spec.encode())
|
|
81
|
+
values = {
|
|
82
|
+
"service_name": "Concierge",
|
|
83
|
+
"user": "Rina",
|
|
84
|
+
"role": "support",
|
|
85
|
+
"host": "meshagent.dev",
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
service = template.to_service_spec(values=values)
|
|
89
|
+
|
|
90
|
+
assert service.metadata.annotations is not None
|
|
91
|
+
assert service.agents is not None
|
|
92
|
+
assert service.external is not None
|
|
93
|
+
assert service.metadata.name == "Concierge"
|
|
94
|
+
assert service.metadata.description == "Hello Rina"
|
|
95
|
+
assert service.metadata.annotations["greeting"] == "hi Rina"
|
|
96
|
+
assert service.external.url == "https://meshagent.dev/api"
|
|
97
|
+
assert service.agents[0].name == "agent-Concierge"
|
|
98
|
+
assert service.agents[0].description == "handles support"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_service_template_spec_replaces_email_in_command():
|
|
102
|
+
template = ServiceTemplateSpec(
|
|
103
|
+
version="v1",
|
|
104
|
+
kind="ServiceTemplate",
|
|
105
|
+
metadata=ServiceTemplateMetadata(
|
|
106
|
+
name="PropertyAssistant",
|
|
107
|
+
description="Email template",
|
|
108
|
+
repo=None,
|
|
109
|
+
annotations=None,
|
|
110
|
+
),
|
|
111
|
+
container=ContainerTemplateSpec(
|
|
112
|
+
image="us-central1-docker.pkg.dev/meshagent-public/images/cli:{SERVER_VERSION}-esgz",
|
|
113
|
+
command=(
|
|
114
|
+
'!template meshagent multi service -c "chatbot --require-uuid '
|
|
115
|
+
"--agent-name=PropertyAssistant --image-generation=gpt-image-1 "
|
|
116
|
+
"--require-storage --require-toolkit=propertyemail --require-table-write=propertyinsurance "
|
|
117
|
+
"--require-table-write=propertyexpenses --mcp --web-search "
|
|
118
|
+
"-rr='agents/PropertyAssistant/assistantrules.txt' --rule='you have access to "
|
|
119
|
+
"the email tool, and you can send out emails.'; mailbot --reply-all "
|
|
120
|
+
"--enable-attachments --room-rules='/agents/PropertyAssistant/emailrules.txt' "
|
|
121
|
+
"--rule='never respnod in JSON or HTML, only in text.' --agent-name=PropertyAssistant "
|
|
122
|
+
"--require-table-write=propertyinsurance --require-table-write=propertyexpenses "
|
|
123
|
+
"--queue={{email}} --require-uuid --reply-all --require-storage "
|
|
124
|
+
"--email-address={{email}} --require-web-search --toolkit-name=propertyemail; "
|
|
125
|
+
"worker --require-storage --room-rules='/agents/PropertyAssistant/workerrules.txt' "
|
|
126
|
+
"--agent-name=PropertyAssistant --require-toolkit=propertyemail --queue=sendupdate "
|
|
127
|
+
"--require-table-read=propertyinsurance --require-table-read=propertyexpenses "
|
|
128
|
+
"--rule='Use the read_file tool to read PDFs.'\""
|
|
129
|
+
),
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
service = template.to_service_spec(values={"email": "owner@example.com"})
|
|
134
|
+
|
|
135
|
+
assert service.container is not None
|
|
136
|
+
assert service.container.command is not None
|
|
137
|
+
assert "{{email}}" not in service.container.command
|
|
138
|
+
assert "--queue=owner@example.com" in service.container.command
|
|
139
|
+
assert "--email-address=owner@example.com" in service.container.command
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_service_template_spec_handles_none_values():
|
|
143
|
+
template = ServiceTemplateSpec(
|
|
144
|
+
version="v1",
|
|
145
|
+
kind="ServiceTemplate",
|
|
146
|
+
metadata=ServiceTemplateMetadata(
|
|
147
|
+
name="Plain Service",
|
|
148
|
+
description=None,
|
|
149
|
+
repo=None,
|
|
150
|
+
icon=None,
|
|
151
|
+
annotations=None,
|
|
152
|
+
),
|
|
153
|
+
agents=[
|
|
154
|
+
AgentSpec(
|
|
155
|
+
name="Support",
|
|
156
|
+
description=None,
|
|
157
|
+
annotations=None,
|
|
158
|
+
)
|
|
159
|
+
],
|
|
160
|
+
container=ContainerTemplateSpec(
|
|
161
|
+
image="meshagent/example",
|
|
162
|
+
command=None,
|
|
163
|
+
environment=[EnvironmentVariable(name="EMPTY", value=None)],
|
|
164
|
+
),
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
service = template.to_service_spec(values={})
|
|
168
|
+
|
|
169
|
+
assert service.metadata.annotations is not None
|
|
170
|
+
assert service.agents is not None
|
|
171
|
+
assert service.container is not None
|
|
172
|
+
assert service.container.environment is not None
|
|
173
|
+
assert service.metadata.description is None
|
|
174
|
+
assert service.metadata.repo is None
|
|
175
|
+
assert service.metadata.icon is None
|
|
176
|
+
assert service.metadata.annotations["meshagent.service.template.source"]
|
|
177
|
+
assert service.metadata.annotations["meshagent.service.template.values"] == "{}"
|
|
178
|
+
assert len(service.metadata.annotations) == 2
|
|
179
|
+
assert service.agents[0].description is None
|
|
180
|
+
assert service.agents[0].annotations is None
|
|
181
|
+
assert service.container.environment[0].value is None
|
|
@@ -207,6 +207,8 @@ class ContainerTemplateSpec(BaseModel):
|
|
|
207
207
|
image: Optional[str] = None
|
|
208
208
|
command: Optional[str] = None
|
|
209
209
|
storage: Optional[ServiceTemplateContainerMountSpec] = None
|
|
210
|
+
on_demand: Optional[bool] = None
|
|
211
|
+
writable_root_fs: Optional[bool] = None
|
|
210
212
|
|
|
211
213
|
|
|
212
214
|
class ExternalServiceTemplateSpec(BaseModel):
|
|
@@ -214,6 +216,31 @@ class ExternalServiceTemplateSpec(BaseModel):
|
|
|
214
216
|
url: str
|
|
215
217
|
|
|
216
218
|
|
|
219
|
+
def format_yaml_value(original: Optional[str], values: dict[str, str]):
|
|
220
|
+
if original is None:
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
if original.startswith("!template "):
|
|
224
|
+
from jinja2 import Template
|
|
225
|
+
|
|
226
|
+
template = Template(original.removeprefix("!template "))
|
|
227
|
+
return template.render(**values)
|
|
228
|
+
|
|
229
|
+
else:
|
|
230
|
+
return original
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def format_yaml_map(original: Optional[dict[str, str]], values: dict[str, str]):
|
|
234
|
+
if original is None:
|
|
235
|
+
return None
|
|
236
|
+
output = {}
|
|
237
|
+
|
|
238
|
+
for k, v in original.items():
|
|
239
|
+
output[k] = format_yaml_value(v, values)
|
|
240
|
+
|
|
241
|
+
return output
|
|
242
|
+
|
|
243
|
+
|
|
217
244
|
class ServiceTemplateSpec(BaseModel):
|
|
218
245
|
model_config = ConfigDict(extra="forbid")
|
|
219
246
|
version: Literal["v1"]
|
|
@@ -232,28 +259,39 @@ class ServiceTemplateSpec(BaseModel):
|
|
|
232
259
|
for e in self.container.environment:
|
|
233
260
|
env.append(
|
|
234
261
|
EnvironmentVariable(
|
|
235
|
-
name=e.name, value=e.value
|
|
262
|
+
name=e.name, value=format_yaml_value(e.value, values)
|
|
236
263
|
)
|
|
237
264
|
)
|
|
238
265
|
|
|
239
266
|
return ServiceSpec(
|
|
240
267
|
version=self.version,
|
|
241
268
|
kind="Service",
|
|
242
|
-
agents=
|
|
269
|
+
agents=[
|
|
270
|
+
*(
|
|
271
|
+
AgentSpec(
|
|
272
|
+
name=format_yaml_value(a.name, values),
|
|
273
|
+
description=format_yaml_value(a.description, values),
|
|
274
|
+
annotations=format_yaml_map(a.annotations, values),
|
|
275
|
+
)
|
|
276
|
+
for a in self.agents
|
|
277
|
+
)
|
|
278
|
+
]
|
|
279
|
+
if self.agents is not None
|
|
280
|
+
else None,
|
|
243
281
|
metadata=ServiceMetadata(
|
|
244
|
-
name=self.metadata.name,
|
|
245
|
-
description=self.metadata.description,
|
|
246
|
-
repo=self.metadata.repo,
|
|
247
|
-
icon=self.metadata.icon,
|
|
282
|
+
name=format_yaml_value(self.metadata.name, values),
|
|
283
|
+
description=format_yaml_value(self.metadata.description, values),
|
|
284
|
+
repo=format_yaml_value(self.metadata.repo, values),
|
|
285
|
+
icon=format_yaml_value(self.metadata.icon, values),
|
|
248
286
|
annotations={
|
|
249
287
|
"meshagent.service.template.source": self.model_dump_json(),
|
|
250
288
|
"meshagent.service.template.values": json.dumps(values),
|
|
251
|
-
**self.metadata.annotations,
|
|
289
|
+
**(format_yaml_map(self.metadata.annotations, values) or {}),
|
|
252
290
|
},
|
|
253
291
|
),
|
|
254
292
|
container=ContainerSpec(
|
|
255
|
-
command=self.container.command,
|
|
256
|
-
image=self.container.image,
|
|
293
|
+
command=format_yaml_value(self.container.command, values),
|
|
294
|
+
image=format_yaml_value(self.container.image, values),
|
|
257
295
|
environment=env,
|
|
258
296
|
storage=ContainerMountSpec(
|
|
259
297
|
room=self.container.storage.room
|
|
@@ -266,11 +304,13 @@ class ServiceTemplateSpec(BaseModel):
|
|
|
266
304
|
if self.container.storage is not None
|
|
267
305
|
else None,
|
|
268
306
|
),
|
|
307
|
+
writable_root_fs=self.container.writable_root_fs,
|
|
308
|
+
on_demand=self.container.on_demand,
|
|
269
309
|
)
|
|
270
310
|
if self.container is not None
|
|
271
311
|
else None,
|
|
272
312
|
external=ExternalServiceSpec(
|
|
273
|
-
url=self.external.url,
|
|
313
|
+
url=format_yaml_value(self.external.url, values),
|
|
274
314
|
)
|
|
275
315
|
if self.external is not None
|
|
276
316
|
else None,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.22.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshagent-api
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.2
|
|
4
4
|
Summary: Python Server API for Meshagent
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Documentation, https://docs.meshagent.com
|
|
@@ -15,6 +15,7 @@ Requires-Dist: jsonschema~=4.23
|
|
|
15
15
|
Requires-Dist: pycrdt~=0.12.26
|
|
16
16
|
Requires-Dist: opentelemetry-distro~=0.54b1
|
|
17
17
|
Requires-Dist: pydantic~=2.11.7
|
|
18
|
+
Requires-Dist: jinja2~=3.1.6
|
|
18
19
|
Provides-Extra: all
|
|
19
20
|
Provides-Extra: sync
|
|
20
21
|
Provides-Extra: stpyv8
|
|
@@ -28,6 +28,7 @@ meshagent/api/schema_document_test.py
|
|
|
28
28
|
meshagent/api/schema_registry.py
|
|
29
29
|
meshagent/api/schema_test.py
|
|
30
30
|
meshagent/api/schema_util.py
|
|
31
|
+
meshagent/api/service_template_test.py
|
|
31
32
|
meshagent/api/services.py
|
|
32
33
|
meshagent/api/token_test.py
|
|
33
34
|
meshagent/api/urls.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.22.0"
|
|
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
|
|
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
|
|
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
|