Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions app-backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
FROM python:3.11-slim

RUN apt-get update -y && apt-get install -y --no-install-recommends --fix-missing \
libsqlite3-0=3.40.1-2+deb12u1 \
libgl1-mesa-glx=22.3.6-1+deb12u1 \
libjemalloc-dev=5.3.0-1 \
libsqlite3-0 \
libjemalloc-dev \
git && \
rm -rf /var/lib/apt/lists/*

Expand Down
23 changes: 15 additions & 8 deletions app-frontend/react/src/components/File_Input/FileInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,23 @@ const FileInput: React.FC<FileInputProps> = ({
const uploadFiles = async () => {
dispatch(setUploadInProgress(true));

const responses = await Promise.all(
filesToUpload.map((file: any) => {
dispatch(uploadFile({ file: file.file }));
}),
);
try {
const responses = await Promise.all(
filesToUpload.map((file: any) => {
return dispatch(uploadFile({ file: file.file }));
}),
);

dispatch(setUploadInProgress(false));
// Wait a brief moment to ensure notifications are displayed
await new Promise(resolve => setTimeout(resolve, 100));

setConfirmUpload(false);
setFilesToUpload([]);
dispatch(setUploadInProgress(false));
setConfirmUpload(false);
setFilesToUpload([]);
} catch (error) {
dispatch(setUploadInProgress(false));
setConfirmUpload(false);
}
};

const showConfirmUpload = () => {
Expand Down
85 changes: 53 additions & 32 deletions studio-backend/app/routers/debuglog_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,15 +218,6 @@ async def get_all_pods_in_namespace(namespace: str):
except Exception as e:
pass

# Analyze pod dependencies
dependencies = []
if services:
try:
dependencies = find_pod_dependencies(pod, pods, services, namespace, core_v1_api)
# print(f"Pod {pod_name} dependencies: {dependencies}")
except Exception as e:
pass

# Analyze pod dependencies
dependencies = []
if services:
Expand Down Expand Up @@ -260,41 +251,71 @@ async def get_all_pods_in_namespace(namespace: str):
total_count = len(pod.status.container_statuses)
ready_status = f"{ready_count}/{total_count}"

# Only check for error conditions if not already terminating or in terminal state
has_error = False
# Determine detailed pod status based on current container states
has_current_error = False
is_running = False
is_pending = False

if not is_terminating and pod.status.phase not in ["Failed", "Succeeded"]:
# Check init container statuses for errors
# Check init container statuses for current errors (not historical)
if pod.status.init_container_statuses:
for status in pod.status.init_container_statuses:
if status.state and status.state.waiting and status.state.waiting.reason in ['ImagePullBackOff', 'ErrImagePull', 'CrashLoopBackOff', 'Error']:
has_error = True
has_current_error = True
break
elif status.state and status.state.terminated and status.state.terminated.reason == 'Error':
has_error = True
has_current_error = True
break

# Check main container statuses for errors
if pod.status.container_statuses:
# Check main container statuses for current state - prioritize running state
if pod.status.container_statuses and not has_current_error:
containers_running = 0
containers_with_current_errors = 0
containers_with_high_restarts = 0
total_containers = len(pod.status.container_statuses)

for status in pod.status.container_statuses:
if status.state and status.state.waiting and status.state.waiting.reason in ['ImagePullBackOff', 'ErrImagePull', 'CrashLoopBackOff', 'Error']:
has_error = True
break
# Priority 1: Check if container is currently running (this overrides restart history)
if status.state and status.state.running:
containers_running += 1
# Even if running, check if it has excessive restarts (indicates instability)
if status.restart_count and status.restart_count > 1:
containers_with_high_restarts += 1
# Priority 2: Check for current error states only if not running
elif status.state and status.state.waiting:
if status.state.waiting.reason in ['ImagePullBackOff', 'ErrImagePull', 'CrashLoopBackOff']:
# These are current errors only if container is not running
containers_with_current_errors += 1
elif status.state.waiting.reason in ['ContainerCreating', 'PodInitializing']:
is_pending = True
# Other waiting reasons are treated as pending, not errors
elif status.state and status.state.terminated and status.state.terminated.reason == 'Error':
has_error = True
break
elif status.restart_count and status.restart_count > 0:
# Check if the pod is restarting frequently (possible error condition)
if status.state and status.state.waiting and status.state.waiting.reason == 'CrashLoopBackOff':
has_error = True
break
has_error = True
break
# Only count as error if container is currently terminated with error
containers_with_current_errors += 1

# Determine overall status based on current state (ignore restart history if currently running)
if containers_running == total_containers:
# All containers running - but check if any have high restart counts
if containers_with_high_restarts > 0:
# Containers are running but unstable (high restarts)
has_current_error = True # This will show as "Error" status
else:
is_running = True
elif containers_with_current_errors > 0:
has_current_error = True
elif containers_running > 0:
# Some containers running, some pending - consider it as pending/starting
is_pending = True

# Set pod status based on conditions
if has_error:
pod_status = "Error"
elif pod.metadata.deletion_timestamp:
# Set pod status based on current conditions (prioritize current state over history)
if pod.metadata.deletion_timestamp:
pod_status = "Terminating"
elif has_current_error:
pod_status = "Error"
elif is_running:
pod_status = "Running"
elif is_pending:
pod_status = "Pending"
elif pod.status.init_container_statuses:
ready_count = sum(1 for status in pod.status.init_container_statuses if status.ready)
total_count = len(pod.status.init_container_statuses)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ export const FlowListTable = ({ data, images, isLoading, filterFunction, updateF
justifyContent='center'
alignItems='center'
>
{row.sandboxStatus === "Getting Ready" || row.sandboxStatus === "Stopping" || row.sandboxStatus === "Deleting existing namespace" ? (
{row.sandboxStatus === "Getting Ready" || row.sandboxStatus === "Stopping" || row.sandboxStatus === "Deleting existing namespace" || row.sandboxStatus === "Sending Request" ? (
<CircularProgress size={20} />
) : null
}
Expand Down Expand Up @@ -549,7 +549,7 @@ export const FlowListTable = ({ data, images, isLoading, filterFunction, updateF
window.open(`/debuglogs/sandbox-${row.id}`, '_blank');
handleRunSandbox(row.id);
}}
disabled={row.sandboxStatus === 'Stopping'}
disabled={row.sandboxStatus === 'Stopping' || row.sandboxStatus === 'Sending Request'}
>
</Button>
</Tooltip>
Expand Down
25 changes: 16 additions & 9 deletions tests/playwright/studio-e2e/002_test_sandbox_chatqna.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ async function setupResponseListener(page, apiResponse) {
const lines = event.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const cleanedData = line.slice(6, -1).trim(); // Remove 'data: ' prefix
apiResponse.value += cleanedData + " ";
const cleanedData = line.slice(6).trim(); // Remove 'data: ' prefix only
if (cleanedData && cleanedData !== '[DONE]') {
apiResponse.value += cleanedData;
}
}
}
}
Expand Down Expand Up @@ -212,31 +214,36 @@ test('002_test_sandbox_chatqna', async ({ browser, baseURL }) => {
// }
// }
console.log ('Chat Attempt 2-------------------');
apiResponse.value = ""; // Clear the response listener buffer
await page2.getByRole('button', { name: 'New Chat' }).click();
await page2.getByRole('textbox', { name: 'Enter your message' }).fill(question);
await page2.getByRole('button').filter({ hasText: /^$/ }).nth(2).click();
await page2.waitForTimeout(30000);

// Wait for the Copy button to appear, indicating response is complete
await page2.getByRole('button', { name: 'Copy' }).waitFor({ state: 'visible'});
responseContainsKeyword = apiResponse && containsAnyKeyword(apiResponse.value, keywords);
console.log ('response:', apiResponse.value);
console.log ("responseContainsKeyword:", responseContainsKeyword);

if (!responseContainsKeyword) {
console.log('First attempt failed. Asking a follow-up question...');
apiResponse.value = ""; // Clear the response listener buffer

// Ask another question
const followUpQuestion = "How is Intel performing in Q3 2024?";
await page2.getByRole('textbox', { name: 'Enter your message' }).fill(followUpQuestion);
await page2.getByRole('button').filter({ hasText: /^$/ }).nth(2).click();
await page2.waitForTimeout(30000);
await page2.locator('.MuiButtonBase-root.MuiButton-root').click();

// Wait for the second Copy button to appear, indicating follow-up response is complete
await page2.getByRole('button', { name: 'Copy' }).nth(1).waitFor({ state: 'visible'});

responseContainsKeyword = apiResponse && containsAnyKeyword(apiResponse.value, keywords);
console.log ('response:', apiResponse.value);
console.log ("responseContainsKeyword:", responseContainsKeyword);
console.log ('Follow-up response:', apiResponse.value);
console.log ("Follow-up responseContainsKeyword:", responseContainsKeyword);

if (!responseContainsKeyword) {
throw new Error('RAG failed after follow-up question');
}
} else {
console.log('First attempt succeeded - RAG is working correctly');
}
await page2.screenshot({ path: 'screenshot_chat_attempt2.png' });

Expand Down
4 changes: 2 additions & 2 deletions tests/playwright/studio-e2e/003_test_sandbox_docsum.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test';
import { waitForStatusText } from '../utils';
import path from 'path';

const sampleWorkflow = path.resolve(__dirname, '../../../sample-workflows/sample_workflow_docsum.json');//this workflow consists of Hugging Face token! cannot deploy as off now.
const sampleWorkflow = path.resolve(__dirname, '../../../sample-workflows/sample_docsum.json');
const uploadtxt1 = path.resolve(__dirname, '../../test-files/Little Red Riding Hood.txt');

const keywords = ["Little Red Riding Hood", "sick grandmother", "wolf", "woodcutter", "hunter", "closet", "food"]; // more keywords needed
Expand Down Expand Up @@ -90,7 +90,7 @@ test('003_test_sandbox_docsum', async ({ browser, baseURL }) => {
//Summarization Generation and Response Validation
await page2.waitForTimeout(60000);
let responseContainsKeyword = apiResponse && containsAnyKeyword(apiResponse.value, keywords);
console.log ('response:', apiResponse.value);
// console.log ('response:', apiResponse.value);
await page2.screenshot({ path: 'screenshot_docsum_attempt1.png' });

if (!responseContainsKeyword) {
Expand Down
4 changes: 2 additions & 2 deletions tests/playwright/studio-e2e/004_test_sandbox_codegen.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test';
import { waitForStatusText } from '../utils';
import path from 'path';

const sampleWorkflow = path.resolve(__dirname, '../../../sample-workflows/sample_workflow_codegen.json');
const sampleWorkflow = path.resolve(__dirname, '../../../sample-workflows/sample_codegen.json');
const question = "write me a python function for fibonacci loop";
const keywords = ["Python", "Fibonacci", "iterative", "if", "<=", "=", "(", ")", "[", "]"]; // more keywords needed

Expand Down Expand Up @@ -81,7 +81,7 @@ test('004_test_sandbox_codegen', async ({ browser, baseURL }) => {
await page2.getByRole('button').filter({ hasText: /^$/ }).nth(2).click(); //end here
await page2.waitForTimeout(60000);
let responseContainsKeyword = apiResponse && containsAnyKeyword(apiResponse.value, keywords);
console.log ('response:', apiResponse.value);
// console.log ('response:', apiResponse.value);
await page2.screenshot({ path: 'screenshot_codegen_attempt1.png' });

if (!responseContainsKeyword) {
Expand Down
Loading