@yugabytedb/meko-mcp 2.2.0 → 2.5.0
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/README.md +168 -61
- package/assets/hooks-handlers/lib/capture-cleanup-cli.js +2134 -0
- package/assets/hooks-handlers/lib/capture-notices.js +224 -14
- package/assets/hooks-handlers/lib/capture-state.js +206 -1
- package/assets/hooks-handlers/lib/capture-status-cli.js +6 -2
- package/assets/hooks-handlers/lib/capture.js +1364 -139
- package/assets/hooks-handlers/lib/checkpoint-timer.js +445 -18
- package/assets/hooks-handlers/lib/journal-bridge.js +218 -0
- package/assets/hooks-handlers/lib/kiro-handler.js +26 -4
- package/assets/hooks-handlers/lib/opencode-handler.js +643 -0
- package/assets/hooks-handlers/lib/opencode-normalizer.js +145 -0
- package/assets/hooks-handlers/lib/terminal-handoff.js +10 -1
- package/assets/opencode-plugin/meko.js +213 -0
- package/assets/scripts/meko-statusline.sh +102 -19
- package/assets/skills/meko-mcp-tools/SKILL.md +59 -16
- package/assets/skills/meko-mcp-tools/references/_sections.md +2 -2
- package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +15 -7
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +275 -19
- package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +7 -4
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +39 -11
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +10 -6
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +44 -29
- package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +79 -14
- package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +47 -1
- package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +6 -39
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +57 -21
- package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +4 -4
- package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +1 -1
- package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +8 -6
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +284 -38
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +32 -10
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +16 -12
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +46 -31
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +79 -14
- package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +69 -1
- package/assets/skills/meko-select-datapack-desktop/SKILL.md +93 -14
- package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +44 -12
- package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +14 -10
- package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +17 -5
- package/bin/create-meko-setup.mjs +186 -30
- package/lib/autofix.mjs +100 -0
- package/lib/browser-login.mjs +495 -0
- package/lib/capture-cleanup.mjs +63 -0
- package/lib/clients/claude-code.mjs +1 -0
- package/lib/clients/codex.mjs +80 -35
- package/lib/clients/common.mjs +7 -0
- package/lib/clients/index.mjs +2 -0
- package/lib/clients/kiro.mjs +5 -5
- package/lib/clients/opencode.mjs +537 -0
- package/lib/config.mjs +68 -1
- package/lib/installer.mjs +18 -2
- package/lib/migrate/adapters/claude-code.mjs +11 -2
- package/lib/migrate/adapters/codex.mjs +9 -2
- package/lib/migrate/adapters/memory-md.mjs +27 -8
- package/lib/migrate/adapters/opencode.mjs +148 -0
- package/lib/migrate/claude-parser.mjs +153 -9
- package/lib/migrate/datapack.mjs +254 -16
- package/lib/migrate/id.mjs +195 -13
- package/lib/migrate/mcp-client.mjs +59 -1
- package/lib/migrate/opencode-normalizer.mjs +132 -0
- package/lib/migrate/orchestrator.mjs +294 -78
- package/lib/migrate/progress.mjs +239 -5
- package/lib/migrate/registry.mjs +72 -0
- package/lib/migrate.mjs +97 -9
- package/lib/validate.mjs +111 -22
- package/package.json +5 -5
- package/scripts/bundle-assets.mjs +4 -0
|
@@ -6,6 +6,47 @@ Every tool example below shows the correct parameters, expected response, and co
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## Retrieval
|
|
10
|
+
|
|
11
|
+
### context_search
|
|
12
|
+
|
|
13
|
+
Default first call for open-ended recall ("what do you know about X?"). One call queries memory, the knowledge base, and the conversation-history cache in parallel.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
context_search(
|
|
17
|
+
query="auth migration decisions",
|
|
18
|
+
agent_id="<your agent_id>",
|
|
19
|
+
conversation_id="<session conversation id>",
|
|
20
|
+
datapack_id="<datapack UUID>")
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Required: `query`, `conversation_id`. `datapack_id` is optional (default datapack if omitted); pass the pinned id when you have one.
|
|
24
|
+
|
|
25
|
+
Response:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
{
|
|
29
|
+
"results": {
|
|
30
|
+
"memory": [{"id": "...", "memory": "...", "score": 0.51, ...}],
|
|
31
|
+
"knowledge_base": [{"id": "...", "chunk_text": "...", "document_id": "...", "distance": 0.31, "match_type": "hybrid", ...}],
|
|
32
|
+
"conversation": {"hits": [...], "thread": [...]}
|
|
33
|
+
},
|
|
34
|
+
"token_savings": {"total_tokens": 49000, "memory": {"tokens_sent": 600, "tokens_saved": 48400}, "tokens_saved": 48400}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- A bucket is `null` only when that source wasn't queried: `force_source` excluded it, or the server couldn't build a query vector for it.
|
|
39
|
+
- An empty bucket is ambiguous: either that source found nothing relevant, or it failed. `context_search` turns a failed source into an empty list and records the error only in the trace. Before you tell the user nothing is stored about X, confirm with `memory_search` or `knowledgebase_search`, which return errors.
|
|
40
|
+
- The conversation bucket is datapack-wide. It returns embedded turns from every user and agent on the datapack, and each hit carries its author's `user_id`. Don't present a hit as this user's own history.
|
|
41
|
+
- `limit` bounds the memory and KB buckets only; the conversation bucket returns up to 10 hits plus a thread of whole turns.
|
|
42
|
+
- The memory bucket has no similarity floor on the default path. The KB bucket drops chunks above an absolute distance cutoff, so it can be empty even when `knowledgebase_search` would return a weak best match.
|
|
43
|
+
- `force_source="memory" | "knowledge_base" | "conversation"` queries only that source. `force_source="memory"` reapplies the `memory_search` similarity floor.
|
|
44
|
+
- `token_savings` is an estimate for reporting. Don't base decisions on it.
|
|
45
|
+
|
|
46
|
+
**Errors:** `conversation_id_required`, `invalid_force_source`, `datapack_access_denied`, and `free_tier_limit_reached` (Free tier: 1,000 lifetime calls). Treat any error as a failed search (SKILL.md operating contract 1).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
9
50
|
## Memory Tools
|
|
10
51
|
|
|
11
52
|
**Critical:** Pass your session's `agent_id` on every memory *write* (from the SessionStart `additionalContext`) — it is stored on the row as attribution. It does **not** filter reads: one `memory_search` / `memory_get_all` returns all of your memories across every `agent_id`. For cross-project facts, write with `agent_id="meko_agent"`.
|
|
@@ -27,7 +68,7 @@ memory_add(agent_id="<your-agent-id>",
|
|
|
27
68
|
|
|
28
69
|
**What NOT to store via memory_add:**
|
|
29
70
|
- Full conversations (use `conversation_create` + `conversation_add_message`)
|
|
30
|
-
- Large documents (use the UI's Datapack → Actions → Add Knowledge upload flow)
|
|
71
|
+
- Large documents (use `knowledgebase_upload_document`, or the UI's Datapack → Actions → Add Knowledge upload flow)
|
|
31
72
|
- Multi-topic dumps (transcripts, mixed logs + decisions) — store **one coherent fact per memory**, with the identifiers a later search will use
|
|
32
73
|
|
|
33
74
|
**Common errors:**
|
|
@@ -46,13 +87,15 @@ memory_search(query="What programming language does the team use?", agent_id="ag
|
|
|
46
87
|
|
|
47
88
|
**Cross-conversation discovery.** `memory_search` returns hits across every stored conversation for the `(datapack_id, user_id)` pair, across all agents (`agent_id` scopes the call's trace, not the results). When a hit references an interesting conversation, follow up with `conversation_list` to browse the associated threads and `conversation_get` to read a specific one — the memory hit's `meko_conversation_id` field is the id to fetch. For a deliberately cross-conversation search leave `run_id` off; to scope a search to a single conversation instead, pass `run_id=<conversation_id>` (it filters on `meko_conversation_id` — see `tools-known-limitations.md`).
|
|
48
89
|
|
|
49
|
-
**Relevance floor.**
|
|
90
|
+
**Relevance floor.** `memory_search` drops results whose raw cosine similarity is below the server's `memory_search_min_score` setting (default `0.2`, tunable at runtime). A query can return fewer results than `limit`, or an empty list, when nothing clears the bar. That means no sufficiently relevant memory, not a broken call.
|
|
50
91
|
|
|
51
92
|
**Response:**
|
|
52
93
|
```json
|
|
53
|
-
{"results": [{"id": "mem-uuid-123", "memory": "Team uses Python for backend", "score": 0.89}]}
|
|
94
|
+
{"results": [{"id": "mem-uuid-123", "memory": "Team uses Python for backend", "score": 0.89, "raw_similarity_score": 0.72}]}
|
|
54
95
|
```
|
|
55
96
|
|
|
97
|
+
`score` is the fused hybrid rank (semantic + keyword + entity boost) used to order results; `raw_similarity_score` is the unfused cosine value. A similarity threshold like `MEMORY_SEARCH_MIN_SCORE` gates on `raw_similarity_score` when it is not null, and falls back to `score` when the raw field is absent or null.
|
|
98
|
+
|
|
56
99
|
**With limit:**
|
|
57
100
|
```
|
|
58
101
|
memory_search(query="user preferences", agent_id="agent", conversation_id="<uuid>", limit=5)
|
|
@@ -64,7 +107,7 @@ memory_search(query="user preferences", agent_id="agent", conversation_id="<uuid
|
|
|
64
107
|
|
|
65
108
|
### memory_get_all
|
|
66
109
|
|
|
67
|
-
**When to use:**
|
|
110
|
+
**When to use:** See the most recent memories (about 20 rows) across every `agent_id`, plus the true `total`. It is not a complete listing and takes no paging arguments (SKILL.md operating contract 2). Use `memory_search` or `memory_get_by_id` for anything older or specific.
|
|
68
111
|
|
|
69
112
|
```
|
|
70
113
|
memory_get_all(agent_id="agent", conversation_id="<uuid>")
|
|
@@ -96,11 +139,13 @@ memory_update(memory_id="mem-uuid-123", text="Updated: Team uses Go for all new
|
|
|
96
139
|
memory_delete_by_id(memory_id="mem-uuid-123", agent_id="agent", conversation_id="<uuid>")
|
|
97
140
|
```
|
|
98
141
|
|
|
142
|
+
`memory_update` and `memory_delete_by_id` return `memory_is_promoted` for a promoted memory, and `not_found` for an id that is missing or belongs to another account.
|
|
143
|
+
|
|
99
144
|
---
|
|
100
145
|
|
|
101
146
|
### memory_delete_all
|
|
102
147
|
|
|
103
|
-
**Destructive.** Deletes all memories
|
|
148
|
+
**Destructive.** Deletes all memories in the passed `agent_id`'s bucket in the datapack. It does not touch other agents' rows, even though `memory_search` shows them; omitting `agent_id` deletes only the `meko_agent` bucket. Pass `run_id=<conversation_id>` to limit it to one conversation. For removing a single memory, prefer `memory_delete_by_id`.
|
|
104
149
|
|
|
105
150
|
```
|
|
106
151
|
memory_delete_all(agent_id="agent", conversation_id="<uuid>")
|
|
@@ -134,9 +179,12 @@ Get exact UUIDs from the `id` field of `memory_search` / `memory_get_all` result
|
|
|
134
179
|
|
|
135
180
|
```
|
|
136
181
|
conversation_create(agent_id="agent",
|
|
137
|
-
title="Debugging the auth middleware"
|
|
182
|
+
title="Debugging the auth middleware",
|
|
183
|
+
datapack_id="<uuid from datapack_search>")
|
|
138
184
|
```
|
|
139
185
|
|
|
186
|
+
`datapack_id` is required whenever no server-side default resolves for the caller. Omitting it in that state returns `{"error": "datapack_id_required"}` and persists nothing; the same contract applies to `conversation_add_message`, `conversation_get`, `conversation_update`, and `conversation_delete`.
|
|
187
|
+
|
|
140
188
|
**Response:**
|
|
141
189
|
```json
|
|
142
190
|
{"id": "conv-uuid-123", "title": "Debugging the auth middleware"}
|
|
@@ -177,8 +225,8 @@ conversation_get(conversation_id="conv-uuid-123", agent_id="agent",
|
|
|
177
225
|
### conversation_list
|
|
178
226
|
|
|
179
227
|
Target the datapack by `datapack_id` (UUID). It's optional — omit it to use the
|
|
180
|
-
pinned/default datapack, or pass the pinned `datapack_id`. Use
|
|
181
|
-
to look up the id.
|
|
228
|
+
pinned/default datapack, or pass the pinned `datapack_id`. Use
|
|
229
|
+
`datapack_search(query="<part of the name>")` to look up the id.
|
|
182
230
|
|
|
183
231
|
```
|
|
184
232
|
conversation_list(datapack_id="<datapack-uuid>", agent_id="agent", limit=20)
|
|
@@ -207,7 +255,7 @@ conversation_delete(conversation_id="conv-uuid-123", agent_id="agent")
|
|
|
207
255
|
|
|
208
256
|
## Knowledge Base Tools
|
|
209
257
|
|
|
210
|
-
|
|
258
|
+
Agents upload files via `knowledgebase_upload_document` and poll `knowledgebase_document_status` for indexing progress; a human uploading through the Cloud UI still uses the datapack's Actions → **Add Knowledge** dialog (PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch) — both paths feed the same index. `knowledgebase_search` queries whatever the KB currently holds. MCP also exposes `knowledgebase_delete_document` for removing a single uploaded file.
|
|
211
259
|
|
|
212
260
|
See `tools-rag-workflow.md` for the decision table.
|
|
213
261
|
|
|
@@ -235,6 +283,184 @@ Populated KBs return results with chunk content and similarity scores. An empty/
|
|
|
235
283
|
|
|
236
284
|
---
|
|
237
285
|
|
|
286
|
+
### knowledgebase_delete_document
|
|
287
|
+
|
|
288
|
+
Permanently deletes ONE knowledge-base file — its chunks and metadata in one transaction, plus a best-effort delete of the stored file. Irreversible: confirm with the user before calling, and take `document_id` from `knowledgebase_search` hits — hits carry `document_id` but NOT a filename, so confirm by echoing the id and the matched chunk text (the documents list API / Meko UI is the authoritative name source). Never guess an id; non-UUID values are rejected.
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
knowledgebase_delete_document(document_id="<uuid from a search hit>",
|
|
292
|
+
conversation_id="<session conversation id>")
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Returns `{"document_id", "chunks_deleted", "s3_deleted"}` — if `s3_deleted` is `false`, say so: the index entries are gone but the stored file may remain. Errors include a numeric `status`: `403` means the user is not the datapack owner, a maintainer, or the file's uploader — report it, don't retry; `409` (`DOCUMENT_PROCESSING`) means the file is still being indexed — wait for indexing to finish, then retry.
|
|
296
|
+
|
|
297
|
+
### knowledgebase_upload_document
|
|
298
|
+
|
|
299
|
+
**When to use:** Get a file's bytes into the datapack's KB for later `knowledgebase_search` retrieval — a file already on disk, or one generated mid-conversation. This tool never touches the file's bytes itself; it only requests a presigned S3 URL. Meko registers the file once it lands, so there's no separate confirm call. **The caller POSTs the file to the returned `url` directly** — multipart/form-data, every key in `fields` as a form field (in order), then the file's bytes last as a field named `"file"`.
|
|
300
|
+
|
|
301
|
+
**Confirm first.** The file goes into the datapack's shared knowledge base, which every member can read. Before calling the tool, tell the user which file and datapack, say the team will see it, and wait for a yes.
|
|
302
|
+
|
|
303
|
+
**You need a shell that can make the POST** (Python, curl, or PowerShell, below). Without one, as in Claude Desktop by default, don't call the tool: point the user at Datapack → Actions → **Add Knowledge**. An issued URL holds its `size` against the storage quota for up to 15 minutes even if nothing is uploaded.
|
|
304
|
+
|
|
305
|
+
**After the user confirms and the tool returns, POST the file in the same turn.** The upload is only half-done once you have `url`/`fields`; nothing else completes it for you.
|
|
306
|
+
|
|
307
|
+
**First, compute `content_hash` and `content_head_base64` — both required — *before* calling the tool at all. `content_head_base64` is compulsory: the tool refuses with `content_head_base64_required` if it's missing or blank, so there's no path that skips the sniff.**
|
|
308
|
+
|
|
309
|
+
Linux:
|
|
310
|
+
```bash
|
|
311
|
+
CONTENT_HASH=$(sha256sum report.pdf | cut -d' ' -f1)
|
|
312
|
+
CONTENT_HEAD_B64=$(head -c 3072 report.pdf | base64 -w0)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
macOS (no `sha256sum` by default — use `shasum`; BSD `base64` has no `-w0`, so strip newlines with `tr` instead):
|
|
316
|
+
```bash
|
|
317
|
+
CONTENT_HASH=$(shasum -a 256 report.pdf | cut -d' ' -f1)
|
|
318
|
+
CONTENT_HEAD_B64=$(head -c 3072 report.pdf | base64 | tr -d '\n')
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Windows PowerShell:
|
|
322
|
+
```powershell
|
|
323
|
+
$ContentHash = (Get-FileHash -Algorithm SHA256 -Path "report.pdf").Hash.ToLower()
|
|
324
|
+
$bytes = [System.IO.File]::ReadAllBytes("report.pdf")
|
|
325
|
+
$head = $bytes[0..([Math]::Min(3071, $bytes.Length - 1))]
|
|
326
|
+
$ContentHeadB64 = [Convert]::ToBase64String($head)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Windows cmd.exe (`certutil` ships built in for the hash — prints it on its own line, strip the header/footer lines before use; cmd.exe has **no** built-in way to take just the first 3072 bytes *and* base64-encode them in one step, so use the PowerShell or Python snippet for `content_head_base64` even in a cmd.exe-driven workflow):
|
|
330
|
+
```bat
|
|
331
|
+
certutil -hashfile report.pdf SHA256
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Python (cross-platform; streams the file so a large one isn't fully loaded into memory, and reuses the same read to build `content_head_base64` too):
|
|
335
|
+
```python
|
|
336
|
+
import hashlib, base64
|
|
337
|
+
|
|
338
|
+
h = hashlib.sha256()
|
|
339
|
+
with open(LOCAL_PATH, "rb") as f:
|
|
340
|
+
head = f.read(3072) # also the content_head_base64 sample
|
|
341
|
+
h.update(head)
|
|
342
|
+
for chunk in iter(lambda: f.read(1 << 20), b""):
|
|
343
|
+
h.update(chunk)
|
|
344
|
+
|
|
345
|
+
content_hash = h.hexdigest()
|
|
346
|
+
content_head_base64 = base64.b64encode(head).decode()
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Then, after the tool call returns `{url, fields}` — a portable snippet (identical on Linux/macOS/Windows, needs `python3` + `requests`), because it loops over whatever `fields` came back instead of hand-enumerating field names, so it can't drift out of sync with what the response actually contains:**
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
import json, requests
|
|
353
|
+
resp = json.loads(RESPONSE_JSON) # the tool's raw JSON string
|
|
354
|
+
if not resp.get("already_uploaded"):
|
|
355
|
+
with open(LOCAL_PATH, "rb") as f:
|
|
356
|
+
r = requests.post(resp["url"], data=resp["fields"], files={"file": (FILENAME, f)})
|
|
357
|
+
r.raise_for_status()
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Linux/macOS, curl (needs `jq`; builds the `-F` flags dynamically from whatever `fields` actually contains — a signer using temporary credentials adds `x-amz-security-token`, and extra policy conditions add their own fields, so a hardcoded field list drops them and S3 answers 403 on a form missing a signed field):**
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
if [ "$(echo "$RESPONSE_JSON" | jq -r '.already_uploaded')" != "true" ]; then
|
|
364
|
+
URL=$(echo "$RESPONSE_JSON" | jq -r '.url')
|
|
365
|
+
FIELDS=()
|
|
366
|
+
while IFS= read -r -d '' key && IFS= read -r -d '' value; do
|
|
367
|
+
FIELDS+=(-F "${key}=${value}")
|
|
368
|
+
done < <(echo "$RESPONSE_JSON" | jq -j '.fields | to_entries[] | (.key, "\u0000", .value, "\u0000")')
|
|
369
|
+
curl -sS --fail "${FIELDS[@]}" -F file=@/local/path/report.pdf "$URL"
|
|
370
|
+
fi
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Windows PowerShell 7+ (`Invoke-RestMethod -Form` takes the whole `fields` object as a hashtable — no per-field enumeration needed at all; use `[ordered]@{}`, not a plain `@{}`, since S3 requires `file` to be the *last* form field and a plain hashtable has no guaranteed enumeration order):**
|
|
374
|
+
|
|
375
|
+
```powershell
|
|
376
|
+
$resp = $json | ConvertFrom-Json
|
|
377
|
+
if (-not $resp.already_uploaded) {
|
|
378
|
+
$form = [ordered]@{}
|
|
379
|
+
$resp.fields.PSObject.Properties | ForEach-Object { $form[$_.Name] = $_.Value }
|
|
380
|
+
$form["file"] = Get-Item "C:\path\to\report.pdf"
|
|
381
|
+
Invoke-RestMethod -Uri $resp.url -Method Post -Form $form
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Windows cmd.exe:** cmd.exe has no built-in JSON parsing, so there's no safe way to build the `-F` flags dynamically from whatever `fields` contains without an extra tool. Rather than hardcode a field list that silently drops fields (e.g. `x-amz-security-token` on temporary credentials, or extra policy conditions) and fail with a confusing S3 403, use the PowerShell or Python snippet above even from a cmd.exe-driven workflow.
|
|
386
|
+
|
|
387
|
+
`size` must be the file's exact length in bytes, and the URL only accepts a body of exactly that size and SHA-256, for 5 minutes. Accepted extensions: pdf, txt, text, md, json, csv, xml, html, htm. `content_head_base64` — the file's first 3072 bytes, or the whole file if shorter, base64-encoded — is **required**: the tool sniffs it against the extension before requesting the URL and rejects an obvious mismatch (e.g. a renamed file) at once as `VALIDATION_ERROR`; a missing or blank one is `content_head_base64_required`. Text files must be UTF-8, because indexing reads UTF-8 only: a Latin-1 or Excel "CSV (Windows)" file is refused with a message to save it as UTF-8 (Excel: "CSV UTF-8"). Samples up to 4096 bytes are accepted and trimmed, so older snippets that send 4096 still work. A mismatch the server catches later surfaces as `state: "abandoned"` from `knowledgebase_document_status`. Idempotent — uploading the same content twice (by SHA-256) returns `already_uploaded: true` with an empty `url` and no `fields`; if that file's indexing never started or failed, the repeat queues it again.
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
knowledgebase_upload_document(
|
|
391
|
+
filename="report.pdf",
|
|
392
|
+
size=42000,
|
|
393
|
+
content_hash="<sha256 hex of the file's bytes>",
|
|
394
|
+
conversation_id="<uuid from conversation_create>",
|
|
395
|
+
content_head_base64="<base64 of the file's first 3072 bytes>",
|
|
396
|
+
agent_id="agent",
|
|
397
|
+
)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Response (fresh upload):**
|
|
401
|
+
```json
|
|
402
|
+
{
|
|
403
|
+
"datapack_id": "...",
|
|
404
|
+
"url": "https://<bucket>.s3.amazonaws.com/",
|
|
405
|
+
"fields": {"key": "...", "policy": "...", "...": "..."},
|
|
406
|
+
"key": "user/datapack/hash/report.pdf",
|
|
407
|
+
"already_uploaded": false
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Response (identical content already uploaded):**
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"datapack_id": "...",
|
|
415
|
+
"url": "",
|
|
416
|
+
"key": "user/datapack/hash/report.pdf",
|
|
417
|
+
"already_uploaded": true,
|
|
418
|
+
"existing_filename": "report.pdf"
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
After a fresh upload, POST the file to `url` yourself (see above), then save `key` (as `document_key`) and poll `knowledgebase_document_status` until `state` is terminal. S3 answers a successful POST with `204`. `400 EntityTooSmall` or `EntityTooLarge` means `size` wasn't the file's exact byte count: call the tool again with the right size and upload through the new URL. The earlier URL can never succeed (it only accepts the wrong size) and expires on its own within 5 minutes.
|
|
423
|
+
|
|
424
|
+
**Common errors:**
|
|
425
|
+
- `conversation_id_required` — `conversation_id` was missing or blank.
|
|
426
|
+
- `datapack_id_required` — no `datapack_id` was given and no tenant default could be resolved.
|
|
427
|
+
- `content_head_base64_required` — `content_head_base64` was missing or blank. Checked after the `filename`/`size`/`content_hash` `VALIDATION_ERROR` checks, but always before a URL is requested — there is no way to skip it.
|
|
428
|
+
- `VALIDATION_ERROR` — missing filename, unsupported extension, missing/malformed `content_hash`, size ≤ 0, invalid or oversized `content_head_base64`, a sample shorter than `min(size, 3072)` bytes or longer than `size` (so `size` is wrong), or the sampled content doesn't match its extension.
|
|
429
|
+
- `FREE_TIER_KB_STORAGE_LIMIT` / `STANDARD_TIER_KB_STORAGE_LIMIT` (`status` 402) — no room left in the storage quota. Tell the user to free space or upgrade instead of retrying: every issued URL holds its `size` against the quota until the file is registered, or for up to 15 minutes if it is never uploaded.
|
|
430
|
+
|
|
431
|
+
Every error from the server also carries `status`, its HTTP status code.
|
|
432
|
+
- `knowledgebase_upload_document_failed` — unexpected error (see `detail`).
|
|
433
|
+
- The actual S3 POST isn't made through this tool, so its own failures (e.g. the body exceeding the cap the URL was signed under) surface to whatever made that call directly, not from this tool.
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
### knowledgebase_document_status
|
|
438
|
+
|
|
439
|
+
**When to use:** Track a file uploaded via `knowledgebase_upload_document` from "waiting for bytes" through to indexed.
|
|
440
|
+
|
|
441
|
+
```
|
|
442
|
+
knowledgebase_document_status(
|
|
443
|
+
document_key="user/datapack/hash/report.pdf",
|
|
444
|
+
conversation_id="<uuid from conversation_create>",
|
|
445
|
+
agent_id="agent"
|
|
446
|
+
)
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Response (still indexing):**
|
|
450
|
+
```json
|
|
451
|
+
{
|
|
452
|
+
"document_key": "user/datapack/hash/report.pdf",
|
|
453
|
+
"filename": "report.pdf",
|
|
454
|
+
"state": "indexing",
|
|
455
|
+
"message": "The file is registered and being indexed.",
|
|
456
|
+
"document": {"status": "PROCESSING", "chunks_processed": 3}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Poll until `state` is `completed` or `failed` (or the pre-registration terminals `abandoned`/`oversized`). `NOT_FOUND` means `document_key` is unknown to this datapack — check it was copied verbatim from the upload response. `datapack_id_required` means no `datapack_id` was given and no tenant default could be resolved.
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
238
464
|
## Artifact Tools
|
|
239
465
|
|
|
240
466
|
### artifact_put
|
|
@@ -319,14 +545,44 @@ For large files use the `local_path` value to read the file with normal file too
|
|
|
319
545
|
|
|
320
546
|
## Datapack Management Tools
|
|
321
547
|
|
|
322
|
-
### datapack_create / datapack_list / datapack_describe
|
|
548
|
+
### datapack_create / datapack_search / datapack_list / datapack_describe
|
|
323
549
|
|
|
324
550
|
```
|
|
325
|
-
datapack_create(name="analytics_prod")
|
|
326
|
-
|
|
327
|
-
|
|
551
|
+
datapack_create(name="analytics_prod", conversation_id="<conversation id>")
|
|
552
|
+
datapack_search(conversation_id="<session conversation id>", query="analytics") # find an id by part of the name
|
|
553
|
+
datapack_search(conversation_id="<session conversation id>", name="analytics_prod") # exact name
|
|
554
|
+
datapack_list(conversation_id="<session conversation id>") # small accounts: every datapack in one array
|
|
555
|
+
datapack_describe(datapack_id="<uuid>", include_status=True, conversation_id="<conversation id>")
|
|
328
556
|
```
|
|
329
557
|
|
|
558
|
+
Find a datapack id with `datapack_search(query=...)`. It returns one page:
|
|
559
|
+
`{"datapacks": [...], "has_more": true, "next_cursor": "<token>", "total": null}`.
|
|
560
|
+
To get the next page, call it again with the same filters and
|
|
561
|
+
`cursor="<next_cursor>"`. `next_cursor` is `""` on the last page, and also
|
|
562
|
+
when an older server has more matches than this page but cannot continue.
|
|
563
|
+
Do not send an empty cursor; ask for a narrower `query` instead. Treat the
|
|
564
|
+
cursor as opaque. Pass `include_total=True` only when you must show "N of M".
|
|
565
|
+
|
|
566
|
+
`datapack_list` still returns one array and is fine for an account with a
|
|
567
|
+
handful of datapacks. For an account that can see more than 1000 datapacks
|
|
568
|
+
(the server default limit) it returns `{"error": "too_many_datapacks", ...}`
|
|
569
|
+
instead; switch to `datapack_search`. If the server has no `datapack_search`
|
|
570
|
+
tool (an older server), use `datapack_list`.
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
`datapack_describe` returns these counts:
|
|
574
|
+
|
|
575
|
+
| Field | Meaning |
|
|
576
|
+
|---|---|
|
|
577
|
+
| `memory_count` | All memories stored in the datapack |
|
|
578
|
+
| `collective_memory_count` | Memories promoted to shared knowledge |
|
|
579
|
+
| `learnings_count` | Memories awaiting a promotion decision |
|
|
580
|
+
| `knowledge_base_file_count` | Uploaded KB documents; `null` if the status endpoint is unreachable |
|
|
581
|
+
| `knowledge_chunk_count` | KB chunks across all documents (for debugging retrieval) |
|
|
582
|
+
| `shared_knowledge_count` | `collective_memory_count + knowledge_base_file_count`; `null` when the file count is `null` |
|
|
583
|
+
|
|
584
|
+
`knowledge_count` is a deprecated alias of `knowledge_chunk_count`. Neither `datapack_search` nor `datapack_list` computes counts; call `datapack_describe` for them.
|
|
585
|
+
|
|
330
586
|
### datapack_update / datapack_delete
|
|
331
587
|
|
|
332
588
|
`datapack_update` renames a datapack, edits its description, and/or opts it in/out of conversation-search embedding. `name`, `description`, and `conversation_search_opt_out` are all optional; pass at least one. If none are provided the tool returns `nothing_to_update` without hitting the API.
|
|
@@ -334,11 +590,11 @@ datapack_describe(datapack_id="<uuid>", include_status=True)
|
|
|
334
590
|
The server refuses to rename the caller's `meko_default_datapack` — a rename call against that datapack returns `"meko_default_datapack cannot be renamed"`. Description edits on the default datapack are still allowed. Passing `description=""` does NOT clear an existing description; clearing is not supported via MCP. Conversation-search embedding is on by default; `conversation_search_opt_out=True` stops future turns from being indexed (already-cached turns are unaffected) and is restricted to the datapack's owner or a maintainer. This is best-effort, not a hard guarantee — a transient database error on the live embed path's opt-out check fails open, so a turn can occasionally still get embedded for an opted-out datapack.
|
|
335
591
|
|
|
336
592
|
```
|
|
337
|
-
datapack_update(datapack_id="<uuid>", name="renamed-datapack")
|
|
338
|
-
datapack_update(datapack_id="<uuid>", description="new description")
|
|
339
|
-
datapack_update(datapack_id="<uuid>", name="x", description="y")
|
|
340
|
-
datapack_update(datapack_id="<uuid>", conversation_search_opt_out=True)
|
|
341
|
-
datapack_delete(datapack_id="<uuid>") # Irreversible!
|
|
593
|
+
datapack_update(datapack_id="<uuid>", name="renamed-datapack", conversation_id="<conversation id>")
|
|
594
|
+
datapack_update(datapack_id="<uuid>", description="new description", conversation_id="<conversation id>")
|
|
595
|
+
datapack_update(datapack_id="<uuid>", name="x", description="y", conversation_id="<conversation id>")
|
|
596
|
+
datapack_update(datapack_id="<uuid>", conversation_search_opt_out=True, conversation_id="<conversation id>")
|
|
597
|
+
datapack_delete(datapack_id="<uuid>", conversation_id="<conversation id>") # Irreversible!
|
|
342
598
|
```
|
|
343
599
|
|
|
344
600
|
### Agent and knowledge-base management (NOT MCP — control-plane only)
|
|
@@ -348,4 +604,4 @@ Agent and KB lifecycle does not ship as MCP tools. If the user asks to create/li
|
|
|
348
604
|
- REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (agents), `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases` (KB sources).
|
|
349
605
|
- Or the Meko Cloud UI at `cloud.mekodata.ai` → Datapacks → agents / knowledge-bases.
|
|
350
606
|
|
|
351
|
-
|
|
607
|
+
Uploading a *file* into an existing KB is not part of that lifecycle restriction — use `knowledgebase_upload_document` (see above) rather than the UI for anything driven from MCP. Agents querying a populated index use `knowledgebase_search`, and can remove a single uploaded file with `knowledgebase_delete_document` — see `tools-rag-workflow.md`.
|
|
@@ -14,7 +14,8 @@ Datapacks are isolated workspaces — each has its own memory store and knowledg
|
|
|
14
14
|
## How to obtain a datapack_id
|
|
15
15
|
|
|
16
16
|
- From `datapack_create` response (`"datapack_id"` field; `"datapack_name"` is also returned)
|
|
17
|
-
- From `
|
|
17
|
+
- From `datapack_search(query="<part of the name>")` or `datapack_search(name="<exact name>")`: each row in `"datapacks"` has `"datapack_id"` and `"datapack_name"`. Page with `cursor="<next_cursor>"` only when that value is non-empty. An empty `next_cursor` means stop and narrow with `query`.
|
|
18
|
+
- From `datapack_list` on a small account, or on an older server without `datapack_search` (each entry has `"datapack_id"` and `"datapack_name"`). An account that can see more than 1000 datapacks (the server default limit) gets `too_many_datapacks` from an unfiltered `datapack_list`; use `datapack_search`.
|
|
18
19
|
- From `datapack_describe` response (same field names)
|
|
19
20
|
|
|
20
21
|
## Datapack lifecycle
|
|
@@ -27,13 +28,15 @@ datapack_create(name="sales_analytics",
|
|
|
27
28
|
-- Returns: {"datapack_id": "dp-uuid-123", "datapack_name": "sales_analytics", ...}
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
Provisioning agents and knowledge-base sources
|
|
31
|
+
Provisioning agents and knowledge-base *sources* (registering/indexing a new source against a datapack) is **not** MCP-exposed. Use the Meko control plane:
|
|
31
32
|
|
|
32
33
|
- **UI**: `app.mekodata.ai` → Datapacks → select datapack → Agents / Knowledge Bases
|
|
33
|
-
- **REST**: `POST /datapacks/:datapack_id/agents`, `POST /datapacks/:datapack_id/knowledge-bases`
|
|
34
|
+
- **REST**: `POST /datapacks/:datapack_id/agents`, `POST /datapacks/:datapack_id/knowledge-bases`
|
|
34
35
|
|
|
35
36
|
If the user asks to set those up mid-session, point them at the control plane rather than inventing an MCP call that will fail.
|
|
36
37
|
|
|
38
|
+
Uploading a *file* into an existing KB is a different, already-MCP-exposed operation — use `knowledgebase_upload_document` (see `tools-cookbook.md`) rather than routing the user to the Add Knowledge UI.
|
|
39
|
+
|
|
37
40
|
### Targeting a specific datapack on subsequent calls
|
|
38
41
|
|
|
39
42
|
```
|
|
@@ -50,7 +53,7 @@ Delete child resources first (agents and KB sources via the control plane), then
|
|
|
50
53
|
```
|
|
51
54
|
# Control-plane (REST or UI): DELETE /datapacks/:datapack_id/knowledge-bases
|
|
52
55
|
# Control-plane (REST or UI): DELETE /datapacks/:datapack_id/agents/sales_agent
|
|
53
|
-
datapack_delete(datapack_id="dp-uuid-123") # MCP-exposed, destructive, irreversible
|
|
56
|
+
datapack_delete(datapack_id="dp-uuid-123", conversation_id="<conversation id>") # MCP-exposed, destructive, irreversible
|
|
54
57
|
```
|
|
55
58
|
|
|
56
59
|
## Common mistake: forgetting datapack_id on memory tools
|
|
@@ -12,6 +12,10 @@ These are current limitations of the Meko MCP tools. Know them upfront to avoid
|
|
|
12
12
|
| Standard | 5,000 | 5,000 | 30,000 |
|
|
13
13
|
| Pro / Enterprise | uncapped | uncapped | uncapped |
|
|
14
14
|
|
|
15
|
+
The Free tier also caps `context_search` and `conversation_add_message` at 1,000 calls each. Embedding turns into the conversation-search cache has its own cap: 2,000 turns on Free and 10,000 on Pro; Standard and Enterprise are uncapped. When that cap is reached, `conversation_add_message` still stores the turn and reports `conversation_search_skipped: "quota_exceeded"`; the turn just won't appear in `context_search`'s conversation bucket.
|
|
16
|
+
|
|
17
|
+
A quota error can arrive with HTTP 403. It is not an authentication failure; don't reconfigure credentials because of it.
|
|
18
|
+
|
|
15
19
|
When the cap is reached the tool returns an error object with code `free_tier_limit_reached` (on every tier; the `tier` field names the capped tier) and **no `results` key**.
|
|
16
20
|
|
|
17
21
|
- **Do not retry** — the cap is lifetime.
|
|
@@ -24,9 +28,23 @@ One call returns roughly the **20 most recent rows**; the response's `total` rep
|
|
|
24
28
|
|
|
25
29
|
## run_id is a read/delete filter on the conversation id, not a write key
|
|
26
30
|
|
|
27
|
-
`memory_search(run_id=<conversation_id>)` and
|
|
31
|
+
`memory_search(run_id=<conversation_id>)` and `memory_delete_all(run_id=<conversation_id>)` filter on the row's `meko_conversation_id`, so passing a conversation id there correctly scopes the call to that one conversation — a supported, reliable way to read a single conversation's memories (read/write/delete scoping was made consistent in MEKO-473/MEKO-474, #271). The one gotcha is on the write side: `memory_add`'s own `run_id` is Langfuse trace metadata only and is **not** persisted as the row's conversation id, so a row written with `memory_add(run_id=X)` is not findable via `memory_search(run_id=X)`. Scope writes with `conversation_id`, then filter the matching read by that same id.
|
|
32
|
+
|
|
33
|
+
`memory_get_all` accepts `run_id` but ignores it, and `conversation_list` has no `run_id`.
|
|
34
|
+
|
|
35
|
+
## memory_delete_all is agent-scoped; memory reads are not
|
|
36
|
+
|
|
37
|
+
`memory_search` and `memory_get_all` return every agent's rows for the user. `memory_delete_all` deletes only rows in the `agent_id` you pass, and an omitted `agent_id` means the `meko_agent` bucket. A `memory_search(run_id=X)` preview can therefore list rows that `memory_delete_all(run_id=X)` leaves in place. To clear rows written by several agents, delete them by id with `memory_delete_by_id`, or call `memory_delete_all` once per `agent_id` shown in the preview.
|
|
38
|
+
|
|
39
|
+
## Viewers can read but not write
|
|
40
|
+
|
|
41
|
+
On a datapack shared with you as a viewer, every conversation and memory write returns `read_only_access` and writes nothing: `conversation_create`, `conversation_add_message`, `conversation_update`, `memory_add`, `memory_update`, `memory_promote`, `artifact_put`, and `track_token_usage`. You can still delete your own memories with `memory_delete_by_id` and `memory_delete_all`, and delete a conversation you started. Searches work as for any other role. `context_search` covers every member's conversations, but for a viewer its conversation results and `conversation_get` return `user_id: null`, so they don't say who wrote a turn. Automatic capture holds a viewer's session and reports `read_only_access` at the next session start.
|
|
28
42
|
|
|
29
|
-
##
|
|
43
|
+
## Promoted memories are read-only through MCP
|
|
44
|
+
|
|
45
|
+
`memory_update` and `memory_delete_by_id` return `memory_is_promoted` for a memory that has been promoted to shared knowledge. Edit or remove promoted content in the Cloud UI Learnings tab.
|
|
46
|
+
|
|
47
|
+
## No MCP tools for index / source / pipeline lifecycle
|
|
30
48
|
|
|
31
49
|
There are no MCP tools to:
|
|
32
50
|
- Delete a vector index
|
|
@@ -34,13 +52,15 @@ There are no MCP tools to:
|
|
|
34
52
|
- Clear stuck work queue entries
|
|
35
53
|
- Reset a failed pipeline
|
|
36
54
|
|
|
37
|
-
KB
|
|
55
|
+
The one exception is a single uploaded **file**: `knowledgebase_delete_document` removes that file's chunks and metadata. KB-**source** deletion (the registered source, not one file) happens via the Meko control plane (REST: `DELETE /datapacks/:datapack_id/knowledge-bases`, or the UI): it unregisters the source from the Meko API but does **not** touch the actual `dist_rag` index, source records, or vector data in the datapack's database.
|
|
38
56
|
|
|
39
57
|
**Workaround:** For stuck or failed indexes, create a new index with a different name. Stale indexes remain in the database until manually cleaned up by an admin.
|
|
40
58
|
|
|
41
|
-
##
|
|
59
|
+
## KB index/source management is UI-only
|
|
60
|
+
|
|
61
|
+
Manually creating a vector index, adding a source to an existing one, or polling raw build status is not exposed via MCP. Use the Cloud UI for those (Datapack → Actions → Add Knowledge).
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
**Adding a file** is a registered MCP tool: call `knowledgebase_upload_document` directly (accepted extensions PDF/TXT/MD/JSON/CSV/XML/HTML, up to 5 MB Free / 50 MB Standard / 60 MB Pro+ per file) to get a presigned URL, then POST the bytes to it yourself; Meko registers and indexes the file once it lands, so no separate index-management call is needed. Confirm with the user first, because every datapack member can read the knowledge base. The Cloud UI's **Add Knowledge** flow (10 files per batch) remains the human-facing path for the same upload.
|
|
44
64
|
|
|
45
65
|
To **query** a built index, use `knowledgebase_search` — it returns both uploaded documents and memories the user promoted from the Learnings tab.
|
|
46
66
|
|
|
@@ -56,7 +76,7 @@ It works **poorly** for:
|
|
|
56
76
|
- Data dictionaries — only partial information extracted
|
|
57
77
|
- Structured schemas — relationships between fields lost
|
|
58
78
|
|
|
59
|
-
**
|
|
79
|
+
**Don't store structured data as memories.** The options are:
|
|
60
80
|
|
|
61
81
|
1. **Write a single narrative summary** as a memory — one call, not row-by-row:
|
|
62
82
|
```
|
|
@@ -65,13 +85,21 @@ It works **poorly** for:
|
|
|
65
85
|
conversation_id="<session conversation_id>",
|
|
66
86
|
text="Customer Complaints dataset has fields: Complaint ID (int PK), Date Submitted (date), Product (text, e.g. Mortgage/Credit Card), Sub-product (text), Issue (text), Company Response (text), State (text, 2-letter code), ZIP Code (text)")
|
|
67
87
|
```
|
|
68
|
-
2. **Upload the
|
|
69
|
-
3. **Tell the user** that structured-data storage via MCP isn't supported and let them decide how to proceed.
|
|
88
|
+
2. **Upload the file itself to the knowledge base** with `knowledgebase_upload_document` — `.csv`, `.json` and the other accepted types go in as they are — and query it with `knowledgebase_search`. (The Cloud UI's **Add Knowledge** flow does the same for a person.)
|
|
70
89
|
|
|
71
90
|
Never ingest CSV row-by-row into memory — each row becomes a fragmented fact with lost context.
|
|
72
91
|
|
|
73
|
-
##
|
|
92
|
+
## Conversation search covers embedded turns only
|
|
93
|
+
|
|
94
|
+
`context_search` searches past conversation turns by meaning in its `conversation` bucket. Only turns embedded into the conversation-search cache are searchable. Turns are embedded by default, except when:
|
|
95
|
+
|
|
96
|
+
- the datapack opted out with `datapack_update(datapack_id=..., conversation_search_opt_out=True, conversation_id=...)`;
|
|
97
|
+
- the account hit the embedding quota (`conversation_search_skipped: "quota_exceeded"`); or
|
|
98
|
+
- the turn was too short to carry content (the server skips trivial turns); or
|
|
99
|
+
- the turn was stored before conversation search was enabled.
|
|
100
|
+
|
|
101
|
+
To find a conversation by other attributes, browse with `conversation_list` and inspect candidates with `conversation_get`.
|
|
74
102
|
|
|
75
|
-
|
|
103
|
+
## Very long conversations can't be read back
|
|
76
104
|
|
|
77
|
-
|
|
105
|
+
When a conversation's trace grows too large for Langfuse, `conversation_get` and `conversation_update` return `{"error": "not_found", "detail": "Conversation <id> not found"}` or time out for that conversation, even though `conversation_add_message` and `conversation_delete` still work. Servers without the MEKO-714 fix instead return `not_found` from `conversation_add_message` on these conversations. If read-back or a write fails with `not_found` on a long conversation that you know exists, report the failure as a server-side limit on that conversation. Don't recreate the conversation under the same id or replay its messages; that makes the trace larger.
|
|
@@ -26,22 +26,26 @@ memory_search(query="What plan does Alice have?", agent_id="support_bot")
|
|
|
26
26
|
Conversations are backed by Langfuse sessions and traces. They preserve full structure: who said what, in what order, with what reasoning.
|
|
27
27
|
|
|
28
28
|
```
|
|
29
|
-
conversation_create(agent_id="support_bot", title="Pricing discussion"
|
|
29
|
+
conversation_create(agent_id="support_bot", title="Pricing discussion",
|
|
30
|
+
datapack_id="<uuid from datapack_search>")
|
|
30
31
|
-- Returns: {"id": "conv-uuid-here"}
|
|
31
32
|
|
|
32
33
|
conversation_add_message(conversation_id="conv-uuid-here", agent_id="support_bot",
|
|
34
|
+
datapack_id="<uuid from datapack_search>",
|
|
33
35
|
input="What are your pricing tiers?",
|
|
34
36
|
output="We offer Starter ($10/mo), Pro ($50/mo), and Enterprise (custom).",
|
|
35
37
|
reasoning="Retrieved pricing page data. No special discounts apply.")
|
|
36
38
|
```
|
|
37
39
|
|
|
40
|
+
`datapack_id` is required for both calls whenever no server-side default resolves for the caller. Omitting it in that state returns `{"error": "datapack_id_required"}` and persists nothing.
|
|
41
|
+
|
|
38
42
|
## Decision Matrix
|
|
39
43
|
|
|
40
44
|
| Signal | Tool |
|
|
41
45
|
|--------|------|
|
|
42
46
|
| "remember that...", "note that...", "keep in mind..." | `memory_add` |
|
|
43
47
|
| "store this conversation", "save this chat" | `conversation_create` + `conversation_add_message` |
|
|
44
|
-
| "what do you know about X?", "recall..." | `
|
|
48
|
+
| "what do you know about X?", "recall..." | `context_search` |
|
|
45
49
|
| "show me our past conversation about..." | `conversation_list` + `conversation_get` |
|
|
46
50
|
| "the user prefers...", "their budget is..." | `memory_add` |
|
|
47
51
|
| "save my query and your response" | `conversation_add_message` |
|
|
@@ -81,7 +85,7 @@ Agents on Cloud Meko have two distinct read surfaces. Pick the right one for the
|
|
|
81
85
|
- **Personal memories** — written by `memory_add`. The `agent_id` records the writer but does not restrict reads; memories are scoped **per-user**, so any of that user's agents can read them via MCP, and no other user can.
|
|
82
86
|
- **Team-shared Shared Knowledge** — arrives two ways:
|
|
83
87
|
1. An agent calls `memory_promote` for exact, user-confirmed memory UUIDs, or the user promotes them from the Cloud UI's Learnings tab. Promotion moves the memories into shared knowledge, strips `user_id`, preserves originating `agent_id` as provenance, and evicts the private mem0 records.
|
|
84
|
-
2. The user uploads a file via Datapack → Actions → **Add Knowledge** in the Cloud UI. PDF/TXT/MD/JSON/
|
|
88
|
+
2. The user uploads a file via Datapack → Actions → **Add Knowledge** in the Cloud UI. PDF/TXT/MD/JSON/CSV/XML/HTML up to 5MB (Free) / 50MB (Standard) / 60MB (Pro+) each.
|
|
85
89
|
|
|
86
90
|
Both show up in `knowledgebase_search`, tagged `metadata_filters.source: "memory"` vs other values so the agent can distinguish provenance in responses.
|
|
87
91
|
|
|
@@ -89,7 +93,7 @@ Agents on Cloud Meko have two distinct read surfaces. Pick the right one for the
|
|
|
89
93
|
|
|
90
94
|
### When the user asks "what do you know about X?"
|
|
91
95
|
|
|
92
|
-
|
|
96
|
+
Call `context_search`. One call returns your personal memories (every agent, no per-agent fan-out), team-shared knowledge, and matching past-conversation turns from anyone on the datapack. If the memory or KB bucket is empty, confirm with `memory_search` or `knowledgebase_search` before saying nothing is there, because `context_search` returns an empty list for a failed source. When you answer, name which surface each finding came from, so the user knows why something is or isn't there.
|
|
93
97
|
|
|
94
98
|
## Memory limitations for structured data
|
|
95
99
|
|
|
@@ -98,7 +102,7 @@ A full sweep is two calls: `memory_search` (all your personal memories, every ag
|
|
|
98
102
|
There is no MCP-side "just put it in a database table" option — raw SQL access isn't part of the MCP surface. Workarounds:
|
|
99
103
|
|
|
100
104
|
1. **Write a single narrative summary** as a memory: `"The Customer Complaints dataset has fields: Complaint ID (int), Date Submitted (date), Product (text), Sub-product (text), Issue (text)..."` — one call, not row-by-row.
|
|
101
|
-
2. **Suggest the user upload the file** via the Cloud UI's Add Knowledge flow if it's a document (
|
|
105
|
+
2. **Suggest the user upload the file** via the Cloud UI's Add Knowledge flow if it's a document (PDF/TXT/MD/JSON/CSV/XML/HTML are supported).
|
|
102
106
|
3. **Never ingest CSV row-by-row** into memory — each row becomes a fragmented fact with lost context.
|
|
103
107
|
|
|
104
108
|
## Memory Storage: automatic, not proactive
|
|
@@ -112,7 +116,7 @@ On Claude Code, do **not** proactively `memory_add` facts the user states — ca
|
|
|
112
116
|
|
|
113
117
|
## Automatic Conversation Capture
|
|
114
118
|
|
|
115
|
-
The plugin captures conversations via three mechanisms — a periodic checkpoint (~10 min), a PreCompact hook, and a SessionEnd hook — storing the full transcript verbatim (user prompts as `input`, assistant text as `output`, tool calls and results as `reasoning`).
|
|
119
|
+
The plugin captures conversations via three mechanisms — a periodic checkpoint (~10 min), a PreCompact hook, and a SessionEnd hook — storing the full transcript verbatim (user prompts as `input`, assistant text as `output`, tool calls and results as `reasoning`). Skill bodies, background-task notifications, and subagent reports that Claude Code writes into the transcript go to `reasoning` of the turn they belong to, never to `input`. A typed `/skill args` is captured with that command as its `input`.
|
|
116
120
|
|
|
117
121
|
Each message's seed is `<conversation_id>:<user_message_uuid>`; all three mechanisms derive the same deterministic trace ID from it, so overlapping captures are idempotent. A shared watermark file tracks what has been saved.
|
|
118
122
|
|