soliplex 0.77.2__tar.gz → 0.78__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.
- {soliplex-0.77.2/src/soliplex.egg-info → soliplex-0.78}/PKG-INFO +1 -1
- {soliplex-0.77.2 → soliplex-0.78}/pyproject.toml +1 -1
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/agents.py +5 -12
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/agents.py +15 -4
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/skills.py +86 -11
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/installation.py +1 -1
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/models.py +2 -2
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/quizzes.py +1 -1
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/skills/bwrap_sandbox/SKILL.md +44 -18
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/skills/bwrap_sandbox/__init__.py +194 -10
- {soliplex-0.77.2 → soliplex-0.78/src/soliplex.egg-info}/PKG-INFO +1 -1
- {soliplex-0.77.2 → soliplex-0.78}/LICENSE +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/MANIFEST.in +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/README.md +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/example/skills/bare-bones/SKILL.md +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/example/skills/stanzas/SKILL.md +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/setup.cfg +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/skills/soliplex-docs/SKILL.md +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/agui/__init__.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/agui/parser.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/agui/persistence.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/agui/schema.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/agui/util.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/authn.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/authz/__init__.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/authz/persistence.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/authz/schema.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/capabilities/filesystem.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/capabilities/rag_audit.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/admin_users.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/ask.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/audit.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/cli_util.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/main.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/ollama.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/room_authz.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/serve.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/cli/types.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/completions.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/__init__.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/_utils.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/agui.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/authsystem.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/completions.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/exceptions.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/installation.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/logfire.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/meta.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/middleware.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/quizzes.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/rag.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/rooms.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/routing.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/secrets.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/config/tools.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/examples.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/log_ingest.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/loggers.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/main.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/mcp_auth.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/mcp_client.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/mcp_server.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/ollama.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/rag_audit.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/sandbox_audit.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/secrets.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/titles.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/tools/__init__.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/tools/agui_run_feedback.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/tools/file_uploads.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/tools/rag.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/tui/cli.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/tui/main.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/tui/rest_api.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/tui/serve.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/util.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/__init__.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/agui.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/authn.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/authz.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/completions.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/installation.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/log_ingest.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/quizzes.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/room_file_uploads.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/rooms.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/sandbox_workdirs.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/stats.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/streaming.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex/views/thread_file_uploads.py +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex.egg-info/SOURCES.txt +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex.egg-info/dependency_links.txt +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex.egg-info/entry_points.txt +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex.egg-info/requires.txt +0 -0
- {soliplex-0.77.2 → soliplex-0.78}/src/soliplex.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: soliplex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.78
|
|
4
4
|
Summary: An AI-powered Retrieval-Augmented Generation (RAG) system with a modern web interface.
|
|
5
5
|
Author-email: Enfold <info@enfoldsystems.net>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "soliplex"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.78"
|
|
8
8
|
description = "An AI-powered Retrieval-Augmented Generation (RAG) system with a modern web interface."
|
|
9
9
|
authors = [{ name = "Enfold", email = "info@enfoldsystems.net" }]
|
|
10
10
|
readme = "README.md"
|
|
@@ -144,18 +144,11 @@ def get_default_agent_from_configs(
|
|
|
144
144
|
if isinstance(capability, HR_VisionCapabilities):
|
|
145
145
|
capability.vision = agent_config.multimodal
|
|
146
146
|
|
|
147
|
-
# A
|
|
148
|
-
#
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
capability
|
|
153
|
-
for capability in capabilities
|
|
154
|
-
if _is_routing_capability(capability)
|
|
155
|
-
]
|
|
156
|
-
defer_loading = len(routing_capabilities) > 1
|
|
157
|
-
for capability in routing_capabilities:
|
|
158
|
-
capability.defer_loading = defer_loading
|
|
147
|
+
# A hook-only capability is never deferred: nothing would load it, and
|
|
148
|
+
# its hooks only fire once loaded.
|
|
149
|
+
for capability in capabilities:
|
|
150
|
+
if not _is_routing_capability(capability):
|
|
151
|
+
capability.defer_loading = False
|
|
159
152
|
|
|
160
153
|
return pydantic_ai.Agent(
|
|
161
154
|
model=model,
|
|
@@ -271,6 +271,16 @@ class AgentConfig:
|
|
|
271
271
|
else: # pragma: NO COVER
|
|
272
272
|
pass
|
|
273
273
|
|
|
274
|
+
@property
|
|
275
|
+
def llm_model_name(self) -> str | None:
|
|
276
|
+
model_name = self.model_name
|
|
277
|
+
i_config = self._installation_config
|
|
278
|
+
|
|
279
|
+
if i_config is not None:
|
|
280
|
+
model_name = i_config.interpolate_environment(model_name)
|
|
281
|
+
|
|
282
|
+
return model_name
|
|
283
|
+
|
|
274
284
|
@property
|
|
275
285
|
def llm_provider_base_url(self) -> str | None:
|
|
276
286
|
ic = self._installation_config
|
|
@@ -324,7 +334,7 @@ class AgentConfig:
|
|
|
324
334
|
return {
|
|
325
335
|
"id": self.id,
|
|
326
336
|
"kind": self.kind,
|
|
327
|
-
"model_name": self.model_name,
|
|
337
|
+
"model_name": self.model_name, # not interpolated
|
|
328
338
|
"retries": self.retries,
|
|
329
339
|
"system_prompt": prompt,
|
|
330
340
|
"model_settings": self.model_settings,
|
|
@@ -478,6 +488,7 @@ def get_model_from_config(
|
|
|
478
488
|
provider_kw = agent_config.llm_provider_kw
|
|
479
489
|
|
|
480
490
|
model_settings_kw = {}
|
|
491
|
+
model_name = agent_config.llm_model_name
|
|
481
492
|
|
|
482
493
|
if agent_config.model_settings:
|
|
483
494
|
model_settings_kw["settings"] = ai_settings.ModelSettings(
|
|
@@ -487,7 +498,7 @@ def get_model_from_config(
|
|
|
487
498
|
if agent_config.provider_type == LLMProviderType.GOOGLE:
|
|
488
499
|
provider = google_providers.GoogleProvider(**provider_kw)
|
|
489
500
|
return google_models.GoogleModel(
|
|
490
|
-
model_name=
|
|
501
|
+
model_name=model_name,
|
|
491
502
|
provider=provider,
|
|
492
503
|
**model_settings_kw,
|
|
493
504
|
)
|
|
@@ -496,7 +507,7 @@ def get_model_from_config(
|
|
|
496
507
|
provider_kw["api_key"] = "dummy"
|
|
497
508
|
provider = ollama_providers.OllamaProvider(**provider_kw)
|
|
498
509
|
return openai_models.OpenAIChatModel(
|
|
499
|
-
model_name=
|
|
510
|
+
model_name=model_name,
|
|
500
511
|
provider=provider,
|
|
501
512
|
profile=_OPENAI_COMPAT_PROFILE,
|
|
502
513
|
**model_settings_kw,
|
|
@@ -510,7 +521,7 @@ def get_model_from_config(
|
|
|
510
521
|
)
|
|
511
522
|
provider = openai_providers.OpenAIProvider(**provider_kw)
|
|
512
523
|
return openai_models.OpenAIChatModel(
|
|
513
|
-
model_name=
|
|
524
|
+
model_name=model_name,
|
|
514
525
|
provider=provider,
|
|
515
526
|
**profile_kw,
|
|
516
527
|
**model_settings_kw,
|
|
@@ -179,6 +179,22 @@ class FilesystemSkillConfig:
|
|
|
179
179
|
def extra_parameters(self) -> dict[str, pathlib.Path]:
|
|
180
180
|
return {"path": self.path}
|
|
181
181
|
|
|
182
|
+
def with_defer_loading(self, defer_loading: bool) -> FilesystemSkillConfig:
|
|
183
|
+
"""A copy whose capability loads as a room asked.
|
|
184
|
+
|
|
185
|
+
Installation skill configs are shared between the rooms which name
|
|
186
|
+
them, so a room's choice cannot be written onto the capability.
|
|
187
|
+
"""
|
|
188
|
+
if defer_loading == self._capability.defer_loading:
|
|
189
|
+
return self
|
|
190
|
+
return dataclasses.replace(
|
|
191
|
+
self,
|
|
192
|
+
_capability=dataclasses.replace(
|
|
193
|
+
self._capability,
|
|
194
|
+
defer_loading=defer_loading,
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
|
|
182
198
|
|
|
183
199
|
@dataclasses.dataclass(kw_only=True)
|
|
184
200
|
class _HaikuRAGCapabilityConfig(
|
|
@@ -192,6 +208,8 @@ class _HaikuRAGCapabilityConfig(
|
|
|
192
208
|
state_type: typing.ClassVar[type[pydantic.BaseModel]]
|
|
193
209
|
source: typing.ClassVar[SkillKind] = SkillKind.NATIVE
|
|
194
210
|
|
|
211
|
+
defer_loading: bool = False
|
|
212
|
+
|
|
195
213
|
@classmethod
|
|
196
214
|
def from_yaml(
|
|
197
215
|
cls,
|
|
@@ -230,7 +248,7 @@ class _HaikuRAGCapabilityConfig(
|
|
|
230
248
|
return type(self).capability_factory(
|
|
231
249
|
db_path=self.rag_lancedb_path,
|
|
232
250
|
config=self.haiku_rag_config,
|
|
233
|
-
defer_loading=
|
|
251
|
+
defer_loading=self.defer_loading,
|
|
234
252
|
)
|
|
235
253
|
|
|
236
254
|
@property
|
|
@@ -239,7 +257,10 @@ class _HaikuRAGCapabilityConfig(
|
|
|
239
257
|
|
|
240
258
|
@property
|
|
241
259
|
def as_yaml(self) -> dict:
|
|
242
|
-
result = {
|
|
260
|
+
result = {
|
|
261
|
+
"kind": self.kind,
|
|
262
|
+
"defer_loading": self.defer_loading,
|
|
263
|
+
}
|
|
243
264
|
if self.rag_lancedb_stem is not None:
|
|
244
265
|
result["rag_lancedb_stem"] = self.rag_lancedb_stem
|
|
245
266
|
else:
|
|
@@ -383,6 +404,7 @@ class BwrapSandboxSkillConfig:
|
|
|
383
404
|
allowed_environments: bwrap_sandbox.AllowedEnvironments = None
|
|
384
405
|
sandbox_config: bs_config.Config = None
|
|
385
406
|
volumes: bs_models.VolumeMap = _default_dict_field()
|
|
407
|
+
defer_loading: bool = False
|
|
386
408
|
|
|
387
409
|
@classmethod
|
|
388
410
|
def from_yaml(
|
|
@@ -420,6 +442,7 @@ class BwrapSandboxSkillConfig:
|
|
|
420
442
|
sandbox_config=self.sandbox_config,
|
|
421
443
|
volumes=self.volumes,
|
|
422
444
|
installation_config=self._installation_config,
|
|
445
|
+
defer_loading=self.defer_loading,
|
|
423
446
|
)
|
|
424
447
|
|
|
425
448
|
@property
|
|
@@ -427,6 +450,7 @@ class BwrapSandboxSkillConfig:
|
|
|
427
450
|
result = {
|
|
428
451
|
"kind": self.kind,
|
|
429
452
|
"default_environment": self.default_environment,
|
|
453
|
+
"defer_loading": self.defer_loading,
|
|
430
454
|
}
|
|
431
455
|
if self.id is not None:
|
|
432
456
|
result["id"] = self.id
|
|
@@ -475,6 +499,7 @@ class EntrypointCapabilityConfig:
|
|
|
475
499
|
|
|
476
500
|
name: str
|
|
477
501
|
params: dict[str, typing.Any] = _default_dict_field()
|
|
502
|
+
defer_loading: bool = True
|
|
478
503
|
|
|
479
504
|
def __post_init__(self) -> None:
|
|
480
505
|
# Register the capability's typed AG-UI state feature so the room can
|
|
@@ -500,10 +525,13 @@ class EntrypointCapabilityConfig:
|
|
|
500
525
|
params = dict(config_dict)
|
|
501
526
|
params.pop("kind", None)
|
|
502
527
|
name = params.pop("name", None)
|
|
528
|
+
# Soliplex's own flag, not one of the plugin's parameters.
|
|
529
|
+
defer_loading = params.pop("defer_loading", True)
|
|
503
530
|
try:
|
|
504
531
|
return cls(
|
|
505
532
|
name=name,
|
|
506
533
|
params=params,
|
|
534
|
+
defer_loading=defer_loading,
|
|
507
535
|
_installation_config=installation_config,
|
|
508
536
|
_config_path=config_path,
|
|
509
537
|
)
|
|
@@ -521,7 +549,7 @@ class EntrypointCapabilityConfig:
|
|
|
521
549
|
@property
|
|
522
550
|
def capability(self) -> ai_capabilities.AbstractCapability:
|
|
523
551
|
return self._module.create_capability(
|
|
524
|
-
defer_loading=
|
|
552
|
+
defer_loading=self.defer_loading, **self.params
|
|
525
553
|
)
|
|
526
554
|
|
|
527
555
|
@property
|
|
@@ -543,7 +571,12 @@ class EntrypointCapabilityConfig:
|
|
|
543
571
|
|
|
544
572
|
@property
|
|
545
573
|
def as_yaml(self) -> dict:
|
|
546
|
-
return {
|
|
574
|
+
return {
|
|
575
|
+
"kind": self.kind,
|
|
576
|
+
"name": self.name,
|
|
577
|
+
"defer_loading": self.defer_loading,
|
|
578
|
+
**self.params,
|
|
579
|
+
}
|
|
547
580
|
|
|
548
581
|
@property
|
|
549
582
|
def extra_parameters(self) -> dict[str, typing.Any]:
|
|
@@ -611,24 +644,57 @@ def extract_skill_configs(
|
|
|
611
644
|
return skill_configs
|
|
612
645
|
|
|
613
646
|
|
|
647
|
+
@dataclasses.dataclass(kw_only=True)
|
|
648
|
+
class InstallationSkillRef:
|
|
649
|
+
"""A room's reference to one of the installation's skills.
|
|
650
|
+
|
|
651
|
+
Spelled as a bare name, or as a mapping when the room sets a flag.
|
|
652
|
+
"""
|
|
653
|
+
|
|
654
|
+
name: str
|
|
655
|
+
defer_loading: bool = True
|
|
656
|
+
|
|
657
|
+
@classmethod
|
|
658
|
+
def from_yaml(cls, entry: str | dict | InstallationSkillRef):
|
|
659
|
+
if isinstance(entry, cls):
|
|
660
|
+
return entry
|
|
661
|
+
if isinstance(entry, str):
|
|
662
|
+
return cls(name=entry)
|
|
663
|
+
return cls(**entry)
|
|
664
|
+
|
|
665
|
+
@property
|
|
666
|
+
def as_yaml(self) -> str | dict:
|
|
667
|
+
return {"name": self.name, "defer_loading": self.defer_loading}
|
|
668
|
+
|
|
669
|
+
|
|
614
670
|
@dataclasses.dataclass(kw_only=True)
|
|
615
671
|
class RoomSkillsConfig:
|
|
616
672
|
"""Select native capabilities for a room."""
|
|
617
673
|
|
|
618
|
-
installation_skill_names: list[
|
|
674
|
+
installation_skill_names: list[InstallationSkillRef] = (
|
|
675
|
+
_default_list_field()
|
|
676
|
+
)
|
|
619
677
|
_skill_configs: SkillConfigMap = _default_dict_field()
|
|
620
678
|
_installation_config: config_installation.InstallationConfig = (
|
|
621
679
|
_no_repr_no_compare_none()
|
|
622
680
|
)
|
|
623
681
|
_config_path: pathlib.Path = None
|
|
624
682
|
|
|
683
|
+
def __post_init__(self) -> None:
|
|
684
|
+
# Callers which build the config directly, rather than via
|
|
685
|
+
# 'from_yaml', may spell the entries as bare names.
|
|
686
|
+
self.installation_skill_names = [
|
|
687
|
+
InstallationSkillRef.from_yaml(entry)
|
|
688
|
+
for entry in self.installation_skill_names
|
|
689
|
+
]
|
|
690
|
+
|
|
625
691
|
@staticmethod
|
|
626
692
|
def _check_installation_skills(
|
|
627
693
|
installation_config: config_installation.InstallationConfig,
|
|
628
694
|
config_path: pathlib.Path,
|
|
629
|
-
|
|
695
|
+
refs: typing.Sequence[InstallationSkillRef],
|
|
630
696
|
) -> None:
|
|
631
|
-
requested =
|
|
697
|
+
requested = {ref.name for ref in refs}
|
|
632
698
|
available = set(installation_config.skill_configs)
|
|
633
699
|
if missing := requested - available:
|
|
634
700
|
raise MissingSkillNames(
|
|
@@ -645,11 +711,16 @@ class RoomSkillsConfig:
|
|
|
645
711
|
config_dict: dict,
|
|
646
712
|
):
|
|
647
713
|
try:
|
|
714
|
+
refs = [
|
|
715
|
+
InstallationSkillRef.from_yaml(entry)
|
|
716
|
+
for entry in config_dict.get("installation_skill_names", ())
|
|
717
|
+
]
|
|
648
718
|
cls._check_installation_skills(
|
|
649
719
|
installation_config,
|
|
650
720
|
config_path,
|
|
651
|
-
|
|
721
|
+
refs,
|
|
652
722
|
)
|
|
723
|
+
config_dict["installation_skill_names"] = refs
|
|
653
724
|
config_dict["_skill_configs"] = extract_skill_configs(
|
|
654
725
|
installation_config,
|
|
655
726
|
config_path,
|
|
@@ -671,7 +742,9 @@ class RoomSkillsConfig:
|
|
|
671
742
|
def as_yaml(self) -> dict:
|
|
672
743
|
result = {}
|
|
673
744
|
if self.installation_skill_names:
|
|
674
|
-
result["installation_skill_names"] =
|
|
745
|
+
result["installation_skill_names"] = [
|
|
746
|
+
ref.as_yaml for ref in self.installation_skill_names
|
|
747
|
+
]
|
|
675
748
|
if self._skill_configs:
|
|
676
749
|
result["skill_configs"] = [
|
|
677
750
|
config.as_yaml for config in self._skill_configs.values()
|
|
@@ -682,8 +755,10 @@ class RoomSkillsConfig:
|
|
|
682
755
|
def skill_configs(self) -> SkillConfigMap:
|
|
683
756
|
installation_configs = self._installation_config.skill_configs
|
|
684
757
|
return {
|
|
685
|
-
name: installation_configs[name]
|
|
686
|
-
|
|
758
|
+
ref.name: installation_configs[ref.name].with_defer_loading(
|
|
759
|
+
ref.defer_loading
|
|
760
|
+
)
|
|
761
|
+
for ref in self.installation_skill_names
|
|
687
762
|
} | self._skill_configs
|
|
688
763
|
|
|
689
764
|
@property
|
|
@@ -178,7 +178,7 @@ class Installation:
|
|
|
178
178
|
type_info = found.setdefault(provider_type, {})
|
|
179
179
|
base_url = agent_config.llm_provider_base_url
|
|
180
180
|
url_models = type_info.setdefault(base_url, set())
|
|
181
|
-
url_models.add(agent_config.
|
|
181
|
+
url_models.add(agent_config.llm_model_name)
|
|
182
182
|
|
|
183
183
|
return found
|
|
184
184
|
|
|
@@ -174,7 +174,7 @@ ConfiguredSkills = dict[str, Skill]
|
|
|
174
174
|
|
|
175
175
|
class DefaultAgent(pydantic.BaseModel):
|
|
176
176
|
id: str
|
|
177
|
-
model_name: str
|
|
177
|
+
model_name: str | None
|
|
178
178
|
retries: int
|
|
179
179
|
system_prompt: str | None
|
|
180
180
|
provider_type: config_agents.LLMProviderType # enum, not dataclass
|
|
@@ -187,7 +187,7 @@ class DefaultAgent(pydantic.BaseModel):
|
|
|
187
187
|
llm_provider_kw = agent_config.llm_provider_kw
|
|
188
188
|
return cls(
|
|
189
189
|
id=agent_config.id,
|
|
190
|
-
model_name=agent_config.
|
|
190
|
+
model_name=agent_config.llm_model_name,
|
|
191
191
|
retries=agent_config.retries,
|
|
192
192
|
system_prompt=agent_config.get_system_prompt(),
|
|
193
193
|
provider_type=agent_config.provider_type,
|
|
@@ -52,7 +52,7 @@ def get_quiz_judge_agent(quiz: config_quizzes.QuizConfig):
|
|
|
52
52
|
model_provider = ollama_providers.OllamaProvider(**llm_provider_kw)
|
|
53
53
|
|
|
54
54
|
ollama_model = openai_models.OpenAIChatModel(
|
|
55
|
-
model_name=quiz.judge_agent.
|
|
55
|
+
model_name=quiz.judge_agent.llm_model_name,
|
|
56
56
|
provider=model_provider,
|
|
57
57
|
)
|
|
58
58
|
|
|
@@ -55,11 +55,30 @@ Do NOT use the sandbox if **any** of these is true:
|
|
|
55
55
|
- `run_python(script, environment_name=None, timeout=None)` — run a Python
|
|
56
56
|
script. `script` is the full source as one string.
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
## Environment names come only from `list_environments`
|
|
59
|
+
|
|
60
|
+
**Never guess an environment name.** The only values `environment_name`
|
|
61
|
+
accepts are the exact `name` strings that a `list_environments` call
|
|
62
|
+
returned **to you, in this conversation**.
|
|
63
|
+
|
|
64
|
+
- Call `list_environments` before the first `run` or `run_python` of a
|
|
65
|
+
turn. It is cheap; skipping it is the most common way this skill fails.
|
|
66
|
+
- Every environment name written in this document is a placeholder —
|
|
67
|
+
`<name from list_environments>` — standing in for a name you have yet to
|
|
68
|
+
look up. No placeholder names a real environment.
|
|
69
|
+
- A name that appears in a task, a filename, a library you plan to import,
|
|
70
|
+
or an earlier conversation is not an environment name. Neither is the
|
|
71
|
+
name of a package: an environment's `name` and its `dependencies` are
|
|
72
|
+
different things, and are usually spelled differently.
|
|
73
|
+
- Passing a name that was not in the `list_environments` result fails the
|
|
74
|
+
call. The failure names the environments you may actually use — call
|
|
75
|
+
`list_environments` and retry with one of those, rather than guessing
|
|
76
|
+
again.
|
|
77
|
+
|
|
78
|
+
`environment_name` and `timeout` are both optional and fall back to the
|
|
79
|
+
values this skill was configured with. Always pass `environment_name`
|
|
80
|
+
explicitly: the configured default is not visible to you and may not be
|
|
81
|
+
the environment you want.
|
|
63
82
|
|
|
64
83
|
## Workflow
|
|
65
84
|
|
|
@@ -68,9 +87,9 @@ and may not be the environment you want.
|
|
|
68
87
|
|
|
69
88
|
```python
|
|
70
89
|
{
|
|
71
|
-
"name": "
|
|
72
|
-
"description": "
|
|
73
|
-
"dependencies": ["
|
|
90
|
+
"name": "<name from list_environments>",
|
|
91
|
+
"description": "<what this environment is for>",
|
|
92
|
+
"dependencies": ["<installed package>"],
|
|
74
93
|
}
|
|
75
94
|
```
|
|
76
95
|
|
|
@@ -78,10 +97,11 @@ and may not be the environment you want.
|
|
|
78
97
|
- If the list is empty, stop and tell the user the skill
|
|
79
98
|
is not configured — do not proceed.
|
|
80
99
|
- If the list contains exactly one environment, use its `name`.
|
|
81
|
-
- Otherwise,
|
|
82
|
-
|
|
83
|
-
`
|
|
84
|
-
|
|
100
|
+
- Otherwise, compare the task against each entry's `dependencies` —
|
|
101
|
+
a `pandas` dependency suits tabular data, `numpy` numeric work,
|
|
102
|
+
`pillow` images — and use the `name` of the first entry that matches.
|
|
103
|
+
Use the entry's `name`, not the name of the dependency that matched.
|
|
104
|
+
If no entry matches, use the `name` of the first entry in the list.
|
|
85
105
|
|
|
86
106
|
2. **List files in both volumes.** This step is mandatory — do not skip it,
|
|
87
107
|
even if the task seems to involve one volume. Run both:
|
|
@@ -113,7 +133,7 @@ and may not be the environment you want.
|
|
|
113
133
|
|
|
114
134
|
```python
|
|
115
135
|
run(command=["head", "-n", "5", "/sandbox/volumes/thread/orders.csv"],
|
|
116
|
-
environment_name="<
|
|
136
|
+
environment_name="<name from list_environments>")
|
|
117
137
|
```
|
|
118
138
|
|
|
119
139
|
(or `["wc", "-l", <path>]`, `["file", <path>]`, etc.). For anything
|
|
@@ -125,7 +145,8 @@ and may not be the environment you want.
|
|
|
125
145
|
argument to `run_python`:
|
|
126
146
|
|
|
127
147
|
```python
|
|
128
|
-
run_python(script="<python source>",
|
|
148
|
+
run_python(script="<python source>",
|
|
149
|
+
environment_name="<name from list_environments>")
|
|
129
150
|
```
|
|
130
151
|
|
|
131
152
|
Write the whole program as a single string, and use real newlines between
|
|
@@ -147,7 +168,10 @@ and may not be the environment you want.
|
|
|
147
168
|
```
|
|
148
169
|
|
|
149
170
|
5. **On failure.**
|
|
150
|
-
-
|
|
171
|
+
- If the failure says the environment is not available, you guessed a
|
|
172
|
+
name. Call `list_environments` and retry with a name it returned —
|
|
173
|
+
do not try a different guess.
|
|
174
|
+
- Otherwise change exactly one thing per retry.
|
|
151
175
|
- After 3 failed runs, stop. Report the error to the user (paste the
|
|
152
176
|
`Exited with code: <N>` line and any traceback), instead of retrying
|
|
153
177
|
further.
|
|
@@ -168,8 +192,10 @@ and may not be the environment you want.
|
|
|
168
192
|
Task: user uploads `orders.csv` and asks "what's the total order value?".
|
|
169
193
|
A full run looks like:
|
|
170
194
|
|
|
171
|
-
1. `list_environments()` —
|
|
172
|
-
|
|
195
|
+
1. `list_environments()` — returns exactly one environment, whose
|
|
196
|
+
`dependencies` include `pandas`. Use that entry's `name`; in step 3 it
|
|
197
|
+
is written as `<name from list_environments>`, because what the name
|
|
198
|
+
actually is can only be read off this call's result.
|
|
173
199
|
|
|
174
200
|
2. `list_volume_files("thread")` — returns
|
|
175
201
|
`["/sandbox/volumes/thread/orders.csv"]`.
|
|
@@ -184,7 +210,7 @@ A full run looks like:
|
|
|
184
210
|
df = pd.read_csv('/sandbox/volumes/thread/orders.csv')
|
|
185
211
|
print(f"Total: {df['amount'].sum():.2f}")
|
|
186
212
|
""",
|
|
187
|
-
environment_name="
|
|
213
|
+
environment_name="<name from list_environments>",
|
|
188
214
|
)
|
|
189
215
|
```
|
|
190
216
|
|
|
@@ -31,6 +31,10 @@ SANDBOX_WORKDIR_PATH = SKILL_PROPERTIES.metadata["sandbox_workdir_path"]
|
|
|
31
31
|
LIST_ENVIRONMENTS_DESCRIPTION = """
|
|
32
32
|
Return a list of information about available sandbox environments
|
|
33
33
|
|
|
34
|
+
Call this tool before the first ``run`` or ``run_python`` of a turn: \
|
|
35
|
+
their ``environment_name`` argument accepts nothing but the names \
|
|
36
|
+
returned here.
|
|
37
|
+
|
|
34
38
|
Each entry will contain these fields:
|
|
35
39
|
- 'name' (string) pass this value to the ``run`` and ``run_python`` \
|
|
36
40
|
tools to run the tool in the environment.
|
|
@@ -55,6 +59,164 @@ async def skill_list_environments(
|
|
|
55
59
|
return candidates
|
|
56
60
|
|
|
57
61
|
|
|
62
|
+
class UnknownEnvironment(pydantic_ai.ModelRetry):
|
|
63
|
+
def __init__(self, name, choices):
|
|
64
|
+
self.name = name
|
|
65
|
+
self.choices = choices
|
|
66
|
+
c_list = ", ".join(repr(name) for name in choices)
|
|
67
|
+
super().__init__(
|
|
68
|
+
f"{name!r} is not an available sandbox environment. "
|
|
69
|
+
"Environment names cannot be guessed or copied from examples: "
|
|
70
|
+
"call 'list_environments' and pass one of the names it returns. "
|
|
71
|
+
f"Available environments: {c_list}."
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class NoEnvironmentsConfigured(pydantic_ai.ToolFailed):
|
|
76
|
+
def __init__(self, name):
|
|
77
|
+
self.name = name
|
|
78
|
+
super().__init__(
|
|
79
|
+
f"{name!r} is not an available sandbox environment, "
|
|
80
|
+
"and this room has none configured. "
|
|
81
|
+
"Tell the user the sandbox skill is not configured."
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
async def check_environment_name(
|
|
86
|
+
*,
|
|
87
|
+
bwrap_sandbox: bs_sandbox.BwrapSandbox,
|
|
88
|
+
environment_name: str | None,
|
|
89
|
+
allowed_environments: AllowedEnvironments = None,
|
|
90
|
+
) -> None:
|
|
91
|
+
"""Reject an 'environment_name' the model invented, before anything runs.
|
|
92
|
+
|
|
93
|
+
Guards 'run' / 'run_python' against a name the model guessed rather than
|
|
94
|
+
read from a 'list_environments' result. Without it, an unknown name
|
|
95
|
+
aborts the whole agent run, and a name which exists but is *not* in
|
|
96
|
+
'allowed_environments' runs anyway -- 'allowed_environments' otherwise
|
|
97
|
+
only filters what 'list_environments' reports.
|
|
98
|
+
|
|
99
|
+
The two failures differ in whether the model can do anything about them,
|
|
100
|
+
so they are reported differently. A name outside the choices is fixable
|
|
101
|
+
by calling 'list_environments' and passing one of them, which is what
|
|
102
|
+
'ModelRetry' asks for (and matches how 'pydantic_ai' itself reports an
|
|
103
|
+
unknown *tool* name). A room with no environments at all is the
|
|
104
|
+
operator's to fix: 'ToolFailed' shows the model a failed call to report
|
|
105
|
+
rather than one to retry, and spends none of the tool's retry budget.
|
|
106
|
+
|
|
107
|
+
'None' passes through unchecked: it selects the environment the skill was
|
|
108
|
+
configured with, which is the operator's choice rather than the model's.
|
|
109
|
+
"""
|
|
110
|
+
if environment_name is None:
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
available = [
|
|
114
|
+
env.name
|
|
115
|
+
for env in await skill_list_environments(
|
|
116
|
+
bwrap_sandbox=bwrap_sandbox,
|
|
117
|
+
allowed_environments=allowed_environments,
|
|
118
|
+
)
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
if environment_name in available:
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
if not available:
|
|
125
|
+
raise NoEnvironmentsConfigured(name=environment_name)
|
|
126
|
+
|
|
127
|
+
raise UnknownEnvironment(
|
|
128
|
+
name=environment_name,
|
|
129
|
+
choices=available,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _environment_label(environment_name):
|
|
134
|
+
"""Name the environment a run asked for, without leaking host paths.
|
|
135
|
+
|
|
136
|
+
'bubble_sandbox' builds its messages from the resolved filesystem path
|
|
137
|
+
("Environment not found: PosixPath('/app/sandbox/environments/...')"),
|
|
138
|
+
which is meaningless inside the sandbox and not something to put in
|
|
139
|
+
front of the model. The requested name says the same thing.
|
|
140
|
+
"""
|
|
141
|
+
if environment_name is None:
|
|
142
|
+
return "the environment this room uses by default"
|
|
143
|
+
return f"the {environment_name!r} environment"
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class EnvironmentMissing(pydantic_ai.ToolFailed):
|
|
147
|
+
def __init__(self, environment_name):
|
|
148
|
+
self.environment_name = environment_name
|
|
149
|
+
super().__init__(
|
|
150
|
+
f"The sandbox cannot run: {_environment_label(environment_name)} "
|
|
151
|
+
"is not installed on this server. Report this to the user as a "
|
|
152
|
+
"sandbox configuration problem; retrying will not fix it."
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class EnvironmentNotBuilt(pydantic_ai.ToolFailed):
|
|
157
|
+
def __init__(self, environment_name):
|
|
158
|
+
self.environment_name = environment_name
|
|
159
|
+
super().__init__(
|
|
160
|
+
f"The sandbox cannot run: {_environment_label(environment_name)} "
|
|
161
|
+
"is installed but its Python virtualenv is missing. Report this "
|
|
162
|
+
"to the user as a sandbox configuration problem; retrying will "
|
|
163
|
+
"not fix it."
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class EnvironmentNameInvalid(pydantic_ai.ToolFailed):
|
|
168
|
+
def __init__(self, environment_name):
|
|
169
|
+
self.environment_name = environment_name
|
|
170
|
+
super().__init__(
|
|
171
|
+
f"The sandbox cannot run: {_environment_label(environment_name)} "
|
|
172
|
+
"is not a usable environment name. Report this to the user as a "
|
|
173
|
+
"sandbox configuration problem; retrying will not fix it."
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class SandboxUnavailable(pydantic_ai.ToolFailed):
|
|
178
|
+
def __init__(self, environment_name, reason):
|
|
179
|
+
self.environment_name = environment_name
|
|
180
|
+
self.reason = reason
|
|
181
|
+
super().__init__(
|
|
182
|
+
"The sandbox could not be started in "
|
|
183
|
+
f"{_environment_label(environment_name)}: {reason}. Report this "
|
|
184
|
+
"to the user; retrying will not fix it."
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# 'bubble_sandbox' reports a bad environment name with 'ValueError' and
|
|
189
|
+
# 'FileNotFoundError' subclasses, not 'RuntimeError'; letting one escape
|
|
190
|
+
# aborts the agent run (soliplex#1306) instead of handing the model an
|
|
191
|
+
# error it can act on.
|
|
192
|
+
EXECUTION_ERRORS = (
|
|
193
|
+
RuntimeError,
|
|
194
|
+
OSError,
|
|
195
|
+
bs_config.InvalidEnvironmentName,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def translate_execution_error(exc, *, environment_name):
|
|
200
|
+
"""Return the error the model should see for a failed sandbox start.
|
|
201
|
+
|
|
202
|
+
Every case here is the operator's to fix rather than the model's --
|
|
203
|
+
'check_environment_name' has already rejected any name the model could
|
|
204
|
+
have chosen differently -- so each maps to a 'ToolFailed' subclass: the
|
|
205
|
+
model sees a failed call to report, spends none of the tool's retry
|
|
206
|
+
budget, and is told plainly that retrying will not help.
|
|
207
|
+
"""
|
|
208
|
+
if isinstance(exc, bs_config.EnvironmentNotFound):
|
|
209
|
+
return EnvironmentMissing(environment_name)
|
|
210
|
+
|
|
211
|
+
if isinstance(exc, bs_config.EnvironmentNotInitialized):
|
|
212
|
+
return EnvironmentNotBuilt(environment_name)
|
|
213
|
+
|
|
214
|
+
if isinstance(exc, bs_config.InvalidEnvironmentName):
|
|
215
|
+
return EnvironmentNameInvalid(environment_name)
|
|
216
|
+
|
|
217
|
+
return SandboxUnavailable(environment_name, str(exc))
|
|
218
|
+
|
|
219
|
+
|
|
58
220
|
RUN_DESCRIPTION = f"""\
|
|
59
221
|
Run a shell command inside the bubblewrap sandbox.
|
|
60
222
|
|
|
@@ -69,8 +231,10 @@ pass ``command`` as a single string; it is run via "sh -c".
|
|
|
69
231
|
- Otherwise pass ``command`` as a list of strings: the executable name \
|
|
70
232
|
or path first, then one element per argument. This form needs no \
|
|
71
233
|
quoting and is the safer default.
|
|
72
|
-
- ``environment_name`` selects the environment to run in
|
|
73
|
-
|
|
234
|
+
- ``environment_name`` selects the environment to run in. Pass only a \
|
|
235
|
+
``name`` that ``list_environments`` returned in this conversation -- \
|
|
236
|
+
never a guessed name, a package name, or a name copied from an example. \
|
|
237
|
+
Omit it to use the configured default.
|
|
74
238
|
- ``timeout`` caps the run in seconds; omit it to use the configured \
|
|
75
239
|
default.
|
|
76
240
|
- Paths must be absolute and sandbox-visible: read inputs from \
|
|
@@ -159,8 +323,11 @@ async def skill_run(
|
|
|
159
323
|
timeout=timeout,
|
|
160
324
|
extra_volumes=extra_volumes,
|
|
161
325
|
)
|
|
162
|
-
except
|
|
163
|
-
|
|
326
|
+
except EXECUTION_ERRORS as exc:
|
|
327
|
+
raise translate_execution_error(
|
|
328
|
+
exc,
|
|
329
|
+
environment_name=environment_name,
|
|
330
|
+
) from exc
|
|
164
331
|
|
|
165
332
|
output = result.output
|
|
166
333
|
if result.truncated:
|
|
@@ -182,9 +349,10 @@ Do NOT pass shell commands — use the ``run`` tool for those.
|
|
|
182
349
|
- Pass a complete, self-contained Python script as the ``script`` string.
|
|
183
350
|
- The script runs via the Python interpreter built into the chosen \
|
|
184
351
|
environment, with access to its pre-installed packages.
|
|
185
|
-
-
|
|
186
|
-
and their installed packages. ``environment_name``
|
|
187
|
-
it
|
|
352
|
+
- Call ``list_environments`` first to discover available environments \
|
|
353
|
+
and their installed packages. ``environment_name`` must be one of the \
|
|
354
|
+
``name`` values it returned -- never a guessed name, a package name, or \
|
|
355
|
+
a name copied from an example. Omit it to use the configured default.
|
|
188
356
|
- ``timeout`` caps the run in seconds; omit it to use the configured \
|
|
189
357
|
default.
|
|
190
358
|
- Print results to stdout — the output is captured and returned.
|
|
@@ -235,8 +403,11 @@ async def skill_run_python(
|
|
|
235
403
|
timeout=timeout,
|
|
236
404
|
extra_volumes=extra_volumes,
|
|
237
405
|
)
|
|
238
|
-
except
|
|
239
|
-
|
|
406
|
+
except EXECUTION_ERRORS as exc:
|
|
407
|
+
raise translate_execution_error(
|
|
408
|
+
exc,
|
|
409
|
+
environment_name=environment_name,
|
|
410
|
+
) from exc
|
|
240
411
|
|
|
241
412
|
output = result.output
|
|
242
413
|
if result.truncated:
|
|
@@ -434,6 +605,12 @@ def create_sandbox_toolset(
|
|
|
434
605
|
environment_name: str | None = None,
|
|
435
606
|
timeout: float | None = None, # seconds
|
|
436
607
|
) -> str:
|
|
608
|
+
await check_environment_name(
|
|
609
|
+
bwrap_sandbox=bwrap_sandbox,
|
|
610
|
+
environment_name=environment_name,
|
|
611
|
+
allowed_environments=allowed_environments,
|
|
612
|
+
)
|
|
613
|
+
|
|
437
614
|
deps = ctx.deps
|
|
438
615
|
workdir = get_workdir(
|
|
439
616
|
workdirs_path,
|
|
@@ -486,6 +663,12 @@ def create_sandbox_toolset(
|
|
|
486
663
|
environment_name: str | None = None,
|
|
487
664
|
timeout: float | None = None, # seconds
|
|
488
665
|
) -> str:
|
|
666
|
+
await check_environment_name(
|
|
667
|
+
bwrap_sandbox=bwrap_sandbox,
|
|
668
|
+
environment_name=environment_name,
|
|
669
|
+
allowed_environments=allowed_environments,
|
|
670
|
+
)
|
|
671
|
+
|
|
489
672
|
deps = ctx.deps
|
|
490
673
|
workdir = get_workdir(
|
|
491
674
|
workdirs_path,
|
|
@@ -570,11 +753,12 @@ def create_bwrap_sandbox_capability(
|
|
|
570
753
|
volumes: bs_models.VolumeMap | None = None,
|
|
571
754
|
max_retries: int = 1,
|
|
572
755
|
installation_config=None, # noqa F821 cycles
|
|
756
|
+
defer_loading: bool = False,
|
|
573
757
|
) -> SandboxCapability:
|
|
574
758
|
return SandboxCapability(
|
|
575
759
|
id=id or SKILL_PROPERTIES.name,
|
|
576
760
|
description=SKILL_PROPERTIES.description.strip(),
|
|
577
|
-
defer_loading=
|
|
761
|
+
defer_loading=defer_loading,
|
|
578
762
|
default_environment=default_environment,
|
|
579
763
|
allowed_environments=allowed_environments,
|
|
580
764
|
sandbox_config=sandbox_config,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: soliplex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.78
|
|
4
4
|
Summary: An AI-powered Retrieval-Augmented Generation (RAG) system with a modern web interface.
|
|
5
5
|
Author-email: Enfold <info@enfoldsystems.net>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
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
|
|
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
|
|
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
|