memnixa 0.1.0__tar.gz

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.
Files changed (58) hide show
  1. memnixa-0.1.0/.gitignore +31 -0
  2. memnixa-0.1.0/PKG-INFO +459 -0
  3. memnixa-0.1.0/README.en.md +447 -0
  4. memnixa-0.1.0/README.md +18 -0
  5. memnixa-0.1.0/config.example.json +58 -0
  6. memnixa-0.1.0/pyproject.toml +42 -0
  7. memnixa-0.1.0/src/memnixa/__init__.py +5 -0
  8. memnixa-0.1.0/src/memnixa/__main__.py +5 -0
  9. memnixa-0.1.0/src/memnixa/agent.py +1002 -0
  10. memnixa-0.1.0/src/memnixa/app.py +36 -0
  11. memnixa-0.1.0/src/memnixa/channels/__init__.py +6 -0
  12. memnixa-0.1.0/src/memnixa/channels/base.py +114 -0
  13. memnixa-0.1.0/src/memnixa/channels/feishu.py +349 -0
  14. memnixa-0.1.0/src/memnixa/channels/manager.py +322 -0
  15. memnixa-0.1.0/src/memnixa/channels/qq.py +152 -0
  16. memnixa-0.1.0/src/memnixa/channels/typing.py +169 -0
  17. memnixa-0.1.0/src/memnixa/config.py +637 -0
  18. memnixa-0.1.0/src/memnixa/context.py +181 -0
  19. memnixa-0.1.0/src/memnixa/context_window.py +171 -0
  20. memnixa-0.1.0/src/memnixa/gateway/__init__.py +1 -0
  21. memnixa-0.1.0/src/memnixa/gateway/cli.py +759 -0
  22. memnixa-0.1.0/src/memnixa/gateway/client.py +75 -0
  23. memnixa-0.1.0/src/memnixa/gateway/messages.py +71 -0
  24. memnixa-0.1.0/src/memnixa/gateway/run_queue.py +111 -0
  25. memnixa-0.1.0/src/memnixa/gateway/server.py +188 -0
  26. memnixa-0.1.0/src/memnixa/gateway/ui.py +466 -0
  27. memnixa-0.1.0/src/memnixa/i18n.py +274 -0
  28. memnixa-0.1.0/src/memnixa/identity.py +91 -0
  29. memnixa-0.1.0/src/memnixa/memory.py +428 -0
  30. memnixa-0.1.0/src/memnixa/models.py +56 -0
  31. memnixa-0.1.0/src/memnixa/providers/__init__.py +31 -0
  32. memnixa-0.1.0/src/memnixa/providers/base.py +41 -0
  33. memnixa-0.1.0/src/memnixa/providers/compat.py +33 -0
  34. memnixa-0.1.0/src/memnixa/providers/manager.py +67 -0
  35. memnixa-0.1.0/src/memnixa/providers/openai_compatible.py +122 -0
  36. memnixa-0.1.0/src/memnixa/providers/registry.py +57 -0
  37. memnixa-0.1.0/src/memnixa/runtime_env.py +214 -0
  38. memnixa-0.1.0/src/memnixa/session.py +1580 -0
  39. memnixa-0.1.0/src/memnixa/skills.py +128 -0
  40. memnixa-0.1.0/src/memnixa/tools/__init__.py +25 -0
  41. memnixa-0.1.0/src/memnixa/tools/base.py +265 -0
  42. memnixa-0.1.0/src/memnixa/tools/filesystem.py +159 -0
  43. memnixa-0.1.0/src/memnixa/tools/memory.py +91 -0
  44. memnixa-0.1.0/src/memnixa/tools/shell.py +152 -0
  45. memnixa-0.1.0/src/memnixa/tools/skills.py +133 -0
  46. memnixa-0.1.0/src/memnixa/tools/web.py +243 -0
  47. memnixa-0.1.0/tests/test_agent.py +1034 -0
  48. memnixa-0.1.0/tests/test_channels.py +300 -0
  49. memnixa-0.1.0/tests/test_config.py +339 -0
  50. memnixa-0.1.0/tests/test_context.py +69 -0
  51. memnixa-0.1.0/tests/test_gateway.py +481 -0
  52. memnixa-0.1.0/tests/test_gateway_ui.py +77 -0
  53. memnixa-0.1.0/tests/test_provider_registry.py +23 -0
  54. memnixa-0.1.0/tests/test_run_queue.py +74 -0
  55. memnixa-0.1.0/tests/test_runtime_env.py +104 -0
  56. memnixa-0.1.0/tests/test_skills.py +92 -0
  57. memnixa-0.1.0/tests/test_tools.py +188 -0
  58. memnixa-0.1.0/tests/test_typing.py +86 -0
@@ -0,0 +1,31 @@
1
+ # Python cache and compiled files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+
6
+ # Build artifacts
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+
11
+ # Test and tooling cache
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+ .coverage
15
+ .mypy_cache/
16
+
17
+ # Virtual environments
18
+ .venv/
19
+ venv/
20
+
21
+ # Local environment and secrets
22
+ .env
23
+ .env.*
24
+ config.json
25
+ config.local.json
26
+
27
+ # Runtime data
28
+ .voidbot/
29
+
30
+ # Editor and OS files
31
+ .DS_Store
memnixa-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,459 @@
1
+ Metadata-Version: 2.4
2
+ Name: memnixa
3
+ Version: 0.1.0
4
+ Summary: A minimal Python agent runtime with gateway and provider compatibility.
5
+ Author: mcallzbl
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: lark-oapi>=1.5.3
8
+ Requires-Dist: prompt-toolkit>=3.0.52
9
+ Requires-Dist: qq-botpy>=1.2.1
10
+ Requires-Dist: rich>=14.3.3
11
+ Description-Content-Type: text/markdown
12
+
13
+ # Memnixa English Docs
14
+
15
+ [Back to Index](README.md) | [中文文档](README.zh-CN.md) | [Architecture](docs/architecture.en.md)
16
+
17
+ ## Overview
18
+
19
+ Memnixa is a Python agent runtime built around three ideas:
20
+
21
+ - Borrow the lightweight execution loop and persistence style from `nanobot`
22
+ - Borrow the provider compatibility and gateway/runtime separation from `openclaw`
23
+ - Keep the first version runnable while supporting CLI, gateway, SQLite persistence, multi-provider config, and per-session model switching
24
+
25
+ ## Current Capabilities
26
+
27
+ - Build runtime context from workspace data, system prompt, tools, and session history
28
+ - Call an OpenAI-compatible `/chat/completions` endpoint
29
+ - Execute tools and feed tool results back into the model loop
30
+ - Run directly as a CLI or as a standalone gateway
31
+ - Let the gateway receive HTTP, Feishu, and QQ traffic
32
+ - Store sessions, messages, and session metadata in SQLite
33
+ - Configure multiple providers and switch models per session
34
+ - Support OpenClaw-style local skills discovery and on-demand loading
35
+ - Support canonical identity binding, with local CLI always treated as the owner
36
+ - Let owner-bound direct messages share context with the local `main` session
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ uv tool install --editable .
42
+ ```
43
+
44
+ After installation:
45
+
46
+ ```bash
47
+ memnixa --help
48
+ ```
49
+
50
+ You can also use the `Makefile` shortcuts:
51
+
52
+ ```bash
53
+ make help
54
+ make sync
55
+ make install
56
+ make run
57
+ ```
58
+
59
+ ## Quick Start
60
+
61
+ 1. Sync the default config into `~/.memnixa/config.json`
62
+
63
+ ```bash
64
+ memnixa config sync
65
+ ```
66
+
67
+ 2. Check or open the config file
68
+
69
+ ```bash
70
+ memnixa config path
71
+ memnixa config open
72
+ ```
73
+
74
+ 3. Add a model after installation
75
+
76
+ The easiest path is to append one provider profile with the built-in command instead of editing JSON by hand.
77
+
78
+ For OpenAI:
79
+
80
+ ```bash
81
+ memnixa config add-model \
82
+ --provider openai_chatgpt \
83
+ --api-key YOUR_OPENAI_API_KEY \
84
+ --model gpt-4.1-mini \
85
+ --id openai \
86
+ --label "OpenAI GPT-4.1 Mini" \
87
+ --set-default
88
+ ```
89
+
90
+ For Zhipu Coding Plan:
91
+
92
+ ```bash
93
+ memnixa config add-model \
94
+ --provider zhipu_coding_plan \
95
+ --api-key YOUR_ZHIPU_API_KEY \
96
+ --model glm-4.7 \
97
+ --id zhipu \
98
+ --label "Zhipu GLM-4.7" \
99
+ --set-default
100
+ ```
101
+
102
+ For a custom OpenAI-compatible endpoint:
103
+
104
+ ```bash
105
+ memnixa config add-model \
106
+ --provider custom_openai_compatible \
107
+ --api-key YOUR_API_KEY \
108
+ --api-base http://localhost:8000/v1 \
109
+ --model your-model-name \
110
+ --id local-model \
111
+ --label "Local Compatible Model" \
112
+ --set-default
113
+ ```
114
+
115
+ After this, the config is written into `~/.memnixa/config.json` or the current project's `config.json`, and Memnixa can connect to that model directly.
116
+
117
+ 4. Optionally adjust the config manually for advanced fields
118
+
119
+ 5. Start the CLI
120
+
121
+ ```bash
122
+ memnixa
123
+ ```
124
+
125
+ 6. Run one message
126
+
127
+ ```bash
128
+ memnixa --message "Summarize this repository"
129
+ ```
130
+
131
+ 7. Start the gateway
132
+
133
+ ```bash
134
+ memnixa gateway
135
+ ```
136
+
137
+ 8. Inspect the current identity inside a channel conversation
138
+
139
+ First, send this to Memnixa from Feishu or QQ:
140
+
141
+ ```text
142
+ /whoami
143
+ ```
144
+
145
+ It returns the identity resolved for the current incoming message, including:
146
+
147
+ - `identity_status`
148
+ - `actor_user_id`
149
+ - `actor_external_id`
150
+ - `actor_is_owner`
151
+ - `session_id`
152
+
153
+ The most important field here is `actor_external_id`, because you will use it for binding.
154
+
155
+ 9. Bind that channel identity to the owner locally
156
+
157
+ For Feishu:
158
+
159
+ ```bash
160
+ memnixa identity bind-owner --channel feishu --external-id YOUR_FEISHU_OPEN_ID
161
+ ```
162
+
163
+ For QQ:
164
+
165
+ ```bash
166
+ memnixa identity bind-owner --channel qq --external-id YOUR_QQ_EXTERNAL_ID
167
+ ```
168
+
169
+ After this, the system layer treats that external identity as the owner. The model does not decide this on its own.
170
+
171
+ 10. Continue chatting from the channel DM or the local CLI
172
+
173
+ Current routing rules:
174
+
175
+ - Local `cli` is always treated as the owner and always enters `main`
176
+ - Direct messages bound to the owner also enter `main`
177
+ - Unbound identities or group messages do not merge into `main`
178
+
179
+ So once you bind a Feishu or QQ direct-message identity to the owner, the local CLI and that direct-message thread share the same context.
180
+
181
+ 11. Inspect SQLite data
182
+
183
+ ```bash
184
+ memnixa data dump
185
+ memnixa data dump --session-id main
186
+ memnixa data export-memory
187
+ ```
188
+
189
+ Common `make` targets:
190
+
191
+ - `make help`
192
+ - `make sync`
193
+ - `make sync-dev`
194
+ - `make install`
195
+ - `make reinstall`
196
+ - `make run`
197
+ - `make gateway`
198
+ - `make test`
199
+ - `make fmt`
200
+ - `make lint`
201
+
202
+ ## Config Shape
203
+
204
+ Key fields:
205
+
206
+ - `default_provider`: default provider id for new sessions
207
+ - `providers`: list of configured model endpoints
208
+ - `providers[].id`: stable id used by `/use <id>`
209
+ - `providers[].preset`: provider preset name
210
+ Built-in presets include `openai_chatgpt`, `zhipu_coding_plan`, `siliconflow`, and `custom_openai_compatible`
211
+ - `providers[].api_key`: provider API key
212
+ - `providers[].api_base`: optional compatible base URL
213
+ - `providers[].model`: model name
214
+ - `providers[].label`: display label
215
+ - `providers[].context_window_tokens`: optional per-model context window limit
216
+ - `providers[].max_output_tokens`: optional per-model output reserve
217
+ - `workspace`: workspace used by tools and context
218
+ - `database_path`: SQLite database path
219
+ - `cli_via`: `local` / `gateway` / `auto`
220
+ - `context_window_tokens`: global default context window
221
+ - `max_output_tokens`: global default output reserve
222
+ - `context_warn_threshold_ratio`: warning threshold when nearing the window
223
+ - `context_compact_threshold_ratio`: threshold that triggers compaction
224
+ - `context_safety_margin_tokens`: conservative input headroom
225
+ - `context_compaction_max_rounds`: maximum preflight compaction rounds
226
+ - `memory.enabled`: enable long-term memory extraction and retrieval
227
+ - `memory.extraction_provider_id`: required when memory is enabled; must point to a valid configured provider id
228
+ - `memory.extraction_timeout_seconds`: dedicated timeout for the memory extraction call
229
+ - `memory.retrieval_limit`: maximum number of memory hits injected or returned per search
230
+ - `memory.max_injected_chars`: maximum characters injected from recalled memory into the model context
231
+
232
+ Channel fields:
233
+
234
+ - `channels.feishu.enabled`
235
+ - `channels.feishu.app_id`
236
+ - `channels.feishu.app_secret`
237
+ - `channels.feishu.group_policy`
238
+ - `channels.qq.enabled`
239
+ - `channels.qq.app_id`
240
+ - `channels.qq.secret`
241
+
242
+ ## Dynamic Model Switching
243
+
244
+ Each provider has a unique id, for example:
245
+
246
+ ```json
247
+ {
248
+ "default_provider": "1",
249
+ "providers": [
250
+ { "id": "1", "preset": "zhipu_coding_plan", "api_key": "...", "model": "glm-4.7" },
251
+ { "id": "2", "preset": "openai_chatgpt", "api_key": "...", "model": "gpt-4.1-mini" },
252
+ { "id": "3", "preset": "siliconflow", "api_key": "...", "model": "deepseek-ai/DeepSeek-V3" }
253
+ ]
254
+ }
255
+ ```
256
+
257
+ Inside a conversation:
258
+
259
+ ```text
260
+ /models
261
+ /use 2
262
+ /whoami
263
+ ```
264
+
265
+ - `/models` lists configured models
266
+ - `/use <id>` switches only the current session
267
+ - `/whoami` shows the identity resolution result for the current message
268
+ - The selected provider id is stored in SQLite session metadata
269
+
270
+ ## Long-Term Memory
271
+
272
+ Memnixa now supports a first-pass long-term memory layer on top of the existing
273
+ session history and compaction summary.
274
+
275
+ Design:
276
+
277
+ - Session history remains the source of short-term continuity
278
+ - `session_compactions` still store compacted session summaries only
279
+ - Long-term memory is stored separately in SQLite `memory_items`
280
+ - Memory is scoped by `self`, `agent`, `user`, or `session`
281
+
282
+ When memory is enabled:
283
+
284
+ - Memnixa injects recalled durable memory as an extra system message before the active turn
285
+ - The model can actively call `memory_search` and `memory_get`
286
+ - After a turn finishes, Memnixa calls the configured memory extraction provider to propose durable facts, then validates and stores them
287
+
288
+ ### Config
289
+
290
+ Add a dedicated memory block:
291
+
292
+ ```json
293
+ {
294
+ "memory": {
295
+ "enabled": true,
296
+ "extraction_provider_id": "8",
297
+ "extraction_timeout_seconds": 20,
298
+ "retrieval_limit": 5,
299
+ "max_injected_chars": 2400
300
+ }
301
+ }
302
+ ```
303
+
304
+ Rules:
305
+
306
+ - `memory.enabled = true` requires `memory.extraction_provider_id`
307
+ - `memory.extraction_provider_id` must match a real id in `providers[]`
308
+ - It is recommended to use a cheaper small model, such as an 8B-class model, as the extractor provider
309
+
310
+ ### Suggested Multi-Provider Setup
311
+
312
+ Use one main model for the normal agent loop and one smaller model for memory extraction:
313
+
314
+ ```json
315
+ {
316
+ "default_provider": "1",
317
+ "providers": [
318
+ {
319
+ "id": "1",
320
+ "preset": "zhipu_coding_plan",
321
+ "api_key": "YOUR_MAIN_KEY",
322
+ "model": "glm-4.7"
323
+ },
324
+ {
325
+ "id": "8",
326
+ "preset": "custom_openai_compatible",
327
+ "api_key": "YOUR_MEMORY_KEY",
328
+ "api_base": "http://localhost:11434/v1",
329
+ "model": "qwen-memory-8b",
330
+ "label": "Memory Extractor 8B"
331
+ }
332
+ ],
333
+ "memory": {
334
+ "enabled": true,
335
+ "extraction_provider_id": "8",
336
+ "extraction_timeout_seconds": 20
337
+ }
338
+ }
339
+ ```
340
+
341
+ ### Memory Tools
342
+
343
+ When memory is enabled, the runtime registers:
344
+
345
+ - `memory_search`: search durable memories relevant to the current request
346
+ - `memory_get`: inspect one memory item returned by `memory_search`
347
+
348
+ ### Export
349
+
350
+ You can export all stored long-term memory items through either interface:
351
+
352
+ ```bash
353
+ memnixa data export-memory
354
+ ```
355
+
356
+ Or through the gateway:
357
+
358
+ ```text
359
+ GET /v1/memory/export
360
+ ```
361
+
362
+ ### What Gets Stored
363
+
364
+ The extractor is expected to produce durable facts such as:
365
+
366
+ - preferences
367
+ - constraints
368
+ - corrections
369
+ - goals
370
+ - project facts
371
+ - self-model facts
372
+ - decisions
373
+ - todos
374
+ - user profile details
375
+
376
+ Sensitive data such as API keys, passwords, cookies, and tokens are filtered and should not be stored as memory items.
377
+
378
+ The `self_model` type is stored under the fixed scope `self:memnixa`. Use it for the agent's stable identity, role, capability boundaries, and long-lived behavior contract. It applies across users, sessions, and workspaces.
379
+
380
+ ## Skills
381
+
382
+ Memnixa now supports a first-pass OpenClaw-style local skills system.
383
+
384
+ Design:
385
+
386
+ - The runtime discovers local skill directories containing `SKILL.md`
387
+ - The system prompt includes only the available skill list, not every skill body
388
+ - The model reads a selected skill on demand through `skill_read`
389
+ - The model can inspect what is available with `skill_list`
390
+
391
+ Currently supported discovery roots, from highest to lowest precedence:
392
+
393
+ - `<workspace>/skills`
394
+ - `<workspace>/.agents/skills`
395
+ - `~/.agents/skills`
396
+ - `~/.memnixa/skills`
397
+
398
+ Each skill directory should contain at least one `SKILL.md`. AgentSkills-style frontmatter is recommended:
399
+
400
+ ```md
401
+ ---
402
+ name: release-checklist
403
+ description: Use when preparing a release checklist or release notes.
404
+ ---
405
+
406
+ # Release Checklist
407
+
408
+ Always confirm version, changelog, and tests.
409
+ ```
410
+
411
+ Runtime skill tools:
412
+
413
+ - `skill_list`: list the currently available skills
414
+ - `skill_read`: read the chosen skill's `SKILL.md` or another bundled reference file
415
+
416
+ ## Identity Binding
417
+
418
+ If you want one Feishu or QQ direct-message conversation to share the owner's context with the local CLI, use this flow:
419
+
420
+ 1. Send `/whoami` in that direct-message conversation
421
+ 2. Copy the returned `actor_external_id`
422
+ 3. Run `memnixa identity bind-owner --channel <channel> --external-id <id>` locally
423
+ 4. Later direct messages from that bound identity are routed into the owner `main` session
424
+
425
+ Available commands:
426
+
427
+ ```bash
428
+ memnixa identity bind-owner --channel feishu --external-id YOUR_FEISHU_OPEN_ID
429
+ memnixa identity bind-owner --channel qq --external-id YOUR_QQ_EXTERNAL_ID
430
+ memnixa identity list
431
+ ```
432
+
433
+ Notes:
434
+
435
+ - `bind-owner` is a local CLI management command used to bind one external identity to the owner
436
+ - `identity list` prints canonical users and stored external identity bindings
437
+ - Binding direct-message identities is recommended before binding any group-side identities
438
+
439
+ ## User Home
440
+
441
+ The default user-level data directory is `~/.memnixa`:
442
+
443
+ - `~/.memnixa/config.json`
444
+ - `~/.memnixa/memnixa.db`
445
+ - `~/.memnixa/cli_history`
446
+
447
+ Without `--config`, config lookup order is:
448
+
449
+ 1. `./config.json`
450
+ 2. `~/.memnixa/config.json`
451
+
452
+ ## Notes
453
+
454
+ - The model layer currently focuses on OpenAI-compatible APIs first
455
+ - Built-in tools are `list_dir`, `read_file`, `write_file`, and `run_command`
456
+ - When session history approaches the context budget, Memnixa compacts older turns into a summary and keeps the recent active tail
457
+ - If the provider returns a direct context overflow error, Memnixa tries to compact and retry automatically
458
+ - `memnixa` starts the interactive CLI by default
459
+ - `memnixa gateway` starts HTTP and any enabled channel listeners