feat(sessions): use GraphQL upsertEntity mutation for structured writes #52

Closed
opened 2026-09-28 02:02:49 +00:00 by rock · 1 comment
Owner

Context

Memory service PR #83 added GraphQL mutations:

Write (direct, no LLM):

mutation {
  upsertEntity(input: {
    project: "session-<uuid>"
    name: "..."
    entityType: EPISODE
    summary: "{...}"
  }) { id created }
}

Write (via LLM extraction):

mutation {
  ingest(input: {
    project: "session-<uuid>"
    source: "..."
    ingest_id: "..."
    records: [...]
  }) { ingestId status }
}

Read (unchanged):

query {
  hybridSearch(query: "...", project: "session-<uuid>", limit: 10) {
    entities { id entityType name summary tCreated }
  }
}

Change required

Update internal/sessions/handler.go:

  1. Replace ingest() REST helper (POST /memory/ingest on poimen-memory:8080) with upsertEntity() GraphQL mutation on poimen-graphql:8090 for all structured writes (session create/patch, milestone create)
  2. Remove memoryURL field — all traffic now goes to graphqlURL
  3. handleCreate → upsertEntity(entityType: SESSION, ...)
  4. handlePatch → upsertEntity(entityType: SESSION, ...) (upsert = idempotent update)
  5. handleCreateMilestone → upsertEntity(entityType: MILESTONE, ...)
  6. Summary field carries JSON blob: {id, name, goal, status, cwd, memory_project, created_at} etc.
  7. Update tests to stub graphql server for mutations

Benefits

  • Structured writes are typed (entityType explicit, not LLM-inferred)
  • Single upstream (graphqlURL) for reads and writes
  • No async LLM extraction lag on create/patch
  • Idempotent upsert aligns with episode dedup requirement

Depends on: memory PR #83 merged

## Context Memory service PR #83 added GraphQL mutations: **Write (direct, no LLM):** ```graphql mutation { upsertEntity(input: { project: "session-<uuid>" name: "..." entityType: EPISODE summary: "{...}" }) { id created } } ``` **Write (via LLM extraction):** ```graphql mutation { ingest(input: { project: "session-<uuid>" source: "..." ingest_id: "..." records: [...] }) { ingestId status } } ``` **Read (unchanged):** ```graphql query { hybridSearch(query: "...", project: "session-<uuid>", limit: 10) { entities { id entityType name summary tCreated } } } ``` ## Change required Update `internal/sessions/handler.go`: 1. Replace `ingest()` REST helper (POST /memory/ingest on poimen-memory:8080) with `upsertEntity()` GraphQL mutation on poimen-graphql:8090 for all structured writes (session create/patch, milestone create) 2. Remove `memoryURL` field — all traffic now goes to `graphqlURL` 3. `handleCreate` → `upsertEntity(entityType: SESSION, ...)` 4. `handlePatch` → `upsertEntity(entityType: SESSION, ...)` (upsert = idempotent update) 5. `handleCreateMilestone` → `upsertEntity(entityType: MILESTONE, ...)` 6. Summary field carries JSON blob: `{id, name, goal, status, cwd, memory_project, created_at}` etc. 7. Update tests to stub graphql server for mutations ## Benefits - Structured writes are typed (entityType explicit, not LLM-inferred) - Single upstream (graphqlURL) for reads and writes - No async LLM extraction lag on create/patch - Idempotent upsert aligns with episode dedup requirement Depends on: memory PR #83 merged
Author
Owner

Harness cycle complete — PR

Routes: backend (coder-impl) → testing (coder-tests) → review×2 → patch round → final SIGN-OFF ✅

Changes

  • Removed REST ingest helper — single upstream (graphqlURL) for all reads+writes
  • Added upsertEntity() mutation helper
  • Added fetchEntitySummary() + read-modify-write in handlePatch (prevents partial-summary data loss)
  • json.Marshal error surfaced as 500 in handleCreate + handleCreateMilestone
  • 29 tests, 85.4% coverage

Both reviewers: SIGN-OFF

## Harness cycle complete — PR **Routes:** backend (coder-impl) → testing (coder-tests) → review×2 → patch round → final SIGN-OFF ✅ ### Changes - Removed REST ingest helper — single upstream (graphqlURL) for all reads+writes - Added `upsertEntity()` mutation helper - Added `fetchEntitySummary()` + read-modify-write in handlePatch (prevents partial-summary data loss) - `json.Marshal` error surfaced as 500 in handleCreate + handleCreateMilestone - 29 tests, 85.4% coverage ### Both reviewers: SIGN-OFF
rock closed this issue 2026-09-28 02:24:13 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: riotpiao-poimen/homelab-frontend#52