Repository navigation
Conversation
Replace all log.Printf with slog (stdlib). Request ID flows through context: middleware generates, handler forwards to upstream as x-request-id, response header set on every endpoint. Key changes: - internal/proxy/logging.go: new. RequestLoggingMiddleware, statusWriter with Flush+Hijack, context-aware logging helpers, PROXY_LOG_JSON=1 toggle, -debug flag. - handler.go: request capture writes .request.json before upstream call (exists even on 401/transport failures), response tee unchanged. - assembler.go: context-first constructors, usage logged on finish. - adapter.go: no more debugf field, all logging via context. - router.go: old logger middleware removed, RequestLoggingMiddleware wraps mux. - main.go: InitLogger/EnableDebugLogging, -debug flag. - statusWriter: transparent Flush and Hijack delegation so streaming Flusher type assertions do not break (was a real bug). Docs: README updated (observability section, correct config.environment, full config field list, -capture-dir and -debug flags). ROADMAP updated (1.2 and 2.2 marked done).
Add scripts/diff-captures.sh: compares proxy .request.json captures against cmd-recorder POST_alpha_generate.json captures. Normalizes both with jq -S, runs unified diff, and prints a summary of known expected differences. Docs: README updated with capture-diff workflow example.
Proxy side: - Add XCommandCodeMemory, XCommandCodeSkills, XCommandCodeTaste to OpenAIChatRequest - BuildCCRequestWithWorkingDir forwards these fields to CCRequestBody - Generate threadId per request (uuid.New) for session continuity - Update responsesToChatRequest to forward new fields Pi extension (cc-cwd.ts): - readAgentsMd: reads AGENTS.md from project dir → memory - readSkills: reads SKILL.md from .agents/skills/.pi/skills/.commandcode/skills/ and formats as XML matching the real binary format - parseFrontmatter: parses YAML frontmatter name/description from skill files Docs: README updated with threadId, memory, skills, taste fields.
Theory (2026-06-08): The missing threadId may have been a contributing factor to the "automated environment update" acks. The proxy used to omit threadId entirely, making every request a new session. If the gateway constructs the system prompt only on the first message of a session, the model would see the environment context as new each time and respond to it. The threadId fix makes the proxy match the real binary session model.
Reverse-engineered the minified command-code v0.33.1 bundle. Key findings: **Two distinct /alpha/generate paths** - callApi() (line 4729, -p mode): sends temperature: 0.3, threadId - callServerAPI() (line 5255, interactive mode): no temperature, no threadId in body, may include reasoning_effort - The proxy mimics callServerAPI(); the callApi() captures were misleading **Taste learning is user-config-driven, not a fixed value** - isTasteLearningEnabled() reads userConfig.tasteLearning (default true) - The toggle gates ONLY x-taste-learning header - The taste BODY field is sent unconditionally (gated by file existence) - Proxy currently hardcodes 'true' — lies when user has taste off - Fix direction: pi extension forwards userConfig.tasteLearning as x_command_code_taste_learning, with -taste-learning CLI flag override **Header corrections** - x-co-flag (misnamed INTERNAL_TEAM_FLAG_HEADER) carries isOAuthEnforced().toString(), NOT a team flag - x-session-id is sent by callServerAPI; proxy doesn't send it - For API-key auth, x-co-flag: 'false' is correct **reasoning_effort is irrelevant for MiniMax-M3** - Model registry: MiniMax-M3 has reasoning:!0 but NO reasoningEfforts[] - Binary has nothing to set, so field is absent - Proxy is accidentally correct for the model it actually serves - Still relevant for future reasoning-effort-configurable models **Doc structure** - Deduped 'Two API call paths' (was in both gap-tracker and reverse-eng sections) - New 'Taste learning' section with full analysis - AGENTS.md gains conventions for x-taste-learning and x-co-flag - README.md file layout updated to post-refactor state
…ride) The real binary's callServerAPI() sends x-taste-learning: <isTasteLearningEnabled()>, which is the user's userConfig.tasteLearning (default true). The proxy used to hardcode 'true', lying when the user has taste learning off (e.g. the user's local config.json has tasteLearning: false). For their install the gateway sees 'true' for what should be 'false'. Three places accept the value now: 1. x_command_code_taste_learning on the OpenAI request (per-request, set by the pi extension which reads ~/.commandcode/config.json) 2. -taste-learning CLI flag on the proxy (proxy-wide default, true) 3. true (binary default for unset config) Precedence: per-request > CLI flag > binary default. - Upstream interface gains a tasteLearning bool param on Generate - ccAdapter.createUpstreamRequest uses the resolved value - Proxy.TasteLearning *bool field - ResolveTasteLearning(perRequest, proxyDefault) bool helper - OpenAIChatRequest and OpenAIResponsesRequest gain XCommandCodeTasteLearning *bool The pi cc-cwd extension (in /home/daniel/build/agent-extensions/pi/cc-cwd/) reads ~/.commandcode/config.json tasteLearning and forwards as x_command_code_taste_learning. Honors COMMAND_CODE_CONFIG_FILE env var for matching the binary's config.local.json / config.staging.json variants. Tests: - TestCreateUpstreamRequest_TasteFalse (adapter sets 'false' when asked) - TestResolveTasteLearning (7 precedence cases) - TestHandleChatCompletions_TasteLearningFromRequest (per-request wins) - TestHandleChatCompletions_TasteLearningFromProxy (CLI default used) - TestHandleChatCompletions_TasteLearningDefault (binary default true)
Audit pass after the previous taste commit. Found: 1. Bug: responsesToChatRequest didn't copy XCommandCodeTasteLearning from the Responses request to the chat request. Users on /v1/responses silently lost the per-request taste override. Now wired. Added TestResponsesToChatRequest_PassesTasteLearning (true, false, nil). 2. Stale doc: AGENTS.md convention said the extension should read ~/.commandcode/config.json and forward tasteLearning. The extension actually hardcodes false (per user request, simpler, no cross-system dep). Reworded the convention to match the actual implementation. 3. Missing doc: README.md CLI options table didn't list -taste-learning. Added. 4. Missing doc: ROADMAP.md didn't track the closed fidelity gap. Added 'Closed fidelity gaps' section linking the gap to commit e77a37b.
The pi extension generates a session ID (sess_ + 16 hex chars) per pi process and sends it as x_command_code_session_id on every request. The proxy now forwards this as the upstream x-session-id header. When no extension is present (e.g. direct curl), the proxy generates a per-request fallback in the same format. Closes the last remaining header gap vs the real command-code binary.
- 'response side' → 'client-facing output' (what the proxy sends to clients) - 'request side' → 'upstream request' (what the proxy sends to CommandCode) - 'response-side parity test' → 'client-facing parity test' - 'request-side fidelity table' → 'upstream-request fidelity table'
- translator: emit EventUnknown (with raw type + line) instead of silently dropping unknown NDJSON event types. The assembler (which has request context) logs the warning with request ID correlation. - assembler: handle EventUnknown via reqWarn so concurrent requests don't produce orphaned log lines. - scripts/cc-fingerprint: extract protocol-surface fingerprint from the command-code binary bundle (function bodies, named function list, API paths, headers, symbol counts). Designed to be diffed between versions. - baseline fingerprint saved at ref/fingerprints/v0.33.4.txt. Why: the proxy depends on matching an opaque binary that auto-updates. Unknown response-shape changes were silently swallowed; request-shape drift was invisible until it broke something. These two changes turn protocol drift from a silent failure into a greppable signal.
The 2026-06-08 fix that added per-request threadId was wrong. Captured traffic from callServerAPI() (225 main-loop captures from interactive command-code) shows the real binary does not send threadId in the body at all. The per-request UUID was making the gateway treat each turn as a brand-new session, rebuilding the system prompt every time. Code changes: - remove ThreadID field from CCRequestBody - remove newThreadID() helper and its call in BuildCCRequestWithWorkingDir - update test assertion (was checking for non-nil threadId) Docs: - AGENTS.md: rewrite MiniMax-M3 distraction factor dev2k6#2 as reverted, add factor dev2k6#3 (skills gap), clarify x-session-id vs threadId - MAINTAINING.md: add callServerAPI() capture source, rewrite threadId section as resolved, add skills gap section, update fidelity tables - README.md: remove threadId from request fields, note skills gap - ROADMAP.md: add threadId revert entry, update review date
Tested against live api.commandcode.ai: the gateway rejects system and developer roles in params.messages[] with a hard 400 (not a soft warning). Without DropSystemMessages, every pi request would fail. Also observed: params.stream must be true, and message content must be an array (not a bare string) for non-tool roles.
…ction, global skills forwarding, and removal of threadId field
andomeder
force-pushed
the
fix-null-content-tool-calls
branch
from
August 14, 2026 10:49
1d64106 to
a4d6373
Compare
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.
No description provided.