@simbimbo/memory-ocmemog 0.1.10 → 0.1.12
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 +85 -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 +35 -0
- package/ocmemog/runtime/identity.py +115 -0
- package/ocmemog/runtime/inference.py +164 -0
- package/ocmemog/runtime/instrumentation.py +20 -0
- package/ocmemog/runtime/memory/__init__.py +91 -0
- package/ocmemog/runtime/memory/api.py +1431 -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 +57 -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 +16 -0
- package/ocmemog/runtime/model_router.py +29 -0
- package/ocmemog/runtime/providers.py +79 -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 +34 -0
- package/ocmemog/runtime/storage_paths.py +70 -0
- package/ocmemog/sidecar/app.py +311 -23
- package/ocmemog/sidecar/compat.py +50 -13
- package/ocmemog/sidecar/transcript_watcher.py +391 -190
- 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 +373 -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.12 — 2026-03-21
|
|
4
|
+
|
|
5
|
+
Release hardening, integrated proof validation, and native-ownership cleanup.
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
- fixed conversation-state self-healing so polluted continuity cleanup preserves valid checkpoints instead of deleting the entire checkpoint history for a thread/session/conversation
|
|
9
|
+
- aligned FastAPI sidecar version reporting with the package version and added regression coverage for version drift
|
|
10
|
+
- moved runtime defaults toward native `ocmemog` ownership for report-log and SQLite DB naming while preserving legacy `brain_*` file fallback for existing installs
|
|
11
|
+
- made embedding configuration native-first (`OCMEMOG_*`) while keeping `BRAIN_*` aliases for compatibility
|
|
12
|
+
- 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
|
|
13
|
+
- fixed release-gate/proof path bugs around HTTP method mismatches, async ingest/postprocess timing assumptions, and proof output capture
|
|
14
|
+
- restored live sidecar request-path verification for `/memory/ingest`, `/memory/search`, `/memory/get`, and `/conversation/hydrate`
|
|
15
|
+
- 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
|
|
16
|
+
- 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
|
|
17
|
+
- removed stray invalid transcript-watcher drift assertions from the test suite
|
|
18
|
+
|
|
19
|
+
## 0.1.11 — 2026-03-20
|
|
20
|
+
|
|
21
|
+
Watcher reliability and release-quality follow-up.
|
|
22
|
+
|
|
23
|
+
### Highlights
|
|
24
|
+
- prevented duplicate transcript/session turn ingestion in the watcher path
|
|
25
|
+
- propagated `OCMEMOG_API_TOKEN` auth headers on watcher HTTP posts
|
|
26
|
+
- restored persisted queue stats on sidecar startup
|
|
27
|
+
- added durable watcher error logging instead of silent failure swallowing
|
|
28
|
+
- preserved multi-part text content from session message arrays
|
|
29
|
+
- fixed transcript target handling for both directory mode and file mode
|
|
30
|
+
- hardened retry behavior so failed delivery does not silently drop buffered content and session retries preserve transcript provenance without duplicate transcript rows
|
|
31
|
+
- declared `pytest` as a test extra and refreshed release-facing docs/checklists for current validation flow
|
|
32
|
+
|
|
3
33
|
## 0.1.10 — 2026-03-19
|
|
4
34
|
|
|
5
35
|
Release alignment 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,21 +213,36 @@ 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
|
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
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
|
|
173
226
|
|
|
174
227
|
## Release prep / publish
|
|
175
228
|
|
|
176
|
-
|
|
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
|
+
|
|
242
|
+
Example ClawHub publish command (update version + changelog first; do not reuse stale release text blindly):
|
|
177
243
|
|
|
178
244
|
```bash
|
|
179
|
-
clawhub publish . --slug memory-ocmemog --name "ocmemog" --version
|
|
245
|
+
clawhub publish . --slug memory-ocmemog --name "ocmemog" --version <next-version> --changelog "<concise release summary>"
|
|
180
246
|
```
|
|
181
247
|
|
|
182
248
|
## Install from npm (after publish)
|
|
@@ -203,6 +269,8 @@ plugins:
|
|
|
203
269
|
config:
|
|
204
270
|
endpoint: http://127.0.0.1:17891
|
|
205
271
|
timeoutMs: 30000
|
|
272
|
+
# Optional if the sidecar is protected by OCMEMOG_API_TOKEN
|
|
273
|
+
token: your-ocmemog-token
|
|
206
274
|
```
|
|
207
275
|
|
|
208
276
|
Development install:
|
|
@@ -227,7 +295,6 @@ What is working now:
|
|
|
227
295
|
Current limitations before broader public rollout:
|
|
228
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
|
|
229
297
|
- Packaging and install UX are aimed primarily at power users and local developers today
|
|
230
|
-
-
|
|
298
|
+
- Distribution and release metadata are now tracked in `package.json`, `CHANGELOG.md`, and the release check workflow.
|
|
231
299
|
|
|
232
300
|
When a richer path is unavailable, the sidecar is designed to fail soft with explicit warnings rather than crash.
|
|
233
|
-
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
|