ninetrix-sdk 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.
- ninetrix_sdk-0.1.0/.github/workflows/publish.yml +30 -0
- ninetrix_sdk-0.1.0/PKG-INFO +196 -0
- ninetrix_sdk-0.1.0/README.md +180 -0
- ninetrix_sdk-0.1.0/examples/db_tools.py +68 -0
- ninetrix_sdk-0.1.0/pyproject.toml +49 -0
- ninetrix_sdk-0.1.0/src/ninetrix/__init__.py +60 -0
- ninetrix_sdk-0.1.0/src/ninetrix/discover.py +226 -0
- ninetrix_sdk-0.1.0/src/ninetrix/registry.py +129 -0
- ninetrix_sdk-0.1.0/src/ninetrix/schema.py +181 -0
- ninetrix_sdk-0.1.0/src/ninetrix/tool.py +138 -0
- ninetrix_sdk-0.1.0/tests/__init__.py +0 -0
- ninetrix_sdk-0.1.0/tests/test_discover.py +159 -0
- ninetrix_sdk-0.1.0/tests/test_schema.py +154 -0
- ninetrix_sdk-0.1.0/tests/test_tool.py +191 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published] # trigger when you publish a GitHub Release
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi # optional: require manual approval in GitHub UI
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write # needed for trusted publishing (no token required)
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.11"
|
|
20
|
+
|
|
21
|
+
- name: Install build tools
|
|
22
|
+
run: pip install build
|
|
23
|
+
|
|
24
|
+
- name: Build wheel and sdist
|
|
25
|
+
run: python -m build
|
|
26
|
+
working-directory: . # sdk/ is the repo root
|
|
27
|
+
|
|
28
|
+
- name: Publish to PyPI
|
|
29
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
30
|
+
# Uses PyPI Trusted Publishing — no API token needed at all
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ninetrix-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for Ninetrix — define agent tools in code
|
|
5
|
+
Project-URL: Homepage, https://ninetrix.io
|
|
6
|
+
Project-URL: Repository, https://github.com/Ninetrix-ai/ninetrix
|
|
7
|
+
Project-URL: Documentation, https://ninetrix.io/docs
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
12
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
13
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
14
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# ninetrix-sdk
|
|
18
|
+
|
|
19
|
+
Python SDK for [Ninetrix](https://ninetrix.io) — define AI agent tools in code.
|
|
20
|
+
|
|
21
|
+
## Phase 1: `@Tool` decorator
|
|
22
|
+
|
|
23
|
+
Connect any Python function to a Ninetrix agent. The function is auto-discovered by `ninetrix build`, bundled into the Docker image, and dispatched at runtime alongside MCP tools.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install ninetrix-sdk
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick start
|
|
32
|
+
|
|
33
|
+
**1. Define your tools**
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# tools/db_tools.py
|
|
37
|
+
from ninetrix import Tool
|
|
38
|
+
|
|
39
|
+
@Tool
|
|
40
|
+
def query_customers(sql: str, limit: int = 100) -> list[dict]:
|
|
41
|
+
"""Execute a read-only SQL query against the customer database.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
sql: A valid SELECT statement.
|
|
45
|
+
limit: Maximum rows to return.
|
|
46
|
+
"""
|
|
47
|
+
return db.execute(sql, limit=limit)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@Tool
|
|
51
|
+
def send_notification(channel: str, message: str) -> bool:
|
|
52
|
+
"""Send a message to an internal Slack channel.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
channel: Destination channel (e.g. "#ops").
|
|
56
|
+
message: Notification text.
|
|
57
|
+
"""
|
|
58
|
+
return slack.post(channel, message)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**2. Reference in `agentfile.yaml`**
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
agents:
|
|
65
|
+
my-agent:
|
|
66
|
+
metadata:
|
|
67
|
+
role: Operations assistant
|
|
68
|
+
goal: Answer questions and send alerts using internal tools
|
|
69
|
+
|
|
70
|
+
runtime:
|
|
71
|
+
provider: anthropic
|
|
72
|
+
model: claude-sonnet-4-6
|
|
73
|
+
|
|
74
|
+
tools:
|
|
75
|
+
- name: web_search
|
|
76
|
+
source: mcp://brave-search # MCP tool — unchanged
|
|
77
|
+
|
|
78
|
+
- name: db_tools
|
|
79
|
+
source: ./tools/db_tools.py # Python tool file — NEW
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**3. Build and run**
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
ninetrix build # discovers @Tool functions, bundles them into the image
|
|
86
|
+
ninetrix run # agent can now call query_customers and send_notification
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## How it works
|
|
92
|
+
|
|
93
|
+
| Step | What happens |
|
|
94
|
+
|------|-------------|
|
|
95
|
+
| `ninetrix build` | Scans `source: ./...py` entries, imports the file, extracts `@Tool` schemas |
|
|
96
|
+
| Dockerfile | Copies the `.py` files into the image, installs `ninetrix-sdk` |
|
|
97
|
+
| Container start | Imports the tool files, registers functions in the local registry |
|
|
98
|
+
| LLM call | Agent receives local tool schemas alongside MCP tool schemas |
|
|
99
|
+
| Tool dispatch | When the LLM calls a local tool, the Python function is invoked directly |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## `@Tool` API
|
|
104
|
+
|
|
105
|
+
### Bare decorator
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
@Tool
|
|
109
|
+
def my_function(param: str, count: int = 5) -> str:
|
|
110
|
+
"""One-line description used as the tool description.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
param: Injected into the tool's parameter schema.
|
|
114
|
+
count: Optional param — not required, default shown to LLM.
|
|
115
|
+
"""
|
|
116
|
+
...
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Decorator factory (with overrides)
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
@Tool(name="custom_name", description="Override the docstring description.")
|
|
123
|
+
def my_function(param: str) -> str:
|
|
124
|
+
...
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Supported parameter types
|
|
128
|
+
|
|
129
|
+
| Python type | JSON Schema |
|
|
130
|
+
|------------|------------|
|
|
131
|
+
| `str` | `{"type": "string"}` |
|
|
132
|
+
| `int` | `{"type": "integer"}` |
|
|
133
|
+
| `float` | `{"type": "number"}` |
|
|
134
|
+
| `bool` | `{"type": "boolean"}` |
|
|
135
|
+
| `list[str]` | `{"type": "array", "items": {"type": "string"}}` |
|
|
136
|
+
| `dict` | `{"type": "object"}` |
|
|
137
|
+
| `Optional[str]` | `{"type": "string"}` (not required) |
|
|
138
|
+
| `Literal["a","b"]` | `{"type": "string", "enum": ["a","b"]}` |
|
|
139
|
+
|
|
140
|
+
Parameters without defaults → `required`. Parameters with defaults → optional (default shown in schema).
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Multiple tool files
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
tools:
|
|
148
|
+
- name: db_tools
|
|
149
|
+
source: ./tools/db_tools.py
|
|
150
|
+
|
|
151
|
+
- name: api_tools
|
|
152
|
+
source: ./tools/api_tools.py
|
|
153
|
+
|
|
154
|
+
- name: web_search
|
|
155
|
+
source: mcp://brave-search
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Testing your tools
|
|
161
|
+
|
|
162
|
+
Tools are plain Python functions — test them directly:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
# tests/test_db_tools.py
|
|
166
|
+
from tools.db_tools import query_customers
|
|
167
|
+
|
|
168
|
+
def test_query_customers():
|
|
169
|
+
result = query_customers("SELECT id FROM customers LIMIT 1")
|
|
170
|
+
assert isinstance(result, list)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
To inspect the generated schema:
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from ninetrix import _registry
|
|
177
|
+
from tools import db_tools # triggers @Tool registrations
|
|
178
|
+
|
|
179
|
+
td = _registry.get("query_customers")
|
|
180
|
+
print(td.to_anthropic_schema())
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Roadmap
|
|
186
|
+
|
|
187
|
+
- **Phase 1** ✅ — `@Tool` decorator, build discovery, runtime dispatch
|
|
188
|
+
- **Phase 2** — `Agent(...)` class + `@Workflow` decorator for Python-first agent definition
|
|
189
|
+
- **Phase 3** — Durable execution: checkpoint every workflow step, resume on crash
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
Apache 2.0
|
|
196
|
+
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# ninetrix-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK for [Ninetrix](https://ninetrix.io) — define AI agent tools in code.
|
|
4
|
+
|
|
5
|
+
## Phase 1: `@Tool` decorator
|
|
6
|
+
|
|
7
|
+
Connect any Python function to a Ninetrix agent. The function is auto-discovered by `ninetrix build`, bundled into the Docker image, and dispatched at runtime alongside MCP tools.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install ninetrix-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
**1. Define your tools**
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
# tools/db_tools.py
|
|
21
|
+
from ninetrix import Tool
|
|
22
|
+
|
|
23
|
+
@Tool
|
|
24
|
+
def query_customers(sql: str, limit: int = 100) -> list[dict]:
|
|
25
|
+
"""Execute a read-only SQL query against the customer database.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
sql: A valid SELECT statement.
|
|
29
|
+
limit: Maximum rows to return.
|
|
30
|
+
"""
|
|
31
|
+
return db.execute(sql, limit=limit)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@Tool
|
|
35
|
+
def send_notification(channel: str, message: str) -> bool:
|
|
36
|
+
"""Send a message to an internal Slack channel.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
channel: Destination channel (e.g. "#ops").
|
|
40
|
+
message: Notification text.
|
|
41
|
+
"""
|
|
42
|
+
return slack.post(channel, message)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**2. Reference in `agentfile.yaml`**
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
agents:
|
|
49
|
+
my-agent:
|
|
50
|
+
metadata:
|
|
51
|
+
role: Operations assistant
|
|
52
|
+
goal: Answer questions and send alerts using internal tools
|
|
53
|
+
|
|
54
|
+
runtime:
|
|
55
|
+
provider: anthropic
|
|
56
|
+
model: claude-sonnet-4-6
|
|
57
|
+
|
|
58
|
+
tools:
|
|
59
|
+
- name: web_search
|
|
60
|
+
source: mcp://brave-search # MCP tool — unchanged
|
|
61
|
+
|
|
62
|
+
- name: db_tools
|
|
63
|
+
source: ./tools/db_tools.py # Python tool file — NEW
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**3. Build and run**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
ninetrix build # discovers @Tool functions, bundles them into the image
|
|
70
|
+
ninetrix run # agent can now call query_customers and send_notification
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## How it works
|
|
76
|
+
|
|
77
|
+
| Step | What happens |
|
|
78
|
+
|------|-------------|
|
|
79
|
+
| `ninetrix build` | Scans `source: ./...py` entries, imports the file, extracts `@Tool` schemas |
|
|
80
|
+
| Dockerfile | Copies the `.py` files into the image, installs `ninetrix-sdk` |
|
|
81
|
+
| Container start | Imports the tool files, registers functions in the local registry |
|
|
82
|
+
| LLM call | Agent receives local tool schemas alongside MCP tool schemas |
|
|
83
|
+
| Tool dispatch | When the LLM calls a local tool, the Python function is invoked directly |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## `@Tool` API
|
|
88
|
+
|
|
89
|
+
### Bare decorator
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
@Tool
|
|
93
|
+
def my_function(param: str, count: int = 5) -> str:
|
|
94
|
+
"""One-line description used as the tool description.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
param: Injected into the tool's parameter schema.
|
|
98
|
+
count: Optional param — not required, default shown to LLM.
|
|
99
|
+
"""
|
|
100
|
+
...
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Decorator factory (with overrides)
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
@Tool(name="custom_name", description="Override the docstring description.")
|
|
107
|
+
def my_function(param: str) -> str:
|
|
108
|
+
...
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Supported parameter types
|
|
112
|
+
|
|
113
|
+
| Python type | JSON Schema |
|
|
114
|
+
|------------|------------|
|
|
115
|
+
| `str` | `{"type": "string"}` |
|
|
116
|
+
| `int` | `{"type": "integer"}` |
|
|
117
|
+
| `float` | `{"type": "number"}` |
|
|
118
|
+
| `bool` | `{"type": "boolean"}` |
|
|
119
|
+
| `list[str]` | `{"type": "array", "items": {"type": "string"}}` |
|
|
120
|
+
| `dict` | `{"type": "object"}` |
|
|
121
|
+
| `Optional[str]` | `{"type": "string"}` (not required) |
|
|
122
|
+
| `Literal["a","b"]` | `{"type": "string", "enum": ["a","b"]}` |
|
|
123
|
+
|
|
124
|
+
Parameters without defaults → `required`. Parameters with defaults → optional (default shown in schema).
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Multiple tool files
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
tools:
|
|
132
|
+
- name: db_tools
|
|
133
|
+
source: ./tools/db_tools.py
|
|
134
|
+
|
|
135
|
+
- name: api_tools
|
|
136
|
+
source: ./tools/api_tools.py
|
|
137
|
+
|
|
138
|
+
- name: web_search
|
|
139
|
+
source: mcp://brave-search
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Testing your tools
|
|
145
|
+
|
|
146
|
+
Tools are plain Python functions — test them directly:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
# tests/test_db_tools.py
|
|
150
|
+
from tools.db_tools import query_customers
|
|
151
|
+
|
|
152
|
+
def test_query_customers():
|
|
153
|
+
result = query_customers("SELECT id FROM customers LIMIT 1")
|
|
154
|
+
assert isinstance(result, list)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
To inspect the generated schema:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from ninetrix import _registry
|
|
161
|
+
from tools import db_tools # triggers @Tool registrations
|
|
162
|
+
|
|
163
|
+
td = _registry.get("query_customers")
|
|
164
|
+
print(td.to_anthropic_schema())
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Roadmap
|
|
170
|
+
|
|
171
|
+
- **Phase 1** ✅ — `@Tool` decorator, build discovery, runtime dispatch
|
|
172
|
+
- **Phase 2** — `Agent(...)` class + `@Workflow` decorator for Python-first agent definition
|
|
173
|
+
- **Phase 3** — Durable execution: checkpoint every workflow step, resume on crash
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
Apache 2.0
|
|
180
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Example: custom database + API tools for a Ninetrix agent.
|
|
3
|
+
|
|
4
|
+
Reference in agentfile.yaml:
|
|
5
|
+
tools:
|
|
6
|
+
- name: db_tools
|
|
7
|
+
source: ./examples/db_tools.py
|
|
8
|
+
|
|
9
|
+
Then ninetrix build bundles this file and registers all @Tool functions.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Literal
|
|
15
|
+
|
|
16
|
+
from ninetrix import Tool
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@Tool
|
|
20
|
+
def query_customers(sql: str, limit: int = 100) -> list[dict]:
|
|
21
|
+
"""Execute a read-only SQL query against the customer database.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
sql: A valid SELECT statement. UPDATE/DELETE/INSERT are not allowed.
|
|
25
|
+
limit: Maximum number of rows to return. Hard-capped at 1000.
|
|
26
|
+
"""
|
|
27
|
+
# Replace with real DB call
|
|
28
|
+
raise NotImplementedError("Connect to your database here")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@Tool
|
|
32
|
+
def get_customer(customer_id: str) -> dict:
|
|
33
|
+
"""Fetch a single customer record by ID.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
customer_id: The unique customer identifier (UUID or integer string).
|
|
37
|
+
"""
|
|
38
|
+
raise NotImplementedError
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@Tool
|
|
42
|
+
def search_products(
|
|
43
|
+
query: str,
|
|
44
|
+
category: str | None = None,
|
|
45
|
+
sort: Literal["price_asc", "price_desc", "relevance"] = "relevance",
|
|
46
|
+
limit: int = 20,
|
|
47
|
+
) -> list[dict]:
|
|
48
|
+
"""Search the product catalog.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
query: Full-text search query.
|
|
52
|
+
category: Optional category filter (e.g. "electronics", "apparel").
|
|
53
|
+
sort: Sort order for results.
|
|
54
|
+
limit: Maximum products to return.
|
|
55
|
+
"""
|
|
56
|
+
raise NotImplementedError
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@Tool(name="send_internal_notification")
|
|
60
|
+
def notify(channel: str, message: str, priority: Literal["low", "high"] = "low") -> bool:
|
|
61
|
+
"""Send a notification to an internal Slack channel or PagerDuty.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
channel: Destination channel name (e.g. "#ops-alerts").
|
|
65
|
+
message: Notification body. Keep it under 500 characters.
|
|
66
|
+
priority: "high" pages on-call, "low" posts silently.
|
|
67
|
+
"""
|
|
68
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ninetrix-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python SDK for Ninetrix — define agent tools in code"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "Apache-2.0" }
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
dependencies = []
|
|
13
|
+
|
|
14
|
+
[project.optional-dependencies]
|
|
15
|
+
dev = [
|
|
16
|
+
"pytest>=8.0",
|
|
17
|
+
"pytest-cov>=5.0",
|
|
18
|
+
"ruff>=0.4",
|
|
19
|
+
"mypy>=1.10",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://ninetrix.io"
|
|
24
|
+
Repository = "https://github.com/Ninetrix-ai/ninetrix"
|
|
25
|
+
Documentation = "https://ninetrix.io/docs"
|
|
26
|
+
|
|
27
|
+
[tool.hatch.build.targets.wheel]
|
|
28
|
+
packages = ["src/ninetrix"]
|
|
29
|
+
|
|
30
|
+
[tool.ruff]
|
|
31
|
+
line-length = 88
|
|
32
|
+
target-version = "py311"
|
|
33
|
+
|
|
34
|
+
[tool.ruff.lint]
|
|
35
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
36
|
+
ignore = ["E501"]
|
|
37
|
+
|
|
38
|
+
[tool.mypy]
|
|
39
|
+
python_version = "3.11"
|
|
40
|
+
strict = true
|
|
41
|
+
ignore_missing_imports = true
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
testpaths = ["tests"]
|
|
45
|
+
addopts = "--tb=short -q"
|
|
46
|
+
|
|
47
|
+
[tool.coverage.run]
|
|
48
|
+
source = ["src/ninetrix"]
|
|
49
|
+
omit = ["tests/*"]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ninetrix SDK — Python primitives for building AI agent tools.
|
|
3
|
+
|
|
4
|
+
Phase 1: @Tool decorator
|
|
5
|
+
Define Python functions as agent-callable tools. They are auto-discovered
|
|
6
|
+
by ``ninetrix build``, bundled into the Docker image, and dispatched at
|
|
7
|
+
runtime alongside MCP tools.
|
|
8
|
+
|
|
9
|
+
Phase 2 (upcoming): Agent + Workflow
|
|
10
|
+
Define full agents and complex workflows in Python.
|
|
11
|
+
|
|
12
|
+
Quick start::
|
|
13
|
+
|
|
14
|
+
from ninetrix import Tool
|
|
15
|
+
|
|
16
|
+
@Tool
|
|
17
|
+
def query_customers(sql: str, limit: int = 100) -> list[dict]:
|
|
18
|
+
\"\"\"Run a read-only SQL query against the customer database.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
sql: A valid SELECT statement.
|
|
22
|
+
limit: Maximum rows to return.
|
|
23
|
+
\"\"\"
|
|
24
|
+
return db.execute(sql, limit=limit)
|
|
25
|
+
|
|
26
|
+
Reference the tool in ``agentfile.yaml``::
|
|
27
|
+
|
|
28
|
+
tools:
|
|
29
|
+
- name: query_customers
|
|
30
|
+
source: ./tools/db_tools.py
|
|
31
|
+
|
|
32
|
+
Then build and run as usual::
|
|
33
|
+
|
|
34
|
+
ninetrix build
|
|
35
|
+
ninetrix run
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from ninetrix.tool import Tool
|
|
39
|
+
from ninetrix.registry import ToolDef, ToolRegistry, _registry
|
|
40
|
+
from ninetrix.discover import (
|
|
41
|
+
discover_tools_in_file,
|
|
42
|
+
discover_tools_in_files,
|
|
43
|
+
load_local_tools,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
__version__ = "0.1.0"
|
|
47
|
+
__all__ = [
|
|
48
|
+
# Primary public API
|
|
49
|
+
"Tool",
|
|
50
|
+
# Registry types (useful for type hints and testing)
|
|
51
|
+
"ToolDef",
|
|
52
|
+
"ToolRegistry",
|
|
53
|
+
# Build-time discovery
|
|
54
|
+
"discover_tools_in_file",
|
|
55
|
+
"discover_tools_in_files",
|
|
56
|
+
# Runtime loader (called by generated entrypoint)
|
|
57
|
+
"load_local_tools",
|
|
58
|
+
# Internal registry (advanced / testing)
|
|
59
|
+
"_registry",
|
|
60
|
+
]
|