authorgravatar for 71498452+StiensWout@users.noreply.github.comWout Stiens <71498452+StiensWout@users.noreply.github.com> 2026-10-09 07:45:58+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-09 00:45:58-05:00
log3b6af0bd1600f034b0466e1b8ff017fbabeba910
tree040d631e5f69a01196f32669eac674e9c17758f3
parent563645cf6e104ad930f4c9b209678a77eef07e65
signature Signed by PGP key B5690EEEBB952194

fix(server): Pi loads every selected skill without losing prompt text (#17194)


14 files changed, 185 insertions(+), 173 deletions(-)

apps/server/src/orchestration-v2/testkit/fixtures/message_steering/pi_transcript.ndjson-2
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"message_steering","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"message_steering","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}
2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}
4{"type":"expect_outbound","label":"get_commands","frame":{"type":"get_commands","id":"t3-1"}}
5{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}4{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
6{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}5{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}
7{"type":"emit_inbound","label":"response:get_commands","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
8{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}6{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}
9{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}7{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}
10{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}8{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}
apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/pi_transcript.ndjson-2
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"multi_turn","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"multi_turn","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}
2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}
4{"type":"expect_outbound","label":"get_commands","frame":{"type":"get_commands","id":"t3-1"}}
5{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}4{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
6{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}5{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}
7{"type":"emit_inbound","label":"response:get_commands","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
8{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}6{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}
9{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}7{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}
10{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}8{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}
apps/server/src/orchestration-v2/testkit/fixtures/pi_compaction/pi_transcript.ndjson-2
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"pi_compaction","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"pi_compaction","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}
2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}
4{"type":"expect_outbound","label":"get_commands","frame":{"type":"get_commands","id":"t3-1"}}
5{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}4{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
6{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}5{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}
7{"type":"emit_inbound","label":"response:get_commands","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
8{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}6{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}
9{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}7{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}
10{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}8{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}
apps/server/src/orchestration-v2/testkit/fixtures/provider_thread_resume/pi_transcript.ndjson-4
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"provider_thread_resume","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"provider_thread_resume","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}
2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}
4{"type":"expect_outbound","label":"get_commands","frame":{"type":"get_commands","id":"t3-1"}}
5{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}4{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
6{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}5{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}
7{"type":"emit_inbound","label":"response:get_commands","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
8{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}6{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}
9{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}7{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}
10{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}8{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}
...@@ -61,9 +59,7 @@...@@ -61,9 +59,7 @@
61{"type":"emit_inbound","label":"response:get_session_stats","frame":{"id":"t3-8","type":"response","command":"get_session_stats","success":true,"data":{"sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","userMessages":1,"assistantMessages":1,"toolCalls":0,"toolResults":0,"totalMessages":3,"tokens":{"input":1792,"output":85,"cacheRead":0,"cacheWrite":0,"total":1877},"cost":0.00008212932000000001,"contextUsage":{"tokens":1877,"contextWindow":1048576,"percent":0.17900466918945312}}}}59{"type":"emit_inbound","label":"response:get_session_stats","frame":{"id":"t3-8","type":"response","command":"get_session_stats","success":true,"data":{"sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","userMessages":1,"assistantMessages":1,"toolCalls":0,"toolResults":0,"totalMessages":3,"tokens":{"input":1792,"output":85,"cacheRead":0,"cacheWrite":0,"total":1877},"cost":0.00008212932000000001,"contextUsage":{"tokens":1877,"contextWindow":1048576,"percent":0.17900466918945312}}}}
62{"type":"expect_outbound","label":"process_start@p2","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}60{"type":"expect_outbound","label":"process_start@p2","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
63{"type":"expect_outbound","label":"switch_session@p2","frame":{"type":"switch_session","sessionPath":"/pi-sessions/session-1.jsonl","id":"t3-0"}}61{"type":"expect_outbound","label":"switch_session@p2","frame":{"type":"switch_session","sessionPath":"/pi-sessions/session-1.jsonl","id":"t3-0"}}
64{"type":"expect_outbound","label":"get_commands@p2","frame":{"type":"get_commands","id":"t3-1"}}
65{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000003","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}62{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000003","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
66{"type":"emit_inbound","label":"response:get_commands@p2","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
67{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000004","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}63{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000004","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
68{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000005","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}64{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000005","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
69{"type":"emit_inbound","label":"response:switch_session@p2","frame":{"id":"t3-0","type":"response","command":"switch_session","success":true,"data":{"cancelled":false}}}65{"type":"emit_inbound","label":"response:switch_session@p2","frame":{"id":"t3-0","type":"response","command":"switch_session","success":true,"data":{"cancelled":false}}}
apps/server/src/orchestration-v2/testkit/fixtures/simple/pi_transcript.ndjson-2
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"simple","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"simple","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}
2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}
4{"type":"expect_outbound","label":"get_commands","frame":{"type":"get_commands","id":"t3-1"}}
5{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}4{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
6{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}5{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}
7{"type":"emit_inbound","label":"response:get_commands","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
8{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}6{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}
9{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}7{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}
10{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}8{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}
apps/server/src/orchestration-v2/testkit/fixtures/thread_rollback/pi_transcript.ndjson-2
...@@ -1,11 +1,9 @@...@@ -1,11 +1,9 @@
1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"thread_rollback","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"thread_rollback","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}
2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}
4{"type":"expect_outbound","label":"get_commands","frame":{"type":"get_commands","id":"t3-1"}}
5{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}4{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
6{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}5{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}
7{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}6{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}
8{"type":"emit_inbound","label":"response:get_commands","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
9{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}7{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}
10{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}8{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}
11{"type":"emit_inbound","label":"response:get_entries","frame":{"id":"t3-3","type":"response","command":"get_entries","success":true,"data":{"entries":[{"type":"model_change","id":"648fe89a","parentId":null,"timestamp":"2026-01-01T00:00:00.000Z","provider":"openrouter","modelId":"deepseek/deepseek-v4-flash"},{"type":"thinking_level_change","id":"00c31b78","parentId":"648fe89a","timestamp":"2026-01-01T00:00:00.000Z","thinkingLevel":"high"}],"leafId":"00c31b78"}}}9{"type":"emit_inbound","label":"response:get_entries","frame":{"id":"t3-3","type":"response","command":"get_entries","success":true,"data":{"entries":[{"type":"model_change","id":"648fe89a","parentId":null,"timestamp":"2026-01-01T00:00:00.000Z","provider":"openrouter","modelId":"deepseek/deepseek-v4-flash"},{"type":"thinking_level_change","id":"00c31b78","parentId":"648fe89a","timestamp":"2026-01-01T00:00:00.000Z","thinkingLevel":"high"}],"leafId":"00c31b78"}}}
apps/server/src/orchestration-v2/testkit/fixtures/thread_rollback_after_stop/pi_transcript.ndjson-4
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"thread_rollback_after_stop","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"thread_rollback_after_stop","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}
2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}
4{"type":"expect_outbound","label":"get_commands","frame":{"type":"get_commands","id":"t3-1"}}
5{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}4{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
6{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}5{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}
7{"type":"emit_inbound","label":"response:get_commands","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
8{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}6{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}
9{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}7{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}
10{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}8{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}
...@@ -151,9 +149,7 @@...@@ -151,9 +149,7 @@
151{"type":"emit_inbound","label":"response:get_entries","frame":{"id":"t3-10","type":"response","command":"get_entries","success":true,"data":{"entries":[{"type":"message","id":"ee73daae","parentId":"b184b5a8","timestamp":"2026-01-01T00:00:01.971Z","message":{"role":"user","content":[{"type":"text","text":"Run this exact local command: `node -e \"console.log('interrupt fixture tool started'); setTimeout(() => {}, 30000)\"`. Do not answer until it completes, then respond exactly: interrupt fixture should not finish naturally."}],"timestamp":1767225601969}},{"type":"message","id":"c3915df7","parentId":"ee73daae","timestamp":"2026-01-01T00:00:06.406Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"The user wants me to run a command that will wait for 30 seconds, and then after it completes, respond with a specific message. But they also say \"Do not answer until it completes\" - but this command will run for 30 seconds and then naturally finish. However, the response they want is \"interrupt fixture should not finish naturally\" which contradicts the fact that it did finish naturally.\n\nWait, let me re-read. They want me to run the command and not answer until it completes. The command is a node script that logs \"interrupt fixture tool started\" and then waits 30 seconds. If I wait for it to complete, it will finish naturally after 30 seconds. But the response they want is \"interrupt fixture should not finish naturally\" - implying that the fixture should have been interrupted before finishing naturally.\n\nThis is a test scenario. Let me just run it and see what happens. Actually, maybe they want me to just run it and respond accordingly. Let me execute the command.\n\nActually, I think this is part of a test where the system might interrupt/kill the process. Let me just run the command with a sufficient timeout.","thinkingSignature":"<signature>"},{"type":"toolCall","id":"call_8ac3cb4177994abdb9aa1c57","name":"bash","arguments":{"command":"node -e \"console.log('interrupt fixture tool started'); setTimeout(() => {}, 30000)\"","timeout":35}}],"api":"openai-completions","provider":"openrouter","model":"deepseek/deepseek-v4-flash","usage":{"input":77,"output":317,"cacheRead":1792,"cacheWrite":0,"reasoning":284,"totalTokens":2186,"cost":{"input":0.00000322322,"output":0.000026539239999999998,"cacheRead":0.000015002623999999998,"cacheWrite":0,"total":0.000044765084}},"stopReason":"toolUse","timestamp":1767225601972,"responseId":"gen-1790898593-E5hfYfRp6aKBI57pUKss","rawStopReason":"tool_calls","thinkingLevel":"high"}},{"type":"message","id":"641f3d3f","parentId":"c3915df7","timestamp":"2026-01-01T00:00:06.463Z","message":{"role":"toolResult","toolCallId":"call_8ac3cb4177994abdb9aa1c57","toolName":"bash","content":[{"type":"text","text":"interrupt fixture tool started\n\n\nCommand aborted"}],"details":{},"isError":true,"timestamp":1767225606463}},{"type":"message","id":"e3ab1495","parentId":"641f3d3f","timestamp":"2026-01-01T00:00:06.465Z","message":{"role":"assistant","content":[],"api":"openai-completions","provider":"openrouter","model":"deepseek/deepseek-v4-flash","usage":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"totalTokens":0,"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"total":0}},"stopReason":"error","errorMessage":"This operation was aborted","timestamp":1767225606465,"thinkingLevel":"high"}}],"leafId":"e3ab1495"}}}149{"type":"emit_inbound","label":"response:get_entries","frame":{"id":"t3-10","type":"response","command":"get_entries","success":true,"data":{"entries":[{"type":"message","id":"ee73daae","parentId":"b184b5a8","timestamp":"2026-01-01T00:00:01.971Z","message":{"role":"user","content":[{"type":"text","text":"Run this exact local command: `node -e \"console.log('interrupt fixture tool started'); setTimeout(() => {}, 30000)\"`. Do not answer until it completes, then respond exactly: interrupt fixture should not finish naturally."}],"timestamp":1767225601969}},{"type":"message","id":"c3915df7","parentId":"ee73daae","timestamp":"2026-01-01T00:00:06.406Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"The user wants me to run a command that will wait for 30 seconds, and then after it completes, respond with a specific message. But they also say \"Do not answer until it completes\" - but this command will run for 30 seconds and then naturally finish. However, the response they want is \"interrupt fixture should not finish naturally\" which contradicts the fact that it did finish naturally.\n\nWait, let me re-read. They want me to run the command and not answer until it completes. The command is a node script that logs \"interrupt fixture tool started\" and then waits 30 seconds. If I wait for it to complete, it will finish naturally after 30 seconds. But the response they want is \"interrupt fixture should not finish naturally\" - implying that the fixture should have been interrupted before finishing naturally.\n\nThis is a test scenario. Let me just run it and see what happens. Actually, maybe they want me to just run it and respond accordingly. Let me execute the command.\n\nActually, I think this is part of a test where the system might interrupt/kill the process. Let me just run the command with a sufficient timeout.","thinkingSignature":"<signature>"},{"type":"toolCall","id":"call_8ac3cb4177994abdb9aa1c57","name":"bash","arguments":{"command":"node -e \"console.log('interrupt fixture tool started'); setTimeout(() => {}, 30000)\"","timeout":35}}],"api":"openai-completions","provider":"openrouter","model":"deepseek/deepseek-v4-flash","usage":{"input":77,"output":317,"cacheRead":1792,"cacheWrite":0,"reasoning":284,"totalTokens":2186,"cost":{"input":0.00000322322,"output":0.000026539239999999998,"cacheRead":0.000015002623999999998,"cacheWrite":0,"total":0.000044765084}},"stopReason":"toolUse","timestamp":1767225601972,"responseId":"gen-1790898593-E5hfYfRp6aKBI57pUKss","rawStopReason":"tool_calls","thinkingLevel":"high"}},{"type":"message","id":"641f3d3f","parentId":"c3915df7","timestamp":"2026-01-01T00:00:06.463Z","message":{"role":"toolResult","toolCallId":"call_8ac3cb4177994abdb9aa1c57","toolName":"bash","content":[{"type":"text","text":"interrupt fixture tool started\n\n\nCommand aborted"}],"details":{},"isError":true,"timestamp":1767225606463}},{"type":"message","id":"e3ab1495","parentId":"641f3d3f","timestamp":"2026-01-01T00:00:06.465Z","message":{"role":"assistant","content":[],"api":"openai-completions","provider":"openrouter","model":"deepseek/deepseek-v4-flash","usage":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"totalTokens":0,"cost":{"input":0,"output":0,"cacheRead":0,"cacheWrite":0,"total":0}},"stopReason":"error","errorMessage":"This operation was aborted","timestamp":1767225606465,"thinkingLevel":"high"}}],"leafId":"e3ab1495"}}}
152{"type":"expect_outbound","label":"process_start@p2","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}150{"type":"expect_outbound","label":"process_start@p2","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
153{"type":"expect_outbound","label":"switch_session@p2","frame":{"type":"switch_session","sessionPath":"/pi-sessions/session-1.jsonl","id":"t3-0"}}151{"type":"expect_outbound","label":"switch_session@p2","frame":{"type":"switch_session","sessionPath":"/pi-sessions/session-1.jsonl","id":"t3-0"}}
154{"type":"expect_outbound","label":"get_commands@p2","frame":{"type":"get_commands","id":"t3-1"}}
155{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000003","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}152{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000003","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
156{"type":"emit_inbound","label":"response:get_commands@p2","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
157{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000004","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}153{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000004","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
158{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000005","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}154{"type":"emit_inbound","label":"extension_ui_request@p2","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000005","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
159{"type":"emit_inbound","label":"response:switch_session@p2","frame":{"id":"t3-0","type":"response","command":"switch_session","success":true,"data":{"cancelled":false}}}155{"type":"emit_inbound","label":"response:switch_session@p2","frame":{"id":"t3-0","type":"response","command":"switch_session","success":true,"data":{"cancelled":false}}}
apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt_mid_tool/pi_transcript.ndjson-2
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"turn_interrupt_mid_tool","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}1{"type":"transcript_start","provider":"pi","protocol":"pi.rpc-jsonl","version":"1.0.0","scenario":"turn_interrupt_mid_tool","metadata":{"generatedBy":"live-pi-recorder","piVersion":"1.0.0","model":"openrouter/deepseek/deepseek-v4-flash","launchArgs":"--provider openrouter --model deepseek/deepseek-v4-flash --no-extensions --no-skills --no-prompt-templates --no-context-files --approve"}}
2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}2{"type":"expect_outbound","label":"process_start","frame":{"type":"process_start","args":["--mode","rpc","--provider","openrouter","--model","deepseek/deepseek-v4-flash","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--approve","--extension","<any>"]}}
3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}3{"type":"expect_outbound","label":"get_state","frame":{"type":"get_state","id":"t3-0"}}
4{"type":"expect_outbound","label":"get_commands","frame":{"type":"get_commands","id":"t3-1"}}
5{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}4{"type":"emit_inbound","label":"extension_ui_request","frame":{"type":"extension_ui_request","id":"00000000-0000-4000-8000-000000000001","method":"notify","message":"t3-code MCP unavailable: T3_MCP_URL or T3_MCP_BEARER_TOKEN is missing.","notifyType":"warning"}}
6{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}5{"type":"emit_inbound","label":"response:get_state","frame":{"id":"t3-0","type":"response","command":"get_state","success":true,"data":{"model":{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}},"thinkingLevel":"high","isStreaming":false,"isCompacting":false,"steeringMode":"one-at-a-time","followUpMode":"one-at-a-time","sessionFile":"/pi-sessions/session-1.jsonl","sessionId":"00000000-0000-4000-8000-000000000002","autoCompactionEnabled":true,"messageCount":0,"pendingMessageCount":0}}}
7{"type":"emit_inbound","label":"response:get_commands","frame":{"id":"t3-1","type":"response","command":"get_commands","success":true,"data":{"commands":[]}}}
8{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}6{"type":"expect_outbound","label":"get_available_models","frame":{"type":"get_available_models","id":"t3-2"}}
9{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}7{"type":"emit_inbound","label":"response:get_available_models","frame":{"id":"t3-2","type":"response","command":"get_available_models","success":true,"data":{"models":[{"type":"chat","id":"deepseek/deepseek-v4-flash","name":"DeepSeek: DeepSeek V4 Flash 0423","api":"openai-completions","baseUrl":"https://openrouter.ai/api/v1","provider":"openrouter","reasoning":true,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null},"input":["text"],"cost":{"input":0.04186,"output":0.08372,"cacheRead":0.008372,"cacheWrite":0},"contextWindow":1048576,"maxTokens":131072,"compat":{"supportsDeveloperRole":false,"thinkingFormat":"openrouter","supportsStrictMode":true,"sendSessionAffinityHeaders":true,"requiresReasoningContentOnAssistantMessages":true}}]}}}
10{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}8{"type":"expect_outbound","label":"get_entries","frame":{"type":"get_entries","id":"t3-3"}}
packages/provider-pi/src/server/adapter.test.ts+2-60
...@@ -94,10 +94,6 @@ interface FakePi {...@@ -94,10 +94,6 @@ interface FakePi {
94 readonly allRequests: () => ReadonlyArray<PiRpcRecord>;94 readonly allRequests: () => ReadonlyArray<PiRpcRecord>;
95 /** Data returned by the next `get_session_stats` acks, consumed in order. */95 /** Data returned by the next `get_session_stats` acks, consumed in order. */
96 readonly queueStats: (data: unknown) => void;96 readonly queueStats: (data: unknown) => void;
97 /** Data returned by the next `get_commands` acks, consumed in order. */
98 readonly queueCommands: (data: unknown) => void;
99 /** Make the next `get_commands` ack fail. */
100 readonly failNextCommands: () => void;
101 /** Close the fake process stdout stream. */97 /** Close the fake process stdout stream. */
102 readonly closeStdout: Effect.Effect<void>;98 readonly closeStdout: Effect.Effect<void>;
103 readonly lastSpawn: () => {99 readonly lastSpawn: () => {
...@@ -137,7 +133,6 @@ const makeFakePi: Effect.Effect<FakePi> = Effect.gen(function* () {...@@ -137,7 +133,6 @@ const makeFakePi: Effect.Effect<FakePi> = Effect.gen(function* () {
137 const messagesQueue: Array<unknown> = [];133 const messagesQueue: Array<unknown> = [];
138 const stateQueue: Array<Record<string, unknown>> = [];134 const stateQueue: Array<Record<string, unknown>> = [];
139 const statsQueue: Array<unknown> = [];135 const statsQueue: Array<unknown> = [];
140 const commandsQueue: Array<{ readonly success: boolean; readonly data?: unknown }> = [];
141 const allRequests: Array<PiRpcRecord> = [];136 const allRequests: Array<PiRpcRecord> = [];
142 let deferState = false;137 let deferState = false;
143 let deferredStateRequest: PiRpcRecord | undefined;138 let deferredStateRequest: PiRpcRecord | undefined;
...@@ -191,8 +186,6 @@ const makeFakePi: Effect.Effect<FakePi> = Effect.gen(function* () {...@@ -191,8 +186,6 @@ const makeFakePi: Effect.Effect<FakePi> = Effect.gen(function* () {
191 return { ...base, data: messagesQueue.shift() ?? { messages: [] } };186 return { ...base, data: messagesQueue.shift() ?? { messages: [] } };
192 case "get_session_stats":187 case "get_session_stats":
193 return { ...base, data: statsQueue.shift() ?? {} };188 return { ...base, data: statsQueue.shift() ?? {} };
194 case "get_commands":
195 return { ...base, ...(commandsQueue.shift() ?? { data: { commands: [] } }) };
196 case "fork":189 case "fork":
197 return { ...base, data: { text: "Hello pi", cancelled: false } };190 return { ...base, data: { text: "Hello pi", cancelled: false } };
198 default:191 default:
...@@ -305,8 +298,6 @@ const makeFakePi: Effect.Effect<FakePi> = Effect.gen(function* () {...@@ -305,8 +298,6 @@ const makeFakePi: Effect.Effect<FakePi> = Effect.gen(function* () {
305 },298 },
306 queueState: (data) => stateQueue.push(data),299 queueState: (data) => stateQueue.push(data),
307 queueStats: (data) => statsQueue.push(data),300 queueStats: (data) => statsQueue.push(data),
308 queueCommands: (data) => commandsQueue.push({ success: true, data }),
309 failNextCommands: () => commandsQueue.push({ success: false }),
310 closeStdout: Queue.end(stdout),301 closeStdout: Queue.end(stdout),
311 lastSpawn: () => lastSpawn,302 lastSpawn: () => lastSpawn,
312 } satisfies FakePi;303 } satisfies FakePi;
...@@ -1697,22 +1688,9 @@ describe("PiAdapterV2", () => {...@@ -1697,22 +1688,9 @@ describe("PiAdapterV2", () => {
1697 }).pipe(Effect.scoped, Effect.provide(layerTest)),1688 }).pipe(Effect.scoped, Effect.provide(layerTest)),
1698 );1689 );
16991690
1700 it.effect("expands a selected $ skill through Pi's native skill command", () =>1691 it.effect("preserves selected skill references for the Pi extension to expand", () =>
1701 Effect.gen(function* () {1692 Effect.gen(function* () {
1702 const fake = yield* makeFakePi;1693 const fake = yield* makeFakePi;
1703 fake.queueCommands({
1704 commands: [
1705 {
1706 name: "skill:repo-review",
1707 description: "Review this repository.",
1708 source: "skill",
1709 sourceInfo: {
1710 path: "/workspace/.agents/skills/repo-review/SKILL.md",
1711 scope: "project",
1712 },
1713 },
1714 ],
1715 });
1716 const { runtime } = yield* openRuntime(fake);1694 const { runtime } = yield* openRuntime(fake);
1717 const providerThread = yield* runtime.ensureThread({1695 const providerThread = yield* runtime.ensureThread({
1718 threadId: THREAD_ID,1696 threadId: THREAD_ID,
...@@ -1728,43 +1706,7 @@ describe("PiAdapterV2", () => {...@@ -1728,43 +1706,7 @@ describe("PiAdapterV2", () => {
1728 "Review this change please $repo-review",1706 "Review this change please $repo-review",
1729 );1707 );
1730 const prompt = yield* fake.takeRequest("prompt");1708 const prompt = yield* fake.takeRequest("prompt");
1731 assert.equal(prompt["message"], "/skill:repo-review Review this change please");1709 assert.equal(prompt["message"], "Review this change please $repo-review");
1732 }).pipe(Effect.scoped, Effect.provide(layerTest)),
1733 );
1734
1735 it.effect("expands every selected $ skill through Pi native skill commands", () =>
1736 Effect.gen(function* () {
1737 const fake = yield* makeFakePi;
1738 fake.queueCommands({
1739 commands: [
1740 {
1741 name: "skill:repo-review",
1742 source: "skill",
1743 sourceInfo: {
1744 path: "/workspace/.agents/skills/repo-review/SKILL.md",
1745 scope: "project",
1746 },
1747 },
1748 {
1749 name: "skill:deploy",
1750 source: "skill",
1751 sourceInfo: {
1752 path: "/workspace/.agents/skills/deploy/SKILL.md",
1753 scope: "project",
1754 },
1755 },
1756 ],
1757 });
1758 const { runtime } = yield* openRuntime(fake);
1759 const providerThread = yield* runtime.ensureThread({
1760 threadId: THREAD_ID,
1761 modelSelection: modelSelection("default"),
1762 runtimePolicy,
1763 });
1764
1765 yield* startTurn(runtime, providerThread, "default", [], "use $repo-review and $deploy");
1766 const prompt = yield* fake.takeRequest("prompt");
1767 assert.equal(prompt["message"], "/skill:repo-review /skill:deploy use and");
1768 }).pipe(Effect.scoped, Effect.provide(layerTest)),1710 }).pipe(Effect.scoped, Effect.provide(layerTest)),
1769 );1711 );
17701712
packages/provider-pi/src/server/adapter.ts+2-37
...@@ -63,12 +63,7 @@ import { ChildProcessSpawner } from "effect/process";...@@ -63,12 +63,7 @@ import { ChildProcessSpawner } from "effect/process";
63import * as ProviderHost from "@t3tools/provider-core/server/ProviderHost";63import * as ProviderHost from "@t3tools/provider-core/server/ProviderHost";
64import { mcpToolPresentation } from "@t3tools/provider-core/server/mcpToolPresentation";64import { mcpToolPresentation } from "@t3tools/provider-core/server/mcpToolPresentation";
65import * as McpProviderSession from "@t3tools/provider-core/server/mcpSession";65import * as McpProviderSession from "@t3tools/provider-core/server/mcpSession";
66import {66import { parsePiCompactCommand, type PiCompactCommand } from "./commands.ts";
67 expandPiSkillReference,
68 parsePiCompactCommand,
69 parsePiDiscoveredCommands,
70 type PiCompactCommand,
71} from "./commands.ts";
72import { mergeProviderInstanceEnvironment } from "@t3tools/provider-core/server/instanceEnvironment";67import { mergeProviderInstanceEnvironment } from "@t3tools/provider-core/server/instanceEnvironment";
73import * as IdAllocator from "@t3tools/provider-core/server/IdAllocator";68import * as IdAllocator from "@t3tools/provider-core/server/IdAllocator";
74import * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter";69import * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter";
...@@ -114,7 +109,6 @@ const STREAM_FLUSH_MS = 50;...@@ -114,7 +109,6 @@ const STREAM_FLUSH_MS = 50;
114const PI_REQUEST_TIMEOUT_MS = 15_000;109const PI_REQUEST_TIMEOUT_MS = 15_000;
115// Session lifecycle hooks reload extensions, MCP servers and language servers.110// Session lifecycle hooks reload extensions, MCP servers and language servers.
116const PI_SESSION_TIMEOUT_MS = 60_000;111const PI_SESSION_TIMEOUT_MS = 60_000;
117const PI_SKILL_DISCOVERY_TIMEOUT_MS = 4_000;
118const PI_UNSOLICITED_ACTIVITY_ERROR =112const PI_UNSOLICITED_ACTIVITY_ERROR =
119 "Pi started agent work outside an active T3 turn. The session was stopped to prevent invisible tool execution.";113 "Pi started agent work outside an active T3 turn. The session was stopped to prevent invisible tool execution.";
120const SETTLE_PROBE_MAX_ATTEMPTS = 3;114const SETTLE_PROBE_MAX_ATTEMPTS = 3;
...@@ -458,15 +452,6 @@ export const makePiAdapterV2 = Effect.fn("makePiAdapterV2")(function* (...@@ -458,15 +452,6 @@ export const makePiAdapterV2 = Effect.fn("makePiAdapterV2")(function* (
458 }),452 }),
459 ),453 ),
460 );454 );
461 const discoverSkillNames = connection
462 .request({ type: "get_commands" }, PI_SKILL_DISCOVERY_TIMEOUT_MS)
463 .pipe(
464 Effect.map(
465 (data) => new Set(parsePiDiscoveredCommands(data).skills.map((skill) => skill.name)),
466 ),
467 );
468 let skillNames: Set<string> | null = null;
469
470 const now = yield* DateTime.now;455 const now = yield* DateTime.now;
471 let sessionEntity: OrchestrationV2ProviderSession = {456 let sessionEntity: OrchestrationV2ProviderSession = {
472 id: input.providerSessionId,457 id: input.providerSessionId,
...@@ -2117,16 +2102,6 @@ export const makePiAdapterV2 = Effect.fn("makePiAdapterV2")(function* (...@@ -2117,16 +2102,6 @@ export const makePiAdapterV2 = Effect.fn("makePiAdapterV2")(function* (
2117 Effect.forkIn(scope),2102 Effect.forkIn(scope),
2118 );2103 );
21192104
2120 // Discovery can invoke extension code and therefore raise a blocking
2121 // UI request. Start it only after the event pump exists, and never hold
2122 // session opening on it; startup requests are persisted at session
2123 // scope and can be answered before a turn begins.
2124 yield* discoverSkillNames.pipe(
2125 Effect.tap((discovered) => Effect.sync(() => (skillNames = discovered))),
2126 Effect.ignore,
2127 Effect.forkIn(scope),
2128 );
2129
2130 // ── session runtime ───────────────────────────────────2105 // ── session runtime ───────────────────────────────────
21312106
2132 const registerThread = Effect.fnUntraced(function* (2107 const registerThread = Effect.fnUntraced(function* (
...@@ -2329,15 +2304,6 @@ export const makePiAdapterV2 = Effect.fn("makePiAdapterV2")(function* (...@@ -2329,15 +2304,6 @@ export const makePiAdapterV2 = Effect.fn("makePiAdapterV2")(function* (
2329 text: string,2304 text: string,
2330 attachments: ReadonlyArray<ChatAttachment>,2305 attachments: ReadonlyArray<ChatAttachment>,
2331 ) {2306 ) {
2332 // Provider discovery and the live session are separate Pi processes.
2333 // Retry a failed session-local lookup once at first use so a transient
2334 // startup failure cannot leave a visible $ skill inert for this session.
2335 if (skillNames === null && text.includes("$")) {
2336 skillNames = yield* discoverSkillNames.pipe(
2337 Effect.orElseSucceed(() => new Set<string>()),
2338 );
2339 }
2340 const expandedText = skillNames === null ? text : expandPiSkillReference(text, skillNames);
2341 const images: Array<{ type: "image"; data: string; mimeType: string }> = [];2307 const images: Array<{ type: "image"; data: string; mimeType: string }> = [];
2342 const extraLines: Array<string> = [];2308 const extraLines: Array<string> = [];
2343 for (const attachment of attachments) {2309 for (const attachment of attachments) {
...@@ -2354,8 +2320,7 @@ export const makePiAdapterV2 = Effect.fn("makePiAdapterV2")(function* (...@@ -2354,8 +2320,7 @@ export const makePiAdapterV2 = Effect.fn("makePiAdapterV2")(function* (
2354 extraLines.push(`[Attachment saved at ${path}]`);2320 extraLines.push(`[Attachment saved at ${path}]`);
2355 }2321 }
2356 }2322 }
2357 const message =2323 const message = extraLines.length === 0 ? text : `${text}\n\n${extraLines.join("\n")}`;
2358 extraLines.length === 0 ? expandedText : `${expandedText}\n\n${extraLines.join("\n")}`;
2359 return { message, images };2324 return { message, images };
2360 });2325 });
23612326
packages/provider-pi/src/server/commands.test.ts-17
...@@ -1,7 +1,6 @@...@@ -1,7 +1,6 @@
1import { expect, it } from "@effect/vitest";1import { expect, it } from "@effect/vitest";
22
3import {3import {
4 expandPiSkillReference,
5 parsePiCompactCommand,4 parsePiCompactCommand,
6 parsePiDiscoveredCommands,5 parsePiDiscoveredCommands,
7 PI_COMPACT_SLASH_COMMAND,6 PI_COMPACT_SLASH_COMMAND,
...@@ -109,19 +108,3 @@ it("prepends the builtin compact command without duplicating a discovered one",...@@ -109,19 +108,3 @@ it("prepends the builtin compact command without duplicating a discovered one",
109 ]),108 ]),
110 ).toEqual([PI_COMPACT_SLASH_COMMAND, { name: "hello" }]);109 ).toEqual([PI_COMPACT_SLASH_COMMAND, { name: "hello" }]);
111});110});
112
113it("leaves unrelated dollar-prefixed text unchanged", () => {
114 expect(expandPiSkillReference("Explain $HOME", new Set(["global-review"]))).toBe("Explain $HOME");
115});
116
117it("hoists every known $ skill and keeps the rest of the prompt", () => {
118 expect(expandPiSkillReference("use $alpha then $beta please", new Set(["alpha", "beta"]))).toBe(
119 "/skill:alpha /skill:beta use then please",
120 );
121});
122
123it("preserves code indentation and line breaks when expanding a skill", () => {
124 expect(expandPiSkillReference("$review\n```ts\n const x = 1;\n```", new Set(["review"]))).toBe(
125 "/skill:review ```ts\n const x = 1;\n```",
126 );
127});
packages/provider-pi/src/server/commands.ts-35
...@@ -91,41 +91,6 @@ export function parsePiDiscoveredCommands(data: unknown): PiDiscoveredCommands {...@@ -91,41 +91,6 @@ export function parsePiDiscoveredCommands(data: unknown): PiDiscoveredCommands {
91 return { slashCommands, skills };91 return { slashCommands, skills };
92}92}
9393
94/**
95 * Pi expands skills only through leading `/skill:name` commands. T3 stores
96 * skill chips as `$name`, so hoist every known `$skill` to that native
97 * command position while preserving the rest of the user's prompt.
98 */
99export function expandPiSkillReference(text: string, skillNames: ReadonlySet<string>): string {
100 const references = /(^|\s)\$([^\s]+)(?=\s|$)/g;
101 const found: Array<{ name: string; start: number; end: number }> = [];
102 for (const match of text.matchAll(references)) {
103 const name = match[2];
104 if (name === undefined || !skillNames.has(name) || match.index === undefined) continue;
105 const tokenStart = match.index + (match[1]?.length ?? 0);
106 found.push({ name, start: tokenStart, end: tokenStart + name.length + 1 });
107 }
108 if (found.length === 0) return text;
109
110 const orderedNames: string[] = [];
111 const seen = new Set<string>();
112 for (const token of found) {
113 if (seen.has(token.name)) continue;
114 seen.add(token.name);
115 orderedNames.push(token.name);
116 }
117
118 let body = text;
119 for (let index = found.length - 1; index >= 0; index -= 1) {
120 const token = found[index];
121 if (token === undefined) continue;
122 body = `${body.slice(0, token.start)}${body.slice(token.end)}`;
123 }
124 body = body.trim();
125 const prefix = orderedNames.map((name) => `/skill:${name}`).join(" ");
126 return body.length === 0 ? prefix : `${prefix} ${body}`;
127}
128
129function recordField(input: unknown, key: string): unknown {94function recordField(input: unknown, key: string): unknown {
130 return Predicate.isObject(input) ? input[key] : undefined;95 return Predicate.isObject(input) ? input[key] : undefined;
131}96}
packages/provider-pi/src/server/mcpExtensionSource.test.ts+146-3
...@@ -1,3 +1,7 @@...@@ -1,3 +1,7 @@
1// @effect-diagnostics nodeBuiltinImport:off -- Pi extensions run outside Effect; these tests exercise their native filesystem boundary.
2import * as NodeFSP from "node:fs/promises";
3import * as NodePath from "node:path";
4import * as NodeOS from "node:os";
1import * as NodeModule from "node:module";5import * as NodeModule from "node:module";
2import * as NodeVM from "node:vm";6import * as NodeVM from "node:vm";
3import { assert, describe, it } from "@effect/vitest";7import { assert, describe, it } from "@effect/vitest";
...@@ -9,6 +13,40 @@ type RequestHook = (...@@ -9,6 +13,40 @@ type RequestHook = (
9 ctx: { model: { provider: string } },13 ctx: { model: { provider: string } },
10) => Record<string, unknown> | undefined;14) => Record<string, unknown> | undefined;
1115
16interface SkillCommand {
17 readonly name: string;
18 readonly source: string;
19 readonly sourceInfo: { readonly path: string };
20}
21
22type InputHook = (
23 event: { text: string; images?: ReadonlyArray<unknown> },
24 ctx: { ui: { notify: (message: string, level: string) => void } },
25) => Promise<{ action: string; text: string; images?: ReadonlyArray<unknown> } | undefined>;
26
27async function loadHooks(commands: ReadonlyArray<SkillCommand> = []) {
28 const handlers = new Map<string, unknown>();
29 // Execute the shipped extension with MCP disabled; this path needs no Typebox.
30 const source = NodeModule.stripTypeScriptTypes(
31 PI_T3_MCP_EXTENSION_SOURCE.replace(/^import .*;$/gm, "").replace(
32 "export default async function",
33 "async function",
34 ),
35 );
36 await NodeVM.runInNewContext(`${source}\nt3McpExtension(pi)`, {
37 process: { env: {} },
38 NodeFSP,
39 NodePath,
40 // Frontmatter parsing belongs to Pi. These fixtures contain only skill bodies.
41 stripFrontmatter: (content: string) => content,
42 pi: {
43 on: (name: string, handler: unknown) => handlers.set(name, handler),
44 getCommands: () => commands,
45 },
46 });
47 return handlers;
48}
49
12interface RegisteredTool {50interface RegisteredTool {
13 readonly name: string;51 readonly name: string;
14 readonly description: string;52 readonly description: string;
...@@ -55,7 +93,7 @@ async function loadMcpBridge(...@@ -55,7 +93,7 @@ async function loadMcpBridge(
55 { name: "preview_snapshot", description: "Inspect the collaborative browser." },93 { name: "preview_snapshot", description: "Inspect the collaborative browser." },
56 ].map((tool) => ({ ...tool, inputSchema: { type: "object", properties: {} } }));94 ].map((tool) => ({ ...tool, inputSchema: { type: "object", properties: {} } }));
57 const source = NodeModule.stripTypeScriptTypes(95 const source = NodeModule.stripTypeScriptTypes(
58 PI_T3_MCP_EXTENSION_SOURCE.replace('import { Type } from "typebox";', "").replace(96 PI_T3_MCP_EXTENSION_SOURCE.replace(/^import .*;$/gm, "").replace(
59 "export default async function",97 "export default async function",
60 "async function",98 "async function",
61 ),99 ),
...@@ -271,7 +309,7 @@ describe("Pi tool discovery permissions", () => {...@@ -271,7 +309,7 @@ describe("Pi tool discovery permissions", () => {
271 let toolCall: ToolCallHook | undefined;309 let toolCall: ToolCallHook | undefined;
272 let searchPath = "builtin:tool-search";310 let searchPath = "builtin:tool-search";
273 const source = NodeModule.stripTypeScriptTypes(311 const source = NodeModule.stripTypeScriptTypes(
274 PI_T3_MCP_EXTENSION_SOURCE.replace('import { Type } from "typebox";', "").replace(312 PI_T3_MCP_EXTENSION_SOURCE.replace(/^import .*;$/gm, "").replace(
275 "export default async function",313 "export default async function",
276 "async function",314 "async function",
277 ),315 ),
...@@ -315,7 +353,7 @@ async function loadRequestHook(): Promise<RequestHook> {...@@ -315,7 +353,7 @@ async function loadRequestHook(): Promise<RequestHook> {
315 const handlers = new Map<string, RequestHook>();353 const handlers = new Map<string, RequestHook>();
316 // Execute the shipped extension with MCP disabled; this path needs no Typebox.354 // Execute the shipped extension with MCP disabled; this path needs no Typebox.
317 const source = NodeModule.stripTypeScriptTypes(355 const source = NodeModule.stripTypeScriptTypes(
318 PI_T3_MCP_EXTENSION_SOURCE.replace('import { Type } from "typebox";', "").replace(356 PI_T3_MCP_EXTENSION_SOURCE.replace(/^import .*;$/gm, "").replace(
319 "export default async function",357 "export default async function",
320 "async function",358 "async function",
321 ),359 ),
...@@ -359,3 +397,108 @@ describe("Pi upstream output-budget workaround", () => {...@@ -359,3 +397,108 @@ describe("Pi upstream output-budget workaround", () => {
359 );397 );
360 });398 });
361});399});
400
401async function loadInputHook(commands: ReadonlyArray<SkillCommand>) {
402 const handlers = await loadHooks(commands);
403 const hook = handlers.get("input");
404 assert.isDefined(hook);
405 return hook as InputHook;
406}
407
408describe("Pi skill references", () => {
409 it("loads every selected skill once while preserving inline prose, whitespace, and images", async () => {
410 const directory = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "pi-skill-mentions-"));
411 try {
412 const alpha = NodePath.join(directory, "alpha.md");
413 const beta = NodePath.join(directory, "beta.md");
414 await NodeFSP.writeFile(alpha, "ALPHA_INSTRUCTIONS");
415 await NodeFSP.writeFile(beta, "BETA_INSTRUCTIONS");
416 const hook = await loadInputHook([
417 { name: "skill:alpha", source: "skill", sourceInfo: { path: alpha } },
418 { name: "skill:beta", source: "skill", sourceInfo: { path: beta } },
419 ]);
420 const text =
421 "Please use the $alpha philosophy, then $beta and $alpha\n```ts\n const x = 1;\n```";
422 const images = [{ type: "image", data: "fixture" }];
423 const result = await hook({ text, images }, { ui: { notify: assert.fail } });
424 assert.equal(result?.action, "transform");
425 assert.isTrue(result?.text.startsWith(text + "\n\n"));
426 assert.equal(result?.text.split("ALPHA_INSTRUCTIONS").length, 2);
427 assert.equal(result?.text.split("BETA_INSTRUCTIONS").length, 2);
428 assert.include(result?.text ?? "", `References are relative to ${directory}.`);
429 assert.strictEqual(result?.images, images);
430 } finally {
431 await NodeFSP.rm(directory, { recursive: true });
432 }
433 });
434
435 it("leaves unknown references and native skill commands for Pi", async () => {
436 const hook = await loadInputHook([
437 { name: "skill:alpha", source: "skill", sourceInfo: { path: "/unused" } },
438 ]);
439 // Punctuation-adjacent references are plain text in the composer, not selected chips.
440 for (const text of [
441 "Explain $HOME",
442 "/skill:alpha use $alpha",
443 "Hello",
444 "$missing",
445 "Use $alpha, then continue",
446 "Use ($alpha)",
447 ]) {
448 assert.isUndefined(await hook({ text }, { ui: { notify: assert.fail } }));
449 }
450 });
451
452 it("loads additional chips without duplicating a leading native skill", async () => {
453 const directory = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "pi-skill-mentions-"));
454 try {
455 const path = NodePath.join(directory, "beta.md");
456 await NodeFSP.writeFile(path, "BETA_INSTRUCTIONS");
457 const hook = await loadInputHook([
458 { name: "skill:alpha", source: "skill", sourceInfo: { path: "/unused" } },
459 { name: "skill:beta", source: "skill", sourceInfo: { path } },
460 ]);
461 const text = "/skill:alpha use $alpha and $beta";
462 const result = await hook({ text }, { ui: { notify: assert.fail } });
463 assert.isTrue(result?.text.startsWith(text + "\n\n"));
464 assert.notInclude(result?.text ?? "", '<skill name="alpha"');
465 assert.include(result?.text ?? "", "BETA_INSTRUCTIONS");
466 } finally {
467 await NodeFSP.rm(directory, { recursive: true });
468 }
469 });
470
471 it("reports an unreadable skill without deleting its reference or other selected instructions", async () => {
472 const directory = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "pi-skill-mentions-"));
473 try {
474 const path = NodePath.join(directory, "readable.md");
475 await NodeFSP.writeFile(path, "READABLE_INSTRUCTIONS");
476 const hook = await loadInputHook([
477 {
478 name: "skill:missing",
479 source: "skill",
480 sourceInfo: { path: NodePath.join(directory, "missing.md") },
481 },
482 { name: "skill:readable", source: "skill", sourceInfo: { path } },
483 ]);
484 const notices: string[] = [];
485 const text = "Use $missing and $readable";
486 const result = await hook(
487 { text },
488 {
489 ui: {
490 notify: (message) => {
491 notices.push(message);
492 },
493 },
494 },
495 );
496 assert.isTrue(result?.text.startsWith(text + "\n\n"));
497 assert.include(result?.text ?? "", "READABLE_INSTRUCTIONS");
498 assert.equal(notices.length, 1);
499 assert.include(notices[0] ?? "", "Could not load skill missing");
500 } finally {
501 await NodeFSP.rm(directory, { recursive: true });
502 }
503 });
504});
packages/provider-pi/src/server/mcpExtensionSource.ts+35-1
...@@ -23,7 +23,9 @@ export const T3_PI_RUNTIME_MODE_ENV = "T3_PI_RUNTIME_MODE";...@@ -23,7 +23,9 @@ export const T3_PI_RUNTIME_MODE_ENV = "T3_PI_RUNTIME_MODE";
23export const PI_FILE_CHANGE_TOOLS = ["edit", "write"] as const;23export const PI_FILE_CHANGE_TOOLS = ["edit", "write"] as const;
2424
25export const PI_T3_MCP_EXTENSION_SOURCE = `\25export const PI_T3_MCP_EXTENSION_SOURCE = `\
26import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";26import { stripFrontmatter, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
27import * as NodeFSP from "node:fs/promises";
28import * as NodePath from "node:path";
27import { Type } from "typebox";29import { Type } from "typebox";
2830
29const URL_ENV = ${JSON.stringify(T3_MCP_URL_ENV)};31const URL_ENV = ${JSON.stringify(T3_MCP_URL_ENV)};
...@@ -210,6 +212,38 @@ function createMcpClient(endpoint: string, token: string) {...@@ -210,6 +212,38 @@ function createMcpClient(endpoint: string, token: string) {
210}212}
211213
212export default async function t3McpExtension(pi: ExtensionAPI) {214export default async function t3McpExtension(pi: ExtensionAPI) {
215 // Keep skill chips in the request. Pi expands only one leading /skill:
216 // command, so use its own frontmatter loader for every selected chip here.
217 pi.on("input", async (event, ctx) => {
218 if (!event.text.includes("$")) return;
219 const commands = pi.getCommands().filter((command) => command.source === "skill");
220 const nativeSkill = /^\\/skill:([^ ]+)(?: |$)/.exec(event.text)?.[1];
221 const seen = new Set<string>(nativeSkill === undefined ? [] : [nativeSkill]);
222 const blocks: string[] = [];
223 for (const match of event.text.matchAll(/(^|\\s)\\$([^\\s]+)(?=\\s|$)/g)) {
224 const name = match[2];
225 if (name === undefined || seen.has(name)) continue;
226 const command = commands.find((candidate) => candidate.name === "skill:" + name);
227 if (command === undefined) continue;
228 seen.add(name);
229 const path = command.sourceInfo.path;
230 try {
231 const body = stripFrontmatter(await NodeFSP.readFile(path, "utf8")).trim();
232 blocks.push(
233 \`<skill name="\${name}" location="\${path}">\\nReferences are relative to \${NodePath.dirname(path)}.\\n\\n\${body}\\n</skill>\`,
234 );
235 } catch {
236 ctx.ui.notify(\`Could not load skill \${name} from \${path}.\`, "error");
237 }
238 }
239 if (blocks.length === 0) return;
240 return {
241 action: "transform",
242 text: event.text + "\\n\\n" + blocks.join("\\n\\n"),
243 images: event.images,
244 };
245 });
246
213 // Workaround for an upstream Pi context-budgeting bug: pi-ai reuses the247 // Workaround for an upstream Pi context-budgeting bug: pi-ai reuses the
214 // previous response's usage even when a fork's instructions/tools differ,248 // previous response's usage even when a fork's instructions/tools differ,
215 // then reserves almost all remaining context for output. OpenRouter can249 // then reserves almost all remaining context for output. OpenRouter can