claude-smart 0.2.46 → 0.2.47
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 +19 -11
- package/bin/claude-smart.js +290 -68
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/README.md +11 -10
- package/plugin/dashboard/app/layout.tsx +20 -0
- package/plugin/opencode/dist/server.mjs +76 -2
- package/plugin/opencode/server.mts +79 -2
- package/plugin/pyproject.toml +6 -2
- package/plugin/scripts/smart-install.sh +7 -1
- package/plugin/src/claude_smart/cli.py +210 -22
- package/plugin/src/claude_smart/context_format.py +9 -9
- package/plugin/src/claude_smart/cs_cite.py +66 -19
- package/plugin/uv.lock +5 -5
- package/plugin/vendor/reflexio/README.md +3 -3
- package/plugin/vendor/reflexio/pyproject.toml +1 -1
- package/plugin/vendor/reflexio/reflexio/README.md +3 -1
- package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +1 -1
- package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +2 -2
- package/plugin/vendor/reflexio/reflexio/cli/utils.py +44 -1
- package/plugin/vendor/reflexio/reflexio/client/client.py +97 -0
- package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +8 -0
- package/plugin/vendor/reflexio/reflexio/lib/_base.py +15 -0
- package/plugin/vendor/reflexio/reflexio/lib/_generation.py +9 -8
- package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +27 -16
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +23 -5
- package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +9 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/governance.py +117 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +45 -3
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +16 -0
- package/plugin/vendor/reflexio/reflexio/server/README.md +14 -2
- package/plugin/vendor/reflexio/reflexio/server/api.py +176 -29
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/{_auth.py → auth.py} +2 -0
- package/plugin/vendor/reflexio/reflexio/server/extensions.py +213 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +4 -4
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +12 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +14 -2
- package/plugin/vendor/reflexio/reflexio/server/services/README.md +3 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +8 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/config.py +52 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/service.py +378 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/subject_refs.py +34 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +45 -19
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +9 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/aggregation_prompt_processing.py +100 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator.py +129 -111
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/service.py +9 -9
- package/plugin/vendor/reflexio/reflexio/server/services/profile/components/extractor.py +3 -2
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/recency.py +211 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +29 -13
- package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +4 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/governance_validation.py +681 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +14 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +49 -19
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_governance.py +1965 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +5 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1 -2133
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +262 -107
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +73 -33
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_agent.py +952 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_eval_results.py +189 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_optimization.py +247 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_source_linkage.py +145 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_user.py +838 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +19 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +4 -4
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_governance.py +148 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +0 -909
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_agent.py +365 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_eval_results.py +124 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_optimization.py +85 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_source_linkage.py +47 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_user.py +333 -0
- package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +153 -12
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/user_detail_stripping.py +0 -84
|
@@ -269,7 +269,7 @@ def _compact_citation_instruction(marker_parts: list[str] | None = None) -> str:
|
|
|
269
269
|
gate = cs_cite.WHEN_TO_CITE_COMPACT
|
|
270
270
|
link_style = os.environ.get(_CITATION_LINK_STYLE_ENV, "markdown")
|
|
271
271
|
if link_style == "osc8" and marker_parts:
|
|
272
|
-
marker =
|
|
272
|
+
marker = cs_cite.build_marker(" | ".join(marker_parts), "osc8")
|
|
273
273
|
separator_instruction = (
|
|
274
274
|
" Separate multiple linked memories with the visible ` | ` separator."
|
|
275
275
|
if len(marker_parts) > 1
|
|
@@ -281,12 +281,13 @@ def _compact_citation_instruction(marker_parts: list[str] | None = None) -> str:
|
|
|
281
281
|
)
|
|
282
282
|
if link_style == "osc8":
|
|
283
283
|
return _remoteize_citation_instruction(
|
|
284
|
-
f"{gate} If you do, end with
|
|
285
|
-
"followed by the same linked memory text
|
|
286
|
-
"
|
|
284
|
+
f"{gate} If you do, end with `{cs_cite.MARKER_PREFIX}` "
|
|
285
|
+
"followed by the same linked memory text, then "
|
|
286
|
+
f"`{cs_cite.marker_attribution('osc8')}` linking to the reflexio "
|
|
287
|
+
"repo; keep the links, but do not show the URL."
|
|
287
288
|
)
|
|
288
289
|
if marker_parts:
|
|
289
|
-
marker =
|
|
290
|
+
marker = cs_cite.build_marker(" | ".join(marker_parts), "markdown")
|
|
290
291
|
separator_instruction = (
|
|
291
292
|
" Separate multiple linked memories with the visible ` | ` separator."
|
|
292
293
|
if len(marker_parts) > 1
|
|
@@ -297,9 +298,8 @@ def _compact_citation_instruction(marker_parts: list[str] | None = None) -> str:
|
|
|
297
298
|
f"links: `{marker}`.{separator_instruction}"
|
|
298
299
|
)
|
|
299
300
|
return _remoteize_citation_instruction(
|
|
300
|
-
f"{gate} If you do, end with one final marker like
|
|
301
|
-
"
|
|
302
|
-
"s1-123)` using the shown rule URL."
|
|
301
|
+
f"{gate} If you do, end with one final marker like "
|
|
302
|
+
f"`{cs_cite.MARKDOWN_EXAMPLE_ONE}` using the shown rule URL."
|
|
303
303
|
)
|
|
304
304
|
|
|
305
305
|
|
|
@@ -337,7 +337,7 @@ def _exact_osc8_marker_instruction(entries: list[dict[str, Any]]) -> str:
|
|
|
337
337
|
if not marker_parts:
|
|
338
338
|
return ""
|
|
339
339
|
|
|
340
|
-
marker =
|
|
340
|
+
marker = cs_cite.build_marker(" | ".join(marker_parts), "osc8")
|
|
341
341
|
return (
|
|
342
342
|
"If any listed memory above was used, copy this exact final marker, "
|
|
343
343
|
f"preserving its hidden OSC 8 terminal links: `{marker}`. "
|
|
@@ -85,36 +85,83 @@ WHEN_TO_CITE_COMPACT = (
|
|
|
85
85
|
|
|
86
86
|
_COMPACT_INTRO = f"_{WHEN_TO_CITE}"
|
|
87
87
|
|
|
88
|
+
# Public repo the citation marker attributes its learnings to. The cue rides
|
|
89
|
+
# along on every emitted marker so users see that the applied learning was
|
|
90
|
+
# generated by Reflexio (and can star the repo).
|
|
91
|
+
REFLEXIO_REPO_URL = "https://github.com/ReflexioAI/reflexio"
|
|
92
|
+
MARKER_PREFIX = "✨ claude-smart rule applied:"
|
|
93
|
+
_ATTRIBUTION_LABEL = "⚡Reflexio"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _osc8_link(url: str, text: str) -> str:
|
|
97
|
+
"""Wrap ``text`` in an OSC 8 terminal hyperlink pointing at ``url``."""
|
|
98
|
+
return f"\x1b]8;;{url}\x1b\\{text}\x1b]8;;\x1b\\"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def marker_attribution(link_style: str = "markdown") -> str:
|
|
102
|
+
"""Return the trailing ``· ⚡Reflexio`` attribution, linked to the repo.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
link_style (str): ``"markdown"`` for a markdown link, or ``"osc8"`` for
|
|
106
|
+
a terminal-native hyperlink. Unknown values fall back to markdown.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
str: The attribution segment, beginning with a leading separator.
|
|
110
|
+
"""
|
|
111
|
+
if link_style == "osc8":
|
|
112
|
+
return f" · {_osc8_link(REFLEXIO_REPO_URL, _ATTRIBUTION_LABEL)}"
|
|
113
|
+
return f" · [{_ATTRIBUTION_LABEL}]({REFLEXIO_REPO_URL})"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def build_marker(body: str, link_style: str = "markdown") -> str:
|
|
117
|
+
"""Build the full citation marker line, including the Reflexio attribution.
|
|
118
|
+
|
|
119
|
+
Single source of truth for the marker line so the prefix and attribution
|
|
120
|
+
cannot drift across the markdown / OSC 8 / compact render paths.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
body (str): The linked memory title(s) — already formatted as markdown
|
|
124
|
+
or OSC 8 links, joined with `` | `` for multiple items.
|
|
125
|
+
link_style (str): ``"markdown"`` or ``"osc8"``; selects the attribution
|
|
126
|
+
link form.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
str: ``✨ claude-smart rule applied: <body> · ⚡Reflexio``.
|
|
130
|
+
"""
|
|
131
|
+
return f"{MARKER_PREFIX} {body}{marker_attribution(link_style)}"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
MARKDOWN_EXAMPLE_ONE = build_marker(
|
|
135
|
+
"[verify process state](http://localhost:3001/rules/s1-123)", "markdown"
|
|
136
|
+
)
|
|
137
|
+
_MARKDOWN_EXAMPLE_MULTI = build_marker(
|
|
138
|
+
"[git safety](http://localhost:3001/rules/s1-123) | "
|
|
139
|
+
"[brief answer preference](http://localhost:3001/rules/p1-pref)",
|
|
140
|
+
"markdown",
|
|
141
|
+
)
|
|
88
142
|
_MARKDOWN_MARKER_PARAGRAPH = (
|
|
89
143
|
"How to format: use human-readable linked titles, not raw ids. "
|
|
90
144
|
"Format for one item: "
|
|
91
|
-
"
|
|
92
|
-
"[verify process state](http://localhost:3001/rules/s1-123)`. "
|
|
145
|
+
f"`{MARKDOWN_EXAMPLE_ONE}`. "
|
|
93
146
|
"For multiple items: "
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
147
|
+
f"`{_MARKDOWN_EXAMPLE_MULTI}`. "
|
|
148
|
+
"Always end the marker with the ` · ⚡Reflexio` attribution shown — a link "
|
|
149
|
+
"to the reflexio repo — exactly as given. "
|
|
97
150
|
"Separate multiple linked memories with the visible ` | ` separator. "
|
|
98
151
|
"Use the dashboard URL shown beside each cited item; do not invent URLs. "
|
|
99
152
|
"Do not include `[cs:…]` ids in the marker line. Never use the old "
|
|
100
153
|
"`✨ 1 claude-smart learning applied [cs:...]` marker format._"
|
|
101
154
|
)
|
|
102
155
|
|
|
103
|
-
_OSC8_EXAMPLE_ONE = (
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"verify process state"
|
|
107
|
-
"\x1b]8;;\x1b\\"
|
|
156
|
+
_OSC8_EXAMPLE_ONE = build_marker(
|
|
157
|
+
_osc8_link("http://localhost:3001/rules/s1-123", "verify process state"),
|
|
158
|
+
"osc8",
|
|
108
159
|
)
|
|
109
|
-
_OSC8_EXAMPLE_MULTI = (
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
" | "
|
|
115
|
-
"\x1b]8;;http://localhost:3001/rules/p1-pref\x1b\\"
|
|
116
|
-
"brief answer preference"
|
|
117
|
-
"\x1b]8;;\x1b\\"
|
|
160
|
+
_OSC8_EXAMPLE_MULTI = build_marker(
|
|
161
|
+
_osc8_link("http://localhost:3001/rules/s1-123", "git safety")
|
|
162
|
+
+ " | "
|
|
163
|
+
+ _osc8_link("http://localhost:3001/rules/p1-pref", "brief answer preference"),
|
|
164
|
+
"osc8",
|
|
118
165
|
)
|
|
119
166
|
_OSC8_MARKER_PARAGRAPH = (
|
|
120
167
|
"How to format: use human-readable OSC 8 terminal hyperlinks, not raw ids "
|
package/plugin/uv.lock
CHANGED
|
@@ -476,7 +476,7 @@ wheels = [
|
|
|
476
476
|
|
|
477
477
|
[[package]]
|
|
478
478
|
name = "claude-smart"
|
|
479
|
-
version = "0.2.
|
|
479
|
+
version = "0.2.47"
|
|
480
480
|
source = { editable = "." }
|
|
481
481
|
dependencies = [
|
|
482
482
|
{ name = "chromadb" },
|
|
@@ -494,7 +494,7 @@ dev = [
|
|
|
494
494
|
requires-dist = [
|
|
495
495
|
{ name = "chromadb", specifier = ">=0.5" },
|
|
496
496
|
{ name = "einops", specifier = ">=0.8.0" },
|
|
497
|
-
{ name = "reflexio-ai", specifier = ">=0.2.
|
|
497
|
+
{ name = "reflexio-ai", specifier = ">=0.2.27" },
|
|
498
498
|
{ name = "sqlite-vec", specifier = ">=0.1.6" },
|
|
499
499
|
]
|
|
500
500
|
|
|
@@ -2760,7 +2760,7 @@ wheels = [
|
|
|
2760
2760
|
|
|
2761
2761
|
[[package]]
|
|
2762
2762
|
name = "reflexio-ai"
|
|
2763
|
-
version = "0.2.
|
|
2763
|
+
version = "0.2.27"
|
|
2764
2764
|
source = { registry = "https://pypi.org/simple" }
|
|
2765
2765
|
dependencies = [
|
|
2766
2766
|
{ name = "aiohttp" },
|
|
@@ -2800,9 +2800,9 @@ dependencies = [
|
|
|
2800
2800
|
{ name = "websocket-client" },
|
|
2801
2801
|
{ name = "xlsxwriter" },
|
|
2802
2802
|
]
|
|
2803
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
2803
|
+
sdist = { url = "https://files.pythonhosted.org/packages/85/22/64429eb84ae74aaa6d36f0a2e0d91a27b35ee33ef17c18411d54f08706ba/reflexio_ai-0.2.27.tar.gz", hash = "sha256:e433209ca848245e957943c6476f2bba32581de8804d535d25ca0596b0da0afd", size = 1112139, upload-time = "2026-06-30T06:26:21.88Z" }
|
|
2804
2804
|
wheels = [
|
|
2805
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
2805
|
+
{ url = "https://files.pythonhosted.org/packages/68/22/d65332c75b9072e8838d51f68354d8d17c7636aa1cf73a20cfc1147b4364/reflexio_ai-0.2.27-py3-none-any.whl", hash = "sha256:4598f4aaa61e3c755a04573ab9711a7b5673ebf268029b2cef21cdcd5d4abfcf", size = 1461400, upload-time = "2026-06-30T06:26:19.965Z" },
|
|
2806
2806
|
]
|
|
2807
2807
|
|
|
2808
2808
|
[[package]]
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
[](https://www.python.org/)
|
|
9
9
|
[](LICENSE)
|
|
10
|
-
[](https://pypi.org/project/reflexio-ai/)
|
|
11
11
|
[](https://pepy.tech/project/reflexio-ai)
|
|
12
12
|
[](reflexio/benchmarks/retrieval_latency/results/report.md)
|
|
13
13
|
[](https://github.com/ReflexioAI/reflexio/stargazers)
|
|
@@ -244,10 +244,10 @@ Reflexio will automatically generate profiles and extract playbooks in the backg
|
|
|
244
244
|
|
|
245
245
|
For detailed API documentation, see the [full API reference](https://www.reflexio.ai/docs/api-reference).
|
|
246
246
|
|
|
247
|
-
Install the
|
|
247
|
+
Install the package:
|
|
248
248
|
|
|
249
249
|
```shell
|
|
250
|
-
pip install reflexio-
|
|
250
|
+
pip install reflexio-ai
|
|
251
251
|
```
|
|
252
252
|
|
|
253
253
|
### Basic usage
|
|
@@ -102,6 +102,7 @@ Description: FastAPI backend server that processes user interactions to generate
|
|
|
102
102
|
|
|
103
103
|
### Main Entry Points
|
|
104
104
|
- **API**: `api.py` - FastAPI routes
|
|
105
|
+
- **Extension Registry**: `extensions.py` - optional capability/service registration for OSS and enterprise integrations
|
|
105
106
|
- **Endpoint Helpers**: `api_endpoints/` - Request handlers calling `Reflexio` (reflexio_lib)
|
|
106
107
|
- **Core Service**: `services/generation_service.py` - Main orchestrator
|
|
107
108
|
|
|
@@ -141,7 +142,8 @@ client (Python SDK)
|
|
|
141
142
|
- `playbook_optimizer/` - Scenario-based playbook optimization experiments
|
|
142
143
|
- `braintrust/` - Braintrust eval export/sync support
|
|
143
144
|
- `lineage/` - Resolve current records and schedule tombstone garbage collection for superseded profile/playbook rows
|
|
144
|
-
- `
|
|
145
|
+
- `governance/` - Subject-reference contracts and retention/barrier helpers used by storage and lineage
|
|
146
|
+
- `storage/` - Abstract layer (SQLite prod, LocalJSON test) with governance-aware write validation
|
|
145
147
|
- `pre_retrieval/` - Query rewriting and document expansion helpers
|
|
146
148
|
- `configurator/` - YAML config loader
|
|
147
149
|
- **`site_var/`**: Global settings singleton
|
|
@@ -24,7 +24,7 @@ _DEFAULT_STORAGE = "sqlite"
|
|
|
24
24
|
def default_org_id() -> str:
|
|
25
25
|
"""Resolve the default org id, honoring ``REFLEXIO_DEFAULT_ORG_ID``.
|
|
26
26
|
|
|
27
|
-
Mirrors :func:`reflexio.server.
|
|
27
|
+
Mirrors :func:`reflexio.server.auth.default_get_org_id` so the local CLI
|
|
28
28
|
helpers (``setup``, ``config show`` / ``config local``) resolve the same
|
|
29
29
|
``config_<org>.json`` the running no-auth server reads. Uses ``os.environ``
|
|
30
30
|
directly (not ``env_utils``) to keep this module's import lightweight — see
|
|
@@ -33,7 +33,7 @@ _PROVIDERS: dict[str, dict[str, str]] = {
|
|
|
33
33
|
},
|
|
34
34
|
"anthropic": {
|
|
35
35
|
"env_var": "ANTHROPIC_API_KEY",
|
|
36
|
-
"model": "claude-sonnet-
|
|
36
|
+
"model": "claude-sonnet-5",
|
|
37
37
|
"display": "Anthropic",
|
|
38
38
|
},
|
|
39
39
|
"gemini": {
|
|
@@ -53,7 +53,7 @@ _PROVIDERS: dict[str, dict[str, str]] = {
|
|
|
53
53
|
},
|
|
54
54
|
"minimax": {
|
|
55
55
|
"env_var": "MINIMAX_API_KEY",
|
|
56
|
-
"model": "MiniMax-
|
|
56
|
+
"model": "MiniMax-M3",
|
|
57
57
|
"display": "MiniMax",
|
|
58
58
|
},
|
|
59
59
|
"dashscope": {
|
|
@@ -44,7 +44,7 @@ def find_pids_on_port(port: int) -> list[int]:
|
|
|
44
44
|
"""Find process IDs listening on the given port using lsof."""
|
|
45
45
|
try:
|
|
46
46
|
result = subprocess.run(
|
|
47
|
-
["lsof", "-t", f"-
|
|
47
|
+
["lsof", "-nP", "-t", f"-iTCP:{port}", "-sTCP:LISTEN"],
|
|
48
48
|
capture_output=True,
|
|
49
49
|
text=True,
|
|
50
50
|
check=False,
|
|
@@ -76,6 +76,47 @@ def find_pids_by_pattern(pattern: str) -> list[int]:
|
|
|
76
76
|
return []
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
def get_requested_port_conflicts(ports: dict[str, int]) -> list[str]:
|
|
80
|
+
"""Return startup-blocking conflicts for requested service ports."""
|
|
81
|
+
conflicts: list[str] = []
|
|
82
|
+
services_by_port: dict[int, list[str]] = {}
|
|
83
|
+
for name, port in ports.items():
|
|
84
|
+
services_by_port.setdefault(port, []).append(name)
|
|
85
|
+
|
|
86
|
+
for port, names in sorted(services_by_port.items()):
|
|
87
|
+
if len(names) > 1:
|
|
88
|
+
conflicts.append(
|
|
89
|
+
f"port {port} is assigned to multiple services: {', '.join(sorted(names))}"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
for name, port in sorted(ports.items()):
|
|
93
|
+
pids = find_pids_on_port(port)
|
|
94
|
+
if pids:
|
|
95
|
+
pid_list = ", ".join(str(pid) for pid in sorted(set(pids)))
|
|
96
|
+
conflicts.append(
|
|
97
|
+
f"{name} port {port} is already in use by PID(s): {pid_list}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return conflicts
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def ensure_requested_ports_available(ports: dict[str, int]) -> None:
|
|
104
|
+
"""Exit with a clear message when requested service ports are unavailable."""
|
|
105
|
+
conflicts = get_requested_port_conflicts(ports)
|
|
106
|
+
if not conflicts:
|
|
107
|
+
return
|
|
108
|
+
|
|
109
|
+
sys.stdout.write("Error: cannot start Reflexio services because ports conflict.\n")
|
|
110
|
+
for conflict in conflicts:
|
|
111
|
+
sys.stdout.write(f" - {conflict}\n")
|
|
112
|
+
sys.stdout.write(
|
|
113
|
+
"Stop the existing service with `uv run reflexio services stop` or choose "
|
|
114
|
+
"different BACKEND_PORT/FRONTEND_PORT/DOCS_PORT values.\n"
|
|
115
|
+
)
|
|
116
|
+
sys.stdout.flush()
|
|
117
|
+
sys.exit(1)
|
|
118
|
+
|
|
119
|
+
|
|
79
120
|
def kill_processes(
|
|
80
121
|
pids: list[int], graceful_timeout: float = 2.0, force: bool = False
|
|
81
122
|
) -> None:
|
|
@@ -233,6 +274,8 @@ def run_services(
|
|
|
233
274
|
signal.signal(signal.SIGINT, shutdown)
|
|
234
275
|
signal.signal(signal.SIGTERM, shutdown)
|
|
235
276
|
|
|
277
|
+
ensure_requested_ports_available(ports)
|
|
278
|
+
|
|
236
279
|
for svc in services:
|
|
237
280
|
noise_env = _NOISE_SUPPRESSION_ENV.get(svc.name, {})
|
|
238
281
|
merged_env = {**os.environ, **(svc.env or {}), **noise_env}
|
|
@@ -124,6 +124,7 @@ from .cache import InMemoryCache
|
|
|
124
124
|
class _ClientConfigPayload(Config):
|
|
125
125
|
model_config = ConfigDict(extra="allow")
|
|
126
126
|
|
|
127
|
+
|
|
127
128
|
T = TypeVar("T")
|
|
128
129
|
|
|
129
130
|
logger = logging.getLogger(__name__)
|
|
@@ -1153,9 +1154,13 @@ class ReflexioClient:
|
|
|
1153
1154
|
force_refresh: bool = False,
|
|
1154
1155
|
*,
|
|
1155
1156
|
user_id: str | None = None,
|
|
1157
|
+
profile_id: str | None = None,
|
|
1158
|
+
query: str | None = None,
|
|
1156
1159
|
start_time: datetime | None = None,
|
|
1157
1160
|
end_time: datetime | None = None,
|
|
1158
1161
|
top_k: int | None = None,
|
|
1162
|
+
source: str | None = None,
|
|
1163
|
+
profile_time_to_live: str | None = None,
|
|
1159
1164
|
status_filter: list[Status | str | None] | None = None,
|
|
1160
1165
|
tags: list[str] | None = None,
|
|
1161
1166
|
) -> GetProfilesViewResponse:
|
|
@@ -1165,9 +1170,13 @@ class ReflexioClient:
|
|
|
1165
1170
|
request (Optional[GetUserProfilesRequest]): The list request object (alternative to kwargs)
|
|
1166
1171
|
force_refresh (bool, optional): If True, bypass cache and fetch fresh data. Defaults to False.
|
|
1167
1172
|
user_id (str): The user ID to get profiles for
|
|
1173
|
+
profile_id (Optional[str]): Exact profile ID filter.
|
|
1174
|
+
query (Optional[str]): Case-insensitive text filter across visible fields.
|
|
1168
1175
|
start_time (Optional[datetime]): Filter by start time
|
|
1169
1176
|
end_time (Optional[datetime]): Filter by end time
|
|
1170
1177
|
top_k (Optional[int]): Maximum number of results to return (default: 30)
|
|
1178
|
+
source (Optional[str]): Filter by profile source.
|
|
1179
|
+
profile_time_to_live (Optional[str]): Filter by profile TTL value.
|
|
1171
1180
|
status_filter (Optional[list[Optional[Union[Status, str]]]]): Filter by profile status. Accepts Status enum or string values (e.g., "archived", "pending").
|
|
1172
1181
|
tags (Optional[list[str]]): Match profiles having any of these tags.
|
|
1173
1182
|
|
|
@@ -1190,9 +1199,13 @@ class ReflexioClient:
|
|
|
1190
1199
|
request,
|
|
1191
1200
|
GetUserProfilesRequest,
|
|
1192
1201
|
user_id=user_id,
|
|
1202
|
+
profile_id=profile_id,
|
|
1203
|
+
query=query,
|
|
1193
1204
|
start_time=start_time,
|
|
1194
1205
|
end_time=end_time,
|
|
1195
1206
|
top_k=top_k,
|
|
1207
|
+
source=source,
|
|
1208
|
+
profile_time_to_live=profile_time_to_live,
|
|
1196
1209
|
status_filter=converted_status_filter,
|
|
1197
1210
|
tags=tags,
|
|
1198
1211
|
)
|
|
@@ -1202,9 +1215,13 @@ class ReflexioClient:
|
|
|
1202
1215
|
cached_result = self._cache.get(
|
|
1203
1216
|
"get_profiles",
|
|
1204
1217
|
user_id=req.user_id,
|
|
1218
|
+
profile_id=req.profile_id,
|
|
1219
|
+
query=req.query,
|
|
1205
1220
|
start_time=req.start_time,
|
|
1206
1221
|
end_time=req.end_time,
|
|
1207
1222
|
top_k=req.top_k,
|
|
1223
|
+
source=req.source,
|
|
1224
|
+
profile_time_to_live=req.profile_time_to_live,
|
|
1208
1225
|
status_filter=req.status_filter,
|
|
1209
1226
|
tags=req.tags,
|
|
1210
1227
|
)
|
|
@@ -1224,9 +1241,13 @@ class ReflexioClient:
|
|
|
1224
1241
|
"get_profiles",
|
|
1225
1242
|
result,
|
|
1226
1243
|
user_id=req.user_id,
|
|
1244
|
+
profile_id=req.profile_id,
|
|
1245
|
+
query=req.query,
|
|
1227
1246
|
start_time=req.start_time,
|
|
1228
1247
|
end_time=req.end_time,
|
|
1229
1248
|
top_k=req.top_k,
|
|
1249
|
+
source=req.source,
|
|
1250
|
+
profile_time_to_live=req.profile_time_to_live,
|
|
1230
1251
|
status_filter=req.status_filter,
|
|
1231
1252
|
tags=req.tags,
|
|
1232
1253
|
)
|
|
@@ -1255,6 +1276,13 @@ class ReflexioClient:
|
|
|
1255
1276
|
self,
|
|
1256
1277
|
limit: int = 100,
|
|
1257
1278
|
status_filter: str | None = None,
|
|
1279
|
+
user_id: str | None = None,
|
|
1280
|
+
profile_id: str | None = None,
|
|
1281
|
+
query: str | None = None,
|
|
1282
|
+
source: str | None = None,
|
|
1283
|
+
profile_time_to_live: str | None = None,
|
|
1284
|
+
start_time: int | None = None,
|
|
1285
|
+
end_time: int | None = None,
|
|
1258
1286
|
) -> GetProfilesViewResponse:
|
|
1259
1287
|
"""Get all user profiles across all users.
|
|
1260
1288
|
|
|
@@ -1263,6 +1291,13 @@ class ReflexioClient:
|
|
|
1263
1291
|
status_filter (str, optional): Filter by profile status. Accepts
|
|
1264
1292
|
``"current"``, ``"pending"``, or ``"archived"``. If ``None``
|
|
1265
1293
|
(the default), profiles with any status are returned.
|
|
1294
|
+
user_id (str, optional): Filter by exact user ID.
|
|
1295
|
+
profile_id (str, optional): Filter by exact profile ID.
|
|
1296
|
+
query (str, optional): Case-insensitive text filter across visible fields.
|
|
1297
|
+
source (str, optional): Filter by exact profile source.
|
|
1298
|
+
profile_time_to_live (str, optional): Filter by profile TTL value.
|
|
1299
|
+
start_time (int, optional): Minimum last-modified epoch seconds.
|
|
1300
|
+
end_time (int, optional): Maximum last-modified epoch seconds.
|
|
1266
1301
|
|
|
1267
1302
|
Returns:
|
|
1268
1303
|
GetProfilesViewResponse: Response containing all user profiles
|
|
@@ -1272,6 +1307,21 @@ class ReflexioClient:
|
|
|
1272
1307
|
params: dict[str, str | int] = {"limit": limit}
|
|
1273
1308
|
if status_filter:
|
|
1274
1309
|
params["status_filter"] = status_filter
|
|
1310
|
+
params.update(
|
|
1311
|
+
{
|
|
1312
|
+
key: value
|
|
1313
|
+
for key, value in {
|
|
1314
|
+
"user_id": user_id,
|
|
1315
|
+
"profile_id": profile_id,
|
|
1316
|
+
"query": query,
|
|
1317
|
+
"source": source,
|
|
1318
|
+
"profile_time_to_live": profile_time_to_live,
|
|
1319
|
+
"start_time": start_time,
|
|
1320
|
+
"end_time": end_time,
|
|
1321
|
+
}.items()
|
|
1322
|
+
if value is not None
|
|
1323
|
+
}
|
|
1324
|
+
)
|
|
1275
1325
|
response = self._make_request(
|
|
1276
1326
|
"GET",
|
|
1277
1327
|
f"/api/get_all_profiles?{urlencode(params)}",
|
|
@@ -1374,9 +1424,14 @@ class ReflexioClient:
|
|
|
1374
1424
|
request: GetUserPlaybooksRequest | dict | None = None,
|
|
1375
1425
|
*,
|
|
1376
1426
|
limit: int | None = None,
|
|
1427
|
+
user_playbook_id: int | None = None,
|
|
1377
1428
|
user_id: str | None = None,
|
|
1429
|
+
request_id: str | None = None,
|
|
1430
|
+
query: str | None = None,
|
|
1378
1431
|
playbook_name: str | None = None,
|
|
1379
1432
|
agent_version: str | None = None,
|
|
1433
|
+
start_time: datetime | None = None,
|
|
1434
|
+
end_time: datetime | None = None,
|
|
1380
1435
|
status_filter: list[Status | None] | None = None,
|
|
1381
1436
|
tags: list[str] | None = None,
|
|
1382
1437
|
) -> GetUserPlaybooksViewResponse:
|
|
@@ -1385,9 +1440,14 @@ class ReflexioClient:
|
|
|
1385
1440
|
Args:
|
|
1386
1441
|
request (Optional[GetUserPlaybooksRequest]): The get request object (alternative to kwargs)
|
|
1387
1442
|
limit (Optional[int]): Maximum number of results to return (default: 100)
|
|
1443
|
+
user_playbook_id (Optional[int]): Exact user playbook ID filter.
|
|
1388
1444
|
user_id (Optional[str]): Filter by user ID
|
|
1445
|
+
request_id (Optional[str]): Filter by generating request ID.
|
|
1446
|
+
query (Optional[str]): Case-insensitive text filter across visible fields.
|
|
1389
1447
|
playbook_name (Optional[str]): Filter by playbook name
|
|
1390
1448
|
agent_version (Optional[str]): Filter by agent version
|
|
1449
|
+
start_time (Optional[datetime]): Filter by start time.
|
|
1450
|
+
end_time (Optional[datetime]): Filter by end time.
|
|
1391
1451
|
status_filter (Optional[list[Optional[Status]]]): Filter by status
|
|
1392
1452
|
tags (Optional[list[str]]): Match playbooks having any of these tags.
|
|
1393
1453
|
|
|
@@ -1398,9 +1458,14 @@ class ReflexioClient:
|
|
|
1398
1458
|
request,
|
|
1399
1459
|
GetUserPlaybooksRequest,
|
|
1400
1460
|
limit=limit,
|
|
1461
|
+
user_playbook_id=user_playbook_id,
|
|
1401
1462
|
user_id=user_id,
|
|
1463
|
+
request_id=request_id,
|
|
1464
|
+
query=query,
|
|
1402
1465
|
playbook_name=playbook_name,
|
|
1403
1466
|
agent_version=agent_version,
|
|
1467
|
+
start_time=start_time,
|
|
1468
|
+
end_time=end_time,
|
|
1404
1469
|
status_filter=status_filter,
|
|
1405
1470
|
tags=tags,
|
|
1406
1471
|
)
|
|
@@ -1652,8 +1717,12 @@ class ReflexioClient:
|
|
|
1652
1717
|
force_refresh: bool = False,
|
|
1653
1718
|
*,
|
|
1654
1719
|
limit: int | None = None,
|
|
1720
|
+
agent_playbook_id: int | None = None,
|
|
1721
|
+
query: str | None = None,
|
|
1655
1722
|
playbook_name: str | None = None,
|
|
1656
1723
|
agent_version: str | None = None,
|
|
1724
|
+
start_time: datetime | None = None,
|
|
1725
|
+
end_time: datetime | None = None,
|
|
1657
1726
|
status_filter: list[Status | None] | None = None,
|
|
1658
1727
|
playbook_status_filter: PlaybookStatus | None = None,
|
|
1659
1728
|
tags: list[str] | None = None,
|
|
@@ -1664,8 +1733,12 @@ class ReflexioClient:
|
|
|
1664
1733
|
request (Optional[GetAgentPlaybooksRequest]): The get request object (alternative to kwargs)
|
|
1665
1734
|
force_refresh (bool, optional): If True, bypass cache and fetch fresh data. Defaults to False.
|
|
1666
1735
|
limit (Optional[int]): Maximum number of results to return (default: 100)
|
|
1736
|
+
agent_playbook_id (Optional[int]): Exact agent playbook ID filter.
|
|
1737
|
+
query (Optional[str]): Case-insensitive text filter across visible fields.
|
|
1667
1738
|
playbook_name (Optional[str]): Filter by playbook name
|
|
1668
1739
|
agent_version (Optional[str]): Filter by agent version
|
|
1740
|
+
start_time (Optional[datetime]): Filter by start time.
|
|
1741
|
+
end_time (Optional[datetime]): Filter by end time.
|
|
1669
1742
|
status_filter (Optional[list[Optional[Status]]]): Filter by status
|
|
1670
1743
|
playbook_status_filter (Optional[PlaybookStatus]): Filter by playbook status (default: APPROVED)
|
|
1671
1744
|
tags (Optional[list[str]]): Match playbooks having any of these tags.
|
|
@@ -1677,8 +1750,12 @@ class ReflexioClient:
|
|
|
1677
1750
|
request,
|
|
1678
1751
|
GetAgentPlaybooksRequest,
|
|
1679
1752
|
limit=limit,
|
|
1753
|
+
agent_playbook_id=agent_playbook_id,
|
|
1754
|
+
query=query,
|
|
1680
1755
|
playbook_name=playbook_name,
|
|
1681
1756
|
agent_version=agent_version,
|
|
1757
|
+
start_time=start_time,
|
|
1758
|
+
end_time=end_time,
|
|
1682
1759
|
status_filter=status_filter,
|
|
1683
1760
|
playbook_status_filter=playbook_status_filter,
|
|
1684
1761
|
tags=tags,
|
|
@@ -1689,8 +1766,12 @@ class ReflexioClient:
|
|
|
1689
1766
|
cached_result = self._cache.get(
|
|
1690
1767
|
"get_agent_playbooks",
|
|
1691
1768
|
limit=req.limit,
|
|
1769
|
+
agent_playbook_id=req.agent_playbook_id,
|
|
1770
|
+
query=req.query,
|
|
1692
1771
|
playbook_name=req.playbook_name,
|
|
1693
1772
|
agent_version=req.agent_version,
|
|
1773
|
+
start_time=req.start_time,
|
|
1774
|
+
end_time=req.end_time,
|
|
1694
1775
|
status_filter=req.status_filter,
|
|
1695
1776
|
playbook_status_filter=req.playbook_status_filter,
|
|
1696
1777
|
tags=req.tags,
|
|
@@ -1711,8 +1792,12 @@ class ReflexioClient:
|
|
|
1711
1792
|
"get_agent_playbooks",
|
|
1712
1793
|
result,
|
|
1713
1794
|
limit=req.limit,
|
|
1795
|
+
agent_playbook_id=req.agent_playbook_id,
|
|
1796
|
+
query=req.query,
|
|
1714
1797
|
playbook_name=req.playbook_name,
|
|
1715
1798
|
agent_version=req.agent_version,
|
|
1799
|
+
start_time=req.start_time,
|
|
1800
|
+
end_time=req.end_time,
|
|
1716
1801
|
status_filter=req.status_filter,
|
|
1717
1802
|
playbook_status_filter=req.playbook_status_filter,
|
|
1718
1803
|
tags=req.tags,
|
|
@@ -1726,6 +1811,8 @@ class ReflexioClient:
|
|
|
1726
1811
|
*,
|
|
1727
1812
|
user_id: str | None = None,
|
|
1728
1813
|
request_id: str | None = None,
|
|
1814
|
+
session_id: str | None = None,
|
|
1815
|
+
source: str | None = None,
|
|
1729
1816
|
start_time: datetime | None = None,
|
|
1730
1817
|
end_time: datetime | None = None,
|
|
1731
1818
|
top_k: int | None = None,
|
|
@@ -1736,6 +1823,8 @@ class ReflexioClient:
|
|
|
1736
1823
|
request (Optional[GetRequestsRequest]): The get request object (alternative to kwargs)
|
|
1737
1824
|
user_id (Optional[str]): Filter by user ID
|
|
1738
1825
|
request_id (Optional[str]): Filter by request ID
|
|
1826
|
+
session_id (Optional[str]): Filter by session ID
|
|
1827
|
+
source (Optional[str]): Filter by request source
|
|
1739
1828
|
start_time (Optional[datetime]): Filter by start time
|
|
1740
1829
|
end_time (Optional[datetime]): Filter by end time
|
|
1741
1830
|
top_k (Optional[int]): Maximum number of results to return (default: 30)
|
|
@@ -1748,6 +1837,8 @@ class ReflexioClient:
|
|
|
1748
1837
|
GetRequestsRequest,
|
|
1749
1838
|
user_id=user_id,
|
|
1750
1839
|
request_id=request_id,
|
|
1840
|
+
session_id=session_id,
|
|
1841
|
+
source=source,
|
|
1751
1842
|
start_time=start_time,
|
|
1752
1843
|
end_time=end_time,
|
|
1753
1844
|
top_k=top_k,
|
|
@@ -1765,6 +1856,8 @@ class ReflexioClient:
|
|
|
1765
1856
|
*,
|
|
1766
1857
|
limit: int | None = None,
|
|
1767
1858
|
agent_version: str | None = None,
|
|
1859
|
+
start_time: datetime | None = None,
|
|
1860
|
+
end_time: datetime | None = None,
|
|
1768
1861
|
) -> GetEvaluationResultsViewResponse:
|
|
1769
1862
|
"""Get agent success evaluation results.
|
|
1770
1863
|
|
|
@@ -1772,6 +1865,8 @@ class ReflexioClient:
|
|
|
1772
1865
|
request (Optional[GetAgentSuccessEvaluationResultsRequest]): The get request object (alternative to kwargs)
|
|
1773
1866
|
limit (Optional[int]): Maximum number of results to return (default: 100)
|
|
1774
1867
|
agent_version (Optional[str]): Filter by agent version
|
|
1868
|
+
start_time (Optional[datetime]): Filter by start time
|
|
1869
|
+
end_time (Optional[datetime]): Filter by end time
|
|
1775
1870
|
|
|
1776
1871
|
Returns:
|
|
1777
1872
|
GetEvaluationResultsViewResponse: Response containing agent success evaluation results
|
|
@@ -1781,6 +1876,8 @@ class ReflexioClient:
|
|
|
1781
1876
|
GetAgentSuccessEvaluationResultsRequest,
|
|
1782
1877
|
limit=limit,
|
|
1783
1878
|
agent_version=agent_version,
|
|
1879
|
+
start_time=start_time,
|
|
1880
|
+
end_time=end_time,
|
|
1784
1881
|
)
|
|
1785
1882
|
response = self._make_request(
|
|
1786
1883
|
"POST",
|
|
@@ -213,8 +213,16 @@ class AgentPlaybookMixin(ReflexioBase):
|
|
|
213
213
|
try:
|
|
214
214
|
agent_playbooks = self._get_storage().get_agent_playbooks(
|
|
215
215
|
limit=request.limit or 100,
|
|
216
|
+
agent_playbook_id=request.agent_playbook_id,
|
|
217
|
+
query=request.query,
|
|
216
218
|
playbook_name=request.playbook_name,
|
|
217
219
|
agent_version=request.agent_version,
|
|
220
|
+
start_time=(
|
|
221
|
+
int(request.start_time.timestamp()) if request.start_time else None
|
|
222
|
+
),
|
|
223
|
+
end_time=(
|
|
224
|
+
int(request.end_time.timestamp()) if request.end_time else None
|
|
225
|
+
),
|
|
218
226
|
status_filter=request.status_filter,
|
|
219
227
|
playbook_status_filter=[request.playbook_status_filter]
|
|
220
228
|
if request.playbook_status_filter
|
|
@@ -127,6 +127,21 @@ class ReflexioBase:
|
|
|
127
127
|
raise RuntimeError(STORAGE_NOT_CONFIGURED_MSG)
|
|
128
128
|
return storage
|
|
129
129
|
|
|
130
|
+
def get_storage(self) -> BaseStorage:
|
|
131
|
+
"""Return the configured storage backend.
|
|
132
|
+
|
|
133
|
+
Public accessor for consumers (including enterprise) that need the
|
|
134
|
+
underlying ``BaseStorage``. Prefer ``request_context.storage`` inside
|
|
135
|
+
OSS pipeline code; this exists for callers that hold a ``Reflexio``.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
BaseStorage: The configured storage backend.
|
|
139
|
+
|
|
140
|
+
Raises:
|
|
141
|
+
RuntimeError: If storage is not configured.
|
|
142
|
+
"""
|
|
143
|
+
return self._get_storage()
|
|
144
|
+
|
|
130
145
|
def _get_query_reformulator(self) -> QueryReformulator:
|
|
131
146
|
"""Lazily create and cache a QueryReformulator instance.
|
|
132
147
|
|