Repository navigation
Codex/feature/wework source header #1424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
qdaxb
merged 15 commits into
wecode-ai:main
from
FicoHu:codex/feature/wework-source-header
Jun 17, 2026
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
1256455
feat(executor): tag wework project model requests
5e5a189
fix(executor): preserve wecode headers for project requests
3cf86cb
fix(executor): tag project requests with project id
eb7acb8
fix(executor): preserve project metadata for local headers
31601c3
fix(executor): propagate project headers to direct runtimes
7421356
chore(executor): log project header propagation
2b3e52d
fix(executor): merge process claude headers for project tasks
6d31507
Merge branch 'main' into codex/feature/wework-source-header
FicoHu 388b0eb
chore(executor): remove project header debug logs
536b048
chore(shared): drop project metadata from openai converter
f964255
chore(executor): remove redundant custom header config
7aba82b
fix(executor): fill runtime source headers
aae7570
fix(executor): treat project zero as project
6178bc7
Merge remote-tracking branch 'upstream/main' into codex/feature/wewor…
dbdc9e9
Merge branch 'main' into codex/feature/wework-source-header
FicoHu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| #!/usr/bin/env python | ||
|
|
||
| # SPDX-FileCopyrightText: 2025 Weibo, Inc. | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| """Utilities for model API request headers.""" | ||
|
|
||
| import json | ||
| from collections.abc import Mapping | ||
| from typing import Any | ||
|
|
||
| WECODE_PROJECT_HEADER = "wecode-project" | ||
| WECODE_ACTION_HEADER = "wecode-action" | ||
| WECODE_SOURCE_HEADER = "wecode-source" | ||
| WECODE_EXECUTOR_HEADER = "wecode-executor" | ||
| WECODE_ACTION_VALUE = "wegent" | ||
| WECODE_SOURCE_VALUE = "wegent-local" | ||
| DEFAULT_HEADERS_ENV_KEYS = ("DEFAULT_HEADERS", "default_headers") | ||
|
|
||
|
|
||
| def merge_project_header( | ||
| headers: Mapping[str, Any] | str | None, | ||
| project_id: Any, | ||
| ) -> dict[str, str]: | ||
| """Return headers with the Wegent project header merged.""" | ||
| parsed_headers = _parse_header_map(headers) | ||
| normalized_project_id = _normalize_project_id(project_id) | ||
| if not normalized_project_id: | ||
| return parsed_headers | ||
|
|
||
| return merge_header_map( | ||
| parsed_headers, {WECODE_PROJECT_HEADER: normalized_project_id} | ||
| ) | ||
|
|
||
|
|
||
| def merge_wegent_runtime_headers( | ||
| headers: Mapping[str, Any] | str | None, | ||
| executor: str, | ||
| ) -> dict[str, str]: | ||
| """Return headers with Wegent runtime source headers filled in.""" | ||
| return merge_missing_header_map( | ||
| _parse_header_map(headers), | ||
| { | ||
| WECODE_ACTION_HEADER: WECODE_ACTION_VALUE, | ||
| WECODE_SOURCE_HEADER: WECODE_SOURCE_VALUE, | ||
| WECODE_EXECUTOR_HEADER: executor, | ||
| }, | ||
| ) | ||
|
|
||
|
|
||
| def merge_missing_header_map( | ||
| existing_headers: Mapping[str, Any] | str | None, | ||
| default_headers: Mapping[str, Any], | ||
| ) -> dict[str, str]: | ||
| """Merge only headers whose keys are missing from the existing header map.""" | ||
| result = _parse_header_map(existing_headers) | ||
| existing_keys = {key.lower() for key in result} | ||
| for key, value in default_headers.items(): | ||
| if value is None or str(key).lower() in existing_keys: | ||
| continue | ||
| result[str(key)] = str(value) | ||
| existing_keys.add(str(key).lower()) | ||
| return result | ||
|
|
||
|
|
||
| def merge_header_map( | ||
| existing_headers: Mapping[str, Any] | str | None, | ||
| new_headers: Mapping[str, Any], | ||
| ) -> dict[str, str]: | ||
| """Merge header maps case-insensitively while preserving insertion order.""" | ||
| result = _parse_header_map(existing_headers) | ||
| for key, value in new_headers.items(): | ||
| if value is None: | ||
| continue | ||
| normalized_key = str(key).lower() | ||
| result = { | ||
| existing_key: existing_value | ||
| for existing_key, existing_value in result.items() | ||
| if existing_key.lower() != normalized_key | ||
| } | ||
| result[str(key)] = str(value) | ||
| return result | ||
|
|
||
|
|
||
| def headers_to_anthropic_custom_headers(headers: Mapping[str, Any]) -> str: | ||
| """Format a header map for Claude Code's ANTHROPIC_CUSTOM_HEADERS env var.""" | ||
| return "\n".join(f"{key}: {value}" for key, value in headers.items()) | ||
|
|
||
|
|
||
| def merge_anthropic_header_map( | ||
| existing_headers: str, | ||
| headers: Mapping[str, Any], | ||
| ) -> str: | ||
| """Return Anthropic custom headers with a header map merged.""" | ||
| merged = merge_header_map( | ||
| _parse_anthropic_custom_headers(existing_headers), headers | ||
| ) | ||
| return headers_to_anthropic_custom_headers(merged) | ||
|
|
||
|
|
||
| def merge_anthropic_header_defaults( | ||
| existing_headers: str, | ||
| default_headers: Mapping[str, Any], | ||
| ) -> str: | ||
| """Return Anthropic custom headers with missing defaults filled in.""" | ||
| merged = merge_missing_header_map( | ||
| _parse_anthropic_custom_headers(existing_headers), default_headers | ||
| ) | ||
| return headers_to_anthropic_custom_headers(merged) | ||
|
|
||
|
|
||
| def merge_anthropic_custom_headers(*header_sets: str | None) -> str: | ||
| """Merge multiple ANTHROPIC_CUSTOM_HEADERS strings.""" | ||
| merged: dict[str, str] = {} | ||
| for headers in header_sets: | ||
| if not headers: | ||
| continue | ||
| merged = merge_header_map( | ||
| merged, | ||
| _parse_anthropic_custom_headers(headers), | ||
| ) | ||
| return headers_to_anthropic_custom_headers(merged) | ||
|
|
||
|
|
||
| def extract_default_headers(env: Mapping[str, Any]) -> dict[str, str]: | ||
| """Extract DEFAULT_HEADERS/default_headers from an environment mapping.""" | ||
| for key in DEFAULT_HEADERS_ENV_KEYS: | ||
| headers = _parse_header_map(env.get(key)) | ||
| if headers: | ||
| return headers | ||
| return {} | ||
|
|
||
|
|
||
| def _parse_header_map(headers: Mapping[str, Any] | str | None) -> dict[str, str]: | ||
| if not headers: | ||
| return {} | ||
| if isinstance(headers, Mapping): | ||
| return { | ||
| str(key): str(value) | ||
| for key, value in headers.items() | ||
| if key is not None and value is not None | ||
| } | ||
| if isinstance(headers, str): | ||
| 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 {} | ||
|
|
||
|
|
||
| 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_header_lines(headers: str) -> dict[str, str]: | ||
| parsed: dict[str, str] = {} | ||
| for line in headers.splitlines(): | ||
| stripped = line.strip() | ||
| if not stripped or ":" not in stripped: | ||
| continue | ||
| key, value = stripped.split(":", 1) | ||
| key = key.strip() | ||
| if not key: | ||
| continue | ||
| parsed[key] = value.strip() | ||
| return parsed | ||
|
|
||
|
|
||
| def _normalize_project_id(project_id: Any) -> str: | ||
| if project_id is None: | ||
| return "" | ||
| value = str(project_id).strip() | ||
| if not value: | ||
| return "" | ||
| return value | ||
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
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unify project-id normalization semantics with capability resolution.
This helper accepts
-1/00as valid IDs, while the resolver inexecutor/modes/local/capabilities.pyrejects numeric IDs<= 0. That mismatch can produce inconsistentwecode-projectheader 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
🤖 Prompt for AI Agents