Skip to content

[good first issue-platform adapt-OpenCode] Add durable TencentDB Agent Memory integration - #978

Closed
diqierjia wants to merge 1 commit into
TencentCloud:feat/server_teamfrom
diqierjia:codex/926-opencode-tool-memory
Closed

diqierjia wants to merge 1 commit into
TencentCloud:feat/server_teamfrom
diqierjia:codex/926-opencode-tool-memory

Conversation

@diqierjia

Copy link
Copy Markdown

Description

Adds a native OpenCode adapter for TencentDB Agent Memory with automatic L0/L1/Core/Skill recall, durable completed-turn capture, five native tools, fail-open behavior, and a source-first one-command installation flow that does not depend on an unpublished npm package.

Related Issue

Related to #926

Change Type

  • New adapter
  • Documentation
  • Tests and CI

What is covered

  • Official OpenCode tool() API and lifecycle hooks (chat.message, system transform, session.idle).
  • ISO timestamps and current Memory Gateway v3 envelopes/isolation fields.
  • Automatic cross-session L0 recall plus active conversation, atomic-memory, and Skill tools.
  • Ordered user/text/tool-call/tool-result capture, including multiple queued completed turns.
  • Durable per-pipeline outbox, cross-process filesystem claims, restart recovery, and repeated-idle deduplication.
  • Timeout, configuration validation, sensitive-data redaction, untrusted-memory boundaries, and fail-open logging.
  • English and Chinese user guides plus an OpenCode-readable self-install task.

Verification

Local deterministic checks:

npm run check       -> 9 files, 44 tests passed; typecheck and build passed
npm run e2e:local   -> nativeTools=5, capturedMessages=2,
                       repeatedIdleDeduplicated=true, crossSessionRecall=true
npm run pack:check  -> 54 files; source installer included
npm ls --depth=0    -> clean dependency tree
PowerShell parser   -> scripts/install-from-source.ps1 parsed successfully
git diff --check    -> passed

Isolated new-user acceptance on Windows:

OpenCode            1.18.18
Node.js             24.19.0
Gateway             http://127.0.0.1:18421 (isolated)
OpenCode host       http://127.0.0.1:18422 (isolated XDG config/data/state/cache)
SQLite              separate temporary data directory
Plugin load         passed after restart
L0 capture/search   passed across sessions
Automatic recall    passed in a new session without an explicit tool
L1 extraction       atomic count reached 1
L1 search           tdai_memory_search returned the extracted fact
Credential scan     0 retained occurrences
Cleanup             18421/18422 and temporary config/data removed; existing 18420 untouched

A redacted 15-second H.264 recording and sanitized logs are available for upload with the PR.

Self-test Checklist

  • Code follows repository conventions and uses the MIT license.
  • English and Chinese documentation are included.
  • Unit, contract, package, and real-host isolated acceptance checks pass.
  • No credentials or local test paths are committed.
  • Temporary test processes and data were cleaned up.

Additional Notes

The documented installation path is source-based while the package remains unpublished. Users fill one ignored Gateway .env file, then give OpenCode the checked-in self-install instruction; the installer builds the adapter, starts the local Gateway, installs the private loader, and verifies health without copying model keys into OpenCode configuration.

@Maxwell-Code07

Copy link
Copy Markdown
Collaborator

Thank you for your attention and contribution! We will schedule an internal review of this PR, and we will share any feedback right here.

@diqierjia
diqierjia marked this pull request as ready for review August 14, 2026 09:48
Signed-off-by: diqierjia <jiahongcheng61@gmail.com>
@diqierjia
diqierjia force-pushed the codex/926-opencode-tool-memory branch from e55629c to e73c567 Compare August 20, 2026 07:59
@diqierjia

Copy link
Copy Markdown
Author

Updated on 2026-08-20.

  • Rebased onto the latest feat/server_team (97f9465); the previous merge conflict is resolved. New head: e73c567.
  • Per issue [good first issue] Adapters Wanted: Memory Integration for Agent Frameworks #926, adapters/ is the required standalone directory for framework adapters; this PR keeps the OpenCode implementation under adapters/opencode/.
  • Workflow-equivalent checks passed locally: npm ci, typecheck, 9 test files / 44 tests, build, npm run pack:check (54 package files), and Windows PowerShell installer parsing.
  • Adapter contract E2E passed against an isolated local mock Gateway: 5 native tools, 2 captured messages, repeated-idle deduplication, and cross-session recall.
  • A real standalone Gateway E2E was attempted; this local Node 22.12.0 runtime lacks the node:sqlite builtin required by MemoryCore's SQLite store. The adapter checks themselves pass; the repository workflow uses Node 22.22.2.

@diqierjia

Copy link
Copy Markdown
Author

GitHub Actions has created run 32346604890 for head e73c567, but it is currently action_required with no jobs started because this is a fork PR. The local checks above are the workflow-equivalent results; a maintainer approval is required for GitHub-hosted jobs to execute.

@YOMXXX

YOMXXX commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Review: the durable outbox still has an accepted-write / mark crash window

🔴 Blocking if this PR claims restart-safe duplicate prevention for L0 capture.

The filesystem outbox and cross-process claim correctly serialize live plugin processes, but MemoryGatewayClient.captureL0() sends /v3/conversation/add without the deterministic turn.key (or any other idempotency field). TurnCoordinator.deliver() only sets record.l0 = true after the request resolves.

Failure sequence

  1. The adapter persists a record with l0: false.
  2. /v3/conversation/add succeeds and the Gateway accepts the two L0 messages.
  3. The OpenCode/plugin process terminates before DeliveryStore.mark(key, "l0") is persisted.
  4. On restart, recover() sees the durable record as pending and submits the same turn again.

The local claim file cannot distinguish step 2 from a failed request after the process has died, so this produces duplicated L0 data (and can re-run downstream extraction). The same acknowledgement gap exists for the optional Skill pipeline.

Required change

Please make the adapter depend on the server-side idempotency contract in #1142 (or an equivalent merged Gateway contract), then include the deterministic turn key in the L0 request:

await this.post("/v3/conversation/add", {
  ...this.isolation(turn.sessionId),
  idempotency_key: turn.key,
  messages: [...],
});

The server must treat the identity as tenant-scoped and return the original successful result for an equal-payload replay; a same-key/different-payload replay must fail clearly. Until that contract is available, please document this PR as at-least-once delivery rather than durable deduplication.

Regression coverage

Add a crash-window contract test that simulates:

  • Gateway accepts the L0 request;
  • persistence of the local l0 acknowledgement is interrupted;
  • a new coordinator recovers the pending record.

Assert that both attempts carry the same idempotency_key, and verify against an idempotency-aware Gateway that only one L0 record and one downstream notification result. A request-shape unit test for idempotency_key === turn.key should accompany it.

This is the remaining boundary identified by #1087: a client-side outbox provides delivery recovery, but only the Gateway can make an accepted write retry-safe.

@diqierjia

Copy link
Copy Markdown
Author

The latest changes have been moved to PR #1181. Please continue the review and discussion there. This one can be closed.
对应的新实现已更新到 PR #1181,后续进展请看该 PR。

@aleronwang

Copy link
Copy Markdown
Collaborator

Confirming closure per your 9/1 note, @diqierjia. The outbox ack-gap concern yomxxx raised on 8/27 is fundamentally a "durable delivery needs a server-side idempotency contract" problem — that contract is tracked as #1142, and your rebuild lives on #1181. Closing this in favor of #1181 is the right move.

Two takeaways from this PR that we're preserving as review checkpoints for any future durable-delivery adapter:

  1. Request must carry idempotency_key: turn.key; L0 / atomic write must be a no-op on duplicate key.
  2. Crash-window contract test: gateway-accept → local ack persistence interrupted → restart recover() must not double-submit.

Both are archived at docs/pr-reviews/2026-09-08-batch-review.md in the maintainer tree. Thanks for the thoroughness — see you on #1181.

@diqierjia

Copy link
Copy Markdown
Author

Thanks! See you on #1181.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants