Skip to content

fix: route subagent announce through correct agent in delegation context#124

Closed
duhd-vnpay wants to merge 6 commits intonextlevelbuilder:mainfrom
duhd-vnpay:fix/delegate-subagent-announce-routing
Closed

fix: route subagent announce through correct agent in delegation context#124
duhd-vnpay wants to merge 6 commits intonextlevelbuilder:mainfrom
duhd-vnpay:fix/delegate-subagent-announce-routing

Conversation

@duhd-vnpay
Copy link

Summary

  • Bug: When a delegated agent spawns subagents, the announce results fail with agent default not found because the scheduler's RunFunc only parses agent:{agentId}:{rest} session keys
  • Root cause: Delegate session keys use format delegate:{uuid8}:{targetAgentKey}:{delegationId} — the delegate: prefix was not handled, causing fallback to "default" (which doesn't exist in managed-mode DBs)
  • Fix: Add delegate: case to the session key parser in makeSchedulerRunFunc, extracting the agent key from position 2

Details

gateway_consumer_process.go:makeSchedulerRunFunc resolves which agent loop to use from the session key. It only handled:

agent:{agentId}:{rest}

But subagent announces within delegations use session keys like:

delegate:019cd724:ui-ux-design-agent:1a93a73f-795

This caused repeated errors:

ERROR "subagent announce: agent run failed" error="agent default not found: agent not found: default"
WARN  "unknown channel for outbound message" channel=delegate

The fix adds a switch/case on parts[0] to handle both agent: and delegate: prefixes.

Test plan

  • Build succeeds (docker compose build goclaw)
  • Container starts healthy (docker compose up -d goclaw)
  • Trigger a delegation that spawns subagents → verify announce routes to correct agent (no more agent default not found errors)
  • Verify normal agent: session key routing still works (direct chat via Telegram/Zalo)

🤖 Generated with Claude Code

duhd-vnpay and others added 6 commits March 10, 2026 15:44
…ing, photo handling

- Fix zaloBotInfo to use account_name/display_name (not name)
- Add Label() method for bot display name resolution
- Handle 3 response formats in getUpdates: array, single object, wrapped
- Add photo_url field to zaloMessage for Zalo CDN image URLs
- Add display_name/is_bot to zaloFrom, chat_type to zaloChat
- Use PhotoURL with fallback to Photo in handleImageMessage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ssing

Zalo CDN URLs are auth-restricted and expire quickly, causing read_image
tool failures. Now downloads photos to temp files (like Telegram channel)
so the agent pipeline can base64-encode and process them normally.

Falls back to passing the URL directly if download fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… instance updates

When encryption key is empty, credentials stayed as map[string]any from
JSON unmarshal, causing pgx driver to fail encoding into bytea. Now
credentials are always marshaled to []byte regardless of encryption.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Party Mode to GoClaw: structured multi-persona AI discussions with
Standard (single LLM call), Deep (parallel thinking + cross-talk), and
Token-Ring (sequential turns) modes.

Backend: PartyStore + PG implementation, party engine with parallel
goroutines, 7 RPC methods (party.start/round/question/add_context/
summary/exit/list), 10 WebSocket events, migration 000014.

Frontend: React dashboard page with session list, chat view, persona
sidebar, mode controls, start dialog with 6 team presets, i18n (en/vi/zh).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, sanitizeHistory() only cleaned the in-memory copy for each
LLM request but never persisted the fix — causing the same "dropping
orphaned tool message" WARN to repeat on every single request forever.

Changes:
- sanitizeHistory() now returns drop count alongside cleaned messages
- When orphans are detected, cleaned history is persisted back to the
  session store via new SetHistory() method, then saved to DB
- Per-message WARN logs downgraded to DEBUG (cleanup is logged once
  at INFO level with total count)
- Added SetHistory() to SessionStore interface + both implementations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a delegated agent (e.g. ui-ux-design-agent) spawns subagents, the
announce session key uses the format delegate:{uuid8}:{agentKey}:{id}.
The scheduler's RunFunc only handled agent:{agentId}:{rest} format,
falling back to the hardcoded "default" agent — which doesn't exist in
managed-mode deployments where the default agent has a custom key.

Add delegate: prefix parsing to extract the target agent key from
position 2 of the session key parts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@viettranx
Copy link
Contributor

PR #124 Decomposition Summary

This PR bundles multiple unrelated changes (38 files, +2765 LOC) and has conflicts with main. We've extracted and re-implemented each fix group as focused PRs on main:

Merged

  • Cron context injection (c5b8860 on main) — ExtraSystemPrompt now tells the agent about the cron job's requester, channel, and delivery target. Also fixed cron.create from Web UI to capture userID.

Open PRs

Deferred

  • Party Mode (~20 files) — New feature, not a fix. Will be a separate PR when ready. Has open issues: missing authorization checks on session handlers, snake_case/camelCase event field mismatch.

Closing this PR in favor of the focused PRs above.

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.

2 participants