Compare commits

...

5 Commits

Author SHA1 Message Date
Chuck Butkus
73dcb75217 Set conversation as stopped 2025-09-12 01:38:01 -04:00
Chuck Butkus
5e6eb60d8d Frontend logging 2025-09-12 00:17:30 -04:00
openhands
ed6e29ca35 Enable JavaScript source maps and make them available in GitHub workflows
- Enable source maps in Vite configuration (frontend/vite.config.ts)
- Add source map artifact upload to existing fe-unit-tests workflow
- Create dedicated frontend-source-maps workflow for production builds
- Source maps will be available as downloadable artifacts from GitHub Actions

Co-authored-by: openhands <openhands@all-hands.dev>
2025-09-11 23:41:11 -04:00
Chuck Butkus
7e73ba717d Frontend logging 2025-09-11 22:52:08 -04:00
Chuck Butkus
783496d604 Add logging 2025-09-10 23:31:43 -04:00
8 changed files with 110 additions and 1 deletions

View File

@@ -42,3 +42,10 @@ jobs:
- name: Run tests and collect coverage
working-directory: ./frontend
run: npm run test:coverage
- name: Upload source maps as artifacts
uses: actions/upload-artifact@v4
with:
name: frontend-source-maps-${{ github.sha }}
path: frontend/build/**/*.map
retention-days: 30
if-no-files-found: warn

View File

@@ -0,0 +1,76 @@
# Workflow that builds frontend and uploads source maps as artifacts
name: Build Frontend Source Maps
# Run on main branch pushes, releases, and manual triggers
on:
push:
branches:
- main
paths:
- "frontend/**"
- ".github/workflows/frontend-source-maps.yml"
release:
types: [published]
workflow_dispatch:
# If triggered by a PR, it will be in the same group. However, each commit on main will be in its own unique group
concurrency:
group: ${{ github.workflow }}-${{ (github.head_ref && github.ref) || github.run_id }}
cancel-in-progress: true
jobs:
build-source-maps:
name: Build Frontend and Upload Source Maps
runs-on: blacksmith-4vcpu-ubuntu-2204
strategy:
matrix:
node-version: [22]
fail-fast: true
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: useblacksmith/setup-node@v5
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
working-directory: ./frontend
run: npm ci
- name: Build frontend with source maps
working-directory: ./frontend
run: npm run build
- name: Upload source maps as artifacts
uses: actions/upload-artifact@v4
with:
name: frontend-source-maps-${{ github.sha }}
path: frontend/build/**/*.map
retention-days: 90
if-no-files-found: error
- name: Upload complete build artifacts (for debugging)
uses: actions/upload-artifact@v4
with:
name: frontend-build-${{ github.sha }}
path: |
frontend/build/**/*
!frontend/build/**/*.map
retention-days: 30
if-no-files-found: error
- name: Create source maps summary
run: |
echo "## Source Maps Generated 🗺️" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Source maps have been generated and uploaded as artifacts." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Statistics:" >> $GITHUB_STEP_SUMMARY
echo "- **Total source map files:** $(find frontend/build -name "*.map" | wc -l)" >> $GITHUB_STEP_SUMMARY
echo "- **Total size:** $(du -sh frontend/build/**/*.map 2>/dev/null | tail -1 | cut -f1 || echo 'N/A')" >> $GITHUB_STEP_SUMMARY
echo "- **Commit SHA:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Download:" >> $GITHUB_STEP_SUMMARY
echo "Source maps are available as workflow artifacts and can be downloaded from the Actions tab." >> $GITHUB_STEP_SUMMARY

View File

@@ -178,8 +178,10 @@ class SaasNestedConversationManager(ConversationManager):
redis = self._get_redis_client()
key = self._get_redis_conversation_key(user_id, sid)
starting = await redis.get(key)
logger.debug(f'maybe_start_agent_loop starting from redis: {starting}')
runtime = await self._get_runtime(sid)
logger.debug(f'maybe_start_agent_loop runtime: {runtime}')
nested_url = None
session_api_key = None
@@ -187,15 +189,20 @@ class SaasNestedConversationManager(ConversationManager):
event_store = EventStore(sid, self.file_store, user_id)
if runtime:
nested_url = self._get_nested_url_for_runtime(runtime['runtime_id'], sid)
logger.debug(f'maybe_start_agent_loop nested_url: {nested_url}')
session_api_key = runtime.get('session_api_key')
logger.debug(f'maybe_start_agent_loop session_api_key: {session_api_key}')
status_str = (runtime.get('status') or 'stopped').upper()
logger.debug(f'maybe_start_agent_loop status_str: {status_str}')
if status_str in ConversationStatus:
status = ConversationStatus[status_str]
if status is ConversationStatus.STOPPED and starting:
logger.debug('maybe_start_agent_loop setting status to starting...')
status = ConversationStatus.STARTING
if status is ConversationStatus.STOPPED:
# Mark the agentloop as starting in redis
logger.debug('maybe_start_agent_loop starting agent...')
await redis.set(key, 1, ex=_REDIS_ENTRY_TIMEOUT_SECONDS)
# Start the agent loop in the background

View File

@@ -373,11 +373,15 @@ class OpenHands {
conversationId: string,
providers?: Provider[],
): Promise<Conversation | null> {
const err = new Error("Call stack:");
console.log("startConversation...");
console.log(err.stack);
const { data } = await openHands.post<Conversation | null>(
`/api/conversations/${conversationId}/start`,
providers ? { providers_set: providers } : {},
);
console.log(data);
return data;
}

View File

@@ -46,6 +46,11 @@ function AppContent() {
useDocumentTitleFromState();
React.useEffect(() => {
console.log(
`isFetched: ${isFetched}, conversation: ${conversation}, isAuthed: ${isAuthed}`,
);
console.log("conversation: ", conversation);
console.log(`conversation status: " ${conversation?.status}`);
if (isFetched && !conversation && isAuthed) {
displayErrorToast(
"This conversation does not exist, or you do not have permission to access it.",

View File

@@ -31,6 +31,9 @@ export default defineConfig(({ mode }) => {
svgr(),
tailwindcss(),
],
build: {
sourcemap: true,
},
optimizeDeps: {
include: [
// Pre-bundle ALL dependencies to prevent runtime optimization and page reloads

View File

@@ -103,12 +103,16 @@ async def connect(connection_id: str, environ: dict) -> None:
):
continue
elif isinstance(event, AgentStateChangedObservation):
logger.debug(
f'oh_event: AgentStateChangedObservation {event.agent_state}'
)
agent_state_changed = event
else:
await sio.emit('oh_event', event_to_dict(event), to=connection_id)
# Send the agent state changed event last if we have one
if agent_state_changed:
logger.debug(f'sending AgentStateChangedObservation {event.agent_state}')
await sio.emit(
'oh_event', event_to_dict(agent_state_changed), to=connection_id
)
@@ -121,6 +125,9 @@ async def connect(connection_id: str, environ: dict) -> None:
user_id, conversation_id, providers_set
)
logger.debug(
f'conversation manager type {conversation_manager.__class__.__name__}'
)
agent_loop_info = await conversation_manager.join_conversation(
conversation_id,
connection_id,

View File

@@ -570,7 +570,7 @@ async def stop_conversation(
status='ok',
conversation_id=conversation_id,
message='Conversation stopped successfully',
conversation_status=conversation_status,
conversation_status=ConversationStatus.STOPPED,
)
except Exception as e:
logger.error(