Feat/mcp scope per project#201
Open
duhd-vnpay wants to merge 34 commits intonextlevelbuilder:mainfrom
Open
Conversation
…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 <[email protected]>
…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 <[email protected]>
… 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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
- Add sender_id and channel to team task metadata for audit trail - Remove assistant prefill in team task reminder (thinking models reject it) - Add unit tests for team access control and sender_id tracking Co-Authored-By: Claude Opus 4.6 <[email protected]>
…, mobile UX, budget, traces) Resolved 13 file conflicts: - zalo.go: kept local struct tags + upstream's n==0 safety check - channel_instances.go: used upstream's credential merging (supersedes local bytea fix) - factory.go, stores.go: merged both Party + Contacts/Activity/Snapshots stores - loop_history.go: kept upstream skill inlining constants + local session persistence - session_store.go, sessions/manager.go, sessions_ops.go: deduplicated SetHistory() - sidebar.tsx, routes.tsx: added Party to upstream's restructured sidebar/routes - protocol.ts, i18n/index.ts, sidebar.json (×3): merged Party + upstream events/translations - version.go: bumped to schema version 18 Migration collision fix: renamed 000014_party_sessions → 000018_party_sessions Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add nullish coalescing for PERSONA_COLORS array index - Remove unused destructured `round` variable from PartyPage Co-Authored-By: Claude Opus 4.6 <[email protected]>
…ting Co-Authored-By: Claude Opus 4.6 <[email protected]>
…otocol Backend: - gateway_providers: read default_model from provider settings JSONB - party.go: getEngine() prefers providers with DefaultModel, alphabetical fallback for determinism (fixes random Go map iteration) - party.go: add slog.Error for round failures (was silently swallowed) Frontend: - use-party.ts: align all RPC params/events with snake_case wire format, add transformSession/mapStatus/selectSession helpers - party-start-dialog.tsx: use actual DB persona keys (morpheus-persona etc.) - party-page.tsx: use selectSession() for proper state hydration - connection-status.tsx: fix status text alignment Co-Authored-By: Claude Opus 4.6 <[email protected]>
transformSession() was dropping history/summary fields from backend response, and selectSession() reset messages to empty array. Old sessions appeared blank when clicked in sidebar. - transformSession: preserve _history and _summary from backend - hydrateMessages: new helper to convert RoundResult[] + SummaryResult into PartyMessage[] (round headers, persona messages, summary) - selectSession: call hydrateMessages() instead of setMessages([]) Co-Authored-By: Claude Opus 4.6 <[email protected]>
Root cause: `accumulators` map iterated with sequential `for i := 0; i < len(map)`
but SSE tool_call indices can be non-contiguous (e.g. {0, 2}), causing nil dereference
on `accumulators[i]` when key `i` doesn't exist.
Fixes:
1. openai.go: iterate map by sorted keys instead of sequential 0..len-1
2. lanes.go: add defer recover() in scheduler goroutine to prevent panics from
crashing the entire process — logs error and returns semaphore token
3. tracing: add SweepOrphanTraces() to mark stuck running traces as error on
gateway startup (running > 1h = orphan from previous crash)
Test results (18 tests):
- providers: 9/9 PASS (contiguous, non-contiguous, large gap, high index,
thought_signature, text-only, empty, HTTP error, cancelled context)
- scheduler: 5/5 PASS (no panic, panic recovery, multiple panics, cancelled
context, stats after panic)
- store/pg: 4/4 PASS (sweeps old running, ignores recent, ignores completed,
no orphans)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
… loops When LLM hits max_tokens, tool call arguments may be incomplete/malformed JSON. - Add truncation guard: skip tool execution when finish_reason=length, ask LLM to retry smaller - Wire per-agent max_tokens from other_config JSONB (default 8192) - Log warning on JSON parse failure for non-empty tool call arguments (truncation indicator) Co-Authored-By: Claude Opus 4.6 <[email protected]>
# Conflicts: # internal/tools/team_tasks_tool.go
Previously, when an SSE stream was prematurely closed (e.g. proxy timeout, network interruption), both Anthropic and OpenAI providers would return a response with finish_reason="stop" and missing usage data — silently delivering truncated content. The agent loop only checked for finish_reason="length", so these cases went undetected. Changes: - Anthropic provider: track message_stop event; if absent, set finish_reason="interrupted" and add scanner.Err() check - OpenAI provider: track [DONE] marker; if absent, set finish_reason="interrupted" - Agent loop: on "interrupted" finish_reason, discard partial response and retry once (with retry event emitted to channels) Co-Authored-By: Claude Opus 4.6 <[email protected]>
In Docker deployments, ~/.goclaw resolves to /app/.goclaw/ which is empty. The actual workspace files live at GOCLAW_WORKSPACE (/app/workspace/). This caused the Storage UI to show no files. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Download media URLs, verify local files, and detect MIME types for WhatsApp incoming messages. Replaces raw string paths with resolved media info including proper logging. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Migration file was renumbered to avoid conflict with upstream. RequiredSchemaVersion bumped from 18 to 19. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Create project entity for per-group MCP env overrides with auto-updating timestamps, FK to agent_teams, and unique constraints on slug and (channel_type, chat_id). Bump RequiredSchemaVersion to 20. Co-Authored-By: Claude Opus 4.6 <[email protected]>
…erride types Define store.ProjectStore interface (CRUD + MCP override methods), Project struct embedding BaseModel, and ProjectMCPOverride struct. Wire Projects field into Stores container. Co-Authored-By: Claude Opus 4.6 <[email protected]>
PostgreSQL-backed ProjectStore: full CRUD, chat-ID lookup, MCP override upsert/delete/list with secret-pattern rejection. Register projects and project_mcp_overrides in tablesWithUpdatedAt, wire into NewPGStores factory. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add ProjectID and ProjectOverrides fields to RunRequest and DelegateRunRequest for per-project MCP env overrides. Introduce composite poolKey (name:projectID) in Pool.Acquire/Release so different projects get separate MCP stdio processes with merged environment variables. Update LoadForAgent, connectViaPool, and filterTools to thread project context through the entire chain. Co-Authored-By: Claude Opus 4.6 <[email protected]>
… project) Extend ResolverFunc signature to accept ResolveOpts (ProjectID, ProjectOverrides). Add Router.GetForProject() which uses composite cache key "agentID:projectID" to prevent cross-project MCP contamination in shared agents like sdlc-assistant. The resolver closure now passes opts.ProjectID and opts.ProjectOverrides through to mcpMgr.LoadForAgent(), connecting the per-project MCP scoping pipeline. Co-Authored-By: Claude Opus 4.6 <[email protected]>
…n and announce - Create resolveProjectOverrides() helper in cmd/gateway_consumer_project.go - Add ProjectID/ProjectOverrides tool context keys for delegation chain propagation - Set project context in agent loop from RunRequest fields - Add ProjectID/ProjectOverrides to DelegationTask struct - Wire project context through delegate_prep.go buildRunRequest - Use GetForProject() in consumer main lane, process lane, and runAgentFn - Propagate project resolution through all 4 announce lanes - Pass pgStores.Projects to consumeInboundMessages
Implements Google Chat as a new channel type (google_chat) in GoClaw: - Service Account JWT auth with auto-refresh (no Google client libs) - Pub/Sub REST pull loop for inbound messages with dedup cache - Markdown → Google Chat text format conversion (bold, italic, links) - Cards V2 for tables/structured content - Byte-aware chunking for Vietnamese/CJK (3900-byte safety limit) - Drive upload for long-form responses with retention cleanup - Thread routing for group conversations - Placeholder edit pattern (Thinking... → final response) - Exponential backoff retry on 429/5xx - 28 unit tests, all passing Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add ProjectHandler with 9 endpoints:
- GET/POST /v1/projects (list, create)
- GET /v1/projects/by-chat (lookup by channel_type + chat_id)
- GET/PUT/DELETE /v1/projects/{id} (get, update, delete)
- GET /v1/projects/{id}/mcp (list MCP overrides)
- PUT/DELETE /v1/projects/{id}/mcp/{serverName} (set/remove override)
Wire into gateway server and wireHTTP factory following existing
MCP handler pattern with bearer token auth and i18n error responses.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- mergeEnv: priority, base immutability, nil handling - secretKeyPattern: reject TOKEN/SECRET/PASSWORD/API_KEY - resolveProjectOverrides: stub store, edge cases, graceful degradation - pool key: composite key isolation between projects - Router GetForProject: cache separation, empty project fallback Co-Authored-By: Claude Opus 4.6 <[email protected]>
Prevents false positives on keys like TOKENIZER_TYPE where TOKEN appears as a substring but not as a discrete word. Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Projects list with search, pagination, CRUD dialogs - MCP env overrides dialog per project (add/remove) - i18n support (en/vi/zh) - Sidebar nav item under Connectivity group Co-Authored-By: Claude Opus 4.6 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔄 Hướng dẫn sử dụng tính năng MCP Scope Per Project
📌 Vấn đề giải quyết
Cùng 1 agent (ví dụ SDLC Assistant) nhưng phục vụ nhiều dự án khác nhau, mỗi dự án cần kết nối tới MCP server riêng. Ví dụ:
• Project xPOS → Jira board A, GitLab repo X
• Project Loyalty → Jira board B, GitLab repo Y
🧑💻 User Flow
Bước 1: Tạo Project (qua UI hoặc API)
Qua Web UI:
Qua API:
curl -X POST /v1/projects
-H "Authorization: Bearer "
-d '{"name":"xPOS","slug":"xpos","channel_type":"telegram","chat_id":"-100123456"}'
Bước 2: Cấu hình MCP Overrides cho Project
Qua Web UI:
Qua API:
curl -X PUT /v1/projects/{project_id}/mcp/jira
-H "Authorization: Bearer "
-d '{"env_overrides":{"JIRA_PROJECT_KEY":"XPOS","JIRA_BOARD_ID":"42"}}'
Bước 3: Sử dụng — Hoàn toàn tự động! 🎉
Đây là phần hay nhất — user không cần làm gì thêm:
Telegram Group "xPOS Dev" (chat_id: -100123456)
└→ User: "Tạo Jira ticket cho bug login"
└→ System: resolve project = xPOS
└→ MCP Jira khởi động với JIRA_PROJECT_KEY=XPOS
└→ Ticket tạo đúng board xPOS ✅
📊 Tóm tắt