L-0273: cherry-pick 8 upstream reliability fixes - #1500
Closed
JayGarland wants to merge 94 commits into
Closed
Conversation
added 30 commits
June 27, 2026 16:23
- agent/copilot: add probeCloseTimeout=5s to prevent permanent block on <-ps.done when copilot --headless --stdio doesn't exit cleanly after context cancel - agent/reasonix: implement SessionEnvInjector, dynamic identity/relay/send prompt injection from session env vars (no file dependency, no hardcoded paths) - agent/reasonix: SSE text dedup via cumulative delta extraction (turnTextBuf) - core/engine: cmdList diagnostics + replyWithError fallback (Reply->Send) - core/engine: inject CC_CONNECT_BIN, CC_CONNECT_CONFIG, CC_RELAY_TARGET into session env (auto-resolved from relay bindings) - core/engine: add configPath field + SetConfigPath() setter - cmd/cc-connect: wire engine.SetConfigPath(absConfigPath) - platform/telegram: KeepPreviewOnFinish() -> true (eliminates message flash)
… injection Core fixes: - agent/copilot: dynamic relay injection (identityInjected atomic.Bool, CRITICAL RULES) - agent/copilot: probeCloseTimeout=5s (probe deadlock fix) - agent/reasonix: Send() select+ctx (block forever fix) - agent/reasonix: buildSubmitBody \\ -> / for bash compat (crash fix) - core/engine: HandleRelay goroutine+timeout (Send blocking fix) - core/engine: subcommandIndex() skip --config before dispatch (instance lock fix) - core/relay: sendToGroup DEBUG->WARN, diagnostic logs Quality: - Self-audit passed: build, vet, agent/CUJ/Relay tests - data race fix: identityInjected bool -> atomic.Bool - relay CLI: --config support in runRelaySend - unsolicited events: e.send() -> e.sendWithError() with error logging - FIXME markers for multi-turn context and session ID persistence - config.toml: both seats bypassPermissions
…jection - agent/copilot/reasonix/opencode: relay command uses --data-dir instead of --config (--config consumed by subcommandIndex, unreachable in runRelaySend) - agent/opencode: add dynamic relay injection (sessionEnv, identityInjected atomic.Bool, CRITICAL RULES) — same pattern as Reasonix/Copilot - agent/opencode: pass sessionEnv from Agent to newOpencodeSession - agent/reasonix: parse CC_DATA_DIR in identity injection, forward-slash convert - agent/opencode/session_test.go: update newOpencodeSession call signature All relay directions now work: Copilot↔Reasonix, Reasonix↔OpenCode, Copilot↔OpenCode
…survives - agent/reasonix/session.go: add newReasonixSessionID() (UUID v4) to generate a client-side session ID when sessionID is empty (relay case). Previously CurrentSessionID() returned empty string, so saveRelaySessionID never persisted it and every relay started a fresh reasonix serve session. - agent/reasonix/session.go: always call /new in newSession() (reasonix serve does not support session resume). Removed FIXME from CurrentSessionID(). - agent/reasonix/session_test.go: add POST /new handler to TestReasonixSession_httpPost_ErrorIncludesBody mock server (previously skipped /new when sessionID=test). - core/engine.go: remove resolved FIXME comment block about Reasonix relay session ID persistence.
… works Previous commit (99d1432) always called /new even with a persisted session ID, defeating multi-turn relay. Reasonix serve keeps the session alive across SSE disconnects — calling /new discards it. - Restore conditional /new: only call when sessionID is empty or "new". When a persisted UUID is passed (relay resume), skip /new so the existing serve session is reused. - Verified end-to-end with daemon logs: Round 1: session_id="" → generated rs-9bb13d30... → /new Round 2: session_id=rs-9bb13d30... → reusing existing session (skipped /new)
reasonix serve breaks permanently after the first model call fails or the SSE connection is killed mid-turn. Reusing sessions (skip /new) caused subsequent relays to hang. Always calling /new gives a clean serve session each time. The client-side session ID is still generated and tracked for cc-connect session manager persistence. Root cause: reasonix serve internal state corruption bug — only fixable by process restart.
…w answered Copilot and OpenCode identity injection told the model to relay messages but did not explicitly say "ONLY relay when user says relay to X". Direct questions were being forwarded as relays instead of answered. Added explicit rules: - ONLY relay when user EXPLICITLY says "relay to X: message" or "relay to X" - If it is a direct question (no "relay to" prefix), ANSWER IT YOURSELF
Findings from a fresh-instance audit after the 3-seat Nexus trial: * Loop defense: no hop count, no rate limit. An agent that misinterprets a normal reply as a relay command (Known Issue #11) can cascade silently. Adds per-source rolling-window burst limit in core/relay.go (default 10 relays / 60s per <chatID>::<from>). Configurable via [relay].burst_max and [relay].burst_window_secs in config.toml; burst_max=0 disables. Regression tests in core/relay_test.go cover reject-after-budget, disabled-when-zero, and per-source isolation. * Check-then-act race: the prior atomic.Bool fix on identityInjected prevented torn reads but not the logical race — two concurrent Send() calls could both observe false, both run the ~80-line injection block, and both Store(true), producing a double-prefixed prompt. Replaced Load()/Store() with CompareAndSwap(false, true) in agent/copilot/session.go and agent/opencode/session.go to atomically claim the injection slot. * gofmt -w on all six touched files. Build: go build ./... PASS Tests: go test ./core/ -run "TestRelayManager|TestCUJ|TestRelay" PASS go test ./agent/copilot ./agent/opencode (touched suites) PASS (Pre-existing opencode TestAvailableModels_* and config Windows path-normalization failures unchanged — tracked as HANDOFF #12/#13.)
Runs go build + go test -race on the Nexus audit's touched packages
(core, agent/{copilot,opencode,reasonix}, config), plus a focused -v run
on TestRelayManager_Burst|TestCUJ|TestRelay. Linux runner because the
dev host (Windows) has CGO off and cannot run -race locally.
Guarded by `if: github.repository == 'JayGarland/cc-connect'` so it stays
inert when rebased onto upstream/main or further forked.
Reads {workDir}/{project}.md if it exists and appends its content to
the identity injection on the first message. Enables per-seat persona
instructions (e.g. chef-seat.md for the Chef orchestrator role) without
hardcoding seat names in the injection code. File is optional — silently
skipped when absent, so existing seats are unaffected.
…rkDir
Adds CC_PERSONAS_DIR = data_dir/personas to the session env injected in
core/engine.go (both initial-session and relay-session paths). Copilot
and OpenCode session agents now resolve the persona file from
CC_PERSONAS_DIR first, falling back to {workDir}/{project}.md for
backwards compatibility. This eliminates the per-worktree manual copy
footgun: persona files live in one place (F:\nexus\data\personas\) and
are read by all seats regardless of which worktree they operate in.
- core/message.go: add ReactionEmoji field to Message struct - core/session.go: add PendingReaction, AddReaction(), DrainReactions() to Session - core/context_inject.go: new file — formatPendingReactions, aggregateSeatMessages, formatGroupContext - core/engine.go: reaction early-return in handleMessage; drain+prepend on next real message - platform/telegram/telegram.go: subscribe to message_reaction updates; handleMessageReaction() filters by allow_from, extracts first emoji, dispatches as ReactionEmoji signal Reactions (up to 3) are stored in session state and prepended to the next outbound message as "[Pending reactions: 👎 3min ago]" before reaching the agent.
handleMessageReaction now logs at Info level on every fired event (user, chat, msg ID, emoji) and Debug level on every skip path. This lets us distinguish: update never arrived (Telegram bot not admin in group) vs. update arrived but filtered.
On the first message of a brand-new session (empty history + no agent session ID), read the seat's configured handoff_file and prepend its content as `[Handoff: <filename>]` before the user message. Gives the agent session context that would otherwise be lost across cc-connect restarts or /new resets. Config: add handoff_file to [projects.agent.options] per seat (chef-seat, copilot-seat). File is read silently on cold-start; missing file is a no-op. New Engine.SetHandoffFile(path) setter; read from agent options map in main.
When a message to any seat contains "@", cc-connect reads the last N history entries across all seat session files and prepends them as [Group context (last N)] before forwarding to the agent. N is configured per-seat via on_mention_context in [projects.agent.options]. Uses the existing aggregateSeatMessages()/formatGroupContext() from core/context_inject.go (already committed). New Engine.SetOnMentionContextN setter; default 0 = disabled. Applied to secretary/chef/copilot/opencode (N=10); reviewer-seat stays at 0 (read-only, no context needed). Also removes secretary-seat.md Mechanism 2 (raw session file paths). cc-connect auto-injects context on @-mention; no manual file reads needed.
…tMention Telegram's stripBotMention() removes @botName from message text before the engine sees msg.Content, so strings.Contains(msg.Content, "@") was always false. - core/message.go: add WasMentioned bool to Message struct - platform/telegram/telegram.go: capture mentioned = strings.Contains(text, "@"+botName) before stripping, set WasMentioned on all three dispatch paths (text, photo, document) - core/engine.go: replace strings.Contains(msg.Content, "@") with msg.WasMentioned - cmd/cc-connect/main.go: defensive type switch for on_mention_context (int64 + int)
The opencode engine pre-populates AgentSessionID at startup by reconnecting to its last running session even when the cc-connect session file is deleted. This caused the cold-start condition to always evaluate false. History length alone is the right sentinel: it reflects cc-connect's own recorded turns, which are always zero on a genuinely fresh session, regardless of what the agent backend may have reconnected to. Also adds slog.Info on injection (observable in logs) and slog.Warn on unreadable handoff file to aid diagnostics.
…e level silent = true in heartbeat config was only suppressing the emoji notification, not the agent's response. Added Message.DropReply bool that gates the isSilent check in processInteractiveEvents so the platform send is skipped entirely when the heartbeat is configured silent. The agent still runs its check internally (tools, awareness), it just posts nothing to chat. Also added DropReply to the function signature of processInteractiveEvents (queued messages always pass false).
Two separate concerns, now properly separated: - Platform sends: ExecuteHeartbeat wraps targetPlatform with mutePlatform when silent=true. This stops ALL outbound Telegram sends before they happen — no streaming preview is created, no final reply is posted, no send-then-delete ghost messages. - Session history: processInteractiveMessageWith gates the user-turn AddHistory on !msg.DropReply; processInteractiveEvents gates both assistant-turn AddHistory sites (EventResult + abnormal exit) on !dropReply. Heartbeat content never appears in session JSON, so aggregateSeatMessages() for on-mention context sees only real messages. The DropReply bool on Message remains as the carrier from ExecuteHeartbeat to the message-processing pipeline. isSilent || dropReply checks in the send path are kept as a harmless fast path (mutePlatform would discard anyway, but early return avoids hook emissions and workspace pool calls).
aggregateSeatMessages was reading ALL sessions across ALL seats without any chat boundary. A private DM to Chef leaked into the group on-mention context injected for Secretary because both sessions lived in the same session JSON file (keyed by workDir hash, not chat_id). Fix: use UserSessions (sessionKey → []internalID) to build an allowed-ID set before reading history. extractSessionChatID() parses the chat-id component from any "platform:chatID:..." key, handling workspace-prefixed variants. Only sessions whose sessionKey's chatID matches the inbound message's chatID are included. Hard privacy rule: on-mention in a group → only group sessions. on-mention in a DM → only that DM's sessions. No cross-chat bleed. Also fixes test call sites for processInteractiveEvents which gained a dropReply bool parameter in a prior commit.
…m message In compact mode, every hidden tool event calls freeze()+detachPreview() which clears the preview handle and forces finish() to fall back to p.Reply() — the user sees fragmented multi-message output. The quiet display mode already uses appendSeparator to keep text in one card, but quiet is global and changes other display behavior. New "single" progress_style for Telegram adopts the quiet appendSeparator path for hidden tool/thinking events while otherwise behaving like compact (streaming edits at 500ms interval). On finish(), the one preview message is edited to the full response — no second message. Changes: - core/progress_compact.go: add progressStyleSingle constant + normalize - core/interfaces.go: add StreamPreviewIntervalOverride optional interface - core/streaming.go: honor per-platform interval override; upgrade finish() success logs to Info with message_id - core/engine.go: use appendSeparator path when progressStyle == "single" - platform/telegram: parse "single", implement StreamPreviewIntervalMs()=500
disabled = true in a [[projects]] block causes cc-connect to skip that project entirely without removing the config. The block stays in place for easy revival by flipping the flag back to false. Disabled projects are filtered before all indexed engine loops so cfg.Projects and engines[] stay in sync. A startup info log confirms which seat was skipped.
Two bugs in formatGroupContext: 1. len(c) > 200 measures bytes, not characters — a Chinese char is 3 bytes, so the effective limit was ~66 Chinese characters, which cut off most messages after 1-2 sentences. 2. c[:200] byte-slices a UTF-8 string, which can split a multi-byte character and produce a corrupted string. Fix: convert to []rune before truncating, and raise the limit from 200 bytes to 500 runes (~500 Chinese chars / ~100 English words). With on_mention_context = 20, the injected block stays under ~10k chars while providing meaningful context per entry.
Auto-ack: RelayManager.Send() now posts an immediate "[<target>] ✅ received — implementing: <task>" from the target engine before HandleRelay starts. Boss sees receipt confirmation without waiting for the full response. Handback: After HandleRelay completes, if the source engine exposes a bot username via BotUsernameProvider, the response visibility label is prefixed with @<sourceUsername>. On Telegram this routes the handback as an @-mention to the source bot (Chef), so Chef's session receives the relay result as an incoming message rather than requiring a manual close-the-loop reply. Infrastructure: - BotUsernameProvider interface in core/interfaces.go - BotUsername() on telegram.Platform (wraps private botUsername()) - Engine.BotUsernameForPlatform() for relay manager lookup - Relay tests updated to expect ack as first target message
* fix: letter workspace pattern naming — L- + letter/ prefix fallback + prune compatibility - resolveWorkspacePattern: task- → L- fallback when no letter ID found - branchNameForWorkspace: task- → letter- fallback - cmdPrune: accept both letter/ and task- branch prefixes - All tests passing Co-Authored-By: Claude <noreply@anthropic.com> * fix: align claudeContextWindow default (200K→666K) with global config Per L-0211: default was 200K while fleet context_window=666000, causing [ctx:~N%] to show disproportionately high compaction. Both fallback paths (empty model string, non-[1m] model) now return 666_000 instead of 200_000. Refs L-0211 * fix: repair context window event and letter prune --------- Co-authored-by: architect-claude <architect-claude@resonova.local> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Jie <pjie@presage.care>
* fix: both topic naming paths — handleGeneralTopicIntake (L-0202 Part A) + CreateTaskTopic (L-0202 Part B) - handleGeneralTopicIntake (line 746): topic.Name instead of 'letter-' + numeric thread ID — keeps 'letter-new' name - CreateTaskTopic (line 836): topicTitle instead of 'letter-' + numeric thread ID — matches L-0200 fix direction - Both paths: no longer overwrite topic name with a numeric thread ID; L-0200 branch diff is now superseded Co-Authored-By: Claude <noreply@anthropic.com> * fix: resolve compilation error and update Telegram platform test for topic naming --------- Co-authored-by: architect-claude <architect-claude@resonova.local> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Jie <pjie@presage.care>
Co-authored-by: Jie <pjie@presage.care>
Co-authored-by: Jie <pjie@presage.care>
…#7) Adds core.ComposePersona/ResolvePersonaClass so every seat's system prompt is prefixed with an archive-first preamble (write/read/secretary variant, selected by workspace_pattern per L-0123's existing execution-seat split) before its own persona content. Missing preamble files fall back to a hardcoded one-line truth + WARN log rather than failing the spawn. Wired into claudecode, copilot, and opencode session constructors via a new CC_PERSONA_CLASS env var injected alongside CC_PERSONAS_DIR. Codex has no native persona injection (L-0131), so its adapter instead syncs the same preamble into a <!-- cc-managed:archive-first --> bounded block in AGENTS.md on every StartSession spawn via the new core.SyncManagedBlock helper. Co-authored-by: Jie <pjie@presage.care>
Co-authored-by: Jie <pjie@presage.care>
…PendingReactions fields
…te (chenhg5#1436) cleanupInteractiveState sets state.agentSession = nil under state.mu, but three Send goroutines read state.agentSession without holding the lock. When an agent process exits before the Send goroutine is scheduled, cleanup can nil agentSession, causing a nil pointer dereference panic. Fix: capture agentSession into a local variable under state.mu, then use the local in the goroutine. If the captured value is nil, the goroutine returns an error instead of panicking. Co-authored-by: tanghongliang <tanghongliang@citos.cn> Co-authored-by: Claude <noreply@anthropic.com> (cherry picked from commit a4b4659)
…g5#1436 Follow-up to chenhg5#1436. The third call site in drainPendingMessages was modeled correctly in spirit (capture into local var before goroutine) but missed two details that chenhg5#1436 applied to the first two sites: 1. The capture `as := state.agentSession` happened without holding state.mu, so the same race the PR set out to fix could still nil the field between the unlock above and the capture. 2. The Send goroutine did not have a defensive `if as == nil` check, unlike the other two sites; a nil capture would still panic when the goroutine ran. Also folds the existing nil/Alive check into the post-capture path so the gating uses the local copy (consistent with the new contract). No behavior change for the happy path; in the racy path the goroutine returns an error instead of dereferencing nil, which the existing error handling already covers. Verified locally: - go vet ./... clean - go build clean - go test -race ./core -run TestCUJ_H2_TwoPlatformsConcurrentNoBleed -count=10 PASS - go test ./core -run "Drain|Queue" PASS (cherry picked from commit 5e2d501)
…Refs (chenhg5#1459) (chenhg5#1462) When a user configured a relative work_dir (e.g. "~/project" or ".cc-connect"), SaveFilesToDisk joined relative paths into the attachments directory and the resulting paths were passed verbatim into the agent's prompt. The spawned agent process — typically run from a different cwd by the platform adapter — could not resolve them and silently dropped every attachment. SaveFilesToDisk now calls filepath.Abs(workDir) up front and falls back to the raw value on error, and AppendFileRefs defensively absolutizes each entry. Both behaviors are covered by new tests for relative, absolute, and empty workDir; the empty-workDir case falls back to the process cwd so misconfigured deploys still get a writable attachments directory. Co-authored-by: dev-claudecode <dev-claudecode@cc-connect.local> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> (cherry picked from commit 7e1b53c)
(cherry picked from commit 91c3d44)
…enhg5#1451) * fix(streaming): resume stream preview after permission prompt Add streamPreview.unfreeze() and call it from the EventPermissionRequest handler after <-pending.Resolved, so subsequent EventText in the same turn opens a new streaming card instead of being buffered until EventResult. * fix(test): drop unused nextSessionEventsHook type (cherry picked from commit 230ee3c)
(cherry picked from commit f943666)
* FEAT: 添加会话空闲关闭live agent进程配置 * CHORE: 处理会话空闲关闭配置PR评审意见 * CHORE: 稳定会话空闲关闭测试 (cherry picked from commit 760079b)
filepath.IsAbs is OS-native only, so upstream's chenhg5#1459 cherry-pick (7e1b53c) mis-absolutized already-absolute /tmp/... style paths on Windows into drive-rooted paths. Treat a leading / as absolute on any OS, matching the function's documented passthrough contract.
Author
|
Closing — this was created against the wrong repo by mistake (should target our fork JayGarland/cc-connect, not upstream). Apologies for the noise. |
There was a problem hiding this comment.
Pull request overview
This PR syncs a set of upstream reliability fixes into cc-connect (engine/session safety, streaming behavior, attachment path correctness, heartbeat behavior), plus additional fork-specific adaptations to keep tests and Windows behavior correct.
Changes:
- Improves core reliability around streaming previews, context indicators, queued message draining, heartbeat execution modes, and session hang detection.
- Fixes attachment path correctness by ensuring file refs are absolute (including POSIX-style paths on Windows) and adds regression tests.
- Adds/extends several supporting systems and tests (skill dir parsing, persona/preamble injection, workspace pattern helpers, relay/dispatch helpers, Telegram topic-intake tests, new CLI commands).
Reviewed changes
Copilot reviewed 75 out of 76 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/release_local/turn_contract/turn_contract_test.go | Updates expected context-indicator percentage in release-local contract tests. |
| tests/release_local/config_matrix/config_matrix_test.go | Adjusts for EffectiveDisplay signature change. |
| platform/telegram/telegram_test.go | Expands Telegram platform tests (topic intake, thread routing, progress style). |
| docs/usage.zh-CN.md | Documents same-session message queueing behavior (ZH-CN). |
| docs/usage.md | Documents same-session message queueing behavior (EN). |
| core/workspace_pattern_test.go | Adds tests for workspace pattern helpers and letter/worktree routing. |
| core/streaming.go | Adds preview interval override + unfreeze support; tweaks finish logging. |
| core/streaming_test.go | Adds streaming preview regression tests around freeze/unfreeze behavior. |
| core/statusboard.go | Introduces StatusBoard that posts/edits a pinned Telegram status message. |
| core/statusboard_test.go | Adds unit tests for StatusBoard state transitions/render behavior. |
| core/skill_dirs.go | Adds skill dir parsing/merge/normalization helpers. |
| core/skill_dirs_test.go | Adds tests for skill dir parsing and Engine skill-dir application. |
| core/session.go | Adds LastOutputAt + pending reaction storage/drain APIs; persists new fields. |
| core/progress_compact.go | Adds single progress style normalization. |
| core/persona.go | Adds persona-class resolution + persona composition + managed-block sync. |
| core/persona_test.go | Adds tests for persona composition and managed block syncing. |
| core/multi_workspace_test.go | Adds regression test for workspace agent env propagation. |
| core/message.go | Absolutizes attachment paths and adds reaction/mention/drop-reply fields; adds Event context window field. |
| core/message_test.go | Adds tests for SaveFilesToDisk/AppendFileRefs absolute-path behavior. |
| core/management.go | Exposes heartbeat_type in management endpoints. |
| core/interfaces.go | Adds optional interfaces (bot username, preview interval override, task topic creation, workspace config env provider). |
| core/i18n.go | Adds i18n key for feature-start built-in command and reflows const block. |
| core/heartbeat.go | Adds heartbeat types (ping vs agent) and busy-skip classification. |
| core/heartbeat_test.go | Adds tests for ping heartbeats and busy-skip behavior. |
| core/feature_board.go | Adds a JSON-backed feature board store and task/seat state structures. |
| core/dispatch_test.go | Adds dispatch parsing/archive validation/topic-creation fallback tests. |
| core/context_inject.go | Adds cross-seat context aggregation/formatting helpers and reaction formatting. |
| core/context_inject_test.go | Adds tests for aggregated seat message filtering. |
| core/context_indicator_test.go | Adds tests for configured context window usage in ctx indicator. |
| core/context_guard.go | Adds local history compaction (“context guard”) and optional session rotation. |
| core/context_guard_test.go | Adds tests for context guard compaction, token estimates, and rotation behavior. |
| core/cmdopts.go | Adds env-slice→map conversion helper for workspace agent env propagation. |
| core/api.go | Adds /project/status endpoint + shared project status classification + StatusBoard poller. |
| core/api_test.go | Adds tests for /project/status classifications and stale-output hung detection. |
| config/config.go | Adds new config fields (context_window, status_board, relay extensions, hide_agent_footer, workspace_pattern, idle timeout, project disabled flag). |
| config/config_test.go | Adds tests for new config fields and updated EffectiveDisplay signature. |
| config.example.toml | Documents new display and idle-timeout options. |
| cmd/cc-connect/worktree_test.go | Adds tests for letter extraction and dispatch ledger loading helpers. |
| cmd/cc-connect/status.go | Adds cc-connect status CLI command (daemon /project/status). |
| cmd/cc-connect/send.go | Adds --chat-id/--thread-id/--platform options to derive session key. |
| cmd/cc-connect/send_test.go | Adds tests for new send-arg parsing behavior. |
| cmd/cc-connect/relay.go | Adds --config support to infer data-dir for relay send. |
| cmd/cc-connect/doctor_runas_test.go | Gates run-as doctor tests off on Windows. |
| cmd/cc-connect/context_guard_config_test.go | Adds tests for parsing context guard config. |
| CHANGELOG.md | Documents newly added/changed behavior in Unreleased notes. |
| agent/reasonix/session_test.go | Updates session constructor call sites and adds HTTP error-body coverage. |
| agent/reasonix/session_id_test.go | Adds test ensuring empty session ID generates a usable ID. |
| agent/reasonix/reasonix.go | Adds session env forwarding to reasonix serve session creation. |
| agent/opencode/session.go | Adds per-session env forwarding and one-time identity/relay/persona injection. |
| agent/opencode/session_test.go | Updates constructor signature usage. |
| agent/opencode/opencode.go | Forwards session env to session constructor. |
| agent/copilot/session.go | Adds per-session env forwarding + one-time identity/relay/persona injection; adds probe close timeout. |
| agent/copilot/session_test.go | Adds test that persona injection is skipped when --agent is used. |
| agent/copilot/copilot.go | Forwards session env to session constructor; propagates config env to workspace opts. |
| agent/copilot/copilot_test.go | Extends workspace options test to validate env propagation. |
| agent/codex/codex.go | Syncs archive-first preamble into AGENTS.md managed block for Codex. |
| agent/codex/appserver_session.go | Adds write timeout handling and transport abort for app-server RPC. |
| agent/codex/appserver_session_test.go | Adds regression test for blocked stdin write timing out. |
| agent/claudecode/session.go | Injects persona/preamble into system prompt, throttles session_id events, adds context window to result events, adds debug occupancy monitor. |
| agent/claudecode/session_test.go | Adds tests for persona + archive-first preamble injection. |
| .gitignore | Ignores generated multi-workspace test fixtures. |
| .github/workflows/nexus-race.yml | Adds race-detector workflow for this fork. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+13
to
+17
| "sync" | ||
| "time" | ||
|
|
||
| tgbot "github.com/go-telegram/bot" | ||
| ) |
Comment on lines
+186
to
+189
| label := e.Project | ||
| if e.Role == "user" { | ||
| label = "Jay" | ||
| } |
Comment on lines
+50
to
+52
| if got := e.branchNameForWorkspace(want); got != "letter/L-2222" { | ||
| t.Fatalf("branchNameForWorkspace() = %q, want %q", got, "letter-2222") | ||
| } |
Comment on lines
+941
to
+943
| if len(stubBot.createTopicParams) != 1 || stubBot.createTopicParams[0].Name != "letter-new" { | ||
| t.Fatalf("CreateForumTopic params = %+v, want letter-L-1234", stubBot.createTopicParams) | ||
| } |
Comment on lines
110
to
+115
| child.Env = env | ||
| for _, kv := range env { | ||
| if strings.HasPrefix(kv, "COPILOT_MODEL=") || strings.HasPrefix(kv, "COPILOT_PROVIDER_") { | ||
| slog.Warn("copilotSession: DEBUG child env carries COPILOT_* var", "kv", kv) | ||
| } | ||
| } |
Comment on lines
+137
to
+149
| // Now also exercise a truly relative workDir. | ||
| gotRel := SaveFilesToDisk(filepath.Join("rel", "sub"), files) | ||
| if len(gotRel) != 1 { | ||
| t.Fatalf("SaveFilesToDisk(relative workDir) returned %d paths, want 1", len(gotRel)) | ||
| } | ||
| if !filepath.IsAbs(gotRel[0]) { | ||
| t.Errorf("SaveFilesToDisk(relative workDir) returned non-absolute path %q — agent could not open it (issue #1459)", gotRel[0]) | ||
| } | ||
| // The absolute path must resolve to a real file on disk. | ||
| if _, err := os.Stat(gotRel[0]); err != nil { | ||
| t.Errorf("SaveFilesToDisk returned path %q that does not exist: %v", gotRel[0], err) | ||
| } | ||
| } |
Comment on lines
+515
to
+519
| case <-ticker.C: | ||
| n := len(cs.events) | ||
| if n > 0 { | ||
| slog.Warn("claudeSession: DEBUG events channel occupancy", "len", n, "cap", cap(cs.events)) | ||
| } |
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.
Summary
e739e2eb(throttle message recall fallback probes, fix(core): throttle message recall fallback probes #1321) was skipped: its content is already onmainviab107669b, a prior sync of the same upstream PR — cherry-pick produced an empty diff and was skipped rather than committed as a no-op.test: fix processInteractiveEvents call sites after cherry-pick— two new tests from the footer-hiding commit didn't pass this fork'sdropReply boolparameter (added independently of upstream);go vetcaught the arity mismatch.fix: recognize POSIX-style absolute paths in AppendFileRefs on Windows—filepath.IsAbsis OS-native, so the [Bug] 入站图片附件提示路径与实际落盘路径不一致,agent 永远读不到文件 #1459 cherry-pick's own new tests (TestAppendFileRefs_Absolutize*) failed on Windows because/tmp/...-style already-absolute paths got rewritten with a drive prefix instead of passed through. FixedAppendFileRefs(and the test's own assertion) to also treat a leading/as absolute, matching the function's documented passthrough contract. This fork runs in production on Windows, so this is a real fix, not a workaround.760079bc) merged cleanly alongside the existing ping-only heartbeat mode — confirmed the two mechanisms are orthogonal (agentSessionIdleTimeoutNanosvsExecuteHeartbeatPing), no field collision.Conflict resolution notes
core/engine.go(a4b46593): real conflict — our fork'scurrentPromptLen/currentPromptPreviewstate fields vs upstream'sas := state.agentSessionrace-fix capture landing at the same location twice (once via clean auto-merge, once via the conflict hunk). Resolved by keeping our fields and de-duplicating the capture to one copy (duplicateas :=would have been a compile error).core/engine.go(e739e2eb): trivial struct-field-ordering conflict; both sides' fields kept.core/streaming_test.go(230ee3c6): both sides added a differently-named freeze/unfreeze regression test at the same insertion point; kept both (TestStreamPreview_FreezeAndRecreate+TestStreamPreview_UnfreezeResumesStreaming+ 2 more upstream tests). All streaming tests pass.Test plan
go build ./...cleango vet ./...cleango test ./core/... ./daemon/...— 8 failures remain, all confirmed pre-existing on unmodifiedmain(Windows/environment-specific: home-path shortening, PowerShell shell-output format, nexus skill-dir fixture, path-separator normalization, schtasks file-mode simulation) — none introduced by this syncgo test ./...full suite — all platform adapter packages pass