Skip to content

feat: add agent memory support#33

Merged
sirily11 merged 1 commit into
mainfrom
memory-support
May 21, 2026
Merged

feat: add agent memory support#33
sirily11 merged 1 commit into
mainfrom
memory-support

Conversation

@sirily11
Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI review requested due to automatic review settings May 21, 2026 04:25
@vercel
Copy link
Copy Markdown

vercel Bot commented May 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
rxcode Ready Ready Preview, Comment May 21, 2026 4:25am

Request Review

@sirily11 sirily11 enabled auto-merge (squash) May 21, 2026 04:25
@autopilot-project-manager autopilot-project-manager Bot added the enhancement New feature or request label May 21, 2026
@sirily11 sirily11 merged commit b0ca998 into main May 21, 2026
8 checks passed
@sirily11 sirily11 deleted the memory-support branch May 21, 2026 04:28
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds durable “agent memory” to RxCode (local SwiftData persistence + on-device embeddings) and exposes it via Settings UI and IDE MCP tools so agents can recall/store long-lived preferences/facts/decisions across sessions. Also includes Live Activity healing/end-of-stall handling between desktop ↔ mobile.

Changes:

  • Persist, embed, search, and auto-extract durable memories; inject relevant memories into agent context.
  • Add Settings UI for enabling memory, auto-creation, context injection, and browsing/editing/deleting stored memories.
  • Expose memory CRUD/search as IDE tools and wire “rxcode-ide” MCP bridge/instructions into Codex/Claude paths.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
RxCodeMobile/State/MobileLiveActivityCoordinator.swift Reconciles/ends stalled job Live Activities when sessions update or app foregrounds.
RxCode/Views/SettingsView.swift Adds Memory settings section and sheets for browsing/editing memories.
RxCode/Services/ThreadStore.swift Registers MemoryRecord in SwiftData schema and adds CRUD/touch helpers.
RxCode/Services/OpenAISummarizationService.swift Adds prompt + call path to generate JSON “memory operations”.
RxCode/Services/MobileSyncService.swift Ends orphaned aggregate job activity when desktop has no tracked jobs.
RxCode/Services/MemoryService.swift New actor for embedding-backed memory indexing/search + persistence bridge.
RxCode/Services/MCPService.swift Allows optional Codex config override to inject rxcode-ide MCP server.
RxCode/Services/IDEServer/AppState+IDEToolHandling.swift Adds IDE tool handlers for memory search/add/update/delete.
RxCode/Services/FoundationModelSummarizationService.swift Adds memory-ops generation using the Apple foundation model path.
RxCode/Services/CodexAppServer.swift Adds memory-ops generation + conditional IDE-tools developer instructions.
RxCode/Services/ClaudeService.swift Adds memory-ops generation + expands IDE tool system prompt for memory.
RxCode/App/AppState.swift Adds memory toggles, injection into prompts, auto-extraction pipeline, and parsing/applying ops.
Packages/Sources/RxCodeCore/Models/MemoryRecord.swift New SwiftData model + DTOs for durable memory items and vectors.
Packages/Sources/RxCodeCore/Backend/IDEToolRegistry.swift Registers memory tools and their JSON schemas for MCP exposure.
Comments suppressed due to low confidence (1)

RxCode/App/AppState.swift:5235

  • Same prompt-label duplication applies to the ACP path: memoryContextPromptPrefix(...) adds a "User request:" header, then the skill-context wrapper prefixes another "User request:" when skillContext exists. Consider consolidating so the final prompt contains the header exactly once.
            resolvedPrompt = memoryContextPromptPrefix(for: resolvedMemoryContext, prompt: resolvedPrompt)
            if let skillContext = await marketplace.promptContext(for: .acp) {
                resolvedPrompt = "\(skillContext)\n\nUser request:\n\(resolvedPrompt)"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +654 to +660
func touchMemories(ids: [String], at date: Date = .now) {
guard !ids.isEmpty else { return }
for id in ids {
fetchMemory(id: id)?.touch(at: date)
}
save()
}
Comment on lines +64 to +67
let hits = Array(ranked)
if let store = threadStore {
let ids = hits.map(\.item.id)
await MainActor.run { store.touchMemories(ids: ids) }
Comment thread RxCode/App/AppState.swift
Comment on lines +5214 to 5217
resolvedPrompt = memoryContextPromptPrefix(for: resolvedMemoryContext, prompt: resolvedPrompt)
if let skillContext = await marketplace.promptContext(for: .codex) {
resolvedPrompt = "\(skillContext)\n\nUser request:\n\(prompt)"
resolvedPrompt = "\(skillContext)\n\nUser request:\n\(resolvedPrompt)"
}
Comment on lines +897 to +907
HStack {
Text("Memory")
.font(.system(size: ClaudeTheme.size(13), weight: .semibold))
Spacer()
Button {
editingDraft = MemoryDraft()
} label: {
Label("Add", systemImage: "plus")
}
.help("Add memory")
Button {
Comment on lines +1226 to +1233
Button("Save") {
Task {
await performSave()
dismiss()
}
}
.keyboardShortcut(.defaultAction)
.disabled(draft.content.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
Comment thread RxCode/App/AppState.swift
Comment on lines +3575 to +3612
private static func parseMemoryOperations(_ raw: String) -> [MemoryOperation] {
let trimmed = stripJSONFence(raw)
guard let range = jsonArrayRange(in: trimmed) else { return [] }
let json = String(trimmed[range])
guard let data = json.data(using: .utf8),
let array = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]]
else { return [] }
return array.compactMap { entry in
guard let action = entry["action"] as? String else { return nil }
return MemoryOperation(
action: action.lowercased(),
id: entry["id"] as? String,
content: entry["content"] as? String,
kind: entry["kind"] as? String,
scope: entry["scope"] as? String
)
}
}

private static func stripJSONFence(_ raw: String) -> String {
var text = raw.trimmingCharacters(in: .whitespacesAndNewlines)
if text.hasPrefix("```") {
var lines = text.components(separatedBy: "\n")
if !lines.isEmpty { lines.removeFirst() }
if lines.last?.trimmingCharacters(in: .whitespacesAndNewlines) == "```" {
lines.removeLast()
}
text = lines.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines)
}
return text
}

private static func jsonArrayRange(in text: String) -> Range<String.Index>? {
guard let start = text.firstIndex(of: "["),
let end = text.lastIndex(of: "]"),
start <= end else { return nil }
return start..<text.index(after: end)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants