feat(agent-signal): converge agent execution onto execAgent; reduce signal layer to event dispatcher [LOBE-9434]#15116
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## canary #15116 +/- ##
===========================================
+ Coverage 70.92% 89.27% +18.34%
===========================================
Files 3149 786 -2363
Lines 313673 87058 -226615
Branches 28498 7216 -21282
===========================================
- Hits 222486 77721 -144765
+ Misses 91019 9169 -81850
Partials 168 168
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 761c074bb5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const decision: SkillManagementDecision = options.skillDecisionRunner | ||
| ? ((await options.skillDecisionRunner(action.payload as SkillManagementSignalPayload)) as SkillManagementDecision) | ||
| : { action: 'noop', reason: 'no decision runner configured' }; |
There was a problem hiding this comment.
Wire a real default decision path for skill management
When no custom skillDecisionRunner is injected, this branch now hardcodes a noop decision. In the default server wiring (createPolicyOptions in orchestrator.ts), skillDecisionRunner is not provided, so action.skill-management.handle events are always skipped and no skill create/refine/consolidate action can run in production.
Useful? React with 👍 / 👎.
| if (agentId === BUILTIN_AGENT_SLUGS.nightlyReview) { | ||
| await options.onNightlyReviewCompleted?.({ agentId, operationId, userId }); | ||
| } else if (agentId === BUILTIN_AGENT_SLUGS.selfReflection) { | ||
| await options.onSelfReflectionCompleted?.({ agentId, operationId, userId }); | ||
| } else if (agentId === BUILTIN_AGENT_SLUGS.selfFeedbackIntent) { |
There was a problem hiding this comment.
Match completion handlers on slug, not agent database id
This routing compares agentId to slug constants (nightly-review, self-reflection, etc.), but completion events carry the persisted agent record id from runtime metadata, not the slug string. As a result these conditions never match and all post-completion callbacks are effectively dead.
Useful? React with 👍 / 👎.
| const runner = options.memoryActionRunner ?? ((i) => runMemoryActionAgent(i, options)); | ||
| const result = await runner(runnerInput); |
There was a problem hiding this comment.
Preserve memory safety checks before applying memory writes
Calling the memory runner directly here bypasses the createMemoryService.writeMemory validation boundary that previously enforced assertSafeAutomaticMemory before durable writes. That removes the last server-side safety gate for risky/low-confidence automatic memory content and can allow writes that were previously blocked.
Useful? React with 👍 / 👎.
761c074 to
00eba57
Compare
…eflection/self-feedback-intent) [LOBE-9452]
…ION_AGENT_SLUGS set [LOBE-9452]
… runs [LOBE-9449]
…traction [LOBE-9450]
…c path [LOBE-9455]
…ation with execAgent path [LOBE-9454]
- Add `suppressSignal` and `sourceMessageId` to `ExecAgentAppContext` so background agent runs can flag themselves and skip `agent.user.message` re-emission in execAgent (#2). - Fix character truncation in `ToolResultWithKind.data: unknown` (was bare ` nknown;`). - Replace the invalid `chatConfig.enableAutoCreateTopic` field on the three self-iteration builtin agents (nightly-review / self-reflection / self-feedback-intent) with the required `plugins: ['agent-signal-self-iteration']` so execAgent actually injects the self-iteration tool manifest at runtime. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The original PR commit (`feat(agent-signal): migrate skill management
action to execAgent async path [LOBE-9455]`) regressed
`runSkillDecisionAgentRuntime` to a `{ action: 'noop' }` stub and dropped
~1500 lines of supporting code (decision schemas, manifest, tool
executor, normalizers). This effectively disabled all skill-management
decisions.
Reverting the file to canary keeps the decision agent intact while we
redo the skill-write runner migration in a focused follow-up PR.
LOBE-9455 stays open for that work.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
execAgent returns immediately after queueing (`ExecAgentResult` does not
contain `finalState`). The previous implementation destructured
`finalState` as if execAgent were synchronous, making the
'did the memory write succeed?' branch unreachable and forcing every
memoryWriter run to fall through to skipped at runtime.
Changes:
- `runMemoryActionAgent` now enqueues via execAgent and returns
`{operationId, status: 'applied'}` on successful queueing. Drop the
inline finalState inspection helpers (hasSuccessful/FailedMemoryWrite)
and the `resolveMemoryActionTargetFromState` projector — these belong
in the completion policy once it grows a memory-writer handler.
- `runMemoryActionAgent` passes the writer-specific guidance via
`instructions` (no `systemRoleOverride` exists on `ExecAgentParams`);
a follow-up may introduce a `memory-writer` builtin agent so the
systemRole replaces rather than appends.
- `userMemory.test.ts` drops the 300-line `resolveMemoryActionTargetFromState`
describe block and the corresponding import (the function no longer
exists). Remaining handler-level tests still run against the injected
`memoryActionRunner` mock.
- `executeViaExecAgent` mirrors the same pattern: return `{operationId,
enqueued}` instead of fake `finalState`. Drop the non-existent
`systemRoleOverride` and the `createAgentSignalSelfIterationSystemRole(mode)`
call that passed an argument to a no-arg function.
- Move `trigger: RequestTrigger.AgentSignal` from `appContext` to the
top-level execAgent param (its actual location).
- `appContext.scope` is set to `'agent-signal'` (was `'chat'`) so
cost/observability lanes are distinguishable.
NOTE: the post-completion bookkeeping (writing receipts, marking
idempotency only on real write success) is not yet wired up. The
completion policy registered in this PR is the seam for that work but
no `onMemoryWriterCompleted` callback exists yet — tracked as a
follow-up under LOBE-9451 / LOBE-9455.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The completion policy and the suppressSignal helper landed in the PR as
orphan code: `createCompletionPolicy` was never installed into the
default policy stack, and `shouldSuppressSignal` was never called from
execAgent's emit site. Both are wired up now.
- `completionPolicy.ts`: switch to the correct `defineSourceHandler`
shape (the previous `{ handle, sourceType }` literal did not match
`AgentSignalInstallableHandlerDefinition` and failed type-check).
Drop `context.userId` — `RuntimeProcessorContext` has no such field;
callers can look up userId via the operations table by operationId.
Forward `topicId` from the source payload when present.
- `policies/index.ts`: register `createCompletionPolicy(options.completion)`
in `DEFAULT_AGENT_SIGNAL_POLICY_FACTORIES`, and add a `completion`
field to `CreateDefaultAgentSignalPoliciesOptions` for caller-provided
callbacks.
- `aiAgent/index.ts`: guard the `agent.user.message` emit (lines
1855-1874) with `if (!appContext?.suppressSignal)`. Builtin background
agent runs (memory-writer, self-iteration reviewer, etc.) now skip the
emit and avoid re-entering the analyzeIntent pipeline.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The catch handler for the `agent.user.message` enqueue used the
`debug('lobe-server:...')` logger, which only surfaces output when the
`DEBUG` env var is set. An enqueue failure here means Agent Signal lost
a source event — that must be visible in production logs regardless of
debug flags.
Switch to `console.error` so the failure is always logged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1546212 to
ca2cfb5
Compare
The nightly-review, self-reflection, and self-feedback-intent agents only differed by systemRole prompt — same tools, same plugin. Replace them with a single `self-iteration` agent; the mode-specific guidance is already supplied per-call via `createAgentSignalSelfIterationPrompt`. Also collapse the completionPolicy fanout from 3 onXxxCompleted callbacks to a single `onSelfIterationCompleted` — per-mode dispatch is deferred until a consumer actually wires it up (the previous 3 callbacks had no callers anyway).
|
Closing in favor of a phased split (LOBE-9434 broken into smaller, individually revertable PRs to reduce refactoring risk). Status of the work that was in this PR:
Closing this PR. Phase 3 F (the high-risk |
…nt slugs (#15202) The Phase 1 consolidation into a single `self-iteration` slug (PR #15187, inheriting commit 627f899 from the closed #15116) conflated three distinct background flows that have: - Independent receipt tables and idempotency Redis namespaces - Different preflight / brief projection paths - Different audit pipelines `one identifier = one behavior` is a load-bearing contract once these agents are routed through the standard execAgent plugin lookup. Restore the 3 mode-specific slugs so each agent declares its own tool surface: | slug | future plugin identifier | | ----------------------- | ------------------------------- | | `nightly-review` | `agent-signal-review` | | `self-reflection` | `agent-signal-reflection` | | `self-feedback-intent` | `agent-signal-feedback-intent` | `SELF_ITERATION_AGENT_SLUGS` now contains all three; `completionPolicy` dispatches on slug membership rather than equality; callback receives the resolved `agentId` so mode-specific bookkeeping can route from it. Plugin arrays reference the future identifiers but the tool packages are not yet registered — invoking any of these agents today runs the LLM with no tools (dormant by design). Tool-package registration follows in a separate PR. No behavior change for existing callers (none invoke these slugs yet).
关联 Issue
Closes LOBE-9449 LOBE-9450 LOBE-9451 LOBE-9452 LOBE-9454 LOBE-9455
Parent: https://linear.app/lobehub/issue/LOBE-9434
变更内容
#2 LOBE-9449 — appContext.suppressSignal flag
src/server/services/agentSignal/suppressSignal.ts:shouldSuppressSignal()helperSELF_ITERATION_AGENT_SLUGS集合中的 slug 返回 true(无需手动传 flag)appContext.suppressSignal: true显式覆盖#3 LOBE-9452 — 注册 self-iteration 系列 builtin agent
packages/builtin-agents/src/types.ts:新增三个 slug(nightly-review/self-reflection/self-feedback-intent)agents/nightly-review、agents/self-reflection、agents/self-feedback-intentpackages/builtin-agents/src/index.ts:注册到BUILTIN_AGENTS并导出SELF_ITERATION_AGENT_SLUGSSet#4 LOBE-9451 — agent.execution.completed 监听 policy
src/server/services/agentSignal/policies/completionPolicy.tsagentIdslug 路由到onNightlyReviewCompleted/onSelfReflectionCompleted/onSelfFeedbackIntentCompletedcallbacks#5 LOBE-9450 — tool result kind schema + finalState extractor
src/server/services/agentSignal/services/selfIteration/finalStateExtractor.tsToolResultKind = 'read' | 'artifact' | 'mutation'extractFromFinalState(finalState, kind)替代六个闭包累积器extractArtifacts/extractMutations便捷函数#6 LOBE-9455 — memoryWriter / skillManagement 迁移
userMemory.ts:runMemoryActionAgent改为调用AiAgentService.execAgent,删除createOperation + executeSync阻塞路径skillManagement.ts:skill write 步骤(create/refine/consolidate)改为调用execAgent;decision step(短时只读)保持原实现#7 LOBE-9454 — executeSelfIteration 迁移
src/server/services/agentSignal/services/selfIteration/executeViaExecAgent.tsexecAgent{ operationId, finalState, artifacts, mutations }execute.ts保留,待 build(deps): bump brotli-wasm from 1.3.1 to 2.0.0 #8 cleanup 删除跳过内容
注意
skillManagement.ts的runSkillDecisionAgentRuntime当前返回 stub({ action: 'noop' }),需要 TODO 补全决策步骤userMemory.ts中 thread 创建部分有一处语法问题需要手工修复(metadata 对象字面量)finalStateExtractor.ts中ToolResultWithKind.data类型有一处字符截断需修复这些都是此 PR 中需要 review 关注的点。