ArunKr commited on
Commit
3d07805
·
verified ·
1 Parent(s): 587a706

Upload folder using huggingface_hub

Browse files
.github/scripts/deploy.py CHANGED
@@ -1,4 +1,5 @@
1
  import os
 
2
  from huggingface_hub import HfApi
3
 
4
  token = os.environ["HF_TOKEN"]
 
1
  import os
2
+
3
  from huggingface_hub import HfApi
4
 
5
  token = os.environ["HF_TOKEN"]
app/mcp_client.py CHANGED
@@ -2,7 +2,6 @@ from __future__ import annotations
2
 
3
  import asyncio
4
  import json
5
- from typing import Optional
6
 
7
  from fastapi import HTTPException
8
 
@@ -10,11 +9,11 @@ from fastapi import HTTPException
10
  class McpStdioClient:
11
  def __init__(self, command: list[str]):
12
  self.command = command
13
- self.proc: Optional[asyncio.subprocess.Process] = None
14
  self._lock = asyncio.Lock()
15
  self._pending: dict[int, asyncio.Future] = {}
16
  self._next_id = 1
17
- self._reader_task: Optional[asyncio.Task] = None
18
  self._initialized = False
19
 
20
  async def start(self) -> None:
@@ -69,7 +68,7 @@ class McpStdioClient:
69
  if fut and not fut.done():
70
  fut.set_result(msg)
71
 
72
- async def _rpc(self, method: str, params: Optional[dict] = None) -> dict:
73
  await self.start()
74
  assert self.proc and self.proc.stdin
75
  async with self._lock:
@@ -111,4 +110,3 @@ class McpStdioClient:
111
 
112
  async def call_tool(self, name: str, arguments: dict) -> dict:
113
  return await self._rpc("tools/call", {"name": name, "arguments": arguments})
114
-
 
2
 
3
  import asyncio
4
  import json
 
5
 
6
  from fastapi import HTTPException
7
 
 
9
  class McpStdioClient:
10
  def __init__(self, command: list[str]):
11
  self.command = command
12
+ self.proc: asyncio.subprocess.Process | None = None
13
  self._lock = asyncio.Lock()
14
  self._pending: dict[int, asyncio.Future] = {}
15
  self._next_id = 1
16
+ self._reader_task: asyncio.Task | None = None
17
  self._initialized = False
18
 
19
  async def start(self) -> None:
 
68
  if fut and not fut.done():
69
  fut.set_result(msg)
70
 
71
+ async def _rpc(self, method: str, params: dict | None = None) -> dict:
72
  await self.start()
73
  assert self.proc and self.proc.stdin
74
  async with self._lock:
 
110
 
111
  async def call_tool(self, name: str, arguments: dict) -> dict:
112
  return await self._rpc("tools/call", {"name": name, "arguments": arguments})
 
app/routes/admin.py CHANGED
@@ -48,7 +48,7 @@ async def get_mcp_templates(http_request: Request):
48
  except FileNotFoundError:
49
  return {"version": 1, "templates": []}
50
  except Exception as e:
51
- raise HTTPException(status_code=500, detail=str(e))
52
 
53
 
54
  @router.put("/api/admin/mcp-templates")
@@ -73,5 +73,4 @@ async def put_mcp_templates(body: McpTemplates, http_request: Request):
73
  path.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
74
  return {"ok": True, "count": len(templates)}
75
  except Exception as e:
76
- raise HTTPException(status_code=500, detail=str(e))
77
-
 
48
  except FileNotFoundError:
49
  return {"version": 1, "templates": []}
50
  except Exception as e:
51
+ raise HTTPException(status_code=500, detail=str(e)) from e
52
 
53
 
54
  @router.put("/api/admin/mcp-templates")
 
73
  path.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
74
  return {"ok": True, "count": len(templates)}
75
  except Exception as e:
76
+ raise HTTPException(status_code=500, detail=str(e)) from e
 
app/routes/chat.py CHANGED
@@ -1,7 +1,7 @@
1
  from __future__ import annotations
2
 
3
  import os
4
- from typing import Any, List, Optional, Union
5
 
6
  from fastapi import APIRouter, HTTPException
7
  from fastapi.responses import StreamingResponse
@@ -14,14 +14,14 @@ router = APIRouter()
14
  class ChatMessage(BaseModel):
15
  role: str
16
  # OpenAI-compatible: content can be plain text or an array of multimodal parts.
17
- content: Union[str, List[Any]]
18
 
19
 
20
  class ChatRequest(BaseModel):
21
- messages: List[ChatMessage]
22
- apiKey: Optional[str] = None
23
- baseUrl: Optional[str] = None
24
- model: Optional[str] = "gpt-3.5-turbo"
25
 
26
 
27
  @router.post("/api/chat")
@@ -51,8 +51,8 @@ async def chat_endpoint(request: ChatRequest):
51
 
52
 
53
  class ModelsRequest(BaseModel):
54
- apiKey: Optional[str] = None
55
- baseUrl: Optional[str] = None
56
 
57
 
58
  @router.post("/api/proxy/models")
@@ -80,5 +80,4 @@ async def proxy_models(request: ModelsRequest):
80
  except HTTPException:
81
  raise
82
  except Exception as e:
83
- raise HTTPException(status_code=500, detail=str(e))
84
-
 
1
  from __future__ import annotations
2
 
3
  import os
4
+ from typing import Any
5
 
6
  from fastapi import APIRouter, HTTPException
7
  from fastapi.responses import StreamingResponse
 
14
  class ChatMessage(BaseModel):
15
  role: str
16
  # OpenAI-compatible: content can be plain text or an array of multimodal parts.
17
+ content: str | list[Any]
18
 
19
 
20
  class ChatRequest(BaseModel):
21
+ messages: list[ChatMessage]
22
+ apiKey: str | None = None
23
+ baseUrl: str | None = None
24
+ model: str | None = "gpt-3.5-turbo"
25
 
26
 
27
  @router.post("/api/chat")
 
51
 
52
 
53
  class ModelsRequest(BaseModel):
54
+ apiKey: str | None = None
55
+ baseUrl: str | None = None
56
 
57
 
58
  @router.post("/api/proxy/models")
 
80
  except HTTPException:
81
  raise
82
  except Exception as e:
83
+ raise HTTPException(status_code=500, detail=str(e)) from e
 
app/routes/codex.py CHANGED
@@ -6,7 +6,6 @@ import os
6
  import uuid
7
  from dataclasses import dataclass, field
8
  from pathlib import Path
9
- from typing import List, Optional
10
 
11
  from fastapi import APIRouter, HTTPException, Request
12
  from fastapi.responses import StreamingResponse
@@ -21,14 +20,14 @@ router = APIRouter()
21
 
22
  class CodexRequest(BaseModel):
23
  message: str
24
- threadId: Optional[str] = None
25
- model: Optional[str] = None
26
- sandboxMode: Optional[str] = "workspace-write"
27
- approvalPolicy: Optional[str] = "never"
28
- apiKey: Optional[str] = None
29
- baseUrl: Optional[str] = None
30
- modelReasoningEffort: Optional[str] = "minimal"
31
- workingDirectory: Optional[str] = None
32
 
33
 
34
  @router.post("/api/codex")
@@ -83,7 +82,7 @@ async def codex_agent(request: CodexRequest, http_request: Request):
83
  except HTTPException:
84
  raise
85
  except Exception as e:
86
- raise HTTPException(status_code=500, detail=str(e))
87
 
88
 
89
  def _with_codex_agent_prefix(message: str) -> str:
@@ -180,7 +179,7 @@ async def codex_agent_cli(request: CodexRequest, http_request: Request):
180
  except HTTPException:
181
  raise
182
  except Exception as e:
183
- raise HTTPException(status_code=500, detail=str(e))
184
 
185
 
186
  @router.post("/api/codex/cli/stream")
@@ -367,11 +366,11 @@ class DeviceLoginAttempt:
367
  id: str
368
  proc: asyncio.subprocess.Process
369
  created_at: float
370
- url: Optional[str] = None
371
- code: Optional[str] = None
372
- output: List[str] = field(default_factory=list)
373
  done: bool = False
374
- returncode: Optional[int] = None
375
 
376
 
377
  async def _read_device_login_output(attempt: DeviceLoginAttempt) -> None:
 
6
  import uuid
7
  from dataclasses import dataclass, field
8
  from pathlib import Path
 
9
 
10
  from fastapi import APIRouter, HTTPException, Request
11
  from fastapi.responses import StreamingResponse
 
20
 
21
  class CodexRequest(BaseModel):
22
  message: str
23
+ threadId: str | None = None
24
+ model: str | None = None
25
+ sandboxMode: str | None = "workspace-write"
26
+ approvalPolicy: str | None = "never"
27
+ apiKey: str | None = None
28
+ baseUrl: str | None = None
29
+ modelReasoningEffort: str | None = "minimal"
30
+ workingDirectory: str | None = None
31
 
32
 
33
  @router.post("/api/codex")
 
82
  except HTTPException:
83
  raise
84
  except Exception as e:
85
+ raise HTTPException(status_code=500, detail=str(e)) from e
86
 
87
 
88
  def _with_codex_agent_prefix(message: str) -> str:
 
179
  except HTTPException:
180
  raise
181
  except Exception as e:
182
+ raise HTTPException(status_code=500, detail=str(e)) from e
183
 
184
 
185
  @router.post("/api/codex/cli/stream")
 
366
  id: str
367
  proc: asyncio.subprocess.Process
368
  created_at: float
369
+ url: str | None = None
370
+ code: str | None = None
371
+ output: list[str] = field(default_factory=list)
372
  done: bool = False
373
+ returncode: int | None = None
374
 
375
 
376
  async def _read_device_login_output(attempt: DeviceLoginAttempt) -> None:
app/routes/mcp.py CHANGED
@@ -18,7 +18,7 @@ async def mcp_tools_list(http_request: Request):
18
  result = await http_request.app.state.codex_mcp_client.list_tools()
19
  return result
20
  except Exception as e:
21
- raise HTTPException(status_code=500, detail=str(e))
22
 
23
 
24
  class McpCallRequest(BaseModel):
@@ -34,5 +34,4 @@ async def mcp_tools_call(request: McpCallRequest, http_request: Request):
34
  try:
35
  return await http_request.app.state.codex_mcp_client.call_tool(request.name, request.arguments)
36
  except Exception as e:
37
- raise HTTPException(status_code=500, detail=str(e))
38
-
 
18
  result = await http_request.app.state.codex_mcp_client.list_tools()
19
  return result
20
  except Exception as e:
21
+ raise HTTPException(status_code=500, detail=str(e)) from e
22
 
23
 
24
  class McpCallRequest(BaseModel):
 
34
  try:
35
  return await http_request.app.state.codex_mcp_client.call_tool(request.name, request.arguments)
36
  except Exception as e:
37
+ raise HTTPException(status_code=500, detail=str(e)) from e
 
app/routes/terminal.py CHANGED
@@ -8,7 +8,7 @@ import pty
8
  import struct
9
  import subprocess
10
  import termios
11
- from datetime import datetime, timezone
12
 
13
  from fastapi import APIRouter, HTTPException, WebSocket
14
 
@@ -57,7 +57,7 @@ async def websocket_terminal(websocket: WebSocket):
57
  "refresh_token": refresh_token,
58
  "account_id": account_id,
59
  },
60
- "last_refresh": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
61
  }
62
  for filename in ("auth.json", ".auth.json"):
63
  path = os.path.join(codex_home, filename)
@@ -137,4 +137,3 @@ async def websocket_terminal(websocket: WebSocket):
137
  write_task.cancel()
138
  p.terminate()
139
  os.close(master_fd)
140
-
 
8
  import struct
9
  import subprocess
10
  import termios
11
+ from datetime import UTC, datetime
12
 
13
  from fastapi import APIRouter, HTTPException, WebSocket
14
 
 
57
  "refresh_token": refresh_token,
58
  "account_id": account_id,
59
  },
60
+ "last_refresh": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
61
  }
62
  for filename in ("auth.json", ".auth.json"):
63
  path = os.path.join(codex_home, filename)
 
137
  write_task.cancel()
138
  p.terminate()
139
  os.close(master_fd)
 
app/routes/user.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
 
3
  import json
4
  import os
5
- from typing import Any, Optional
6
 
7
  from fastapi import APIRouter, HTTPException, Request
8
  from pydantic import BaseModel
@@ -61,12 +61,12 @@ async def get_mcp_registry(http_request: Request):
61
  user = await require_user_from_request(http_request)
62
  path = _registry_path(str(user.get("id") or ""))
63
  try:
64
- with open(path, "r", encoding="utf-8") as f:
65
  return json.load(f)
66
  except FileNotFoundError:
67
  return {"version": 1, "servers": []}
68
  except Exception as e:
69
- raise HTTPException(status_code=500, detail=str(e))
70
 
71
 
72
  @router.put("/api/user/mcp-registry")
@@ -92,4 +92,4 @@ async def put_mcp_registry(body: McpRegistry, http_request: Request):
92
  f.write("\n")
93
  return {"ok": True, "count": len(servers)}
94
  except Exception as e:
95
- raise HTTPException(status_code=500, detail=str(e))
 
2
 
3
  import json
4
  import os
5
+ from typing import Any
6
 
7
  from fastapi import APIRouter, HTTPException, Request
8
  from pydantic import BaseModel
 
61
  user = await require_user_from_request(http_request)
62
  path = _registry_path(str(user.get("id") or ""))
63
  try:
64
+ with open(path, encoding="utf-8") as f:
65
  return json.load(f)
66
  except FileNotFoundError:
67
  return {"version": 1, "servers": []}
68
  except Exception as e:
69
+ raise HTTPException(status_code=500, detail=str(e)) from e
70
 
71
 
72
  @router.put("/api/user/mcp-registry")
 
92
  f.write("\n")
93
  return {"ok": True, "count": len(servers)}
94
  except Exception as e:
95
+ raise HTTPException(status_code=500, detail=str(e)) from e
app/server.py CHANGED
@@ -9,12 +9,12 @@ from fastapi.middleware.cors import CORSMiddleware
9
  from fastapi.staticfiles import StaticFiles
10
 
11
  from app.mcp_client import McpStdioClient
 
12
  from app.routes.base import router as base_router
13
  from app.routes.chat import router as chat_router
14
  from app.routes.codex import router as codex_router
15
  from app.routes.mcp import router as mcp_router
16
  from app.routes.terminal import router as terminal_router
17
- from app.routes.admin import router as admin_router
18
  from app.routes.user import router as user_router
19
 
20
  _ROOT = Path(__file__).resolve().parent.parent
 
9
  from fastapi.staticfiles import StaticFiles
10
 
11
  from app.mcp_client import McpStdioClient
12
+ from app.routes.admin import router as admin_router
13
  from app.routes.base import router as base_router
14
  from app.routes.chat import router as chat_router
15
  from app.routes.codex import router as codex_router
16
  from app.routes.mcp import router as mcp_router
17
  from app.routes.terminal import router as terminal_router
 
18
  from app.routes.user import router as user_router
19
 
20
  _ROOT = Path(__file__).resolve().parent.parent
app/workdir.py CHANGED
@@ -1,10 +1,10 @@
1
  from __future__ import annotations
2
 
3
  import os
4
- from typing import Any, Optional
5
 
6
 
7
- def safe_user_workdir(user: dict[str, Any], requested: Optional[str]) -> str:
8
  """
9
  Restrict Codex workdir to an allowlisted root to prevent traversal.
10
  """
@@ -28,4 +28,3 @@ def safe_user_workdir(user: dict[str, Any], requested: Optional[str]) -> str:
28
 
29
  os.makedirs(user_root, exist_ok=True)
30
  return user_root
31
-
 
1
  from __future__ import annotations
2
 
3
  import os
4
+ from typing import Any
5
 
6
 
7
+ def safe_user_workdir(user: dict[str, Any], requested: str | None) -> str:
8
  """
9
  Restrict Codex workdir to an allowlisted root to prevent traversal.
10
  """
 
28
 
29
  os.makedirs(user_root, exist_ok=True)
30
  return user_root
 
tests/test_security_gates.py CHANGED
@@ -1,5 +1,3 @@
1
- import os
2
-
3
  import pytest
4
  from fastapi.testclient import TestClient
5
  from starlette.websockets import WebSocketDisconnect
@@ -47,4 +45,3 @@ def test_features_can_be_disabled(monkeypatch: pytest.MonkeyPatch):
47
 
48
  res = c.get("/api/codex/login/status")
49
  assert res.status_code == 403
50
-
 
 
 
1
  import pytest
2
  from fastapi.testclient import TestClient
3
  from starlette.websockets import WebSocketDisconnect
 
45
 
46
  res = c.get("/api/codex/login/status")
47
  assert res.status_code == 403