chore: ai, public course and other ui improvements

This commit is contained in:
Rotimi Best
2026-05-09 06:05:03 +01:00
parent 5717dd8004
commit c31ad63955
318 changed files with 20668 additions and 4788 deletions
@@ -0,0 +1,18 @@
export interface CoursePlanSectionItem {
type: 'lesson' | 'exercise';
title: string;
description: string;
order: number;
hasExercise: boolean;
}
export interface CoursePlanSection {
title: string;
order: number;
items: CoursePlanSectionItem[];
}
export interface CoursePlan {
title: string;
sections: CoursePlanSection[];
}
@@ -1,4 +1,5 @@
import { writable } from 'svelte/store';
import type { AgentModelId } from '@cio/utils/agent-models';
/** Controls whether the AI assistant right sidebar Sheet is open. */
export const isAiAssistantOpen = writable(false);
@@ -14,3 +15,23 @@ export function closeAiAssistant() {
export function toggleAiAssistant() {
isAiAssistantOpen.update((open) => !open);
}
/** Carries a prompt from the home page course creator into the AI chat on first open. */
export const initialChatPrompt = writable<string | null>(null);
export const initialChatModel = writable<AgentModelId | null>(null);
export function setInitialChatPrompt(prompt: string) {
initialChatPrompt.set(prompt);
}
export function setInitialChatModel(model: AgentModelId) {
initialChatModel.set(model);
}
export function clearInitialChatPrompt() {
initialChatPrompt.set(null);
}
export function clearInitialChatModel() {
initialChatModel.set(null);
}
@@ -8,7 +8,9 @@ const TOOL_LABELS: Record<string, string> = {
update_lesson: 'Updating lesson',
update_lesson_content: 'Writing lesson content',
create_exercise: 'Creating exercise',
create_exercise_section: 'Creating exercise section',
update_exercise: 'Updating exercise',
update_exercise_section: 'Updating exercise section',
add_questions: 'Adding questions',
update_questions: 'Updating questions',
reorder_content: 'Reordering content',
@@ -40,6 +42,8 @@ export function getToolResultLabel(toolName: string, result: unknown): string {
return `Created exercise with ${r.questionCount} questions`;
case 'update_exercise':
return `Updated exercise: ${r.title}`;
case 'update_exercise_section':
return `Updated exercise section: ${r.title}`;
case 'add_questions':
return `Added ${r.addedCount} questions`;
case 'update_questions':
@@ -78,7 +82,9 @@ export const MUTATION_TOOLS = [
'update_lesson',
'update_lesson_content',
'create_exercise',
'create_exercise_section',
'update_exercise',
'update_exercise_section',
'add_questions',
'update_questions',
'reorder_content',
@@ -12,12 +12,18 @@ export interface AgentToolPart {
};
}
export function isAgentToolPart(part: Record<string, unknown>): part is AgentToolPart {
if (part.type === 'tool-invocation') {
export function isAgentToolPart(part: unknown): part is AgentToolPart {
if (!part || typeof part !== 'object') {
return false;
}
const record = part as Record<string, unknown>;
if (record.type === 'tool-invocation') {
return true;
}
return typeof part.type === 'string' && part.type.startsWith('tool-');
return typeof record.type === 'string' && record.type.startsWith('tool-');
}
export function getAgentToolName(part: AgentToolPart): string | null {
@@ -11,8 +11,22 @@ export interface AiAssistantMessageAttachment {
name: string;
}
export interface AiAssistantMessageTokenUsage {
promptTokens: number;
completionTokens: number;
totalTokens: number;
}
export interface AiAssistantMessageContinuation {
reason: 'step_limit';
maxSteps: number;
finishReason?: string;
}
export interface AiAssistantMessageMetadata {
attachment?: AiAssistantMessageAttachment;
tokenUsage?: AiAssistantMessageTokenUsage;
continuation?: AiAssistantMessageContinuation;
}
export type AiAssistantMessage = UIMessage<AiAssistantMessageMetadata>;
@@ -47,3 +61,7 @@ export type AgentConversationCreateData = AgentConversationCreateSuccess['data']
export type AgentHistorySaveRequest = (typeof classroomio.agent.history)[':conversationId']['$put'];
export type AgentHistoryDeleteRequest = (typeof classroomio.agent.history)[':conversationId']['$delete'];
export type GenerateCourseTitleRequest = (typeof classroomio.agent)['generate-course-title']['$post'];
export type GenerateCourseTitleSuccess = Extract<InferResponseType<GenerateCourseTitleRequest>, { success: true }>;
export type GenerateCourseTitleData = GenerateCourseTitleSuccess['data'];