nanoscrypt 0.2.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.
Files changed (73) hide show
  1. nanoscrypt/__init__.py +1 -0
  2. nanoscrypt/api/__init__.py +1 -0
  3. nanoscrypt/api/app.py +56 -0
  4. nanoscrypt/api/dependencies.py +92 -0
  5. nanoscrypt/api/routers/__init__.py +1 -0
  6. nanoscrypt/api/routers/agents.py +94 -0
  7. nanoscrypt/api/routers/approval.py +66 -0
  8. nanoscrypt/api/routers/audit.py +67 -0
  9. nanoscrypt/api/routers/health.py +12 -0
  10. nanoscrypt/api/routers/sessions.py +24 -0
  11. nanoscrypt/api/routers/tasks.py +47 -0
  12. nanoscrypt/api/routers/tools.py +55 -0
  13. nanoscrypt/api/schemas.py +99 -0
  14. nanoscrypt/cli/__init__.py +1 -0
  15. nanoscrypt/cli/commands/__init__.py +1 -0
  16. nanoscrypt/cli/commands/agents.py +118 -0
  17. nanoscrypt/cli/commands/init.py +43 -0
  18. nanoscrypt/cli/commands/run.py +572 -0
  19. nanoscrypt/cli/commands/serve.py +14 -0
  20. nanoscrypt/cli/commands/tools.py +92 -0
  21. nanoscrypt/cli/main.py +30 -0
  22. nanoscrypt/config/__init__.py +1 -0
  23. nanoscrypt/config/settings.py +123 -0
  24. nanoscrypt/core/__init__.py +1 -0
  25. nanoscrypt/core/approval.py +152 -0
  26. nanoscrypt/core/audit.py +61 -0
  27. nanoscrypt/core/code_agent.py +406 -0
  28. nanoscrypt/core/command_handlers.py +219 -0
  29. nanoscrypt/core/command_router.py +22 -0
  30. nanoscrypt/core/compressor.py +91 -0
  31. nanoscrypt/core/context.py +229 -0
  32. nanoscrypt/core/events.py +80 -0
  33. nanoscrypt/core/generator.py +61 -0
  34. nanoscrypt/core/guardrails.py +206 -0
  35. nanoscrypt/core/harness.py +120 -0
  36. nanoscrypt/core/hooks.py +74 -0
  37. nanoscrypt/core/loop.py +76 -0
  38. nanoscrypt/core/memmachine_engine.py +78 -0
  39. nanoscrypt/core/memory.py +270 -0
  40. nanoscrypt/core/orchestrator.py +1019 -0
  41. nanoscrypt/core/pipeline.py +119 -0
  42. nanoscrypt/core/planner.py +38 -0
  43. nanoscrypt/core/postprocessor.py +442 -0
  44. nanoscrypt/core/registry.py +200 -0
  45. nanoscrypt/core/repair.py +393 -0
  46. nanoscrypt/core/runtime.py +429 -0
  47. nanoscrypt/core/validator.py +1009 -0
  48. nanoscrypt/core/versioning.py +157 -0
  49. nanoscrypt/llm/__init__.py +1 -0
  50. nanoscrypt/llm/base.py +22 -0
  51. nanoscrypt/llm/litellm_provider.py +286 -0
  52. nanoscrypt/llm/prompts/__init__.py +1 -0
  53. nanoscrypt/llm/prompts/generator.py +158 -0
  54. nanoscrypt/llm/prompts/planner.py +35 -0
  55. nanoscrypt/llm/prompts/repair.py +217 -0
  56. nanoscrypt/logging.py +29 -0
  57. nanoscrypt/models/__init__.py +1 -0
  58. nanoscrypt/models/agent.py +27 -0
  59. nanoscrypt/models/application.py +46 -0
  60. nanoscrypt/models/database.py +147 -0
  61. nanoscrypt/models/permissions.py +19 -0
  62. nanoscrypt/models/plan.py +39 -0
  63. nanoscrypt/models/session.py +22 -0
  64. nanoscrypt/models/tool.py +46 -0
  65. nanoscrypt/py.typed +1 -0
  66. nanoscrypt/utils/__init__.py +1 -0
  67. nanoscrypt/utils/async_runner.py +52 -0
  68. nanoscrypt/utils/filesystem.py +38 -0
  69. nanoscrypt/utils/hashing.py +8 -0
  70. nanoscrypt-0.2.0.dist-info/METADATA +769 -0
  71. nanoscrypt-0.2.0.dist-info/RECORD +73 -0
  72. nanoscrypt-0.2.0.dist-info/WHEEL +4 -0
  73. nanoscrypt-0.2.0.dist-info/entry_points.txt +2 -0
nanoscrypt/__init__.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1 @@
1
+ # Initialize subpackage
nanoscrypt/api/app.py ADDED
@@ -0,0 +1,56 @@
1
+ from contextlib import asynccontextmanager
2
+
3
+ from fastapi import FastAPI
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+
6
+ from nanoscrypt.api.dependencies import get_registry
7
+ from nanoscrypt.api.routers import (
8
+ agents,
9
+ approval,
10
+ audit,
11
+ health,
12
+ sessions,
13
+ tasks,
14
+ tools,
15
+ )
16
+ from nanoscrypt.logging import setup_logging
17
+
18
+
19
+ @asynccontextmanager
20
+ async def lifespan(app: FastAPI):
21
+ setup_logging()
22
+ yield
23
+ registry = await get_registry()
24
+ await registry.engine.dispose()
25
+
26
+
27
+ def create_app() -> FastAPI:
28
+ app = FastAPI(
29
+ title="Nanoscrypt API",
30
+ description="REST API for the standalone Nanoscrypt tool-synthesis framework",
31
+ version="0.2.0",
32
+ lifespan=lifespan,
33
+ )
34
+
35
+ # Enable CORS for frontend integration
36
+ app.add_middleware(
37
+ CORSMiddleware,
38
+ allow_origins=["*"],
39
+ allow_credentials=True,
40
+ allow_methods=["*"],
41
+ allow_headers=["*"],
42
+ )
43
+
44
+ # Mount API routers under /api/v1 prefix
45
+ app.include_router(health.router, prefix="/api/v1")
46
+ app.include_router(sessions.router, prefix="/api/v1")
47
+ app.include_router(tasks.router, prefix="/api/v1")
48
+ app.include_router(tools.router, prefix="/api/v1")
49
+ app.include_router(agents.router, prefix="/api/v1")
50
+ app.include_router(approval.router, prefix="/api/v1")
51
+ app.include_router(audit.router, prefix="/api/v1")
52
+
53
+ return app
54
+
55
+
56
+ app = create_app()
@@ -0,0 +1,92 @@
1
+ from nanoscrypt.config.settings import settings
2
+ from nanoscrypt.core.approval import ApprovalGate
3
+ from nanoscrypt.core.audit import AuditLogger
4
+ from nanoscrypt.core.context import ContextBuilder
5
+ from nanoscrypt.core.generator import ToolGenerator
6
+
7
+ # Enterprise imports v0.2.0
8
+ from nanoscrypt.core.hooks import HookManager
9
+ from nanoscrypt.core.memory import LongTermMemory, ShortTermMemory
10
+ from nanoscrypt.core.orchestrator import Orchestrator
11
+ from nanoscrypt.core.planner import Planner
12
+ from nanoscrypt.core.registry import ToolRegistry
13
+ from nanoscrypt.core.repair import RepairLoop
14
+ from nanoscrypt.core.runtime import RuntimeManager
15
+ from nanoscrypt.core.validator import ToolValidator
16
+ from nanoscrypt.core.versioning import VersionManager
17
+ from nanoscrypt.llm.litellm_provider import LiteLLMProvider
18
+
19
+ # We cache registry instance globally to prevent re-opening database connections
20
+ _registry: ToolRegistry | None = None
21
+ _orchestrator: Orchestrator | None = None
22
+
23
+
24
+ def get_settings():
25
+ return settings
26
+
27
+
28
+ async def get_registry() -> ToolRegistry:
29
+ global _registry
30
+ if _registry is None:
31
+ cfg = get_settings()
32
+ _registry = ToolRegistry(cfg.registry.database_url)
33
+ await _registry.initialize_db()
34
+ return _registry
35
+
36
+
37
+ async def get_orchestrator() -> Orchestrator:
38
+ global _orchestrator
39
+ if _orchestrator is not None:
40
+ return _orchestrator
41
+
42
+ cfg = get_settings()
43
+
44
+ # Initialize LiteLLM wrapper
45
+ llm = LiteLLMProvider(
46
+ default_model=cfg.llm.model,
47
+ temperature=cfg.llm.temperature,
48
+ max_tokens=cfg.llm.max_tokens,
49
+ )
50
+
51
+ registry = await get_registry()
52
+
53
+ context_builder = ContextBuilder(workspace_root="./") # Scan workspace root
54
+ planner = Planner(llm=llm)
55
+ generator = ToolGenerator(llm=llm)
56
+ validator = ToolValidator(llm=llm)
57
+ runtime_manager = RuntimeManager(
58
+ workspace_root=cfg.runtime.workspace_root,
59
+ timeout_seconds=cfg.runtime.timeout_seconds,
60
+ )
61
+ version_manager = VersionManager(tools_dir=cfg.registry.tools_dir)
62
+
63
+ repair_loop = RepairLoop(
64
+ llm=llm,
65
+ validator=validator,
66
+ runtime_manager=runtime_manager,
67
+ max_attempts=cfg.resilience.max_repair_attempts,
68
+ )
69
+
70
+ # Instantiate enterprise helpers
71
+ hook_manager = HookManager()
72
+ approval_gate = ApprovalGate()
73
+ audit_logger = AuditLogger(session_factory=registry.session_factory)
74
+ short_term_memory = ShortTermMemory(max_entries=cfg.memory.short_term_max_entries)
75
+ long_term_memory = LongTermMemory(session_factory=registry.session_factory)
76
+
77
+ _orchestrator = Orchestrator(
78
+ context_builder=context_builder,
79
+ planner=planner,
80
+ generator=generator,
81
+ validator=validator,
82
+ runtime_manager=runtime_manager,
83
+ registry=registry,
84
+ version_manager=version_manager,
85
+ repair_loop=repair_loop,
86
+ hook_manager=hook_manager,
87
+ approval_gate=approval_gate,
88
+ audit_logger=audit_logger,
89
+ short_term_memory=short_term_memory,
90
+ long_term_memory=long_term_memory,
91
+ )
92
+ return _orchestrator
@@ -0,0 +1 @@
1
+ # Initialize subpackage
@@ -0,0 +1,94 @@
1
+ from fastapi import APIRouter, Depends, HTTPException
2
+ from sqlalchemy import select
3
+
4
+ from nanoscrypt.api.dependencies import get_registry
5
+ from nanoscrypt.api.schemas import AgentCreate, AgentPermissionsSchema, AgentResponse
6
+ from nanoscrypt.core.registry import ToolRegistry
7
+ from nanoscrypt.models.database import DBAgentDefinition
8
+
9
+ router = APIRouter(prefix="/agents", tags=["agents"])
10
+
11
+
12
+ @router.post("", response_model=AgentResponse)
13
+ async def create_agent(
14
+ payload: AgentCreate, registry: ToolRegistry = Depends(get_registry)
15
+ ):
16
+ """Registers a new agent role in the persistent registry database."""
17
+ async with registry.session_factory() as session:
18
+ async with session.begin():
19
+ # Check if name unique
20
+ stmt = select(DBAgentDefinition).where(
21
+ DBAgentDefinition.name == payload.name
22
+ )
23
+ res = await session.execute(stmt)
24
+ existing = res.scalar_one_or_none()
25
+ if existing:
26
+ raise HTTPException(
27
+ status_code=400,
28
+ detail=f"Agent with name '{payload.name}' already exists.",
29
+ )
30
+
31
+ agent_db = DBAgentDefinition(
32
+ name=payload.name,
33
+ role=payload.role,
34
+ goal=payload.goal,
35
+ backstory=payload.backstory,
36
+ tools=payload.tools,
37
+ permissions=payload.permissions.model_dump(),
38
+ )
39
+ session.add(agent_db)
40
+ await session.flush()
41
+
42
+ return AgentResponse(
43
+ name=agent_db.name,
44
+ role=agent_db.role,
45
+ goal=agent_db.goal,
46
+ backstory=agent_db.backstory,
47
+ tools=agent_db.tools,
48
+ permissions=AgentPermissionsSchema(**agent_db.permissions),
49
+ created_at=agent_db.created_at,
50
+ )
51
+
52
+
53
+ @router.get("", response_model=list[AgentResponse])
54
+ async def list_agents(registry: ToolRegistry = Depends(get_registry)):
55
+ """Lists all registered agent configurations."""
56
+ async with registry.session_factory() as session:
57
+ stmt = select(DBAgentDefinition)
58
+ res = await session.execute(stmt)
59
+ agents = res.scalars().all()
60
+ response = []
61
+ for a in agents:
62
+ response.append(
63
+ AgentResponse(
64
+ name=a.name,
65
+ role=a.role,
66
+ goal=a.goal,
67
+ backstory=a.backstory,
68
+ tools=a.tools,
69
+ permissions=AgentPermissionsSchema(**a.permissions),
70
+ created_at=a.created_at,
71
+ )
72
+ )
73
+ return response
74
+
75
+
76
+ @router.get("/{name}", response_model=AgentResponse)
77
+ async def get_agent(name: str, registry: ToolRegistry = Depends(get_registry)):
78
+ """Retrieves details of a specific agent role configuration."""
79
+ async with registry.session_factory() as session:
80
+ stmt = select(DBAgentDefinition).where(DBAgentDefinition.name == name)
81
+ res = await session.execute(stmt)
82
+ a = res.scalar_one_or_none()
83
+ if not a:
84
+ raise HTTPException(status_code=404, detail=f"Agent '{name}' not found.")
85
+
86
+ return AgentResponse(
87
+ name=a.name,
88
+ role=a.role,
89
+ goal=a.goal,
90
+ backstory=a.backstory,
91
+ tools=a.tools,
92
+ permissions=AgentPermissionsSchema(**a.permissions),
93
+ created_at=a.created_at,
94
+ )
@@ -0,0 +1,66 @@
1
+ from fastapi import APIRouter, Depends, HTTPException, Query
2
+
3
+ from nanoscrypt.api.dependencies import get_orchestrator
4
+ from nanoscrypt.api.schemas import ApprovalRecordResponse, ApprovalResolution
5
+ from nanoscrypt.core.approval import ApprovalStatus
6
+ from nanoscrypt.core.orchestrator import Orchestrator
7
+
8
+ router = APIRouter(prefix="/approvals", tags=["approvals"])
9
+
10
+
11
+ @router.get("/pending", response_model=list[ApprovalRecordResponse])
12
+ async def list_pending_approvals(
13
+ session_id: str | None = Query(
14
+ None, description="Filter approvals by active session ID"
15
+ ),
16
+ orchestrator: Orchestrator = Depends(get_orchestrator),
17
+ ):
18
+ """Lists all active human-in-the-loop pending approval requests."""
19
+ pending = orchestrator.approval_gate.get_pending(session_id)
20
+ response = []
21
+ for r in pending:
22
+ response.append(
23
+ ApprovalRecordResponse(
24
+ id=r.id,
25
+ session_id=r.session_id,
26
+ approval_type=r.approval_type.value,
27
+ description=r.description,
28
+ risk_level=r.risk_level,
29
+ resource_details=r.resource_details,
30
+ agent_name=r.agent_name,
31
+ status=r.status.value,
32
+ timestamp=r.timestamp,
33
+ resolved_at=r.resolved_at,
34
+ reason=r.reason,
35
+ )
36
+ )
37
+ return response
38
+
39
+
40
+ @router.post("/{request_id}/resolve", response_model=dict[str, str])
41
+ async def resolve_approval_request(
42
+ request_id: str,
43
+ payload: ApprovalResolution,
44
+ orchestrator: Orchestrator = Depends(get_orchestrator),
45
+ ):
46
+ """Approves or denies a pending approval request."""
47
+ if request_id not in orchestrator.approval_gate.pending_requests:
48
+ raise HTTPException(
49
+ status_code=404, detail="Pending approval request not found."
50
+ )
51
+
52
+ status = ApprovalStatus.APPROVED if payload.approved else ApprovalStatus.DENIED
53
+ success = orchestrator.approval_gate.resolve_request(
54
+ request_id=request_id,
55
+ status=status,
56
+ reason=payload.reason or "Resolved via API call.",
57
+ )
58
+ if not success:
59
+ raise HTTPException(
60
+ status_code=500, detail="Failed to resolve approval request."
61
+ )
62
+
63
+ return {
64
+ "status": "success",
65
+ "message": f"Request has been resolved to '{status.value}'.",
66
+ }
@@ -0,0 +1,67 @@
1
+ from typing import Any
2
+
3
+ from fastapi import APIRouter, Depends, Query
4
+ from sqlalchemy import select
5
+
6
+ from nanoscrypt.api.dependencies import get_registry
7
+ from nanoscrypt.api.schemas import AuditLogResponse
8
+ from nanoscrypt.core.registry import ToolRegistry
9
+ from nanoscrypt.models.database import DBAuditLog
10
+
11
+ router = APIRouter(prefix="/audit", tags=["audit"])
12
+
13
+
14
+ @router.get("", response_model=list[AuditLogResponse])
15
+ async def query_audit_logs(
16
+ session_id: str | None = Query(None, description="Filter logs by session ID"),
17
+ event_type: str | None = Query(None, description="Filter logs by event type"),
18
+ limit: int = Query(50, description="Maximum number of log entries to retrieve"),
19
+ registry: ToolRegistry = Depends(get_registry),
20
+ ):
21
+ """Retrieves immutable audit logs from database with optional filters."""
22
+ async with registry.session_factory() as session:
23
+ stmt = select(DBAuditLog)
24
+
25
+ # Apply filters
26
+ if session_id:
27
+ stmt = stmt.where(DBAuditLog.session_id == session_id)
28
+ if event_type:
29
+ stmt = stmt.where(DBAuditLog.event_type == event_type)
30
+
31
+ stmt = stmt.order_by(DBAuditLog.timestamp.desc()).limit(limit)
32
+ res = await session.execute(stmt)
33
+ logs = res.scalars().all()
34
+
35
+ response = []
36
+ for l in logs:
37
+ response.append(
38
+ AuditLogResponse(
39
+ id=l.id,
40
+ event_type=l.event_type,
41
+ session_id=l.session_id,
42
+ agent_name=l.agent_name,
43
+ details=l.details,
44
+ cost=l.cost,
45
+ token_usage=l.token_usage,
46
+ timestamp=l.timestamp,
47
+ )
48
+ )
49
+ return response
50
+
51
+
52
+ @router.get("/summary", response_model=dict[str, Any])
53
+ async def get_audit_summary(registry: ToolRegistry = Depends(get_registry)):
54
+ """Aggregates costs and token usage totals across all runs."""
55
+ async with registry.session_factory() as session:
56
+ stmt = select(DBAuditLog.cost, DBAuditLog.token_usage)
57
+ res = await session.execute(stmt)
58
+ records = res.all()
59
+
60
+ total_cost = sum(r[0] for r in records)
61
+ total_tokens = sum(r[1] for r in records)
62
+
63
+ return {
64
+ "total_runs": len(records),
65
+ "total_estimated_cost_usd": float(total_cost),
66
+ "total_tokens_consumed": int(total_tokens),
67
+ }
@@ -0,0 +1,12 @@
1
+ from fastapi import APIRouter
2
+
3
+ router = APIRouter(prefix="/health", tags=["system"])
4
+
5
+
6
+ @router.get("")
7
+ def health_check():
8
+ """
9
+ Check the health status of the API.
10
+ Returns a simple JSON response indicating the service is running.
11
+ """
12
+ return {"status": "ok", "service": "nanoscrypt-api"}
@@ -0,0 +1,24 @@
1
+ import uuid
2
+ from datetime import datetime, timezone
3
+
4
+ from fastapi import APIRouter, Depends
5
+
6
+ from nanoscrypt.api.dependencies import get_settings
7
+ from nanoscrypt.api.schemas import SessionCreate, SessionResponse
8
+ from nanoscrypt.config.settings import Settings
9
+
10
+ router = APIRouter(prefix="/sessions", tags=["sessions"])
11
+
12
+
13
+ @router.post("", response_model=SessionResponse)
14
+ def create_session(payload: SessionCreate, cfg: Settings = Depends(get_settings)):
15
+ """
16
+ Create a new execution session.
17
+ Allocates a workspace path based on the session ID.
18
+ """
19
+ session_id = payload.session_id or f"sess_{uuid.uuid4().hex[:8]}"
20
+ workspace_path = f"{cfg.runtime.workspace_root}/{session_id}"
21
+
22
+ return SessionResponse(
23
+ id=session_id, workspace_path=workspace_path, created_at=datetime.now(timezone.utc)
24
+ )
@@ -0,0 +1,47 @@
1
+ from fastapi import APIRouter, Depends, HTTPException, Query
2
+
3
+ from nanoscrypt.api.dependencies import get_orchestrator
4
+ from nanoscrypt.api.schemas import TaskResponse, TaskSubmit
5
+ from nanoscrypt.core.orchestrator import Orchestrator
6
+ from nanoscrypt.models.session import Session
7
+
8
+ router = APIRouter(prefix="/tasks", tags=["tasks"])
9
+
10
+
11
+ @router.post("", response_model=TaskResponse)
12
+ async def submit_task(
13
+ payload: TaskSubmit,
14
+ session_id: str = Query(
15
+ ..., description="Active session ID to bound the execution workspace"
16
+ ),
17
+ orchestrator: Orchestrator = Depends(get_orchestrator),
18
+ ):
19
+ """
20
+ Submit a task to be executed by the orchestrator.
21
+ Requires a session_id to bound the execution workspace.
22
+ """
23
+ # Initialize ephemeral session tracking
24
+ session = Session(id=session_id, workspace_path=f"./workspaces/{session_id}")
25
+
26
+ try:
27
+ result = await orchestrator.execute_task(
28
+ user_prompt=payload.prompt, session=session
29
+ )
30
+
31
+ # Map execution outcome to target HTTP response format
32
+ return TaskResponse(
33
+ status=result.get("status", "error"),
34
+ action_taken=result.get("action_taken", "none"),
35
+ tool_name=result.get("tool_name"),
36
+ version=result.get("version"),
37
+ output=result.get("output") or result.get("response"),
38
+ error=result.get("error") or result.get("message"),
39
+ runtime_ms=result.get("runtime_ms"),
40
+ )
41
+ except Exception as e:
42
+ import logging
43
+
44
+ logging.error(f"Task execution failed inside engine: {e!s}")
45
+ raise HTTPException(
46
+ status_code=500, detail="An internal error occurred during task execution."
47
+ )
@@ -0,0 +1,55 @@
1
+ from fastapi import APIRouter, Depends, HTTPException
2
+
3
+ from nanoscrypt.api.dependencies import get_registry
4
+ from nanoscrypt.api.schemas import ToolResponse
5
+ from nanoscrypt.core.registry import ToolRegistry
6
+
7
+ router = APIRouter(prefix="/tools", tags=["tools"])
8
+
9
+
10
+ @router.get("", response_model=list[ToolResponse])
11
+ async def list_tools(query: str = "", registry: ToolRegistry = Depends(get_registry)):
12
+ """
13
+ List or search available tools in the registry.
14
+ Optional query parameter filters tools by name or description.
15
+ """
16
+ tools = await registry.search(query)
17
+ response = []
18
+ for t in tools:
19
+ response.append(
20
+ ToolResponse(
21
+ name=t.name,
22
+ purpose=t.purpose,
23
+ language=t.language,
24
+ current_version=t.current_version,
25
+ success_rate=t.success_rate,
26
+ usage_count=t.usage_count,
27
+ status=t.status,
28
+ created_at=t.created_at,
29
+ )
30
+ )
31
+ return response
32
+
33
+
34
+ @router.get("/{name}", response_model=ToolResponse)
35
+ async def get_tool(name: str, registry: ToolRegistry = Depends(get_registry)):
36
+ """
37
+ Get a specific tool's details by its name.
38
+ Returns a 404 error if the tool is not found.
39
+ """
40
+ t = await registry.get(name)
41
+ if not t:
42
+ raise HTTPException(
43
+ status_code=404, detail=f"Tool '{name}' not found or inactive in registry."
44
+ )
45
+
46
+ return ToolResponse(
47
+ name=t.name,
48
+ purpose=t.purpose,
49
+ language=t.language,
50
+ current_version=t.current_version,
51
+ success_rate=t.success_rate,
52
+ usage_count=t.usage_count,
53
+ status=t.status,
54
+ created_at=t.created_at,
55
+ )
@@ -0,0 +1,99 @@
1
+ from datetime import datetime
2
+ from typing import Any
3
+
4
+ from pydantic import BaseModel, Field
5
+
6
+
7
+ class SessionCreate(BaseModel):
8
+ session_id: str | None = None
9
+
10
+
11
+ class SessionResponse(BaseModel):
12
+ id: str
13
+ workspace_path: str
14
+ created_at: datetime
15
+
16
+
17
+ class TaskSubmit(BaseModel):
18
+ prompt: str
19
+
20
+
21
+ class TaskResponse(BaseModel):
22
+ status: str
23
+ action_taken: str
24
+ tool_name: str | None = None
25
+ version: int | None = None
26
+ output: str | None = None
27
+ error: str | None = None
28
+ runtime_ms: int | None = None
29
+
30
+
31
+ class ToolResponse(BaseModel):
32
+ name: str
33
+ purpose: str
34
+ language: str
35
+ current_version: int
36
+ success_rate: float
37
+ usage_count: int
38
+ status: str
39
+ created_at: datetime
40
+
41
+
42
+ # --- ENTERPRISE SCHEMAS V0.2.0 ---
43
+
44
+
45
+ class AgentPermissionsSchema(BaseModel):
46
+ file_system: str = "deny"
47
+ network: str = "deny"
48
+ tool_generation: str = "execute"
49
+ tool_execution: str = "execute"
50
+ delegation: bool = False
51
+
52
+
53
+ class AgentCreate(BaseModel):
54
+ name: str
55
+ role: str
56
+ goal: str
57
+ backstory: str = ""
58
+ tools: list[str] = Field(default_factory=list)
59
+ permissions: AgentPermissionsSchema = Field(default_factory=AgentPermissionsSchema)
60
+
61
+
62
+ class AgentResponse(BaseModel):
63
+ name: str
64
+ role: str
65
+ goal: str
66
+ backstory: str
67
+ tools: list[str]
68
+ permissions: AgentPermissionsSchema
69
+ created_at: datetime
70
+
71
+
72
+ class ApprovalRecordResponse(BaseModel):
73
+ id: str
74
+ session_id: str
75
+ approval_type: str
76
+ description: str
77
+ risk_level: str
78
+ resource_details: dict[str, Any]
79
+ agent_name: str
80
+ status: str
81
+ timestamp: datetime
82
+ resolved_at: datetime | None = None
83
+ reason: str | None = None
84
+
85
+
86
+ class ApprovalResolution(BaseModel):
87
+ approved: bool
88
+ reason: str | None = None
89
+
90
+
91
+ class AuditLogResponse(BaseModel):
92
+ id: int
93
+ event_type: str
94
+ session_id: str
95
+ agent_name: str
96
+ details: dict[str, Any]
97
+ cost: float
98
+ token_usage: int
99
+ timestamp: datetime
@@ -0,0 +1 @@
1
+ # Initialize subpackage
@@ -0,0 +1 @@
1
+ # Initialize subpackage