alms-cli 0.1.7__tar.gz → 0.1.9__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 (87) hide show
  1. {alms_cli-0.1.7 → alms_cli-0.1.9}/PKG-INFO +1 -1
  2. {alms_cli-0.1.7 → alms_cli-0.1.9}/pyproject.toml +1 -1
  3. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/__init__.py +1 -1
  4. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/.env.example.j2 +2 -0
  5. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/pyproject.toml.j2 +3 -0
  6. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/endpoints/v1/dependencies.py.j2 +5 -2
  7. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/endpoints/v1/health.py.j2 +5 -1
  8. alms_cli-0.1.9/src/alms_cli/templates/files/src/api/endpoints/v1/sample_agent.py.j2 +15 -0
  9. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/main.py.j2 +21 -19
  10. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/config/settings.py.j2 +6 -5
  11. alms_cli-0.1.9/src/alms_cli/templates/files/src/providers/ai/factory.py.j2 +9 -0
  12. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/providers/ai/langchain_model_loader.py.j2 +3 -3
  13. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/integration/test_full_stack.py.j2 +2 -1
  14. alms_cli-0.1.9/src/alms_cli/templates/files/src/tests/v1/test_agent.py.j2 +18 -0
  15. alms_cli-0.1.9/src/alms_cli/templates/files/src/tests/v1/test_health.py.j2 +19 -0
  16. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/v1/test_observability_middleware.py.j2 +2 -1
  17. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/ui/components.py +28 -8
  18. alms_cli-0.1.7/src/alms_cli/templates/files/src/api/endpoints/v1/sample_agent.py.j2 +0 -15
  19. alms_cli-0.1.7/src/alms_cli/templates/files/src/providers/ai/factory.py.j2 +0 -10
  20. alms_cli-0.1.7/src/alms_cli/templates/files/src/tests/v1/test_agent.py.j2 +0 -10
  21. alms_cli-0.1.7/src/alms_cli/templates/files/src/tests/v1/test_health.py.j2 +0 -12
  22. {alms_cli-0.1.7 → alms_cli-0.1.9}/.gitignore +0 -0
  23. {alms_cli-0.1.7 → alms_cli-0.1.9}/LICENSE +0 -0
  24. {alms_cli-0.1.7 → alms_cli-0.1.9}/README.md +0 -0
  25. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/__main__.py +0 -0
  26. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/commands/__init__.py +0 -0
  27. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/commands/info.py +0 -0
  28. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/commands/init.py +0 -0
  29. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/main.py +0 -0
  30. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/__init__.py +0 -0
  31. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/.github/ISSUE_TEMPLATE/bug_report.yml.j2 +0 -0
  32. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/.github/ISSUE_TEMPLATE/feature_request.yml.j2 +0 -0
  33. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/.github/dependabot.yml.j2 +0 -0
  34. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/.github/pull_request_template.md.j2 +0 -0
  35. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/.github/workflows/ci.yml.j2 +0 -0
  36. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/.gitignore.j2 +0 -0
  37. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/Dockerfile.j2 +0 -0
  38. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/README.md.j2 +0 -0
  39. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/alembic/README.j2 +0 -0
  40. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/alembic/env.py.j2 +0 -0
  41. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/alembic/script.py.mako.j2 +0 -0
  42. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/alembic.ini.j2 +0 -0
  43. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docker-compose.yml.j2 +0 -0
  44. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docs/01-System-Design.md.j2 +0 -0
  45. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docs/02-Design-Patterns.md.j2 +0 -0
  46. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docs/03-Database-Design.md.j2 +0 -0
  47. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docs/04-Tech-Stack.md.j2 +0 -0
  48. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docs/05-Project-Structure.md.j2 +0 -0
  49. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docs/06-API-Documentation.md.j2 +0 -0
  50. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docs/07-Setup-Installation.md.j2 +0 -0
  51. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/docs/08-Contribution-Guide.md.j2 +0 -0
  52. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/pytest.ini.j2 +0 -0
  53. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/rules/project_rules.md.j2 +0 -0
  54. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/agents/agent_manager/agent.py.j2 +0 -0
  55. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/agents/prompts/sample_agent_prompt.py.j2 +0 -0
  56. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/endpoints/v1/metrics.py.j2 +0 -0
  57. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/endpoints/v1/routers.py.j2 +0 -0
  58. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/endpoints/v1/sample_di.py.j2 +0 -0
  59. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/endpoints/v1/schemas/base.py.j2 +0 -0
  60. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/endpoints/v1/schemas/sample.py.j2 +0 -0
  61. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/middlewares/error_handler.py.j2 +0 -0
  62. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/middlewares/logging.py.j2 +0 -0
  63. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/middlewares/observability.py.j2 +0 -0
  64. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/middlewares/security.py.j2 +0 -0
  65. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/api/router/routers.py.j2 +0 -0
  66. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/config/logs_config.py.j2 +0 -0
  67. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/core/exceptions.py.j2 +0 -0
  68. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/database/connection.py.j2 +0 -0
  69. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/database/repositories/base.py.j2 +0 -0
  70. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/database/repositories/sqlalchemy_repository.py.j2 +0 -0
  71. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/execution/actions/sample_action.py.j2 +0 -0
  72. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/execution/usecases/sample_usecase.py.j2 +0 -0
  73. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/observability/__init__.py.j2 +0 -0
  74. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/observability/metrics.py.j2 +0 -0
  75. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/observability/tracing.py.j2 +0 -0
  76. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/providers/ai/base.py.j2 +0 -0
  77. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/README.md.j2 +0 -0
  78. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/conftest.py.j2 +0 -0
  79. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/e2e/test_workflows.py.j2 +0 -0
  80. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/v1/test_metrics.py.j2 +0 -0
  81. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/v1/test_metrics_endpoint.py.j2 +0 -0
  82. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/v1/test_sqlalchemy_repository.py.j2 +0 -0
  83. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/files/src/tests/v1/test_tracing.py.j2 +0 -0
  84. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/generator.py +0 -0
  85. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/profiles.py +0 -0
  86. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/templates/template_renderer.py +0 -0
  87. {alms_cli-0.1.7 → alms_cli-0.1.9}/src/alms_cli/ui/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alms-cli
3
- Version: 0.1.7
3
+ Version: 0.1.9
4
4
  Summary: ALMS CLI - Beautiful project scaffolding tool for AI-first backends
5
5
  Project-URL: Homepage, https://github.com/KJ-AIML/alms
6
6
  Project-URL: Repository, https://github.com/KJ-AIML/alms
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "alms-cli"
3
- version = "0.1.7"
3
+ version = "0.1.9"
4
4
  description = "ALMS CLI - Beautiful project scaffolding tool for AI-first backends"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -1,3 +1,3 @@
1
1
  """ALMS CLI - Beautiful project scaffolding tool."""
2
2
 
3
- __version__ = "0.1.7"
3
+ __version__ = "0.1.9"
@@ -7,6 +7,8 @@ SERVICE_NAME={{ project_name | lower | replace(' ', '-') }}
7
7
  # Server Configuration
8
8
  SERVER_PORT=3000
9
9
  SERVER_HOST=0.0.0.0
10
+ # WARNING: ALLOWED_HOSTS=["*"] is for development only.
11
+ # Production must use explicit origins, e.g. ALLOWED_HOSTS=["https://example.com"]
10
12
  ALLOWED_HOSTS=["*"]
11
13
 
12
14
  # Environment Configuration
@@ -24,6 +24,9 @@ dev = [
24
24
  "ruff>=0.14.11",
25
25
  ]
26
26
 
27
+ [tool.pytest.ini_options]
28
+ asyncio_mode = "auto"
29
+
27
30
  [tool.alms]
28
31
  profile = "{{ profile }}"
29
32
  capabilities = {{ capabilities_repr }}
@@ -18,8 +18,11 @@ def get_db_session():
18
18
  return get_db()
19
19
  {% else %}
20
20
  def get_db_session():
21
- """Get database session."""
22
- pass
21
+ """Get database session (stub for non-database profiles)."""
22
+ raise RuntimeError(
23
+ "Database is not enabled in this profile. "
24
+ "Regenerate with --profile db-agent or full to enable database support."
25
+ )
23
26
  {% endif %}{% if has_ai %}
24
27
 
25
28
  try:
@@ -29,7 +29,11 @@ async def ready_check():
29
29
  try:
30
30
  from src.database.connection import check_database_connection
31
31
  except ImportError:
32
- return AppResponse(success=False, data={"status": "degraded", "ready": False})
32
+ from fastapi.responses import JSONResponse
33
+ return JSONResponse(
34
+ status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
35
+ content=AppResponse(success=False, data={"status": "degraded", "ready": False}).model_dump(),
36
+ )
33
37
  db_ready = await check_database_connection()
34
38
  if db_ready:
35
39
  return AppResponse(success=True, data={"status": "ready", "ready": True, "dependencies": {"database": "healthy"}})
@@ -0,0 +1,15 @@
1
+ """Sample agent endpoint."""
2
+
3
+ from fastapi import APIRouter, Depends
4
+ from src.api.endpoints.v1.dependencies import get_sample_usecase
5
+ from src.api.endpoints.v1.schemas.base import AppResponse
6
+ from src.api.endpoints.v1.schemas.sample import SampleRequest
7
+
8
+ router = APIRouter()
9
+
10
+
11
+ @router.post("/sample")
12
+ async def sample_agent(request: SampleRequest, usecase=Depends(get_sample_usecase)):
13
+ """Sample agent endpoint."""
14
+ result = await usecase.execute(query=request.query)
15
+ return AppResponse(success=True, data=result)
@@ -38,22 +38,34 @@ def create_app() -> FastAPI:
38
38
  redoc_url=None,
39
39
  )
40
40
 
41
- # Middleware registration order matters - added in reverse execution order
42
- # LoggingMiddleware executes first on incoming requests
43
- app.add_middleware(LoggingMiddleware)
44
- {% if has_obs %} app.add_middleware(ObservabilityMiddleware)
45
- {% endif %} app.add_middleware(SecurityHeadersMiddleware)
46
- app.add_middleware(APIKeyMiddleware)
47
- app.add_middleware(ErrorHandlerMiddleware)
41
+ # Middleware registration order matters: last added = outermost = executes first on incoming request.
42
+ # Intended request flow: Logging APIKey → ErrorHandler → SecurityHeaders → Observability → CORS
48
43
  app.add_middleware(
49
44
  CORSMiddleware,
50
- allow_origins=["*"],
45
+ allow_origins=settings.ALLOWED_HOSTS,
51
46
  allow_credentials=True,
52
47
  allow_methods=["*"],
53
48
  allow_headers=["*"],
54
49
  )
50
+ app.add_middleware(ErrorHandlerMiddleware)
51
+ app.add_middleware(APIKeyMiddleware)
52
+ app.add_middleware(SecurityHeadersMiddleware)
53
+ {% if has_obs %} app.add_middleware(ObservabilityMiddleware)
54
+ {% endif %} app.add_middleware(LoggingMiddleware)
55
55
 
56
56
  app.include_router(api_router, prefix=settings.API_PREFIX)
57
+ {% if has_scalar %}
58
+
59
+ # Scalar API Documentation
60
+ try:
61
+ from scalar_fastapi import get_scalar_api_reference
62
+
63
+ @app.get("/docs", include_in_schema=False)
64
+ async def scalar_html():
65
+ return get_scalar_api_reference(openapi_url=app.openapi_url, title=app.title)
66
+ except ImportError:
67
+ pass
68
+ {% endif %}
57
69
  return app
58
70
 
59
71
 
@@ -66,14 +78,4 @@ if __name__ == "__main__":
66
78
  host=settings.SERVER_HOST,
67
79
  port=settings.SERVER_PORT,
68
80
  reload=settings.DEBUG,
69
- )
70
- {% if has_scalar %}
71
-
72
- try:
73
- from scalar_fastapi import get_scalar_api_reference
74
- @app.get("/docs", include_in_schema=False)
75
- async def scalar_html():
76
- return get_scalar_api_reference(openapi_url=app.openapi_url, title=app.title)
77
- except ImportError:
78
- pass
79
- {% endif %}
81
+ )
@@ -1,8 +1,10 @@
1
1
  """Application settings."""
2
2
 
3
- from pydantic_settings import BaseSettings
4
3
  from functools import lru_cache
5
4
 
5
+ from pydantic import ConfigDict
6
+ from pydantic_settings import BaseSettings
7
+
6
8
 
7
9
  class Settings(BaseSettings):
8
10
  APP_NAME: str = "ALMS Backend"
@@ -15,7 +17,8 @@ class Settings(BaseSettings):
15
17
  {% if has_ai %} AI_ENABLED: bool = False
16
18
  {% endif %}{% if has_db %} DATABASE_ENABLED: bool = True
17
19
  {% endif %}{% if has_redis %} REDIS_ENABLED: bool = False
18
- {% endif %}{% if has_ai %} OPENAI_API_KEY: str = ""
20
+ {% endif %}{% if has_ai %} MODEL_PROVIDER: str = "openai" # reserved for future provider selection; only "openai" is supported
21
+ OPENAI_API_KEY: str = ""
19
22
  OPENAI_MODEL_BASIC: str = "gpt-4o-mini"
20
23
  OPENAI_MODEL_REASONING: str = "gpt-4o"
21
24
  {% endif %}{% if has_db %} DATABASE_URL: str | None = None
@@ -43,9 +46,7 @@ class Settings(BaseSettings):
43
46
  if "*" in self.ALLOWED_HOSTS:
44
47
  raise ValueError("ALLOWED_HOSTS must not contain * in production")
45
48
 
46
- class Config:
47
- env_file = ".env"
48
- case_sensitive = True
49
+ model_config = ConfigDict(env_file=".env", case_sensitive=True)
49
50
 
50
51
 
51
52
  @lru_cache()
@@ -0,0 +1,9 @@
1
+ """AI provider factory."""
2
+
3
+ from src.providers.ai.base import AIModelProvider
4
+ from src.providers.ai.langchain_model_loader import LangchainModelLoader
5
+
6
+
7
+ def get_ai_provider() -> AIModelProvider:
8
+ """Return the configured AI provider."""
9
+ return LangchainModelLoader()
@@ -5,8 +5,8 @@ from src.config.settings import settings
5
5
  from src.providers.ai.base import AIModelProvider
6
6
 
7
7
 
8
- class LangChainModelProvider(AIModelProvider):
9
- """LangChain AI model provider."""
8
+ class LangchainModelLoader(AIModelProvider):
9
+ """LangChain AI model loader."""
10
10
 
11
11
  def get_chat_model(self, tier: str = "basic"):
12
12
  """Get LLM instance."""
@@ -24,4 +24,4 @@ class LangChainModelProvider(AIModelProvider):
24
24
 
25
25
  def get_llm(model: str = "basic"):
26
26
  """Get LLM instance."""
27
- return LangChainModelProvider().get_chat_model(tier=model)
27
+ return LangchainModelLoader().get_chat_model(tier=model)
@@ -7,4 +7,5 @@ import pytest
7
7
  async def test_full_stack(client):
8
8
  """Test full stack integration."""
9
9
  response = await client.get("/api/v1/health")
10
- assert response.status_code == 200
10
+ # Health returns 200 when all deps healthy, 503 when degraded (e.g., no DB)
11
+ assert response.status_code in (200, 503)
@@ -0,0 +1,18 @@
1
+ """Agent endpoint tests."""
2
+
3
+ import pytest
4
+
5
+
6
+ @pytest.mark.asyncio
7
+ async def test_sample_agent(client):
8
+ """Test sample agent endpoint."""
9
+ response = await client.post("/api/v1/agent/sample", json={"query": "test"})
10
+ # Endpoint returns 200 when AI deps are available, 503 when not installed
11
+ assert response.status_code in (200, 503)
12
+ data = response.json()
13
+ assert "success" in data
14
+ if response.status_code == 200:
15
+ assert data["success"] is True
16
+ else:
17
+ assert data["success"] is False
18
+ assert data["error"]["code"] == "AGENT_UNAVAILABLE"
@@ -0,0 +1,19 @@
1
+ """Health endpoint tests."""
2
+
3
+ import pytest
4
+
5
+
6
+ @pytest.mark.asyncio
7
+ async def test_health_check(client):
8
+ """Test health check endpoint."""
9
+ response = await client.get("/api/v1/health")
10
+ # Health endpoint returns 200 when healthy, 503 when degraded (e.g., DB unavailable)
11
+ assert response.status_code in (200, 503)
12
+ data = response.json()
13
+ assert "success" in data
14
+ assert "data" in data
15
+ if response.status_code == 200:
16
+ assert data["success"] is True
17
+ else:
18
+ assert data["success"] is False
19
+ assert data["data"]["status"] == "degraded"
@@ -7,4 +7,5 @@ import pytest
7
7
  async def test_observability_middleware(client):
8
8
  """Test observability middleware."""
9
9
  response = await client.get("/api/v1/health")
10
- assert response.status_code == 200
10
+ # Health returns 200 when all deps healthy, 503 when degraded (e.g., no DB)
11
+ assert response.status_code in (200, 503)
@@ -1,18 +1,38 @@
1
1
  """Rich UI components for beautiful terminal output."""
2
2
 
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ from rich import box
3
7
  from rich.console import Console
4
8
  from rich.panel import Panel
5
- from rich.tree import Tree
6
9
  from rich.progress import (
10
+ BarColumn,
7
11
  Progress,
8
12
  SpinnerColumn,
9
13
  TextColumn,
10
- BarColumn,
11
14
  TimeElapsedColumn,
12
15
  )
13
16
  from rich.table import Table
14
- from rich import box
15
- from pathlib import Path
17
+ from rich.tree import Tree
18
+
19
+
20
+ def _stdout_supports_unicode() -> bool:
21
+ """Check whether stdout can encode Unicode symbols (e.g. not cp1252)."""
22
+ encoding = getattr(sys.stdout, "encoding", None) or ""
23
+ try:
24
+ "\u2139".encode(encoding)
25
+ return True
26
+ except (UnicodeEncodeError, LookupError):
27
+ return False
28
+
29
+
30
+ # ponytail: ASCII fallbacks for Windows cp1252 terminals where Unicode glyphs crash stdout.
31
+ _unicode_ok = _stdout_supports_unicode()
32
+ SYM_OK = "\u2713" if _unicode_ok else "[OK]"
33
+ SYM_ERR = "\u2717" if _unicode_ok else "[X]"
34
+ SYM_INFO = "\u2139" if _unicode_ok else "[i]"
35
+ SYM_WARN = "\u26a0" if _unicode_ok else "[!]"
16
36
 
17
37
  console = Console()
18
38
 
@@ -42,22 +62,22 @@ def print_step(step_num: int, total: int, message: str):
42
62
 
43
63
  def print_success(message: str):
44
64
  """Print a success message."""
45
- console.print(f"[bold green][/bold green] [green]{message}[/green]")
65
+ console.print(f"[bold green]{SYM_OK}[/bold green] [green]{message}[/green]")
46
66
 
47
67
 
48
68
  def print_error(message: str):
49
69
  """Print an error message."""
50
- console.print(f"[bold red][/bold red] [red]{message}[/red]")
70
+ console.print(f"[bold red]{SYM_ERR}[/bold red] [red]{message}[/red]")
51
71
 
52
72
 
53
73
  def print_info(message: str):
54
74
  """Print an info message."""
55
- console.print(f"[bold blue][/bold blue] [blue]{message}[/blue]")
75
+ console.print(f"[bold blue]{SYM_INFO}[/bold blue] [blue]{message}[/blue]")
56
76
 
57
77
 
58
78
  def print_warning(message: str):
59
79
  """Print a warning message."""
60
- console.print(f"[bold yellow][/bold yellow] [yellow]{message}[/yellow]")
80
+ console.print(f"[bold yellow]{SYM_WARN}[/bold yellow] [yellow]{message}[/yellow]")
61
81
 
62
82
 
63
83
  def create_progress():
@@ -1,15 +0,0 @@
1
- """Sample agent endpoint."""
2
-
3
- from fastapi import APIRouter
4
- from src.api.endpoints.v1.schemas.base import AppResponse
5
- from src.execution.usecases.sample_usecase import SampleUseCase
6
-
7
- router = APIRouter()
8
-
9
-
10
- @router.post("/sample")
11
- async def sample_agent(query: str):
12
- """Sample agent endpoint."""
13
- usecase = SampleUseCase()
14
- result = await usecase.execute(query)
15
- return AppResponse(success=True, data=result)
@@ -1,10 +0,0 @@
1
- """AI provider factory."""
2
-
3
- from functools import lru_cache
4
- from src.providers.ai.langchain_model_loader import LangChainModelProvider
5
-
6
-
7
- @lru_cache
8
- def get_ai_provider() -> LangChainModelProvider:
9
- """Return the configured AI provider."""
10
- return LangChainModelProvider()
@@ -1,10 +0,0 @@
1
- """Agent endpoint tests."""
2
-
3
- import pytest
4
-
5
-
6
- @pytest.mark.asyncio
7
- async def test_sample_agent(client):
8
- """Test sample agent endpoint."""
9
- response = await client.post("/api/v1/agent/sample", json={"query": "test"})
10
- assert response.status_code == 200
@@ -1,12 +0,0 @@
1
- """Health endpoint tests."""
2
-
3
- import pytest
4
-
5
-
6
- @pytest.mark.asyncio
7
- async def test_health_check(client):
8
- """Test health check endpoint."""
9
- response = await client.get("/api/v1/health")
10
- assert response.status_code == 200
11
- data = response.json()
12
- assert data["success"] is True
File without changes
File without changes
File without changes
File without changes