@@ -1311,3 +1311,81 @@ describe('classifyRunFailure — batch A reclassification out of execution_faile
13111311 expect ( result ?. failure_detail ) . toBe ( 'session_resume_expired' ) ;
13121312 } ) ;
13131313} ) ;
1314+
1315+ describe ( 'classifyRunFailure — BYOK OpenCode reclassification out of stream_error' , ( ) => {
1316+ it ( 'classifies missing BYOK OpenCode run config as fixable agent config' , ( ) => {
1317+ const result = classify (
1318+ 'BYOK_PROVIDER_REQUIRED' ,
1319+ 'BYOK OpenCode requires a provider, API key, and model for this run.' ,
1320+ ) ;
1321+ expect ( result ) . toMatchObject ( {
1322+ failure_category : 'process_exit' ,
1323+ failure_detail : 'agent_config_invalid' ,
1324+ failure_stage : 'session_init' ,
1325+ retryable : false ,
1326+ user_action : 'fix_config' ,
1327+ } ) ;
1328+ } ) ;
1329+
1330+ it ( 'classifies BYOK OpenCode 404 provider responses as non-retryable upstream client errors' , ( ) => {
1331+ const result = classify (
1332+ 'AGENT_EXECUTION_FAILED' ,
1333+ 'json-rpc id 4: opencode event stream: opencode session error: Not Found: 404 page not found' ,
1334+ ) ;
1335+ expect ( result ) . toMatchObject ( {
1336+ failure_category : 'upstream_unavailable' ,
1337+ failure_detail : 'upstream_client_error' ,
1338+ failure_stage : 'first_token_wait' ,
1339+ retryable : false ,
1340+ user_action : 'none' ,
1341+ } ) ;
1342+ } ) ;
1343+
1344+ it ( 'classifies BYOK OpenCode provider request-shape rejections as non-retryable upstream client errors' , ( ) => {
1345+ const result = classify (
1346+ 'AGENT_EXECUTION_FAILED' ,
1347+ 'json-rpc id 4: opencode event stream: data did not match any variant of untagged enum InputParam' ,
1348+ ) ;
1349+ expect ( result ) . toMatchObject ( {
1350+ failure_category : 'upstream_unavailable' ,
1351+ failure_detail : 'upstream_client_error' ,
1352+ retryable : false ,
1353+ user_action : 'none' ,
1354+ } ) ;
1355+ } ) ;
1356+
1357+ it ( 'classifies BYOK OpenCode config directory permission errors as fixable agent config' , ( ) => {
1358+ const result = classify (
1359+ 'AGENT_EXECUTION_FAILED' ,
1360+ [
1361+ "EACCES: permission denied, mkdir '/Users/11140200/.config/opencode'" ,
1362+ ' path: "/Users/11140200/.config/opencode",' ,
1363+ ' syscall: "mkdir",' ,
1364+ ' errno: -13,' ,
1365+ ' code: "EACCES"' ,
1366+ ] . join ( '\n' ) ,
1367+ ) ;
1368+ expect ( result ) . toMatchObject ( {
1369+ failure_category : 'process_exit' ,
1370+ failure_detail : 'agent_config_invalid' ,
1371+ failure_stage : 'session_init' ,
1372+ retryable : false ,
1373+ user_action : 'fix_config' ,
1374+ } ) ;
1375+ } ) ;
1376+ } ) ;
1377+
1378+ describe ( 'classifyRunFailure — custom Anthropic endpoint disconnects' , ( ) => {
1379+ it ( 'classifies configured custom Anthropic endpoint drops as stream_disconnected' , ( ) => {
1380+ const result = classify (
1381+ 'AGENT_CONNECTION_DROPPED' ,
1382+ 'Claude Code lost its connection to the configured custom Anthropic endpoint before the response finished.' ,
1383+ ) ;
1384+ expect ( result ) . toMatchObject ( {
1385+ failure_category : 'upstream_unavailable' ,
1386+ failure_detail : 'stream_disconnected' ,
1387+ retryable : true ,
1388+ user_action : 'retry' ,
1389+ } ) ;
1390+ } ) ;
1391+ } ) ;
0 commit comments