nodus-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.
Files changed (34) hide show
  1. nodus_sdk-0.1.0/LICENSE +21 -0
  2. nodus_sdk-0.1.0/PKG-INFO +231 -0
  3. nodus_sdk-0.1.0/README.md +136 -0
  4. nodus_sdk-0.1.0/nodus_sdk/__init__.py +12 -0
  5. nodus_sdk-0.1.0/nodus_sdk/_version.py +1 -0
  6. nodus_sdk-0.1.0/nodus_sdk/bridges/__init__.py +1 -0
  7. nodus_sdk-0.1.0/nodus_sdk/bridges/api.py +124 -0
  8. nodus_sdk-0.1.0/nodus_sdk/bridges/http.py +42 -0
  9. nodus_sdk-0.1.0/nodus_sdk/bridges/llm.py +44 -0
  10. nodus_sdk-0.1.0/nodus_sdk/bridges/observability.py +51 -0
  11. nodus_sdk-0.1.0/nodus_sdk/bridges/redis.py +41 -0
  12. nodus_sdk-0.1.0/nodus_sdk/bridges/scheduler.py +159 -0
  13. nodus_sdk-0.1.0/nodus_sdk/bridges/sql.py +103 -0
  14. nodus_sdk-0.1.0/nodus_sdk/bridges/vector.py +164 -0
  15. nodus_sdk-0.1.0/nodus_sdk/bridges/webhook.py +147 -0
  16. nodus_sdk-0.1.0/nodus_sdk/factory.py +88 -0
  17. nodus_sdk-0.1.0/nodus_sdk/runtime.py +175 -0
  18. nodus_sdk-0.1.0/nodus_sdk.egg-info/PKG-INFO +231 -0
  19. nodus_sdk-0.1.0/nodus_sdk.egg-info/SOURCES.txt +32 -0
  20. nodus_sdk-0.1.0/nodus_sdk.egg-info/dependency_links.txt +1 -0
  21. nodus_sdk-0.1.0/nodus_sdk.egg-info/requires.txt +70 -0
  22. nodus_sdk-0.1.0/nodus_sdk.egg-info/top_level.txt +1 -0
  23. nodus_sdk-0.1.0/pyproject.toml +70 -0
  24. nodus_sdk-0.1.0/setup.cfg +4 -0
  25. nodus_sdk-0.1.0/tests/test_bridges_api.py +150 -0
  26. nodus_sdk-0.1.0/tests/test_bridges_http.py +51 -0
  27. nodus_sdk-0.1.0/tests/test_bridges_llm.py +67 -0
  28. nodus_sdk-0.1.0/tests/test_bridges_observability.py +41 -0
  29. nodus_sdk-0.1.0/tests/test_bridges_redis.py +63 -0
  30. nodus_sdk-0.1.0/tests/test_bridges_scheduler.py +129 -0
  31. nodus_sdk-0.1.0/tests/test_bridges_sql.py +138 -0
  32. nodus_sdk-0.1.0/tests/test_bridges_vector.py +139 -0
  33. nodus_sdk-0.1.0/tests/test_bridges_webhook.py +121 -0
  34. nodus_sdk-0.1.0/tests/test_factory.py +180 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shawn Knight
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.
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: nodus-sdk
3
+ Version: 0.1.0
4
+ Summary: Unified platform SDK for Nodus — factory, bridges, and integration layer
5
+ Author: Shawn Knight
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Shawn Knight
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/Masterplanner25/nodus-sdk
29
+ Project-URL: Repository, https://github.com/Masterplanner25/nodus-sdk
30
+ Classifier: Development Status :: 3 - Alpha
31
+ Classifier: Intended Audience :: Developers
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Programming Language :: Python :: 3
34
+ Classifier: Programming Language :: Python :: 3.10
35
+ Classifier: Programming Language :: Python :: 3.11
36
+ Classifier: Programming Language :: Python :: 3.12
37
+ Classifier: Programming Language :: Python :: 3.13
38
+ Requires-Python: >=3.10
39
+ Description-Content-Type: text/markdown
40
+ License-File: LICENSE
41
+ Requires-Dist: nodus-lang>=4.0.0
42
+ Requires-Dist: nodus-schema>=0.1.0
43
+ Requires-Dist: nodus-protocol>=0.1.0
44
+ Requires-Dist: nodus-retry>=0.1.0
45
+ Provides-Extra: agent
46
+ Requires-Dist: nodus-agent>=0.1.0; extra == "agent"
47
+ Requires-Dist: nodus-state>=0.1.0; extra == "agent"
48
+ Requires-Dist: nodus-circuit-breaker>=0.1.0; extra == "agent"
49
+ Provides-Extra: workflow
50
+ Requires-Dist: nodus-workflow>=0.1.0; extra == "workflow"
51
+ Requires-Dist: nodus-state>=0.1.0; extra == "workflow"
52
+ Requires-Dist: nodus-events>=0.1.0; extra == "workflow"
53
+ Provides-Extra: memory
54
+ Requires-Dist: nodus-memory>=0.1.0; extra == "memory"
55
+ Provides-Extra: memory-ai
56
+ Requires-Dist: nodus-memory[openai]>=0.1.0; extra == "memory-ai"
57
+ Provides-Extra: auth
58
+ Requires-Dist: nodus-auth>=0.1.0; extra == "auth"
59
+ Provides-Extra: llm
60
+ Requires-Dist: nodus-llm>=0.1.0; extra == "llm"
61
+ Requires-Dist: nodus-circuit-breaker>=0.1.0; extra == "llm"
62
+ Provides-Extra: http
63
+ Requires-Dist: nodus-http>=0.1.0; extra == "http"
64
+ Provides-Extra: redis
65
+ Requires-Dist: nodus-queue[redis]>=0.1.0; extra == "redis"
66
+ Requires-Dist: nodus-events[redis]>=0.1.0; extra == "redis"
67
+ Provides-Extra: sql
68
+ Requires-Dist: sqlalchemy>=2.0; extra == "sql"
69
+ Provides-Extra: vector
70
+ Requires-Dist: pgvector>=0.2; extra == "vector"
71
+ Requires-Dist: sqlalchemy>=2.0; extra == "vector"
72
+ Provides-Extra: scheduler
73
+ Requires-Dist: apscheduler>=3.10; extra == "scheduler"
74
+ Provides-Extra: fastapi
75
+ Requires-Dist: fastapi>=0.100; extra == "fastapi"
76
+ Requires-Dist: httpx>=0.27; extra == "fastapi"
77
+ Provides-Extra: webhooks
78
+ Requires-Dist: httpx>=0.27; extra == "webhooks"
79
+ Provides-Extra: observability
80
+ Requires-Dist: nodus-observability>=0.1.0; extra == "observability"
81
+ Requires-Dist: nodus-observability-framework>=0.1.0; extra == "observability"
82
+ Provides-Extra: extensions
83
+ Requires-Dist: nodus-extension>=0.1.0; extra == "extensions"
84
+ Provides-Extra: full
85
+ Requires-Dist: nodus-sdk[agent,auth,extensions,fastapi,http,llm,memory,observability,redis,scheduler,sql,vector,webhooks,workflow]; extra == "full"
86
+ Provides-Extra: dev
87
+ Requires-Dist: pytest>=7; extra == "dev"
88
+ Requires-Dist: pytest-asyncio; extra == "dev"
89
+ Requires-Dist: respx; extra == "dev"
90
+ Requires-Dist: fastapi[all]; extra == "dev"
91
+ Requires-Dist: sqlalchemy>=2.0; extra == "dev"
92
+ Requires-Dist: apscheduler>=3.10; extra == "dev"
93
+ Requires-Dist: httpx>=0.27; extra == "dev"
94
+ Dynamic: license-file
95
+
96
+ # nodus-sdk
97
+
98
+ **Unified platform SDK for Nodus AI systems.**
99
+
100
+ Single-package installation story for the Nodus ecosystem. Auto-wires
101
+ available packages via `create_runtime(**kwargs)`, provides 9 bridge modules
102
+ for external integrations, and exposes a FastAPI control-plane router.
103
+
104
+ > **Status:** v0.1.0 — prepared, not yet published.
105
+
106
+ ---
107
+
108
+ ## Install
109
+
110
+ ```bash
111
+ pip install nodus-sdk # core only
112
+ pip install "nodus-sdk[agent,sql,fastapi]" # agent + SQLAlchemy + FastAPI
113
+ pip install "nodus-sdk[full]" # everything
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Quick start
119
+
120
+ ```python
121
+ from nodus_sdk import create_runtime
122
+
123
+ rt = create_runtime(memory=True, trace_id="req-001", timeout_ms=None)
124
+ result = rt.run_source('print("hello from sdk")')
125
+ ```
126
+
127
+ ---
128
+
129
+ ## create_runtime()
130
+
131
+ ```python
132
+ from nodus_sdk import create_runtime, NodusSDKRuntime
133
+
134
+ rt = create_runtime(
135
+ memory=True, # True = auto-configure; or pass a store object
136
+ events=True, # True = auto-configure; or pass EventBusConfig
137
+ extensions=True, # attach ExtensionRegistry
138
+ auth=True, # attach KeyRing
139
+ observability=True, # or pass service name string
140
+ trace_id="tid-001", # injected into every emitted event
141
+ timeout_ms=None, # None = unlimited (required for long-lived services)
142
+ max_steps=None,
143
+ allowed_paths=None,
144
+ project_root=None,
145
+ )
146
+ ```
147
+
148
+ `create_runtime` returns a `NodusSDKRuntime` — a `NodusRuntime` subclass with
149
+ fluent `attach_*` bridge methods. All capability kwargs accept `True` (default
150
+ config) or a config/store object.
151
+
152
+ ---
153
+
154
+ ## NodusSDKRuntime fluent API
155
+
156
+ ```python
157
+ from nodus_sdk import NodusSDKRuntime
158
+ from nodus_sdk.bridges.sql import SqlBridge
159
+ from nodus_sdk.bridges.webhook import WebhookBridge
160
+
161
+ rt = (
162
+ NodusSDKRuntime(timeout_ms=None)
163
+ .attach_sql(SqlBridge("postgresql://..."))
164
+ .attach_webhook(WebhookBridge(secret="my-secret"))
165
+ )
166
+ ```
167
+
168
+ All `attach_*` methods are idempotent and return `self`.
169
+
170
+ ---
171
+
172
+ ## Bridges
173
+
174
+ | Bridge | Install extra | Key class |
175
+ |---|---|---|
176
+ | `bridges/redis.py` | `[redis]` | `RedisBridge(url)` → queue_backend, event_bus |
177
+ | `bridges/http.py` | `[http]` | `HttpBridge()` → NodusHttpClient |
178
+ | `bridges/llm.py` | `[llm]` | `LLMBridge(credentials)` → FailoverClient |
179
+ | `bridges/observability.py` | `[observability]` | `init_observability(name, otel=, prometheus=)` |
180
+ | `bridges/sql.py` | `[sql]` | `SqlBridge(url)` → sql_query/sql_execute host fns |
181
+ | `bridges/vector.py` | `[vector]` | `VectorBridge(url, table, dimensions)` → vector_search/upsert/delete |
182
+ | `bridges/scheduler.py` | `[scheduler]` | `SchedulerBridge()` → scheduler_add_interval/cron/cancel |
183
+ | `bridges/webhook.py` | `[webhooks]` | `WebhookBridge(secret=)` → webhook_send |
184
+ | `bridges/api.py` | `[fastapi]` | `create_nodus_router(rt)` + `NodusTraceMiddleware` |
185
+
186
+ **Bridge return type note:** Bridge host functions return Python maps (dicts),
187
+ not Records. Use index access in `.nd` code: `r["status"]`, not `r.status`.
188
+
189
+ ---
190
+
191
+ ## FastAPI integration
192
+
193
+ ```python
194
+ from fastapi import FastAPI
195
+ from nodus_sdk import create_runtime
196
+ from nodus_sdk.bridges.api import create_nodus_router, NodusTraceMiddleware
197
+
198
+ rt = create_runtime(timeout_ms=None)
199
+ app = FastAPI()
200
+ app.add_middleware(NodusTraceMiddleware, runtime=rt)
201
+ app.include_router(create_nodus_router(rt))
202
+ # Routes: POST /run, GET /health, GET /syscalls, GET|POST|DELETE /memory/{key}
203
+ ```
204
+
205
+ ---
206
+
207
+ ## detect_available()
208
+
209
+ ```python
210
+ from nodus_sdk import detect_available
211
+
212
+ avail = detect_available()
213
+ # {"memory": True, "extension": False, "events": True, ...}
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Development
219
+
220
+ ```bash
221
+ pip install -e ".[dev]"
222
+ PYTHONPATH="C:/dev/Coding Language/src" pytest tests/ -q
223
+ ```
224
+
225
+ Tests require nodus-lang source on `PYTHONPATH`.
226
+
227
+ ---
228
+
229
+ ## License
230
+
231
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,136 @@
1
+ # nodus-sdk
2
+
3
+ **Unified platform SDK for Nodus AI systems.**
4
+
5
+ Single-package installation story for the Nodus ecosystem. Auto-wires
6
+ available packages via `create_runtime(**kwargs)`, provides 9 bridge modules
7
+ for external integrations, and exposes a FastAPI control-plane router.
8
+
9
+ > **Status:** v0.1.0 — prepared, not yet published.
10
+
11
+ ---
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install nodus-sdk # core only
17
+ pip install "nodus-sdk[agent,sql,fastapi]" # agent + SQLAlchemy + FastAPI
18
+ pip install "nodus-sdk[full]" # everything
19
+ ```
20
+
21
+ ---
22
+
23
+ ## Quick start
24
+
25
+ ```python
26
+ from nodus_sdk import create_runtime
27
+
28
+ rt = create_runtime(memory=True, trace_id="req-001", timeout_ms=None)
29
+ result = rt.run_source('print("hello from sdk")')
30
+ ```
31
+
32
+ ---
33
+
34
+ ## create_runtime()
35
+
36
+ ```python
37
+ from nodus_sdk import create_runtime, NodusSDKRuntime
38
+
39
+ rt = create_runtime(
40
+ memory=True, # True = auto-configure; or pass a store object
41
+ events=True, # True = auto-configure; or pass EventBusConfig
42
+ extensions=True, # attach ExtensionRegistry
43
+ auth=True, # attach KeyRing
44
+ observability=True, # or pass service name string
45
+ trace_id="tid-001", # injected into every emitted event
46
+ timeout_ms=None, # None = unlimited (required for long-lived services)
47
+ max_steps=None,
48
+ allowed_paths=None,
49
+ project_root=None,
50
+ )
51
+ ```
52
+
53
+ `create_runtime` returns a `NodusSDKRuntime` — a `NodusRuntime` subclass with
54
+ fluent `attach_*` bridge methods. All capability kwargs accept `True` (default
55
+ config) or a config/store object.
56
+
57
+ ---
58
+
59
+ ## NodusSDKRuntime fluent API
60
+
61
+ ```python
62
+ from nodus_sdk import NodusSDKRuntime
63
+ from nodus_sdk.bridges.sql import SqlBridge
64
+ from nodus_sdk.bridges.webhook import WebhookBridge
65
+
66
+ rt = (
67
+ NodusSDKRuntime(timeout_ms=None)
68
+ .attach_sql(SqlBridge("postgresql://..."))
69
+ .attach_webhook(WebhookBridge(secret="my-secret"))
70
+ )
71
+ ```
72
+
73
+ All `attach_*` methods are idempotent and return `self`.
74
+
75
+ ---
76
+
77
+ ## Bridges
78
+
79
+ | Bridge | Install extra | Key class |
80
+ |---|---|---|
81
+ | `bridges/redis.py` | `[redis]` | `RedisBridge(url)` → queue_backend, event_bus |
82
+ | `bridges/http.py` | `[http]` | `HttpBridge()` → NodusHttpClient |
83
+ | `bridges/llm.py` | `[llm]` | `LLMBridge(credentials)` → FailoverClient |
84
+ | `bridges/observability.py` | `[observability]` | `init_observability(name, otel=, prometheus=)` |
85
+ | `bridges/sql.py` | `[sql]` | `SqlBridge(url)` → sql_query/sql_execute host fns |
86
+ | `bridges/vector.py` | `[vector]` | `VectorBridge(url, table, dimensions)` → vector_search/upsert/delete |
87
+ | `bridges/scheduler.py` | `[scheduler]` | `SchedulerBridge()` → scheduler_add_interval/cron/cancel |
88
+ | `bridges/webhook.py` | `[webhooks]` | `WebhookBridge(secret=)` → webhook_send |
89
+ | `bridges/api.py` | `[fastapi]` | `create_nodus_router(rt)` + `NodusTraceMiddleware` |
90
+
91
+ **Bridge return type note:** Bridge host functions return Python maps (dicts),
92
+ not Records. Use index access in `.nd` code: `r["status"]`, not `r.status`.
93
+
94
+ ---
95
+
96
+ ## FastAPI integration
97
+
98
+ ```python
99
+ from fastapi import FastAPI
100
+ from nodus_sdk import create_runtime
101
+ from nodus_sdk.bridges.api import create_nodus_router, NodusTraceMiddleware
102
+
103
+ rt = create_runtime(timeout_ms=None)
104
+ app = FastAPI()
105
+ app.add_middleware(NodusTraceMiddleware, runtime=rt)
106
+ app.include_router(create_nodus_router(rt))
107
+ # Routes: POST /run, GET /health, GET /syscalls, GET|POST|DELETE /memory/{key}
108
+ ```
109
+
110
+ ---
111
+
112
+ ## detect_available()
113
+
114
+ ```python
115
+ from nodus_sdk import detect_available
116
+
117
+ avail = detect_available()
118
+ # {"memory": True, "extension": False, "events": True, ...}
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ pip install -e ".[dev]"
127
+ PYTHONPATH="C:/dev/Coding Language/src" pytest tests/ -q
128
+ ```
129
+
130
+ Tests require nodus-lang source on `PYTHONPATH`.
131
+
132
+ ---
133
+
134
+ ## License
135
+
136
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,12 @@
1
+ """nodus-sdk — unified platform SDK for Nodus."""
2
+
3
+ from nodus_sdk._version import __version__
4
+ from nodus_sdk.factory import create_runtime, detect_available
5
+ from nodus_sdk.runtime import NodusSDKRuntime
6
+
7
+ __all__ = [
8
+ "__version__",
9
+ "NodusSDKRuntime",
10
+ "create_runtime",
11
+ "detect_available",
12
+ ]
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1 @@
1
+ """nodus_sdk.bridges — Python bridge implementations."""
@@ -0,0 +1,124 @@
1
+ """FastAPI bridge — NodusRuntime router and trace middleware."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib.util
6
+ from typing import TYPE_CHECKING, Any, Optional
7
+
8
+ _FASTAPI_AVAILABLE = importlib.util.find_spec("fastapi") is not None
9
+
10
+ if TYPE_CHECKING:
11
+ from nodus.runtime.embedding import NodusRuntime
12
+
13
+ if _FASTAPI_AVAILABLE:
14
+ from pydantic import BaseModel
15
+
16
+ class _RunRequest(BaseModel):
17
+ source: str
18
+ timeout_ms: Optional[int] = None
19
+
20
+ class _MemoryWriteRequest(BaseModel):
21
+ value: Any
22
+
23
+
24
+ def create_nodus_router(
25
+ runtime: "NodusRuntime",
26
+ *,
27
+ prefix: str = "",
28
+ tags: list[str] | None = None,
29
+ include_memory: bool = True,
30
+ include_syscalls: bool = True,
31
+ ) -> Any:
32
+ """Return a FastAPI APIRouter with Nodus control-plane endpoints.
33
+
34
+ Routes:
35
+ POST {prefix}/run — run Nodus source code
36
+ GET {prefix}/health — runtime health
37
+ GET {prefix}/syscalls — list sys.v1.* syscalls
38
+ GET {prefix}/memory/{key} — read from memory store
39
+ POST {prefix}/memory/{key} — write to memory store
40
+ DELETE{prefix}/memory/{key} — delete from memory store
41
+
42
+ Requires ``nodus-sdk[fastapi]``.
43
+ """
44
+ if not _FASTAPI_AVAILABLE:
45
+ raise ImportError("fastapi not installed. pip install nodus-sdk[fastapi]")
46
+
47
+ from fastapi import APIRouter
48
+
49
+ from nodus.support.version import __version__ as nodus_version
50
+
51
+ router = APIRouter(prefix=prefix, tags=tags or ["nodus"])
52
+
53
+ @router.post("/run")
54
+ def run_source(req: _RunRequest) -> dict:
55
+ result = runtime.run_source(req.source)
56
+ return {
57
+ "ok": result.get("ok", False),
58
+ "stdout": result.get("stdout", ""),
59
+ "stderr": result.get("stderr", ""),
60
+ "error": result.get("error"),
61
+ }
62
+
63
+ @router.get("/health")
64
+ def health() -> dict:
65
+ return {"ok": True, "version": nodus_version}
66
+
67
+ if include_syscalls:
68
+ @router.get("/syscalls")
69
+ def list_syscalls() -> list:
70
+ try:
71
+ from nodus.services.syscall_runtime import list_syscalls as _list
72
+ return _list()
73
+ except ImportError:
74
+ return []
75
+
76
+ if include_memory:
77
+ @router.get("/memory/{key}")
78
+ def memory_get(key: str) -> dict:
79
+ from nodus.services.memory_runtime import get_value
80
+ value = get_value(key)
81
+ return {"key": key, "value": value}
82
+
83
+ @router.post("/memory/{key}")
84
+ def memory_set(key: str, req: _MemoryWriteRequest) -> dict:
85
+ from nodus.services.memory_runtime import put_value
86
+ stored = put_value(key, req.value)
87
+ return {"key": key, "value": stored}
88
+
89
+ @router.delete("/memory/{key}")
90
+ def memory_delete(key: str) -> dict:
91
+ from nodus.services.memory_runtime import delete_value
92
+ found = delete_value(key)
93
+ return {"key": key, "found": found}
94
+
95
+ return router
96
+
97
+
98
+ class NodusTraceMiddleware:
99
+ """ASGI middleware that injects X-Trace-ID into NodusRuntime before each request.
100
+
101
+ Usage::
102
+
103
+ app = FastAPI()
104
+ rt = create_runtime()
105
+ app.add_middleware(NodusTraceMiddleware, runtime=rt)
106
+
107
+ Requires ``nodus-sdk[fastapi]``.
108
+ """
109
+
110
+ def __init__(self, app: Any, *, runtime: "NodusRuntime", header: str = "X-Trace-ID") -> None:
111
+ self.app = app
112
+ self.runtime = runtime
113
+ self.header = header.lower().encode()
114
+
115
+ async def __call__(self, scope: dict, receive: Any, send: Any) -> None:
116
+ if scope["type"] == "http":
117
+ trace_id = None
118
+ for name, value in scope.get("headers", []):
119
+ if name.lower() == self.header:
120
+ trace_id = value.decode()
121
+ break
122
+ if trace_id:
123
+ self.runtime.set_trace_id(trace_id)
124
+ await self.app(scope, receive, send)
@@ -0,0 +1,42 @@
1
+ """HttpBridge — thin bridge over nodus-http."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib.util
6
+ from typing import Any
7
+
8
+ _AVAILABLE = importlib.util.find_spec("nodus_http") is not None
9
+
10
+
11
+ class HttpBridge:
12
+ """Thin bridge wrapping nodus-http's HttpClient with optional circuit-breaker.
13
+
14
+ Requires ``nodus-sdk[http]`` (``nodus-http``).
15
+ """
16
+
17
+ def __init__(
18
+ self,
19
+ base_url: str | None = None,
20
+ timeout: float = 30.0,
21
+ circuit_breaker: Any = None,
22
+ retry_config: Any = None,
23
+ ) -> None:
24
+ self._base_url = base_url
25
+ self._timeout = timeout
26
+ self._circuit_breaker = circuit_breaker
27
+ self._retry_config = retry_config
28
+
29
+ def available(self) -> bool:
30
+ return _AVAILABLE
31
+
32
+ def client(self) -> Any:
33
+ """Return a configured NodusHttpClient."""
34
+ if not _AVAILABLE:
35
+ raise ImportError("nodus-http not installed. pip install nodus-sdk[http]")
36
+ from nodus_http import NodusHttpClient
37
+ kwargs: dict[str, Any] = {}
38
+ if self._base_url:
39
+ kwargs["base_url"] = self._base_url
40
+ if self._circuit_breaker is not None:
41
+ kwargs["circuit_breaker"] = self._circuit_breaker
42
+ return NodusHttpClient(**kwargs)
@@ -0,0 +1,44 @@
1
+ """LLMBridge — thin bridge over nodus-llm's FailoverClient."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib.util
6
+ from typing import Any
7
+
8
+ _AVAILABLE = importlib.util.find_spec("nodus_llm") is not None
9
+
10
+
11
+ class LLMBridge:
12
+ """Thin bridge wrapping nodus-llm for multi-provider LLM failover.
13
+
14
+ Requires ``nodus-sdk[llm]`` (``nodus-llm``).
15
+ """
16
+
17
+ def __init__(self, credentials: list[Any] | None = None) -> None:
18
+ self._credentials = credentials or []
19
+
20
+ def available(self) -> bool:
21
+ return _AVAILABLE
22
+
23
+ def failover_client(self, provider_fn: Any = None) -> Any:
24
+ """Return a FailoverClient configured with provided credentials.
25
+
26
+ provider_fn maps CredentialProfile → LLMClient. Required by nodus-llm;
27
+ pass a callable that constructs a provider-specific client.
28
+ """
29
+ if not _AVAILABLE:
30
+ raise ImportError("nodus-llm not installed. pip install nodus-sdk[llm]")
31
+ if provider_fn is None:
32
+ raise ValueError(
33
+ "provider_fn is required: pass a callable that maps CredentialProfile → LLMClient"
34
+ )
35
+ from nodus_llm import FailoverClient, CredentialStore
36
+ store = CredentialStore(profiles=self._credentials)
37
+ return FailoverClient(store, provider_fn)
38
+
39
+ def credential_store(self) -> Any:
40
+ """Return a CredentialStore from the provided credential profiles."""
41
+ if not _AVAILABLE:
42
+ raise ImportError("nodus-llm not installed. pip install nodus-sdk[llm]")
43
+ from nodus_llm import CredentialStore
44
+ return CredentialStore(profiles=self._credentials)
@@ -0,0 +1,51 @@
1
+ """Observability bridge — thin wrapper over nodus-observability bootstrap."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib.util
6
+
7
+ _AVAILABLE = importlib.util.find_spec("nodus_observability") is not None
8
+
9
+
10
+ def available() -> bool:
11
+ return _AVAILABLE
12
+
13
+
14
+ def init_observability(
15
+ service_name: str,
16
+ *,
17
+ otel: bool = False,
18
+ prometheus: bool = False,
19
+ configure_logging: bool = True,
20
+ ) -> None:
21
+ """Bootstrap observability for the given service.
22
+
23
+ Calls nodus-observability's init_otel() and/or create_registry() depending
24
+ on the flags. Safe to call multiple times (subsequent calls are no-ops at
25
+ the nodus-observability layer).
26
+
27
+ Requires ``nodus-sdk[observability]``.
28
+ """
29
+ if not _AVAILABLE:
30
+ return
31
+
32
+ if configure_logging:
33
+ try:
34
+ from nodus_observability import configure_logging as _conf_logging
35
+ _conf_logging()
36
+ except (ImportError, TypeError):
37
+ pass
38
+
39
+ if otel:
40
+ try:
41
+ from nodus_observability import init_otel
42
+ init_otel(service_name)
43
+ except (ImportError, TypeError):
44
+ pass
45
+
46
+ if prometheus:
47
+ try:
48
+ from nodus_observability import create_registry
49
+ create_registry()
50
+ except (ImportError, TypeError):
51
+ pass