@simbimbo/memory-ocmemog 0.1.11 → 0.1.13
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/CHANGELOG.md +30 -0
- package/README.md +83 -18
- package/brain/runtime/__init__.py +2 -12
- package/brain/runtime/config.py +1 -24
- package/brain/runtime/inference.py +1 -151
- package/brain/runtime/instrumentation.py +1 -15
- package/brain/runtime/memory/__init__.py +3 -13
- package/brain/runtime/memory/api.py +1 -1219
- package/brain/runtime/memory/candidate.py +1 -185
- package/brain/runtime/memory/conversation_state.py +1 -1823
- package/brain/runtime/memory/distill.py +1 -344
- package/brain/runtime/memory/embedding_engine.py +1 -92
- package/brain/runtime/memory/freshness.py +1 -112
- package/brain/runtime/memory/health.py +1 -40
- package/brain/runtime/memory/integrity.py +1 -186
- package/brain/runtime/memory/memory_consolidation.py +1 -58
- package/brain/runtime/memory/memory_links.py +1 -107
- package/brain/runtime/memory/memory_salience.py +1 -233
- package/brain/runtime/memory/memory_synthesis.py +1 -31
- package/brain/runtime/memory/memory_taxonomy.py +1 -33
- package/brain/runtime/memory/pondering_engine.py +1 -654
- package/brain/runtime/memory/promote.py +1 -277
- package/brain/runtime/memory/provenance.py +1 -406
- package/brain/runtime/memory/reinforcement.py +1 -71
- package/brain/runtime/memory/retrieval.py +1 -210
- package/brain/runtime/memory/semantic_search.py +1 -64
- package/brain/runtime/memory/store.py +1 -429
- package/brain/runtime/memory/unresolved_state.py +1 -91
- package/brain/runtime/memory/vector_index.py +1 -323
- package/brain/runtime/model_roles.py +1 -9
- package/brain/runtime/model_router.py +1 -22
- package/brain/runtime/providers.py +1 -66
- package/brain/runtime/security/redaction.py +1 -12
- package/brain/runtime/state_store.py +1 -23
- package/brain/runtime/storage_paths.py +1 -39
- package/docs/architecture/memory.md +20 -24
- package/docs/release-checklist.md +19 -6
- package/docs/usage.md +33 -17
- package/index.ts +8 -1
- package/ocmemog/__init__.py +11 -0
- package/ocmemog/doctor.py +1255 -0
- package/ocmemog/runtime/__init__.py +18 -0
- package/ocmemog/runtime/_compat_bridge.py +28 -0
- package/ocmemog/runtime/config.py +34 -0
- package/ocmemog/runtime/identity.py +115 -0
- package/ocmemog/runtime/inference.py +163 -0
- package/ocmemog/runtime/instrumentation.py +20 -0
- package/ocmemog/runtime/memory/__init__.py +91 -0
- package/ocmemog/runtime/memory/api.py +1594 -0
- package/ocmemog/runtime/memory/candidate.py +192 -0
- package/ocmemog/runtime/memory/conversation_state.py +1831 -0
- package/ocmemog/runtime/memory/distill.py +282 -0
- package/ocmemog/runtime/memory/embedding_engine.py +151 -0
- package/ocmemog/runtime/memory/freshness.py +114 -0
- package/ocmemog/runtime/memory/health.py +93 -0
- package/ocmemog/runtime/memory/integrity.py +208 -0
- package/ocmemog/runtime/memory/memory_consolidation.py +60 -0
- package/ocmemog/runtime/memory/memory_links.py +109 -0
- package/ocmemog/runtime/memory/memory_salience.py +235 -0
- package/ocmemog/runtime/memory/memory_synthesis.py +33 -0
- package/ocmemog/runtime/memory/memory_taxonomy.py +35 -0
- package/ocmemog/runtime/memory/pondering_engine.py +681 -0
- package/ocmemog/runtime/memory/promote.py +279 -0
- package/ocmemog/runtime/memory/provenance.py +408 -0
- package/ocmemog/runtime/memory/reinforcement.py +73 -0
- package/ocmemog/runtime/memory/retrieval.py +224 -0
- package/ocmemog/runtime/memory/semantic_search.py +66 -0
- package/ocmemog/runtime/memory/store.py +433 -0
- package/ocmemog/runtime/memory/unresolved_state.py +93 -0
- package/ocmemog/runtime/memory/vector_index.py +411 -0
- package/ocmemog/runtime/model_roles.py +15 -0
- package/ocmemog/runtime/model_router.py +28 -0
- package/ocmemog/runtime/providers.py +78 -0
- package/ocmemog/runtime/roles.py +92 -0
- package/ocmemog/runtime/security/__init__.py +8 -0
- package/ocmemog/runtime/security/redaction.py +17 -0
- package/ocmemog/runtime/state_store.py +32 -0
- package/ocmemog/runtime/storage_paths.py +70 -0
- package/ocmemog/sidecar/app.py +421 -60
- package/ocmemog/sidecar/compat.py +50 -13
- package/ocmemog/sidecar/transcript_watcher.py +327 -242
- package/openclaw.plugin.json +4 -0
- package/package.json +1 -1
- package/scripts/ocmemog-backfill-vectors.py +5 -3
- package/scripts/ocmemog-continuity-benchmark.py +1 -1
- package/scripts/ocmemog-demo.py +1 -1
- package/scripts/ocmemog-doctor.py +15 -0
- package/scripts/ocmemog-install.sh +29 -7
- package/scripts/ocmemog-integrated-proof.py +374 -0
- package/scripts/ocmemog-reindex-vectors.py +5 -3
- package/scripts/ocmemog-release-check.sh +330 -0
- package/scripts/ocmemog-sidecar.sh +4 -2
- package/scripts/ocmemog-test-rig.py +5 -3
- package/brain/runtime/memory/artifacts.py +0 -33
- package/brain/runtime/memory/context_builder.py +0 -112
- package/brain/runtime/memory/interaction_memory.py +0 -57
- package/brain/runtime/memory/memory_gate.py +0 -38
- package/brain/runtime/memory/memory_graph.py +0 -54
- package/brain/runtime/memory/person_identity.py +0 -83
- package/brain/runtime/memory/person_memory.py +0 -138
- package/brain/runtime/memory/sentiment_memory.py +0 -67
- package/brain/runtime/memory/tool_catalog.py +0 -68
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.13 — 2026-03-22
|
|
4
|
+
|
|
5
|
+
Final hardening release before a possible 1.0 cut.
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
- tested the full shipped surface aggressively: full pytest suite, release gate, live sidecar contract smoke, packaging dry-run, installer surfaces, and governance summary responsiveness checks all passed together
|
|
9
|
+
- fixed a supersession-governance regression that could suppress `supersession_recommendation` generation and break governance queue/review/summary and auto-resolve flows
|
|
10
|
+
- moved dashboard supersession plain-English rewriting out of the render path so live dashboard loads stay fast while recommendations still carry human-readable text
|
|
11
|
+
- added a lightweight cached governance review summary path for the dashboard, reducing review load time from multi-second scans to sub-second first load and near-instant cached refresh
|
|
12
|
+
- simplified Governance Review UI output into more concise, single-row plain-English review items
|
|
13
|
+
- hardened supersession summary generation against polluted transcript/log content with tighter preview normalization, aggressive noise stripping, bounded local-model rewriting, and safe heuristic fallbacks
|
|
14
|
+
- fixed dashboard cursor handling so the dashboard route tolerates minimal/mock DB cursor implementations used by tests
|
|
15
|
+
- hardened the integrated proof token/session identifiers to avoid fresh-state collisions during repeated release validation
|
|
16
|
+
|
|
17
|
+
## 0.1.12 — 2026-03-21
|
|
18
|
+
|
|
19
|
+
Release hardening, integrated proof validation, and native-ownership cleanup.
|
|
20
|
+
|
|
21
|
+
### Highlights
|
|
22
|
+
- fixed conversation-state self-healing so polluted continuity cleanup preserves valid checkpoints instead of deleting the entire checkpoint history for a thread/session/conversation
|
|
23
|
+
- aligned FastAPI sidecar version reporting with the package version and added regression coverage for version drift
|
|
24
|
+
- moved runtime defaults toward native `ocmemog` ownership for report-log and SQLite DB naming while preserving legacy `brain_*` file fallback for existing installs
|
|
25
|
+
- made embedding configuration native-first (`OCMEMOG_*`) while keeping `BRAIN_*` aliases for compatibility
|
|
26
|
+
- hardened the integrated memory contract proof and release gate so fresh-state proof, live sidecar smoke, and route/regression validation run together as the canonical pre-release bar
|
|
27
|
+
- fixed release-gate/proof path bugs around HTTP method mismatches, async ingest/postprocess timing assumptions, and proof output capture
|
|
28
|
+
- restored live sidecar request-path verification for `/memory/ingest`, `/memory/search`, `/memory/get`, and `/conversation/hydrate`
|
|
29
|
+
- collapsed the legacy `brain/runtime/*` implementation tree into thin compatibility shims and removed orphan legacy side-modules that were no longer part of the shipped product contract
|
|
30
|
+
- cleaned release docs, compat wording, and helper scripts so new deployments follow native `ocmemog` behavior by default and stale side-DB architecture references are removed
|
|
31
|
+
- removed stray invalid transcript-watcher drift assertions from the test suite
|
|
32
|
+
|
|
3
33
|
## 0.1.11 — 2026-03-20
|
|
4
34
|
|
|
5
35
|
Watcher reliability and release-quality follow-up.
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ It is designed to go beyond simple memory search by providing:
|
|
|
12
12
|
Architecture at a glance:
|
|
13
13
|
- **OpenClaw plugin (`index.ts`)** handles tools and hook integration
|
|
14
14
|
- **FastAPI sidecar (`ocmemog/sidecar/`)** exposes memory and continuity APIs
|
|
15
|
-
- **SQLite-backed runtime (`
|
|
15
|
+
- **SQLite-backed runtime (`ocmemog/runtime/memory/`)** powers storage, hydration, checkpoints, salience ranking, and pondering
|
|
16
16
|
|
|
17
17
|
Current local runtime architecture note:
|
|
18
18
|
- `docs/architecture/local-runtime-2026-03-19.md`
|
|
@@ -21,8 +21,9 @@ Current local runtime architecture note:
|
|
|
21
21
|
|
|
22
22
|
- `openclaw.plugin.json`, `index.ts`, `package.json`: OpenClaw plugin package and manifest.
|
|
23
23
|
- `ocmemog/sidecar/`: FastAPI sidecar with `/memory/search` and `/memory/get`.
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
24
|
+
- `ocmemog/runtime/`: native runtime surfaces used by the sidecar and memory engine.
|
|
25
|
+
- `ocmemog/runtime/memory/`: local memory/runtime package used by the sidecar.
|
|
26
|
+
- `brain/`: internal compatibility residue retained for transitional shim paths; not the primary runtime surface.
|
|
26
27
|
- `scripts/ocmemog-sidecar.sh`: convenience launcher.
|
|
27
28
|
|
|
28
29
|
## Run the sidecar
|
|
@@ -38,11 +39,44 @@ pip install -r requirements.txt
|
|
|
38
39
|
# http://127.0.0.1:17891/dashboard
|
|
39
40
|
```
|
|
40
41
|
|
|
42
|
+
For local development and CI-style test runs, install test dependencies as well:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cd /path/to/ocmemog
|
|
46
|
+
python3 -m venv .venv
|
|
47
|
+
. .venv/bin/activate
|
|
48
|
+
python -m pip install -r requirements-test.txt
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Run the doctor check
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
./.venv/bin/python3 scripts/ocmemog-doctor.py
|
|
55
|
+
./.venv/bin/python3 scripts/ocmemog-doctor.py --json
|
|
56
|
+
./.venv/bin/python3 scripts/ocmemog-doctor.py --fix create-missing-paths --fix repair-queue
|
|
57
|
+
./.venv/bin/python3 scripts/ocmemog-doctor.py --strict --check runtime/imports --check sqlite/schema-access
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The doctor command currently checks:
|
|
61
|
+
- runtime/imports
|
|
62
|
+
- state/path-writable
|
|
63
|
+
- sqlite/schema-access
|
|
64
|
+
- sidecar/http-auth
|
|
65
|
+
- queue/health
|
|
66
|
+
- sidecar/transcript-watcher
|
|
67
|
+
- sidecar/app-import
|
|
68
|
+
- sidecar/transcript-roots
|
|
69
|
+
- sidecar/env-toggles
|
|
70
|
+
- vector/runtime-probe
|
|
71
|
+
|
|
41
72
|
## Optional: transcript watcher (auto-ingest)
|
|
42
73
|
|
|
43
74
|
```bash
|
|
44
|
-
# defaults
|
|
75
|
+
# defaults:
|
|
76
|
+
# - transcript mode: ~/.openclaw/workspace/memory/transcripts
|
|
77
|
+
# - session mode: ~/.openclaw/agents/main/sessions (used when OCMEMOG_TRANSCRIPT_DIR is unset)
|
|
45
78
|
export OCMEMOG_TRANSCRIPT_DIR="$HOME/.openclaw/workspace/memory/transcripts"
|
|
79
|
+
export OCMEMOG_SESSION_DIR="$HOME/.openclaw/agents/main/sessions"
|
|
46
80
|
./scripts/ocmemog-transcript-watcher.sh
|
|
47
81
|
```
|
|
48
82
|
|
|
@@ -80,11 +114,26 @@ Optional environment variables:
|
|
|
80
114
|
- `OCMEMOG_OPENAI_API_KEY` (required for model-backed distill)
|
|
81
115
|
- `OCMEMOG_OPENAI_API_BASE` (default: `https://api.openai.com/v1`)
|
|
82
116
|
- `OCMEMOG_OPENAI_EMBED_MODEL` (default: `text-embedding-3-small`)
|
|
83
|
-
- `
|
|
84
|
-
- `
|
|
117
|
+
- `OCMEMOG_EMBED_MODEL_LOCAL` (`simple` by default; legacy alias: `BRAIN_EMBED_MODEL_LOCAL`)
|
|
118
|
+
- `OCMEMOG_EMBED_MODEL_PROVIDER` (`local-openai` to use the local llama.cpp embedding endpoint; `openai` remains available for hosted embeddings; legacy alias: `BRAIN_EMBED_MODEL_PROVIDER`)
|
|
85
119
|
- `OCMEMOG_TRANSCRIPT_WATCHER` (`true` to auto-start transcript watcher inside the sidecar)
|
|
86
120
|
- `OCMEMOG_TRANSCRIPT_ROOTS` (comma-separated allowed roots for transcript context retrieval; default: `~/.openclaw/workspace/memory`)
|
|
87
|
-
- `
|
|
121
|
+
- `OCMEMOG_TRANSCRIPT_DIR` (default: `~/.openclaw/workspace/memory/transcripts`)
|
|
122
|
+
- `OCMEMOG_SESSION_DIR` (default: `~/.openclaw/agents/main/sessions`)
|
|
123
|
+
- `OCMEMOG_TRANSCRIPT_POLL_SECONDS` (poll interval for file/session watcher; default: `30`, or `120` in battery mode)
|
|
124
|
+
- `OCMEMOG_INGEST_BATCH_SECONDS` (max lines per watcher batch; default: `30`, or `120` in battery mode)
|
|
125
|
+
- `OCMEMOG_INGEST_BATCH_MAX` (max watcher batches before yield; default: `25`, or `10` in battery mode)
|
|
126
|
+
- `OCMEMOG_SESSION_GLOB` (default file glob for session sources: `*.jsonl`)
|
|
127
|
+
- `OCMEMOG_TRANSCRIPT_GLOB` (default file glob for transcripts: `*.log`)
|
|
128
|
+
- `OCMEMOG_INGEST_ASYNC_WORKER` (`true` to keep async ingest queue processing enabled; defaults to `true`)
|
|
129
|
+
- `OCMEMOG_INGEST_ASYNC_POLL_SECONDS` (`5` by default)
|
|
130
|
+
- `OCMEMOG_INGEST_ASYNC_BATCH_MAX` (`25` by default)
|
|
131
|
+
- `OCMEMOG_INGEST_ENDPOINT` (default: `http://127.0.0.1:17891/memory/ingest_async`)
|
|
132
|
+
- `OCMEMOG_SHUTDOWN_DRAIN_QUEUE` (`true` to drain remaining queue entries during shutdown; defaults to `false`)
|
|
133
|
+
- `OCMEMOG_WORKER_SHUTDOWN_TIMEOUT_SECONDS` (`0.35` by default)
|
|
134
|
+
- `OCMEMOG_SHUTDOWN_DUMP_THREADS` (`true` to include worker thread dump output during shutdown joins; defaults to `false`)
|
|
135
|
+
- `OCMEMOG_SHUTDOWN_TIMING` (`true` enables shutdown timing logs; defaults to `true`)
|
|
136
|
+
- `OCMEMOG_API_TOKEN` (optional; if set, requests must include `x-ocmemog-token` or `Authorization: Bearer ...`; OpenClaw plugin users should also set the plugin `config.token` field)
|
|
88
137
|
- `OCMEMOG_AUTO_HYDRATION` (`true` to re-enable prompt-time continuity prepending; defaults to `false` as a safety guard until the host runtime is verified not to persist prepended context into session history)
|
|
89
138
|
- `OCMEMOG_LAPTOP_MODE` (`auto` by default; on macOS battery power this slows watcher polling, reduces ingest batch size, and disables sentiment reinforcement unless explicitly overridden)
|
|
90
139
|
- `OCMEMOG_LOCAL_LLM_BASE_URL` (default: `http://127.0.0.1:18080/v1`; local OpenAI-compatible text endpoint, e.g. llama.cpp)
|
|
@@ -101,6 +150,8 @@ Optional environment variables:
|
|
|
101
150
|
- `OCMEMOG_PONDER_MODEL` (default via launcher: `local-openai:qwen2.5-7b-instruct`; recommended for structured local memory refinement)
|
|
102
151
|
- `OCMEMOG_LESSON_MINING_ENABLED` (default: `true`)
|
|
103
152
|
|
|
153
|
+
Boolean env values are parsed case-insensitively and support `1/0`, `true/false`, `yes/no`, `on/off`, `y/n`, and `t/f`.
|
|
154
|
+
|
|
104
155
|
## Security
|
|
105
156
|
|
|
106
157
|
- Sidecar binds to **127.0.0.1** by default. Keep it local unless you add auth + firewall rules.
|
|
@@ -162,19 +213,32 @@ launchctl bootstrap gui/$UID scripts/launchagents/com.openclaw.ocmemog.guard.pli
|
|
|
162
213
|
|
|
163
214
|
## Recent changes
|
|
164
215
|
|
|
165
|
-
### 0.1.
|
|
216
|
+
### 0.1.12 (current main)
|
|
166
217
|
|
|
167
|
-
Current main includes
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
174
|
-
-
|
|
218
|
+
Current main now includes:
|
|
219
|
+
- integrated release-gate validation with a fresh-state memory contract proof
|
|
220
|
+
- live sidecar smoke checks for `/memory/ingest`, `/memory/search`, `/memory/get`, and `/conversation/hydrate`
|
|
221
|
+
- hardened async ingest/postprocess handling and queue-health validation
|
|
222
|
+
- native-first `ocmemog` config, DB, and report-log naming with legacy fallback support
|
|
223
|
+
- sidecar/package version alignment and regression coverage for checkpoint self-heal behavior
|
|
224
|
+
- major collapse of the legacy `brain/runtime/*` implementation surface into thin compatibility shims
|
|
225
|
+
- removal of orphan legacy memory side-modules and stale architecture references to retired side DBs
|
|
175
226
|
|
|
176
227
|
## Release prep / publish
|
|
177
228
|
|
|
229
|
+
Run the release gate first:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
./scripts/ocmemog-release-check.sh
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
This command is the canonical pre-release and CI validation path. A pass now means:
|
|
236
|
+
- strict doctor checks succeed on a clean temporary state
|
|
237
|
+
- the broad regression subset plus sidecar route tests pass
|
|
238
|
+
- live `/healthz`, `/memory/ingest`, `/memory/search`, `/memory/get`, and `/conversation/hydrate` checks pass on `OCMEMOG_RELEASE_LIVE_ENDPOINT`
|
|
239
|
+
- the integrated memory contract proof runs in fresh state and emits `reports/release-gate-proof.json`
|
|
240
|
+
- syntax checks, integration assertions, and non-blocking packing validation are attempted
|
|
241
|
+
|
|
178
242
|
Example ClawHub publish command (update version + changelog first; do not reuse stale release text blindly):
|
|
179
243
|
|
|
180
244
|
```bash
|
|
@@ -205,6 +269,8 @@ plugins:
|
|
|
205
269
|
config:
|
|
206
270
|
endpoint: http://127.0.0.1:17891
|
|
207
271
|
timeoutMs: 30000
|
|
272
|
+
# Optional if the sidecar is protected by OCMEMOG_API_TOKEN
|
|
273
|
+
token: your-ocmemog-token
|
|
208
274
|
```
|
|
209
275
|
|
|
210
276
|
Development install:
|
|
@@ -229,7 +295,6 @@ What is working now:
|
|
|
229
295
|
Current limitations before broader public rollout:
|
|
230
296
|
- Some advanced inference- and embedding-dependent paths still depend on environment configuration and may degrade to simpler local behavior if provider access is unavailable
|
|
231
297
|
- Packaging and install UX are aimed primarily at power users and local developers today
|
|
232
|
-
-
|
|
298
|
+
- Distribution and release metadata are now tracked in `package.json`, `CHANGELOG.md`, and the release check workflow.
|
|
233
299
|
|
|
234
300
|
When a richer path is unavailable, the sidecar is designed to fail soft with explicit warnings rather than crash.
|
|
235
|
-
soft with explicit warnings rather than crash.
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from . import
|
|
4
|
-
|
|
5
|
-
__all__ = [
|
|
6
|
-
"config",
|
|
7
|
-
"inference",
|
|
8
|
-
"instrumentation",
|
|
9
|
-
"model_roles",
|
|
10
|
-
"model_router",
|
|
11
|
-
"state_store",
|
|
12
|
-
"storage_paths",
|
|
13
|
-
]
|
|
3
|
+
from ocmemog.runtime import * # noqa: F401,F403
|
package/brain/runtime/config.py
CHANGED
|
@@ -1,26 +1,3 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
BRAIN_EMBED_MODEL_LOCAL = os.environ.get("BRAIN_EMBED_MODEL_LOCAL", "simple")
|
|
6
|
-
BRAIN_EMBED_MODEL_PROVIDER = os.environ.get("BRAIN_EMBED_MODEL_PROVIDER", "")
|
|
7
|
-
|
|
8
|
-
OCMEMOG_MEMORY_MODEL = os.environ.get("OCMEMOG_MEMORY_MODEL", "gpt-4o-mini")
|
|
9
|
-
OCMEMOG_OPENAI_API_BASE = os.environ.get("OCMEMOG_OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
10
|
-
OCMEMOG_OPENAI_EMBED_MODEL = os.environ.get("OCMEMOG_OPENAI_EMBED_MODEL", "text-embedding-3-small")
|
|
11
|
-
|
|
12
|
-
OCMEMOG_LOCAL_LLM_BASE_URL = os.environ.get("OCMEMOG_LOCAL_LLM_BASE_URL", "http://127.0.0.1:18080/v1")
|
|
13
|
-
OCMEMOG_LOCAL_LLM_MODEL = os.environ.get("OCMEMOG_LOCAL_LLM_MODEL", "qwen2.5-7b-instruct")
|
|
14
|
-
OCMEMOG_LOCAL_EMBED_BASE_URL = os.environ.get("OCMEMOG_LOCAL_EMBED_BASE_URL", "http://127.0.0.1:18081/v1")
|
|
15
|
-
OCMEMOG_LOCAL_EMBED_MODEL = os.environ.get("OCMEMOG_LOCAL_EMBED_MODEL", "nomic-embed-text-v1.5")
|
|
16
|
-
|
|
17
|
-
OCMEMOG_OLLAMA_HOST = os.environ.get("OCMEMOG_OLLAMA_HOST", "http://127.0.0.1:11434")
|
|
18
|
-
OCMEMOG_OLLAMA_MODEL = os.environ.get("OCMEMOG_OLLAMA_MODEL", "qwen2.5:7b")
|
|
19
|
-
OCMEMOG_OLLAMA_EMBED_MODEL = os.environ.get("OCMEMOG_OLLAMA_EMBED_MODEL", "nomic-embed-text:latest")
|
|
20
|
-
|
|
21
|
-
OCMEMOG_PROMOTION_THRESHOLD = float(os.environ.get("OCMEMOG_PROMOTION_THRESHOLD", "0.5"))
|
|
22
|
-
OCMEMOG_DEMOTION_THRESHOLD = float(os.environ.get("OCMEMOG_DEMOTION_THRESHOLD", "0.2"))
|
|
23
|
-
|
|
24
|
-
OCMEMOG_PONDER_ENABLED = os.environ.get("OCMEMOG_PONDER_ENABLED", "true")
|
|
25
|
-
OCMEMOG_PONDER_MODEL = os.environ.get("OCMEMOG_PONDER_MODEL", OCMEMOG_MEMORY_MODEL)
|
|
26
|
-
OCMEMOG_LESSON_MINING_ENABLED = os.environ.get("OCMEMOG_LESSON_MINING_ENABLED", "true")
|
|
3
|
+
from ocmemog.runtime.config import * # noqa: F401,F403
|
|
@@ -1,153 +1,3 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import os
|
|
5
|
-
import re
|
|
6
|
-
import urllib.request
|
|
7
|
-
|
|
8
|
-
from brain.runtime import config, state_store
|
|
9
|
-
from brain.runtime.instrumentation import emit_event
|
|
10
|
-
|
|
11
|
-
LOGFILE = state_store.reports_dir() / "brain_memory.log.jsonl"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def _infer_openai_compatible(prompt: str, *, base_url: str, model: str, api_key: str | None = None, provider_label: str = "openai-compatible") -> dict[str, str]:
|
|
15
|
-
url = f"{base_url.rstrip('/')}/chat/completions"
|
|
16
|
-
payload = {
|
|
17
|
-
"model": model,
|
|
18
|
-
"messages": [{"role": "user", "content": prompt}],
|
|
19
|
-
"temperature": 0.2,
|
|
20
|
-
}
|
|
21
|
-
data = json.dumps(payload).encode("utf-8")
|
|
22
|
-
req = urllib.request.Request(url, data=data, method="POST")
|
|
23
|
-
if api_key:
|
|
24
|
-
req.add_header("Authorization", f"Bearer {api_key}")
|
|
25
|
-
req.add_header("Content-Type", "application/json")
|
|
26
|
-
|
|
27
|
-
try:
|
|
28
|
-
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
29
|
-
response = json.loads(resp.read().decode("utf-8"))
|
|
30
|
-
except Exception as exc:
|
|
31
|
-
emit_event(LOGFILE, "brain_infer_error", status="error", provider=provider_label, error=str(exc))
|
|
32
|
-
return {"status": "error", "error": f"request_failed:{exc}"}
|
|
33
|
-
|
|
34
|
-
try:
|
|
35
|
-
output = response["choices"][0]["message"]["content"]
|
|
36
|
-
except Exception as exc:
|
|
37
|
-
emit_event(LOGFILE, "brain_infer_error", status="error", provider=provider_label, error=str(exc))
|
|
38
|
-
return {"status": "error", "error": "invalid_response"}
|
|
39
|
-
|
|
40
|
-
return {"status": "ok", "output": str(output).strip()}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def _infer_ollama(prompt: str, model: str | None = None) -> dict[str, str]:
|
|
44
|
-
payload = {
|
|
45
|
-
"model": model or config.OCMEMOG_OLLAMA_MODEL,
|
|
46
|
-
"prompt": prompt,
|
|
47
|
-
"stream": False,
|
|
48
|
-
}
|
|
49
|
-
data = json.dumps(payload).encode("utf-8")
|
|
50
|
-
req = urllib.request.Request(f"{config.OCMEMOG_OLLAMA_HOST.rstrip('/')}/api/generate", data=data, method="POST")
|
|
51
|
-
req.add_header("Content-Type", "application/json")
|
|
52
|
-
try:
|
|
53
|
-
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
54
|
-
response = json.loads(resp.read().decode("utf-8"))
|
|
55
|
-
except Exception as exc:
|
|
56
|
-
emit_event(LOGFILE, "brain_infer_error", status="error", provider="ollama", error=str(exc))
|
|
57
|
-
return {"status": "error", "error": f"ollama_failed:{exc}"}
|
|
58
|
-
output = response.get("response")
|
|
59
|
-
if not output:
|
|
60
|
-
emit_event(LOGFILE, "brain_infer_error", status="error", provider="ollama", error="invalid_response")
|
|
61
|
-
return {"status": "error", "error": "invalid_response"}
|
|
62
|
-
return {"status": "ok", "output": str(output).strip()}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def _looks_like_local_openai_model(name: str) -> bool:
|
|
66
|
-
if not name:
|
|
67
|
-
return False
|
|
68
|
-
lowered = name.strip().lower()
|
|
69
|
-
return lowered.startswith("local-openai:") or lowered.startswith("local_openai:") or lowered.startswith("llamacpp:")
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def _normalize_local_model_name(name: str) -> str:
|
|
73
|
-
lowered = (name or "").strip()
|
|
74
|
-
for prefix in ("local-openai:", "local_openai:", "llamacpp:"):
|
|
75
|
-
if lowered.lower().startswith(prefix):
|
|
76
|
-
return lowered[len(prefix):]
|
|
77
|
-
return lowered
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def _looks_like_ollama_model(name: str) -> bool:
|
|
81
|
-
if not name:
|
|
82
|
-
return False
|
|
83
|
-
lowered = name.strip().lower()
|
|
84
|
-
if lowered.startswith("ollama:"):
|
|
85
|
-
return True
|
|
86
|
-
if "/" in lowered:
|
|
87
|
-
return False
|
|
88
|
-
return ":" in lowered
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def stats() -> dict[str, object]:
|
|
92
|
-
materialized_local = int(_LOCAL_INFER_STATS.get("local_success", 0)) + int(_LOCAL_INFER_STATS.get("cache_hits", 0))
|
|
93
|
-
est_prompt_tokens_saved = materialized_local * _AVG_PROMPT_TOKENS_SAVED
|
|
94
|
-
est_completion_tokens_saved = materialized_local * _AVG_COMPLETION_TOKENS_SAVED
|
|
95
|
-
est_cost_saved = (
|
|
96
|
-
(est_prompt_tokens_saved / 1000.0) * _EST_FRONTIER_INPUT_COST_PER_1K
|
|
97
|
-
+ (est_completion_tokens_saved / 1000.0) * _EST_FRONTIER_OUTPUT_COST_PER_1K
|
|
98
|
-
)
|
|
99
|
-
return {
|
|
100
|
-
"cache_entries": len(_LOCAL_INFER_CACHE),
|
|
101
|
-
"warm_models": sorted(_MODEL_WARM_STATE.keys()),
|
|
102
|
-
"frontier_calls_avoided_est": materialized_local,
|
|
103
|
-
"prompt_tokens_saved_est": est_prompt_tokens_saved,
|
|
104
|
-
"completion_tokens_saved_est": est_completion_tokens_saved,
|
|
105
|
-
"cost_saved_usd_est": round(est_cost_saved, 4),
|
|
106
|
-
**{k: int(v) for k, v in _LOCAL_INFER_STATS.items()},
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def infer(prompt: str, provider_name: str | None = None) -> dict[str, str]:
|
|
111
|
-
if not isinstance(prompt, str) or not prompt.strip():
|
|
112
|
-
return {"status": "error", "error": "empty_prompt"}
|
|
113
|
-
|
|
114
|
-
use_ollama = os.environ.get("OCMEMOG_USE_OLLAMA", "").lower() in {"1", "true", "yes"}
|
|
115
|
-
model_override = provider_name or config.OCMEMOG_MEMORY_MODEL
|
|
116
|
-
if _looks_like_local_openai_model(model_override):
|
|
117
|
-
model = _normalize_local_model_name(model_override) or config.OCMEMOG_LOCAL_LLM_MODEL
|
|
118
|
-
return _infer_openai_compatible(
|
|
119
|
-
prompt,
|
|
120
|
-
base_url=config.OCMEMOG_LOCAL_LLM_BASE_URL,
|
|
121
|
-
model=model,
|
|
122
|
-
api_key=os.environ.get("OCMEMOG_LOCAL_LLM_API_KEY") or os.environ.get("LOCAL_LLM_API_KEY"),
|
|
123
|
-
provider_label="local-openai",
|
|
124
|
-
)
|
|
125
|
-
if use_ollama or _looks_like_ollama_model(model_override):
|
|
126
|
-
model = model_override.split(":", 1)[-1] if model_override.startswith("ollama:") else model_override
|
|
127
|
-
return _infer_ollama(prompt, model)
|
|
128
|
-
|
|
129
|
-
api_key = os.environ.get("OCMEMOG_OPENAI_API_KEY") or os.environ.get("OPENAI_API_KEY")
|
|
130
|
-
if not api_key:
|
|
131
|
-
return _infer_openai_compatible(
|
|
132
|
-
prompt,
|
|
133
|
-
base_url=config.OCMEMOG_LOCAL_LLM_BASE_URL,
|
|
134
|
-
model=config.OCMEMOG_LOCAL_LLM_MODEL,
|
|
135
|
-
api_key=os.environ.get("OCMEMOG_LOCAL_LLM_API_KEY") or os.environ.get("LOCAL_LLM_API_KEY"),
|
|
136
|
-
provider_label="local-openai",
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
model = model_override
|
|
140
|
-
return _infer_openai_compatible(
|
|
141
|
-
prompt,
|
|
142
|
-
base_url=config.OCMEMOG_OPENAI_API_BASE,
|
|
143
|
-
model=model,
|
|
144
|
-
api_key=api_key,
|
|
145
|
-
provider_label="openai",
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
def parse_operator_name(text: str) -> dict[str, str] | None:
|
|
150
|
-
match = re.search(r"\bmy name is ([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b", text, flags=re.IGNORECASE)
|
|
151
|
-
if not match:
|
|
152
|
-
return None
|
|
153
|
-
return {"name": match.group(1)}
|
|
3
|
+
from ocmemog.runtime.inference import * # noqa: F401,F403
|
|
@@ -1,17 +1,3 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
from datetime import datetime, timezone
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def emit_event(path: Path, event: str, **fields: Any) -> None:
|
|
10
|
-
path.parent.mkdir(parents=True, exist_ok=True)
|
|
11
|
-
payload = {
|
|
12
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
13
|
-
"event": event,
|
|
14
|
-
**fields,
|
|
15
|
-
}
|
|
16
|
-
with path.open("a", encoding="utf-8") as handle:
|
|
17
|
-
handle.write(json.dumps(payload, sort_keys=True) + "\n")
|
|
3
|
+
from ocmemog.runtime.instrumentation import * # noqa: F401,F403
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
"candidate",
|
|
5
|
-
"promote",
|
|
6
|
-
"retrieval",
|
|
7
|
-
"reinforcement",
|
|
8
|
-
"integrity",
|
|
9
|
-
"vector_index",
|
|
10
|
-
"context_builder",
|
|
11
|
-
"memory_taxonomy",
|
|
12
|
-
"health",
|
|
13
|
-
]
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ocmemog.runtime.memory import * # noqa: F401,F403
|