Skip to main content
POST
/
v1
/
memories
/
trigger
Procedural-memory recall (pre-tool-call hook)
curl --request POST \
  --url https://api.production.xtrace.ai/v1/memories/trigger \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '
{
  "action": {
    "tool": "<string>",
    "args": {},
    "output": "<string>"
  },
  "entities": [
    "tool_loop.py",
    "AbortError"
  ],
  "include": [],
  "task": "fix finalize-on-abort in the tool loop",
  "mode": "compose",
  "user_id": "user-123",
  "group_ids": [
    "<string>"
  ],
  "agent_id": "bot-7",
  "app_id": "app-3"
}
'
{
  "object": "search",
  "data": [
    {
      "id": "<string>",
      "text": "<string>",
      "object": "memory",
      "user_id": "<string>",
      "agent_id": "<string>",
      "conv_id": "<string>",
      "app_id": "<string>",
      "group_ids": [
        "<string>"
      ],
      "categories": [
        "<string>"
      ],
      "score": 123,
      "created_at": "2023-11-07T05:31:56Z",
      "updated_at": "2023-11-07T05:31:56Z",
      "details": {
        "fact_type": "<string>",
        "status": "<string>",
        "supersedes": "<string>",
        "source_role": "<string>",
        "episode_id": "<string>",
        "artifact_id": "<string>",
        "artifact_ids": [
          "<string>"
        ],
        "source_event_ids": [
          "<string>"
        ]
      }
    }
  ],
  "context": "<string>",
  "stage_timings": {},
  "context_selection_applied": false
}

Authorizations

x-api-key
string
header
required

Long-lived org API key. Alternative: Authorization: Bearer <key>.

Body

application/json

POST /v1/memories/trigger — procedural-memory recall for a pre-tool-call hook.

An agent calls this right before (or just after) a tool runs to pull the lesson/procedure insights that past sessions recorded about the symbols it's touching — what worked, what didn't. Recall fires on the symbol tripwire, never a semantic query: the server extracts greppable identifiers from action (tool / args / output) or takes them straight from entities, and matches them exactly against directives' trigger_entities.

What comes back is advisory, not a mandate — ranked :class:Memory rows (type: "lesson" | "procedure") in the shared :class:SearchResponse, with the assembled markdown in context under mode="compose".

Scope follows "scope by what you pass": every axis you supply ANDs; org_id is derived server-side from your API key. At least one of user_id / agent_id / app_id / group_ids is required — an unscoped org-wide recall is rejected.

action
ActionContext · object | null

The in-flight tool call the agent is touching right now — the firing signal for recall. Greppable identifiers are extracted server-side (tool name, args values, optional output) and matched exactly against directives' trigger_entities. Supply this or entities.

entities
string[] | null

Escape hatch: pre-extracted greppable identifiers to fire on, bypassing server-side extraction from action. Use when the client already knows the exact symbols the agent is touching.

Example:
["tool_loop.py", "AbortError"]
include
enum<string>[]

Which procedural corpora to recall. Defaults to both (lesson/procedure); subset to restrict (e.g. ["lesson"]).

Available options:
lesson,
procedure
task
string | null

The agent's current goal, in one line. Fed to the relevance gate under mode=compose so it keeps only the insights that help with THIS task.

Maximum string length: 2000
Example:

"fix finalize-on-abort in the tool loop"

mode
enum<string>
default:compose

Pipeline depth selector.

  • compose (default) — symbol-tripwire recall plus an LLM relevance-gate step that keeps only the insights relevant to task, then assembles a markdown block. data carries the gated rows; context carries the markdown. One LLM call.
  • retrieve — recall only. No LLM, cheaper and faster. data carries the matched rows; context is null.
Available options:
retrieve,
compose
user_id
string | null

Scope key. When supplied, applied as an AND pin so reads are tenant-isolated at the storage filter layer. Optional: omit it and pass group_ids to read a shared group across users. At least one of user_id / agent_id / app_id / group_ids is required.

Example:

"user-123"

group_ids
string[]

Optional group tags — another AND scope axis. When non-empty, matched rows must be tagged to at least one of the requested group(s). Group ids are server-generated unguessable handles (see POST /v1/groups); knowing the id is the access boundary.

Example:
["grp_a1b2c3d4e5f6071829304a5b6c7d8e9f"]
agent_id
string | null

Optional agent scope. When set, ANDs onto the active primary scope (whether that's user_id or group_ids): matched rows must also carry this exact agent_id.

Example:

"bot-7"

app_id
string | null

Optional app scope. When set, ANDs onto the active primary scope (like agent_id): matched rows must also carry this exact app_id.

Example:

"app-3"

Response

Successful Response

POST /v1/memories/search response.

data is always populated — both modes return the ranked Memory rows from retrieval. context is populated only when mode='compose' with the assembled markdown block from the LLM context-selection step. stage_timings is always present for per-stage latency attribution.

Note that under mode='compose' the rows in data are the retrieval candidates — a possibly larger set than the subset the LLM selected and wove into context. Useful for showing "everything we found" alongside "what we sent to the model."

mode
enum<string>
required

Echoes the request's mode. compose ⇒ both data and context populated; retrievedata populated and context null.

Available options:
retrieve,
compose
object
string
default:search

Constant discriminator for the resource type.

Allowed value: "search"
data
Memory · object[]

Ranked Memory rows from retrieval. Populated for both modes. Semantic rows (fact/artifact/episode) are ordered by score desc; when include requests lesson/procedure, those directive rows are precision-gated (not vector-scored, score is null) and lead the list ahead of the semantic rows. For mode=compose, the semantic rows are the candidates considered by the context-selection step — a (possibly larger) superset of what ended up in context.

context
string | null

Assembled markdown context block ready for prompt insertion. Populated only when mode=compose; null otherwise.

stage_timings
Stage Timings · object

Per-stage retrieval-pipeline latencies (seconds). Populated in both modes.

context_selection_applied
boolean
default:false

True when the LLM context-selection step ran. False indicates the pipeline fell through (e.g. an empty candidate pool, or context selection disabled by config).