Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
3de9d05
feat(MEMMY-418): generate task titles and summaries from episode turns
origami-chen Sep 14, 2026
b103865
fix: keep Codex noise out of turns
origami-chen Sep 15, 2026
3988bf6
fix: pin episode title/summary generation to the displayed UI language
origami-chen Sep 15, 2026
7abac1d
fix: pin episode title/summary generation to the displayed UI language
origami-chen Sep 15, 2026
51f49cb
feat: unify hook and scan L1 capture across agent sources
origami-chen Sep 16, 2026
bc09cea
feat: unify hook and scan L1 capture across agent sources
origami-chen Sep 17, 2026
16d2c05
feat: unify hook and scan L1 capture across agent sources
origami-chen Sep 17, 2026
7de24ec
feat: unify hook and scan L1 capture across agent sources
origami-chen Sep 17, 2026
31e2048
feat: unify hook and scan L1 capture across agent sources
origami-chen Sep 17, 2026
993ca93
Merge pull request #480 from origami-chen/cjq_dev/fix_l1_memory_merge
syzsunshine219 Sep 18, 2026
4459abc
fix(memory): truncate oversized skill embedding text
endxxxx Sep 17, 2026
8bb5a01
fix(memory): chunk oversized embedding inputs
endxxxx Sep 17, 2026
28bbdb5
fix(memory): ignore XML metadata in import titles
endxxxx Sep 17, 2026
2a70ee5
fix(memory): repair resume integrations across agents
endxxxx Sep 17, 2026
02a0522
Merge pull request #472 from endxxxx/fix/import-title-xml-metadata
endxxxx Sep 20, 2026
01a29ac
Merge pull request #466 from endxxxx/fix/skill-embedding-input-trunca…
endxxxx Sep 20, 2026
6bd5e1c
Merge pull request #487 from endxxxx/fix/memmy-resume-agent-integrations
endxxxx Sep 20, 2026
ab5d409
fix(models): prune stale assignments after partial deletion
endxxxx Sep 20, 2026
a35c173
Merge pull request #496 from endxxxx/fix/v1.1.9-model-assignment-cleanup
endxxxx Sep 20, 2026
289e06e
fix(models): preserve custom session model after restart
endxxxx Sep 20, 2026
ba6d527
Merge pull request #499 from endxxxx/fix/v1.1.9-session-custom-model-…
endxxxx Sep 20, 2026
7d3c557
fix(providers): treat kimi-k3 as immutable-temperature model
endxxxx Sep 21, 2026
35eb710
Merge pull request #502 from endxxxx/fix/v1.1.9-kimi-k3-temperature
endxxxx Sep 21, 2026
dd6921b
fix(memory): keep import summaries across agent-source rescans
endxxxx Sep 21, 2026
10e43a6
fix(memory): type import rescan tests for tsc
endxxxx Sep 21, 2026
5bb4524
fix: explain existing Windows install directory
Sep 21, 2026
8c68cae
Merge pull request #503 from endxxxx/fix/v1.1.9-import-summary-rescan…
endxxxx Sep 21, 2026
692e8e5
Merge pull request #504 from Memtensor-AI/bugfix/memmy-493-windows-in…
syzsunshine219 Sep 21, 2026
72bef10
fix: contain long user memory content
Sep 21, 2026
56fe5fb
Merge pull request #508 from Memtensor-AI/bugfix/yunxiao-memmy-446-mu…
syzsunshine219 Sep 21, 2026
6588f74
Merge main into v1.1.9 with conflict resolution
Sep 21, 2026
3f6bc37
fix: complete v1.1.9 Codex conflict resolution
Sep 21, 2026
9ea3205
fix: preserve v1.1.9 ingestion failure statistics
Sep 21, 2026
4c0ccf3
Merge pull request #515 from MemTensor/codex/sync-main-into-v1.1.9-re…
syzsunshine219 Sep 21, 2026
6f30443
fix(memory): sanitize attachment capture summaries
endxxxx Sep 22, 2026
37eaa21
Merge pull request #528 from endxxxx/fix/v1.1.9-capture-summary-sanit…
endxxxx Sep 22, 2026
0794ccc
Let knowledge sharing identify people by user ID, phone, or email, an…
Sep 23, 2026
e3d352e
Merge upstream/v1.1.9 into feature/personal-knowledge-base.
Sep 23, 2026
42e3822
Merge pull request #532 from shinetata/feature/personal-knowledge-base
syzsunshine219 Sep 23, 2026
343a111
merge: sync main into v1.1.9
Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions AgentSourceCore/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# @memmy/agent-source-core

Shared native-turn parsers for Memmy agent-history import. The hook or plugin
path and the offline agent-source scan both read the same on-disk record, emit
the same `SourceTurn`, and submit it through `completeSourceTurn`. Identity,
tool pairing, and session binding are therefore the same on both channels.

This package is a workspace library. `App/backend` and `Memory` each own their
SQLite or filesystem adapters and installers. They must not fork a second copy
of the turn logic.

## Why this package exists

The write contract is shared across agents. A completed native turn has a
stable identity that can be rebuilt from that agent's own files. The realtime
hook or plugin is the primary writer. The offline scan fills gaps when a hook
misses, times out, or never ran. Neither path may invent a second L1 for the
same turn, and a scan must not patch an L1 that already exists.

Agent-specific parsers stay independent because each product persists a
different transcript. Shared helpers stay small: staging, `callId` pairing,
secret redaction at the reader boundary, and `buildSourceTurnRequest`.

A turn is complete only when the native record says so. Missing completion
time, open tools, or an unresolved profile keep the turn pending. `answer` may
be empty when a finished tool already holds the result.

## Architecture

```text
agent disk record
│
▼
AgentSourceCore reader ── SourceTurn (source, profileId, conversationId, turnId, …)
│
├─ hook / plugin ──► POST /api/v1/source-turns/complete channel=hook
└─ offline scan ──► completeSourceTurn channel=agent_source_scan
│
▼
source_turn_captures + Session / Episode / L1
```

| Rule | Meaning |
| --- | --- |
| One durable artifact | Hook and scan reconstruct the turn from the same files. A hook-only id is a locator, not the primary key. |
| One write API | Both channels call `completeSourceTurn`. The scan must not bypass it with `addMemory`. |
| Stable identity | `turnId` and `profileId` come from immutable native fields. Mutable session-level agent names are not a fallback. |
| Shared session | Memory binds `${source}-memory-${conversationId}`. Do not add source-specific session aliases. |
| Tool pairing | Pair calls and results by a stable `callId`. Do not pair by array position. |
| Frozen L1 | A later channel arrival reuses the capture (`existing`). It does not rewrite L1 content. |
| Pending, then fill | If the realtime path cannot read a complete turn, record `pending`. The scan writes the same `turnId`. |

## Current agents

| Source id | Native record | Shared reader | Typical realtime entry |
| --- | --- | --- | --- |
| `codex` | `~/.codex/sessions/**/rollout-*.jsonl` | `readCodexRollout` / `readCodexSourceTurn` | Codex hook |
| `cursor` | Cursor `state.vscdb` composer and bubble rows | `readCursorComposer` / `readCursorSourceTurn` | Cursor hook |
| `claude_code` | `~/.claude/projects/**/*.jsonl` | `readClaudeCodeSession` / `readClaudeCodeSourceTurn` | Claude Code hook |
| `opencode` | OpenCode `session` / `message` / `part` SQLite | `readOpencodeSessions` / `readOpencodeSourceTurn` | OpenCode plugin |
| `openclaw` | OpenClaw transcript SQLite | `readOpenclawTranscripts` / `readOpenclawSourceTurn` | OpenClaw plugin |
| `hermes` | Hermes `state.db` rows | `readHermesSessions` / `readHermesSourceTurn` | Hermes plugin |
| `deepseek_harness` | DeepSeek Harness session event logs | `readDeepseekHarnessEvents` / `readDeepseekHarnessSourceTurn` | DeepSeek Harness plugin |

Skill-only agents (WorkBuddy, Pi, QwenWork) have no hook or offline-scan
artifact that can produce a `SourceTurn`. They are outside this package.

Database-backed readers take an injected query object (`CursorVscdbSource`,
`OpencodeSource`, `HermesSource`, `OpenclawTranscriptSource`). App/backend
uses `node:sqlite`. Memory uses `better-sqlite3`. Only the queries differ.

## Layout

```text
AgentSourceCore/
package.json Workspace package @memmy/agent-source-core
tsconfig.json Production build (excludes tests)
vitest.config.ts Test include: src/tests/**/*.test.ts
README.md
src/
index.ts Public exports plus scan-store message types
source-turn.ts SourceTurn, staging, pairing, request builder
secret-redactor.ts Reader-boundary secret redaction
jsonl-lines.ts JSONL helper for file-backed agents
codex-source-turn.ts
cursor-source-turn.ts
claude-code-source-turn.ts
opencode-source-turn.ts
openclaw-source-turn.ts
hermes-source-turn.ts
deepseek-source-turn.ts
deepseek-session-files.ts
tests/
tsconfig.json noEmit typecheck for tests
*.test.ts
```

Consumers (not in this package):

| Package | Role |
| --- | --- |
| `App/backend/src/adapters/outbound/agent-source/*` | Discovery, driver-specific readers, scan adapters |
| `App/backend/src/adapters/outbound/skill-writer/*` | Hook, plugin, and skill installers |
| `Memory/src/agent-source/adapters/*` | The same readers on the Memory scan runtime |
| `Memory/src/agent-source/integration/*` | Generated hook and plugin scripts |
| `Memory/src/service/session/session-turn-service.ts` | `completeSourceTurn` persistence |

## Adding an agent

Do this only when the agent has a durable record that both the realtime path
and a later scan can read. Prove the following from source, real files, or a
failing test before writing production code:

1. Which file or SQLite tables are the shared artifact.
2. How `conversationId` and `turnId` are computed on both channels.
3. Where tool calls and results get a stable `callId`.
4. Which native fields mean "this turn is finished" versus still open.

Then keep the change slice small:

1. Add `${agent}-source-turn.ts` that yields staged `RawSourceMessage` values
and a `read*SourceTurn` helper for the just-finished turn.
2. Reuse `stageSourceTurnMessages`, `pairSourceToolCalls`, `selectSourceTurn`,
and `buildSourceTurnRequest`. Redact at the reader boundary, not in public
`completeTurn`.
3. Add thin wrappers in App/backend and Memory that open the native store and
inject queries. Do not copy the parser.
4. Point the hook or plugin at the same `read*SourceTurn`. If the turn is not
complete, leave it pending.
5. Point the scan ingest at `completeSourceTurn(..., "agent_source_scan")`.
6. Add parser tests, both-driver tests when the store is SQLite, and a
hook-then-scan / scan-then-hook capture test that expects `stored` then
`existing` with one `source_turn_captures` row.

If a generated Python plugin also builds a `SourceTurn`, it must omit the same
null fields and apply the same redaction as TypeScript. A serialization
mismatch becomes a `conflict`.

### Do not

- Design a second identity, fuzzy time-window dedup, or post-hoc L1 edit.
- Use hook-only request ids, mutable `session.agent`, or "main" as a hidden
profile default when the native record has no agent.
- Treat `time.created` as completion, or complete a turn that still has
pending or running host tools.
- Widen `sanitizeTurnCompleteRequest` / public `completeTurn` to compensate
for one agent.
- Add a shared normalizer framework, move this package under `App/backend`,
or mix formatting and dependency upgrades into the agent slice.
- Assume a new agent matches Codex finish, profile, or tool semantics.
- Bring skill-only agents into this path without a shared disk contract.

## Testing

Run commands from the repository root. Backend and Memory tests build this
package first.

```bash
npm test -w @memmy/agent-source-core
npx tsc -p AgentSourceCore/src/tests/tsconfig.json --noEmit
npm test -w @memmy/backend -- src/adapters/outbound/agent-source src/adapters/outbound/skill-writer
npm test -w @memmy/memory -- tests/agent-source-opencode-reader.test.ts tests/service/session/source-turn-opencode-structured.test.ts tests/service/session/source-turn-capture.test.ts tests/service/session/turn-tool-pairing.test.ts
```

`source-turn-capture.test.ts` can abort the Vitest worker on Node 24 while
closing `better-sqlite3` statements. That is an environment limit. Split the
file by test-name filters if the whole file exits non-zero; do not describe
grouped passes as a stable whole-file run.

Parser tests belong in `src/tests`. They should cover a completed turn, an
incomplete or pending turn, missing identity, and hook/scan identity equality.

## Development

```bash
npm run build -w @memmy/agent-source-core
npm run typecheck -w @memmy/agent-source-core
npm test -w @memmy/agent-source-core
```

`main` and `types` point at `dist/src`. After changing a reader, rebuild this
workspace before running App/backend or Memory tests that import the package.
5 changes: 4 additions & 1 deletion AgentSourceCore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "vitest run"
"test": "vitest run --config ./vitest.config.ts src"
},
"dependencies": {
"fzstd": "^0.1.1"
}
}
Loading
Loading