adding linted files and nvmrc -- will trigger precommit failures

Signed-off-by: Francisco Javier Arceo <farceo@redhat.com>
This commit is contained in:
Francisco Javier Arceo 2025-08-14 15:51:11 -04:00
parent ca80ab3b9e
commit 3f87db2eea
65 changed files with 1307 additions and 1137 deletions

View file

@ -1,50 +1,50 @@
type RecordAudioType = {
(stream: MediaStream): Promise<Blob>
stop: () => void
currentRecorder?: MediaRecorder
}
(stream: MediaStream): Promise<Blob>;
stop: () => void;
currentRecorder?: MediaRecorder;
};
export const recordAudio = (function (): RecordAudioType {
const func = async function recordAudio(stream: MediaStream): Promise<Blob> {
try {
const mediaRecorder = new MediaRecorder(stream, {
mimeType: "audio/webm;codecs=opus",
})
const audioChunks: Blob[] = []
});
const audioChunks: Blob[] = [];
return new Promise((resolve, reject) => {
mediaRecorder.ondataavailable = (event) => {
mediaRecorder.ondataavailable = event => {
if (event.data.size > 0) {
audioChunks.push(event.data)
audioChunks.push(event.data);
}
}
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: "audio/webm" })
resolve(audioBlob)
}
const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
resolve(audioBlob);
};
mediaRecorder.onerror = () => {
reject(new Error("MediaRecorder error occurred"))
}
reject(new Error("MediaRecorder error occurred"));
};
mediaRecorder.start(1000)
;(func as RecordAudioType).currentRecorder = mediaRecorder
})
mediaRecorder.start(1000);
(func as RecordAudioType).currentRecorder = mediaRecorder;
});
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error occurred"
throw new Error("Failed to start recording: " + errorMessage)
error instanceof Error ? error.message : "Unknown error occurred";
throw new Error("Failed to start recording: " + errorMessage);
}
}
};
;(func as RecordAudioType).stop = () => {
const recorder = (func as RecordAudioType).currentRecorder
(func as RecordAudioType).stop = () => {
const recorder = (func as RecordAudioType).currentRecorder;
if (recorder && recorder.state !== "inactive") {
recorder.stop()
recorder.stop();
}
delete (func as RecordAudioType).currentRecorder
}
delete (func as RecordAudioType).currentRecorder;
};
return func as RecordAudioType
})()
return func as RecordAudioType;
})();

View file

@ -27,19 +27,19 @@ export function validateServerConfig() {
!optionalConfigs.GITHUB_CLIENT_SECRET
) {
console.log(
"\n📝 GitHub OAuth not configured (authentication features disabled)",
"\n📝 GitHub OAuth not configured (authentication features disabled)"
);
console.log(" To enable GitHub OAuth:");
console.log(" 1. Go to https://github.com/settings/applications/new");
console.log(
" 2. Set Application name: Llama Stack UI (or your preferred name)",
" 2. Set Application name: Llama Stack UI (or your preferred name)"
);
console.log(" 3. Set Homepage URL: http://localhost:8322");
console.log(
" 4. Set Authorization callback URL: http://localhost:8322/api/auth/callback/github",
" 4. Set Authorization callback URL: http://localhost:8322/api/auth/callback/github"
);
console.log(
" 5. Create the app and copy the Client ID and Client Secret",
" 5. Create the app and copy the Client ID and Client Secret"
);
console.log(" 6. Add them to your .env.local file:");
console.log(" GITHUB_CLIENT_ID=your_client_id");

View file

@ -32,11 +32,18 @@ export interface VectorStoreListContentsResponse {
export class ContentsAPI {
constructor(private client: LlamaStackClient) {}
async getFileContents(vectorStoreId: string, fileId: string): Promise<VectorStoreContentsResponse> {
async getFileContents(
vectorStoreId: string,
fileId: string
): Promise<VectorStoreContentsResponse> {
return this.client.vectorStores.files.content(vectorStoreId, fileId);
}
async getContent(vectorStoreId: string, fileId: string, contentId: string): Promise<VectorStoreContentItem> {
async getContent(
vectorStoreId: string,
fileId: string,
contentId: string
): Promise<VectorStoreContentItem> {
const contentsResponse = await this.listContents(vectorStoreId, fileId);
const targetContent = contentsResponse.data.find(c => c.id === contentId);
@ -56,7 +63,11 @@ export class ContentsAPI {
throw new Error("Individual content updates not yet implemented in API");
}
async deleteContent(vectorStoreId: string, fileId: string, contentId: string): Promise<VectorStoreContentDeleteResponse> {
async deleteContent(
vectorStoreId: string,
fileId: string,
contentId: string
): Promise<VectorStoreContentDeleteResponse> {
throw new Error("Individual content deletion not yet implemented in API");
}
@ -70,7 +81,10 @@ export class ContentsAPI {
before?: string;
}
): Promise<VectorStoreListContentsResponse> {
const fileContents = await this.client.vectorStores.files.content(vectorStoreId, fileId);
const fileContents = await this.client.vectorStores.files.content(
vectorStoreId,
fileId
);
const contentItems: VectorStoreContentItem[] = [];
fileContents.content.forEach((content, contentIndex) => {
@ -78,10 +92,16 @@ export class ContentsAPI {
// Extract actual fields from the API response
const embedding = rawContent.embedding || undefined;
const created_timestamp = rawContent.created_timestamp || rawContent.created_at || Date.now() / 1000;
const created_timestamp =
rawContent.created_timestamp ||
rawContent.created_at ||
Date.now() / 1000;
const chunkMetadata = rawContent.chunk_metadata || {};
const contentId = rawContent.chunk_metadata?.chunk_id || rawContent.id || `content_${fileId}_${contentIndex}`;
const objectType = rawContent.object || 'vector_store.file.content';
const contentId =
rawContent.chunk_metadata?.chunk_id ||
rawContent.id ||
`content_${fileId}_${contentIndex}`;
const objectType = rawContent.object || "vector_store.file.content";
contentItems.push({
id: contentId,
object: objectType,
@ -92,7 +112,7 @@ export class ContentsAPI {
embedding: embedding,
metadata: {
...chunkMetadata, // chunk_metadata fields from API
content_length: content.type === 'text' ? content.text.length : 0,
content_length: content.type === "text" ? content.text.length : 0,
},
});
});
@ -104,7 +124,7 @@ export class ContentsAPI {
}
return {
object: 'list',
object: "list",
data: filteredItems,
has_more: contentItems.length > (options?.limit || contentItems.length),
};

View file

@ -18,7 +18,7 @@ describe("extractTextFromContentPart", () => {
it("should extract text from an array of text content objects", () => {
const content = [{ type: "text", text: "Which planet do humans live on?" }];
expect(extractTextFromContentPart(content)).toBe(
"Which planet do humans live on?",
"Which planet do humans live on?"
);
});
@ -37,7 +37,7 @@ describe("extractTextFromContentPart", () => {
{ type: "text", text: "It's an image." },
];
expect(extractTextFromContentPart(content)).toBe(
"Look at this: [Image] It's an image.",
"Look at this: [Image] It's an image."
);
});
@ -77,7 +77,7 @@ describe("extractTextFromContentPart", () => {
{ type: "text", text: "Last part." },
] as any;
expect(extractTextFromContentPart(content)).toBe(
"First part. Just a string. [Image] Last part.",
"First part. Just a string. [Image] Last part."
);
});
});
@ -125,7 +125,7 @@ describe("extractDisplayableText (composite function)", () => {
tool_calls: [toolCall],
};
expect(extractDisplayableText(messageWithEffectivelyEmptyContent)).toBe(
mockFormatToolCallToString(toolCall),
mockFormatToolCallToString(toolCall)
);
const messageWithEmptyContent: ChatMessage = {
@ -134,7 +134,7 @@ describe("extractDisplayableText (composite function)", () => {
tool_calls: [toolCall],
};
expect(extractDisplayableText(messageWithEmptyContent)).toBe(
mockFormatToolCallToString(toolCall),
mockFormatToolCallToString(toolCall)
);
});
@ -149,7 +149,7 @@ describe("extractDisplayableText (composite function)", () => {
};
const expectedToolCallStr = mockFormatToolCallToString(toolCall);
expect(extractDisplayableText(message)).toBe(
`The result is: ${expectedToolCallStr}`,
`The result is: ${expectedToolCallStr}`
);
});
@ -167,7 +167,7 @@ describe("extractDisplayableText (composite function)", () => {
};
const expectedToolCallStr = mockFormatToolCallToString(toolCall);
expect(extractDisplayableText(message)).toBe(
`Okay, checking weather for London. ${expectedToolCallStr}`,
`Okay, checking weather for London. ${expectedToolCallStr}`
);
});
@ -178,7 +178,7 @@ describe("extractDisplayableText (composite function)", () => {
tool_calls: [],
};
expect(extractDisplayableText(messageEmptyToolCalls)).toBe(
"No tools here.",
"No tools here."
);
const messageUndefinedToolCalls: ChatMessage = {
@ -187,7 +187,7 @@ describe("extractDisplayableText (composite function)", () => {
tool_calls: undefined,
};
expect(extractDisplayableText(messageUndefinedToolCalls)).toBe(
"Still no tools.",
"Still no tools."
);
});
});

View file

@ -2,7 +2,7 @@ import { ChatMessage, ChatMessageContentPart } from "@/lib/types";
import { formatToolCallToString } from "@/lib/format-tool-call";
export function extractTextFromContentPart(
content: string | ChatMessageContentPart[] | null | undefined,
content: string | ChatMessageContentPart[] | null | undefined
): string {
if (content === null || content === undefined) {
return "";
@ -37,7 +37,7 @@ export function extractTextFromContentPart(
}
export function extractDisplayableText(
message: ChatMessage | undefined | null,
message: ChatMessage | undefined | null
): string {
if (!message) {
return "";

View file

@ -1,6 +1,6 @@
export function truncateText(
text: string | null | undefined,
maxLength: number = 50,
maxLength: number = 50
): string {
if (!text) return "N/A";
if (text.length <= maxLength) return text;