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
7 changes: 1 addition & 6 deletions web/packages/common/src/constants/query.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { JobStatus as IJobStatus, PlatformJobStatus } from '@nemo/sdk/generated/platform/schema';
import { PlatformJobStatus } from '@nemo/sdk/generated/platform/schema';

// Customizer uses Platform SDK status
export const CJobCancellableStatuses: PlatformJobStatus[] = [
Expand All @@ -16,11 +16,6 @@ export const CJobTerminalStatuses: PlatformJobStatus[] = [
PlatformJobStatus.error, // was 'failed'
PlatformJobStatus.cancelled,
];
export const IJobTerminalStatuses: IJobStatus[] = [
IJobStatus.completed,
IJobStatus.failed,
IJobStatus.cancelled,
];
export const PlatformJobTerminalStatuses: PlatformJobStatus[] = [
PlatformJobStatus.completed,
PlatformJobStatus.cancelled,
Expand Down
68 changes: 0 additions & 68 deletions web/packages/common/src/utils/chat.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { FlexibleMessage } from '@nemo/sdk/generated/platform/schema';
import {
ChatCompletion,
ChatCompletionChunk,
Expand Down Expand Up @@ -71,70 +70,3 @@ export const maybeInsertSystemMessage = (
...parsedMessages,
];
};

/**
* Safely extracts string content from a FlexibleMessage.
* Returns empty string if content is undefined, null, or not a string.
*/
const getStringContent = (content: unknown): string => {
if (typeof content === 'string') return content;
if (content === null || content === undefined) return '';
// Handle array content (OpenAI multi-part messages) by joining text parts
if (Array.isArray(content)) {
return content
.filter(
(part): part is { type: 'text'; text: string } =>
typeof part === 'object' && part?.type === 'text' && typeof part?.text === 'string'
)
.map((part) => part.text)
.join(' ');
}
return '';
};

/**
* Converts a FlexibleMessage (intake API) to ChatCompletionMessageParam (OpenAI).
* FlexibleMessage is provider-agnostic; this maps it to the OpenAI standard.
*/
export const toOpenAIMessage = (message: FlexibleMessage): ChatCompletionMessageParam => {
const { role, content, name, tool_calls, tool_call_id } = message;
const stringContent = getStringContent(content);

switch (role) {
case 'user':
return {
role: 'user',
content: stringContent,
...(typeof name === 'string' && { name }),
};
case 'assistant':
return {
role: 'assistant',
content: stringContent || null,
...(Array.isArray(tool_calls) && { tool_calls }),
};
case 'system':
return {
role: 'system',
content: stringContent,
...(typeof name === 'string' && { name }),
};
case 'tool':
return {
role: 'tool',
content: stringContent,
tool_call_id: typeof tool_call_id === 'string' ? tool_call_id : '',
};
case 'function':
// Map legacy 'function' role to 'tool' for OpenAI compatibility
return {
role: 'tool',
content: stringContent,
tool_call_id: typeof tool_call_id === 'string' ? tool_call_id : '',
};
case 'developer':
return { role: 'developer', content: stringContent };
default:
return { role: 'user', content: stringContent };
}
};
12 changes: 4 additions & 8 deletions web/packages/common/src/utils/query.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { JobStatus as IJobStatus, PlatformJobStatus } from '@nemo/sdk/generated/platform/schema';
import { CJobTerminalStatuses } from '@nemo/common/src/constants/query';
import type { PlatformJobStatus } from '@nemo/sdk/generated/platform/schema';

import * as DataView from '../components/DataView/internal';
import { JOB_POLLING_INTERVAL_MS } from '../constants';
import { CJobTerminalStatuses, IJobTerminalStatuses } from '../constants/query';

export const getJobRefetchInterval = (status?: PlatformJobStatus | IJobStatus) => {
if (
!status ||
(!CJobTerminalStatuses.includes(status as PlatformJobStatus) &&
!IJobTerminalStatuses.includes(status as IJobStatus))
) {
export const getJobRefetchInterval = (status?: PlatformJobStatus): number | false => {
if (!status || !CJobTerminalStatuses.includes(status)) {
return JOB_POLLING_INTERVAL_MS;
}
return false;
Expand Down
1 change: 0 additions & 1 deletion web/packages/studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@
"react-router-dom": "catalog:",
"recharts": "catalog:",
"seedrandom": "^3.0.5",
"unique-names-generator": "^4.7.1",
"use-debounce": "catalog:",
"vite": "catalog:",
"vite-plugin-mkcert": "catalog:",
Expand Down
15 changes: 0 additions & 15 deletions web/packages/studio/src/api/intake/constants.ts

This file was deleted.

68 changes: 0 additions & 68 deletions web/packages/studio/src/api/intake/utils.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { MultiselectOption } from '@studio/constants/mutliselect';
import type { MultiselectOption } from '@studio/constants/mutliselect';

export const LOADING_FILES_OPTION: MultiselectOption = {
label: 'Loading files...',
value: 'loading',
isDisabled: true,
};

export enum FeedbackAddToDatasetFileSource {
New = 'Create new',
Existing = 'Add to existing',
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import {
SelectRoot,
SelectTrigger,
} from '@nvidia/foundations-react-core';
import { FeedbackAddToDatasetFileSource } from '@studio/api/intake/constants';
import { LOADING_FILES_OPTION } from '@studio/components/DatasetFileSelect/constants';
import {
FeedbackAddToDatasetFileSource,
LOADING_FILES_OPTION,
} from '@studio/components/DatasetFileSelect/constants';
import { MultiselectOption } from '@studio/constants/mutliselect';
import { Plus } from 'lucide-react';
import { FC, ReactNode, useMemo } from 'react';
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { IntakeAnnotationsPanel } from '@studio/components/IntakeAnnotationsPanel';
import { resetMockAnnotations } from '@studio/mocks/intake/telemetry';
import { renderRoute, screen, waitFor, within } from '@studio/tests/util/render';
import userEvent from '@testing-library/user-event';

const SPAN_ID = 'span-root-001';
const SESSION_ID = 'session-agent-run-001';

describe('IntakeAnnotationsPanel', () => {
beforeEach(() => {
resetMockAnnotations();
});

it('lists and creates span annotations through the generated client', async () => {
const user = userEvent.setup();

renderRoute(
<IntakeAnnotationsPanel workspace="default" spanId={SPAN_ID} sessionId={SESSION_ID} />,
{ history: '/workspaces/default/intake/spans/span-root-001' }
);

expect(
await screen.findByText('Good final response, but verify policy citations.')
).toBeInTheDocument();

await user.click(screen.getByRole('button', { name: /Negative/i }));
expect(await screen.findByText('Negative feedback')).toBeInTheDocument();

await user.type(screen.getByPlaceholderText('Add a note about this span.'), 'Needs review.');
await user.click(screen.getByRole('button', { name: /Add Note/i }));

expect(await screen.findByText('Needs review.')).toBeInTheDocument();
});

it('deletes span annotations through the generated client', async () => {
const user = userEvent.setup();

renderRoute(
<IntakeAnnotationsPanel workspace="default" spanId={SPAN_ID} sessionId={SESSION_ID} />,
{ history: '/workspaces/default/intake/spans/span-root-001' }
);

const note = await screen.findByRole('article', { name: 'Note annotation' });
await user.click(within(note).getByRole('button', { name: /Delete/i }));

await waitFor(() => {
expect(
screen.queryByText('Good final response, but verify policy citations.')
).not.toBeInTheDocument();
});
});
});
Loading
Loading