Skip to content

Codex/feature/wework source header - #1424

Merged
qdaxb merged 15 commits into
wecode-ai:mainfrom
FicoHu:codex/feature/wework-source-header
Jun 17, 2026
Merged

qdaxb merged 15 commits into
wecode-ai:mainfrom
FicoHu:codex/feature/wework-source-header

Conversation

@FicoHu

@FicoHu FicoHu commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added project-mode header injection for Claude Code and Codex in local execution, ensuring consistent project identity is sent to the model runtime.
    • Updated project-task detection to correctly recognize project-backed requests (including project id 0).
    • Applied Codex per-provider HTTP header overrides when a project id is present.
  • Documentation
    • Updated the local-device architecture developer guide to document the new Claude Code and Codex header behavior.
  • Tests
    • Expanded coverage for project header injection and default/custom header merging across Claude Code and Codex flows.
  • Chores
    • Removed a deprecated global Anthropic custom-header configuration variable in the executor config.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a wecode-project: <project_id> HTTP request header to Claude Code and Codex API calls when running in project mode. Introduces a new api_headers utility module with header parsing and merging helpers, a get_project_id resolver for multiple ExecutionRequest shapes, wiring in both LocalModeStrategy and build_codex_config, removal of the static config.ANTHROPIC_CUSTOM_HEADERS, and matching English and Chinese documentation.

Changes

Project-mode request header injection

Layer / File(s) Summary
Project ID resolution
executor/modes/local/capabilities.py, executor/tests/modes/local/test_global_capabilities.py
is_project_task delegates to new get_project_id(task_data) helper probing four nested ExecutionRequest locations (top-level, workspace.project, workspace.metadata.project, task_data.task_data); _normalize_project_id trims whitespace and does not filter zero/negative values. Tests verify workspace-project path extraction and treat project_id=0 as valid project task.
Header utility library
executor/agents/api_headers.py
New standalone module: constants for Wegent header names/values and DEFAULT_HEADERS_ENV_KEYS; functions merge_project_header, merge_wegent_runtime_headers, merge_missing_header_map, merge_header_map, merge_anthropic_custom_headers and variants, extract_default_headers; helpers for JSON/line-delimited/mapping header parsing with case-insensitive merging.
Claude Code agent and LocalModeStrategy
executor/agents/claude_code/claude_code_agent.py, executor/agents/claude_code/local_mode_strategy.py, executor/config/config.py, executor/tests/agents/test_mode_strategy.py
ClaudeCodeAgent imports get_project_id and passes both is_project_task result and computed project_id into use_global_capabilities. LocalModeStrategy stores optional _project_id, refactors configure_client_options to merge ANTHROPIC_CUSTOM_HEADERS from process and runtime env via shared helpers, optionally injects project header into default headers, serializes and writes to all DEFAULT_HEADERS_ENV_KEYS. Removes static config.ANTHROPIC_CUSTOM_HEADERS. Tests add autouse env-clearing fixture and verify header injection, merging with preexisting headers, and DEFAULT_HEADERS JSON serialization.
Codex agent and config builder
executor/agents/codex/codex_agent.py, executor/agents/codex/config_builder.py, executor/tests/agents/test_codex_config_builder.py, executor/tests/agents/test_project_workspace_paths.py
CodeXAgent.initialize computes project_id via get_project_id(self.task_data) and passes into build_codex_config. build_codex_config accepts optional keyword-only project_id and adds _resolve_explicit_model_provider and _build_header_overrides helpers to inject wecode-project and wecode-executor TOML override strings in both Wegent-managed and user-runtime-provider paths. Unit tests cover header-injection scenarios with/without project_id, with preexisting headers, and user-runtime provider. Integration test verifies Codex agent initialization with project_id returns SUCCESS and includes correct overrides.
Architecture documentation
docs/en/developer-guide/local-device-architecture.md, docs/zh/developer-guide/local-device-architecture.md
Two paragraphs added to each language variant describing project-mode wecode-project header injection alongside source identity headers (wecode-action, wecode-source, wecode-executor), Claude Code ANTHROPIC_CUSTOM_HEADERS merge and DEFAULT_HEADERS propagation, and Codex HTTP header override injection for both Wegent-managed and explicitly-named provider configs.

Sequence Diagram(s)

sequenceDiagram
    participant ClaudeCodeAgent
    participant capabilities
    participant LocalModeStrategy
    participant api_headers as api_headers module

    ClaudeCodeAgent->>capabilities: get_project_id(task_data)
    capabilities-->>ClaudeCodeAgent: "42" or empty string
    ClaudeCodeAgent->>LocalModeStrategy: use_global_capabilities(True, project_id="42")
    ClaudeCodeAgent->>LocalModeStrategy: configure_client_options(...)
    LocalModeStrategy->>api_headers: merge_anthropic_custom_headers(process_env + runtime_env)
    LocalModeStrategy->>api_headers: extract_default_headers(merged_env)
    alt global_capabilities enabled and project_id set
        LocalModeStrategy->>api_headers: merge_project_header(default_headers, "42")
        api_headers-->>LocalModeStrategy: {wecode-project: "42", ...}
    end
    LocalModeStrategy->>api_headers: merge_header_map(custom_headers, final_defaults)
    LocalModeStrategy->>LocalModeStrategy: serialize and inject DEFAULT_HEADERS_ENV_KEYS
    LocalModeStrategy-->>ClaudeCodeAgent: SDK env with merged ANTHROPIC_CUSTOM_HEADERS + DEFAULT_HEADERS
Loading
sequenceDiagram
    participant CodeXAgent
    participant build_codex_config
    participant helpers as _resolve and _build helpers
    participant api_headers

    CodeXAgent->>build_codex_config: model_config, project_id="42"
    build_codex_config->>helpers: _resolve_explicit_model_provider(model_config)
    helpers-->>build_codex_config: provider resolved or None
    build_codex_config->>helpers: _build_header_overrides(default_headers, "42", provider)
    helpers->>api_headers: merge_project_header(default_headers, "42")
    api_headers-->>helpers: merged headers with wecode-project
    helpers-->>build_codex_config: TOML override strings for model_providers.*.http_headers
    build_codex_config->>build_codex_config: append to config_overrides
    build_codex_config-->>CodeXAgent: CodeXConfig with wecode-project and wecode-executor overrides
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • wecode-ai/Wegent#1172: Modifies the same executor/modes/local/capabilities.py local global-capabilities flow that this PR extends with get_project_id helper and project-scoped header propagation.
  • wecode-ai/Wegent#1226: Introduces the CodeXAgent execution path and executor/agents/codex/config_builder.py baseline that this PR extends by adding project_id parameter and header override injection.
  • wecode-ai/Wegent#1322: Modifies the same build_codex_config function to extend config_overrides with additional override segments, directly related at the Codex config-building level.

Suggested reviewers

  • qdaxb

Poem

🐇 A header so small, yet it travels so far,
Through Claude and Codex, past env and config.
"wecode-project" hops into each call,
Merging and normalizing through layer and hall.
The rabbit stamps "42" with a cheerful crunch! 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 49.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Codex/feature/wework source header' is only partially related to the changeset. While it mentions Codex and source headers, the PR's scope is significantly broader, including Claude Code, project header injection, header merging utilities, and comprehensive documentation updates across multiple systems. Consider revising the title to reflect the broader scope, such as 'Add project identity header injection for Claude Code and Codex' or 'Support project-scoped header management for local execution.'
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@executor/agents/api_headers.py`:
- Around line 134-140: The _normalize_project_id function in
executor/agents/api_headers.py currently accepts negative IDs and zero, while
the capability resolver in executor/modes/local/capabilities.py rejects numeric
IDs <= 0. Update _normalize_project_id to convert the string value to a numeric
check and return an empty string for any numeric ID that is less than or equal
to zero, ensuring consistency between the two normalization paths and preventing
mismatched wecode-project header injection.

In `@shared/models/openai_converter.py`:
- Around line 390-395: The `metadata.get("standalone_chat_workspace", False)`
call at line 391 does not properly normalize null values to boolean—when the key
exists with a null value in metadata, dict.get() returns None instead of the
default False, which violates the bool type contract expected by
ExecutionRequest. Modify the standalone_chat_workspace parameter assignment to
explicitly normalize the value to a real boolean, ensuring that both missing
keys and null values result in False being passed to the ExecutionRequest
constructor.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97f9f96e-b44c-42b2-a073-e4037c8aa9f4

📥 Commits

Reviewing files that changed from the base of the PR and between b54fe77 and 6d31507.

📒 Files selected for processing (14)
  • docs/en/developer-guide/local-device-architecture.md
  • docs/zh/developer-guide/local-device-architecture.md
  • executor/agents/api_headers.py
  • executor/agents/claude_code/claude_code_agent.py
  • executor/agents/claude_code/local_mode_strategy.py
  • executor/agents/codex/codex_agent.py
  • executor/agents/codex/config_builder.py
  • executor/modes/local/capabilities.py
  • executor/tests/agents/test_codex_config_builder.py
  • executor/tests/agents/test_mode_strategy.py
  • executor/tests/agents/test_project_workspace_paths.py
  • executor/tests/modes/local/test_global_capabilities.py
  • shared/models/openai_converter.py
  • shared/tests/test_openai_converter.py

Comment on lines +134 to +140
def _normalize_project_id(project_id: Any) -> str:
if project_id is None:
return ""
value = str(project_id).strip()
if not value or value == "0":
return ""
return value

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Unify project-id normalization semantics with capability resolution.

This helper accepts -1/00 as valid IDs, while the resolver in executor/modes/local/capabilities.py rejects numeric IDs <= 0. That mismatch can produce inconsistent wecode-project header injection when callers pass raw IDs.

Suggested fix
 def _normalize_project_id(project_id: Any) -> str:
     if project_id is None:
         return ""
     value = str(project_id).strip()
-    if not value or value == "0":
+    if not value:
         return ""
+    try:
+        if int(value) <= 0:
+            return ""
+    except ValueError:
+        pass
     return value
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _normalize_project_id(project_id: Any) -> str:
if project_id is None:
return ""
value = str(project_id).strip()
if not value or value == "0":
return ""
return value
def _normalize_project_id(project_id: Any) -> str:
if project_id is None:
return ""
value = str(project_id).strip()
if not value:
return ""
try:
if int(value) <= 0:
return ""
except ValueError:
pass
return value
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@executor/agents/api_headers.py` around lines 134 - 140, The
_normalize_project_id function in executor/agents/api_headers.py currently
accepts negative IDs and zero, while the capability resolver in
executor/modes/local/capabilities.py rejects numeric IDs <= 0. Update
_normalize_project_id to convert the string value to a numeric check and return
an empty string for any numeric ID that is less than or equal to zero, ensuring
consistency between the two normalization paths and preventing mismatched
wecode-project header injection.

Comment thread shared/models/openai_converter.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
executor/agents/api_headers.py (1)

157-163: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid fallback line-parsing after successful JSON parsing.

If input is valid JSON but normalizes to an empty map (for example {"x": null}), the current fallback at Line 163 re-parses it as header lines and creates malformed keys. This can emit invalid custom headers.

Suggested fix
-def _parse_anthropic_custom_headers(headers: str) -> dict[str, str]:
-    if not headers:
-        return {}
-    parsed_json = _parse_header_map(headers)
-    if parsed_json:
-        return parsed_json
-    return _parse_header_lines(headers)
+def _parse_anthropic_custom_headers(headers: str | None) -> dict[str, str]:
+    if not headers:
+        return {}
+    stripped = headers.strip()
+    if not stripped:
+        return {}
+    try:
+        parsed = json.loads(stripped)
+    except json.JSONDecodeError:
+        return _parse_header_lines(stripped)
+    if isinstance(parsed, Mapping):
+        return _parse_header_map(parsed)
+    return {}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@executor/agents/api_headers.py` around lines 157 - 163, The
_parse_anthropic_custom_headers function cannot distinguish between failed JSON
parsing and valid JSON that normalizes to an empty map (like {"x": null}). When
valid JSON produces an empty dict, the function incorrectly falls back to
_parse_header_lines which creates malformed keys. Instead of checking if
parsed_json is truthy, check if it is not None to determine whether JSON parsing
actually succeeded, and only fall back to _parse_header_lines when JSON parsing
truly fails, not when it returns an empty but valid dict.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@executor/agents/api_headers.py`:
- Around line 157-163: The _parse_anthropic_custom_headers function cannot
distinguish between failed JSON parsing and valid JSON that normalizes to an
empty map (like {"x": null}). When valid JSON produces an empty dict, the
function incorrectly falls back to _parse_header_lines which creates malformed
keys. Instead of checking if parsed_json is truthy, check if it is not None to
determine whether JSON parsing actually succeeded, and only fall back to
_parse_header_lines when JSON parsing truly fails, not when it returns an empty
but valid dict.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 39970634-0535-4922-9f01-4437c9f874db

📥 Commits

Reviewing files that changed from the base of the PR and between f964255 and 7aba82b.

📒 Files selected for processing (8)
  • docs/en/developer-guide/local-device-architecture.md
  • docs/zh/developer-guide/local-device-architecture.md
  • executor/agents/api_headers.py
  • executor/agents/claude_code/local_mode_strategy.py
  • executor/agents/codex/config_builder.py
  • executor/tests/agents/test_codex_config_builder.py
  • executor/tests/agents/test_mode_strategy.py
  • executor/tests/agents/test_project_workspace_paths.py
✅ Files skipped from review due to trivial changes (1)
  • docs/en/developer-guide/local-device-architecture.md
🚧 Files skipped from review as they are similar to previous changes (5)
  • executor/tests/agents/test_project_workspace_paths.py
  • executor/tests/agents/test_codex_config_builder.py
  • executor/tests/agents/test_mode_strategy.py
  • executor/agents/claude_code/local_mode_strategy.py
  • executor/agents/codex/config_builder.py

@qdaxb
qdaxb merged commit d4b8d23 into wecode-ai:main Jun 17, 2026
24 checks passed
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