{
  "file": "F21-agent-profiles.md",
  "bullet": "TypeScript client (`F21.ts-client`).",
  "ids": [
    "F21.ts-client"
  ],
  "line": 688,
  "script": "test -f clients/typescript/dist/clients.js || (cd clients/typescript && npm ci && npm run build)\nF21TS=\"$AGENT_SERVER_VERIFY_RUN/fixtures/qa-f21-ts\"\nmkdir -p \"$F21TS\"\ncat > \"$F21TS/ts_agent_profiles.mjs\" <<'JS'\nimport assert from 'node:assert/strict';\nimport { resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nconst { AgentProfilesClient, AgentServerClient } = await import(pathToFileURL(resolve('clients/typescript/dist/clients.js')).href);\nconst options = { host: process.env.AGENT_SERVER_URL, apiKey: process.env.SESSION_API_KEY };\nconst client = new AgentProfilesClient(options);\nconst coder = process.env.QA_F21_CODER;\nconst before = await client.listAgentProfiles();\nassert.equal(before.active_agent_profile_id, coder);\nassert.equal(before.profiles.filter((p) => p.name === 'default' && p.agent_kind === 'openhands').length, 1);\nconst body = { agent_kind: 'openhands', llm_profile_ref: 'deepseek-flash', tools: [], mcp_server_refs: [] };\nassert.deepEqual(await client.saveAgentProfile('qa-f21-ts', body), { name: 'qa-f21-ts', message: \"Agent profile 'qa-f21-ts' saved\" });\nconst saved = (await client.getAgentProfile('qa-f21-ts')).profile;\nassert.equal(saved.revision, 0);\nassert.equal(saved.llm_profile_ref, 'deepseek-flash');\nassert.equal((await client.renameAgentProfile('qa-f21-ts', 'qa-f21-ts2')).name, 'qa-f21-ts2');\nassert.equal((await client.getAgentProfile('qa-f21-ts2')).profile.id, saved.id);\nconst activated = await client.activateAgentProfile(saved.id);\nassert.equal(activated.id, saved.id);\nassert.equal(activated.agent_settings_applied, false);\nconst server = new AgentServerClient(options);\nassert.equal((await server.agentProfiles.listAgentProfiles()).active_agent_profile_id, saved.id);\nconst draft = await client.materializeAgentProfile('qa-f21-ts2', { ...body, llm_profile_ref: 'deepseek-pro' });\nassert.equal(draft.valid, true);\nassert.equal(draft.llm_profile_ref, 'deepseek-pro');\nassert.equal(draft.resolved_settings.llm.model, 'deepseek/deepseek-v4-pro');\nconst stored = await client.materializeAgentProfile('qa-f21-ts2');\nassert.equal(stored.valid, true);\nassert.equal(stored.resolved_settings.llm.model, 'deepseek/deepseek-flash');\nassert.equal((await client.getAgentProfile('qa-f21-ts2')).profile.revision, 0);\nassert.equal((await client.activateAgentProfile(coder)).id, coder);\nassert.equal((await client.deleteAgentProfile('qa-f21-ts2')).message, \"Agent profile 'qa-f21-ts2' deleted\");\nawait assert.rejects(client.getAgentProfile('qa-f21-ts2'), (err) => err.name === 'HttpError' && err.status === 404);\nawait assert.rejects(client.materializeAgentProfile('qa-f21-ts2'), (err) => err.name === 'HttpError' && err.status === 404);\nawait assert.rejects(client.saveAgentProfile('-qa-f21-bad', body), (err) => err.name === 'HttpError' && err.status === 422);\nconst after = await client.listAgentProfiles();\nassert.equal(after.active_agent_profile_id, coder);\nassert.equal(after.profiles.length, before.profiles.length);\nclient.close();\nserver.close();\nconsole.log('QA_F21_TS_OK');\nJS\ncontrol-agent-server exec --env QA_F21_CODER=\"$CODER\" --timeout 120 --expect-output QA_F21_TS_OK --save F21.ts-client/program \\\n  -- node \"$F21TS/ts_agent_profiles.mjs\"\ncontrol-agent-server api GET /api/agent-profiles --check active_agent_profile_id eq \"$CODER\" --save F21.ts-client/list-after\ncontrol-agent-server api GET /api/agent-profiles/qa-f21-ts --expect 404\ncontrol-agent-server api GET /api/agent-profiles/qa-f21-ts2 --expect 404\n",
  "exit_code": 0,
  "elapsed_ms": 3717,
  "failed_line": null,
  "failed_command": null,
  "stdout": "{\n  \"ok\": true,\n  \"exit_code\": 0,\n  \"elapsed_ms\": 884,\n  \"stdout_tail\": \"QA_F21_TS_OK\\n\",\n  \"stderr_tail\": \"\",\n  \"saved\": \"/workspace/verification-artifacts/runs/20261013-024523-a1a8-map-f21/evidence/F21.ts-client/program.json\"\n}\n{\n  \"ok\": true,\n  \"status\": 200,\n  \"request\": {\n    \"method\": \"GET\",\n    \"path\": \"/api/agent-profiles\",\n    \"query\": [],\n    \"auth\": \"header\",\n    \"body\": null,\n    \"files\": []\n  },\n  \"response\": {\n    \"status\": 200,\n    \"headers\": {\n      \"content-length\": \"1210\",\n      \"content-type\": \"application/json\"\n    },\n    \"body\": {\n      \"profiles\": [\n        {\n          \"id\": \"1fff4213-eb21-47ae-a931-7e69f48534c8\",\n          \"name\": \"default\",\n          \"agent_kind\": \"openhands\",\n          \"revision\": 0,\n          \"llm_profile_ref\": \"deepseek-flash\",\n          \"mcp_server_refs\": null\n        },\n        {\n          \"id\": \"c7e9ccda-14ac-48cd-a256-acf298db21a9\",\n          \"name\": \"qa-f21-acp\",\n          \"agent_kind\": \"acp\",\n          \"revision\": 0,\n          \"llm_profile_ref\": null,\n          \"mcp_server_refs\": null\n        },\n        {\n          \"id\": \"562ebf69-ef57-497a-b6ed-6b78ee3a53f2\",\n          \"name\": \"qa-f21-additions\",\n          \"agent_kind\": \"openhands\",\n          \"revision\": 0,\n          \"llm_profile_ref\": \"deepseek-flash\",\n          \"mcp_server_refs\": []\n        },\n        {\n          \"id\": \"43ce9247-266d-4a2f-b19b-b537c2f5449c\",\n          \"name\": \"qa-f21-coder\",\n          \"agent_kind\": \"openhands\",\n          \"revision\": 1,\n          \"llm_profile_ref\": \"deepseek-pro\",\n          \"mcp_server_refs\": []\n        },\n        {\n          \"id\": \"6f00b085-90f6-492a-8437-db8f4f94d000\",\n          \"name\": \"qa-f21-preview\",\n          \"agent_kind\": \"openhands\",\n          \"revision\": 0,\n          \"llm_profile_ref\": \"deepseek-flash\",\n          \"mcp_server_refs\": [\n            \"qa-f21-mcp\"\n          ]\n        },\n        {\n          \"id\": \"22ff29e4-8e31-4b5b-9994-9dc948b01c9a\",\n          \"name\": \"qa-f21-runner\",\n          \"agent_kind\": \"openhands\",\n          \"revision\": 1,\n          \"llm_profile_ref\": \"deepseek-flash\",\n          \"mcp_server_refs\": []\n        },\n        {\n          \"id\": \"b131acbf-0885-4fd5-8bd3-ffd22b4d5883\",\n          \"name\": \"qa-f21-scoped\",\n          \"agent_kind\": \"openhands\",\n          \"revision\": 0,\n          \"llm_profile_ref\": \"deepseek-flash\",\n          \"mcp_server_refs\": []\n        }\n      ],\n      \"active_agent_profile_id\": \"43ce9247-266d-4a2f-b19b-b537c2f5449c\"\n    },\n    \"truncated\": false\n  },\n  \"elapsed_ms\": 103,\n  \"checks\": [\n    {\n      \"check\": \"active_agent_profile_id eq 43ce9247-266d-4a2f-b19b-b537c2f5449c\",\n      \"ok\": true,\n      \"actual\": \"43ce9247-266d-4a2f-b19b-b537c2f5449c\"\n    }\n  ],\n  \"saved\": \"/workspace/verification-artifacts/runs/20261013-024523-a1a8-map-f21/evidence/F21.ts-client/list-after.json\"\n}\n{\n  \"ok\": true,\n  \"status\": 404,\n  \"request\": {\n    \"method\": \"GET\",\n    \"path\": \"/api/agent-profiles/qa-f21-ts\",\n    \"query\": [],\n    \"auth\": \"header\",\n    \"body\": null,\n    \"files\": []\n  },\n  \"response\": {\n    \"status\": 404,\n    \"headers\": {\n      \"content-length\": \"48\",\n      \"content-type\": \"application/json\"\n    },\n    \"body\": {\n      \"detail\": \"Agent profile 'qa-f21-ts' not found\"\n    },\n    \"truncated\": false\n  },\n  \"elapsed_ms\": 91\n}\n{\n  \"ok\": true,\n  \"status\": 404,\n  \"request\": {\n    \"method\": \"GET\",\n    \"path\": \"/api/agent-profiles/qa-f21-ts2\",\n    \"query\": [],\n    \"auth\": \"header\",\n    \"body\": null,\n    \"files\": []\n  },\n  \"response\": {\n    \"status\": 404,\n    \"headers\": {\n      \"content-length\": \"49\",\n      \"content-type\": \"application/json\"\n    },\n    \"body\": {\n      \"detail\": \"Agent profile 'qa-f21-ts2' not found\"\n    },\n    \"truncated\": false\n  },\n  \"elapsed_ms\": 102\n}\n",
  "stderr": ""
}
