akseljoonas HF Staff Claude Opus 4.6 commited on
Commit
6c9f1f6
·
1 Parent(s): b22c5f3

fix: wire sandbox bash streaming to frontend panel

Browse files

- Accept 'bash' in onToolLog filter (was only 'hf_jobs'|'sandbox')
- Initialize panel on tool_call for bash with command in script tab
- Handle null panelData in setPanelOutput (create panel instead of dropping)
- Auto-open right panel and switch to output view for streaming logs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

frontend/src/hooks/useAgentChat.ts CHANGED
@@ -98,19 +98,28 @@ export function useAgentChat({ sessionId, isActive, onReady, onError, onSessionD
98
  },
99
  onToolLog: (tool: string, log: string) => {
100
  if (!isActiveRef.current) return;
101
- if (tool === 'hf_jobs' || tool === 'sandbox') {
102
- const state = useAgentStore.getState();
103
- const existingOutput = state.panelData?.output?.content || '';
104
- const header = tool === 'sandbox' ? '--- Sandbox creation ---' : '--- Job execution started ---';
105
- const newContent = existingOutput
106
- ? existingOutput + '\n' + log
107
- : header + '\n' + log;
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  setPanelOutput({ content: newContent, language: 'text' });
 
110
 
111
- if (!useLayoutStore.getState().isRightPanelOpen) {
112
- setRightPanelOpen(true);
113
- }
114
  }
115
  },
116
  onConnectionChange: (connected: boolean) => {
@@ -169,6 +178,12 @@ export function useAgentChat({ sessionId, isActive, onReady, onError, onSessionD
169
  });
170
  setRightPanelOpen(true);
171
  setLeftSidebarOpen(false);
 
 
 
 
 
 
172
  }
173
  },
174
  onToolOutputPanel: (toolName: string, _toolCallId: string, output: string, success: boolean) => {
@@ -176,6 +191,9 @@ export function useAgentChat({ sessionId, isActive, onReady, onError, onSessionD
176
  if (toolName === 'hf_jobs' && output) {
177
  setPanelOutput({ content: output, language: 'markdown' });
178
  if (!success) useAgentStore.getState().setPanelView('output');
 
 
 
179
  }
180
  },
181
  onStreaming: () => {
 
98
  },
99
  onToolLog: (tool: string, log: string) => {
100
  if (!isActiveRef.current) return;
101
+ const STREAMABLE_TOOLS = new Set(['hf_jobs', 'sandbox', 'bash']);
102
+ if (!STREAMABLE_TOOLS.has(tool)) return;
 
 
 
 
 
103
 
104
+ const state = useAgentStore.getState();
105
+ const existingOutput = state.panelData?.output?.content || '';
106
+ const newContent = existingOutput
107
+ ? existingOutput + '\n' + log
108
+ : log;
109
+
110
+ if (!state.panelData) {
111
+ // Initialize panel when it doesn't exist (bash bypasses approval, so no panel yet)
112
+ const title = tool === 'hf_jobs' ? 'Job Output' : 'Sandbox';
113
+ setPanel(
114
+ { title, output: { content: newContent, language: 'text' } },
115
+ 'output',
116
+ );
117
+ } else {
118
  setPanelOutput({ content: newContent, language: 'text' });
119
+ }
120
 
121
+ if (!useLayoutStore.getState().isRightPanelOpen) {
122
+ setRightPanelOpen(true);
 
123
  }
124
  },
125
  onConnectionChange: (connected: boolean) => {
 
178
  });
179
  setRightPanelOpen(true);
180
  setLeftSidebarOpen(false);
181
+ } else if (toolName === 'bash' && args.command) {
182
+ // Initialize panel for sandbox bash — command in script tab, output tab active for streaming
183
+ setPanel(
184
+ { title: 'Sandbox', script: { content: String(args.command), language: 'bash' } },
185
+ 'output',
186
+ );
187
  }
188
  },
189
  onToolOutputPanel: (toolName: string, _toolCallId: string, output: string, success: boolean) => {
 
191
  if (toolName === 'hf_jobs' && output) {
192
  setPanelOutput({ content: output, language: 'markdown' });
193
  if (!success) useAgentStore.getState().setPanelView('output');
194
+ } else if (toolName === 'bash') {
195
+ // Streaming already populated the output — ensure output view on error
196
+ if (!success) useAgentStore.getState().setPanelView('output');
197
  }
198
  },
199
  onStreaming: () => {
frontend/src/store/agentStore.ts CHANGED
@@ -135,7 +135,10 @@ export const useAgentStore = create<AgentStore>()((set, get) => ({
135
  setPanelView: (view) => set({ panelView: view }),
136
 
137
  setPanelOutput: (output) => set((state) => ({
138
- panelData: state.panelData ? { ...state.panelData, output } : null,
 
 
 
139
  })),
140
 
141
  updatePanelScript: (content) => set((state) => ({
 
135
  setPanelView: (view) => set({ panelView: view }),
136
 
137
  setPanelOutput: (output) => set((state) => ({
138
+ panelData: state.panelData
139
+ ? { ...state.panelData, output }
140
+ : { title: 'Output', output },
141
+ panelView: 'output',
142
  })),
143
 
144
  updatePanelScript: (content) => set((state) => ({