Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 22 additions & 4 deletions app/modules/proxy/_service/http_bridge/streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -980,18 +980,25 @@ def classify_durable_full_resend(
replay_projection = project_responses_input_for_account_neutral_fresh_replay(
cast(list[JsonValue], payload.input),
stored_count=stored_count,
# Classification only: inline Responses-Lite developer IDs
# must remain visible until the exact-manifest check rejects
# response-owned messages. Cross-account replay uses the
# default ID-stripping projection below.
preserve_developer_message_ids=True,
)
safe_fresh_context = False
if replay_projection is not None:
safe_fresh_context = responses_input_suffix_retains_prior_output(
replay_projection.input_items,
stored_count=replay_projection.stored_prefix_count,
canonical_lite_developer_index=replay_projection.canonical_lite_developer_index,
) or (
lookup.latest_pending_tool_calls is not None
and responses_input_suffix_matches_pending_tool_calls(
replay_projection.input_items,
stored_count=replay_projection.stored_prefix_count,
pending_tool_calls=lookup.latest_pending_tool_calls,
canonical_lite_developer_index=replay_projection.canonical_lite_developer_index,
)
)
return stored_count, lookup.latest_input_full_fingerprint, safe_fresh_context
Expand All @@ -1015,6 +1022,7 @@ def classify_durable_full_resend(
durable_full_resend_retains_prior_output = responses_input_suffix_retains_prior_output(
replay_projection.input_items,
stored_count=replay_projection.stored_prefix_count,
canonical_lite_developer_index=replay_projection.canonical_lite_developer_index,
)
durable_full_resend_fresh_payload = _http_bridge_payload_without_previous_response_id(
payload
Expand Down Expand Up @@ -1376,6 +1384,20 @@ def owner_unavailable_allows_account_neutral_replay(exc: ProxyResponseError) ->
if durable_full_resend_fresh_payload is None:
if not isinstance(payload.input, list):
return False
eligibility_projection = project_responses_input_for_account_neutral_fresh_replay(
cast(list[JsonValue], payload.input),
stored_count=durable_full_resend_anchor_count,
preserve_developer_message_ids=True,
)
if eligibility_projection is None:
return False
durable_full_resend_retains_prior_output = responses_input_suffix_retains_prior_output(
eligibility_projection.input_items,
stored_count=eligibility_projection.stored_prefix_count,
canonical_lite_developer_index=eligibility_projection.canonical_lite_developer_index,
)
if not durable_full_resend_retains_prior_output:
return False
replay_projection = project_responses_input_for_account_neutral_fresh_replay(
cast(list[JsonValue], payload.input),
stored_count=durable_full_resend_anchor_count,
Expand All @@ -1385,10 +1407,6 @@ def owner_unavailable_allows_account_neutral_replay(exc: ProxyResponseError) ->
durable_full_resend_fresh_payload = _http_bridge_payload_without_previous_response_id(
payload
).model_copy(update={"input": replay_projection.input_items})
durable_full_resend_retains_prior_output = responses_input_suffix_retains_prior_output(
replay_projection.input_items,
stored_count=replay_projection.stored_prefix_count,
)
if not durable_full_resend_retains_prior_output:
return False
if durable_full_resend_is_account_neutral is None:
Expand Down
Loading
Loading