orxtra 0.1.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.
- orxtra-0.1.0/.gitignore +23 -0
- orxtra-0.1.0/LICENSE +61 -0
- orxtra-0.1.0/PKG-INFO +16 -0
- orxtra-0.1.0/agent/pyproject.toml +20 -0
- orxtra-0.1.0/agent/src/orxtra/agent/__init__.py +18 -0
- orxtra-0.1.0/agent/src/orxtra/agent/_categories.py +29 -0
- orxtra-0.1.0/agent/src/orxtra/agent/_loader.py +61 -0
- orxtra-0.1.0/agent/src/orxtra/agent/_prompt.py +57 -0
- orxtra-0.1.0/agent/src/orxtra/agent/_types.py +29 -0
- orxtra-0.1.0/agent/src/orxtra/agent/py.typed +0 -0
- orxtra-0.1.0/cli/pyproject.toml +26 -0
- orxtra-0.1.0/cli/src/orxtra/cli/__init__.py +0 -0
- orxtra-0.1.0/cli/src/orxtra/cli/_cli.py +527 -0
- orxtra-0.1.0/cli/src/orxtra/cli/_formatters.py +108 -0
- orxtra-0.1.0/cli/src/orxtra/cli/py.typed +0 -0
- orxtra-0.1.0/knowledge-module/pyproject.toml +18 -0
- orxtra-0.1.0/knowledge-module/src/orxtra/knowledge_module/__init__.py +26 -0
- orxtra-0.1.0/knowledge-module/src/orxtra/knowledge_module/_cognee_import.py +20 -0
- orxtra-0.1.0/knowledge-module/src/orxtra/knowledge_module/_config.py +25 -0
- orxtra-0.1.0/knowledge-module/src/orxtra/knowledge_module/_freshness.py +34 -0
- orxtra-0.1.0/knowledge-module/src/orxtra/knowledge_module/_ingest.py +68 -0
- orxtra-0.1.0/knowledge-module/src/orxtra/knowledge_module/_retrieve.py +57 -0
- orxtra-0.1.0/knowledge-module/src/orxtra/knowledge_module/_types.py +61 -0
- orxtra-0.1.0/knowledge-module/src/orxtra/knowledge_module/py.typed +0 -0
- orxtra-0.1.0/mcp/pyproject.toml +27 -0
- orxtra-0.1.0/mcp/src/orxtra/mcp/__init__.py +9 -0
- orxtra-0.1.0/mcp/src/orxtra/mcp/_server.py +383 -0
- orxtra-0.1.0/mcp/src/orxtra/mcp/_tools.py +239 -0
- orxtra-0.1.0/mcp/src/orxtra/mcp/py.typed +0 -0
- orxtra-0.1.0/notepad/pyproject.toml +27 -0
- orxtra-0.1.0/notepad/src/orxtra/notepad/__init__.py +10 -0
- orxtra-0.1.0/notepad/src/orxtra/notepad/_reader.py +45 -0
- orxtra-0.1.0/notepad/src/orxtra/notepad/_types.py +5 -0
- orxtra-0.1.0/notepad/src/orxtra/notepad/py.typed +0 -0
- orxtra-0.1.0/overseer/prompts/overseer_base.md +162 -0
- orxtra-0.1.0/overseer/pyproject.toml +36 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/__init__.py +20 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_autonomy.py +15 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_handoff.py +65 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_health.py +81 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_inbox.py +28 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_knowledge.py +73 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_learning.py +95 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_memory.py +169 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_overseer.py +148 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/_tools.py +207 -0
- orxtra-0.1.0/overseer/src/orxtra/overseer/py.typed +0 -0
- orxtra-0.1.0/protocols/pyproject.toml +17 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/__init__.py +94 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_autonomy.py +46 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_checks.py +51 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_constraints.py +26 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_errors.py +11 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_events.py +113 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_execution.py +70 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_task.py +118 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_tool.py +20 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/_tools.py +136 -0
- orxtra-0.1.0/protocols/src/orxtra/protocols/py.typed +0 -0
- orxtra-0.1.0/pyproject.toml +195 -0
- orxtra-0.1.0/scheduler/pyproject.toml +42 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/__init__.py +67 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_agent_execution.py +1177 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_base.py +346 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_enforcement.py +704 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_events.py +50 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_executor.py +1006 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_graph.py +130 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_lifecycle_handlers.py +338 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_loader.py +177 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_locks.py +28 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_overseer.py +636 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_services.py +79 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_task_dispatch.py +491 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_types.py +63 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/_validator.py +181 -0
- orxtra-0.1.0/scheduler/src/orxtra/scheduler/py.typed +0 -0
- orxtra-0.1.0/secrets/pyproject.toml +18 -0
- orxtra-0.1.0/secrets/src/orxtra/secrets/__init__.py +3 -0
- orxtra-0.1.0/secrets/src/orxtra/secrets/_registry.py +39 -0
- orxtra-0.1.0/secrets/src/orxtra/secrets/py.typed +0 -0
- orxtra-0.1.0/services/pyproject.toml +32 -0
- orxtra-0.1.0/services/src/orxtra/services/__init__.py +62 -0
- orxtra-0.1.0/services/src/orxtra/services/_config.py +37 -0
- orxtra-0.1.0/services/src/orxtra/services/_events.py +17 -0
- orxtra-0.1.0/services/src/orxtra/services/_inbox.py +49 -0
- orxtra-0.1.0/services/src/orxtra/services/_run.py +131 -0
- orxtra-0.1.0/services/src/orxtra/services/_trace.py +87 -0
- orxtra-0.1.0/services/src/orxtra/services/_validate.py +36 -0
- orxtra-0.1.0/services/src/orxtra/services/py.typed +0 -0
- orxtra-0.1.0/session/pyproject.toml +25 -0
- orxtra-0.1.0/session/src/orxtra/session/__init__.py +13 -0
- orxtra-0.1.0/session/src/orxtra/session/_factory.py +56 -0
- orxtra-0.1.0/session/src/orxtra/session/_pricing.py +79 -0
- orxtra-0.1.0/session/src/orxtra/session/_session.py +243 -0
- orxtra-0.1.0/session/src/orxtra/session/py.typed +0 -0
- orxtra-0.1.0/tool/pyproject.toml +33 -0
- orxtra-0.1.0/tool/src/orxtra/tool/__init__.py +91 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_consult_tool.py +120 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_exec_tool.py +124 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_git_tool.py +215 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_http_tool.py +129 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_notepad_tool.py +66 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_path.py +70 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_pipeline.py +123 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_preview.py +91 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_read_tools.py +853 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_shell_tool.py +147 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_task_tools.py +335 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_validation.py +23 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_write_integration.py +74 -0
- orxtra-0.1.0/tool/src/orxtra/tool/_write_tools.py +433 -0
- orxtra-0.1.0/tool/src/orxtra/tool/py.typed +0 -0
- orxtra-0.1.0/trace/pyproject.toml +19 -0
- orxtra-0.1.0/trace/src/orxtra/trace/__init__.py +75 -0
- orxtra-0.1.0/trace/src/orxtra/trace/_lock.py +54 -0
- orxtra-0.1.0/trace/src/orxtra/trace/_reader.py +223 -0
- orxtra-0.1.0/trace/src/orxtra/trace/_recovery.py +88 -0
- orxtra-0.1.0/trace/src/orxtra/trace/_schema.py +310 -0
- orxtra-0.1.0/trace/src/orxtra/trace/_transitions.py +57 -0
- orxtra-0.1.0/trace/src/orxtra/trace/_types.py +120 -0
- orxtra-0.1.0/trace/src/orxtra/trace/_writer.py +649 -0
- orxtra-0.1.0/trace/src/orxtra/trace/py.typed +0 -0
- orxtra-0.1.0/transport/pyproject.toml +29 -0
- orxtra-0.1.0/transport/src/orxtra/transport/__init__.py +45 -0
- orxtra-0.1.0/transport/src/orxtra/transport/_events.py +131 -0
- orxtra-0.1.0/transport/src/orxtra/transport/_provider.py +48 -0
- orxtra-0.1.0/transport/src/orxtra/transport/_state_machine.py +23 -0
- orxtra-0.1.0/transport/src/orxtra/transport/_transport.py +832 -0
- orxtra-0.1.0/transport/src/orxtra/transport/providers/__init__.py +9 -0
- orxtra-0.1.0/transport/src/orxtra/transport/providers/_anthropic.py +191 -0
- orxtra-0.1.0/transport/src/orxtra/transport/providers/_openai.py +172 -0
- orxtra-0.1.0/transport/src/orxtra/transport/py.typed +0 -0
- orxtra-0.1.0/verify/pyproject.toml +27 -0
- orxtra-0.1.0/verify/src/orxtra/verify/__init__.py +29 -0
- orxtra-0.1.0/verify/src/orxtra/verify/_execution.py +138 -0
- orxtra-0.1.0/verify/src/orxtra/verify/_runner.py +49 -0
- orxtra-0.1.0/verify/src/orxtra/verify/_types.py +23 -0
- orxtra-0.1.0/verify/src/orxtra/verify/py.typed +0 -0
- orxtra-0.1.0/write-safety/pyproject.toml +21 -0
- orxtra-0.1.0/write-safety/src/orxtra/write_safety/__init__.py +16 -0
- orxtra-0.1.0/write-safety/src/orxtra/write_safety/_atomic.py +30 -0
- orxtra-0.1.0/write-safety/src/orxtra/write_safety/_queue.py +39 -0
- orxtra-0.1.0/write-safety/src/orxtra/write_safety/_replay.py +42 -0
- orxtra-0.1.0/write-safety/src/orxtra/write_safety/_stale.py +72 -0
- orxtra-0.1.0/write-safety/src/orxtra/write_safety/py.typed +0 -0
orxtra-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.pyc
|
|
3
|
+
.venv/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.mypy_cache/
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
docs/_build/
|
|
11
|
+
.env
|
|
12
|
+
node_modules/
|
|
13
|
+
|
|
14
|
+
*.log
|
|
15
|
+
.DS_Store
|
|
16
|
+
coverage/
|
|
17
|
+
.rlsbl-notes-*.tmp
|
|
18
|
+
.rlsbl/lock
|
|
19
|
+
.rlsbl-monorepo/lock
|
|
20
|
+
.credentials.json
|
|
21
|
+
.*-cache.json
|
|
22
|
+
.env.local
|
|
23
|
+
*.local-only
|
orxtra-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
|
|
2
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
3
|
+
|
|
4
|
+
Parameters
|
|
5
|
+
|
|
6
|
+
Licensor: SMM-H
|
|
7
|
+
Licensed Work: orxtra. The Licensed Work is (c) 2026 SMM-H.
|
|
8
|
+
Additional Use Grant: You may make non-production use of the Licensed Work
|
|
9
|
+
for purposes of development, testing, evaluation, and
|
|
10
|
+
education. Production use of the Licensed Work requires
|
|
11
|
+
a commercial license from the Licensor.
|
|
12
|
+
Change Date: 2030-06-19
|
|
13
|
+
Change License: Apache License, Version 2.0
|
|
14
|
+
|
|
15
|
+
For information about alternative licensing arrangements for the Licensed
|
|
16
|
+
Work, please contact i@smmh.dev.
|
|
17
|
+
|
|
18
|
+
Notice
|
|
19
|
+
|
|
20
|
+
Business Source License 1.1
|
|
21
|
+
|
|
22
|
+
Terms
|
|
23
|
+
|
|
24
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
25
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
26
|
+
Licensor may make an Additional Use Grant, above, permitting limited production use.
|
|
27
|
+
|
|
28
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
29
|
+
available distribution of a specific version of the Licensed Work under this
|
|
30
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
31
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
32
|
+
above terminate.
|
|
33
|
+
|
|
34
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
35
|
+
currently in effect as described in this License, you must purchase a
|
|
36
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
37
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
38
|
+
|
|
39
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
40
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
41
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
42
|
+
for each version of the Licensed Work released by Licensor.
|
|
43
|
+
|
|
44
|
+
You must conspicuously display this License on each original or modified copy
|
|
45
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
46
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
47
|
+
License apply to your use of that work.
|
|
48
|
+
|
|
49
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
50
|
+
terminate your rights under this License for the current and all other
|
|
51
|
+
versions of the Licensed Work.
|
|
52
|
+
|
|
53
|
+
This License does not grant you any right in any trademark or logo of
|
|
54
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
55
|
+
Licensor as expressly required by this License).
|
|
56
|
+
|
|
57
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
58
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
59
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
60
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
61
|
+
TITLE.
|
orxtra-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: orxtra
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Autonomous multi-agent AI workflows
|
|
5
|
+
License-Expression: BUSL-1.1
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: rlsbl
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Requires-Dist: asyncpg
|
|
10
|
+
Requires-Dist: cognee
|
|
11
|
+
Requires-Dist: httpx
|
|
12
|
+
Requires-Dist: jsonschema
|
|
13
|
+
Requires-Dist: pathspec
|
|
14
|
+
Requires-Dist: pydantic>=2
|
|
15
|
+
Requires-Dist: strictcli
|
|
16
|
+
Requires-Dist: uuid6
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "orxtra-agent"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
license = "BUSL-1.1"
|
|
5
|
+
description = "Agent definition loader. TOML + composable .md prompts, strict validation, category resolution."
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"pydantic>=2",
|
|
9
|
+
]
|
|
10
|
+
keywords = ["rlsbl"]
|
|
11
|
+
|
|
12
|
+
[dependency-groups]
|
|
13
|
+
dev = ["pytest>=9.1.0"]
|
|
14
|
+
|
|
15
|
+
[build-system]
|
|
16
|
+
requires = ["hatchling"]
|
|
17
|
+
build-backend = "hatchling.build"
|
|
18
|
+
|
|
19
|
+
[tool.hatch.build.targets.wheel]
|
|
20
|
+
packages = ["src/orxtra"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from orxtra.agent._categories import load_categories, resolve_category
|
|
4
|
+
from orxtra.agent._loader import load_agent, load_agents
|
|
5
|
+
from orxtra.agent._prompt import resolve_includes, resolve_prompt
|
|
6
|
+
from orxtra.agent._types import Agent, ExecToolConfig, ShellConfig
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Agent",
|
|
10
|
+
"ExecToolConfig",
|
|
11
|
+
"ShellConfig",
|
|
12
|
+
"load_agent",
|
|
13
|
+
"load_agents",
|
|
14
|
+
"load_categories",
|
|
15
|
+
"resolve_category",
|
|
16
|
+
"resolve_includes",
|
|
17
|
+
"resolve_prompt",
|
|
18
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import tomllib
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from orxtra.agent._types import Agent
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_categories(path: Path) -> dict[str, str]:
|
|
13
|
+
if not path.is_file():
|
|
14
|
+
msg = f"Categories file not found: {path}"
|
|
15
|
+
raise FileNotFoundError(msg)
|
|
16
|
+
with path.open("rb") as f:
|
|
17
|
+
data = tomllib.load(f)
|
|
18
|
+
if "categories" not in data:
|
|
19
|
+
msg = f"Missing [categories] section in {path}"
|
|
20
|
+
raise ValueError(msg)
|
|
21
|
+
categories: dict[str, str] = data["categories"]
|
|
22
|
+
return categories
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def resolve_category(agent: Agent, categories: dict[str, str]) -> str:
|
|
26
|
+
if agent.category not in categories:
|
|
27
|
+
msg = f"Unknown category: {agent.category}"
|
|
28
|
+
raise ValueError(msg)
|
|
29
|
+
return categories[agent.category]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import tomllib
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
|
+
|
|
6
|
+
from orxtra.agent._prompt import resolve_includes
|
|
7
|
+
from orxtra.agent._types import Agent
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_agent(path: Path) -> Agent:
|
|
14
|
+
if not path.is_file():
|
|
15
|
+
msg = f"Agent file not found: {path}"
|
|
16
|
+
raise FileNotFoundError(msg)
|
|
17
|
+
with path.open("rb") as f:
|
|
18
|
+
data = tomllib.load(f)
|
|
19
|
+
|
|
20
|
+
agent_section: dict[str, Any] = dict(data.get("agent", {}))
|
|
21
|
+
if "tools" not in data:
|
|
22
|
+
msg = f"Missing [tools] section in {path}"
|
|
23
|
+
raise ValueError(msg)
|
|
24
|
+
tools_section: dict[str, Any] = data["tools"]
|
|
25
|
+
|
|
26
|
+
prompt_rel = agent_section.pop("prompt", "")
|
|
27
|
+
prompt_path = (path.parent / prompt_rel).resolve()
|
|
28
|
+
if not prompt_path.is_file():
|
|
29
|
+
msg = f"Prompt file not found: {prompt_path}"
|
|
30
|
+
raise FileNotFoundError(msg)
|
|
31
|
+
prompt_text = prompt_path.read_text()
|
|
32
|
+
prompt_text = resolve_includes(prompt_text, prompt_path.parent)
|
|
33
|
+
|
|
34
|
+
agent_section["prompt"] = prompt_text
|
|
35
|
+
if "allow" not in tools_section:
|
|
36
|
+
msg = f"Missing 'allow' key in [tools] section in {path}"
|
|
37
|
+
raise ValueError(msg)
|
|
38
|
+
unknown_keys = set(tools_section.keys()) - {"allow"}
|
|
39
|
+
if unknown_keys:
|
|
40
|
+
names = ", ".join(sorted(unknown_keys))
|
|
41
|
+
msg = f"Unknown keys in [tools] section: {names}"
|
|
42
|
+
raise ValueError(msg)
|
|
43
|
+
agent_section["allow"] = tools_section["allow"]
|
|
44
|
+
|
|
45
|
+
exec_configs: list[dict[str, Any]] = data.get("exec", [])
|
|
46
|
+
shell_section: dict[str, Any] | None = data.get("shell")
|
|
47
|
+
agent_section["exec_tools"] = exec_configs
|
|
48
|
+
agent_section["shell_config"] = shell_section
|
|
49
|
+
|
|
50
|
+
return Agent(**agent_section)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def load_agents(directory: Path) -> dict[str, Agent]:
|
|
54
|
+
agents: dict[str, Agent] = {}
|
|
55
|
+
for toml_path in sorted(directory.glob("*.toml")):
|
|
56
|
+
agent = load_agent(toml_path)
|
|
57
|
+
if agent.name in agents:
|
|
58
|
+
msg = f"Duplicate agent name: {agent.name}"
|
|
59
|
+
raise ValueError(msg)
|
|
60
|
+
agents[agent.name] = agent
|
|
61
|
+
return agents
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
_INCLUDE_RE = re.compile(r"\{include:([^}]+)\}")
|
|
10
|
+
_VAR_RE = re.compile(r"\{([a-zA-Z_][a-zA-Z0-9_]*)\}")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def resolve_includes(template: str, base_dir: Path) -> str:
|
|
14
|
+
return _resolve_includes(template, base_dir, frozenset())
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _resolve_includes(
|
|
18
|
+
template: str, base_dir: Path, seen: frozenset[Path]
|
|
19
|
+
) -> str:
|
|
20
|
+
def replacer(match: re.Match[str]) -> str:
|
|
21
|
+
rel_path = match.group(1)
|
|
22
|
+
abs_path = (base_dir / rel_path).resolve()
|
|
23
|
+
if abs_path in seen:
|
|
24
|
+
msg = f"Circular include detected: {abs_path}"
|
|
25
|
+
raise ValueError(msg)
|
|
26
|
+
if not abs_path.is_file():
|
|
27
|
+
msg = f"Include file not found: {abs_path}"
|
|
28
|
+
raise FileNotFoundError(msg)
|
|
29
|
+
content = abs_path.read_text()
|
|
30
|
+
return _resolve_includes(content, abs_path.parent, seen | {abs_path})
|
|
31
|
+
|
|
32
|
+
return _INCLUDE_RE.sub(replacer, template)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def resolve_prompt(template: str, variables: dict[str, str]) -> str:
|
|
36
|
+
placeholders = set(_VAR_RE.findall(template))
|
|
37
|
+
var_keys = set(variables.keys())
|
|
38
|
+
|
|
39
|
+
unresolved = placeholders - var_keys
|
|
40
|
+
if unresolved:
|
|
41
|
+
name = sorted(unresolved)[0]
|
|
42
|
+
msg = f"Unresolved placeholder: {{{name}}}"
|
|
43
|
+
raise ValueError(msg)
|
|
44
|
+
|
|
45
|
+
unused = var_keys - placeholders
|
|
46
|
+
if unused:
|
|
47
|
+
name = sorted(unused)[0]
|
|
48
|
+
msg = f"Unused variable: {name}"
|
|
49
|
+
raise ValueError(msg)
|
|
50
|
+
|
|
51
|
+
if not placeholders:
|
|
52
|
+
return template
|
|
53
|
+
|
|
54
|
+
def replacer(match: re.Match[str]) -> str:
|
|
55
|
+
return variables[match.group(1)]
|
|
56
|
+
|
|
57
|
+
return _VAR_RE.sub(replacer, template)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ExecToolConfig(BaseModel):
|
|
7
|
+
model_config = ConfigDict(frozen=True, strict=True, extra="forbid")
|
|
8
|
+
name: str
|
|
9
|
+
executable: str
|
|
10
|
+
description: str
|
|
11
|
+
timeout_ceiling: int = 300
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ShellConfig(BaseModel):
|
|
15
|
+
model_config = ConfigDict(frozen=True, strict=True, extra="forbid")
|
|
16
|
+
allowed_binaries: list[str]
|
|
17
|
+
description: str = "Execute shell commands with whitelisted binaries"
|
|
18
|
+
timeout_ceiling: int = 300
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Agent(BaseModel):
|
|
22
|
+
model_config = ConfigDict(frozen=True, strict=True, extra="forbid")
|
|
23
|
+
name: str
|
|
24
|
+
description: str
|
|
25
|
+
prompt: str
|
|
26
|
+
category: str
|
|
27
|
+
allow: list[str]
|
|
28
|
+
exec_tools: list[ExecToolConfig] = []
|
|
29
|
+
shell_config: ShellConfig | None = None
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "orxtra-cli"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
license = "BUSL-1.1"
|
|
5
|
+
description = "strictcli CLI frontend. Agents are the primary users."
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"strictcli",
|
|
9
|
+
"orxtra-services",
|
|
10
|
+
"orxtra-trace",
|
|
11
|
+
]
|
|
12
|
+
keywords = ["rlsbl"]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
orxtra = "orxtra.cli._cli:main"
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["hatchling"]
|
|
19
|
+
build-backend = "hatchling.build"
|
|
20
|
+
|
|
21
|
+
[tool.hatch.build.targets.wheel]
|
|
22
|
+
packages = ["src/orxtra"]
|
|
23
|
+
|
|
24
|
+
[tool.uv.sources]
|
|
25
|
+
orxtra-services = { workspace = true }
|
|
26
|
+
orxtra-trace = { workspace = true }
|
|
File without changes
|