Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
84db61d
fix(whatsapp): preserve native bridge audio metadata
WolframRavenwolf Mar 30, 2026
b6d479d
feat(tool_progress): add 'full' mode — unlimited tool args in gateway…
WolframRavenwolf Mar 31, 2026
06c9e12
feat(prompt): add Amy platform hints and Mattermost Private Assistant…
WolframRavenwolf May 18, 2026
1a80063
docs: add Amy's patches changelog for v0.6.0 fork
WolframRavenwolf Mar 31, 2026
d4710f4
fix: suppress pkg_resources deprecation warning from lark_oapi
WolframRavenwolf Apr 19, 2026
e6faede
fix(addon): make dashboard assets work behind HA ingress
WolframRavenwolf Apr 24, 2026
f4c001c
feat(vision): add provider-safe inject_image tool
WolframRavenwolf May 18, 2026
0790976
feat(moa): route experts through provider-aware clients
WolframRavenwolf May 18, 2026
53c4a77
feat(gateway): add macOS app-wrapper launchd identity
WolframRavenwolf May 15, 2026
00ebca5
fix: enable GPT-5.5 priority processing fast mode
WolframRavenwolf May 16, 2026
68a1694
fix(gateway): keep macOS launchd runtime paths logical
WolframRavenwolf May 18, 2026
4e945ba
fix(deps): restore CVE-fixed pyproject pins
WolframRavenwolf May 21, 2026
c017d98
feat(status): restore model and context in gateway status
WolframRavenwolf May 31, 2026
68b454c
feat(resume): restore cross-platform full session listing
WolframRavenwolf May 31, 2026
17be309
docs(patches): update upstream PR reconciliation
WolframRavenwolf Jun 8, 2026
3e67d69
fix(mattermost): caption file-only media posts
WolframRavenwolf Jun 14, 2026
7ef1ea7
fix(mattermost): make post length configurable
WolframRavenwolf Jun 17, 2026
852d51d
feat(tools): keep send_message in explicit messaging toolset
WolframRavenwolf Jun 21, 2026
24225b1
test(auxiliary): make codex timeout check deterministic
WolframRavenwolf Jun 21, 2026
12b3b44
fix(gateway): harden self-management guard
WolframRavenwolf Jun 21, 2026
e2aa31a
fix(raft): quiet optional dependency checks
WolframRavenwolf Jun 21, 2026
198b4d3
fix(auxiliary): preserve auto fallback policy for vision calls
WolframRavenwolf Jun 23, 2026
180b275
fix(providers): resolve ProviderProfile plugins in CLI identity
WolframRavenwolf Jun 25, 2026
bc8b031
feat(providers): support provider-scoped model headers
WolframRavenwolf Jun 25, 2026
54c14d9
feat(gateway): configure macOS app-wrapper identity
WolframRavenwolf Jul 4, 2026
8447438
fix(redact): preserve replayable tool arguments
WolframRavenwolf Jul 14, 2026
69c7663
fix(terminal): ignore inert heredoc background markers
WolframRavenwolf Jul 14, 2026
50ea1a9
fix(gateway): preserve app wrapper during plist recovery
WolframRavenwolf Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,006 changes: 1,006 additions & 0 deletions RELEASE_amy-patches.md

Large diffs are not rendered by default.

58 changes: 39 additions & 19 deletions agent/anthropic_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1767,18 +1767,15 @@ def _convert_assistant_message(m: Dict[str, Any]) -> Dict[str, Any]:
# dropped, leaving thinking signatures and tool_use id/name/input intact.
ordered_blocks = m.get("anthropic_content_blocks")
if isinstance(ordered_blocks, list) and ordered_blocks:
# Re-source each tool_use input from the stored tool_calls map rather
# than the captured block. The ordered-blocks list captures tool_use
# input from the RAW API response (normalize_response), which is NOT
# credential-redacted; tool_calls[].function.arguments IS redacted at
# storage time (build_assistant_message, #19798). Replaying the raw
# block input would resurrect a secret the model inlined into a tool
# call (e.g. terminal(command="curl -H 'Authorization: Bearer sk-...'")
# onto the wire, even though the same value is redacted everywhere else
# in history. Keying by sanitized tool id preserves interleave order
# (the reason this channel exists) while swapping in the redacted
# input. Adapted from #36071 (replay-time tool-input re-sourcing).
redacted_input_by_id: Dict[str, Any] = {}
# Re-source each tool_use input from the canonical replayable
# tool_calls map rather than the separately captured ordered block.
# build_assistant_message preserves these arguments byte-exactly because
# masking them poisons subsequent turns and resumed sessions. This means
# credentials in tool arguments are also persisted raw; at-rest security
# belongs to state-file permissions/encryption, not destructive replay
# mutation. Keying by sanitized tool id preserves interleave order while
# keeping one canonical argument copy (upstream #43083 / PR #54136).
replay_input_by_id: Dict[str, Any] = {}
for tc in m.get("tool_calls", []) or []:
if not isinstance(tc, dict):
continue
Expand All @@ -1788,19 +1785,16 @@ def _convert_assistant_message(m: Dict[str, Any]) -> Dict[str, Any]:
parsed_args = json.loads(raw_args) if isinstance(raw_args, str) else raw_args
except (json.JSONDecodeError, ValueError):
parsed_args = {}
redacted_input_by_id[_sanitize_tool_id(tc.get("id", ""))] = parsed_args
replay_input_by_id[_sanitize_tool_id(tc.get("id", ""))] = parsed_args
replayed: List[Dict[str, Any]] = []
for b in ordered_blocks:
clean = _sanitize_replay_block(b)
if clean is None:
continue
if clean.get("type") == "tool_use":
# Override raw (un-redacted) input with the redacted copy when
# we have one for this id; fall back to the sanitized block
# input only if the tool_call is missing (shape mismatch).
redacted = redacted_input_by_id.get(clean.get("id", ""))
if redacted is not None:
clean["input"] = redacted
canonical_input = replay_input_by_id.get(clean.get("id", ""))
if canonical_input is not None:
clean["input"] = canonical_input
replayed.append(clean)
if replayed:
return {"role": "assistant", "content": replayed}
Expand Down Expand Up @@ -1894,6 +1888,32 @@ def _convert_tool_message_to_result(
if text_content else list(stashed)
)

# inject_image returns a JSON marker containing base64 image bytes. Native
# Anthropic can receive that as an image block inside the tool_result while
# still keeping a compact textual status around it.
if multimodal_blocks is None and isinstance(content, str) and '"_inject_image"' in content:
try:
parsed_result = json.loads(content)
if isinstance(parsed_result, dict) and isinstance(parsed_result.get("_inject_image"), dict):
img = parsed_result["_inject_image"]
media_type = img.get("media_type")
data = img.get("data")
if isinstance(media_type, str) and media_type.startswith("image/") and isinstance(data, str) and data:
text = parsed_result.get("message") or "Image injected into native multimodal context."
multimodal_blocks = [
{"type": "text", "text": str(text)},
{
"type": "image",
"source": {
"type": "base64",
"media_type": media_type,
"data": data,
},
},
]
except (json.JSONDecodeError, TypeError, KeyError):
pass

if multimodal_blocks:
result_content: Any = multimodal_blocks
elif isinstance(content, str):
Expand Down
Loading
Loading