claude-smart 0.2.48 → 0.2.50
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 +2 -2
- package/README.md +11 -40
- package/bin/claude-smart.js +393 -55
- package/package.json +3 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.coverage +0 -0
- package/plugin/README.md +4 -3
- package/plugin/dashboard/app/api/reflexio/[...path]/route.ts +4 -2
- package/plugin/dashboard/app/dashboard/page.tsx +6 -1
- package/plugin/dashboard/app/preferences/[id]/page.tsx +18 -6
- package/plugin/dashboard/app/preferences/page.tsx +32 -35
- package/plugin/dashboard/app/sessions/[sessionId]/page.tsx +16 -1
- package/plugin/dashboard/app/sessions/page.tsx +2 -0
- package/plugin/dashboard/app/skills/page.tsx +65 -50
- package/plugin/dashboard/app/skills/project/[id]/page.tsx +17 -8
- package/plugin/dashboard/app/skills/shared/[id]/page.tsx +1 -6
- package/plugin/dashboard/components/common/host-badge.tsx +118 -0
- package/plugin/dashboard/components/common/learning-application-badge.tsx +34 -0
- package/plugin/dashboard/components/common/learnings-badge.tsx +1 -1
- package/plugin/dashboard/components/common/page-header.tsx +3 -3
- package/plugin/dashboard/lib/config-file.ts +5 -1
- package/plugin/dashboard/lib/host-attribution.ts +62 -0
- package/plugin/dashboard/lib/session-reader.ts +40 -2
- package/plugin/dashboard/lib/types.ts +7 -1
- 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 +255 -7
- package/plugin/scripts/backend-python-runner.py +46 -0
- package/plugin/scripts/backend-service.sh +766 -123
- package/plugin/scripts/codex-hook.js +79 -229
- package/plugin/scripts/dashboard-open.sh +6 -4
- package/plugin/scripts/dashboard-service.sh +118 -137
- package/plugin/scripts/ensure-plugin-root.sh +106 -8
- package/plugin/scripts/hook_entry.sh +3 -0
- package/plugin/scripts/opencode-claude-compat.js +8 -1
- package/plugin/scripts/smart-install.sh +116 -21
- package/plugin/src/README.md +1 -1
- package/plugin/src/claude_smart/cli.py +93 -29
- package/plugin/src/claude_smart/context_inject.py +3 -0
- package/plugin/src/claude_smart/env_config.py +56 -11
- package/plugin/src/claude_smart/events/post_tool.py +2 -1
- package/plugin/src/claude_smart/events/session_end.py +2 -1
- package/plugin/src/claude_smart/events/stop.py +3 -0
- package/plugin/src/claude_smart/events/user_prompt.py +2 -1
- package/plugin/src/claude_smart/internal_call.py +5 -2
- package/plugin/src/claude_smart/optimizer_assistant.py +59 -13
- package/plugin/src/claude_smart/publish.py +59 -7
- package/plugin/src/claude_smart/reflexio_adapter.py +137 -14
- package/plugin/src/claude_smart/runtime.py +15 -6
- package/plugin/src/claude_smart/state.py +211 -52
- package/plugin/uv.lock +5 -5
- package/plugin/vendor/reflexio/.env.example +13 -0
- package/plugin/vendor/reflexio/reflexio/README.md +7 -3
- package/plugin/vendor/reflexio/reflexio/__init__.py +12 -0
- package/plugin/vendor/reflexio/reflexio/cli/README.md +3 -0
- package/plugin/vendor/reflexio/reflexio/client/client.py +166 -9
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +10 -3
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +28 -0
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +41 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +195 -25
- package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +7 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +2 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +63 -4
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +1 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +8 -1
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/README.md +22 -4
- package/plugin/vendor/reflexio/reflexio/server/__init__.py +18 -8
- package/plugin/vendor/reflexio/reflexio/server/__main__.py +6 -0
- package/plugin/vendor/reflexio/reflexio/server/api.py +79 -5
- package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +263 -3
- package/plugin/vendor/reflexio/reflexio/server/callback_executor.py +164 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_embedding.py +81 -81
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_subprocess.py +28 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_text_generation.py +63 -6
- package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -52
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +28 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +9 -1
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedder_warmup.py +329 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +85 -10
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +199 -2
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +77 -9
- package/plugin/vendor/reflexio/reflexio/server/org_fanout.py +184 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.0.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.1.0.prompt.md +32 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.4.0.prompt.md +63 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v2.0.0.prompt.md +30 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/retrieved_learning_impact/v1.0.0.prompt.md +51 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/retrieved_learning_relevance/v1.0.0.prompt.md +39 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.1.0.prompt.md +43 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/config.py +3 -3
- package/plugin/vendor/reflexio/reflexio/server/routes/evaluation.py +122 -28
- package/plugin/vendor/reflexio/reflexio/server/routes/interactions.py +63 -2
- package/plugin/vendor/reflexio/reflexio/server/routes/system.py +22 -3
- package/plugin/vendor/reflexio/reflexio/server/scheduling.py +64 -3
- package/plugin/vendor/reflexio/reflexio/server/services/README.md +6 -4
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +3 -2
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +41 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/retrieved_learning_evaluator.py +554 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +35 -1
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/runner.py +253 -101
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/scheduler.py +5 -7
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/service.py +27 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_extraction_lifecycle.py +11 -5
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_should_run.py +4 -4
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_usage_billing.py +6 -2
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +255 -74
- package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +72 -0
- package/plugin/vendor/reflexio/reflexio/server/services/deferred_learning_plan.py +270 -0
- 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 +262 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/hero_state.py +2 -11
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/rule_attribution.py +6 -2
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +17 -13
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +18 -3
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +12 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +2 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +1 -3
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +66 -0
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +640 -80
- package/plugin/vendor/reflexio/reflexio/server/services/governance/service.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +179 -99
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/vector_backfill_sweep.py +139 -0
- package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +66 -27
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/aggregation_trigger.py +177 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator.py +68 -2
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/consolidator.py +360 -49
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/extractor.py +27 -30
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +8 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/service.py +137 -69
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +20 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +13 -6
- package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +40 -25
- package/plugin/vendor/reflexio/reflexio/server/services/profile/components/consolidator.py +12 -39
- package/plugin/vendor/reflexio/reflexio/server/services/profile/components/extractor.py +30 -35
- package/plugin/vendor/reflexio/reflexio/server/services/profile/service.py +166 -66
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/service.py +457 -107
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/session_dedup.py +127 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/temporal.py +104 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/dispatcher.py +139 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +16 -6
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/worker.py +137 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/governance_validation.py +12 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/lifecycle_filters.py +54 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +41 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +40 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +190 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +11 -4
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_governance.py +28 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_learning_jobs.py +414 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +11 -5
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +8 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +4 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/_deletion.py +16 -5
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/_fts_vec.py +86 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_erase_execution.py +104 -42
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_subject_barrier.py +7 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_agent.py +59 -7
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_eval_results.py +430 -5
- 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 +57 -12
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_interaction_store.py +197 -12
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py +70 -11
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +17 -0
- 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/_extras.py +9 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_learning_jobs.py +269 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +3 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +4 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_models.py +12 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/evaluation_state_keys.py +78 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_agent.py +38 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_eval_results.py +171 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_user.py +52 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/_interaction_store.py +82 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/_profile_store.py +74 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/retrieved_learning_state.py +226 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +5 -6
- package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +209 -29
- package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +3 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +33 -0
- package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
|
@@ -15,6 +15,13 @@ import requests
|
|
|
15
15
|
from pydantic import ConfigDict
|
|
16
16
|
|
|
17
17
|
from reflexio.defaults import DEFAULT_AGENT_VERSION
|
|
18
|
+
from reflexio.models.api_schema.eval_overview_schema import (
|
|
19
|
+
GradeOnDemandRequest,
|
|
20
|
+
GradeOnDemandResponse,
|
|
21
|
+
RegenerateRequest,
|
|
22
|
+
RegenerateStartResponse,
|
|
23
|
+
RegenerateStatusResponse,
|
|
24
|
+
)
|
|
18
25
|
from reflexio.models.api_schema.retriever_schema import (
|
|
19
26
|
ConversationTurn,
|
|
20
27
|
GetAgentPlaybooksRequest,
|
|
@@ -26,6 +33,8 @@ from reflexio.models.api_schema.retriever_schema import (
|
|
|
26
33
|
GetProfilesViewResponse,
|
|
27
34
|
GetRequestsRequest,
|
|
28
35
|
GetRequestsViewResponse,
|
|
36
|
+
GetRetrievedLearningEvaluationResultsRequest,
|
|
37
|
+
GetRetrievedLearningEvaluationResultsResponse,
|
|
29
38
|
GetUserPlaybooksRequest,
|
|
30
39
|
GetUserPlaybooksViewResponse,
|
|
31
40
|
GetUserProfilesRequest,
|
|
@@ -306,9 +315,8 @@ class ReflexioClient:
|
|
|
306
315
|
if headers:
|
|
307
316
|
request_headers.update(headers)
|
|
308
317
|
|
|
309
|
-
self.session.headers.update(request_headers)
|
|
310
318
|
kwargs.setdefault("timeout", self.timeout)
|
|
311
|
-
response = self.session.request(method, url, **kwargs)
|
|
319
|
+
response = self.session.request(method, url, headers=request_headers, **kwargs)
|
|
312
320
|
response.raise_for_status()
|
|
313
321
|
|
|
314
322
|
# Empty body on a successful response (e.g. 204 No Content).
|
|
@@ -445,12 +453,17 @@ class ReflexioClient:
|
|
|
445
453
|
explicit retry after reauth or limit reset.
|
|
446
454
|
|
|
447
455
|
Returns:
|
|
448
|
-
PublishUserInteractionResponse: Server response.
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
456
|
+
PublishUserInteractionResponse: Server response.
|
|
457
|
+
|
|
458
|
+
In deferred mode (``wait_for_response=False``) the
|
|
459
|
+
response carries ``learning_status="deferred"`` and a
|
|
460
|
+
``request_id``; ``profiles_added``/``playbooks_added`` are
|
|
461
|
+
0 because extraction has not run yet. Poll
|
|
462
|
+
``get_learning_status(request_id)`` for completion.
|
|
463
|
+
|
|
464
|
+
In ``wait_for_response=True`` mode the server waits for
|
|
465
|
+
extraction and the response includes ``request_id``,
|
|
466
|
+
storage routing, and real profile/playbook deltas.
|
|
454
467
|
"""
|
|
455
468
|
if session_id is None or not session_id.strip():
|
|
456
469
|
raise ValueError("session_id is required and cannot be empty")
|
|
@@ -481,6 +494,35 @@ class ReflexioClient:
|
|
|
481
494
|
self._cache.invalidate("get_agent_playbooks")
|
|
482
495
|
return result
|
|
483
496
|
|
|
497
|
+
def get_learning_status(self, request_id: str) -> str:
|
|
498
|
+
"""Poll the learning status for a previously published request.
|
|
499
|
+
|
|
500
|
+
Call this after a deferred ``publish_interaction`` (where
|
|
501
|
+
``wait_for_response=False``). The response carries
|
|
502
|
+
``learning_status="deferred"`` to signal that extraction has been
|
|
503
|
+
queued; use this method to track progress once the durable queue
|
|
504
|
+
is active.
|
|
505
|
+
|
|
506
|
+
Args:
|
|
507
|
+
request_id: The ``request_id`` of the published interaction, as
|
|
508
|
+
returned in ``PublishUserInteractionResponse.request_id``
|
|
509
|
+
(populated on both the deferred and ``wait_for_response=True``
|
|
510
|
+
paths) or known by the caller.
|
|
511
|
+
|
|
512
|
+
Returns:
|
|
513
|
+
One of: ``"pending"`` | ``"processing"`` | ``"done"`` | ``"failed"``.
|
|
514
|
+
|
|
515
|
+
Raises:
|
|
516
|
+
requests.HTTPError: 404 when the request_id is not known to the
|
|
517
|
+
server for this org.
|
|
518
|
+
"""
|
|
519
|
+
response = self._make_request(
|
|
520
|
+
"GET",
|
|
521
|
+
"/api/learning_status",
|
|
522
|
+
params={"request_id": request_id},
|
|
523
|
+
)
|
|
524
|
+
return str(response["status"])
|
|
525
|
+
|
|
484
526
|
def search_interactions(
|
|
485
527
|
self,
|
|
486
528
|
request: SearchInteractionRequest | dict | None = None,
|
|
@@ -1886,6 +1928,116 @@ class ReflexioClient:
|
|
|
1886
1928
|
)
|
|
1887
1929
|
return GetEvaluationResultsViewResponse(**response)
|
|
1888
1930
|
|
|
1931
|
+
def get_retrieved_learning_evaluation_results(
|
|
1932
|
+
self,
|
|
1933
|
+
request: GetRetrievedLearningEvaluationResultsRequest | dict | None = None,
|
|
1934
|
+
*,
|
|
1935
|
+
user_id: str | None = None,
|
|
1936
|
+
session_id: str | None = None,
|
|
1937
|
+
limit: int | None = None,
|
|
1938
|
+
) -> GetRetrievedLearningEvaluationResultsResponse:
|
|
1939
|
+
"""Get per-learning relevance and impact verdicts for retrieved context."""
|
|
1940
|
+
req = self._build_request(
|
|
1941
|
+
request,
|
|
1942
|
+
GetRetrievedLearningEvaluationResultsRequest,
|
|
1943
|
+
user_id=user_id,
|
|
1944
|
+
session_id=session_id,
|
|
1945
|
+
limit=limit,
|
|
1946
|
+
)
|
|
1947
|
+
response = self._make_request(
|
|
1948
|
+
"POST",
|
|
1949
|
+
"/api/get_retrieved_learning_evaluation_results",
|
|
1950
|
+
json=req.model_dump(),
|
|
1951
|
+
)
|
|
1952
|
+
return GetRetrievedLearningEvaluationResultsResponse(**response)
|
|
1953
|
+
|
|
1954
|
+
def regenerate_evaluations(
|
|
1955
|
+
self,
|
|
1956
|
+
request: RegenerateRequest | dict | None = None,
|
|
1957
|
+
*,
|
|
1958
|
+
from_ts: int | None = None,
|
|
1959
|
+
to_ts: int | None = None,
|
|
1960
|
+
evaluation_name: str | None = None,
|
|
1961
|
+
) -> RegenerateStartResponse:
|
|
1962
|
+
"""Start a replay-the-judge regeneration job over a time window.
|
|
1963
|
+
|
|
1964
|
+
Args:
|
|
1965
|
+
request: Optional ``RegenerateRequest`` or dict. If omitted,
|
|
1966
|
+
keyword arguments are used.
|
|
1967
|
+
from_ts: Inclusive lower bound of the window as Unix seconds.
|
|
1968
|
+
to_ts: Inclusive upper bound of the window as Unix seconds.
|
|
1969
|
+
evaluation_name: Deprecated compatibility field accepted by the
|
|
1970
|
+
API but ignored by the singleton evaluator.
|
|
1971
|
+
|
|
1972
|
+
Returns:
|
|
1973
|
+
RegenerateStartResponse: The job id and number of queued sessions.
|
|
1974
|
+
"""
|
|
1975
|
+
req = self._build_request(
|
|
1976
|
+
request,
|
|
1977
|
+
RegenerateRequest,
|
|
1978
|
+
from_ts=from_ts,
|
|
1979
|
+
to_ts=to_ts,
|
|
1980
|
+
evaluation_name=evaluation_name,
|
|
1981
|
+
)
|
|
1982
|
+
response = self._make_request(
|
|
1983
|
+
"POST",
|
|
1984
|
+
"/api/evaluations/regenerate",
|
|
1985
|
+
json=req.model_dump(),
|
|
1986
|
+
)
|
|
1987
|
+
return RegenerateStartResponse(**response)
|
|
1988
|
+
|
|
1989
|
+
def get_evaluation_regeneration_status(
|
|
1990
|
+
self, job_id: str
|
|
1991
|
+
) -> RegenerateStatusResponse:
|
|
1992
|
+
"""Get status for an evaluation regeneration job."""
|
|
1993
|
+
response = self._make_request(
|
|
1994
|
+
"GET",
|
|
1995
|
+
f"/api/evaluations/regenerate/{job_id}",
|
|
1996
|
+
)
|
|
1997
|
+
return RegenerateStatusResponse(**response)
|
|
1998
|
+
|
|
1999
|
+
def cancel_evaluation_regeneration(self, job_id: str) -> dict[str, str]:
|
|
2000
|
+
"""Request cancellation for an evaluation regeneration job."""
|
|
2001
|
+
return self._make_request(
|
|
2002
|
+
"DELETE",
|
|
2003
|
+
f"/api/evaluations/regenerate/{job_id}",
|
|
2004
|
+
)
|
|
2005
|
+
|
|
2006
|
+
def grade_on_demand(
|
|
2007
|
+
self,
|
|
2008
|
+
request: GradeOnDemandRequest | dict | None = None,
|
|
2009
|
+
*,
|
|
2010
|
+
session_id: str | None = None,
|
|
2011
|
+
agent_version: str | None = None,
|
|
2012
|
+
evaluation_name: str | None = None,
|
|
2013
|
+
) -> GradeOnDemandResponse:
|
|
2014
|
+
"""Grade a single session synchronously.
|
|
2015
|
+
|
|
2016
|
+
Args:
|
|
2017
|
+
request: Optional ``GradeOnDemandRequest`` or dict. If omitted,
|
|
2018
|
+
keyword arguments are used.
|
|
2019
|
+
session_id: Session to grade.
|
|
2020
|
+
agent_version: Agent version to grade.
|
|
2021
|
+
evaluation_name: Deprecated compatibility field accepted by the
|
|
2022
|
+
API but ignored by the singleton evaluator.
|
|
2023
|
+
|
|
2024
|
+
Returns:
|
|
2025
|
+
GradeOnDemandResponse: Result id, cache flag, or skipped reason.
|
|
2026
|
+
"""
|
|
2027
|
+
req = self._build_request(
|
|
2028
|
+
request,
|
|
2029
|
+
GradeOnDemandRequest,
|
|
2030
|
+
session_id=session_id,
|
|
2031
|
+
agent_version=agent_version,
|
|
2032
|
+
evaluation_name=evaluation_name,
|
|
2033
|
+
)
|
|
2034
|
+
response = self._make_request(
|
|
2035
|
+
"POST",
|
|
2036
|
+
"/api/evaluations/grade_on_demand",
|
|
2037
|
+
json=req.model_dump(),
|
|
2038
|
+
)
|
|
2039
|
+
return GradeOnDemandResponse(**response)
|
|
2040
|
+
|
|
1889
2041
|
def _poll_operation_status(
|
|
1890
2042
|
self,
|
|
1891
2043
|
service_name: str,
|
|
@@ -2365,7 +2517,12 @@ class ReflexioClient:
|
|
|
2365
2517
|
"profiles", "user_playbooks", "agent_playbooks".
|
|
2366
2518
|
agent_playbook_status_filter (Optional[list[Union[PlaybookStatus, str]]]):
|
|
2367
2519
|
Agent-playbook approval statuses to include.
|
|
2368
|
-
enable_reformulation (Optional[bool]): Enable
|
|
2520
|
+
enable_reformulation (Optional[bool]): Enable the pre-search LLM
|
|
2521
|
+
query reformulation call (default: False). Besides rewriting
|
|
2522
|
+
the query, it extracts temporal signals — time windows
|
|
2523
|
+
("this week"), as-of boundaries, and current-value intent —
|
|
2524
|
+
that make retrieval time-sensitive (window filters,
|
|
2525
|
+
freshness-preferred ranking for superseded facts).
|
|
2369
2526
|
enable_agent_answer (Optional[bool]): Enable agentic answer synthesis when
|
|
2370
2527
|
the configured search backend supports it (default: False).
|
|
2371
2528
|
conversation_history (Optional[list[ConversationTurn] | list[dict]]): Prior conversation turns for context-aware query reformulation. Accepts ConversationTurn objects or dicts with "role" and "content" keys.
|
package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py
CHANGED
|
@@ -36,7 +36,9 @@ _DEFAULT_STATE_DIR = Path.home() / ".openclaw-smart" / "sessions"
|
|
|
36
36
|
|
|
37
37
|
_TOOL_DATA_FIELD_MAX_LEN = 256
|
|
38
38
|
|
|
39
|
-
_VALID_CITATION_KINDS = frozenset(
|
|
39
|
+
_VALID_CITATION_KINDS = frozenset(
|
|
40
|
+
{"playbook", "profile", "user_playbook", "agent_playbook"}
|
|
41
|
+
)
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
def _truncate_tool_data_field(value: Any) -> Any:
|
|
@@ -240,13 +242,18 @@ def _to_wire_citations(cited_items: Any) -> list[dict[str, str]]:
|
|
|
240
242
|
kind = item.get("kind")
|
|
241
243
|
if not isinstance(real_id, str) or not real_id:
|
|
242
244
|
continue
|
|
243
|
-
|
|
245
|
+
wire_kind = kind
|
|
246
|
+
if kind == "playbook":
|
|
247
|
+
source_kind = item.get("source_kind")
|
|
248
|
+
if source_kind in {"user_playbook", "agent_playbook"}:
|
|
249
|
+
wire_kind = source_kind
|
|
250
|
+
if wire_kind not in _VALID_CITATION_KINDS:
|
|
244
251
|
continue
|
|
245
252
|
tag = item.get("id")
|
|
246
253
|
title = item.get("title")
|
|
247
254
|
out.append(
|
|
248
255
|
{
|
|
249
|
-
"kind":
|
|
256
|
+
"kind": wire_kind,
|
|
250
257
|
"real_id": real_id,
|
|
251
258
|
"tag": tag if isinstance(tag, str) else "",
|
|
252
259
|
"title": title if isinstance(title, str) else "",
|
|
@@ -233,3 +233,31 @@ def test_safe_session_ids_accepted():
|
|
|
233
233
|
path = state.session_path(sid)
|
|
234
234
|
assert path is not None, f"safe id {sid!r} should have been accepted"
|
|
235
235
|
assert path.name == f"{sid}.jsonl"
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_to_wire_citations_preserves_explicit_playbook_source_kind() -> None:
|
|
239
|
+
wire = state._to_wire_citations(
|
|
240
|
+
[
|
|
241
|
+
{
|
|
242
|
+
"id": "s1-1",
|
|
243
|
+
"kind": "playbook",
|
|
244
|
+
"source_kind": "agent_playbook",
|
|
245
|
+
"real_id": "20",
|
|
246
|
+
"title": "Agent",
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"id": "s2-1",
|
|
250
|
+
"kind": "playbook",
|
|
251
|
+
"source_kind": "user_playbook",
|
|
252
|
+
"real_id": "101",
|
|
253
|
+
"title": "User",
|
|
254
|
+
},
|
|
255
|
+
{"id": "p1-1", "kind": "profile", "real_id": "p1", "title": "Profile"},
|
|
256
|
+
]
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
assert [item["kind"] for item in wire] == [
|
|
260
|
+
"agent_playbook",
|
|
261
|
+
"user_playbook",
|
|
262
|
+
"profile",
|
|
263
|
+
]
|
|
@@ -6,6 +6,8 @@ from reflexio.models.api_schema.retriever_schema import (
|
|
|
6
6
|
GetAgentSuccessEvaluationResultsResponse,
|
|
7
7
|
GetRequestsRequest,
|
|
8
8
|
GetRequestsResponse,
|
|
9
|
+
GetRetrievedLearningEvaluationResultsRequest,
|
|
10
|
+
GetRetrievedLearningEvaluationResultsResponse,
|
|
9
11
|
RequestData,
|
|
10
12
|
Session,
|
|
11
13
|
UnifiedSearchRequest,
|
|
@@ -72,6 +74,45 @@ class SearchMixin(ReflexioBase):
|
|
|
72
74
|
success=False, agent_success_evaluation_results=[], msg=str(e)
|
|
73
75
|
)
|
|
74
76
|
|
|
77
|
+
def get_retrieved_learning_evaluation_results(
|
|
78
|
+
self,
|
|
79
|
+
request: GetRetrievedLearningEvaluationResultsRequest | dict,
|
|
80
|
+
) -> GetRetrievedLearningEvaluationResultsResponse:
|
|
81
|
+
"""Get per-learning retrieved-learning evaluation verdicts.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
request (GetRetrievedLearningEvaluationResultsRequest | dict): The
|
|
85
|
+
read request (optional user/session filters + limit).
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
GetRetrievedLearningEvaluationResultsResponse: Matching verdicts
|
|
89
|
+
ordered by created_at DESC, result_id DESC.
|
|
90
|
+
"""
|
|
91
|
+
if not self._is_storage_configured():
|
|
92
|
+
return GetRetrievedLearningEvaluationResultsResponse(
|
|
93
|
+
success=True, results=[], msg=STORAGE_NOT_CONFIGURED_MSG
|
|
94
|
+
)
|
|
95
|
+
if isinstance(request, dict):
|
|
96
|
+
request = GetRetrievedLearningEvaluationResultsRequest(**request)
|
|
97
|
+
try:
|
|
98
|
+
results = self._get_storage().get_retrieved_learning_evaluation_results(
|
|
99
|
+
user_id=request.user_id,
|
|
100
|
+
session_id=request.session_id,
|
|
101
|
+
limit=request.limit,
|
|
102
|
+
)
|
|
103
|
+
return GetRetrievedLearningEvaluationResultsResponse(
|
|
104
|
+
success=True,
|
|
105
|
+
results=results,
|
|
106
|
+
msg=f"Found {len(results)} retrieved-learning evaluation result(s)",
|
|
107
|
+
)
|
|
108
|
+
except Exception:
|
|
109
|
+
_LOGGER.exception("Failed to read retrieved-learning evaluation results")
|
|
110
|
+
return GetRetrievedLearningEvaluationResultsResponse(
|
|
111
|
+
success=False,
|
|
112
|
+
results=[],
|
|
113
|
+
msg="Failed to read retrieved-learning evaluation results",
|
|
114
|
+
)
|
|
115
|
+
|
|
75
116
|
def get_requests(
|
|
76
117
|
self,
|
|
77
118
|
request: GetRequestsRequest | dict,
|
|
@@ -33,7 +33,11 @@ __all__ = [
|
|
|
33
33
|
"BlockingIssue",
|
|
34
34
|
"BlockingIssueKind",
|
|
35
35
|
"ToolUsed",
|
|
36
|
+
"CitationKind",
|
|
36
37
|
"Citation",
|
|
38
|
+
"RetrievedLearningKind",
|
|
39
|
+
"RetrievedLearning",
|
|
40
|
+
"LearningImpact",
|
|
37
41
|
"Interaction",
|
|
38
42
|
"Request",
|
|
39
43
|
"UserProfile",
|
|
@@ -41,6 +45,7 @@ __all__ = [
|
|
|
41
45
|
"ProfileChangeLog",
|
|
42
46
|
"AgentPlaybook",
|
|
43
47
|
"AgentSuccessEvaluationResult",
|
|
48
|
+
"RetrievedLearningEvaluationResult",
|
|
44
49
|
"DeleteUserProfileRequest",
|
|
45
50
|
"DeleteUserProfileResponse",
|
|
46
51
|
"DeleteUserInteractionRequest",
|
|
@@ -123,12 +128,15 @@ __all__ = [
|
|
|
123
128
|
"LineageEvent",
|
|
124
129
|
"LineageContext",
|
|
125
130
|
"RecordRef",
|
|
131
|
+
"LearningStatusResponse",
|
|
126
132
|
]
|
|
127
133
|
|
|
128
134
|
# ===============================
|
|
129
135
|
# Data Models
|
|
130
136
|
# ===============================
|
|
131
137
|
|
|
138
|
+
type CitationKind = Literal["playbook", "profile", "user_playbook", "agent_playbook"]
|
|
139
|
+
|
|
132
140
|
|
|
133
141
|
class Citation(BaseModel):
|
|
134
142
|
"""A playbook or profile item the agent cited as influential.
|
|
@@ -140,22 +148,52 @@ class Citation(BaseModel):
|
|
|
140
148
|
it was applied?).
|
|
141
149
|
|
|
142
150
|
Attributes:
|
|
143
|
-
kind (
|
|
144
|
-
|
|
151
|
+
kind (CitationKind): Which kind of cited item this references.
|
|
152
|
+
``"playbook"`` is the legacy compatibility value.
|
|
153
|
+
``"user_playbook"`` is the direct tuner target.
|
|
154
|
+
``"agent_playbook"`` references an org-level playbook row.
|
|
155
|
+
``"profile"`` references a user profile row.
|
|
145
156
|
real_id (str): Stable storage id — ``user_playbook_id`` for
|
|
146
|
-
playbooks, ``
|
|
157
|
+
user playbooks, ``agent_playbook_id`` for agent playbooks,
|
|
158
|
+
and ``profile_id`` for profiles.
|
|
147
159
|
tag (str): Injection-time rank tag (e.g. ``"r1-301"``,
|
|
148
160
|
``"p1-0f37"``). Per-injection, not stable across sessions;
|
|
149
161
|
kept as a debug aid.
|
|
150
162
|
title (str): Short human-readable label for logs and UI.
|
|
151
163
|
"""
|
|
152
164
|
|
|
153
|
-
kind:
|
|
165
|
+
kind: CitationKind
|
|
154
166
|
real_id: str
|
|
155
167
|
tag: str = ""
|
|
156
168
|
title: str = ""
|
|
157
169
|
|
|
158
170
|
|
|
171
|
+
# Canonical kinds accepted and persisted by retrieved-learning evaluation.
|
|
172
|
+
# Unlike ``Citation.kind`` there is no legacy ``"playbook"`` alias.
|
|
173
|
+
type RetrievedLearningKind = Literal["profile", "user_playbook", "agent_playbook"]
|
|
174
|
+
|
|
175
|
+
type LearningImpact = Literal["positive", "negative", "neutral"]
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class RetrievedLearning(BaseModel):
|
|
179
|
+
"""A learning the caller retrieved and injected into the agent context.
|
|
180
|
+
|
|
181
|
+
Deliberately minimal — just the identity pair. It does NOT reuse
|
|
182
|
+
``Citation``: citations carry injection-time debug fields (``tag``,
|
|
183
|
+
``title``) that callers should not need to supply (or see) when declaring
|
|
184
|
+
what was retrieved.
|
|
185
|
+
|
|
186
|
+
Attributes:
|
|
187
|
+
kind (RetrievedLearningKind): Which kind of learning this references.
|
|
188
|
+
learning_id (str): Stable storage id — ``profile_id`` for profiles,
|
|
189
|
+
``user_playbook_id`` for user playbooks, ``agent_playbook_id``
|
|
190
|
+
for agent playbooks (numeric ids as decimal strings).
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
kind: RetrievedLearningKind
|
|
194
|
+
learning_id: str = Field(min_length=1, max_length=1_000)
|
|
195
|
+
|
|
196
|
+
|
|
159
197
|
# information about the user interaction sent by the client
|
|
160
198
|
class Interaction(BaseModel):
|
|
161
199
|
interaction_id: int = 0 # 0 = placeholder for DB auto-increment
|
|
@@ -172,6 +210,10 @@ class Interaction(BaseModel):
|
|
|
172
210
|
expert_content: str = ""
|
|
173
211
|
tools_used: list[ToolUsed] = Field(default_factory=list)
|
|
174
212
|
citations: list[Citation] = Field(default_factory=list)
|
|
213
|
+
# Every learning retrieved and injected for this turn — including ones
|
|
214
|
+
# that did not end up influencing the response (contrast: ``citations``
|
|
215
|
+
# is the agent's claim of influence).
|
|
216
|
+
retrieved_learnings: list[RetrievedLearning] = Field(default_factory=list)
|
|
175
217
|
embedding: EmbeddingVector = []
|
|
176
218
|
|
|
177
219
|
@field_validator("interacted_image_url", mode="after")
|
|
@@ -398,17 +440,107 @@ class AgentSuccessEvaluationResult(BaseModel):
|
|
|
398
440
|
embedding: EmbeddingVector = []
|
|
399
441
|
|
|
400
442
|
|
|
443
|
+
class RetrievedLearningEvaluationResult(BaseModel):
|
|
444
|
+
"""Latest per-learning relevance/impact verdict for one evaluated session.
|
|
445
|
+
|
|
446
|
+
One row per ``(user_id, session_id, kind, learning_id)``. The table holds
|
|
447
|
+
the most recent successfully persisted evaluation set for a session, not
|
|
448
|
+
an append-only history.
|
|
449
|
+
|
|
450
|
+
Attributes:
|
|
451
|
+
result_id (int): DB auto-increment identifier (0 = placeholder).
|
|
452
|
+
user_id (str): Session owner.
|
|
453
|
+
session_id (str): Evaluated session.
|
|
454
|
+
agent_version (str): Version supplied to group evaluation;
|
|
455
|
+
informational, not part of the uniqueness key.
|
|
456
|
+
kind (RetrievedLearningKind): The learning kind.
|
|
457
|
+
learning_id (str): Stable storage id, matching
|
|
458
|
+
``RetrievedLearning.learning_id``.
|
|
459
|
+
is_relevant (bool | None): Whether the learning applies to the
|
|
460
|
+
session. ``None`` only when the relevance judge/chunk failed.
|
|
461
|
+
relevance_reason (str): Judge reasoning; empty when ``is_relevant``
|
|
462
|
+
is ``None``.
|
|
463
|
+
impact (LearningImpact | None): Whether the learning improved,
|
|
464
|
+
harmed, or did not materially change the response. ``None`` only
|
|
465
|
+
when the impact judge/chunk failed.
|
|
466
|
+
impact_reason (str): Judge reasoning; empty when ``impact`` is
|
|
467
|
+
``None``.
|
|
468
|
+
created_at (int): Earliest request timestamp in the evaluated
|
|
469
|
+
session.
|
|
470
|
+
"""
|
|
471
|
+
|
|
472
|
+
result_id: int = 0
|
|
473
|
+
user_id: str
|
|
474
|
+
session_id: str
|
|
475
|
+
agent_version: str = ""
|
|
476
|
+
kind: RetrievedLearningKind
|
|
477
|
+
learning_id: str
|
|
478
|
+
is_relevant: bool | None = None
|
|
479
|
+
relevance_reason: str = ""
|
|
480
|
+
impact: LearningImpact | None = None
|
|
481
|
+
impact_reason: str = ""
|
|
482
|
+
created_at: int = Field(default_factory=lambda: int(datetime.now(UTC).timestamp()))
|
|
483
|
+
|
|
484
|
+
|
|
401
485
|
class PlaybookRetrievalLogItem(BaseModel):
|
|
402
|
-
"""One retrieved
|
|
486
|
+
"""One retrieved playbook plus the serve-time attribution snapshot.
|
|
487
|
+
|
|
488
|
+
``agent_playbook_id`` remains as a nullable legacy compatibility field for
|
|
489
|
+
old agent-only rows. New rows should prefer ``target_kind`` + ``target_id``.
|
|
490
|
+
"""
|
|
403
491
|
|
|
404
492
|
retrieval_log_item_id: int = 0
|
|
405
493
|
retrieval_log_id: int = 0
|
|
406
494
|
ordinal: int
|
|
407
|
-
agent_playbook_id: int
|
|
495
|
+
agent_playbook_id: int | None = Field(default=None, gt=0)
|
|
496
|
+
target_kind: Literal["agent_playbook", "user_playbook"] | None = None
|
|
497
|
+
target_id: int | None = Field(default=None, gt=0)
|
|
498
|
+
target_title: str = ""
|
|
499
|
+
target_content: str = ""
|
|
500
|
+
target_trigger: str | None = None
|
|
408
501
|
source_user_playbook_ids: list[int] = Field(default_factory=list)
|
|
409
502
|
source_interaction_ids_by_user_playbook_id: dict[str, list[int]] = Field(
|
|
410
503
|
default_factory=dict
|
|
411
504
|
)
|
|
505
|
+
source_window_snapshot_mode: Literal["final_response", "live_lookup_compat"] = (
|
|
506
|
+
"live_lookup_compat"
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
@model_validator(mode="after")
|
|
510
|
+
def backfill_legacy_target_fields(self) -> Self:
|
|
511
|
+
if self.target_kind is None:
|
|
512
|
+
if self.agent_playbook_id is None:
|
|
513
|
+
raise ValueError(
|
|
514
|
+
"PlaybookRetrievalLogItem requires target_kind/target_id or"
|
|
515
|
+
" legacy agent_playbook_id"
|
|
516
|
+
)
|
|
517
|
+
self.target_kind = "agent_playbook"
|
|
518
|
+
self.target_id = self.agent_playbook_id
|
|
519
|
+
return self
|
|
520
|
+
|
|
521
|
+
if self.target_id is None:
|
|
522
|
+
if self.target_kind != "agent_playbook" or self.agent_playbook_id is None:
|
|
523
|
+
raise ValueError(
|
|
524
|
+
"PlaybookRetrievalLogItem.target_id is required for explicit"
|
|
525
|
+
" targets"
|
|
526
|
+
)
|
|
527
|
+
self.target_id = self.agent_playbook_id
|
|
528
|
+
|
|
529
|
+
if self.target_kind == "user_playbook":
|
|
530
|
+
if self.agent_playbook_id is not None:
|
|
531
|
+
raise ValueError(
|
|
532
|
+
"user_playbook retrieval-log items cannot carry agent_playbook_id"
|
|
533
|
+
)
|
|
534
|
+
return self
|
|
535
|
+
|
|
536
|
+
if self.agent_playbook_id is None:
|
|
537
|
+
self.agent_playbook_id = self.target_id
|
|
538
|
+
elif self.agent_playbook_id != self.target_id:
|
|
539
|
+
raise ValueError(
|
|
540
|
+
"agent_playbook retrieval-log item agent_playbook_id must match"
|
|
541
|
+
" target_id"
|
|
542
|
+
)
|
|
543
|
+
return self
|
|
412
544
|
|
|
413
545
|
|
|
414
546
|
class PlaybookRetrievalLog(BaseModel):
|
|
@@ -598,19 +730,19 @@ class BulkDeleteResponse(BaseModel):
|
|
|
598
730
|
|
|
599
731
|
|
|
600
732
|
class DeleteRequestsByIdsRequest(BaseModel):
|
|
601
|
-
request_ids: list[str] = Field(min_length=1)
|
|
733
|
+
request_ids: list[str] = Field(min_length=1, max_length=10_000)
|
|
602
734
|
|
|
603
735
|
|
|
604
736
|
class DeleteProfilesByIdsRequest(BaseModel):
|
|
605
|
-
profile_ids: list[str] = Field(min_length=1)
|
|
737
|
+
profile_ids: list[str] = Field(min_length=1, max_length=10_000)
|
|
606
738
|
|
|
607
739
|
|
|
608
740
|
class DeleteAgentPlaybooksByIdsRequest(BaseModel):
|
|
609
|
-
agent_playbook_ids: list[int] = Field(min_length=1)
|
|
741
|
+
agent_playbook_ids: list[int] = Field(min_length=1, max_length=10_000)
|
|
610
742
|
|
|
611
743
|
|
|
612
744
|
class DeleteUserPlaybooksByIdsRequest(BaseModel):
|
|
613
|
-
user_playbook_ids: list[int] = Field(min_length=1)
|
|
745
|
+
user_playbook_ids: list[int] = Field(min_length=1, max_length=10_000)
|
|
614
746
|
|
|
615
747
|
|
|
616
748
|
# Clear all data scoped to a single user_id (interactions, requests, user
|
|
@@ -631,16 +763,25 @@ class ClearUserDataResponse(BaseModel):
|
|
|
631
763
|
# user provided interaction data from the request
|
|
632
764
|
class InteractionData(BaseModel):
|
|
633
765
|
created_at: int = Field(default_factory=lambda: int(datetime.now(UTC).timestamp()))
|
|
634
|
-
role: str = "User"
|
|
635
|
-
content: str = ""
|
|
636
|
-
shadow_content: str = ""
|
|
637
|
-
expert_content: str = ""
|
|
766
|
+
role: str = Field(default="User", max_length=1_000)
|
|
767
|
+
content: str = Field(default="", max_length=1_000_000)
|
|
768
|
+
shadow_content: str = Field(default="", max_length=1_000_000)
|
|
769
|
+
expert_content: str = Field(default="", max_length=1_000_000)
|
|
638
770
|
user_action: UserActionType = UserActionType.NONE
|
|
639
|
-
user_action_description: str = ""
|
|
640
|
-
interacted_image_url: str = ""
|
|
641
|
-
image_encoding: str =
|
|
642
|
-
|
|
643
|
-
|
|
771
|
+
user_action_description: str = Field(default="", max_length=10_000)
|
|
772
|
+
interacted_image_url: str = Field(default="", max_length=2_048)
|
|
773
|
+
image_encoding: str = Field(
|
|
774
|
+
default="", max_length=15_000_000
|
|
775
|
+
) # base64 encoded image
|
|
776
|
+
tools_used: list[ToolUsed] = Field(default_factory=list, max_length=1_000)
|
|
777
|
+
citations: list[Citation] = Field(default_factory=list, max_length=1_000)
|
|
778
|
+
# Learnings (profiles / user playbooks / agent playbooks) the caller
|
|
779
|
+
# retrieved and injected into the agent context for this turn. Distinct
|
|
780
|
+
# from ``citations`` (agent-claimed influence): this is everything that
|
|
781
|
+
# was injected, whether or not it helped.
|
|
782
|
+
retrieved_learnings: list[RetrievedLearning] = Field(
|
|
783
|
+
default_factory=list, max_length=1_000
|
|
784
|
+
)
|
|
644
785
|
|
|
645
786
|
@field_validator("interacted_image_url", mode="after")
|
|
646
787
|
@classmethod
|
|
@@ -652,11 +793,10 @@ class InteractionData(BaseModel):
|
|
|
652
793
|
class PublishUserInteractionRequest(BaseModel):
|
|
653
794
|
request_id: NonEmptyStr | None = None
|
|
654
795
|
user_id: NonEmptyStr
|
|
655
|
-
interaction_data_list: list[InteractionData] = Field(min_length=1)
|
|
656
|
-
source: str = ""
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
)
|
|
796
|
+
interaction_data_list: list[InteractionData] = Field(min_length=1, max_length=1_000)
|
|
797
|
+
source: str = Field(default="", max_length=1_000)
|
|
798
|
+
# this is used for aggregating interactions for generating agent playbooks
|
|
799
|
+
agent_version: str = Field(default="", max_length=1_000)
|
|
660
800
|
session_id: NonEmptyStr # used for grouping requests together
|
|
661
801
|
skip_aggregation: bool = (
|
|
662
802
|
False # when True, extract profiles/playbooks but skip aggregation
|
|
@@ -673,6 +813,19 @@ class PublishUserInteractionRequest(BaseModel):
|
|
|
673
813
|
raise ValueError("evaluation_only publishes require session_id")
|
|
674
814
|
return self
|
|
675
815
|
|
|
816
|
+
@model_validator(mode="after")
|
|
817
|
+
def validate_retrieved_learnings_total(self) -> Self:
|
|
818
|
+
total = sum(
|
|
819
|
+
len(interaction.retrieved_learnings)
|
|
820
|
+
for interaction in self.interaction_data_list
|
|
821
|
+
)
|
|
822
|
+
if total > 1_000:
|
|
823
|
+
raise ValueError(
|
|
824
|
+
"a publish request may carry at most 1000 retrieved_learnings"
|
|
825
|
+
f" across all interactions (got {total})"
|
|
826
|
+
)
|
|
827
|
+
return self
|
|
828
|
+
|
|
676
829
|
|
|
677
830
|
# publish user interaction response
|
|
678
831
|
class PublishUserInteractionResponse(BaseModel):
|
|
@@ -689,6 +842,23 @@ class PublishUserInteractionResponse(BaseModel):
|
|
|
689
842
|
profiles_updated: int | None = None
|
|
690
843
|
playbooks_added: int | None = None
|
|
691
844
|
playbooks_updated: int | None = None
|
|
845
|
+
# Set to "deferred" when the server queued extraction asynchronously.
|
|
846
|
+
# None on the sync (wait_for_response=True) path. Poll GET
|
|
847
|
+
# /api/learning_status?request_id=... to track progress once the
|
|
848
|
+
# durable queue is active.
|
|
849
|
+
learning_status: str | None = None
|
|
850
|
+
|
|
851
|
+
|
|
852
|
+
class LearningStatusResponse(BaseModel):
|
|
853
|
+
"""Response for GET /api/learning_status.
|
|
854
|
+
|
|
855
|
+
Attributes:
|
|
856
|
+
status: One of ``pending | processing | done | failed``.
|
|
857
|
+
Coverage-based: reflects whether a durable learning job has
|
|
858
|
+
processed through the request's creation timestamp.
|
|
859
|
+
"""
|
|
860
|
+
|
|
861
|
+
status: Literal["pending", "processing", "done", "failed"]
|
|
692
862
|
|
|
693
863
|
|
|
694
864
|
# whoami response — caller identity + resolved storage routing (masked)
|
|
@@ -712,7 +882,7 @@ class MyConfigResponse(BaseModel):
|
|
|
712
882
|
|
|
713
883
|
# add user playbook request/response
|
|
714
884
|
class AddUserPlaybookRequest(BaseModel):
|
|
715
|
-
user_playbooks: list[UserPlaybook] = Field(min_length=1)
|
|
885
|
+
user_playbooks: list[UserPlaybook] = Field(min_length=1, max_length=1_000)
|
|
716
886
|
|
|
717
887
|
@model_validator(mode="after")
|
|
718
888
|
def check_content_fields(self) -> Self:
|