@@ -63,6 +63,24 @@ function createDeferred<T>() {
6363 return { promise, resolve, reject } ;
6464}
6565
66+ function createAgentControlServerError (
67+ status : number ,
68+ payload : Record < string , unknown > ,
69+ statusText = "Server Error" ,
70+ ) {
71+ const body = JSON . stringify ( payload ) ;
72+ return {
73+ name : "AgentControlSDKDefaultError" ,
74+ message : "API error occurred" ,
75+ response$ : new Response ( body , {
76+ status,
77+ statusText,
78+ headers : { "content-type" : "application/json" } ,
79+ } ) ,
80+ body$ : body ,
81+ } ;
82+ }
83+
6684function createMockApi ( pluginConfig : Record < string , unknown > ) : MockApi {
6785 const handlers = new Map < string , ( ...args : any [ ] ) => unknown > ( ) ;
6886 const info = vi . fn ( ) ;
@@ -668,7 +686,9 @@ describe("agent-control plugin logging and blocking", () => {
668686 } ,
669687 ] ,
670688 } ) ;
671- clientMocks . ingestEvents . mockRejectedValueOnce ( new Error ( "observability offline" ) ) ;
689+ clientMocks . ingestEvents . mockRejectedValueOnce (
690+ createAgentControlServerError ( 503 , { error : "observability offline" } , "Service Unavailable" ) ,
691+ ) ;
672692
673693 // When the plugin evaluates the tool call
674694 register ( api . api ) ;
@@ -678,9 +698,11 @@ describe("agent-control plugin logging and blocking", () => {
678698
679699 // Then the tool call is still allowed and the ingest failure is only logged
680700 expect ( result ) . toBeUndefined ( ) ;
681- expect ( api . warn ) . toHaveBeenCalledWith (
682- expect . stringContaining ( "observability_ingest failed" ) ,
683- ) ;
701+ const warning = api . warn . mock . calls
702+ . map ( ( [ message ] ) => String ( message ) )
703+ . find ( ( message ) => message . includes ( "observability_ingest failed" ) ) ;
704+ expect ( warning ) . toContain ( "status=503" ) ;
705+ expect ( warning ) . toContain ( 'response_body={"error":"observability offline"}' ) ;
684706 } ) ;
685707
686708 it ( "does not emit control execution events when observability is explicitly disabled" , async ( ) => {
@@ -718,6 +740,31 @@ describe("agent-control plugin logging and blocking", () => {
718740 expect ( clientMocks . ingestEvents ) . not . toHaveBeenCalled ( ) ;
719741 } ) ;
720742
743+
744+ it ( "logs Agent Control response details when agent sync fails" , async ( ) => {
745+ // Given the Agent Control server rejects agent sync with an HTTP payload
746+ const api = createMockApi ( {
747+ serverUrl : "http://localhost:8000" ,
748+ } ) ;
749+
750+ clientMocks . agentsInit . mockRejectedValueOnce (
751+ createAgentControlServerError ( 409 , { detail : "agent registration conflict" } , "Conflict" ) ,
752+ ) ;
753+
754+ // When the plugin attempts to sync before evaluating a tool call
755+ register ( api . api ) ;
756+ const result = await runBeforeToolCall ( api ) ;
757+
758+ // Then the failure warning includes the HTTP status and response payload
759+ expect ( result ) . toBeUndefined ( ) ;
760+ const warning = api . warn . mock . calls
761+ . map ( ( [ message ] ) => String ( message ) )
762+ . find ( ( message ) => message . includes ( "unable to sync" ) ) ;
763+ expect ( warning ) . toContain ( "status=409" ) ;
764+ expect ( warning ) . toContain ( 'response_body={"detail":"agent registration conflict"}' ) ;
765+ expect ( clientMocks . evaluationEvaluate ) . not . toHaveBeenCalled ( ) ;
766+ } ) ;
767+
721768 it ( "allows the tool call when fail-open sync fails" , async ( ) => {
722769 // Given fail-open mode and a step-resolution failure before evaluation
723770 const api = createMockApi ( {
@@ -737,6 +784,30 @@ describe("agent-control plugin logging and blocking", () => {
737784 expect ( api . warn ) . not . toHaveBeenCalledWith ( expect . stringContaining ( "blocked tool=shell" ) ) ;
738785 } ) ;
739786
787+
788+ it ( "logs Agent Control response details when evaluation fails" , async ( ) => {
789+ // Given the Agent Control server rejects policy evaluation with an HTTP payload
790+ const api = createMockApi ( {
791+ serverUrl : "http://localhost:8000" ,
792+ } ) ;
793+
794+ clientMocks . evaluationEvaluate . mockRejectedValueOnce (
795+ createAgentControlServerError ( 500 , { error : "policy engine unavailable" } , "Internal Server Error" ) ,
796+ ) ;
797+
798+ // When the plugin attempts to evaluate a tool call
799+ register ( api . api ) ;
800+ const result = await runBeforeToolCall ( api ) ;
801+
802+ // Then the failure warning includes the HTTP status and response payload
803+ expect ( result ) . toBeUndefined ( ) ;
804+ const warning = api . warn . mock . calls
805+ . map ( ( [ message ] ) => String ( message ) )
806+ . find ( ( message ) => message . includes ( "evaluation failed for agent=default tool=shell" ) ) ;
807+ expect ( warning ) . toContain ( "status=500" ) ;
808+ expect ( warning ) . toContain ( 'response_body={"error":"policy engine unavailable"}' ) ;
809+ } ) ;
810+
740811 it ( "blocks the tool call when fail-closed evaluation throws" , async ( ) => {
741812 // Given fail-closed mode and an evaluation request that throws
742813 const api = createMockApi ( {
0 commit comments