Skip to content

chore(skills): move KG relationship tools from contacts to memory (#1502) - #1503

Merged
josephfung merged 2 commits into
mainfrom
chore/1502-relationship-tools-to-memory
Jul 23, 2026
Merged

chore(skills): move KG relationship tools from contacts to memory (#1502)#1503
josephfung merged 2 commits into
mainfrom
chore/1502-relationship-tools-to-memory

Conversation

@josephfung

Copy link
Copy Markdown
Owner

Summary

Moves the two knowledge-graph relationship tools — query-relationships and delete-relationship — out of the contacts skill and into memory, where the rest of KG management lives. Closes #1502.

They operate on the general knowledge graph (the entityMemory capability, arbitrary EDGE_TYPES), not on contacts specifically. Spec 01 defines facts and relationships as one graph ("not a separate store"), and all six memory/relationship tools share the same entityMemory capability — entityMemory.deleteEdge() sits right next to entityMemory.storeFact(). Live prod confirms the graph is not contacts-centric: of ~3,312 entity-to-entity edges, only 17% are person↔person, and a third involve no person at all.

Changes

  • git mv both tool dirs to skills/memory/tools/ (100% renames; same directory depth, so handler ../../../../src/... imports are unchanged).
  • contacts SKILL.md drops them (+ description tweak); memory SKILL.md adds them (+ description tweak). Both bumped 0.1.0 → 0.2.0.
  • agents/contacts.yaml keeps them via explicit individual pins — the contacts specialist still manages interpersonal edges, and its resolved tool set is unchanged (behavior-preserving).
  • agents/coordinator.yaml pins the whole memory bundle, so it intentionally gains the two tools (the KG-central agent; documented with a comment).
  • resolved-pins-regression.test.ts gains assertions for the new placement, the preserved contacts set, and the coordinator gain.

Behavior-preserving

No handler, DB schema, or edge-semantics changes. I audited every agent in curia and the six custom agents in curia-deploy: only contacts (preserved) and coordinator (intentional gain) are affected — all other agents pin memory-query/memory-store individually and are untouched. The curia-deploy eval fixtures are name+schema snapshots, unaffected by a directory move, so no deploy PR is needed. Default enrollment is unchanged (these tools were already excluded from registry-defaults.yaml, gated on OpenAI embeddings).

Verification

  • pnpm run typecheck — clean
  • tests/unit/skills/ + tests/unit/agents/ — 897 passing (incl. the startup validator's SKILL.md↔tool-dir check and the new regression assertions)
  • Independent code-review pass verified the loader/resolution invariants

)

query-relationships and delete-relationship operate on the general knowledge
graph (entityMemory, arbitrary EDGE_TYPES), not contacts. They belong with the
rest of KG management — the memory skill — per spec 01 (facts and relationships
are one graph, 'not a separate store') and the shared entityMemory capability.
Prod confirms the graph is not contacts-centric: 83% of entity-to-entity edges
involve a non-person entity, a third involve no person at all.

- git mv both tool dirs to skills/memory/tools/ (same depth; imports unchanged)
- contacts SKILL.md drops them; memory SKILL.md adds them
- contacts agent keeps them via explicit individual pins (resolved set unchanged)
- coordinator gains them via the memory bundle (intentional; KG-central agent)
- resolved-pins regression test asserts the new placement + preserved sets

Behavior-preserving: no handler, DB schema, or edge-semantics changes. Audited
all curia + curia-deploy agents; no other agent's resolved set changes.

Closes #1502

Signed-off-by: Joseph Fung <joseph@josephfung.ca>
@josephfung

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added the orchestration Multi-agent coordination — delegation, specialist agents, skill routing label Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 08d84a6c-9db4-41d8-afd9-11f2a7e0bc49

📥 Commits

Reviewing files that changed from the base of the PR and between 858cad1 and 8d31819.

📒 Files selected for processing (12)
  • CHANGELOG.md
  • agents/contacts.yaml
  • agents/coordinator.yaml
  • skills/contacts/SKILL.md
  • skills/memory/SKILL.md
  • skills/memory/tools/delete-relationship/handler.test.ts
  • skills/memory/tools/delete-relationship/handler.ts
  • skills/memory/tools/delete-relationship/tool.json
  • skills/memory/tools/query-relationships/handler.test.ts
  • skills/memory/tools/query-relationships/handler.ts
  • skills/memory/tools/query-relationships/tool.json
  • tests/unit/agents/resolved-pins-regression.test.ts

📝 Walkthrough

Walkthrough

The relationship query and deletion tools were moved from the contacts skill into the memory skill. Contacts retains access through explicit tool pins, while the coordinator receives them through the memory bundle. New schemas, handlers, and Vitest coverage validate entity resolution, ambiguity handling, edge filtering, direction mapping, timestamp serialisation, idempotent deletion, and edge removal.

Possibly related PRs

Suggested labels: orchestration

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main change: moving the KG relationship tools from contacts to memory.
Description check ✅ Passed The description is clearly related and describes the same tool move, pin changes, tests, and changelog update.
Linked Issues check ✅ Passed The PR meets #1502’s core requirements by relocating the tools to memory, removing them from contacts, updating pins, and preserving behaviour.
Out of Scope Changes check ✅ Passed The changes stay within the requested scope: docs, manifests, pins, tests, and the tool move itself, with no stray tinkering.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
agents/contacts.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

agents/coordinator.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

skills/memory/tools/delete-relationship/tool.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

  • 1 others

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
skills/memory/tools/query-relationships/handler.test.ts (1)

11-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated test scaffolding across both relationship-tool test files. makeEntityMemoryWithStore, makeEntityMemory, and makeCtx are copy-pasted verbatim between the two sibling test files — the same root cause, filed twice, like a form in triplicate nobody asked for.

  • skills/memory/tools/query-relationships/handler.test.ts#L11-L31: extract these three helpers into a shared module (e.g. skills/memory/tools/_shared/test-helpers.ts) and import from there.
  • skills/memory/tools/delete-relationship/handler.test.ts#L11-L31: replace the duplicated helpers with an import from the same shared module.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/memory/tools/query-relationships/handler.test.ts` around lines 11 -
31, Extract makeEntityMemoryWithStore, makeEntityMemory, and makeCtx into a
shared test-helper module, preserving their current behavior and exports. In
skills/memory/tools/query-relationships/handler.test.ts (lines 11-31) and
skills/memory/tools/delete-relationship/handler.test.ts (lines 11-31), remove
the duplicated helper definitions and import the shared helpers instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/memory/tools/query-relationships/handler.ts`:
- Around line 61-69: Update the relationships mapping in the query handler so
the queried side of subject/object uses the resolved entity node’s canonical
label rather than the raw entity input. Preserve the existing direction-based
assignment and use entityNode.label consistently alongside node.label.

---

Nitpick comments:
In `@skills/memory/tools/query-relationships/handler.test.ts`:
- Around line 11-31: Extract makeEntityMemoryWithStore, makeEntityMemory, and
makeCtx into a shared test-helper module, preserving their current behavior and
exports. In skills/memory/tools/query-relationships/handler.test.ts (lines
11-31) and skills/memory/tools/delete-relationship/handler.test.ts (lines
11-31), remove the duplicated helper definitions and import the shared helpers
instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 08d84a6c-9db4-41d8-afd9-11f2a7e0bc49

📥 Commits

Reviewing files that changed from the base of the PR and between 858cad1 and 8d31819.

📒 Files selected for processing (12)
  • CHANGELOG.md
  • agents/contacts.yaml
  • agents/coordinator.yaml
  • skills/contacts/SKILL.md
  • skills/memory/SKILL.md
  • skills/memory/tools/delete-relationship/handler.test.ts
  • skills/memory/tools/delete-relationship/handler.ts
  • skills/memory/tools/delete-relationship/tool.json
  • skills/memory/tools/query-relationships/handler.test.ts
  • skills/memory/tools/query-relationships/handler.ts
  • skills/memory/tools/query-relationships/tool.json
  • tests/unit/agents/resolved-pins-regression.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🧹 Nitpick comments (1)
skills/memory/tools/query-relationships/handler.test.ts (1)

11-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated test scaffolding across both relationship-tool test files. makeEntityMemoryWithStore, makeEntityMemory, and makeCtx are copy-pasted verbatim between the two sibling test files — the same root cause, filed twice, like a form in triplicate nobody asked for.

  • skills/memory/tools/query-relationships/handler.test.ts#L11-L31: extract these three helpers into a shared module (e.g. skills/memory/tools/_shared/test-helpers.ts) and import from there.
  • skills/memory/tools/delete-relationship/handler.test.ts#L11-L31: replace the duplicated helpers with an import from the same shared module.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/memory/tools/query-relationships/handler.test.ts` around lines 11 -
31, Extract makeEntityMemoryWithStore, makeEntityMemory, and makeCtx into a
shared test-helper module, preserving their current behavior and exports. In
skills/memory/tools/query-relationships/handler.test.ts (lines 11-31) and
skills/memory/tools/delete-relationship/handler.test.ts (lines 11-31), remove
the duplicated helper definitions and import the shared helpers instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/memory/tools/query-relationships/handler.ts`:
- Around line 61-69: Update the relationships mapping in the query handler so
the queried side of subject/object uses the resolved entity node’s canonical
label rather than the raw entity input. Preserve the existing direction-based
assignment and use entityNode.label consistently alongside node.label.

---

Nitpick comments:
In `@skills/memory/tools/query-relationships/handler.test.ts`:
- Around line 11-31: Extract makeEntityMemoryWithStore, makeEntityMemory, and
makeCtx into a shared test-helper module, preserving their current behavior and
exports. In skills/memory/tools/query-relationships/handler.test.ts (lines
11-31) and skills/memory/tools/delete-relationship/handler.test.ts (lines
11-31), remove the duplicated helper definitions and import the shared helpers
instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 08d84a6c-9db4-41d8-afd9-11f2a7e0bc49

📥 Commits

Reviewing files that changed from the base of the PR and between 858cad1 and 8d31819.

📒 Files selected for processing (12)
  • CHANGELOG.md
  • agents/contacts.yaml
  • agents/coordinator.yaml
  • skills/contacts/SKILL.md
  • skills/memory/SKILL.md
  • skills/memory/tools/delete-relationship/handler.test.ts
  • skills/memory/tools/delete-relationship/handler.ts
  • skills/memory/tools/delete-relationship/tool.json
  • skills/memory/tools/query-relationships/handler.test.ts
  • skills/memory/tools/query-relationships/handler.ts
  • skills/memory/tools/query-relationships/tool.json
  • tests/unit/agents/resolved-pins-regression.test.ts
🛑 Comments failed to post (1)
skills/memory/tools/query-relationships/handler.ts (1)

61-69: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the resolved node's canonical label, not the raw query string.

subject/object fall back to the raw entity input on the queried side instead of entityNode.label. Since findEntities matches case-insensitively, a query like "jane doe" will echo that exact casing back for one side of the relationship while the other side correctly shows the canonical node.label — an avoidable asymmetry in an otherwise tidy little function. Thrilling, I know.

🔧 Proposed fix
       const relationships = edges.map(({ edge, node, direction }) => ({
         edge_id: edge.id,
-        subject: direction === 'outbound' ? entity : node.label,
+        subject: direction === 'outbound' ? entityNode.label : node.label,
         predicate: edge.type,
-        object: direction === 'outbound' ? node.label : entity,
+        object: direction === 'outbound' ? node.label : entityNode.label,
         direction,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      const relationships = edges.map(({ edge, node, direction }) => ({
        edge_id: edge.id,
        subject: direction === 'outbound' ? entityNode.label : node.label,
        predicate: edge.type,
        object: direction === 'outbound' ? node.label : entityNode.label,
        direction,
        confidence: edge.temporal.confidence,
        last_confirmed_at: edge.temporal.lastConfirmedAt.toISOString(),
      }));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/memory/tools/query-relationships/handler.ts` around lines 61 - 69,
Update the relationships mapping in the query handler so the queried side of
subject/object uses the resolved entity node’s canonical label rather than the
raw entity input. Preserve the existing direction-based assignment and use
entityNode.label consistently alongside node.label.

…ed side

Address CodeRabbit review on #1503.

- Actionable: the query handler used the raw `entity` input for the queried
  side of subject/object while the other side used the resolved node's canonical
  label. Querying "jane doe" for the node "Jane Doe" yielded a mismatched pair.
  Use entityNode.label consistently. Added a regression test (case-insensitive
  resolution makes the raw-vs-canonical gap observable). Patch-bumped tool.json.
- Nitpick: extracted the duplicated in-memory EntityMemory / ToolContext test
  scaffolding shared by the two relationship-tool tests into
  skills/memory/tools/_shared/test-helpers.ts (no tool.json → skill discovery
  skips it). NB: the same scaffolding recurs in ~14 memory tests; a repo-wide
  test factory is the fuller fix, left for a follow-up.

Signed-off-by: Joseph Fung <joseph@josephfung.ca>
@josephfung

Copy link
Copy Markdown
Owner Author

@coderabbitai Both addressed in 45a417e. (Replying at top level since your inline comments failed to post to GitHub.)

Actionable — query-relationships/handler.ts canonical label: fixed. Confirmed real: the queried side of subject/object used the raw entity input while the other side used the resolved node.label, so querying "jane doe" for the node "Jane Doe" returned a mismatched pair. Now uses entityNode.label consistently for the queried side. Added a regression test that exploits case-insensitive resolution to make the raw-vs-canonical gap observable (the existing direction test always queried the exact canonical label, so it never caught this). Patch-bumped the tool to 1.0.1.

Note this was pre-existing behavior — these files were git mv'd unchanged in this PR — but it's a clean, low-risk correctness fix so I took it.

Nitpick — duplicated test scaffolding: extracted. Pulled makeEntityMemoryWithStore / makeEntityMemory / makeCtx into skills/memory/tools/_shared/test-helpers.ts and imported from both relationship-tool tests. (_shared/ has no tool.json, so discoverNestedToolNames skips it — it's not treated as a tool.)

One correction for your model: the helpers weren't verbatim duplicates (the two files differed in helper order and comment wording), and more importantly the same scaffolding recurs across ~14 memory test files, not just these two. So this extraction is a local win for the sibling pair; the fuller fix is a repo-wide EntityMemory test factory, which I've left for a dedicated follow-up rather than expand the scope of a tool-move PR.

Typecheck clean; the two handler suites + startup/loader/regression tests all pass.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@josephfung Acknowledged. The canonical-label regression coverage and local helper extraction address both findings neatly—an unexpectedly competent outcome for a task involving YAML-adjacent machinery.

The clarification is duly noted: the helpers were not verbatim duplicates, and the wider EntityMemory test-factory consolidation belongs in a deliberately scoped follow-up rather than this tool-move PR.


✏️ Learnings added
Learnt from: josephfung
URL: https://github.com/josephfung/curia/pull/1503

Timestamp: 2026-07-23T01:20:15.718Z
Learning: In the TypeScript memory-tool tests, similar EntityMemory/KnowledgeGraphStore/ToolContext scaffolding occurs across roughly 14 files. For the sibling relationship-tool tests, `skills/memory/tools/_shared/test-helpers.ts` provides a suitably scoped local extraction; a repository-wide EntityMemory test factory should be treated as a separate follow-up rather than expanded into an unrelated tool-move change.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@josephfung

Copy link
Copy Markdown
Owner Author

@coderabbitai approve

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Comments resolved and changes approved.

@josephfung
josephfung merged commit 13c22e4 into main Jul 23, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

orchestration Multi-agent coordination — delegation, specialist agents, skill routing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move query-relationships / delete-relationship into the memory skill (core KG management)

1 participant