Skip to content
Draft
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ the open-source home for EverMe CLI and agent plugins.

### Plugins

- Fix the agent SDK's dead transport-retry path by distinguishing semantic
reads from non-idempotent writes. `mem_context` and `mem_search` now retry
transient transport failures, HTTP 429, and HTTP 5xx once within the
original timeout budget; memory writes remain single-attempt.
- Add redacted structured SDK/MCP failure diagnostics (`classification`,
`causeCode`, `httpStatus`, `requestId`, `attempts`, `retryable`, and
`elapsedMs`) without exposing request queries, bodies, URLs, or tokens.
- Open-source the plugin workspace under `plugins/`.
- Include `@everme/agent-sdk`, the shared JavaScript client and helper package.
- Include `@everme/memory-mcp`, the generic MCP memory server.
Expand Down
36 changes: 36 additions & 0 deletions docs/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,42 @@ failures return MCP tool errors with `isError: true`; resource-read failures are
thrown as MCP JSON-RPC errors so hosts can distinguish them from successful
markdown content.

### MCP tool error diagnostics

For backward compatibility, a tool failure still returns a short redacted text
line in `content[0].text`. When the failure reaches the MCP adapter through the
agent SDK, the same result also contains `structuredContent.error`:

```json
{
"classification": "http",
"causeCode": "HTTP_503",
"httpStatus": 503,
"requestId": "req_example",
"attempts": 2,
"retryable": true,
"elapsedMs": 152
}
```

The fields are additive and machine-readable:

| Field | Meaning |
|---|---|
| `classification` | Redacted failure class such as `transport`, `timeout`, `http`, `rate_limit`, `auth`, or `application`. |
| `causeCode` | Sanitized transport, HTTP, or EverMe code. It never contains native exception text. |
| `httpStatus` | HTTP status, or `0` when no response was received. |
| `requestId` | Sanitized upstream correlation id when available. |
| `attempts` | Number of actual network attempts made. |
| `retryable` | Whether another read attempt is semantically safe; writes report `false`. |
| `elapsedMs` | Total elapsed time across attempts and retry delay. |

Diagnostics never include the memory query, request body, URL, token, or raw
fetch cause. `mem_context` and `mem_search` are semantic reads even though the
wire method is POST: they retry transient transport failures, HTTP 429, and
HTTP 5xx once within the original timeout budget. Memory writes are
non-idempotent and remain single-attempt.

## MCP Tools

The stable tool names are:
Expand Down
13 changes: 9 additions & 4 deletions plugins/agent-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Without a shared SDK each plugin would reimplement the EverMe wire protocol —
```js
import {
// HTTP layer
createClient, EvermeError, redactError,
createClient, EvermeError, redactError, REQUEST_SEMANTICS,
// Agent-memory realtime writes
saveAgentMemory, AGENT_MEMORY_ROLES, AGENT_MEMORY_TOOL_CALL_TYPES,
// Search / context
Expand Down Expand Up @@ -51,9 +51,12 @@ The envelope every endpoint follows:

## Concurrency / safety contracts

- **Retry**: `execWithRetry` retries transport failures once — but only for GET/HEAD. POST writes (`/mem/agent-memory`) surface the transport error so the caller can decide; retrying a POST after a mid-flight drop can duplicate writes.
- **Request semantics**: GET/HEAD default to `safe_read`. The POST read endpoints `/mem/search` and `/mem/context` opt in explicitly through `REQUEST_SEMANTICS.SAFE_READ`. All other requests are `non_idempotent_write`; a caller cannot make a write retry merely by mislabelling it.
- **Retry**: safe reads make at most two attempts for transient transport failures, HTTP 429, and HTTP 5xx. Both attempts and any `Retry-After` delay share the original timeout budget. A timeout that consumes that budget is surfaced after one attempt rather than starting another full timeout.
- **Write safety**: POST writes such as `/mem/agent-memory` are attempted exactly once. A lost response can hide a server-side success, so blind retry can duplicate memory until every write path has a supported idempotency key.
- **Structured failures**: `EvermeError` includes `classification`, `causeCode`, `httpStatus`, `requestId`, `attempts`, `retryable`, and `elapsedMs`. These fields never include the request URL, query, body, token, or the native fetch cause message.
- **Redaction**: `redactError` scrubs `evt_*`, `emk_*`, `X-Amz-Signature/Credential/Security-Token`, and AWS access key ids. Apply at every error sink before passing to host stderr / model context.
- **Timeouts**: `EvermeError{type:"timeout"}` is thrown so callers can branch on it (e.g. degrade to fallback) rather than retrying as if it were a transport blip. Body-read timeouts are caught too — a stuck body no longer silently parses as `null`.
- **Timeouts**: `EvermeError{type:"timeout", classification:"timeout"}` is thrown so callers can branch on it (e.g. degrade to fallback). Body-read timeouts are caught too — a stuck body no longer silently parses as `null`.

The public CLI/MCP/token redaction contract is documented in
[`../../docs/contracts.md`](../../docs/contracts.md).
Expand All @@ -64,7 +67,9 @@ The public CLI/MCP/token redaction contract is documented in
npm test
```

Covers HTTP envelope, retry gating, config precedence, message normalization, agent-memory shaping.
Covers HTTP envelope, safe-read retry gating, write single-attempt safety,
structured error metadata, config precedence, message normalization, and
agent-memory shaping.

## License

Expand Down
2 changes: 1 addition & 1 deletion plugins/agent-sdk/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* dedicated module rather than reviving the multi-layer buffer.
*/

export { createClient, EvermeError, redactError } from "./src/client.js";
export { createClient, EvermeError, redactError, REQUEST_SEMANTICS } from "./src/client.js";
export {
saveAgentMemory,
convertAgentMessage,
Expand Down
Loading