feat(tegg): [1/3] add agent-runtime package with OSS-backed store#5818
feat(tegg): [1/3] add agent-runtime package with OSS-backed store#5818jerryliang64 wants to merge 15 commits intoeggjs:nextfrom
Conversation
Add @eggjs/agent-runtime package providing an AgentStore interface and ObjectStorageClient abstraction for persistent agent state management. - Self-contained types (AgentObjectType, RunStatus, InputMessage, etc.) - AgentStore interface for thread/run CRUD operations - ObjectStorageClient interface for pluggable storage backends - OSSObjectStorageClient adapter for Alibaba Cloud OSS (oss-client) - OSSAgentStore implementation with prefix-based key isolation - Error types: AgentNotFoundError (404), AgentConflictError (409) - Full test coverage using inline MapStorageClient Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new agent runtime package designed to manage agent-related data, such as threads and runs, with a flexible storage abstraction. It enables the use of Alibaba Cloud OSS as a backend for persistent storage, providing a scalable and robust solution for handling agent state. The changes lay the groundwork for integrating advanced agent capabilities within the Egg.js tegg framework, ensuring data integrity and proper error handling. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new tegg/core/agent-runtime package: typed AgentStore and ObjectStorageClient interfaces, OSS-backed implementations (OSSAgentStore, OSSObjectStorageClient), error types, utilities, comprehensive tests, package manifest, workspace/tsconfig references, and Vitest config. (26 words) Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Store as OSSAgentStore
participant OSS as OSSObjectStorageClient
Client->>Store: createThread(metadata)
Store->>OSS: put("prefix/thread/{threadId}", JSON(threadRecord))
OSS-->>Store: OK
Client->>Store: createRun(input, threadId, config)
Store->>OSS: put("prefix/run/{runId}", JSON(runRecord))
OSS-->>Store: OK
Client->>Store: appendMessages(threadId, messages)
Store->>OSS: get("prefix/thread/{threadId}")
OSS-->>Store: JSON(threadRecord)
Store->>OSS: put("prefix/thread/{threadId}", JSON(updatedThreadRecord))
OSS-->>Store: OK
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## next #5818 +/- ##
==========================================
+ Coverage 85.23% 85.29% +0.06%
==========================================
Files 650 655 +5
Lines 12522 12591 +69
Branches 1435 1447 +12
==========================================
+ Hits 10673 10740 +67
- Misses 1729 1731 +2
Partials 120 120 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request introduces the new @eggjs/agent-runtime package, which provides a store abstraction for agent threads and runs, with an initial implementation backed by Aliyun OSS. The code is well-structured with clear separation of concerns between the store logic, storage client interface, and the OSS-specific implementation.
My review focuses on improving the robustness and correctness of the new package. Key feedback points include:
- Relaxing the strict Node.js engine requirement in
package.jsonfor better compatibility. - Adding data validation after parsing JSON from the object store to prevent runtime errors from malformed data.
- Addressing potential race conditions in update operations (
appendMessagesandupdateRun) by using atomic/conditional writes. - Improving the type safety of error handling in the
OSSObjectStorageClient.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
tegg/core/agent-runtime/src/index.ts (1)
6-6: Consider whetherutilsshould be part of the public API.Re-exporting
utils.tsexposes internal utilities likenowUnix()as part of the package's public surface. If these are intended only for internal use, consider either:
- Removing this export from the barrel
- Keeping them unexported and importing directly within the package
If consumers need these utilities, this export is fine.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tegg/core/agent-runtime/src/index.ts` at line 6, The barrel file currently re-exports internal utilities via the line exporting './utils.ts', which exposes functions like nowUnix() publicly; decide whether they should be internal and if so remove that export from the barrel (keep utils.ts imports internal to modules that need them) or explicitly mark/rename and document them if they must remain public; update the export line in index.ts accordingly and adjust any internal imports that previously relied on the barrel to import directly from './utils.ts' (or alternatively add explicit named exports for only the intended public symbols).tegg/core/agent-runtime/src/OSSAgentStore.ts (1)
60-64: Read-modify-write pattern lacks atomicity guarantees.Both
appendMessagesandupdateRunuse a get-then-put pattern that can lose concurrent updates. If two calls toappendMessageshappen simultaneously, one message set may be lost.This is an inherent limitation when using object storage without conditional writes (ETags/versioning). Consider documenting this behavior, or if OSS supports conditional puts, implementing optimistic concurrency control.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tegg/core/agent-runtime/src/OSSAgentStore.ts` around lines 60 - 64, The read-modify-write in appendMessages (and similarly updateRun) can lose concurrent updates; either document this limitation or implement optimistic concurrency: modify appendMessages to read the thread via getThread(), capture a version/ETag (or a lastModified field) from the stored object, merge messages, then use a conditional put (client.put with an If-Match/expected ETag or OSS conditional put API) or a compare-and-swap loop with retries to ensure the put fails if the stored version changed; if the OSS client has no conditional-put support, add retry-on-conflict by re-reading and merging up to N attempts or add explicit documentation in OSSAgentStore that concurrent updates are not atomic. Ensure you reference and change the methods appendMessages, updateRun, getThread, threadKey and the use of client.put accordingly.tegg/core/agent-runtime/test/OSSAgentStore.test.ts (1)
39-40: Timestamp assertions may be fragile under clock drift.The assertions
thread.created_at <= Math.floor(Date.now() / 1000)could theoretically fail if the test execution spans a second boundary or under clock adjustments. This is a minor concern since it's unlikely in practice, but you could make it more robust by capturing the timestamp before the operation.it('should create a thread', async () => { + const beforeCreate = Math.floor(Date.now() / 1000); const thread = await store.createThread(); assert(thread.id.startsWith('thread_')); assert.equal(thread.object, 'thread'); assert(Array.isArray(thread.messages)); assert.equal(thread.messages.length, 0); assert(typeof thread.created_at === 'number'); - assert(thread.created_at <= Math.floor(Date.now() / 1000)); + assert(thread.created_at >= beforeCreate && thread.created_at <= Math.floor(Date.now() / 1000)); });Also applies to: 107-108
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tegg/core/agent-runtime/test/OSSAgentStore.test.ts` around lines 39 - 40, Capture the current timestamp immediately before creating the thread (e.g., const before = Math.floor(Date.now() / 1000)) and again immediately after (const after = Math.floor(Date.now() / 1000)), then replace the fragile assertion on thread.created_at with a range check like thread.created_at >= before && thread.created_at <= after; update both occurrences that assert thread.created_at (the checks around thread.created_at in OSSAgentStore.test.ts) to use this before/after range so the test is robust against clock boundaries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tegg/core/agent-runtime/tsconfig.json`:
- Around line 1-3: Add "emitDecoratorMetadata": true under a "compilerOptions"
object in this package tsconfig so tegg DI can infer types; if "compilerOptions"
is not present, create it and set "emitDecoratorMetadata": true (and ensure
"experimentalDecorators": true is enabled or inherited). Update the JSON in the
tsconfig that currently only extends "../../../tsconfig.json" to include these
compilerOptions while keeping the existing extends entry.
---
Nitpick comments:
In `@tegg/core/agent-runtime/src/index.ts`:
- Line 6: The barrel file currently re-exports internal utilities via the line
exporting './utils.ts', which exposes functions like nowUnix() publicly; decide
whether they should be internal and if so remove that export from the barrel
(keep utils.ts imports internal to modules that need them) or explicitly
mark/rename and document them if they must remain public; update the export line
in index.ts accordingly and adjust any internal imports that previously relied
on the barrel to import directly from './utils.ts' (or alternatively add
explicit named exports for only the intended public symbols).
In `@tegg/core/agent-runtime/src/OSSAgentStore.ts`:
- Around line 60-64: The read-modify-write in appendMessages (and similarly
updateRun) can lose concurrent updates; either document this limitation or
implement optimistic concurrency: modify appendMessages to read the thread via
getThread(), capture a version/ETag (or a lastModified field) from the stored
object, merge messages, then use a conditional put (client.put with an
If-Match/expected ETag or OSS conditional put API) or a compare-and-swap loop
with retries to ensure the put fails if the stored version changed; if the OSS
client has no conditional-put support, add retry-on-conflict by re-reading and
merging up to N attempts or add explicit documentation in OSSAgentStore that
concurrent updates are not atomic. Ensure you reference and change the methods
appendMessages, updateRun, getThread, threadKey and the use of client.put
accordingly.
In `@tegg/core/agent-runtime/test/OSSAgentStore.test.ts`:
- Around line 39-40: Capture the current timestamp immediately before creating
the thread (e.g., const before = Math.floor(Date.now() / 1000)) and again
immediately after (const after = Math.floor(Date.now() / 1000)), then replace
the fragile assertion on thread.created_at with a range check like
thread.created_at >= before && thread.created_at <= after; update both
occurrences that assert thread.created_at (the checks around thread.created_at
in OSSAgentStore.test.ts) to use this before/after range so the test is robust
against clock boundaries.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (13)
pnpm-workspace.yamltegg/core/agent-runtime/package.jsontegg/core/agent-runtime/src/AgentStore.tstegg/core/agent-runtime/src/OSSAgentStore.tstegg/core/agent-runtime/src/OSSObjectStorageClient.tstegg/core/agent-runtime/src/ObjectStorageClient.tstegg/core/agent-runtime/src/errors.tstegg/core/agent-runtime/src/index.tstegg/core/agent-runtime/src/utils.tstegg/core/agent-runtime/test/OSSAgentStore.test.tstegg/core/agent-runtime/tsconfig.jsontegg/core/agent-runtime/vitest.config.tstsconfig.json
Verify Buffer encoding on put, content decoding on get (Buffer and non-Buffer paths), null content handling, NoSuchKey → null mapping, and re-throw of unexpected errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tegg/core/agent-runtime/test/OSSObjectStorageClient.test.ts`:
- Line 5: Update the ESM import specifier to use the compiled .js extension:
replace the import of OSSObjectStorageClient from
'../src/OSSObjectStorageClient.ts' with '../src/OSSObjectStorageClient.js' so
that the test file imports the runtime JS module (referencing the
OSSObjectStorageClient export/class in the test) and satisfies the project
tsconfig verbatimModuleSyntax requirement.
- Use safer NoSuchKey error check with type narrowing - Add race condition comments to appendMessages/updateRun - Add test coverage for AgentConflictError, newMsgId, init/destroy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tegg/core/agent-runtime/src/OSSObjectStorageClient.ts`:
- Line 3: Replace all local ESM import extensions from ".ts" to ".js" in this
package: update the import statement in OSSObjectStorageClient.ts (the import of
ObjectStorageClient) and the corresponding imports/exports referenced in
OSSAgentStore.ts and the package index (and any test files) so they import
"./ObjectStorageClient.js", "./OSSAgentStore.js", etc.; ensure all module
specifiers in functions/classes referenced (e.g., ObjectStorageClient,
OSSAgentStore, and the index.ts export entries) are changed consistently to use
.js so the ESM loader resolves local modules correctly.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
tegg/core/agent-runtime/src/OSSAgentStore.tstegg/core/agent-runtime/src/OSSObjectStorageClient.tstegg/core/agent-runtime/test/OSSAgentStore.test.tstegg/core/agent-runtime/test/errors.test.tstegg/core/agent-runtime/test/utils.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- tegg/core/agent-runtime/src/OSSAgentStore.ts
… test helper The oxlint type-aware checker reports TS2339 because MapStorageClient did not declare the optional init/destroy methods from ObjectStorageClient, causing type errors when tests assign vi.fn() to them. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…SAgentStore Mark appendMessages and updateRun as follow-up items for atomic operations (e.g. ETag-based conditional writes) in multi-writer scenarios. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split thread storage into metadata (JSON) + messages (JSONL) to leverage
the OSS AppendObject API for O(1) message writes instead of
read-modify-write. This avoids reading the entire thread on every
appendMessages call, which is much more efficient for long conversations.
- Add optional append() to ObjectStorageClient interface
- Implement append() in OSSObjectStorageClient with position cache
and HEAD-based fallback for stale cache self-healing
- Refactor OSSAgentStore: threads/{id}.json → threads/{id}/meta.json
+ threads/{id}/messages.jsonl
- Fall back to get-concat-put when client has no append()
- Add tests for incremental append, fallback path, and edge cases
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add mock tests for OSSObjectStorageClient.append (position cache, PositionNotEqualToLength HEAD fallback, error propagation) - Add TODO(PR2) comments for newMsgId and AgentConflictError - Add JSDoc to ThreadRecord.messages explaining storage separation - Remove redundant type assertions in OSSAgentStore tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…istency Follow tegg convention where utility files use PascalCase (e.g., ObjectUtils.ts, TimerUtil.ts, NameUtil.ts). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nstructing internally Follow IoC/DI principle: external SDK clients should be injected by the caller, not constructed inside the class. This improves testability and decouples OSSObjectStorageClient from OSS configuration details. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Match the original tegg coding convention established by the original authors, using standard TypeScript enum declarations. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
9cb6f66 to
22513fc
Compare
… compliance Replace `export enum` with `as const` + type extraction pattern to fix TS1294 errors under `erasableSyntaxOnly: true`. This aligns with the established convention in tegg/core/types/src/core-decorator/enum/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
针对 @killagu 的 review comments 统一回复: 1. prefix 拼接 (OSSAgentStore.ts:64)
已修复。构造函数中增加了 normalize 逻辑:非空 prefix 如果不以 2. OSS 对象应该外部传入 (OSSObjectStorageClient.ts:42)
当前已经是外部注入的: 3. append 的 position 问题 (OSSObjectStorageClient.ts:79)
OSS AppendObject API 本身是安全的——position 不匹配时会返回
所以不存在覆盖问题。唯一的风险是两个 writer 同时 append 同一个 key 时可能丢数据(HEAD 之后另一个 writer 又 append 了),但这属于 last-write-wins 的固有限制,注释中已说明。如果需要多 writer 安全,应该用数据库 store。 |
Prefix without trailing slash (e.g. 'myapp') would produce malformed keys like 'myappthreads/...'. Now the constructor ensures non-empty prefixes always end with '/'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cnpmcore master upgraded oxlint-tsgolint from ^0.14.2 to ^0.15.0, resolving the ERESOLVE conflict with oxlint@1.51.0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move type definitions (AgentStore, ObjectStorageClient, errors) from @eggjs/agent-runtime to @eggjs/tegg-types/agent-runtime for centralized type management. Implementation code (OSSAgentStore, OSSObjectStorageClient, AgentStoreUtils) stays in agent-runtime. The agent-runtime package re-exports all types from tegg-types for backward compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
) sync from: #5818 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Introduced a new agent runtime module for managing agent threads and runs with persistent storage capabilities. * Added thread creation and run lifecycle operations with metadata and conversation history management. * Implemented error handling for missing resources and conflicting operations. * **Tests** * Added comprehensive test suites for agent runtime components and storage functionality. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
@eggjs/agent-runtimepackage undertegg/core/agent-runtime/AgentObjectType,RunStatus,InputMessage,MessageObject,AgentRunConfig,ThreadRecord,RunRecordAgentStoreinterface for thread/run CRUD operationsObjectStorageClientabstraction for pluggable storage backendsOSSObjectStorageClientadapter for Alibaba Cloud OSS (oss-client)OSSAgentStoreimplementation with prefix-based key namespace isolationAgentNotFoundError(404),AgentConflictError(409)MapStorageClient(no external dependencies)Test plan
pnpm --filter @eggjs/agent-runtime run typecheckpassespnpm --filter @eggjs/agent-runtime run test— 16 tests passing🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests
Chores
Stacked PRs
This is part of a 3-PR series (review in order):