aictx 0.3.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.
- aictx-0.3.0/LICENSE +21 -0
- aictx-0.3.0/PKG-INFO +170 -0
- aictx-0.3.0/README.md +152 -0
- aictx-0.3.0/pyproject.toml +41 -0
- aictx-0.3.0/setup.cfg +4 -0
- aictx-0.3.0/src/aictx/__init__.py +4 -0
- aictx-0.3.0/src/aictx/__main__.py +3 -0
- aictx-0.3.0/src/aictx/_version.py +1 -0
- aictx-0.3.0/src/aictx/adapters.py +200 -0
- aictx-0.3.0/src/aictx/agent_runtime.py +201 -0
- aictx-0.3.0/src/aictx/cli.py +585 -0
- aictx-0.3.0/src/aictx/core_runtime.py +1877 -0
- aictx-0.3.0/src/aictx/global_metrics.py +759 -0
- aictx-0.3.0/src/aictx/middleware.py +401 -0
- aictx-0.3.0/src/aictx/runner_integrations.py +372 -0
- aictx-0.3.0/src/aictx/runtime_compat.py +130 -0
- aictx-0.3.0/src/aictx/runtime_contract.py +229 -0
- aictx-0.3.0/src/aictx/runtime_cost.py +445 -0
- aictx-0.3.0/src/aictx/runtime_failure.py +244 -0
- aictx-0.3.0/src/aictx/runtime_graph.py +339 -0
- aictx-0.3.0/src/aictx/runtime_io.py +101 -0
- aictx-0.3.0/src/aictx/runtime_knowledge.py +1098 -0
- aictx-0.3.0/src/aictx/runtime_launcher.py +108 -0
- aictx-0.3.0/src/aictx/runtime_memory.py +280 -0
- aictx-0.3.0/src/aictx/runtime_metrics.py +125 -0
- aictx-0.3.0/src/aictx/runtime_task_memory.py +167 -0
- aictx-0.3.0/src/aictx/runtime_tasks.py +302 -0
- aictx-0.3.0/src/aictx/runtime_versioning.py +92 -0
- aictx-0.3.0/src/aictx/scaffold.py +224 -0
- aictx-0.3.0/src/aictx/state.py +129 -0
- aictx-0.3.0/src/aictx/templates/context_packet_schema.json +34 -0
- aictx-0.3.0/src/aictx/templates/model_routing.json +47 -0
- aictx-0.3.0/src/aictx/templates/user_preferences.json +74 -0
- aictx-0.3.0/src/aictx.egg-info/PKG-INFO +170 -0
- aictx-0.3.0/src/aictx.egg-info/SOURCES.txt +37 -0
- aictx-0.3.0/src/aictx.egg-info/dependency_links.txt +1 -0
- aictx-0.3.0/src/aictx.egg-info/entry_points.txt +2 -0
- aictx-0.3.0/src/aictx.egg-info/top_level.txt +1 -0
- aictx-0.3.0/tests/test_smoke.py +1012 -0
aictx-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Santi Santamaria
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aictx-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aictx
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Repo-native runtime contract and context bootstrapper for coding agents
|
|
5
|
+
Author: Santi Santamaria
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/oldskultxo/aictx
|
|
8
|
+
Project-URL: Repository, https://github.com/oldskultxo/aictx
|
|
9
|
+
Project-URL: Issues, https://github.com/oldskultxo/aictx/issues
|
|
10
|
+
Keywords: ai,llm,coding-agents,developer-tools,context-engine,codex,claude
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# aictx
|
|
20
|
+
|
|
21
|
+
**Install once. Initialize a repo. Give coding agents a real runtime contract.**
|
|
22
|
+
|
|
23
|
+
`aictx` turns a normal repository into a repository that is prepared for coding agents.
|
|
24
|
+
|
|
25
|
+
## Product surface
|
|
26
|
+
|
|
27
|
+
The sellable user flow stays intentionally small:
|
|
28
|
+
|
|
29
|
+
1. `aictx install`
|
|
30
|
+
2. `aictx init`
|
|
31
|
+
3. use Codex, Claude Code, or your normal automation
|
|
32
|
+
|
|
33
|
+
Everything else exists to support that runtime, not to expand the primary UX.
|
|
34
|
+
|
|
35
|
+
## What it really does today
|
|
36
|
+
|
|
37
|
+
After `install + init`, `aictx` can provide:
|
|
38
|
+
|
|
39
|
+
- repo-local bootstrap memory under `.ai_context_engine/`
|
|
40
|
+
- packet-oriented context for non-trivial work
|
|
41
|
+
- task memory, failure memory, and memory graph scaffolds
|
|
42
|
+
- repo-native instruction integration for Codex and Claude Code
|
|
43
|
+
- wrapped middleware for generic automation via `aictx internal run-execution`
|
|
44
|
+
- local/global telemetry and health artifacts
|
|
45
|
+
|
|
46
|
+
## Honest limits
|
|
47
|
+
|
|
48
|
+
This is still a **0.x beta** product.
|
|
49
|
+
|
|
50
|
+
- final behavior depends on each runner honoring its instruction and hook system
|
|
51
|
+
- telemetry quality is best-effort unless confidence is explicitly high
|
|
52
|
+
- advanced/internal commands are supported, but not the main thing being sold
|
|
53
|
+
- some deeper capabilities are still being extracted from the canonical engine
|
|
54
|
+
|
|
55
|
+
See [docs/LIMITATIONS.md](docs/LIMITATIONS.md).
|
|
56
|
+
|
|
57
|
+
## Install from PyPI
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install aictx
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
aictx install
|
|
67
|
+
aictx init --repo .
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Install once
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
aictx install
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Non-interactive:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
aictx install --yes --workspace-root ~/projects
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This creates the global runtime under `~/.ai_context_engine/` and provisions:
|
|
83
|
+
|
|
84
|
+
- global configuration
|
|
85
|
+
- workspace registry
|
|
86
|
+
- adapters and wrappers
|
|
87
|
+
- global telemetry storage
|
|
88
|
+
- global Codex instructions
|
|
89
|
+
|
|
90
|
+
## Initialize a repo
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
aictx init
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Non-interactive:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
aictx init --repo . --yes
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`init` creates:
|
|
103
|
+
|
|
104
|
+
- `.ai_context_engine/memory/`
|
|
105
|
+
- `.ai_context_engine/cost/`
|
|
106
|
+
- `.ai_context_engine/task_memory/`
|
|
107
|
+
- `.ai_context_engine/failure_memory/`
|
|
108
|
+
- `.ai_context_engine/memory_graph/`
|
|
109
|
+
- `.ai_context_engine/library/`
|
|
110
|
+
- `.ai_context_engine/metrics/`
|
|
111
|
+
- `.ai_context_engine/adapters/`
|
|
112
|
+
- `.ai_context_engine/state.json`
|
|
113
|
+
- `.ai_context_engine/agent_runtime.md`
|
|
114
|
+
|
|
115
|
+
And native repo integration files:
|
|
116
|
+
|
|
117
|
+
- `AGENTS.md`
|
|
118
|
+
- `AGENTS.override.md`
|
|
119
|
+
- `CLAUDE.md`
|
|
120
|
+
- `.claude/settings.json`
|
|
121
|
+
- `.claude/hooks/...`
|
|
122
|
+
- `.gitignore`
|
|
123
|
+
|
|
124
|
+
## Runtime consistency
|
|
125
|
+
|
|
126
|
+
`aictx boot --repo <path>` and `aictx execution prepare ...` now expose:
|
|
127
|
+
|
|
128
|
+
- effective communication policy
|
|
129
|
+
- communication source precedence
|
|
130
|
+
- runtime consistency checks between repo preferences and repo state
|
|
131
|
+
|
|
132
|
+
Precedence is:
|
|
133
|
+
|
|
134
|
+
`explicit user instruction > repo prefs > global defaults > hardcoded fallback`
|
|
135
|
+
|
|
136
|
+
## Public beta posture
|
|
137
|
+
|
|
138
|
+
`aictx` is now distributed publicly as a **beta 0.x** package.
|
|
139
|
+
|
|
140
|
+
- installation is supported through PyPI and GitHub releases
|
|
141
|
+
- the core user flow is `pip install aictx` -> `aictx install` -> `aictx init`
|
|
142
|
+
- compatibility is still best-effort, not a long-term 1.0 stability promise
|
|
143
|
+
|
|
144
|
+
## Development quickstart
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
python3 -m venv .venv
|
|
148
|
+
.venv/bin/pip install --upgrade pip
|
|
149
|
+
.venv/bin/pip install -e . pytest build
|
|
150
|
+
make test
|
|
151
|
+
make smoke
|
|
152
|
+
make package-check
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
You can also call the installed script directly:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
.venv/bin/aictx --help
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Public release validation also checks clean wheel installation, not just editable installs.
|
|
162
|
+
|
|
163
|
+
## Read next
|
|
164
|
+
|
|
165
|
+
- [Usage guide](docs/USAGE.md)
|
|
166
|
+
- [Technical overview](docs/TECHNICAL_OVERVIEW.md)
|
|
167
|
+
- [5-minute demo](docs/DEMO.md)
|
|
168
|
+
- [Current limitations](docs/LIMITATIONS.md)
|
|
169
|
+
- [Phase 2 notes](docs/PHASE2_NOTES.md)
|
|
170
|
+
- [Release checklist](docs/RELEASE_CHECKLIST.md)
|
aictx-0.3.0/README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# aictx
|
|
2
|
+
|
|
3
|
+
**Install once. Initialize a repo. Give coding agents a real runtime contract.**
|
|
4
|
+
|
|
5
|
+
`aictx` turns a normal repository into a repository that is prepared for coding agents.
|
|
6
|
+
|
|
7
|
+
## Product surface
|
|
8
|
+
|
|
9
|
+
The sellable user flow stays intentionally small:
|
|
10
|
+
|
|
11
|
+
1. `aictx install`
|
|
12
|
+
2. `aictx init`
|
|
13
|
+
3. use Codex, Claude Code, or your normal automation
|
|
14
|
+
|
|
15
|
+
Everything else exists to support that runtime, not to expand the primary UX.
|
|
16
|
+
|
|
17
|
+
## What it really does today
|
|
18
|
+
|
|
19
|
+
After `install + init`, `aictx` can provide:
|
|
20
|
+
|
|
21
|
+
- repo-local bootstrap memory under `.ai_context_engine/`
|
|
22
|
+
- packet-oriented context for non-trivial work
|
|
23
|
+
- task memory, failure memory, and memory graph scaffolds
|
|
24
|
+
- repo-native instruction integration for Codex and Claude Code
|
|
25
|
+
- wrapped middleware for generic automation via `aictx internal run-execution`
|
|
26
|
+
- local/global telemetry and health artifacts
|
|
27
|
+
|
|
28
|
+
## Honest limits
|
|
29
|
+
|
|
30
|
+
This is still a **0.x beta** product.
|
|
31
|
+
|
|
32
|
+
- final behavior depends on each runner honoring its instruction and hook system
|
|
33
|
+
- telemetry quality is best-effort unless confidence is explicitly high
|
|
34
|
+
- advanced/internal commands are supported, but not the main thing being sold
|
|
35
|
+
- some deeper capabilities are still being extracted from the canonical engine
|
|
36
|
+
|
|
37
|
+
See [docs/LIMITATIONS.md](docs/LIMITATIONS.md).
|
|
38
|
+
|
|
39
|
+
## Install from PyPI
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install aictx
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Then:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
aictx install
|
|
49
|
+
aictx init --repo .
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Install once
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
aictx install
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Non-interactive:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
aictx install --yes --workspace-root ~/projects
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This creates the global runtime under `~/.ai_context_engine/` and provisions:
|
|
65
|
+
|
|
66
|
+
- global configuration
|
|
67
|
+
- workspace registry
|
|
68
|
+
- adapters and wrappers
|
|
69
|
+
- global telemetry storage
|
|
70
|
+
- global Codex instructions
|
|
71
|
+
|
|
72
|
+
## Initialize a repo
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
aictx init
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Non-interactive:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
aictx init --repo . --yes
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`init` creates:
|
|
85
|
+
|
|
86
|
+
- `.ai_context_engine/memory/`
|
|
87
|
+
- `.ai_context_engine/cost/`
|
|
88
|
+
- `.ai_context_engine/task_memory/`
|
|
89
|
+
- `.ai_context_engine/failure_memory/`
|
|
90
|
+
- `.ai_context_engine/memory_graph/`
|
|
91
|
+
- `.ai_context_engine/library/`
|
|
92
|
+
- `.ai_context_engine/metrics/`
|
|
93
|
+
- `.ai_context_engine/adapters/`
|
|
94
|
+
- `.ai_context_engine/state.json`
|
|
95
|
+
- `.ai_context_engine/agent_runtime.md`
|
|
96
|
+
|
|
97
|
+
And native repo integration files:
|
|
98
|
+
|
|
99
|
+
- `AGENTS.md`
|
|
100
|
+
- `AGENTS.override.md`
|
|
101
|
+
- `CLAUDE.md`
|
|
102
|
+
- `.claude/settings.json`
|
|
103
|
+
- `.claude/hooks/...`
|
|
104
|
+
- `.gitignore`
|
|
105
|
+
|
|
106
|
+
## Runtime consistency
|
|
107
|
+
|
|
108
|
+
`aictx boot --repo <path>` and `aictx execution prepare ...` now expose:
|
|
109
|
+
|
|
110
|
+
- effective communication policy
|
|
111
|
+
- communication source precedence
|
|
112
|
+
- runtime consistency checks between repo preferences and repo state
|
|
113
|
+
|
|
114
|
+
Precedence is:
|
|
115
|
+
|
|
116
|
+
`explicit user instruction > repo prefs > global defaults > hardcoded fallback`
|
|
117
|
+
|
|
118
|
+
## Public beta posture
|
|
119
|
+
|
|
120
|
+
`aictx` is now distributed publicly as a **beta 0.x** package.
|
|
121
|
+
|
|
122
|
+
- installation is supported through PyPI and GitHub releases
|
|
123
|
+
- the core user flow is `pip install aictx` -> `aictx install` -> `aictx init`
|
|
124
|
+
- compatibility is still best-effort, not a long-term 1.0 stability promise
|
|
125
|
+
|
|
126
|
+
## Development quickstart
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
python3 -m venv .venv
|
|
130
|
+
.venv/bin/pip install --upgrade pip
|
|
131
|
+
.venv/bin/pip install -e . pytest build
|
|
132
|
+
make test
|
|
133
|
+
make smoke
|
|
134
|
+
make package-check
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
You can also call the installed script directly:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
.venv/bin/aictx --help
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Public release validation also checks clean wheel installation, not just editable installs.
|
|
144
|
+
|
|
145
|
+
## Read next
|
|
146
|
+
|
|
147
|
+
- [Usage guide](docs/USAGE.md)
|
|
148
|
+
- [Technical overview](docs/TECHNICAL_OVERVIEW.md)
|
|
149
|
+
- [5-minute demo](docs/DEMO.md)
|
|
150
|
+
- [Current limitations](docs/LIMITATIONS.md)
|
|
151
|
+
- [Phase 2 notes](docs/PHASE2_NOTES.md)
|
|
152
|
+
- [Release checklist](docs/RELEASE_CHECKLIST.md)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "aictx"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Repo-native runtime contract and context bootstrapper for coding agents"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Santi Santamaria" }
|
|
13
|
+
]
|
|
14
|
+
license = "MIT"
|
|
15
|
+
keywords = ["ai", "llm", "coding-agents", "developer-tools", "context-engine", "codex", "claude"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Development Status :: 4 - Beta"
|
|
20
|
+
]
|
|
21
|
+
dependencies = []
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://github.com/oldskultxo/aictx"
|
|
25
|
+
Repository = "https://github.com/oldskultxo/aictx"
|
|
26
|
+
Issues = "https://github.com/oldskultxo/aictx/issues"
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
aictx = "aictx.cli:main"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools]
|
|
32
|
+
package-dir = {"" = "src"}
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
where = ["src"]
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.package-data]
|
|
38
|
+
"aictx" = ["templates/*.json"]
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = ["tests"]
|
aictx-0.3.0/setup.cfg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.0"
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import stat
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from .state import ENGINE_HOME, REPO_ADAPTERS_DIR, write_json, read_json
|
|
8
|
+
|
|
9
|
+
GLOBAL_ADAPTERS_DIR = ENGINE_HOME / "adapters"
|
|
10
|
+
GLOBAL_ADAPTERS_REGISTRY_PATH = GLOBAL_ADAPTERS_DIR / "registry.json"
|
|
11
|
+
GLOBAL_ADAPTERS_BIN_DIR = GLOBAL_ADAPTERS_DIR / "bin"
|
|
12
|
+
GLOBAL_ADAPTERS_INSTALL_STATUS_PATH = GLOBAL_ADAPTERS_DIR / "install_status.json"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def adapter_runtime_contract(adapter_id: str) -> dict[str, Any]:
|
|
16
|
+
return {
|
|
17
|
+
"runtime_entrypoint": "aictx internal run-execution",
|
|
18
|
+
"integration_mode": "wrapper",
|
|
19
|
+
"auto_prepare_finalize": True,
|
|
20
|
+
"requires_request_context": True,
|
|
21
|
+
"wrapper_env": [
|
|
22
|
+
"AICTX_REQUEST",
|
|
23
|
+
"AICTX_REPO",
|
|
24
|
+
"AICTX_EXECUTION_ID",
|
|
25
|
+
"AICTX_AGENT_ID",
|
|
26
|
+
"AICTX_TASK_TYPE",
|
|
27
|
+
"AICTX_EXECUTION_MODE",
|
|
28
|
+
"AICTX_VALIDATED_LEARNING",
|
|
29
|
+
],
|
|
30
|
+
"wrapper_script_name": f"aictx-{adapter_id}-auto",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def adapter_profiles() -> dict[str, dict[str, Any]]:
|
|
35
|
+
return {
|
|
36
|
+
"generic": {
|
|
37
|
+
"adapter_id": "generic",
|
|
38
|
+
"display_name": "Generic multi-LLM runner",
|
|
39
|
+
"family": "multi_llm",
|
|
40
|
+
"middleware_always_on": True,
|
|
41
|
+
"explicit_skill_metadata": False,
|
|
42
|
+
"structured_skill_metadata": True,
|
|
43
|
+
"heuristic_skill_fallback": True,
|
|
44
|
+
"auto_installed": True,
|
|
45
|
+
"runtime_contract": adapter_runtime_contract("generic"),
|
|
46
|
+
},
|
|
47
|
+
"codex": {
|
|
48
|
+
"adapter_id": "codex",
|
|
49
|
+
"display_name": "OpenAI Codex",
|
|
50
|
+
"family": "openai_codex",
|
|
51
|
+
"middleware_always_on": True,
|
|
52
|
+
"explicit_skill_metadata": True,
|
|
53
|
+
"structured_skill_metadata": True,
|
|
54
|
+
"heuristic_skill_fallback": True,
|
|
55
|
+
"expected_skill_metadata_fields": ["skill_id", "skill_name", "skill_path", "source"],
|
|
56
|
+
"auto_installed": True,
|
|
57
|
+
"runtime_contract": adapter_runtime_contract("codex"),
|
|
58
|
+
},
|
|
59
|
+
"claude": {
|
|
60
|
+
"adapter_id": "claude",
|
|
61
|
+
"display_name": "Anthropic Claude",
|
|
62
|
+
"family": "anthropic_claude",
|
|
63
|
+
"middleware_always_on": True,
|
|
64
|
+
"explicit_skill_metadata": True,
|
|
65
|
+
"structured_skill_metadata": True,
|
|
66
|
+
"heuristic_skill_fallback": True,
|
|
67
|
+
"expected_skill_metadata_fields": ["skill_id", "skill_name", "skill_path", "source"],
|
|
68
|
+
"auto_installed": True,
|
|
69
|
+
"runtime_contract": adapter_runtime_contract("claude"),
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def adapter_registry_payload(scope: str) -> dict[str, Any]:
|
|
75
|
+
profiles = adapter_profiles()
|
|
76
|
+
return {
|
|
77
|
+
"version": 1,
|
|
78
|
+
"scope": scope,
|
|
79
|
+
"default_adapter_id": "generic",
|
|
80
|
+
"supported_adapters": sorted(profiles.keys()),
|
|
81
|
+
"middleware_mode": "always_on",
|
|
82
|
+
"skill_detection_contract": {
|
|
83
|
+
"authoritative_signal": "explicit_runner_metadata",
|
|
84
|
+
"structured_fallback": True,
|
|
85
|
+
"heuristic_fallback": True,
|
|
86
|
+
},
|
|
87
|
+
"runtime_contract": {
|
|
88
|
+
"entrypoint": "aictx internal run-execution",
|
|
89
|
+
"integration_mode": "wrapper",
|
|
90
|
+
"supported_runners": sorted(profiles.keys()),
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def write_executable(path: Path, content: str) -> None:
|
|
96
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
97
|
+
path.write_text(content, encoding="utf-8")
|
|
98
|
+
path.chmod(path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def render_wrapper_script(adapter_id: str) -> str:
|
|
102
|
+
return f"""#!/bin/sh
|
|
103
|
+
set -eu
|
|
104
|
+
REQUEST="${{AICTX_REQUEST:-}}"
|
|
105
|
+
if [ -z "$REQUEST" ]; then
|
|
106
|
+
echo "AICTX_REQUEST must be set for {adapter_id} auto wrapper." >&2
|
|
107
|
+
exit 64
|
|
108
|
+
fi
|
|
109
|
+
REPO="${{AICTX_REPO:-.}}"
|
|
110
|
+
EXEC_ID="${{AICTX_EXECUTION_ID:-auto}}"
|
|
111
|
+
AGENT_ID="${{AICTX_AGENT_ID:-{adapter_id}}}"
|
|
112
|
+
TASK_TYPE="${{AICTX_TASK_TYPE:-}}"
|
|
113
|
+
EXEC_MODE="${{AICTX_EXECUTION_MODE:-plain}}"
|
|
114
|
+
VALIDATED="${{AICTX_VALIDATED_LEARNING:-0}}"
|
|
115
|
+
if [ "$VALIDATED" = "1" ] || [ "$VALIDATED" = "true" ]; then
|
|
116
|
+
VALIDATED_FLAG="--validated-learning"
|
|
117
|
+
else
|
|
118
|
+
VALIDATED_FLAG=""
|
|
119
|
+
fi
|
|
120
|
+
if [ -n "$TASK_TYPE" ]; then
|
|
121
|
+
exec aictx internal run-execution --repo "$REPO" --request "$REQUEST" --agent-id "$AGENT_ID" --adapter-id "{adapter_id}" --execution-id "$EXEC_ID" --execution-mode "$EXEC_MODE" $VALIDATED_FLAG --task-type "$TASK_TYPE" -- "$@"
|
|
122
|
+
fi
|
|
123
|
+
exec aictx internal run-execution --repo "$REPO" --request "$REQUEST" --agent-id "$AGENT_ID" --adapter-id "{adapter_id}" --execution-id "$EXEC_ID" --execution-mode "$EXEC_MODE" $VALIDATED_FLAG -- "$@"
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def install_adapter_wrappers() -> list[Path]:
|
|
128
|
+
created: list[Path] = []
|
|
129
|
+
GLOBAL_ADAPTERS_BIN_DIR.mkdir(parents=True, exist_ok=True)
|
|
130
|
+
for adapter_id in sorted(adapter_profiles().keys()):
|
|
131
|
+
wrapper_name = adapter_runtime_contract(adapter_id)["wrapper_script_name"]
|
|
132
|
+
path = GLOBAL_ADAPTERS_BIN_DIR / wrapper_name
|
|
133
|
+
write_executable(path, render_wrapper_script(adapter_id))
|
|
134
|
+
created.append(path)
|
|
135
|
+
return created
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def adapter_install_status_payload(wrapper_paths: list[Path]) -> dict[str, Any]:
|
|
139
|
+
profiles = adapter_profiles()
|
|
140
|
+
wrappers = {
|
|
141
|
+
adapter_id: str(GLOBAL_ADAPTERS_BIN_DIR / profiles[adapter_id]["runtime_contract"]["wrapper_script_name"])
|
|
142
|
+
for adapter_id in sorted(profiles.keys())
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
"version": 1,
|
|
146
|
+
"engine_home": str(ENGINE_HOME),
|
|
147
|
+
"integration_mode": "wrapper",
|
|
148
|
+
"runtime_entrypoint": "aictx internal run-execution",
|
|
149
|
+
"supported_runners": sorted(profiles.keys()),
|
|
150
|
+
"wrappers": wrappers,
|
|
151
|
+
"artifacts": [str(path) for path in wrapper_paths],
|
|
152
|
+
"status": "wrapper_ready",
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def install_global_adapters() -> list[Path]:
|
|
157
|
+
GLOBAL_ADAPTERS_DIR.mkdir(parents=True, exist_ok=True)
|
|
158
|
+
write_json(GLOBAL_ADAPTERS_REGISTRY_PATH, adapter_registry_payload("global"))
|
|
159
|
+
created = [GLOBAL_ADAPTERS_REGISTRY_PATH]
|
|
160
|
+
for adapter_id, payload in adapter_profiles().items():
|
|
161
|
+
path = GLOBAL_ADAPTERS_DIR / f"{adapter_id}.json"
|
|
162
|
+
write_json(path, payload)
|
|
163
|
+
created.append(path)
|
|
164
|
+
wrapper_paths = install_adapter_wrappers()
|
|
165
|
+
created.extend(wrapper_paths)
|
|
166
|
+
write_json(GLOBAL_ADAPTERS_INSTALL_STATUS_PATH, adapter_install_status_payload(wrapper_paths))
|
|
167
|
+
created.append(GLOBAL_ADAPTERS_INSTALL_STATUS_PATH)
|
|
168
|
+
return created
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def install_repo_adapters(repo: Path) -> list[Path]:
|
|
172
|
+
adapters_dir = repo / REPO_ADAPTERS_DIR
|
|
173
|
+
adapters_dir.mkdir(parents=True, exist_ok=True)
|
|
174
|
+
registry_path = adapters_dir / "registry.json"
|
|
175
|
+
write_json(registry_path, adapter_registry_payload("repo"))
|
|
176
|
+
created = [registry_path]
|
|
177
|
+
for adapter_id, payload in adapter_profiles().items():
|
|
178
|
+
path = adapters_dir / f"{adapter_id}.json"
|
|
179
|
+
write_json(path, payload)
|
|
180
|
+
created.append(path)
|
|
181
|
+
return created
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def resolve_adapter_profile(adapter_id: str | None, agent_id: str | None = None, repo_root: Path | None = None) -> dict[str, Any]:
|
|
185
|
+
requested = str(adapter_id or "").strip().lower()
|
|
186
|
+
agent = str(agent_id or "").strip().lower()
|
|
187
|
+
profiles = adapter_profiles()
|
|
188
|
+
resolved_id = requested if requested in profiles else "generic"
|
|
189
|
+
if resolved_id == "generic":
|
|
190
|
+
if "codex" in requested or "codex" in agent:
|
|
191
|
+
resolved_id = "codex"
|
|
192
|
+
elif "claude" in requested or "claude" in agent:
|
|
193
|
+
resolved_id = "claude"
|
|
194
|
+
if repo_root:
|
|
195
|
+
repo_path = repo_root / REPO_ADAPTERS_DIR / f"{resolved_id}.json"
|
|
196
|
+
if repo_path.exists():
|
|
197
|
+
payload = read_json(repo_path, {})
|
|
198
|
+
if payload:
|
|
199
|
+
return payload
|
|
200
|
+
return dict(profiles[resolved_id])
|