diff --git a/cockpit/chat/a2ui/angular/e2e/scripts/record-c-a2ui.sh b/cockpit/chat/a2ui/angular/e2e/scripts/record-c-a2ui.sh deleted file mode 100755 index 89b1c99f..00000000 --- a/cockpit/chat/a2ui/angular/e2e/scripts/record-c-a2ui.sh +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: MIT -# -# Capture aimock fixtures for the c-a2ui graph by running the standalone -# langgraph dev server against aimock in --record mode. Drives two prompts -# (one per welcome chip) covering the booking-form flows. -# -# Run from repo root: -# OPENAI_API_KEY=sk-... bash cockpit/chat/a2ui/angular/e2e/scripts/record-c-a2ui.sh -# -# Adapted from record-c-interrupts.sh without the interrupt-resume logic — -# a2ui flows emit inline A2UI JSONL envelopes within a single run. -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "$0")/../../../../../.." && pwd)" -cd "$REPO_ROOT" - -if [[ -z "${OPENAI_API_KEY:-}" ]]; then - for env_path in examples/chat/python/.env cockpit/chat/a2ui/python/.env; do - if [[ -f "$env_path" ]]; then - set -a; source "$env_path"; set +a - break - fi - done -fi -if [[ -z "${OPENAI_API_KEY:-}" ]]; then - echo "OPENAI_API_KEY not set (in env or examples/chat/python/.env)" >&2 - exit 1 -fi - -AIMOCK_PORT=19997 -LANGGRAPH_PORT=5512 -FIXTURE_OUT="cockpit/chat/a2ui/angular/e2e/fixtures/c-a2ui.json" -RECORD_DIR="$(pwd)/cockpit/chat/a2ui/angular/e2e/fixtures/.staging" -rm -rf "$RECORD_DIR" -mkdir -p "$RECORD_DIR" -TMP_DIR="$(mktemp -d)" -trap 'rm -rf "$TMP_DIR"' EXIT - -if [[ -f "examples/chat/python/.env" ]]; then - cp examples/chat/python/.env cockpit/chat/a2ui/python/.env -fi - -echo "[record] starting aimock --record on :$AIMOCK_PORT" -mkdir -p "$(dirname "$FIXTURE_OUT")" -npx -y -p @copilotkit/aimock llmock \ - --port "$AIMOCK_PORT" \ - --record \ - --provider-openai https://api.openai.com \ - --fixtures "$RECORD_DIR" \ - --chunk-size 4096 \ - > "$TMP_DIR/aimock.log" 2>&1 & -AIMOCK_PID=$! - -cleanup() { - if [[ -n "${LG_PID:-}" ]]; then - pkill -P "$LG_PID" 2>/dev/null || true - kill "$LG_PID" 2>/dev/null || true - fi - kill "$AIMOCK_PID" 2>/dev/null || true - wait 2>/dev/null || true - rm -rf "$TMP_DIR" -} -trap cleanup EXIT - -for _ in {1..30}; do - if curl -sf "http://127.0.0.1:$AIMOCK_PORT/health" > /dev/null 2>&1; then break; fi - if curl -sf "http://127.0.0.1:$AIMOCK_PORT/" > /dev/null 2>&1; then break; fi - sleep 1 -done -echo "[record] aimock ready" - -echo "[record] starting langgraph dev on :$LANGGRAPH_PORT (OPENAI_BASE_URL=http://127.0.0.1:$AIMOCK_PORT/v1)" -if command -v setsid >/dev/null 2>&1; then - RUN_PREFIX="setsid" -else - RUN_PREFIX="" -fi -( - cd cockpit/chat/a2ui/python - OPENAI_BASE_URL="http://127.0.0.1:$AIMOCK_PORT/v1" OPENAI_API_KEY="$OPENAI_API_KEY" \ - exec $RUN_PREFIX uv run langgraph dev --port "$LANGGRAPH_PORT" --no-browser -) > "$TMP_DIR/langgraph.log" 2>&1 & -LG_PID=$! - -for _ in {1..60}; do - if curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/ok" > /dev/null; then break; fi - sleep 1 -done -if ! curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/ok" > /dev/null; then - echo "[record] langgraph failed to start; tail of log:" >&2 - tail -30 "$TMP_DIR/langgraph.log" >&2 - exit 2 -fi -echo "[record] langgraph ready" - -drive_prompt() { - local prompt="$1" - local label="$2" - - echo "[record][$label] thread + run with prompt: $prompt" - local thread - thread=$(curl -sf -X POST "http://127.0.0.1:$LANGGRAPH_PORT/threads" \ - -H 'content-type: application/json' -d '{}' \ - | python3 -c 'import sys,json; print(json.load(sys.stdin)["thread_id"])') - local run - run=$(curl -sf -X POST "http://127.0.0.1:$LANGGRAPH_PORT/threads/$thread/runs" \ - -H 'content-type: application/json' \ - -d "{\"assistant_id\": \"c-a2ui\", \"input\": {\"messages\": [{\"role\": \"user\", \"content\": \"$prompt\"}]}}" \ - | python3 -c 'import sys,json; print(json.load(sys.stdin)["run_id"])') - echo "[record][$label] thread=$thread run=$run; polling for completion" - - local status="" - for _ in {1..120}; do - status=$(curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/threads/$thread/runs/$run" \ - | python3 -c 'import sys,json; print(json.load(sys.stdin).get("status",""))') - case "$status" in - success|error|timeout|interrupted) break ;; - esac - sleep 2 - done - if [[ "$status" != "success" ]]; then - echo "[record][$label] run did not reach success (status=$status)" >&2 - tail -40 "$TMP_DIR/langgraph.log" >&2 - exit 3 - fi - echo "[record][$label] run succeeded" -} - -# Welcome-chip prompts from a2ui.component.ts. -drive_prompt "I want to fly LAX to JFK" "lax-jfk" -drive_prompt "I want to fly SFO to SEA" "sfo-sea" - -sleep 2 - -RECORDED_DIR="$RECORD_DIR/recorded" -if [[ ! -d "$RECORDED_DIR" ]]; then - echo "[record] no recorded fixtures dir at $RECORDED_DIR" >&2 - tail -40 "$TMP_DIR/aimock.log" >&2 - exit 5 -fi -RECORDED_FILES=$(find "$RECORDED_DIR" -name "*.json" | wc -l | tr -d ' ') -echo "[record] $RECORDED_FILES recorded fixture files in $RECORDED_DIR" - -python3 - <&2 - exit 6 -fi -echo "[record] fixture written: $FIXTURE_OUT ($(wc -c < "$FIXTURE_OUT") bytes)" -ENTRY_COUNT=$(python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print(len(d.get("fixtures",[])))' "$FIXTURE_OUT") -echo "[record] $ENTRY_COUNT fixture entries" diff --git a/cockpit/chat/generative-ui/angular/e2e/scripts/record-c-generative-ui.sh b/cockpit/chat/generative-ui/angular/e2e/scripts/record-c-generative-ui.sh deleted file mode 100755 index 06e2938d..00000000 --- a/cockpit/chat/generative-ui/angular/e2e/scripts/record-c-generative-ui.sh +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: MIT -# -# Capture aimock fixtures for the c-generative-ui graph by running the -# standalone langgraph dev server against aimock in --record mode. Drives -# two prompts (one per welcome chip) so the recorded fixture covers the -# dashboard + filter flows. -# -# Run from repo root: -# OPENAI_API_KEY=sk-... bash cockpit/chat/generative-ui/angular/e2e/scripts/record-c-generative-ui.sh -# -# Adapted from cockpit/chat/interrupts/angular/e2e/scripts/record-c-interrupts.sh -# without the interrupt-resume logic — generative-ui flows are normal -# tool_call → tool_result → text continuation runs. -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "$0")/../../../../../.." && pwd)" -cd "$REPO_ROOT" - -if [[ -z "${OPENAI_API_KEY:-}" ]]; then - for env_path in examples/chat/python/.env cockpit/chat/generative-ui/python/.env; do - if [[ -f "$env_path" ]]; then - set -a; source "$env_path"; set +a - break - fi - done -fi -if [[ -z "${OPENAI_API_KEY:-}" ]]; then - echo "OPENAI_API_KEY not set (in env or examples/chat/python/.env)" >&2 - exit 1 -fi - -AIMOCK_PORT=19998 -LANGGRAPH_PORT=5511 -FIXTURE_OUT="cockpit/chat/generative-ui/angular/e2e/fixtures/c-generative-ui.json" -RECORD_DIR="$(pwd)/cockpit/chat/generative-ui/angular/e2e/fixtures/.staging" -rm -rf "$RECORD_DIR" -mkdir -p "$RECORD_DIR" -TMP_DIR="$(mktemp -d)" -trap 'rm -rf "$TMP_DIR"' EXIT - -if [[ -f "examples/chat/python/.env" ]]; then - cp examples/chat/python/.env cockpit/chat/generative-ui/python/.env -fi - -echo "[record] starting aimock --record on :$AIMOCK_PORT" -mkdir -p "$(dirname "$FIXTURE_OUT")" -npx -y -p @copilotkit/aimock llmock \ - --port "$AIMOCK_PORT" \ - --record \ - --provider-openai https://api.openai.com \ - --fixtures "$RECORD_DIR" \ - --chunk-size 4096 \ - > "$TMP_DIR/aimock.log" 2>&1 & -AIMOCK_PID=$! - -cleanup() { - if [[ -n "${LG_PID:-}" ]]; then - pkill -P "$LG_PID" 2>/dev/null || true - kill "$LG_PID" 2>/dev/null || true - fi - kill "$AIMOCK_PID" 2>/dev/null || true - wait 2>/dev/null || true - rm -rf "$TMP_DIR" -} -trap cleanup EXIT - -for _ in {1..30}; do - if curl -sf "http://127.0.0.1:$AIMOCK_PORT/health" > /dev/null 2>&1; then break; fi - if curl -sf "http://127.0.0.1:$AIMOCK_PORT/" > /dev/null 2>&1; then break; fi - sleep 1 -done -echo "[record] aimock ready" - -echo "[record] starting langgraph dev on :$LANGGRAPH_PORT (OPENAI_BASE_URL=http://127.0.0.1:$AIMOCK_PORT/v1)" -if command -v setsid >/dev/null 2>&1; then - RUN_PREFIX="setsid" -else - RUN_PREFIX="" -fi -( - cd cockpit/chat/generative-ui/python - OPENAI_BASE_URL="http://127.0.0.1:$AIMOCK_PORT/v1" OPENAI_API_KEY="$OPENAI_API_KEY" \ - exec $RUN_PREFIX uv run langgraph dev --port "$LANGGRAPH_PORT" --no-browser -) > "$TMP_DIR/langgraph.log" 2>&1 & -LG_PID=$! - -for _ in {1..60}; do - if curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/ok" > /dev/null; then break; fi - sleep 1 -done -if ! curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/ok" > /dev/null; then - echo "[record] langgraph failed to start; tail of log:" >&2 - tail -30 "$TMP_DIR/langgraph.log" >&2 - exit 2 -fi -echo "[record] langgraph ready" - -# Helper: drive one prompt to completion (no interrupt; normal tool_call/ -# continuation cycle handled within the run). -drive_prompt() { - local prompt="$1" - local label="$2" - - echo "[record][$label] thread + run with prompt: $prompt" - local thread - thread=$(curl -sf -X POST "http://127.0.0.1:$LANGGRAPH_PORT/threads" \ - -H 'content-type: application/json' -d '{}' \ - | python3 -c 'import sys,json; print(json.load(sys.stdin)["thread_id"])') - local run - run=$(curl -sf -X POST "http://127.0.0.1:$LANGGRAPH_PORT/threads/$thread/runs" \ - -H 'content-type: application/json' \ - -d "{\"assistant_id\": \"c-generative-ui\", \"input\": {\"messages\": [{\"role\": \"user\", \"content\": \"$prompt\"}]}}" \ - | python3 -c 'import sys,json; print(json.load(sys.stdin)["run_id"])') - echo "[record][$label] thread=$thread run=$run; polling for completion" - - local status="" - for _ in {1..120}; do - status=$(curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/threads/$thread/runs/$run" \ - | python3 -c 'import sys,json; print(json.load(sys.stdin).get("status",""))') - case "$status" in - success|error|timeout|interrupted) break ;; - esac - sleep 2 - done - if [[ "$status" != "success" ]]; then - echo "[record][$label] run did not reach success (status=$status)" >&2 - tail -40 "$TMP_DIR/langgraph.log" >&2 - exit 3 - fi - echo "[record][$label] run succeeded" -} - -# Welcome-chip prompts from generative-ui.component.ts. -drive_prompt "Show me a dashboard of airline operations." "dashboard" -drive_prompt "Filter to only the cancelled flights." "filter" - -sleep 2 - -RECORDED_DIR="$RECORD_DIR/recorded" -if [[ ! -d "$RECORDED_DIR" ]]; then - echo "[record] no recorded fixtures dir at $RECORDED_DIR" >&2 - tail -40 "$TMP_DIR/aimock.log" >&2 - exit 5 -fi -RECORDED_FILES=$(find "$RECORDED_DIR" -name "*.json" | wc -l | tr -d ' ') -echo "[record] $RECORDED_FILES recorded fixture files in $RECORDED_DIR" - -python3 - <&2 - exit 6 -fi -echo "[record] fixture written: $FIXTURE_OUT ($(wc -c < "$FIXTURE_OUT") bytes)" -ENTRY_COUNT=$(python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print(len(d.get("fixtures",[])))' "$FIXTURE_OUT") -echo "[record] $ENTRY_COUNT fixture entries" diff --git a/cockpit/chat/interrupts/angular/e2e/scripts/record-c-interrupts.sh b/cockpit/chat/interrupts/angular/e2e/scripts/record-c-interrupts.sh index d81046db..a8c7e4dd 100755 --- a/cockpit/chat/interrupts/angular/e2e/scripts/record-c-interrupts.sh +++ b/cockpit/chat/interrupts/angular/e2e/scripts/record-c-interrupts.sh @@ -6,6 +6,20 @@ # flows in sequence so the recorded fixture covers both confirm and cancel # resume paths. # +# WHY THIS IS A SPECIAL-CASE SCRIPT (not using the generic +# scripts/record-aimock-cap.sh): +# +# Most caps' flows are normal LLM-call → tool_call → continuation cycles +# that complete in a single run; the generic recorder handles those by +# polling for terminal status (success/error/timeout/interrupted) and then +# merging the captured fixture files. c-interrupts is different: the graph +# calls langgraph's interrupt() inside a ToolNode, which pauses the run +# (status=interrupted) and requires the client to POST a `command.resume` +# value back to continue. The recorded fixture has to capture BOTH the +# pre-interrupt LLM call AND the post-resume continuation, which means +# driving the resume API call from the recorder script. The drive_flow +# helper below handles that two-phase dance. +# # Run from repo root: # OPENAI_API_KEY=sk-... bash cockpit/chat/interrupts/angular/e2e/scripts/record-c-interrupts.sh set -euo pipefail diff --git a/cockpit/chat/subagents/angular/e2e/scripts/record-c-subagents.sh b/cockpit/chat/subagents/angular/e2e/scripts/record-c-subagents.sh deleted file mode 100755 index 7c5ed86d..00000000 --- a/cockpit/chat/subagents/angular/e2e/scripts/record-c-subagents.sh +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: MIT -# -# Capture a complete aimock fixture for the c-subagents graph by running the -# real langgraph dev server against aimock in --record mode. Captures every -# LLM call (orchestrator + each subagent's nested calls + tool-driven -# sub-rounds) at the HTTP layer. -# -# Why this shape (vs. direct Python LLM invocation): the c-subagents graph's -# `task` tool dispatches to subagent functions that run their own LLM-driven -# agent loops. Direct invocation only captures the orchestrator's calls; -# proxying through aimock captures every LLM call in the full graph. -# -# Run from repo root: -# OPENAI_API_KEY=sk-... bash cockpit/chat/subagents/angular/e2e/scripts/record-c-subagents.sh -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "$0")/../../../../../.." && pwd)" -cd "$REPO_ROOT" - -if [[ -z "${OPENAI_API_KEY:-}" ]]; then - # Try .env (examples first, then the standalone backend as fallback for worktrees) - for env_path in examples/chat/python/.env cockpit/chat/subagents/python/.env; do - if [[ -f "$env_path" ]]; then - set -a; source "$env_path"; set +a - break - fi - done -fi -if [[ -z "${OPENAI_API_KEY:-}" ]]; then - echo "OPENAI_API_KEY not set (in env, examples/chat/python/.env, or cockpit/chat/subagents/python/.env)" >&2 - exit 1 -fi - -AIMOCK_PORT=19999 -LANGGRAPH_PORT=5505 -FIXTURE_OUT="cockpit/chat/subagents/angular/e2e/fixtures/c-subagents.json" -# Aimock --record writes per-request files into /recorded/. -# We hand it a dedicated staging dir, then merge all recorded entries into the -# single multi-turn fixture file consumed by the e2e harness. -RECORD_DIR="$(pwd)/cockpit/chat/subagents/angular/e2e/fixtures/.staging" -rm -rf "$RECORD_DIR" -mkdir -p "$RECORD_DIR" -TMP_DIR="$(mktemp -d)" -trap 'rm -rf "$TMP_DIR"' EXIT - -# Copy .env into the standalone subagents python project (gitignored). -# Use examples/.env when present; otherwise the project .env already exists -# in worktrees where examples/.env hasn't been propagated. -mkdir -p cockpit/chat/subagents/python -if [[ -f "examples/chat/python/.env" ]]; then - cp examples/chat/python/.env cockpit/chat/subagents/python/.env -fi - -# 1. Start aimock in record mode -echo "[record] starting aimock --record on :$AIMOCK_PORT" -mkdir -p "$(dirname "$FIXTURE_OUT")" -npx -y -p @copilotkit/aimock llmock \ - --port "$AIMOCK_PORT" \ - --record \ - --provider-openai https://api.openai.com \ - --fixtures "$RECORD_DIR" \ - --chunk-size 4096 \ - > "$TMP_DIR/aimock.log" 2>&1 & -AIMOCK_PID=$! - -# Cleanup on exit -cleanup() { - if [[ -n "${LG_PID:-}" ]]; then - # Kill descendants first (uv → python → langgraph workers), then the parent - pkill -P "$LG_PID" 2>/dev/null || true - kill "$LG_PID" 2>/dev/null || true - fi - kill "$AIMOCK_PID" 2>/dev/null || true - wait 2>/dev/null || true - rm -rf "$TMP_DIR" -} -trap cleanup EXIT - -# Wait for aimock to be ready -for _ in {1..30}; do - if curl -sf "http://127.0.0.1:$AIMOCK_PORT/health" > /dev/null 2>&1; then break; fi - if curl -sf "http://127.0.0.1:$AIMOCK_PORT/" > /dev/null 2>&1; then break; fi - sleep 1 -done -echo "[record] aimock ready" - -# 2. Start langgraph dev pointed at aimock -echo "[record] starting langgraph dev on :$LANGGRAPH_PORT (OPENAI_BASE_URL=http://127.0.0.1:$AIMOCK_PORT/v1)" -# setsid on Linux gives us a new process group for clean teardown; on macOS -# fall back to plain background — `pkill -P` later handles descendants. -if command -v setsid >/dev/null 2>&1; then - RUN_PREFIX="setsid" -else - RUN_PREFIX="" -fi -( - cd cockpit/chat/subagents/python - OPENAI_BASE_URL="http://127.0.0.1:$AIMOCK_PORT/v1" OPENAI_API_KEY="test-record" \ - exec $RUN_PREFIX uv run langgraph dev --port "$LANGGRAPH_PORT" --no-browser -) > "$TMP_DIR/langgraph.log" 2>&1 & -LG_PID=$! - -# Wait for langgraph -for i in {1..60}; do - if curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/ok" > /dev/null; then break; fi - sleep 1 -done -if ! curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/ok" > /dev/null; then - echo "[record] langgraph failed to start; tail of log:" >&2 - tail -30 "$TMP_DIR/langgraph.log" >&2 - exit 2 -fi -echo "[record] langgraph ready" - -# 3. Submit a run via the LangGraph SDK HTTP API -THREAD=$(curl -sf -X POST "http://127.0.0.1:$LANGGRAPH_PORT/threads" -H 'content-type: application/json' -d '{}' | python3 -c 'import sys,json; print(json.load(sys.stdin)["thread_id"])') -echo "[record] thread: $THREAD" -RUN=$(curl -sf -X POST "http://127.0.0.1:$LANGGRAPH_PORT/threads/$THREAD/runs" \ - -H 'content-type: application/json' \ - -d '{ - "assistant_id": "c-subagents", - "input": {"messages": [{"role": "user", "content": "Plan a trip from LAX to JFK"}]} - }' | python3 -c 'import sys,json; print(json.load(sys.stdin)["run_id"])') -echo "[record] run: $RUN" - -# 4. Poll the run status (pending → running → success/error/timeout/interrupted) -echo "[record] waiting for run to complete (this hits real OpenAI; ~30-180s)..." -RUN_STATUS="" -for i in {1..180}; do - RUN_STATUS=$(curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/threads/$THREAD/runs/$RUN" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("status",""))') - case "$RUN_STATUS" in - success|error|timeout|interrupted) break ;; - esac - sleep 2 -done -echo "[record] final run status: $RUN_STATUS" -if [[ "$RUN_STATUS" != "success" ]]; then - echo "[record] run did not succeed (status=$RUN_STATUS)" >&2 - echo "--- langgraph.log tail ---" >&2 - tail -80 "$TMP_DIR/langgraph.log" >&2 - echo "--- aimock.log tail ---" >&2 - tail -40 "$TMP_DIR/aimock.log" >&2 - exit 3 -fi -MSG_COUNT=$(curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/threads/$THREAD/state" | python3 -c 'import sys,json; s=json.load(sys.stdin); print(len(s["values"].get("messages",[])))') -echo "[record] run complete; ${MSG_COUNT} messages in state" -if [[ "$MSG_COUNT" == "0" ]]; then - echo "[record] run produced 0 messages — surfacing logs for debugging" >&2 - echo "--- langgraph.log tail ---" >&2 - tail -60 "$TMP_DIR/langgraph.log" >&2 - echo "--- aimock.log tail ---" >&2 - tail -60 "$TMP_DIR/aimock.log" >&2 - echo "--- run status ---" >&2 - curl -sf "http://127.0.0.1:$LANGGRAPH_PORT/threads/$THREAD/runs/$RUN" >&2 - exit 5 -fi - -# 5. Give aimock a moment to flush per-request fixture files -sleep 2 - -# 6. Merge all recorded-* files in $RECORD_DIR/recorded/ into one fixtures.json -RECORDED_DIR="$RECORD_DIR/recorded" -if [[ ! -d "$RECORDED_DIR" ]]; then - echo "[record] no recorded fixtures dir at $RECORDED_DIR" >&2 - echo "[record] aimock log tail:" >&2 - tail -40 "$TMP_DIR/aimock.log" >&2 - exit 4 -fi -RECORDED_FILES=$(find "$RECORDED_DIR" -name "*.json" | wc -l | tr -d ' ') -echo "[record] $RECORDED_FILES recorded fixture files in $RECORDED_DIR" -python3 - <&2 - exit 4 -fi -echo "[record] fixture written: $FIXTURE_OUT ($(wc -c < "$FIXTURE_OUT") bytes)" -ENTRY_COUNT=$(python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print(len(d.get("fixtures",[])))' "$FIXTURE_OUT") -echo "[record] $ENTRY_COUNT fixture entries" diff --git a/cockpit/chat/tool-calls/angular/e2e/scripts/record-c-tool-calls.py b/cockpit/chat/tool-calls/angular/e2e/scripts/record-c-tool-calls.py deleted file mode 100644 index d9f3cb60..00000000 --- a/cockpit/chat/tool-calls/angular/e2e/scripts/record-c-tool-calls.py +++ /dev/null @@ -1,95 +0,0 @@ -"""Capture parent first-call (tool_call) + continuation (text) for c-tool-calls. - -Mirrors cockpit/chat/tool-calls/python/src/graph.py's c-tool-calls LLM setup: -ChatOpenAI(gpt-5-mini, streaming=True) bound with AVIATION_TOOLS, system -prompt from prompts/tool-calls.md. - -Two LLM calls captured, written into one fixture with the hasToolResult -discriminator on the continuation entry. - -Run from repo root: - OPENAI_API_KEY=sk-... uv run --project cockpit/chat/tool-calls/python \ - python cockpit/chat/tool-calls/angular/e2e/scripts/record-c-tool-calls.py -""" -import asyncio -import json -import os -import sys -import uuid -from pathlib import Path - -env_path = Path("cockpit/chat/tool-calls/python/.env") -if env_path.exists(): - for line in env_path.read_text().splitlines(): - line = line.strip() - if line and not line.startswith("#") and "=" in line: - k, _, v = line.partition("=") - os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'")) - -if not os.environ.get("OPENAI_API_KEY"): - print("OPENAI_API_KEY not set", file=sys.stderr) - sys.exit(1) - -sys.path.insert(0, str(Path("cockpit/chat/tool-calls/python/src").resolve())) - -from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage -from langchain_openai import ChatOpenAI - -from src.aviation_tools import ALL_TOOLS as AVIATION_TOOLS, lookup_flight # type: ignore - -PROMPT = "What's the status of UA123?" -SYSTEM_PROMPT = ( - Path("cockpit/chat/tool-calls/python/prompts/tool-calls.md").read_text() -) - -llm = ChatOpenAI(model="gpt-5-mini", temperature=0).bind_tools(AVIATION_TOOLS) - -# 1. Parent's first call. -first = llm.invoke([SystemMessage(content=SYSTEM_PROMPT), HumanMessage(content=PROMPT)]) -assert first.tool_calls, f"Parent did not emit tool_calls; content={first.content!r}" -tc = first.tool_calls[0] -tc_args = tc.get("args") or {} -tc_id = tc.get("id") or f"call_{uuid.uuid4().hex[:12]}" -print(f"1. parent tool_call name={tc.get('name')} args={tc_args}") - -# 2. Tool result (real lookup_flight). -tool_result = asyncio.run(lookup_flight.ainvoke(tc_args)) # returns canned aviation data -print(f"2. tool result length={len(str(tool_result))}") - -# 3. Parent's continuation call. -continuation = llm.invoke( - [ - SystemMessage(content=SYSTEM_PROMPT), - HumanMessage(content=PROMPT), - AIMessage( - content="", - tool_calls=[{"name": tc.get("name"), "args": tc_args, "id": tc_id, "type": "tool_call"}], - ), - ToolMessage(content=str(tool_result), tool_call_id=tc_id), - ], -) -text = continuation.content if isinstance(continuation.content, str) else "" -if not text.strip(): - print("Continuation returned empty; aborting", file=sys.stderr) - sys.exit(2) -print(f"3. continuation: {len(text)} chars; first 80: {text[:80]!r}") - -fixture = { - "fixtures": [ - # ORDER MATTERS: continuation match is more specific (hasToolResult); - # aimock evaluates fixtures top-to-bottom and picks the first match. - { - "match": {"userMessage": PROMPT, "hasToolResult": True}, - "response": {"content": text}, - }, - { - "match": {"userMessage": PROMPT}, - "response": {"toolCalls": [{"name": tc.get("name"), "arguments": tc_args}]}, - }, - ] -} - -out_path = Path("cockpit/chat/tool-calls/angular/e2e/fixtures/c-tool-calls.json") -out_path.parent.mkdir(parents=True, exist_ok=True) -out_path.write_text(json.dumps(fixture, indent=2) + "\n") -print(f"\nWrote fixture to {out_path}") diff --git a/cockpit/langgraph/streaming/angular/e2e/scripts/record-streaming.py b/cockpit/langgraph/streaming/angular/e2e/scripts/record-streaming.py deleted file mode 100644 index a77e9910..00000000 --- a/cockpit/langgraph/streaming/angular/e2e/scripts/record-streaming.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Capture a real text response from the streaming graph's LLM. - -Mirrors cockpit/langgraph/streaming/python/src/graph.py's -build_streaming_graph() setup: ChatOpenAI(gpt-5-mini, streaming=True) -+ system prompt from prompts/streaming.md. - -Run from repo root: - OPENAI_API_KEY=sk-... uv run --project cockpit/langgraph/streaming/python \ - python cockpit/langgraph/streaming/angular/e2e/scripts/record-streaming.py -""" -import json -import os -import sys -from pathlib import Path - -env_path = Path("cockpit/langgraph/streaming/python/.env") -if env_path.exists(): - for line in env_path.read_text().splitlines(): - line = line.strip() - if line and not line.startswith("#") and "=" in line: - k, _, v = line.partition("=") - os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'")) - -if not os.environ.get("OPENAI_API_KEY"): - print("OPENAI_API_KEY not set (in env or .env)", file=sys.stderr) - sys.exit(1) - -from langchain_core.messages import HumanMessage, SystemMessage -from langchain_openai import ChatOpenAI - -PROMPT = "Tell me one quick fact about Angular signals in two sentences." -SYSTEM_PROMPT = ( - Path("cockpit/langgraph/streaming/python/prompts/streaming.md").read_text() -) - -llm = ChatOpenAI(model="gpt-5-mini", temperature=0) -response = llm.invoke( - [SystemMessage(content=SYSTEM_PROMPT), HumanMessage(content=PROMPT)], -) -text = response.content if isinstance(response.content, str) else "" -if not text.strip(): - print("LLM returned empty content; cannot build fixture", file=sys.stderr) - sys.exit(2) -print(f"captured {len(text)} chars; first 80: {text[:80]!r}") - -fixture = { - "fixtures": [ - { - "match": {"userMessage": PROMPT}, - "response": {"content": text}, - } - ] -} - -out_path = Path("cockpit/langgraph/streaming/angular/e2e/fixtures/streaming.json") -out_path.parent.mkdir(parents=True, exist_ok=True) -out_path.write_text(json.dumps(fixture, indent=2) + "\n") -print(f"\nWrote fixture to {out_path}")