@@ -5,6 +5,7 @@ import EventTimeline from "./EventTimeline";
55import { Card } from "./ui/card" ;
66import {
77 fetchAgentStatus ,
8+ fetchArtifact ,
89 fetchChainSpec ,
910 fetchEvents ,
1011 fetchReports ,
@@ -78,6 +79,8 @@ export default function RunDetail({
7879 const [ toolCalls , setToolCalls ] = useState < ToolCallRecord [ ] > ( [ ] ) ;
7980 const [ toolCallsError , setToolCallsError ] = useState ( "" ) ;
8081 const [ toolCallsLoading , setToolCallsLoading ] = useState ( false ) ;
82+ const [ planningContracts , setPlanningContracts ] = useState < Array < Record < string , unknown > > > ( [ ] ) ;
83+ const [ planningContractsError , setPlanningContractsError ] = useState ( "" ) ;
8184 const [ chainSpecError , setChainSpecError ] = useState ( "" ) ;
8285 const [ chainSpecLoading , setChainSpecLoading ] = useState ( false ) ;
8386 const [ liveEnabled , setLiveEnabled ] = useState ( true ) ;
@@ -130,6 +133,12 @@ export default function RunDetail({
130133 const schemaVersion = toStringOr ( run ?. manifest ?. versions ?. contracts_schema , "v1" ) ;
131134 const evidenceHashes = toObject ( run ?. manifest ?. evidence_hashes ) ;
132135 const manifestArtifacts = toArray ( run ?. manifest ?. artifacts as unknown [ ] | undefined ) ;
136+ const hasPlanningContractsArtifact = manifestArtifacts . some ( ( item ) => {
137+ const record = toObject ( item ) ;
138+ const name = toStringOr ( record . name , "" ) ;
139+ const path = toStringOr ( record . path , "" ) ;
140+ return name === "planning_worker_prompt_contracts" || path === "artifacts/planning_worker_prompt_contracts.json" ;
141+ } ) ;
133142 const observability = toObject ( run ?. manifest ?. observability ) ;
134143 const summaryGroups = [ "reports/" , "events.jsonl" , "contract.json" , "other" ] ;
135144 const summary = summaryGroups . map ( ( group ) => {
@@ -232,6 +241,41 @@ export default function RunDetail({
232241 } ;
233242 } , [ run ?. run_id ] ) ;
234243
244+ useEffect ( ( ) => {
245+ let alive = true ;
246+ async function loadPlanningContracts ( ) {
247+ if ( ! run ?. run_id || ! hasPlanningContractsArtifact ) {
248+ if ( alive ) {
249+ setPlanningContracts ( [ ] ) ;
250+ setPlanningContractsError ( "" ) ;
251+ }
252+ return ;
253+ }
254+ try {
255+ const artifact = await fetchArtifact ( run . run_id , "planning_worker_prompt_contracts.json" ) ;
256+ const rows = Array . isArray ( artifact ?. data ) ? artifact . data : [ ] ;
257+ if ( alive ) {
258+ setPlanningContracts (
259+ rows
260+ . map ( ( item ) => ( item && typeof item === "object" && ! Array . isArray ( item ) ? ( item as Record < string , unknown > ) : null ) )
261+ . filter ( ( item ) : item is Record < string , unknown > => item !== null ) ,
262+ ) ;
263+ setPlanningContractsError ( "" ) ;
264+ }
265+ } catch ( err : unknown ) {
266+ if ( alive ) {
267+ setPlanningContracts ( [ ] ) ;
268+ console . error ( `[run-detail] load planning contracts failed: ${ uiErrorDetail ( err ) } ` ) ;
269+ setPlanningContractsError ( sanitizeUiError ( err , "Planning governance unavailable" ) ) ;
270+ }
271+ }
272+ }
273+ void loadPlanningContracts ( ) ;
274+ return ( ) => {
275+ alive = false ;
276+ } ;
277+ } , [ hasPlanningContractsArtifact , run ?. run_id ] ) ;
278+
235279 useEffect ( ( ) => {
236280 let alive = true ;
237281 async function loadChainSpec ( ) {
@@ -445,6 +489,8 @@ export default function RunDetail({
445489 pendingApprovals = { pendingApprovals }
446490 evidenceHashes = { evidenceHashes }
447491 manifestArtifacts = { manifestArtifacts }
492+ planningContracts = { planningContracts }
493+ planningContractsError = { planningContractsError }
448494 onOpenLogs = { ( ) => handleFailedTerminalAction ( "logs" ) }
449495 onOpenReports = { ( ) => handleFailedTerminalAction ( "reports" ) }
450496 failedTerminalActionFeedback = { failedTerminalActionFeedback }
0 commit comments