Korely

Core operations

Update a memory

Replace a memory's content and re-extract its facts in one call.

When you send a PATCH request, Korely replaces the stored content, then runs the full extraction pipeline on the new text: entity detection, typed fact extraction, and the two-stage contradiction check. Facts produced by the old content that conflict with what the new text says are automatically invalidated and replaced by the incoming facts. Facts that are not contradicted remain active. The response returns the memory with its current fact set so you can confirm what changed without a second round-trip.

Call this whenever an agent learns that previously recorded information is wrong or outdated — for example, a customer corrects a preference mid-session, or a support case is re-categorised after triage. You do not need to delete the memory and re-add it: update it in place and Korely handles the contradiction resolution automatically.

flowchart LR
  A([PATCH /v1/memories/mem_8f2c1a]) --> B[Replace content]
  B --> C[Re-run extraction]
  C --> D{Contradiction check}
  D -->|supersedes old fact| E[Invalidate fct_b91e]
  D -->|no conflict| F[Keep existing facts]
  E --> G([200 OK — updated memory + new facts])
  F --> G
Update pipeline: the new content replaces the stored text, extraction runs, and any contradicted facts are invalidated before the response is returned.

Request

Endpoint: PATCH /v1/memories/{id}. SDK: korely.update(memory_id, *, content, expected_updated_at=None).

ParamTypeNotes
id string Required. The memory ID in the URL path (e.g. mem_8f2c1a).
content string Required. The new plain text or Markdown that fully replaces the existing content. Extraction runs on this text.
expected_updated_at ISO 8601 string Optional. Optimistic concurrency guard. Pass the updated_at value you last read. If the memory has been updated since then, the server returns 409 Conflict and the write is rejected. Omit to skip the check.

Example

from korely_memory import Korely
korely = Korely(api_key="kor_live_...", region="eu")
# Basic update — new content replaces the old one; facts are re-extracted.
result = korely.update(
"mem_8f2c1a",
content="Northwind Hosting costs 55 euro per month after the storage add-on.",
)
print(result.facts)
# [Fact(id="fct_c30a", subject="Northwind Hosting",
# predicate="costs", object="55 euro per month",
# invalidated=["fct_b91e"])]
# Return values are dataclasses — use attribute access (result.facts,
# result.facts[0].predicate), never result["facts"].
# With optimistic concurrency: pass the updated_at you last saw.
# A 409 means someone else wrote to this memory since you read it.
result = korely.update(
"mem_8f2c1a",
content="Northwind Hosting costs 55 euro per month after the storage add-on.",
expected_updated_at="2026-06-07T09:14:00Z",
)

Response

{
"id": "mem_8f2c1a",
"content": "Northwind Hosting costs 55 euro per month after the storage add-on.",
"agent_id": "infra-bot",
"user_id": "customer-4812",
"metadata": { "source": "slack" },
"created_at": "2026-06-07T09:14:00Z",
"updated_at": "2026-06-09T16:02:00Z",
"facts": [
{
"id": "fct_c30a",
"subject": "Northwind Hosting",
"predicate": "costs",
"object": "55 euro per month",
"predicate_family": "financial",
"valid_from": "2026-06-09T16:02:00Z",
"invalidated": ["fct_b91e"]
}
]
}

The invalidated array lists every fact ID that the new content superseded. Those facts still exist in the store — they appear in GET /v1/memories/mem_8f2c1a/history — but they no longer appear in search results or context calls unless you pass include_invalidated=true. If the content change produces no contradictions, invalidated is an empty array and all previous facts remain active.

Response fields

FieldTypeMeaning
id string The memory's permanent identifier. Never changes across updates.
content string The new content as stored after this write.
agent_id string or null The agent namespace this memory belongs to.
user_id string or null The end-user scope. Unchanged by an update.
metadata object The metadata last written via add(). Not modified by update().
created_at ISO 8601 string Original creation timestamp. Never changes.
updated_at ISO 8601 string Timestamp of this write. Use this as the next expected_updated_at if you plan to chain updates.
facts array The full current fact set extracted from the new content. Each item includes id, subject, predicate, object, predicate_family, valid_from, and invalidated (the array of fact IDs this fact supersedes).
facts[].invalidated array of strings IDs of facts from the previous version that this new fact supersedes. Empty when no contradiction was detected.

Errors

StatusCode stringCause
401 invalid_key The Authorization header is missing, malformed, or the key has been revoked.
404 not_found No memory exists for the given id, or it was previously deleted.
409 stale_write expected_updated_at was provided but does not match the server's current updated_at. Another write happened since you last read this memory. Fetch the latest version and retry.
422 invalid_request Request body failed validation — most commonly content is missing or empty. The body is the flat {"code":"invalid_request","message":"content: Field required"} envelope.
429 quota_exceeded Your plan's monthly write quota (including the 10 % grace allowance) has been reached. Body is {"code":"quota_exceeded","message":"..."}; the write-quota 429 carries no Retry-After header. Quota resets at the start of your next billing month.

Notes

  • Not idempotent. Each call to PATCH /v1/memories/{id} re-runs extraction and updates updated_at. Sending the same content twice produces two entries in the memory's history and re-validates facts each time. Use expected_updated_at to guard against unintended repeated writes in retry loops.
  • Scoping is inherited, not settable. The user_id, agent_id, and run_id set at creation cannot be changed by an update. If you need to move a memory to a different scope, delete it and add a new one.
  • Metadata is not updated here. The metadata field is write-once from add(). If you need to attach new metadata, delete and re-add the memory.
  • Write quota. Each update counts as one write against your monthly quota (hobby: 1 k, developer: 5 k, team: 20 k, scale: 75 k). There is a soft +10 % grace above the limit before writes return 429. Reads and searches are never blocked by write quota.
  • Fact history is preserved. Superseded facts are never hard-deleted. They remain visible in GET /v1/memories/{id}/history and in facts queries when include_invalidated=true is set. This lets you audit how knowledge evolved over time.
  • Contradiction detection is automatic. You do not need to locate and delete old facts manually. Pass the corrected content and the two-stage contradiction pipeline identifies and invalidates any conflicting facts within the same user scope.

Related

  • Add a memory — write new content and run the full extraction pipeline from scratch.
  • Delete a memory — soft-delete one memory and invalidate its derived facts.
  • Search memories — retrieve the memories most relevant to a query before deciding whether to update.
  • API reference — full endpoint contract including GET /v1/memories/{id}/history for auditing past versions.