feat(adk): dream improvements - #1124
Conversation
Change-Id: I09b9754cf51f10fe662fb6cb33935ad92a4d1656
…mance
- Add HumanReadableSerializer that produces human-readable JSON output
- Add GobSerializer for comparison benchmarks
- Refactor serialization_test.go to use table-driven tests for both serializers
- Add comprehensive benchmarks comparing InternalSerializer, HumanReadableSerializer, and GobSerializer
Performance improvements over InternalSerializer:
- 30-68% faster marshal/unmarshal operations
- 17-49% less memory allocation
- 30-76% fewer allocations
- 33-59% smaller serialized output size
The HumanReadableSerializer uses standard JSON encoding with type annotations
only for interface{} fields, making the output both human-readable and
type-preserving for round-trip serialization.~
Change-Id: Ifeae12484fc73b74067a0ac3a496e73e0674b975
Change-Id: Iecbcfd8ab5905e61df9a5578e8d3c99387dace85
Change-Id: I5ac5d8b60be92a28d1e57929f03fa4201649fbd0
Change-Id: I318ff16a6bd81bb57b38791eeea17b3385b1fde4
Change-Id: Iefb047967d4cb4796edd363e7e6ba0a9c4f49148
Change-Id: I3de2ba37914fe779cd880b38ce067acf5fbde7c8
The runner previously wrote the interrupt checkpoint inline, before the session event persister had flushed. This risks a checkpoint that references events not yet durable in the SessionStore. Introduce deferredRunnerCheckpoint: on the interrupt/cancel path the checkpoint payload is captured but not written until finalize() confirms persister.closeAndWait succeeded. If event persistence failed, the checkpoint write is skipped entirely (fail-closed). Also adds regression tests for checkpoint ordering invariants and the InMemoryStore checkpoint round-trip. Change-Id: Ib29263add4a261513f1349a9173a913c74ee65ef
Resume previously assumed the agent_tool interrupt state was always the JSON envelope (agentToolInterruptState) introduced for SessionID-based event filtering. Pre-envelope checkpoints stored raw gob bridge bytes, so json.Unmarshal failed outright and resume errored. Try the JSON envelope first; on parse failure or empty BridgeCheckpoint, treat the raw bytes as the legacy bridge checkpoint and synthesize a fresh childSessionID. Pre-envelope checkpoints predate session persistence and have no parent-session filter to coordinate with, so the synthesized ID is harmless. Un-skip the v0.7.37, v0.8.2, v0.8.3, v0.8.4 compat fixtures so the resume path is now exercised for real on-disk legacy bytes. Change-Id: I5000424ba028e9fb9fe3843ea9673a3dd23a7860
Merge AfterCursor and PageToken into a single `After` field in LoadEventsOptions. Rename NextPageToken to `Next` in LoadEventsResult. Rename afterEventCursor to afterCursor in LoadLatestTurnEnd returns. One concept, one name: the caller seeds After from LoadLatestTurnEnd, then passes res.Next back as After on subsequent pages. Change-Id: Icd0960940b7f69938e2b4a5062d220c709bc0e66
The Options suffix implies a functional-options pattern; Request better reflects the struct-pointer parameter style and pairs with LoadEventsResult. Also removes dead variable in conformance test. Change-Id: Ia28d8a1f92f4307182508dfba56e2b3c454acfa4
…ializer Correct the tool-call middleware ordering in chatmodel.go doc comments (cancelMonitor wraps around user handlers, not inside). Add architectural doc comment to newTypedInvokableAgentToolRunner explaining why AgentTool lacks its own SessionStore. Remove the unused GobSerializer type alias from schema/serialization.go (already aliased internally). Update conformance test variable names to match LoadEventsRequest rename. Change-Id: I2251e190c9d343dbd1e57cbebfc236840be4a0fa
…igurable page size AppendEvents failures in the session persister now retry with exponential backoff (default 3 retries, 50ms initial delay, 2x multiplier, 25% jitter) before latching the error. This prevents transient store failures from causing irrecoverable session log corruption. Also extracts the hard-coded page-size=100 in reconstructFromEventLog and replayTailEvents into the configurable LoadPageSize field on SessionPersistenceConfig (default 100, preserving current behavior). New config fields on SessionPersistenceConfig: - MaxFlushRetries (default 3, set to -1 to disable) - FlushRetryInitialBackoff (default 50ms) - LoadPageSize (default 100) Change-Id: I407b6038fd61df74420a5ddd16ce8ec0f8860948
…preservation When a SessionStore is configured, the Runner now reuses the exact tool list from the previous turn's TurnEndState to feed the model, ensuring byte-exact prompt cache hits across turns. The ToolSearch middleware skips its initialization strip logic when it detects pre-seeded tool infos via the new ToolInfosPreSeededKey RunLocalValue. Users can opt out with WithRefreshToolInfos() when tools have genuinely changed between turns. Change-Id: I95585e105d41689f08116325478f21552482b79b
Change-Id: Id35944259eaee9254bc9ffa7288fe6bc43bc021b
…ion mode When sessions are enabled, TurnEndState.Messages carries the previous turn's system message. The Runner prepends this history to the new input, then defaultGenModelInput unconditionally prepends a fresh system message, causing duplication. Strip the leading system message from history before prepending the fresh instruction so that dynamic SessionValues are always re-evaluated without duplicating the system prompt. Change-Id: Id14acc6aa5f2941ea64c4de82393a36bcea2fb36
…to single file Merge three scattered test files (human_readable_test.go, human_readable_edge_test.go, schema/toolinfo_humanreadable_test.go) into one unified file in internal/serialization. Replace schema.ToolInfo usage with a local mock type to eliminate the circular dependency, and remove duplicate test cases that exercised identical code paths. Change-Id: I0b1fa9d001201382917abb8bf4b3bd220ffdf13d
Reduce SessionStore from 4 methods to 2 (AppendEvents + LoadEvents) by merging TurnEndState into the event log as a SessionEvent variant. This eliminates duplicate message storage and unifies reconstruction into a single reverse-scan algorithm. - Rewrite session/in_memory_store.go with forward/reverse pagination - Remove SaveTurnEnd/LoadLatestTurnEnd from all test mocks - Replace encodeTurnEndState/decodeTurnEndState with encodeSessionEvent - Replace reconstructFromEventLog with reconstructSessionState Change-Id: I979e88727dd33bfaa6983241b7e90b7bbbe040e0
Replace the opaque integer-index cursor with the per-event UUIDv4 event_id, giving SSE consumers a stable identity for Last-Event-ID resume and de-duplication. AppendEvents becomes idempotent (first-write-wins on duplicate event_id) so persister retries no longer double-write. Introduce ErrInvalidEventID and ErrEventIDOutOfRange sentinels with isProtocolError classification, so the persister fail-fasts protocol violations while still retrying infrastructure errors. Stores treat event_id as an opaque non-empty string; UUIDv4 is the Runner allocation convention, not a store-enforced format. Change-Id: I70c277af5505d57c7354e8056372c1021d6009eb
Allocate EventID once at the AgentEvent emission boundary (execCtx.send) so user-land stream consumers and persisted SessionStore records share the same identity. SSE adapters can now use AgentEvent.EventID as the SSE id: line, and clients reconnecting with Last-Event-ID can pass that value directly to SessionStore.LoadEvents(After: ...) without going through the store. toSessionEvent reuses event.EventID instead of minting a new UUID, with a defensive fallback for test fixtures that construct events directly. makeInputSessionEvent is unchanged (no upstream AgentEvent). Change-Id: I525675f948aef55d6afc0dcdc46bd7e255a68311
Persist lifecycle, model span, retry/failover, and tool observation events through the managed session log while preserving the EventID identity contract between live AgentEvents and stored SessionEvents. Add focused coverage for replay boundaries, timeline exposure, retry/failover observability, model usage metadata, gob compatibility, and persistence guards. Change-Id: Id78c137b40265324d315237067a82e8ea1ffc8ef
Change-Id: I84f8155f66807d6e229741b9f5b3f6345f58f1d5
Change-Id: Id53b725579b6e7ceaeb9f4edd3c65a11e092f8e1
Delay loaded checkpoint abandonment until fresh-turn agent preparation succeeds, and fail before execution if checkpoint deletion fails. Fold durable attack coverage into normal ADK test suites and remove the standalone attack test file. Change-Id: I43fa3cd8d25dbd4ea3d1ca4c845191fa5a9c503d
Change-Id: I6714153ef2f58bed54dce9dfe3fe73bace3f6f04
Change-Id: I6fdded746daacdaa973c1914bfb789230254b17f
Change-Id: Ib830e9e647f9f2f9429d50136153cd253305c382
Add a JSONL-backed session store, expose schema serializers for session persistence, and wire configurable session event serialization through runner reconstruction and persistence. Change-Id: Ic6bf3905162c2f730428cf1bc5b65f1c8d8567cd
Add exported helper docs, reduce TurnLoop.run length by extracting input collection, and group model span end parameters to satisfy revive in CI. Change-Id: Ie23013d91d3d502d50c3787fa3e9ec191feeaf35
Replace the blocking ErrPendingSessionCheckpoint behavior with automatic checkpoint deletion via deleteCheckPointIfSupported. Calling Run is an explicit intent to start a new turn; session correctness is guaranteed by event log replay, not checkpoint presence. Change-Id: I9a19b4b44c90d134c28a4d2cc2746cd44d705144
…nt model (#1106) * refactor(adk): introduce SessionEventVariant and simplify session event model - Replace SessionEvent pointer in TypedAgentEvent with SessionEventVariant sum type - SessionEventVariant carries either materialized SessionEvent or MessageStreamRef for streaming - Move SessionID from durable SessionEvent to live SessionEventVariant metadata - Remove EventID and Timestamp from TypedAgentEvent (already in SessionEvent/MessageStreamRef) - Simplify store interface: pass sessionID as first-class arg, remove AppendEventsRequest - Rename UserObservation/UserInterrupt/AgentInterrupt to Cancel/Interrupt - Remove SessionRunStateRescheduled (only running and idle remain) Change-Id: Iab036b8ac7c445fde8cb54215aefab12f51eef1c * fix(adk): resolve dead code in toSessionEventChecked and add doc comments - Remove unused SessionEvent construction in fallback path of toSessionEventChecked - Add doc comments for MessageStreamRef, CancelEvent, and SessionEventVariant methods Change-Id: I4ba1ff5faf2abfa13ddc59fafb065a73a17d0345 * fix(adk): snapshot leading system message before genModelInput - deep copy leading system message before calling GenModelInput to detect in-place mutations (Extra map, Content, etc.) that would otherwise be missed by sameSystemMessage comparison - remove dead code in streaming-complete persistence branch (persistMV / persistOutput were constructed and immediately discarded) - add regression tests for in-place Extra and Content mutation in GenModelInput - document SessionEventVariant invariant and turn_end legacy compatibility Change-Id: Id8d6d3f91e013642a7573502ae4ad562239cbc07 * refactor(adk): replace turn_end bypass with generic unknown-kind tolerance replace hardcoded "turn_end" compatibility shim with a general mechanism that tolerates any unrecognized event kind carrying no payload: - add knownSessionEventKinds set and isKnownSessionEventKind helper - add countActiveSessionEventPayloads helper for structural check - tolerate unknown kinds with zero recognized payloads (forward/backward compat) - known kinds with missing/wrong payloads still error as before Change-Id: I48a74dc546a3c3b5a1f21a6a9a23ccae32aaf7fe * chore(adk): remove unreachable gob registrations for SessionEventVariant and MessageStreamRef checkpoint sanitizers strip SessionEventVariant before gob encoding, and the store serializer only encodes *SessionEvent[M]. add a comment explaining why these types are not registered. Change-Id: I55e2726a95ed3e31abc28719b8ed4c2f8106114e * test(adk): align variant serialization test with durable payload Change-Id: I0b9607028aebc61976529082b67f2d9751196563
…ng (#1107) * feat(adk): background-task manager with subagent/filesystem/deep wiring Introduce a shared, domain-agnostic background-task engine and wire it into the subagent and filesystem middlewares and the deep prebuilt agent. adk/backgroundtask (engine): - Manager tracks foreground/background/auto-background runs under one task-ID space; Run blocks with an optional foreground budget, then either completes, auto-backgrounds (Config.ShouldAutoBackground), or times out. - RunStream + StreamWorkFunc forward a run's output to the caller in real time during the foreground phase, then on auto-background inject a generic notice and drain the rest into the task result. - Cancellation records a reason on Task.Error and the foreground caller reports StatusCanceled (not a StatusFailed ctx error). - Task ids are TaskType_base62(int64), where the int64 packs a ms timestamp, a per-ms sequence (spinning to the next ms on overflow), and random low bits — unique within a process and self-describing by type. - Optional OutputStore persists completed results (filesystem.Backend satisfies it directly); WaitForTask/WaitAllDone for lifecycle waits. adk/middlewares/backgroundtask (control tools): - Injects task_output/task_stop once, bound to a Config{Manager}. task_output supports CC-aligned block/timeout inputs. adk/middlewares/subagent + filesystem: - subagent agent tool and filesystem execute tool route through a shared Manager when configured, gaining run_in_background; the streaming execute tool streams its foreground output via RunStream. filesystem.Shell now documents the ctx-cancellation contract. adk/prebuilt/deep: - deep.New accepts a Manager, wiring it into the top-level subagent + filesystem middlewares and injecting the control tools once; sub-agents stay foreground-only. Replaces the old task_tool with the subagent middleware. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * feat: adjust background.Manager * refactor(adk): clarify background task events * feat: simplify done check * feat: reduce one goroutine for direct run_in_background * refactor: enchance background task with direct run_in_background * refactor(adk): make background task output file worker-owned The background-task Manager previously declared an output file globally and wrote it once at completion, which broke its "interim output" promise and made the file redundant with Task.Result. Move output-file ownership to the launching adapters (execute / agent tools): the Manager only records RunInput.OutputFile, while the worker writes — shell runs tee interim output as it streams, sub-agent runs append their final result. - backgroundtask: drop Config.OutputStore/OutputDir and persistOutput; add RunInput.OutputFile (path only, Manager never writes) - filesystem: add Appender optional interface + AppendRequest (InMemoryBackend implements it); output files require an Appender, no rewrite fallback - bundle Manager + output config into a nested BackgroundConfig across the filesystem, subagent, and deep configs - name output files after the launching tool-call id (matching Task.ToolUseID), with a uuid fallback when absent - task_output's formatTask points at the file when present instead of inlining the result Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * feat: support mark output file * fix: golangci-lint * refactor(adk): hand WorkFunc a TaskInfo and key output-file failures by id The launcher needs the Manager-assigned task id at write time to report an output-file write failure, but the id is generated inside createTask, after the work closure is already built. Pass a TaskInfo (read-only snapshot of creation-time identity) as an explicit WorkFunc/StreamWorkFunc parameter so the work receives the id directly; MarkOutputFileUnreliable then keys by id (O(1) map lookup) instead of scanning all tasks by output-file path. Also make the failed-write reporting honest: when a write fails, neither the partial file nor the in-memory Result is the authoritative complete output (Result may be empty while the task runs, or a partial projection of the file for sub-agent runs). formatTask and the OutputFileErr doc no longer claim Result is always the full copy. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
| @@ -0,0 +1,117 @@ | |||
| /* | |||
| * Copyright 2026 CloudWeGo Authors | |||
There was a problem hiding this comment.
🚨 Breaking API Changes Detected
Package: github.com/cloudwego/eino/adk/middlewares/automemory/dream
Incompatible changes:
- Config.Schedule: removed
- New: changed from func(context.Context, *Config[M]) (github.com/cloudwego/eino/adk.TypedChatModelAgentMiddleware[M], error) to func(context.Context, *MiddlewareConfig[M]) (github.com/cloudwego/eino/adk.TypedChatModelAgentMiddleware[M], error)
- NewLocalStore: removed
- OnError: changed from func(context.Context, string, error) to func(context.Context, ErrorStage, error)
- Run: changed from func(context.Context, *Config[M], *RunRequest) error to func(context.Context, *Config[M], *RunRequest) (string, error)
- ScheduleConfig: removed
- Store: removed
Review Guidelines
Please ensure that:
- The changes are absolutely necessary
- They are properly documented
- Migration guides are provided if needed
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## alpha/10 #1124 +/- ##
===========================================
Coverage ? 81.66%
===========================================
Files ? 190
Lines ? 30903
Branches ? 0
===========================================
Hits ? 25237
Misses ? 3827
Partials ? 1839 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…rated leading system messages (#1121) * fix(schema): remove gob registration for map[string]any and []any Registering map[string]any / []any with custom _eino_ prefixed names in init() causes gob to panic when other libraries (e.g. go-openapi/spec) register the same types with their default names, since gob enforces one name per concrete type globally. These registrations were added preemptively in commit 318c253 (model timeout feature) so that GobSerializer could round-trip nested maps/ slices inside Extra/MetaData fields. However: - No eino-internal code puts nested map[string]any / []any into Extra - All existing tests pass without them - The conflict with third-party libraries is a real init-time failure GobSerializer will still fail at runtime if users store nested map[string]any / []any in Extra, but that is a runtime error surface rather than an unconditional init-time panic. Change-Id: Id4594751cb0a7ffb4666e07749ee2104f04a0267 * refactor(adk): remove session turn ids Use committed idle event IDs as rollback boundaries and remove runner-side turn ID generation, checkpointing, and session event stamping. Change-Id: Ica138789eae5cc901a9af23572d5f6aee801b416 * fix(adk): stop persisting runtime generated leading system messages in session events Generated leading system messages from GenModelInput are runtime model input scaffolding, not durable conversation history. They should be recalculated on each run via applyBeforeAgent -> GenModelInput rather than reconstructed from SessionEventStore. - Add runtime provenance marker (_eino_adk_runtime_generated_system_message) to distinguish generated vs caller-supplied leading system messages - Remove syncLeadingSystemMessageSessionEvent from all 3 run paths (no-tools, message ReAct, agentic ReAct) - Summarization Middleware strips marked messages from MessagesReplaced event payload while preserving them in runtime state - Caller-supplied leading system messages (unmarked) remain durable Change-Id: I4a9ddd895b1d5fd32ad15345e3f7d43417342f4d * chore: format code Change-Id: I4d8b7e4d78f688255142a1823462ca8864d8468d * refactor(adk): remove TurnLoop managed resume mode Remove the redundant managed interrupt resume mode where business interrupts kept the TurnLoop alive and waited for explicit Resume(). Business interrupts now always exit with *InterruptError and persist a checkpoint when Store + CheckpointID are configured, consistent with the normal interrupt-exit path. Restored checkpoint resume via GenResume remains intact. Deleted: - TurnLoopInterruptMode type and constants - InterruptMode and ResumeWaitTimeout from TurnLoopConfig - TurnLoop.Resume() method and sentinel errors - turnLoopPendingResumeSource enum and managed-only fields/helpers - Managed parking loop in takePendingResume - Managed-mode branch in run() and proxy iterator - Resume-wait watcher and timeout logic - InterruptContexts from turnLoopCheckpoint - ~2000 lines of managed-mode tests and helpers Change-Id: I4cc772012939ed8d0c768d00b9472ea8887f937f * fix(adk): use json canonical comparison for model context tool equality reflect.DeepEqual incorrectly reports tool change when persisted ToolInfo numbers decoded as float64 differ from runtime int values, causing redundant model context events every model call. Fall back to comparing canonical JSON form to keep semantic equivalence across persist/reload. Change-Id: I3baffe7decdf0d30217ccf45db354dc01a7779f5 * refactor(adk): skip persisting ModelContext session event Change-Id: I7ebc6ceb603b4d236c1978a5db2e64e6d5afb413
#1123) fix(summarization): extract messageUserTextContent helper to prefer UserInputMultiContent Refactored user text content extraction into a reusable internal helper that prioritizes UserInputMultiContent text parts (joined with "\n") over the raw Content field. Applied it in both getUserMsgTextContent and extractSkillInfos to ensure consistent behavior.
…#1091) * chore: ensure that tool calls match tool results and correct comments * chore: adjust condition
| @@ -0,0 +1,132 @@ | |||
| /* | |||
| * Copyright 2026 CloudWeGo Authors | |||
There was a problem hiding this comment.
🚨 Breaking API Changes Detected
Package: github.com/cloudwego/eino/adk
Incompatible changes:
- RollbackSessionOptions.ExpectedHeadEventID: removed
- WithRollbackSessionExpectedHeadEventID: removed
Review Guidelines
Please ensure that:
- The changes are absolutely necessary
- They are properly documented
- Migration guides are provided if needed
Change-Id: Iabc283f15ab65dc8100ace045344a4a24574eea9
| @@ -0,0 +1,132 @@ | |||
| /* | |||
| * Copyright 2026 CloudWeGo Authors | |||
There was a problem hiding this comment.
🚨 Breaking API Changes Detected
Package: github.com/cloudwego/eino/compose
Incompatible changes:
- AddressSegmentMiddleware: removed
- ToolMiddleware.Name: removed
Review Guidelines
Please ensure that:
- The changes are absolutely necessary
- They are properly documented
- Migration guides are provided if needed
509e919 to
9a6766d
Compare
What type of PR is this?
Check the PR title.
(Optional) Translate the PR title into Chinese.
(Optional) More detailed description for this PR(en: English/zh: Chinese).
en:
zh(optional):
(Optional) Which issue(s) this PR fixes:
(optional) The PR that updates user documentation: