claude-smart 0.2.47 → 0.2.49
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +6 -2
- package/bin/claude-smart.js +289 -56
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/dashboard/app/sessions/[sessionId]/page.tsx +36 -2
- package/plugin/dashboard/package-lock.json +61 -390
- package/plugin/dashboard/package.json +2 -2
- package/plugin/opencode/dist/server.mjs +60 -2
- package/plugin/opencode/server.mts +64 -2
- package/plugin/pyproject.toml +2 -2
- package/plugin/scripts/_lib.sh +58 -6
- package/plugin/scripts/backend-service.sh +15 -10
- package/plugin/scripts/codex-hook.js +16 -4
- package/plugin/scripts/dashboard-service.sh +1 -1
- package/plugin/scripts/ensure-plugin-root.sh +106 -8
- package/plugin/scripts/opencode-claude-compat.js +8 -1
- package/plugin/scripts/smart-install.sh +101 -20
- package/plugin/src/README.md +1 -1
- package/plugin/src/claude_smart/cli.py +79 -29
- package/plugin/src/claude_smart/env_config.py +53 -11
- package/plugin/uv.lock +5 -5
- package/plugin/vendor/reflexio/.env.example +7 -0
- package/plugin/vendor/reflexio/pyproject.toml +2 -1
- package/plugin/vendor/reflexio/reflexio/README.md +8 -5
- package/plugin/vendor/reflexio/reflexio/cli/README.md +3 -0
- package/plugin/vendor/reflexio/reflexio/client/client.py +40 -6
- package/plugin/vendor/reflexio/reflexio/lib/_config.py +23 -18
- package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +16 -1
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +15 -11
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +18 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +1 -0
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +24 -3
- package/plugin/vendor/reflexio/reflexio/server/README.md +25 -8
- package/plugin/vendor/reflexio/reflexio/server/__init__.py +21 -2
- package/plugin/vendor/reflexio/reflexio/server/api.py +148 -3277
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/README.md +4 -3
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +16 -1
- package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +62 -36
- package/plugin/vendor/reflexio/reflexio/server/deployment_profile.py +69 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_embedding.py +424 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_json_extraction.py +249 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_structured_output.py +195 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_subprocess.py +152 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_text_generation.py +980 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_types.py +110 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +72 -1817
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +56 -4
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +183 -1
- package/plugin/vendor/reflexio/reflexio/server/middleware.py +244 -0
- package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +9 -1
- package/plugin/vendor/reflexio/reflexio/server/rate_limit.py +79 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/__init__.py +6 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/_common.py +25 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/_metering.py +98 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/braintrust.py +129 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/config.py +210 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/evaluation.py +549 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/interactions.py +320 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/playbooks.py +578 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/profiles.py +423 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/provenance.py +345 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/search.py +349 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/system.py +261 -0
- package/plugin/vendor/reflexio/reflexio/server/scheduling.py +132 -0
- package/plugin/vendor/reflexio/reflexio/server/services/README.md +3 -2
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/__init__.py +38 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_batch_progress.py +298 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_config_filter.py +152 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_extraction_lifecycle.py +243 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_should_run.py +299 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_status_change.py +273 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_usage_billing.py +258 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +17 -1183
- package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +8 -1
- package/plugin/vendor/reflexio/reflexio/server/services/durable_learning/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/durable_learning/scheduler.py +142 -0
- package/plugin/vendor/reflexio/reflexio/server/services/durable_learning/worker.py +193 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +24 -41
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +335 -113
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +362 -81
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator.py +68 -490
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator_clustering.py +184 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator_postprocessing.py +130 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator_prompt_formatting.py +212 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/consolidator.py +258 -69
- package/plugin/vendor/reflexio/reflexio/server/services/profile/service.py +44 -22
- package/plugin/vendor/reflexio/reflexio/server/services/publish_learning_worker.py +288 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +31 -4
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +10 -1167
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +196 -353
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_governance.py +0 -1513
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_learning_jobs.py +379 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +17 -6
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +7 -1281
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +8 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +30 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/agent_run/__init__.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/agent_run/_agent_run_store.py +506 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/agent_run/_pending_tool_call_store.py +704 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/agent_run/_run_tool_dependency_store.py +123 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/__init__.py +6 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/_deletion.py +263 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/_fts_vec.py +216 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_audit.py +122 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_erase_execution.py +465 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_purge.py +387 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_rebuild_hide.py +332 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_subject_barrier.py +511 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_agent.py +22 -10
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_source_linkage.py +8 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_user.py +25 -12
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/__init__.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_interaction_store.py +308 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py +920 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_search.py +270 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +50 -8
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +64 -370
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_commit_scope.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_learning_jobs.py +219 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +20 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/__init__.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_agent_run_store.py +86 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_models.py +195 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_pending_tool_call_store.py +148 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_run_tool_dependency_store.py +38 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_audit.py +29 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_erase_execution.py +30 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_purge.py +74 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_rebuild_hide.py +32 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_subject_barrier.py +49 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/__init__.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/_interaction_store.py +95 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/{_profiles.py → profiles/_profile_store.py} +60 -80
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/_search.py +32 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_governance.py +0 -148
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"""Interaction route handlers (extracted from api.py, Tier3 A2)."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import uuid
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
from fastapi import (
|
|
11
|
+
APIRouter,
|
|
12
|
+
BackgroundTasks,
|
|
13
|
+
Depends,
|
|
14
|
+
HTTPException,
|
|
15
|
+
Request,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from reflexio.models.api_schema.retriever_schema import (
|
|
19
|
+
GetInteractionsRequest,
|
|
20
|
+
GetInteractionsViewResponse,
|
|
21
|
+
GetRequestsRequest,
|
|
22
|
+
GetRequestsViewResponse,
|
|
23
|
+
RequestDataView,
|
|
24
|
+
SessionView,
|
|
25
|
+
)
|
|
26
|
+
from reflexio.models.api_schema.service_schemas import (
|
|
27
|
+
BulkDeleteResponse,
|
|
28
|
+
DeleteRequestRequest,
|
|
29
|
+
DeleteRequestResponse,
|
|
30
|
+
DeleteRequestsByIdsRequest,
|
|
31
|
+
DeleteSessionRequest,
|
|
32
|
+
DeleteSessionResponse,
|
|
33
|
+
DeleteUserInteractionRequest,
|
|
34
|
+
DeleteUserInteractionResponse,
|
|
35
|
+
LearningStatusResponse,
|
|
36
|
+
PublishUserInteractionRequest,
|
|
37
|
+
PublishUserInteractionResponse,
|
|
38
|
+
)
|
|
39
|
+
from reflexio.models.api_schema.ui.converters import (
|
|
40
|
+
to_interaction_view,
|
|
41
|
+
)
|
|
42
|
+
from reflexio.server.api_endpoints import (
|
|
43
|
+
publisher_api,
|
|
44
|
+
)
|
|
45
|
+
from reflexio.server.auth import (
|
|
46
|
+
default_billing_gate,
|
|
47
|
+
default_get_org_id,
|
|
48
|
+
)
|
|
49
|
+
from reflexio.server.cache import reflexio_cache
|
|
50
|
+
from reflexio.server.rate_limit import limiter
|
|
51
|
+
from reflexio.server.routes._common import _run_limited_api
|
|
52
|
+
|
|
53
|
+
logger = logging.getLogger(__name__)
|
|
54
|
+
router = APIRouter()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@router.post(
|
|
58
|
+
"/api/publish_interaction",
|
|
59
|
+
response_model=PublishUserInteractionResponse,
|
|
60
|
+
response_model_exclude_none=True,
|
|
61
|
+
)
|
|
62
|
+
@limiter.limit("60/minute") # Rate limit for write operations
|
|
63
|
+
def publish_user_interaction(
|
|
64
|
+
request: Request,
|
|
65
|
+
payload: PublishUserInteractionRequest,
|
|
66
|
+
background_tasks: BackgroundTasks,
|
|
67
|
+
org_id: str = Depends(default_get_org_id),
|
|
68
|
+
wait_for_response: bool = False,
|
|
69
|
+
_gate: None = Depends(default_billing_gate("learnings_generated")), # noqa: B008
|
|
70
|
+
) -> PublishUserInteractionResponse:
|
|
71
|
+
if wait_for_response:
|
|
72
|
+
# Sync callers wait for the real result, so preserve bounded backpressure
|
|
73
|
+
# before any storage side effects. The inner service limiter is disabled
|
|
74
|
+
# because this route already owns the publish slot.
|
|
75
|
+
return _run_limited_api(
|
|
76
|
+
org_id,
|
|
77
|
+
"publish",
|
|
78
|
+
lambda: publisher_api.add_user_interaction(
|
|
79
|
+
org_id=org_id,
|
|
80
|
+
request=payload,
|
|
81
|
+
use_publish_limiter=False,
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Resolve the request_id BEFORE backgrounding so we can return it to the
|
|
86
|
+
# caller for polling. GenerationService uses a caller-supplied request_id
|
|
87
|
+
# verbatim (and generates one only when absent), so pinning it on the
|
|
88
|
+
# payload guarantees the background task stores its status under the same
|
|
89
|
+
# id we hand back here.
|
|
90
|
+
request_id = payload.request_id or str(uuid.uuid4())
|
|
91
|
+
payload.request_id = request_id
|
|
92
|
+
|
|
93
|
+
def _publish_task() -> None:
|
|
94
|
+
try:
|
|
95
|
+
publisher_api.add_user_interaction(
|
|
96
|
+
org_id=org_id,
|
|
97
|
+
request=payload,
|
|
98
|
+
defer_learning=True,
|
|
99
|
+
)
|
|
100
|
+
except Exception:
|
|
101
|
+
logger.exception("Background publish failed for org %s", org_id)
|
|
102
|
+
|
|
103
|
+
# Run in background — caller gets immediate acknowledgement.
|
|
104
|
+
# learning_status="deferred" tells the caller that extraction has not yet
|
|
105
|
+
# run; they can poll GET /api/learning_status?request_id=... (using the
|
|
106
|
+
# request_id returned here) to track it.
|
|
107
|
+
background_tasks.add_task(_publish_task)
|
|
108
|
+
return PublishUserInteractionResponse(
|
|
109
|
+
success=True,
|
|
110
|
+
message="Interaction queued for processing",
|
|
111
|
+
request_id=request_id,
|
|
112
|
+
learning_status="deferred",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@router.delete(
|
|
117
|
+
"/api/delete_interaction",
|
|
118
|
+
response_model=DeleteUserInteractionResponse,
|
|
119
|
+
response_model_exclude_none=True,
|
|
120
|
+
)
|
|
121
|
+
def delete_interaction(
|
|
122
|
+
request: DeleteUserInteractionRequest,
|
|
123
|
+
org_id: str = Depends(default_get_org_id),
|
|
124
|
+
) -> DeleteUserInteractionResponse:
|
|
125
|
+
return publisher_api.delete_user_interaction(org_id=org_id, request=request)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@router.delete(
|
|
129
|
+
"/api/delete_request",
|
|
130
|
+
response_model=DeleteRequestResponse,
|
|
131
|
+
response_model_exclude_none=True,
|
|
132
|
+
)
|
|
133
|
+
def delete_request(
|
|
134
|
+
request: DeleteRequestRequest,
|
|
135
|
+
org_id: str = Depends(default_get_org_id),
|
|
136
|
+
) -> DeleteRequestResponse:
|
|
137
|
+
return publisher_api.delete_request(org_id=org_id, request=request)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@router.delete(
|
|
141
|
+
"/api/delete_session",
|
|
142
|
+
response_model=DeleteSessionResponse,
|
|
143
|
+
response_model_exclude_none=True,
|
|
144
|
+
)
|
|
145
|
+
def delete_session(
|
|
146
|
+
request: DeleteSessionRequest,
|
|
147
|
+
org_id: str = Depends(default_get_org_id),
|
|
148
|
+
) -> DeleteSessionResponse:
|
|
149
|
+
return publisher_api.delete_session(org_id=org_id, request=request)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@router.delete(
|
|
153
|
+
"/api/delete_requests_by_ids",
|
|
154
|
+
response_model=BulkDeleteResponse,
|
|
155
|
+
response_model_exclude_none=True,
|
|
156
|
+
)
|
|
157
|
+
def delete_requests_by_ids(
|
|
158
|
+
request: DeleteRequestsByIdsRequest,
|
|
159
|
+
org_id: str = Depends(default_get_org_id),
|
|
160
|
+
) -> BulkDeleteResponse:
|
|
161
|
+
"""Delete multiple requests by their IDs.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
request (DeleteRequestsByIdsRequest): Request containing list of request IDs to delete
|
|
165
|
+
org_id (str): Organization ID
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
BulkDeleteResponse: Response containing success status and deleted count
|
|
169
|
+
"""
|
|
170
|
+
return publisher_api.delete_requests_by_ids(org_id=org_id, request=request)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@router.delete(
|
|
174
|
+
"/api/delete_all_interactions",
|
|
175
|
+
response_model=BulkDeleteResponse,
|
|
176
|
+
response_model_exclude_none=True,
|
|
177
|
+
)
|
|
178
|
+
@limiter.limit("10/minute")
|
|
179
|
+
def delete_all_interactions(
|
|
180
|
+
request: Request,
|
|
181
|
+
org_id: str = Depends(default_get_org_id),
|
|
182
|
+
) -> BulkDeleteResponse:
|
|
183
|
+
"""Delete all requests and their associated interactions.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
org_id (str): Organization ID
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
BulkDeleteResponse: Response containing success status and deleted count
|
|
190
|
+
"""
|
|
191
|
+
return publisher_api.delete_all_interactions_bulk(org_id=org_id)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@router.post(
|
|
195
|
+
"/api/get_interactions",
|
|
196
|
+
response_model=GetInteractionsViewResponse,
|
|
197
|
+
response_model_exclude_none=True,
|
|
198
|
+
)
|
|
199
|
+
def get_interactions(
|
|
200
|
+
request: GetInteractionsRequest,
|
|
201
|
+
org_id: str = Depends(default_get_org_id),
|
|
202
|
+
) -> GetInteractionsViewResponse:
|
|
203
|
+
response = reflexio_cache.get_reflexio(org_id=org_id).get_interactions(request)
|
|
204
|
+
return GetInteractionsViewResponse(
|
|
205
|
+
success=response.success,
|
|
206
|
+
interactions=[to_interaction_view(i) for i in response.interactions],
|
|
207
|
+
msg=response.msg,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@router.get(
|
|
212
|
+
"/api/get_all_interactions",
|
|
213
|
+
response_model=GetInteractionsViewResponse,
|
|
214
|
+
response_model_exclude_none=True,
|
|
215
|
+
)
|
|
216
|
+
@limiter.limit("30/minute")
|
|
217
|
+
def get_all_interactions(
|
|
218
|
+
request: Request,
|
|
219
|
+
limit: int = 100,
|
|
220
|
+
org_id: str = Depends(default_get_org_id),
|
|
221
|
+
) -> GetInteractionsViewResponse:
|
|
222
|
+
"""Get all user interactions across all users.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
limit (int, optional): Maximum number of interactions to return. Defaults to 100.
|
|
226
|
+
org_id (str): Organization ID
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
GetInteractionsViewResponse: Response containing all user interactions
|
|
230
|
+
"""
|
|
231
|
+
reflexio = reflexio_cache.get_reflexio(org_id=org_id)
|
|
232
|
+
response = reflexio.get_all_interactions(limit=limit)
|
|
233
|
+
return GetInteractionsViewResponse(
|
|
234
|
+
success=response.success,
|
|
235
|
+
interactions=[to_interaction_view(i) for i in response.interactions],
|
|
236
|
+
msg=response.msg,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@router.post(
|
|
241
|
+
"/api/get_requests",
|
|
242
|
+
response_model=GetRequestsViewResponse,
|
|
243
|
+
response_model_exclude_none=True,
|
|
244
|
+
)
|
|
245
|
+
def get_requests_endpoint(
|
|
246
|
+
request: GetRequestsRequest,
|
|
247
|
+
org_id: str = Depends(default_get_org_id),
|
|
248
|
+
) -> GetRequestsViewResponse:
|
|
249
|
+
"""Get requests with their associated interactions.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
request (GetRequestsRequest): The get request
|
|
253
|
+
org_id (str): Organization ID
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
GetRequestsViewResponse: Response containing requests with their interactions
|
|
257
|
+
"""
|
|
258
|
+
internal_response = reflexio_cache.get_reflexio(org_id=org_id).get_requests(request)
|
|
259
|
+
return GetRequestsViewResponse(
|
|
260
|
+
success=internal_response.success,
|
|
261
|
+
sessions=[
|
|
262
|
+
SessionView(
|
|
263
|
+
session_id=s.session_id,
|
|
264
|
+
requests=[
|
|
265
|
+
RequestDataView(
|
|
266
|
+
request=rd.request,
|
|
267
|
+
interactions=[to_interaction_view(i) for i in rd.interactions],
|
|
268
|
+
)
|
|
269
|
+
for rd in s.requests
|
|
270
|
+
],
|
|
271
|
+
)
|
|
272
|
+
for s in internal_response.sessions
|
|
273
|
+
],
|
|
274
|
+
has_more=internal_response.has_more,
|
|
275
|
+
msg=internal_response.msg,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@router.get(
|
|
280
|
+
"/api/learning_status",
|
|
281
|
+
response_model=LearningStatusResponse,
|
|
282
|
+
response_model_exclude_none=True,
|
|
283
|
+
)
|
|
284
|
+
@limiter.limit("120/minute")
|
|
285
|
+
def get_learning_status(
|
|
286
|
+
request: Request,
|
|
287
|
+
request_id: str,
|
|
288
|
+
org_id: str = Depends(default_get_org_id),
|
|
289
|
+
) -> LearningStatusResponse:
|
|
290
|
+
"""Return the coverage-based learning status for a published request.
|
|
291
|
+
|
|
292
|
+
The status reflects whether a durable learning job has processed through
|
|
293
|
+
the request's creation timestamp:
|
|
294
|
+
|
|
295
|
+
- ``pending``: not yet picked up.
|
|
296
|
+
- ``processing``: a worker currently holds the job.
|
|
297
|
+
- ``done``: at least one completed job covers this request.
|
|
298
|
+
- ``failed``: a dead job covers this request and no done job does.
|
|
299
|
+
|
|
300
|
+
Note: this endpoint reads ``learning_jobs`` rows written by the durable
|
|
301
|
+
queue. When the durable queue is OFF (in-memory deferred path) it returns
|
|
302
|
+
absence-based status (``pending`` for recent requests, ``done`` for old
|
|
303
|
+
ones) — acceptable for v1; the poll contract is tied to the durable queue.
|
|
304
|
+
|
|
305
|
+
Raises:
|
|
306
|
+
HTTPException: 404 when ``request_id`` is not found for this org.
|
|
307
|
+
Never reports ``done`` for a request that never existed.
|
|
308
|
+
"""
|
|
309
|
+
reflexio = reflexio_cache.get_reflexio(org_id=org_id)
|
|
310
|
+
storage = reflexio.request_context.storage
|
|
311
|
+
if storage is None:
|
|
312
|
+
raise HTTPException(status_code=503, detail="Storage not configured")
|
|
313
|
+
req = storage.get_request(request_id)
|
|
314
|
+
if req is None:
|
|
315
|
+
raise HTTPException(status_code=404, detail="request not found")
|
|
316
|
+
status = storage.get_learning_status_for_request(
|
|
317
|
+
user_id=req.user_id,
|
|
318
|
+
request_created_at=float(req.created_at),
|
|
319
|
+
)
|
|
320
|
+
return LearningStatusResponse(status=status)
|