File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -22,6 +22,7 @@ import {
2222 type CompactionGovernor ,
2323} from "./compaction.js" ;
2424import { onTurnBoundary } from "./reactor-events.js" ;
25+ import { isOperatorOriginated } from "./message-provenance.js" ;
2526import { type } from "arktype" ;
2627import {
2728 applyManageTasks ,
@@ -1019,7 +1020,15 @@ class ChatDirectorImpl extends DefaultDirector {
10191020 this . toolOnlyStreak = 0 ;
10201021 this . toolOnlyNudgeFired = false ;
10211022 this . pendingToolOnlyNudge = false ;
1022- this . clearDenials ?.( ) ;
1023+ // Occupancy mailbox / fleet-dry / bg-shell inbounds are also
1024+ // message.received; only a human prompt may forget cached denies.
1025+ const inboundFlags =
1026+ "flags" in event . message && Array . isArray ( event . message . flags )
1027+ ? event . message . flags . filter (
1028+ ( flag ) : flag is string => typeof flag === "string" ,
1029+ )
1030+ : undefined ;
1031+ if ( isOperatorOriginated ( inboundFlags ) ) this . clearDenials ?.( ) ;
10231032 }
10241033 if ( onTurnBoundary ( event ) ) this . inferenceRecoveries = 0 ;
10251034
Original file line number Diff line number Diff line change @@ -740,7 +740,11 @@ describe("open-task termination guard", () => {
740740 await director . decide (
741741 {
742742 type : "message.received" ,
743- message : { role : "user" , content : "just talk" } ,
743+ message : {
744+ role : "user" ,
745+ content : "just talk" ,
746+ flags : [ "operator-originated" ] ,
747+ } ,
744748 } as unknown as ReactorInboundEvent ,
745749 mockState ,
746750 mockCapabilities ,
@@ -757,6 +761,28 @@ describe("open-task termination guard", () => {
757761 expect ( next . some ( ( a ) => a . type === "infer" ) ) . toBe ( true ) ;
758762 expect ( cleared ) . toBe ( 1 ) ;
759763 } ) ;
764+
765+ test ( "mailbox inbound does not clear cached denies" , async ( ) => {
766+ const director = createChatDirector ( "base" , [ ] , { } ) ;
767+ let cleared = 0 ;
768+ director . setClearDenials ( ( ) => {
769+ cleared ++ ;
770+ } ) ;
771+ await director . decide (
772+ makeToolErrorEvent ( "c" , declined ) ,
773+ mockState ,
774+ mockCapabilities ,
775+ ) ;
776+ await director . decide (
777+ {
778+ type : "message.received" ,
779+ message : { role : "user" , content : "worker report" } ,
780+ } as unknown as ReactorInboundEvent ,
781+ mockState ,
782+ mockCapabilities ,
783+ ) ;
784+ expect ( cleared ) . toBe ( 0 ) ;
785+ } ) ;
760786} ) ;
761787
762788describe ( "chatDirector compaction" , ( ) => {
Original file line number Diff line number Diff line change @@ -32,6 +32,7 @@ import { type } from "arktype";
3232
3333import { createAgentWithLiveToolDispatch } from "../../src/agent/live-tool-dispatch.js" ;
3434import { createChatDirector } from "../../src/agent/director.js" ;
35+ import { OPERATOR_ORIGINATED_FLAG } from "../../src/agent/message-provenance.js" ;
3536import {
3637 readSourceCredentialMaterial ,
3738 registerSourceCredential ,
@@ -304,7 +305,19 @@ export async function runUntilDone(
304305
305306 const collectTask = collect ;
306307 const sendResult = await Promise . all ( [
307- session . agent . send ( message ) . then ( ( result ) => {
308+ session . agent . send ( {
309+ ref : { uid : 1 , mailbox : "INBOX" } ,
310+ headers : {
311+ from : "user@local" ,
312+ to : [ "agent@local" ] ,
313+ date : new Date ( ) . toISOString ( ) ,
314+ messageId : `<${ crypto . randomUUID ( ) } @local>` ,
315+ interchangeType : "conversation.message" ,
316+ } ,
317+ flags : [ OPERATOR_ORIGINATED_FLAG ] ,
318+ content : message ,
319+ signatureStatus : "missing" ,
320+ } ) . then ( ( result ) => {
308321 turnComplete = true ;
309322 return result ;
310323 } ) ,
You can’t perform that action at this time.
0 commit comments