-
Notifications
You must be signed in to change notification settings - Fork 0
feat(foundry): add brokered responses mode #19
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
Merged
Changes from 23 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
7b9f0f6
feat(foundry): add brokered responses mode
sozercan 268a67c
fix(foundry): harden brokered response auth
sozercan bd9641c
fix(config): align brokered auth text validation
sozercan ba92655
fix(foundry): reject lossy model-loop floats
sozercan 4ad34a9
fix(foundry): tidy doctor auth warning
sozercan 9a71858
fix(foundry): address brokered review feedback
sozercan 82a98ae
fix(foundry): address follow-up review feedback
sozercan 528e8ff
fix(foundry): bound brokered continuation outputs
sozercan 021c83d
fix(foundry): reject lossy tool output numbers
sozercan 6e61abb
fix(brokered): harden validation and fixtures
sozercan 5ce2d5b
fix(brokered): preserve schema and transcript fidelity
sozercan 6c0234b
fix(config): preserve brokered schema numbers
sozercan 14cad45
fix(brokered): normalize usage and schema edge cases
sozercan a0a9729
fix(brokered): preserve numeric ABI fidelity
sozercan 67e69b0
fix(foundry): reject decoded model arguments
sozercan 10ae43a
fix(config): preserve negative zero schema values
sozercan 85ffae8
fix(foundry): harden fallback and fixtures
sozercan 7400cd2
fix(brokered): harden synthesis and deep copies
sozercan e6d3b25
fix(brokered): close conformance and continuation gaps
sozercan 75957e6
fix(foundry): harden persisted continuation state
sozercan 0b33dc2
fix(conformance): harden transcript evidence
sozercan ba81cd7
fix(foundry): distinguish expired continuation states
sozercan 42006c6
fix(foundry): reject ambiguous broker output
sozercan e1b3db1
fix(conformance): validate complete broker exchange
sozercan f0a3d72
fix(foundry): close brokered validation gaps
sozercan 10addc8
fix(foundry): harden brokered response validation
sozercan 52309dd
fix(foundry): bound brokered state and transcript data
sozercan 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
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,172 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| umask 077 | ||
|
|
||
| usage() { | ||
| cat >&2 <<'EOF' | ||
| usage: foundry_brokered_conformance.sh [prompt] [transcript-dir] | ||
|
|
||
| Runs the Phase A0 hosted Responses brokered conformance loop against a deployed | ||
| Foundry hosted agent endpoint: | ||
| 1. POST an initial /responses request with no request-level tools. | ||
| 2. Assert the response contains the deterministic conformance_read function_call. | ||
| 3. POST a function_call_output continuation with previous_response_id. | ||
| 4. Assert the final response is a completed assistant message. | ||
|
|
||
| Required environment: | ||
| AGENT_RESPONSES_ENDPOINT Full deployed /responses endpoint URL. | ||
|
|
||
| Authentication, one of: | ||
| AGENT_RESPONSES_BEARER_TOKEN Pre-acquired bearer token for the endpoint. | ||
| AZURE_SUBSCRIPTION_ID Optional subscription to select before `az account get-access-token`. | ||
| If omitted, the current `az` account is used. | ||
|
|
||
| Optional: | ||
| AGENTKIT_CONFORMANCE_OUTPUT Defaults to {"approved":true,"output":{"success":true}}. | ||
| AGENTKIT_EXPECTED_TOOL_NAME Defaults to conformance_read. | ||
| AGENTKIT_EXPECTED_ARGUMENTS Defaults to {"probe":true}. | ||
| AGENTKIT_EXPECTED_CALL_ID Defaults to call_conformance_1; set to auto for generated IDs. | ||
| AGENTKIT_EXPECTED_CALL_ID_PREFIX Optional required call_id prefix, e.g. call_. | ||
| AGENTKIT_CONTINUATION_PROOF Optional x-agentkit-brokered-continuation-proof header. | ||
| EOF | ||
| } | ||
|
|
||
| if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then | ||
| usage | ||
| exit 0 | ||
| fi | ||
|
|
||
| write_curl_header() { | ||
| local header="$1" | ||
| if [[ "$header" == *$'\r'* || "$header" == *$'\n'* ]]; then | ||
| echo "refusing curl header containing a newline" >&2 | ||
| return 1 | ||
| fi | ||
| header="${header//\\/\\\\}" | ||
| header="${header//\"/\\\"}" | ||
| printf 'header = "%s"\n' "$header" | ||
| } | ||
|
|
||
| : "${AGENT_RESPONSES_ENDPOINT:?set AGENT_RESPONSES_ENDPOINT to the deployed /responses URL}" | ||
|
|
||
| prompt="${1:-conformance_read}" | ||
| transcript_dir="${2:-$(mktemp -d "${TMPDIR:-/tmp}/agentkit-foundry-brokered.XXXXXX")}" | ||
| mkdir -p "$transcript_dir" | ||
|
|
||
| if [[ -n "${AGENT_RESPONSES_BEARER_TOKEN:-}" ]]; then | ||
| token="$AGENT_RESPONSES_BEARER_TOKEN" | ||
| else | ||
| if [[ -n "${AZURE_SUBSCRIPTION_ID:-}" ]]; then | ||
| az account set --subscription "$AZURE_SUBSCRIPTION_ID" >/dev/null | ||
| else | ||
| az account show >/dev/null | ||
| fi | ||
| token="$(az account get-access-token --resource https://ai.azure.com --query accessToken -o tsv)" | ||
| fi | ||
|
|
||
| conformance_output="${AGENTKIT_CONFORMANCE_OUTPUT:-{\"approved\":true,\"output\":{\"success\":true}}}" | ||
| expected_tool_name="${AGENTKIT_EXPECTED_TOOL_NAME:-conformance_read}" | ||
| expected_arguments="${AGENTKIT_EXPECTED_ARGUMENTS:-{\"probe\":true}}" | ||
| expected_call_id="${AGENTKIT_EXPECTED_CALL_ID:-call_conformance_1}" | ||
| expected_call_id_prefix="${AGENTKIT_EXPECTED_CALL_ID_PREFIX:-}" | ||
| initial_request="$transcript_dir/01-initial-request.json" | ||
| initial_response="$transcript_dir/02-initial-response.json" | ||
| continuation_request="$transcript_dir/03-continuation-request.json" | ||
| continuation_response="$transcript_dir/04-continuation-response.json" | ||
| summary_file="$transcript_dir/summary.json" | ||
| expected_output_file="$transcript_dir/.expected-output.json" | ||
| trap 'rm -f -- "$expected_output_file"' EXIT | ||
| printf '%s' "$conformance_output" >"$expected_output_file" | ||
|
|
||
| PROMPT="$prompt" python3 - <<'PY' >"$initial_request" | ||
| import json | ||
| import os | ||
| print(json.dumps({"input": os.environ["PROMPT"]}, separators=(",", ":"))) | ||
| PY | ||
|
|
||
| initial_curl_config="$(write_curl_header "Authorization: Bearer ${token}")" | ||
| printf '%s\n' "$initial_curl_config" | curl -fsS \ | ||
| --config - \ | ||
| -H 'content-type: application/json' \ | ||
| "$AGENT_RESPONSES_ENDPOINT" \ | ||
| -d "@$initial_request" >"$initial_response" | ||
| unset initial_curl_config | ||
|
|
||
| read -r response_id call_id < <(EXPECTED_TOOL_NAME="$expected_tool_name" EXPECTED_ARGUMENTS="$expected_arguments" EXPECTED_CALL_ID="$expected_call_id" EXPECTED_CALL_ID_PREFIX="$expected_call_id_prefix" python3 - "$initial_response" <<'PY' | ||
| import json | ||
| import os | ||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| body = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) | ||
| assert body.get("status") == "completed", body | ||
| response_id = body.get("id") | ||
| assert isinstance(response_id, str) and response_id.startswith("caresp_"), body | ||
| assert not response_id.startswith("resp_"), body | ||
| output = body.get("output") | ||
| assert isinstance(output, list) and len(output) == 1, body | ||
| call = output[0] | ||
| assert call.get("type") == "function_call", call | ||
| expected_tool_name = os.environ["EXPECTED_TOOL_NAME"] | ||
| expected_arguments = json.loads(os.environ["EXPECTED_ARGUMENTS"]) | ||
| expected_call_id = os.environ["EXPECTED_CALL_ID"] | ||
| expected_call_id_prefix = os.environ.get("EXPECTED_CALL_ID_PREFIX", "") | ||
| assert call.get("name") == expected_tool_name, call | ||
| call_id = call.get("call_id") | ||
| assert isinstance(call_id, str) and call_id, call | ||
| if expected_call_id != "auto": | ||
| assert call_id == expected_call_id, call | ||
| if expected_call_id_prefix: | ||
| assert call_id.startswith(expected_call_id_prefix), call | ||
| assert json.loads(call.get("arguments") or "{}") == expected_arguments, call | ||
| print(response_id, call_id) | ||
| PY | ||
| ) | ||
|
|
||
| PREVIOUS_RESPONSE_ID="$response_id" CALL_ID="$call_id" CONFORMANCE_OUTPUT="$conformance_output" python3 - <<'PY' >"$continuation_request" | ||
| import json | ||
| import os | ||
| # Validate the configured output is JSON before placing it in the Responses item. | ||
| json.loads(os.environ["CONFORMANCE_OUTPUT"]) | ||
| print(json.dumps({ | ||
| "previous_response_id": os.environ["PREVIOUS_RESPONSE_ID"], | ||
| "input": [{ | ||
| "type": "function_call_output", | ||
| "call_id": os.environ["CALL_ID"], | ||
| "output": os.environ["CONFORMANCE_OUTPUT"], | ||
| "status": "completed", | ||
| }], | ||
| }, separators=(",", ":"))) | ||
| PY | ||
|
|
||
| continuation_curl_config="$({ | ||
| write_curl_header "Authorization: Bearer ${token}" | ||
| if [[ -n "${AGENTKIT_CONTINUATION_PROOF:-}" ]]; then | ||
| write_curl_header "x-agentkit-brokered-continuation-proof: ${AGENTKIT_CONTINUATION_PROOF}" | ||
| fi | ||
| })" | ||
| printf '%s\n' "$continuation_curl_config" | curl -fsS \ | ||
| --config - \ | ||
| -H 'content-type: application/json' \ | ||
| "$AGENT_RESPONSES_ENDPOINT" \ | ||
| -d "@$continuation_request" >"$continuation_response" | ||
| unset continuation_curl_config | ||
|
|
||
| verifier_args=( | ||
| "$transcript_dir" | ||
| --expected-tool-name "$expected_tool_name" | ||
| --expected-arguments-json "$expected_arguments" | ||
| --expected-output-file "$expected_output_file" | ||
| --expected-call-id "$expected_call_id" | ||
| --write-summary | ||
| ) | ||
| if [[ -n "$expected_call_id_prefix" ]]; then | ||
| verifier_args+=(--expected-call-id-prefix "$expected_call_id_prefix") | ||
| fi | ||
| python3 deploy/foundry/scripts/verify_brokered_transcript.py "${verifier_args[@]}" >"$summary_file.tmp" | ||
| rm -f "$summary_file.tmp" | ||
| rm -f "$expected_output_file" | ||
| trap - EXIT | ||
|
|
||
| echo "Foundry brokered conformance passed. Sanitized transcript: ${transcript_dir}" | ||
| cat "$summary_file" | ||
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.
Uh oh!
There was an error while loading. Please reload this page.