socrates-ai-api 1.3.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.
- socrates_ai_api-1.3.0.dist-info/METADATA +446 -0
- socrates_ai_api-1.3.0.dist-info/RECORD +11 -0
- socrates_ai_api-1.3.0.dist-info/WHEEL +5 -0
- socrates_ai_api-1.3.0.dist-info/entry_points.txt +2 -0
- socrates_ai_api-1.3.0.dist-info/top_level.txt +1 -0
- socrates_api/__init__.py +12 -0
- socrates_api/database.py +118 -0
- socrates_api/main.py +876 -0
- socrates_api/models.py +929 -0
- socrates_api/monitoring.py +222 -0
- socrates_api/testing_mode.py +77 -0
socrates_api/models.py
ADDED
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pydantic models for API request/response bodies
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# ============================================================================
|
|
12
|
+
# Standardized API Response Model
|
|
13
|
+
# ============================================================================
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class APIResponse(BaseModel):
|
|
17
|
+
"""
|
|
18
|
+
Standardized wrapper for all API responses.
|
|
19
|
+
|
|
20
|
+
This model provides consistent response formatting across all endpoints:
|
|
21
|
+
- success: boolean indicating operation success/failure
|
|
22
|
+
- status: more specific status string (e.g., "success", "error", "pending")
|
|
23
|
+
- data: the actual response data (optional, varies by endpoint)
|
|
24
|
+
- message: optional message to user
|
|
25
|
+
- error_code: machine-readable error code (for errors)
|
|
26
|
+
- timestamp: when the response was generated
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
model_config = ConfigDict(
|
|
30
|
+
json_schema_extra={
|
|
31
|
+
"example": {
|
|
32
|
+
"success": True,
|
|
33
|
+
"status": "success",
|
|
34
|
+
"message": "Operation completed successfully",
|
|
35
|
+
"data": {
|
|
36
|
+
"project_id": "proj_abc123",
|
|
37
|
+
"name": "My Project"
|
|
38
|
+
},
|
|
39
|
+
"error_code": None,
|
|
40
|
+
"timestamp": "2026-01-08T12:30:45.123456Z"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
success: bool = Field(..., description="Whether the operation succeeded")
|
|
46
|
+
status: Literal["success", "error", "pending", "created", "updated", "deleted"] = Field(
|
|
47
|
+
..., description="Status of the operation"
|
|
48
|
+
)
|
|
49
|
+
data: Optional[Dict[str, Any]] = Field(
|
|
50
|
+
None, description="Response data (structure varies by endpoint)"
|
|
51
|
+
)
|
|
52
|
+
message: Optional[str] = Field(
|
|
53
|
+
None, description="Human-readable message (useful for errors and status updates)"
|
|
54
|
+
)
|
|
55
|
+
error_code: Optional[str] = Field(
|
|
56
|
+
None, description="Machine-readable error code for programmatic handling"
|
|
57
|
+
)
|
|
58
|
+
timestamp: Optional[str] = Field(
|
|
59
|
+
None, description="ISO 8601 timestamp when response was generated"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# ============================================================================
|
|
64
|
+
# Project Models
|
|
65
|
+
# ============================================================================
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class CreateProjectRequest(BaseModel):
|
|
69
|
+
"""Request body for creating a new project"""
|
|
70
|
+
|
|
71
|
+
model_config = ConfigDict(
|
|
72
|
+
extra="forbid",
|
|
73
|
+
json_schema_extra={
|
|
74
|
+
"example": {
|
|
75
|
+
"name": "Python API Development",
|
|
76
|
+
"description": "Building a REST API with FastAPI",
|
|
77
|
+
"knowledge_base_content": "FastAPI is a modern web framework...",
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
name: str = Field(..., min_length=1, max_length=200, description="Project name")
|
|
83
|
+
description: Optional[str] = Field(None, max_length=1000, description="Project description")
|
|
84
|
+
knowledge_base_content: Optional[str] = Field(
|
|
85
|
+
None, description="Initial knowledge base content"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class UpdateProjectRequest(BaseModel):
|
|
90
|
+
"""Request body for updating a project"""
|
|
91
|
+
|
|
92
|
+
model_config = ConfigDict(
|
|
93
|
+
extra="forbid",
|
|
94
|
+
json_schema_extra={
|
|
95
|
+
"example": {
|
|
96
|
+
"name": "Updated Project Name",
|
|
97
|
+
"phase": "implementation",
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
name: Optional[str] = Field(None, min_length=1, max_length=200, description="Project name")
|
|
103
|
+
phase: Optional[str] = Field(None, description="Project phase")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ProjectResponse(BaseModel):
|
|
107
|
+
"""Response model for project data"""
|
|
108
|
+
|
|
109
|
+
model_config = ConfigDict(
|
|
110
|
+
json_schema_extra={
|
|
111
|
+
"example": {
|
|
112
|
+
"project_id": "proj_abc123",
|
|
113
|
+
"name": "Python API Development",
|
|
114
|
+
"owner": "alice",
|
|
115
|
+
"description": "Building a REST API with FastAPI",
|
|
116
|
+
"phase": "active",
|
|
117
|
+
"created_at": "2025-12-04T10:00:00Z",
|
|
118
|
+
"updated_at": "2025-12-04T10:30:00Z",
|
|
119
|
+
"is_archived": False,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
project_id: str = Field(..., description="Unique project identifier")
|
|
125
|
+
name: str = Field(..., description="Project name")
|
|
126
|
+
owner: str = Field(..., description="Project owner username")
|
|
127
|
+
description: Optional[str] = Field(None, description="Project description")
|
|
128
|
+
phase: str = Field(..., description="Current project phase")
|
|
129
|
+
created_at: datetime = Field(..., description="Project creation timestamp")
|
|
130
|
+
updated_at: datetime = Field(..., description="Project last update timestamp")
|
|
131
|
+
is_archived: bool = Field(default=False, description="Whether project is archived")
|
|
132
|
+
overall_maturity: float = Field(default=0.0, description="Project maturity percentage (0-100)")
|
|
133
|
+
progress: int = Field(default=0, description="Project progress percentage (0-100)")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class ListProjectsResponse(BaseModel):
|
|
137
|
+
"""Response model for listing projects"""
|
|
138
|
+
|
|
139
|
+
model_config = ConfigDict(
|
|
140
|
+
json_schema_extra={
|
|
141
|
+
"example": {
|
|
142
|
+
"projects": [
|
|
143
|
+
{
|
|
144
|
+
"project_id": "proj_abc123",
|
|
145
|
+
"name": "Python API Development",
|
|
146
|
+
"owner": "alice",
|
|
147
|
+
"description": "Building a REST API with FastAPI",
|
|
148
|
+
"phase": "active",
|
|
149
|
+
"created_at": "2025-12-04T10:00:00Z",
|
|
150
|
+
"updated_at": "2025-12-04T10:30:00Z",
|
|
151
|
+
"is_archived": False,
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
"total": 1,
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
projects: List[ProjectResponse] = Field(..., description="List of projects")
|
|
160
|
+
total: int = Field(..., description="Total number of projects")
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class AskQuestionRequest(BaseModel):
|
|
164
|
+
"""Request body for asking a Socratic question"""
|
|
165
|
+
|
|
166
|
+
model_config = ConfigDict(
|
|
167
|
+
extra="forbid",
|
|
168
|
+
json_schema_extra={
|
|
169
|
+
"example": {
|
|
170
|
+
"project_id": "proj_abc123",
|
|
171
|
+
"topic": "API design patterns",
|
|
172
|
+
"difficulty_level": "intermediate",
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
topic: Optional[str] = Field(None, description="Topic to ask about")
|
|
178
|
+
difficulty_level: str = Field(default="intermediate", description="Question difficulty level")
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class QuestionResponse(BaseModel):
|
|
182
|
+
"""Response model for a Socratic question"""
|
|
183
|
+
|
|
184
|
+
model_config = ConfigDict(
|
|
185
|
+
json_schema_extra={
|
|
186
|
+
"example": {
|
|
187
|
+
"question_id": "q_xyz789",
|
|
188
|
+
"question": "What are the main principles of RESTful API design?",
|
|
189
|
+
"context": "You are designing an API for a tutoring system",
|
|
190
|
+
"hints": [
|
|
191
|
+
"Think about resource-oriented design",
|
|
192
|
+
"Consider HTTP methods and status codes",
|
|
193
|
+
],
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
question_id: str = Field(..., description="Unique question identifier")
|
|
199
|
+
question: str = Field(..., description="The Socratic question")
|
|
200
|
+
context: Optional[str] = Field(None, description="Context for the question")
|
|
201
|
+
hints: List[str] = Field(default_factory=list, description="Available hints")
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class ProcessResponseRequest(BaseModel):
|
|
205
|
+
"""Request body for processing a user's response to a question"""
|
|
206
|
+
|
|
207
|
+
model_config = ConfigDict(
|
|
208
|
+
extra="forbid",
|
|
209
|
+
json_schema_extra={
|
|
210
|
+
"example": {
|
|
211
|
+
"question_id": "q_xyz789",
|
|
212
|
+
"user_response": "REST APIs should follow resource-oriented design...",
|
|
213
|
+
"project_id": "proj_abc123",
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
question_id: str = Field(..., description="Question identifier")
|
|
219
|
+
user_response: str = Field(..., min_length=1, description="User's response to the question")
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class ProcessResponseResponse(BaseModel):
|
|
223
|
+
"""Response model for processing a user response"""
|
|
224
|
+
|
|
225
|
+
model_config = ConfigDict(
|
|
226
|
+
json_schema_extra={
|
|
227
|
+
"example": {
|
|
228
|
+
"feedback": "Good understanding of REST principles! Let me ask you about HTTP methods...",
|
|
229
|
+
"is_correct": True,
|
|
230
|
+
"next_question": {
|
|
231
|
+
"question_id": "q_xyz790",
|
|
232
|
+
"question": "Which HTTP method should be used for retrieving data?",
|
|
233
|
+
"context": "In REST API design",
|
|
234
|
+
"hints": [],
|
|
235
|
+
},
|
|
236
|
+
"insights": [
|
|
237
|
+
"Student understands resource-oriented design",
|
|
238
|
+
"Can explain REST principles clearly",
|
|
239
|
+
],
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
feedback: str = Field(..., description="Feedback on the user's response")
|
|
245
|
+
is_correct: bool = Field(..., description="Whether the response is correct")
|
|
246
|
+
next_question: Optional[QuestionResponse] = Field(
|
|
247
|
+
None, description="Next question if available"
|
|
248
|
+
)
|
|
249
|
+
insights: Optional[List[str]] = Field(None, description="Key insights extracted")
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class GenerateCodeRequest(BaseModel):
|
|
253
|
+
"""Request body for code generation"""
|
|
254
|
+
|
|
255
|
+
model_config = ConfigDict(
|
|
256
|
+
extra="forbid",
|
|
257
|
+
json_schema_extra={
|
|
258
|
+
"example": {
|
|
259
|
+
"project_id": "proj_abc123",
|
|
260
|
+
"specification": "Create a FastAPI endpoint for user registration",
|
|
261
|
+
"language": "python",
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
project_id: str = Field(..., description="Project identifier")
|
|
267
|
+
specification: Optional[str] = Field(None, description="Code specification or requirements")
|
|
268
|
+
language: str = Field(default="python", description="Programming language")
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class GenerateCodeForProjectRequest(BaseModel):
|
|
272
|
+
"""Request body for code generation (when project_id is in URL path)"""
|
|
273
|
+
|
|
274
|
+
model_config = ConfigDict(
|
|
275
|
+
extra="forbid",
|
|
276
|
+
json_schema_extra={
|
|
277
|
+
"example": {
|
|
278
|
+
"specification": "Create a FastAPI endpoint for user registration",
|
|
279
|
+
"language": "python",
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
specification: Optional[str] = Field(None, description="Code specification or requirements")
|
|
285
|
+
language: Optional[str] = Field(default="python", description="Programming language")
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class CodeGenerationResponse(BaseModel):
|
|
289
|
+
"""Response model for code generation"""
|
|
290
|
+
|
|
291
|
+
model_config = ConfigDict(
|
|
292
|
+
json_schema_extra={
|
|
293
|
+
"example": {
|
|
294
|
+
"code": "@app.post('/api/users/register')\nasync def register_user(user: User):\n # Implementation here",
|
|
295
|
+
"explanation": "This endpoint handles user registration using FastAPI...",
|
|
296
|
+
"language": "python",
|
|
297
|
+
"token_usage": {"input_tokens": 150, "output_tokens": 200, "total_tokens": 350},
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
code: str = Field(..., description="Generated code")
|
|
303
|
+
explanation: Optional[str] = Field(None, description="Explanation of the generated code")
|
|
304
|
+
language: str = Field(..., description="Programming language")
|
|
305
|
+
token_usage: Optional[Dict[str, int]] = Field(None, description="Token usage statistics")
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class ErrorResponse(BaseModel):
|
|
309
|
+
"""Standard error response model"""
|
|
310
|
+
|
|
311
|
+
model_config = ConfigDict(
|
|
312
|
+
json_schema_extra={
|
|
313
|
+
"example": {
|
|
314
|
+
"error": "ProjectNotFoundError",
|
|
315
|
+
"message": "Project 'proj_abc123' not found",
|
|
316
|
+
"error_code": "PROJECT_NOT_FOUND",
|
|
317
|
+
"details": {"project_id": "proj_abc123"},
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
error: str = Field(..., description="Error type")
|
|
323
|
+
message: str = Field(..., description="Error message")
|
|
324
|
+
error_code: Optional[str] = Field(None, description="Machine-readable error code")
|
|
325
|
+
details: Optional[Dict[str, Any]] = Field(None, description="Additional error details")
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class SystemInfoResponse(BaseModel):
|
|
329
|
+
"""Response model for system information"""
|
|
330
|
+
|
|
331
|
+
model_config = ConfigDict(
|
|
332
|
+
json_schema_extra={
|
|
333
|
+
"example": {
|
|
334
|
+
"version": "8.0.0",
|
|
335
|
+
"library_version": "8.0.0",
|
|
336
|
+
"status": "operational",
|
|
337
|
+
"uptime": 3600.5,
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
version: str = Field(..., description="API version")
|
|
343
|
+
library_version: str = Field(..., description="Socrates library version")
|
|
344
|
+
status: str = Field(..., description="API status")
|
|
345
|
+
uptime: float = Field(..., description="API uptime in seconds")
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
# ============================================================================
|
|
349
|
+
# Authentication Models
|
|
350
|
+
# ============================================================================
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
class RegisterRequest(BaseModel):
|
|
354
|
+
"""Request body for user registration"""
|
|
355
|
+
|
|
356
|
+
model_config = ConfigDict(
|
|
357
|
+
extra="forbid",
|
|
358
|
+
json_schema_extra={
|
|
359
|
+
"example": {
|
|
360
|
+
"username": "alice_smith",
|
|
361
|
+
"email": "alice@example.com",
|
|
362
|
+
"password": "SecurePassword123!",
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
username: str = Field(
|
|
368
|
+
..., min_length=3, max_length=100, description="Username (3-100 characters)"
|
|
369
|
+
)
|
|
370
|
+
email: Optional[str] = Field(None, description="User email address (optional)")
|
|
371
|
+
password: str = Field(
|
|
372
|
+
..., min_length=8, max_length=200, description="Password (min 8 characters)"
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
class LoginRequest(BaseModel):
|
|
377
|
+
"""Request body for user login"""
|
|
378
|
+
|
|
379
|
+
model_config = ConfigDict(
|
|
380
|
+
extra="forbid",
|
|
381
|
+
json_schema_extra={
|
|
382
|
+
"example": {
|
|
383
|
+
"username": "alice_smith",
|
|
384
|
+
"password": "SecurePassword123!",
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
username: str = Field(..., description="Username")
|
|
390
|
+
password: str = Field(..., description="Password")
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
class UserResponse(BaseModel):
|
|
394
|
+
"""Response model for user information"""
|
|
395
|
+
|
|
396
|
+
model_config = ConfigDict(
|
|
397
|
+
json_schema_extra={
|
|
398
|
+
"example": {
|
|
399
|
+
"username": "alice_smith",
|
|
400
|
+
"email": "alice@example.com",
|
|
401
|
+
"subscription_tier": "pro",
|
|
402
|
+
"subscription_status": "active",
|
|
403
|
+
"testing_mode": False,
|
|
404
|
+
"created_at": "2025-12-01T12:00:00Z",
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
username: str = Field(..., description="Username")
|
|
410
|
+
email: str = Field(..., description="User email address")
|
|
411
|
+
subscription_tier: str = Field(..., description="Subscription tier (free/pro/enterprise)")
|
|
412
|
+
subscription_status: str = Field(..., description="Subscription status")
|
|
413
|
+
testing_mode: bool = Field(..., description="Whether testing mode is enabled")
|
|
414
|
+
created_at: datetime = Field(..., description="Account creation timestamp")
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
class TokenResponse(BaseModel):
|
|
418
|
+
"""Response model for authentication tokens"""
|
|
419
|
+
|
|
420
|
+
model_config = ConfigDict(
|
|
421
|
+
json_schema_extra={
|
|
422
|
+
"example": {
|
|
423
|
+
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
424
|
+
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
425
|
+
"token_type": "bearer",
|
|
426
|
+
"expires_in": 900,
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
access_token: str = Field(..., description="Short-lived access token (15 min)")
|
|
432
|
+
refresh_token: str = Field(..., description="Long-lived refresh token (7 days)")
|
|
433
|
+
token_type: str = Field(default="bearer", description="Token type")
|
|
434
|
+
expires_in: int = Field(default=900, description="Access token expiry in seconds")
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class AuthResponse(BaseModel):
|
|
438
|
+
"""Combined response for auth operations with user info and tokens"""
|
|
439
|
+
|
|
440
|
+
model_config = ConfigDict(
|
|
441
|
+
json_schema_extra={
|
|
442
|
+
"example": {
|
|
443
|
+
"user": {
|
|
444
|
+
"username": "alice_smith",
|
|
445
|
+
"email": "alice@example.com",
|
|
446
|
+
"subscription_tier": "pro",
|
|
447
|
+
"subscription_status": "active",
|
|
448
|
+
"testing_mode": False,
|
|
449
|
+
"created_at": "2025-12-01T12:00:00Z",
|
|
450
|
+
},
|
|
451
|
+
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
452
|
+
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
453
|
+
"token_type": "bearer",
|
|
454
|
+
"expires_in": 900,
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
user: UserResponse = Field(..., description="User information")
|
|
460
|
+
access_token: str = Field(..., description="Short-lived access token")
|
|
461
|
+
refresh_token: str = Field(..., description="Long-lived refresh token")
|
|
462
|
+
token_type: str = Field(default="bearer", description="Token type")
|
|
463
|
+
expires_in: int = Field(default=900, description="Access token expiry in seconds")
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class RefreshTokenRequest(BaseModel):
|
|
467
|
+
"""Request body for refreshing access token"""
|
|
468
|
+
|
|
469
|
+
model_config = ConfigDict(
|
|
470
|
+
extra="forbid",
|
|
471
|
+
json_schema_extra={
|
|
472
|
+
"example": {
|
|
473
|
+
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
refresh_token: str = Field(..., description="The refresh token")
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
class ChangePasswordRequest(BaseModel):
|
|
482
|
+
"""Request body for changing password"""
|
|
483
|
+
|
|
484
|
+
model_config = ConfigDict(
|
|
485
|
+
extra="forbid",
|
|
486
|
+
json_schema_extra={
|
|
487
|
+
"example": {
|
|
488
|
+
"old_password": "current_password",
|
|
489
|
+
"new_password": "new_secure_password",
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
old_password: str = Field(..., description="Current password")
|
|
495
|
+
new_password: str = Field(..., description="New password")
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
class SuccessResponse(BaseModel):
|
|
499
|
+
"""Generic success response"""
|
|
500
|
+
|
|
501
|
+
model_config = ConfigDict(
|
|
502
|
+
json_schema_extra={
|
|
503
|
+
"example": {
|
|
504
|
+
"success": True,
|
|
505
|
+
"message": "Logout successful",
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
success: bool = Field(default=True, description="Whether operation succeeded")
|
|
511
|
+
message: str = Field(..., description="Success message")
|
|
512
|
+
data: Optional[Dict[str, Any]] = Field(None, description="Additional response data")
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
class GitHubImportRequest(BaseModel):
|
|
516
|
+
"""Request body for GitHub import"""
|
|
517
|
+
|
|
518
|
+
model_config = ConfigDict(
|
|
519
|
+
extra="forbid",
|
|
520
|
+
json_schema_extra={
|
|
521
|
+
"example": {
|
|
522
|
+
"url": "https://github.com/user/repo",
|
|
523
|
+
"project_name": "My Project",
|
|
524
|
+
"branch": "main",
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
url: str = Field(..., description="GitHub repository URL")
|
|
530
|
+
project_name: Optional[str] = Field(None, description="Custom project name")
|
|
531
|
+
branch: Optional[str] = Field(None, description="Branch to import")
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
class SetDefaultProviderRequest(BaseModel):
|
|
535
|
+
"""Request body for setting default LLM provider"""
|
|
536
|
+
|
|
537
|
+
model_config = ConfigDict(
|
|
538
|
+
extra="forbid",
|
|
539
|
+
json_schema_extra={"example": {"provider": "anthropic"}},
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
provider: str = Field(..., description="Provider name (claude, openai, gemini, local)")
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
class SetLLMModelRequest(BaseModel):
|
|
546
|
+
"""Request body for setting LLM model"""
|
|
547
|
+
|
|
548
|
+
model_config = ConfigDict(
|
|
549
|
+
extra="forbid",
|
|
550
|
+
json_schema_extra={"example": {"provider": "anthropic", "model": "claude-3-sonnet"}},
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
provider: str = Field(..., description="Provider name")
|
|
554
|
+
model: str = Field(..., description="Model identifier")
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
class AddAPIKeyRequest(BaseModel):
|
|
558
|
+
"""Request body for adding API key"""
|
|
559
|
+
|
|
560
|
+
model_config = ConfigDict(
|
|
561
|
+
extra="forbid",
|
|
562
|
+
json_schema_extra={"example": {"provider": "anthropic", "api_key": "sk-ant-..."}},
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
provider: str = Field(..., description="Provider name")
|
|
566
|
+
api_key: str = Field(..., description="API key for the provider")
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
class CollaborationInviteRequest(BaseModel):
|
|
570
|
+
"""Request body for inviting collaborator"""
|
|
571
|
+
|
|
572
|
+
model_config = ConfigDict(
|
|
573
|
+
extra="forbid",
|
|
574
|
+
json_schema_extra={"example": {"email": "user@example.com", "role": "editor"}},
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
email: str = Field(..., description="Email of the collaborator")
|
|
578
|
+
role: str = Field(default="viewer", description="Role (editor, viewer, admin)")
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
class CollaborationInvitationResponse(BaseModel):
|
|
582
|
+
"""Response body for invitation operations"""
|
|
583
|
+
|
|
584
|
+
model_config = ConfigDict(
|
|
585
|
+
json_schema_extra={
|
|
586
|
+
"example": {
|
|
587
|
+
"id": "inv_123",
|
|
588
|
+
"project_id": "proj_123",
|
|
589
|
+
"inviter_id": "user1",
|
|
590
|
+
"invitee_email": "user2@example.com",
|
|
591
|
+
"role": "editor",
|
|
592
|
+
"token": "eyJ...",
|
|
593
|
+
"status": "pending",
|
|
594
|
+
"created_at": "2024-01-01T00:00:00Z",
|
|
595
|
+
"expires_at": "2024-01-08T00:00:00Z",
|
|
596
|
+
"accepted_at": None,
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
id: str = Field(..., description="Invitation ID")
|
|
602
|
+
project_id: str = Field(..., description="Project ID")
|
|
603
|
+
inviter_id: str = Field(..., description="Username of inviter")
|
|
604
|
+
invitee_email: str = Field(..., description="Email of invitee")
|
|
605
|
+
role: str = Field(..., description="Assigned role")
|
|
606
|
+
token: str = Field(..., description="Unique invitation token")
|
|
607
|
+
status: str = Field(
|
|
608
|
+
..., description="Invitation status (pending, accepted, expired, cancelled)"
|
|
609
|
+
)
|
|
610
|
+
created_at: str = Field(..., description="Creation timestamp")
|
|
611
|
+
expires_at: str = Field(..., description="Expiration timestamp")
|
|
612
|
+
accepted_at: Optional[str] = Field(None, description="Acceptance timestamp")
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
class DeleteDocumentRequest(BaseModel):
|
|
616
|
+
"""Request body for deleting knowledge document"""
|
|
617
|
+
|
|
618
|
+
model_config = ConfigDict(
|
|
619
|
+
extra="forbid",
|
|
620
|
+
json_schema_extra={"example": {"document_id": "doc_123"}},
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
document_id: str = Field(..., description="Document ID to delete")
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
class InitializeRequest(BaseModel):
|
|
627
|
+
"""Request body for API initialization"""
|
|
628
|
+
|
|
629
|
+
model_config = ConfigDict(
|
|
630
|
+
extra="forbid",
|
|
631
|
+
json_schema_extra={"example": {"api_key": "sk-ant-..."}},
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
api_key: Optional[str] = Field(None, description="Claude API key")
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
# ============================================================================
|
|
638
|
+
# Chat Session and Message Models
|
|
639
|
+
# ============================================================================
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
class CreateChatSessionRequest(BaseModel):
|
|
643
|
+
"""Request body for creating a chat session"""
|
|
644
|
+
|
|
645
|
+
model_config = ConfigDict(
|
|
646
|
+
extra="forbid",
|
|
647
|
+
json_schema_extra={"example": {"title": "Initial Design Discussion"}},
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
title: Optional[str] = Field(None, max_length=255, description="Session title")
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
class ChatSessionResponse(BaseModel):
|
|
654
|
+
"""Response model for a chat session"""
|
|
655
|
+
|
|
656
|
+
model_config = ConfigDict(
|
|
657
|
+
json_schema_extra={
|
|
658
|
+
"example": {
|
|
659
|
+
"session_id": "sess_abc123",
|
|
660
|
+
"project_id": "proj_xyz789",
|
|
661
|
+
"user_id": "alice",
|
|
662
|
+
"title": "Initial Design Discussion",
|
|
663
|
+
"created_at": "2025-12-04T10:00:00Z",
|
|
664
|
+
"updated_at": "2025-12-04T10:30:00Z",
|
|
665
|
+
"archived": False,
|
|
666
|
+
"message_count": 5,
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
session_id: str = Field(..., description="Unique session identifier")
|
|
672
|
+
project_id: str = Field(..., description="Project ID this session belongs to")
|
|
673
|
+
user_id: str = Field(..., description="User who created the session")
|
|
674
|
+
title: Optional[str] = Field(None, description="Session title")
|
|
675
|
+
created_at: datetime = Field(..., description="Session creation timestamp")
|
|
676
|
+
updated_at: datetime = Field(..., description="Session last update timestamp")
|
|
677
|
+
archived: bool = Field(default=False, description="Whether session is archived")
|
|
678
|
+
message_count: int = Field(default=0, description="Number of messages in session")
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
class ListChatSessionsResponse(BaseModel):
|
|
682
|
+
"""Response model for listing chat sessions"""
|
|
683
|
+
|
|
684
|
+
model_config = ConfigDict(
|
|
685
|
+
json_schema_extra={
|
|
686
|
+
"example": {
|
|
687
|
+
"sessions": [
|
|
688
|
+
{
|
|
689
|
+
"session_id": "sess_abc123",
|
|
690
|
+
"project_id": "proj_xyz789",
|
|
691
|
+
"user_id": "alice",
|
|
692
|
+
"title": "Initial Design Discussion",
|
|
693
|
+
"created_at": "2025-12-04T10:00:00Z",
|
|
694
|
+
"updated_at": "2025-12-04T10:30:00Z",
|
|
695
|
+
"archived": False,
|
|
696
|
+
"message_count": 5,
|
|
697
|
+
}
|
|
698
|
+
],
|
|
699
|
+
"total": 1,
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
sessions: List[ChatSessionResponse] = Field(..., description="List of chat sessions")
|
|
705
|
+
total: int = Field(..., description="Total number of sessions")
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
class ChatMessageRequest(BaseModel):
|
|
709
|
+
"""Request body for sending a chat message"""
|
|
710
|
+
|
|
711
|
+
model_config = ConfigDict(
|
|
712
|
+
extra="forbid",
|
|
713
|
+
json_schema_extra={
|
|
714
|
+
"example": {
|
|
715
|
+
"message": "What should I focus on next?",
|
|
716
|
+
"role": "user",
|
|
717
|
+
"mode": "socratic",
|
|
718
|
+
}
|
|
719
|
+
},
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
message: str = Field(..., min_length=1, max_length=5000, description="Message content (max 5000 characters)")
|
|
723
|
+
role: str = Field(default="user", description="Message role (user or assistant)")
|
|
724
|
+
mode: str = Field(default="socratic", description="Chat mode (socratic or direct)")
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
class ChatMessage(BaseModel):
|
|
728
|
+
"""Model for a chat message"""
|
|
729
|
+
|
|
730
|
+
model_config = ConfigDict(
|
|
731
|
+
json_schema_extra={
|
|
732
|
+
"example": {
|
|
733
|
+
"message_id": "msg_def456",
|
|
734
|
+
"session_id": "sess_abc123",
|
|
735
|
+
"user_id": "alice",
|
|
736
|
+
"content": "What should I focus on next?",
|
|
737
|
+
"role": "user",
|
|
738
|
+
"created_at": "2025-12-04T10:10:00Z",
|
|
739
|
+
"updated_at": "2025-12-04T10:10:00Z",
|
|
740
|
+
"metadata": None,
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
message_id: str = Field(..., description="Unique message identifier")
|
|
746
|
+
session_id: str = Field(..., description="Session ID this message belongs to")
|
|
747
|
+
user_id: str = Field(..., description="User who sent the message")
|
|
748
|
+
content: str = Field(..., description="Message content")
|
|
749
|
+
role: str = Field(..., description="Message role (user or assistant)")
|
|
750
|
+
created_at: datetime = Field(..., description="Message creation timestamp")
|
|
751
|
+
updated_at: datetime = Field(..., description="Message last update timestamp")
|
|
752
|
+
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional message metadata")
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
class GetChatMessagesResponse(BaseModel):
|
|
756
|
+
"""Response model for listing chat messages"""
|
|
757
|
+
|
|
758
|
+
model_config = ConfigDict(
|
|
759
|
+
json_schema_extra={
|
|
760
|
+
"example": {
|
|
761
|
+
"messages": [
|
|
762
|
+
{
|
|
763
|
+
"message_id": "msg_def456",
|
|
764
|
+
"session_id": "sess_abc123",
|
|
765
|
+
"user_id": "alice",
|
|
766
|
+
"content": "What should I focus on next?",
|
|
767
|
+
"role": "user",
|
|
768
|
+
"created_at": "2025-12-04T10:10:00Z",
|
|
769
|
+
"updated_at": "2025-12-04T10:10:00Z",
|
|
770
|
+
"metadata": None,
|
|
771
|
+
}
|
|
772
|
+
],
|
|
773
|
+
"total": 1,
|
|
774
|
+
"session_id": "sess_abc123",
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
)
|
|
778
|
+
|
|
779
|
+
messages: List[ChatMessage] = Field(..., description="List of messages in session")
|
|
780
|
+
total: int = Field(..., description="Total number of messages")
|
|
781
|
+
session_id: str = Field(..., description="Session ID")
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
class UpdateMessageRequest(BaseModel):
|
|
785
|
+
"""Request body for updating a chat message"""
|
|
786
|
+
|
|
787
|
+
model_config = ConfigDict(
|
|
788
|
+
extra="forbid",
|
|
789
|
+
json_schema_extra={"example": {"content": "Updated message content", "metadata": None}},
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
content: str = Field(..., min_length=1, description="Updated message content")
|
|
793
|
+
metadata: Optional[Dict[str, Any]] = Field(
|
|
794
|
+
None, description="Optional metadata for the message"
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
# ============================================================================
|
|
799
|
+
# Collaboration Response Models
|
|
800
|
+
# ============================================================================
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
class CollaboratorData(BaseModel):
|
|
804
|
+
"""Response data for collaborator information"""
|
|
805
|
+
|
|
806
|
+
username: str = Field(..., description="Username of collaborator")
|
|
807
|
+
email: str = Field(..., description="Email of collaborator")
|
|
808
|
+
role: str = Field(..., description="Role in project (owner, editor, viewer)")
|
|
809
|
+
joined_at: Optional[str] = Field(None, description="When collaborator joined")
|
|
810
|
+
status: Optional[str] = Field(default="inactive", description="Current status")
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
class CollaboratorListData(BaseModel):
|
|
814
|
+
"""Response data for list of collaborators"""
|
|
815
|
+
|
|
816
|
+
project_id: str = Field(..., description="Project ID")
|
|
817
|
+
total: int = Field(..., description="Total number of collaborators")
|
|
818
|
+
collaborators: List[Dict[str, Any]] = Field(..., description="List of collaborators")
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
class ActiveCollaboratorData(BaseModel):
|
|
822
|
+
"""Response data for active collaborators"""
|
|
823
|
+
|
|
824
|
+
project_id: str = Field(..., description="Project ID")
|
|
825
|
+
active_count: int = Field(..., description="Number of active collaborators")
|
|
826
|
+
collaborators: List[Dict[str, Any]] = Field(..., description="List of active collaborators")
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
class CollaborationTokenData(BaseModel):
|
|
830
|
+
"""Response data for collaboration token validation"""
|
|
831
|
+
|
|
832
|
+
valid: bool = Field(..., description="Whether token is valid")
|
|
833
|
+
inviter: Optional[str] = Field(None, description="User who sent invitation")
|
|
834
|
+
project_id: Optional[str] = Field(None, description="Associated project ID")
|
|
835
|
+
email: Optional[str] = Field(None, description="Invited email")
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
class CollaborationSyncData(BaseModel):
|
|
839
|
+
"""Response data for collaboration sync"""
|
|
840
|
+
|
|
841
|
+
synced_count: int = Field(..., description="Number of items synced")
|
|
842
|
+
last_sync: str = Field(..., description="Timestamp of last sync")
|
|
843
|
+
status: str = Field(..., description="Sync status")
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
class ActiveSessionsData(BaseModel):
|
|
847
|
+
"""Response data for active collaboration sessions"""
|
|
848
|
+
|
|
849
|
+
total: int = Field(..., description="Total active sessions")
|
|
850
|
+
sessions: List[Dict[str, Any]] = Field(..., description="List of active sessions")
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
class PresenceData(BaseModel):
|
|
854
|
+
"""Response data for user presence"""
|
|
855
|
+
|
|
856
|
+
user_id: str = Field(..., description="User identifier")
|
|
857
|
+
project_id: str = Field(..., description="Project ID")
|
|
858
|
+
status: str = Field(..., description="Presence status (online, away, offline)")
|
|
859
|
+
last_activity: Optional[str] = Field(None, description="Last activity timestamp")
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
# ============================================================================
|
|
863
|
+
# Project Analytics Response Models
|
|
864
|
+
# ============================================================================
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
class ProjectStatsData(BaseModel):
|
|
868
|
+
"""Response data for project statistics"""
|
|
869
|
+
|
|
870
|
+
project_id: str = Field(..., description="Project ID")
|
|
871
|
+
total_collaborators: int = Field(..., description="Total collaborators")
|
|
872
|
+
total_messages: int = Field(..., description="Total messages exchanged")
|
|
873
|
+
code_generations: int = Field(..., description="Number of code generations")
|
|
874
|
+
last_activity: Optional[str] = Field(None, description="Last activity timestamp")
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
class ProjectMaturityData(BaseModel):
|
|
878
|
+
"""Response data for project maturity assessment"""
|
|
879
|
+
|
|
880
|
+
project_id: str = Field(..., description="Project ID")
|
|
881
|
+
overall_maturity: float = Field(..., description="Overall maturity percentage (0-100)")
|
|
882
|
+
components: Dict[str, float] = Field(..., description="Maturity by component")
|
|
883
|
+
last_assessment: str = Field(..., description="When assessment was done")
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
class ProjectAnalyticsData(BaseModel):
|
|
887
|
+
"""Response data for project analytics"""
|
|
888
|
+
|
|
889
|
+
project_id: str = Field(..., description="Project ID")
|
|
890
|
+
period: str = Field(..., description="Analytics period")
|
|
891
|
+
metrics: Dict[str, Any] = Field(..., description="Various metrics")
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
class ProjectExportData(BaseModel):
|
|
895
|
+
"""Response data for project export"""
|
|
896
|
+
|
|
897
|
+
export_id: str = Field(..., description="Export identifier")
|
|
898
|
+
format: str = Field(..., description="Export format (json, csv, etc)")
|
|
899
|
+
size: int = Field(..., description="Size in bytes")
|
|
900
|
+
status: str = Field(..., description="Export status")
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
# ============================================================================
|
|
904
|
+
# Knowledge Response Models
|
|
905
|
+
# ============================================================================
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
class KnowledgeSearchData(BaseModel):
|
|
909
|
+
"""Response data for knowledge search"""
|
|
910
|
+
|
|
911
|
+
query: str = Field(..., description="Search query")
|
|
912
|
+
total_results: int = Field(..., description="Total search results")
|
|
913
|
+
results: List[Dict[str, Any]] = Field(..., description="Search results")
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
class RelatedDocumentsData(BaseModel):
|
|
917
|
+
"""Response data for related documents"""
|
|
918
|
+
|
|
919
|
+
document_id: str = Field(..., description="Source document ID")
|
|
920
|
+
total_related: int = Field(..., description="Number of related documents")
|
|
921
|
+
documents: List[Dict[str, Any]] = Field(..., description="Related documents")
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
class BulkImportData(BaseModel):
|
|
925
|
+
"""Response data for bulk import"""
|
|
926
|
+
|
|
927
|
+
imported_count: int = Field(..., description="Number of documents imported")
|
|
928
|
+
failed_count: int = Field(default=0, description="Number of failed imports")
|
|
929
|
+
details: List[Dict[str, Any]] = Field(..., description="Import details")
|