Skip to content

Commit 986f6a6

Browse files
axiomofjoycephalizationclaude
authored
feat!: agent session persistence (#14143)
* agent session persistence Co-authored-by: Tony Powell <apowell@arize.com> * fix(ci): regenerate UI message stream fixtures for ai@7.0.58 (#15320) The committed fixtures were generated against ai@7.0.48, but the lockfile now resolves ai@7.0.58, so the fixture codegen check in Typescript CI produced a diff. Only the upstreamTag provenance fields change. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix: don't error in-flight client tool calls on transcript poll sync (#15321) * fix: don't error in-flight client tool calls on transcript poll sync While a pending client tool (e.g. execute_ui) is paused awaiting an approval, the session poll can observe the mid-turn persisted transcript tail, replace chat.messages, and run recoverPendingToolCalls — which was designed for fresh page loads and classified every pending client call as either rehydratable (re-dispatch) or stale (resolve with the "can't be restored" error). That falsely errored calls whose script worker and approval promise were still alive in this page. partitionPendingClientToolCalls now takes an isToolCallInFlight predicate and skips those calls entirely — a live handler owns its pending part. The predicate comes from the client-tool timing recorder, which already brackets every dispatch, via a new isInFlight method. Genuinely orphaned calls (page reload, or after an interrupt resolves the run) are still errored or rehydrated as before, and poll syncs no longer redundantly re-dispatch in-flight rehydratable tools like ask_user. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: bake client tool timing metadata into the local transcript on resolution (#15326) * fix: bake client tool timing metadata into the local transcript on resolution A resend of an already-resolved client tool output is rejected (409 agent_session_tool_outputs_conflict) when it differs from the persisted part, but the client could not always reproduce the persisted bytes: enrichMessageWithClientToolMetadata stamps phoenix.clientStartedAt / clientEndedAt onto the request payload only, never onto the local chat.messages copy, and the per-turn timing recorder clears when the turn completes. Any resend between turn completion and the next poll sync (e.g. accepting an edit_prompt suggestion and immediately sending a message, which re-carries the preceding assistant message's resolved outputs) lacked the timing fields and read as a divergent result. Write the recorder's timings back into the resolved part right after chat.addToolOutput, using the same enrichment the wire payload gets, so the local transcript stays byte-identical to what the server persists and resends survive the recorder clearing. The CLI needs no counterpart: it executes no client tools and never submits toolOutputs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Tony Powell <apowell@arize.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 740e8bd commit 986f6a6

271 files changed

Lines changed: 63743 additions & 12106 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/phoenix-design/references/icons.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Phoenix has a curated icon set in `app/src/components/core/icon/Icons.tsx`. Use
2020
| Video | `Icons.PlayCircle` | Video-typed file attachments (no dedicated `Video*` icon). |
2121
| Code-evaluator form | `Icons.Edit` | Task-role context pill for the code-evaluator create/edit form the user is working in. The edit glyph reads as an action, distinct from entity icons used by surface pills. |
2222
| Context (generic) | `Icons.Info` | Default for an `AttachmentContextData` whose category has no canonical icon yet. |
23+
| Chat (temporary) | `Icons.ChatEphemeralityOn` | A temporary conversation that is excluded from durable session history. The check communicates that ephemeral mode is enabled. |
24+
| Chat (saved) | `Icons.ChatEphemeralityOff` | A conversation retained in durable session history because ephemeral mode is disabled. |
2325
| Update / release notice | `Icons.Gift` | New-version notices and release prompts. |
2426
| Bypass / unguarded approvals | `Icons.Shield` | Warning shield for bypass/auto-approval modes where approvals are skipped. |
2527
| Undo / rewind | `Icons.RotateCcw` | Counterclockwise arrow for reverting/undoing an action (e.g. rewinding a chat). Distinct from `History` (clock = history/session list). |

.github/workflows/claude-weekly-deps-upgrade.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ jobs:
123123
run gen-graphql make graphql
124124
run gen-openapi make openapi
125125
run gen-generative-ui make schema-generative-ui
126+
run gen-ui-reducer make ui-message-stream-fixtures
126127
run python-format make format-python
127128
run python-lint make lint-python
128129
run python-typecheck make typecheck-python
@@ -264,6 +265,7 @@ jobs:
264265
- `.scratch/verify/gen-graphql.log`
265266
- `.scratch/verify/gen-openapi.log`
266267
- `.scratch/verify/gen-generative-ui.log`
268+
- `.scratch/verify/gen-ui-reducer.log`
267269
- `.scratch/verify/python-format.log`
268270
- `.scratch/verify/python-lint.log`
269271
- `.scratch/verify/python-typecheck.log`

.github/workflows/openapi-schema.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,15 @@ jobs:
2525
env:
2626
BASE_REF: ${{ github.base_ref || github.event.before }}
2727
run: |
28-
jq '.paths |= with_entries(select(.key | startswith("/agent") | not))' \
29-
schemas/openapi.json > head.json
28+
cp schemas/openapi.json head.json
3029
if [ -z "$BASE_REF" ]; then
3130
echo "::error::Could not determine base ref for OpenAPI schema comparison"
3231
exit 1
3332
fi
3433
git checkout "$BASE_REF"
3534
- name: Snapshot base schema
3635
run: |
37-
jq '.paths |= with_entries(select(.key | startswith("/agent") | not))' \
38-
schemas/openapi.json > base.json
36+
cp schemas/openapi.json base.json
3937
- uses: docker://openapitools/openapi-diff@sha256:82291446e5554742d9c0725d7b315d18e93958c5526f9a663e8885227bdd6cb6 # latest
4038
with:
4139
args: --fail-on-incompatible base.json head.json

.github/workflows/typescript-CI.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ jobs:
3333
- "app/**"
3434
- "schemas/openapi.json"
3535
- "src/phoenix/server/generative_ui/**"
36+
- "tests/unit/server/agents/fixtures/ui_message_stream/**"
3637
- ".oxlintrc.json"
3738
- ".oxfmtrc.jsonc"
3839
- ".nvmrc"
@@ -85,6 +86,10 @@ jobs:
8586
run: |
8687
make schema-generative-ui
8788
git diff --exit-code
89+
- name: UI Message Stream Fixture Codegen
90+
run: |
91+
make ui-message-stream-fixtures
92+
git diff --exit-code
8893
- name: Test
8994
working-directory: ./app
9095
run: |

Makefile

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ NC := \033[0m # No Color
3232
.PHONY: help check-tools \
3333
setup setup-remote-export install-python install-node \
3434
graphql schema-graphql relay-build \
35-
openapi schema-openapi schema-generative-ui codegen-python-client codegen-ts-client codegen-ts-app \
35+
openapi schema-openapi schema-generative-ui ui-message-stream-fixtures codegen-python-client codegen-ts-client codegen-ts-app \
3636
dev dev-backend dev-frontend dev-docker dev-mock-llm \
3737
test test-python test-frontend test-ts test-helm test-jcs doctest typecheck typecheck-python typecheck-python-ty typecheck-frontend typecheck-ts \
3838
format format-python format-frontend format-ts lint lint-python lint-frontend lint-ts clean-notebooks \
@@ -54,6 +54,7 @@ help: ## Show this help message
5454
@echo -e " relay-build - Build Relay from existing schema"
5555
@echo -e " schema-openapi - Generate OpenAPI schema only"
5656
@echo -e " schema-generative-ui - Generate Generative UI catalog schema artifacts"
57+
@echo -e " ui-message-stream-fixtures - Generate AI SDK reducer conformance fixtures"
5758
@echo -e " codegen-python-client - Generate Python client types from OpenAPI"
5859
@echo -e " codegen-ts-client - Generate TypeScript client types from OpenAPI"
5960
@echo -e " codegen-ts-app - Generate TypeScript OpenAPI types for frontend (app/)"
@@ -219,6 +220,11 @@ codegen-ts-client: ## Generate TypeScript client types from OpenAPI
219220
@cd $(JS_DIR)/packages/phoenix-testing && $(PNPM) run --silent generate
220221
@echo -e "$(GREEN)✓ Done$(NC)"
221222

223+
codegen-ts-testing: ## Generate phoenix-testing TypeScript types from OpenAPI
224+
@echo -e "$(CYAN)Generating phoenix-testing TypeScript types...$(NC)"
225+
@cd $(JS_DIR)/packages/phoenix-testing && $(PNPM) run --silent generate
226+
@echo -e "$(GREEN)✓ Done$(NC)"
227+
222228
codegen-ts-app: ## Generate TypeScript OpenAPI types for app/
223229
@echo -e "$(CYAN)Generating TypeScript OpenAPI types for app...$(NC)"
224230
@cd $(APP_DIR) && $(PNPM) run --silent generate:openapi
@@ -229,7 +235,12 @@ schema-generative-ui: ## Generate generative UI catalog schema artifacts
229235
@cd $(APP_DIR) && $(PNPM) run --silent generate:generative-ui-catalog
230236
@echo -e "$(GREEN)✓ src/phoenix/server/generative_ui$(NC)"
231237

232-
openapi: schema-openapi codegen-python-client codegen-ts-client codegen-ts-app ## Generate OpenAPI schema and all clients (full workflow)
238+
ui-message-stream-fixtures: ## Generate AI SDK UI-message reducer conformance fixtures
239+
@echo -e "$(CYAN)Generating UI-message stream conformance fixtures...$(NC)"
240+
@cd $(APP_DIR) && $(PNPM) run --silent generate:ui-message-stream-fixtures
241+
@echo -e "$(GREEN)✓ tests/unit/server/agents/fixtures/ui_message_stream$(NC)"
242+
243+
openapi: schema-openapi codegen-python-client codegen-ts-client codegen-ts-testing codegen-ts-app ## Generate OpenAPI schema and all clients (full workflow)
233244
@echo -e "$(GREEN)✓ OpenAPI schema workflow complete$(NC)"
234245

235246
#=============================================================================

app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"fmt:check": "oxfmt --check --config ../.oxfmtrc.jsonc",
2525
"generate:generative-ui-catalog": "tsx scripts/generate-generative-ui-catalog.ts",
2626
"generate:openapi": "openapi-typescript --empty-objects-unknown=true --default-non-nullable=false ../schemas/openapi.json -o ./src/api/__generated__/v1.ts",
27+
"generate:ui-message-stream-fixtures": "tsx scripts/generate-ui-message-stream-fixtures.ts",
2728
"lint": "oxlint",
2829
"lint:fix": "oxlint --fix",
2930
"preinstall": "npx only-allow pnpm",
@@ -84,7 +85,6 @@
8485
"d3-format": "^3.1.2",
8586
"d3-scale-chromatic": "^3.1.0",
8687
"date-fns": "^4.4.0",
87-
"just-bash": "^2.14.5",
8888
"lodash": "^4.18.1",
8989
"motion": "^12.43.0",
9090
"mustache": "^4.2.0",

0 commit comments

Comments
 (0)