Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions plugin/pi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ Pi-native compact tools use the same HTTP server path as event capture, includin

Normal memory activity also updates the status bar with short progress/result text such as `🧠 engram · search…` and `🧠 engram · ✓ 4 results`. The extension does not use notifications for normal memory operations.

When a tool call fails because Engram cannot determine which project to use, the status bar shows an actionable label instead of the generic `error`:

| Status bar label | Meaning |
| -------------------------- | ----------------------------------------------------------------------------------------------------- |
| `🧠 repos · ambiguous project` | Pi was started from a directory that contains multiple git repos. Run Pi from inside a single repo, or add `.engram/config.json` with `project_name` to the parent directory. |
| `🧠 repos · error` | A different tool or network error occurred. Expand the tool output in Pi for the full error message. |

Full tool details remain available by expanding the tool output in Pi. If `gentle-engram` or the Engram server is not installed/running, the compact tool reports an error instead of implying memory is available.

## What Pi can remember
Expand Down Expand Up @@ -231,6 +238,7 @@ MCP tool calls still use Engram core's canonical project resolver at call time.
| Existing MCP config was not replaced | Run `pi-engram init --force`. |
| `mem_current_project` reports `/project/current` unsupported | Restart or upgrade the running `engram serve`; check `ENGRAM_URL`/`ENGRAM_BIN`. If `.engram/config.json` exists, Pi uses it as a temporary fallback. |
| `mem_session_summary` cannot detect a project | Ask the user which project should receive the summary, then retry `mem_session_summary` with `project: "name"`. |
| Status bar shows `🧠 repos · ambiguous project` | Pi was started from a parent directory that contains multiple git repos. Run Pi from inside a single repo, or add `.engram/config.json` with `"project_name": "my-project"` to the ambiguous directory. |

## Next steps

Expand Down
7 changes: 6 additions & 1 deletion plugin/pi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ function truncate(str: string, max: number): string {
return str.length > max ? `${str.slice(0, max)}...` : str;
}

function errorStatusLabel(message: string): string {
if (/ambiguous project/i.test(message)) return "ambiguous project";
return "error";
}

function stripPrivateTags(str: string): string {
return redactPrivateTags(str).trim();
}
Expand Down Expand Up @@ -686,7 +691,7 @@ async function executeMemoryTool(toolName: string, params: Record<string, unknow
const details = error instanceof EngramHttpError
? { error: message, http_status: error.status, data: error.data }
: { error: message };
ctx.ui?.setStatus?.("engram", `🧠 ${project} · error`);
ctx.ui?.setStatus?.("engram", `🧠 ${project} · ${errorStatusLabel(message)}`);
return { content: [{ type: "text" as const, text: message }], details, isError: true };
}
}
Expand Down
12 changes: 12 additions & 0 deletions plugin/pi/test/index-source.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,15 @@ test("project detection 404 falls back to local config or diagnostic", () => {
assert.match(source, /error\.status === 404[\s\S]*detectLocalConfigProject\(cwd\) \|\| projectCurrentUnsupportedError\(cwd\)/);
assert.match(source, /does not support \/project\/current/);
});

test("ambiguous_project error maps to actionable status label, not generic 'error'", () => {
// The status bar must NOT show the generic 'error' label for ambiguous project conditions.
// Instead it should show an actionable label such as 'ambiguous project'.
assert.match(source, /function errorStatusLabel\(/);
// Verify the function maps ambiguous project messages to the actionable label
assert.match(source, /ambiguous project/);
// Verify executeMemoryTool uses errorStatusLabel instead of the bare 'error' string
assert.match(source, /errorStatusLabel\(message\)/);
Comment on lines +22 to +26
// The bare '· error' hardcoded string should no longer be present in the catch block
assert.doesNotMatch(source, /setStatus\?\.\("engram",\s*`🧠 \$\{project\} · error`\)/);
});
Loading