nexus-coding-agent 0.1.0__py3-none-any.whl
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.
- nexus/__init__.py +4 -0
- nexus/application/__init__.py +2 -0
- nexus/application/approval_service.py +130 -0
- nexus/application/diff_service.py +177 -0
- nexus/application/event_publisher.py +180 -0
- nexus/application/execution_context.py +29 -0
- nexus/application/execution_ledger.py +126 -0
- nexus/application/model_call_context.py +29 -0
- nexus/application/observed_model_gateway.py +194 -0
- nexus/application/plan_approval_service.py +250 -0
- nexus/application/planning.py +668 -0
- nexus/application/runtime.py +624 -0
- nexus/application/session_service.py +411 -0
- nexus/application/structured_output.py +96 -0
- nexus/application/telemetry.py +396 -0
- nexus/application/telemetry_subscriber.py +216 -0
- nexus/application/tool_runtime.py +496 -0
- nexus/application/tracing_dispatcher.py +283 -0
- nexus/application/validation.py +293 -0
- nexus/config/__init__.py +17 -0
- nexus/config/loader.py +253 -0
- nexus/config/models.py +310 -0
- nexus/context/__init__.py +6 -0
- nexus/context/budget.py +24 -0
- nexus/context/builder.py +92 -0
- nexus/context/chunking.py +65 -0
- nexus/context/explorer.py +246 -0
- nexus/context/integration.py +63 -0
- nexus/context/manager.py +328 -0
- nexus/context/retrieval.py +261 -0
- nexus/domain/__init__.py +2 -0
- nexus/domain/agent_decision.py +113 -0
- nexus/domain/agent_state.py +49 -0
- nexus/domain/approvals.py +64 -0
- nexus/domain/context.py +108 -0
- nexus/domain/exploration.py +86 -0
- nexus/domain/mcp.py +51 -0
- nexus/domain/model.py +173 -0
- nexus/domain/observability.py +326 -0
- nexus/domain/persistence.py +122 -0
- nexus/domain/planning.py +329 -0
- nexus/domain/ports/__init__.py +61 -0
- nexus/domain/ports/agent_decision.py +9 -0
- nexus/domain/ports/approval_unit_of_work.py +27 -0
- nexus/domain/ports/checkpoint_provider.py +11 -0
- nexus/domain/ports/context.py +71 -0
- nexus/domain/ports/events.py +21 -0
- nexus/domain/ports/graph_runtime.py +30 -0
- nexus/domain/ports/mcp.py +23 -0
- nexus/domain/ports/model_gateway.py +21 -0
- nexus/domain/ports/model_input_budget.py +15 -0
- nexus/domain/ports/planning.py +62 -0
- nexus/domain/ports/repositories.py +54 -0
- nexus/domain/ports/repository_context.py +18 -0
- nexus/domain/ports/session_unit_of_work.py +33 -0
- nexus/domain/ports/skills.py +41 -0
- nexus/domain/ports/tooling.py +39 -0
- nexus/domain/ports/tracer.py +13 -0
- nexus/domain/ports/validation.py +32 -0
- nexus/domain/runtime_events.py +445 -0
- nexus/domain/skills.py +129 -0
- nexus/domain/tooling.py +163 -0
- nexus/domain/validation.py +161 -0
- nexus/errors/__init__.py +82 -0
- nexus/evaluation/__init__.py +7 -0
- nexus/evaluation/assertions.py +4 -0
- nexus/evaluation/evaluator.py +263 -0
- nexus/evaluation/fixtures.py +36 -0
- nexus/evaluation/harness.py +606 -0
- nexus/evaluation/loader.py +415 -0
- nexus/evaluation/metrics.py +27 -0
- nexus/evaluation/models.py +362 -0
- nexus/evaluation/report.py +43 -0
- nexus/evaluation/runner.py +480 -0
- nexus/infrastructure/__init__.py +2 -0
- nexus/infrastructure/asyncio_compat.py +13 -0
- nexus/infrastructure/bootstrap/__init__.py +17 -0
- nexus/infrastructure/bootstrap/composition.py +663 -0
- nexus/infrastructure/checkpoint/__init__.py +5 -0
- nexus/infrastructure/checkpoint/postgres.py +62 -0
- nexus/infrastructure/database.py +39 -0
- nexus/infrastructure/embedding.py +61 -0
- nexus/infrastructure/graph/__init__.py +6 -0
- nexus/infrastructure/graph/day4_runtime.py +966 -0
- nexus/infrastructure/graph/langgraph_runtime.py +172 -0
- nexus/infrastructure/mcp/__init__.py +5 -0
- nexus/infrastructure/mcp/manager.py +380 -0
- nexus/infrastructure/model_gateway/__init__.py +6 -0
- nexus/infrastructure/model_gateway/openai_compatible.py +345 -0
- nexus/infrastructure/observability/__init__.py +7 -0
- nexus/infrastructure/observability/console.py +31 -0
- nexus/infrastructure/observability/langsmith.py +236 -0
- nexus/infrastructure/observability/structured_logger.py +70 -0
- nexus/infrastructure/persistence/__init__.py +13 -0
- nexus/infrastructure/persistence/approval_unit_of_work.py +74 -0
- nexus/infrastructure/persistence/models.py +146 -0
- nexus/infrastructure/persistence/repositories.py +326 -0
- nexus/infrastructure/persistence/unit_of_work.py +82 -0
- nexus/infrastructure/repository_files.py +117 -0
- nexus/infrastructure/sandbox/__init__.py +5 -0
- nexus/infrastructure/sandbox/local_process.py +353 -0
- nexus/infrastructure/semantic.py +276 -0
- nexus/infrastructure/semantic_models.py +56 -0
- nexus/interfaces/__init__.py +2 -0
- nexus/interfaces/cli/__init__.py +2 -0
- nexus/interfaces/cli/__main__.py +6 -0
- nexus/interfaces/cli/app.py +266 -0
- nexus/interfaces/cli/renderer.py +118 -0
- nexus/security/__init__.py +14 -0
- nexus/security/approval_policies.py +73 -0
- nexus/security/command_policy.py +117 -0
- nexus/security/executables.py +107 -0
- nexus/security/git_commands.py +65 -0
- nexus/security/workspace.py +93 -0
- nexus/skills/__init__.py +7 -0
- nexus/skills/builtin/__init__.py +1 -0
- nexus/skills/builtin/debug-python/SKILL.md +26 -0
- nexus/skills/builtin/review-repository/SKILL.md +26 -0
- nexus/skills/builtin/write-tests/SKILL.md +26 -0
- nexus/skills/loader.py +439 -0
- nexus/skills/registry.py +146 -0
- nexus/skills/selector.py +152 -0
- nexus/tools/__init__.py +6 -0
- nexus/tools/editing.py +312 -0
- nexus/tools/mcp.py +160 -0
- nexus/tools/native.py +654 -0
- nexus/tools/registry.py +27 -0
- nexus_coding_agent-0.1.0.dist-info/METADATA +142 -0
- nexus_coding_agent-0.1.0.dist-info/RECORD +131 -0
- nexus_coding_agent-0.1.0.dist-info/WHEEL +4 -0
- nexus_coding_agent-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Lifecycle adapter for the official asynchronous PostgreSQL checkpointer."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from contextlib import AbstractAsyncContextManager
|
|
6
|
+
|
|
7
|
+
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
|
8
|
+
from sqlalchemy.engine import make_url
|
|
9
|
+
|
|
10
|
+
from nexus.errors import NexusError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PostgresCheckpointProvider:
|
|
14
|
+
"""Own AsyncPostgresSaver creation, setup, and release."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, database_url: str) -> None:
|
|
17
|
+
self._connection_string = _to_psycopg_connection_string(database_url)
|
|
18
|
+
self._context: AbstractAsyncContextManager[AsyncPostgresSaver] | None = None
|
|
19
|
+
self._checkpointer: AsyncPostgresSaver | None = None
|
|
20
|
+
|
|
21
|
+
async def setup(self) -> None:
|
|
22
|
+
if self._checkpointer is not None:
|
|
23
|
+
return
|
|
24
|
+
context = AsyncPostgresSaver.from_conn_string(self._connection_string)
|
|
25
|
+
self._context = context
|
|
26
|
+
try:
|
|
27
|
+
checkpointer = await context.__aenter__()
|
|
28
|
+
await checkpointer.setup()
|
|
29
|
+
except Exception as exc:
|
|
30
|
+
self._context = None
|
|
31
|
+
try:
|
|
32
|
+
await context.__aexit__(type(exc), exc, exc.__traceback__)
|
|
33
|
+
except Exception:
|
|
34
|
+
pass
|
|
35
|
+
raise NexusError(
|
|
36
|
+
"Nexus could not initialize durable graph checkpoints.",
|
|
37
|
+
code="CHECKPOINT_SETUP_ERROR",
|
|
38
|
+
retryable=True,
|
|
39
|
+
) from exc
|
|
40
|
+
self._checkpointer = checkpointer
|
|
41
|
+
|
|
42
|
+
def get_checkpointer(self) -> object:
|
|
43
|
+
if self._checkpointer is None:
|
|
44
|
+
raise RuntimeError("CheckpointProvider.setup() must run before use.")
|
|
45
|
+
return self._checkpointer
|
|
46
|
+
|
|
47
|
+
async def close(self) -> None:
|
|
48
|
+
context = self._context
|
|
49
|
+
self._context = None
|
|
50
|
+
self._checkpointer = None
|
|
51
|
+
if context is not None:
|
|
52
|
+
await context.__aexit__(None, None, None)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _to_psycopg_connection_string(database_url: str) -> str:
|
|
56
|
+
url = make_url(database_url)
|
|
57
|
+
if url.get_backend_name() != "postgresql":
|
|
58
|
+
raise NexusError(
|
|
59
|
+
"The checkpoint database must use PostgreSQL.",
|
|
60
|
+
code="CHECKPOINT_CONFIGURATION_ERROR",
|
|
61
|
+
)
|
|
62
|
+
return url.set(drivername="postgresql").render_as_string(hide_password=False)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Day 1 PostgreSQL engine bootstrap and connectivity check."""
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import text
|
|
4
|
+
from sqlalchemy.ext.asyncio import (
|
|
5
|
+
AsyncEngine,
|
|
6
|
+
AsyncSession,
|
|
7
|
+
async_sessionmaker,
|
|
8
|
+
create_async_engine,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DatabaseBootstrap:
|
|
13
|
+
"""Own the Day 1 async engine without introducing business persistence."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, database_url: str) -> None:
|
|
16
|
+
self._engine: AsyncEngine = create_async_engine(
|
|
17
|
+
database_url,
|
|
18
|
+
connect_args={"timeout": 5},
|
|
19
|
+
hide_parameters=True,
|
|
20
|
+
pool_timeout=5,
|
|
21
|
+
)
|
|
22
|
+
self._session_factory = async_sessionmaker(self._engine, expire_on_commit=False)
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def session_factory(self) -> async_sessionmaker[AsyncSession]:
|
|
26
|
+
"""Provide transaction-scoped sessions to infrastructure adapters."""
|
|
27
|
+
|
|
28
|
+
return self._session_factory
|
|
29
|
+
|
|
30
|
+
async def check_connection(self) -> None:
|
|
31
|
+
"""Open a connection and execute the smallest useful smoke query."""
|
|
32
|
+
|
|
33
|
+
async with self._engine.connect() as connection:
|
|
34
|
+
await connection.execute(text("SELECT 1"))
|
|
35
|
+
|
|
36
|
+
async def close(self) -> None:
|
|
37
|
+
"""Dispose the engine pool and any checked-in connections."""
|
|
38
|
+
|
|
39
|
+
await self._engine.dispose()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Independent LangChain OpenAI-compatible embedding adapter."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from math import isfinite
|
|
5
|
+
|
|
6
|
+
from langchain_openai import OpenAIEmbeddings
|
|
7
|
+
|
|
8
|
+
from nexus.config.models import RuntimeConfig
|
|
9
|
+
from nexus.domain.context import EmbeddingConfig
|
|
10
|
+
from nexus.errors import ContextError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class OpenAICompatibleEmbeddingGateway:
|
|
14
|
+
def __init__(self, config: RuntimeConfig) -> None:
|
|
15
|
+
config.require_embedding()
|
|
16
|
+
self._config = EmbeddingConfig(
|
|
17
|
+
config.embedding_provider,
|
|
18
|
+
config.embedding_model,
|
|
19
|
+
config.embedding_dimension,
|
|
20
|
+
)
|
|
21
|
+
self._client = OpenAIEmbeddings(
|
|
22
|
+
model=config.embedding_model,
|
|
23
|
+
base_url=config.embedding_base_url,
|
|
24
|
+
api_key=config.embedding_api_key,
|
|
25
|
+
dimensions=config.embedding_dimension,
|
|
26
|
+
check_embedding_ctx_length=False,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def config(self) -> EmbeddingConfig:
|
|
31
|
+
return self._config
|
|
32
|
+
|
|
33
|
+
async def embed_documents(self, texts: Sequence[str]) -> tuple[tuple[float, ...], ...]:
|
|
34
|
+
if not texts:
|
|
35
|
+
return ()
|
|
36
|
+
try:
|
|
37
|
+
vectors = await self._client.aembed_documents(list(texts))
|
|
38
|
+
return validate_vectors(vectors, len(texts), self.config.dimension)
|
|
39
|
+
except Exception as exc:
|
|
40
|
+
raise ContextError(
|
|
41
|
+
"Embedding request failed or returned invalid vectors.",
|
|
42
|
+
code="EMBEDDING_FAILED",
|
|
43
|
+
retryable=True,
|
|
44
|
+
) from exc
|
|
45
|
+
|
|
46
|
+
async def embed_query(self, text: str) -> tuple[float, ...]:
|
|
47
|
+
return (await self.embed_documents((text,)))[0]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def validate_vectors(
|
|
51
|
+
vectors: Sequence[Sequence[float]],
|
|
52
|
+
count: int,
|
|
53
|
+
dimension: int,
|
|
54
|
+
) -> tuple[tuple[float, ...], ...]:
|
|
55
|
+
result = tuple(tuple(float(value) for value in vector) for vector in vectors)
|
|
56
|
+
if len(result) != count or any(
|
|
57
|
+
len(vector) != dimension or not all(isfinite(value) for value in vector) or not any(vector)
|
|
58
|
+
for vector in result
|
|
59
|
+
):
|
|
60
|
+
raise ContextError("Invalid embedding shape or values.", code="EMBEDDING_FAILED")
|
|
61
|
+
return result
|