diff --git a/apps/backend/package.json b/apps/backend/package.json index 86cbe4a..1d56f55 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -50,10 +50,10 @@ }, "dependencies": { "@fastify/cors": "^10.0.2", - "@github/copilot-sdk": "^0.1.0", + "@github/copilot-sdk": "^0.1.28", "better-sqlite3": "^11.7.0", "drizzle-orm": "^0.38.4", - "fastify": "^5.2.1", + "fastify": "^5.7.4", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "sharp": "^0.34.5", diff --git a/apps/backend/src/native/host.ts b/apps/backend/src/native/host.ts index eb5ac27..0bb6750 100644 --- a/apps/backend/src/native/host.ts +++ b/apps/backend/src/native/host.ts @@ -254,10 +254,14 @@ class NativeMessagingHost { break; } - // Process message asynchronously - this.handleMessage(message).catch((err) => { - this.log(`Error handling message: ${err}`); - }); + // Process message asynchronously but catch synchronous errors from the promise initialization + try { + this.handleMessage(message).catch((err) => { + this.log(`Error handling message: ${err}`); + }); + } catch (handleErr) { + this.log(`Error initializing message handler: ${handleErr}`); + } } catch (error) { this.log(`Error reading message: ${error}`); break; diff --git a/apps/backend/src/routes/chat.ts b/apps/backend/src/routes/chat.ts index 484b3d1..9fa9839 100644 --- a/apps/backend/src/routes/chat.ts +++ b/apps/backend/src/routes/chat.ts @@ -112,7 +112,7 @@ const fullContextSchema = z.object({ }), }).passthrough(); -// Schema for image payload +// Schema for image payload (inline data URL - legacy / small images) const imagePayloadSchema = z.object({ id: z.string(), dataUrl: z.string(), @@ -120,12 +120,25 @@ const imagePayloadSchema = z.object({ source: z.enum(['screenshot', 'paste', 'drop']), }); +// Schema for pre-uploaded image reference (from /api/images/upload endpoint) +const preUploadedImageSchema = z.object({ + id: z.string(), + fullImagePath: z.string(), + mimeType: z.string(), + thumbnailUrl: z.string().optional(), + fullImageUrl: z.string().optional(), + dimensions: z.object({ width: z.number(), height: z.number() }).optional(), + fileSize: z.number().optional(), +}); + const sendMessageSchema = z.object({ prompt: z.string().min(1), context: simpleContextSchema.optional(), fullContext: fullContextSchema.optional(), useContextAwareMode: z.boolean().optional(), images: z.array(imagePayloadSchema).max(5).optional(), + /** Pre-uploaded image references (already processed on disk) */ + preUploadedImages: z.array(preUploadedImageSchema).max(5).optional(), }); export async function chatRoutes(fastify: FastifyInstance) { @@ -269,6 +282,7 @@ export async function chatRoutes(fastify: FastifyInstance) { // Process images if provided let processedImagesRaw: ProcessedImage[] = []; let processedImages: ImageAttachment[] = []; + let copilotAttachments: Array<{ type: 'file'; path: string; displayName: string }> = []; // Build backend URL with port for image serving const host = request.headers.host || `${request.hostname}:3847`; const backendUrl = `http://${host}`; @@ -288,9 +302,36 @@ export async function chatRoutes(fastify: FastifyInstance) { ); // Process images after we have the message ID - if (body.images && body.images.length > 0) { + // Prefer pre-uploaded images (already on disk) over inline data URLs + if (body.preUploadedImages && body.preUploadedImages.length > 0) { + // Images were already processed via /api/images/upload endpoint + console.log(`[ChatRoute] Using ${body.preUploadedImages.length} pre-uploaded images`); + copilotAttachments = body.preUploadedImages.map((img, index) => ({ + type: 'file' as const, + path: img.fullImagePath, + displayName: `image_${index + 1}.${(img.mimeType || 'image/jpeg').split('/')[1] || 'jpg'}`, + })); + + // Build metadata for message storage + processedImages = body.preUploadedImages.map(img => ({ + id: img.id, + source: 'screenshot' as const, + mimeType: (img.mimeType || 'image/jpeg') as any, + dimensions: img.dimensions || { width: 0, height: 0 }, + fileSize: img.fileSize || 0, + timestamp: new Date().toISOString(), + thumbnailUrl: img.thumbnailUrl, + fullImageUrl: img.fullImageUrl, + })); + + fastify.sessionService.updateMessageMetadata(userMessage.id, { + ...userMessage.metadata, + images: processedImages, + }); + } else if (body.images && body.images.length > 0) { + // Inline image upload (legacy path for small images) try { - console.log(`[ChatRoute] Processing ${body.images.length} images for message ${userMessage.id}`); + console.log(`[ChatRoute] Processing ${body.images.length} inline images for message ${userMessage.id}`); processedImagesRaw = await processMessageImages( sessionId, userMessage.id, @@ -305,19 +346,18 @@ export async function chatRoutes(fastify: FastifyInstance) { images: processedImages, }); + copilotAttachments = processedImagesRaw.map((img, index) => ({ + type: 'file' as const, + path: img.fullImagePath, + displayName: `image_${index + 1}.${img.mimeType.split('/')[1] || 'jpg'}`, + })); + console.log(`[ChatRoute] Processed ${processedImages.length} images successfully`); } catch (err) { console.error('[ChatRoute] Failed to process images:', err); // Continue without images - don't fail the message } } - - // Build attachments for Copilot SDK from processed images - const copilotAttachments = processedImagesRaw.map((img, index) => ({ - type: 'file' as const, - path: img.fullImagePath, - displayName: `image_${index + 1}.${img.mimeType.split('/')[1] || 'jpg'}`, - })); if (copilotAttachments.length > 0) { console.log(`[ChatRoute] Built ${copilotAttachments.length} attachments for Copilot:`, copilotAttachments); @@ -475,6 +515,12 @@ export async function chatRoutes(fastify: FastifyInstance) { cleanupTimers(); if (!streamEnded) { + if (!reply.raw.headersSent) { + reply.raw.setHeader('Content-Type', 'text/event-stream'); + reply.raw.setHeader('Cache-Control', 'no-cache'); + reply.raw.setHeader('Connection', 'keep-alive'); + reply.raw.setHeader('Access-Control-Allow-Origin', '*'); + } sendSSE({ type: 'error', data: { @@ -516,6 +562,12 @@ export async function chatRoutes(fastify: FastifyInstance) { } // Send error via SSE + if (!reply.raw.headersSent) { + reply.raw.setHeader('Content-Type', 'text/event-stream'); + reply.raw.setHeader('Cache-Control', 'no-cache'); + reply.raw.setHeader('Connection', 'keep-alive'); + reply.raw.setHeader('Access-Control-Allow-Origin', '*'); + } const errorEvent: StreamEvent = { type: 'error', data: { error: error instanceof Error ? error.message : 'Unknown error' }, diff --git a/apps/backend/src/routes/images.ts b/apps/backend/src/routes/images.ts index 7fb6e80..c3fdd75 100644 --- a/apps/backend/src/routes/images.ts +++ b/apps/backend/src/routes/images.ts @@ -2,16 +2,24 @@ * Images Route * * Serves thumbnail and full images stored on disk. + * Also provides an upload endpoint for pre-uploading images before chat. + * * Routes: - * GET /api/images/:sessionId/:messageId/thumb_:index.jpg - Thumbnail - * GET /api/images/:sessionId/:messageId/image_:index.:ext - Full image + * GET /api/images/:sessionId/:messageId/thumb_:index.jpg - Thumbnail + * GET /api/images/:sessionId/:messageId/image_:index.:ext - Full image + * POST /api/images/upload/:sessionId/:messageId - Pre-upload images */ import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; +import { z } from 'zod'; import fs from 'node:fs'; import path from 'node:path'; import { IMAGES_DIR } from '../lib/paths.js'; -import { getThumbnailFilePath } from '../services/thumbnail-service.js'; +import { + getThumbnailFilePath, + processMessageImages, + toImageAttachments, +} from '../services/thumbnail-service.js'; interface ImageParams { sessionId: string; @@ -28,7 +36,89 @@ const MIME_TYPES: Record = { 'gif': 'image/gif', }; +// Schema for identifying a single image in an upload payload +const uploadImageSchema = z.object({ + id: z.string(), + dataUrl: z.string(), + mimeType: z.enum(['image/png', 'image/jpeg', 'image/webp']), + source: z.enum(['screenshot', 'paste', 'drop']), +}); + +const uploadBodySchema = z.object({ + images: z.array(uploadImageSchema).min(1).max(5), +}); + export async function imagesRoutes(fastify: FastifyInstance) { + /** + * POST /api/images/upload/:sessionId/:messageId + * Pre-upload images before sending the chat message. + * Returns processed image info (thumbnailUrl, fullImageUrl, fullImagePath). + */ + fastify.post<{ + Params: { sessionId: string; messageId: string }; + Body: z.infer; + }>( + '/upload/:sessionId/:messageId', + async (request, reply) => { + try { + const { sessionId, messageId } = request.params; + const body = uploadBodySchema.parse(request.body); + + // Build backend URL for image serving + const host = request.headers.host || `${request.hostname}:3847`; + const backendUrl = `http://${host}`; + + console.log(`[ImagesRoute] Pre-uploading ${body.images.length} images for ${sessionId}/${messageId}`); + + const processedImagesRaw = await processMessageImages( + sessionId, + messageId, + body.images, + backendUrl + ); + + const processedImages = toImageAttachments(processedImagesRaw); + + // Return the processed image metadata + absolute paths for Copilot SDK attachments + const responseImages = processedImagesRaw.map((img, i) => ({ + id: img.id, + thumbnailUrl: img.thumbnailUrl, + fullImageUrl: img.fullImageUrl, + fullImagePath: img.fullImagePath, + mimeType: img.mimeType, + dimensions: img.dimensions, + fileSize: img.fileSize, + })); + + console.log(`[ImagesRoute] Pre-upload complete: ${responseImages.length} images processed`); + + return reply.send({ + success: true, + data: { images: responseImages }, + }); + } catch (error) { + if (error instanceof z.ZodError) { + return reply.code(400).send({ + success: false, + error: { + code: 'VALIDATION_ERROR', + message: 'Invalid upload body', + details: error.errors, + }, + }); + } + console.error('[ImagesRoute] Upload failed:', error); + return reply.code(500).send({ + success: false, + error: { + code: 'UPLOAD_ERROR', + message: error instanceof Error ? error.message : 'Failed to process images', + }, + }); + } + } + ); + /** * GET /api/images/:sessionId/:messageId/:filename * Serves thumbnail or full image diff --git a/apps/backend/src/server.ts b/apps/backend/src/server.ts index 497e7a9..a8034d1 100644 --- a/apps/backend/src/server.ts +++ b/apps/backend/src/server.ts @@ -30,6 +30,8 @@ function truncate(str: string | undefined | null, maxLen = 500): string { export async function createServer() { const fastify = Fastify({ + // Allow large payloads for image uploads (data URLs can be 10-30MB for full-page screenshots) + bodyLimit: 50 * 1024 * 1024, // 50MB logger: { level: DEBUG_MODE ? 'debug' : 'info', transport: { diff --git a/apps/backend/src/services/copilot.service.ts b/apps/backend/src/services/copilot.service.ts index 596b7c1..3c0382e 100644 --- a/apps/backend/src/services/copilot.service.ts +++ b/apps/backend/src/services/copilot.service.ts @@ -1,4 +1,4 @@ -import { CopilotClient, type SessionEvent, type Tool as CopilotTool } from '@github/copilot-sdk'; +import { CopilotClient, type SessionEvent, type Tool as CopilotTool, approveAll } from '@github/copilot-sdk'; import { SessionService } from './session.service.js'; import { getAgentConfig, SESSION_TYPE_CONFIGS } from '@devmentorai/shared'; import type { @@ -360,6 +360,7 @@ export class CopilotService { systemMessage: systemPrompt ? { content: systemPrompt } : undefined, tools, mcpServers, + onPermissionRequest: approveAll, }); this.sessions.set(sessionId, { sessionId, session, type }); @@ -394,7 +395,7 @@ export class CopilotService { // First, try to resume existing session try { - const session = await this.client.resumeSession(sessionId); + const session = await this.client.resumeSession(sessionId, { onPermissionRequest: approveAll }); // Try to get type from DB, fallback to 'general' const dbSession = this.sessionService.getSession(sessionId); this.sessions.set(sessionId, { sessionId, session, type: dbSession?.type || 'general' }); diff --git a/apps/backend/src/services/thumbnail-service.ts b/apps/backend/src/services/thumbnail-service.ts index e90b10e..4437888 100644 --- a/apps/backend/src/services/thumbnail-service.ts +++ b/apps/backend/src/services/thumbnail-service.ts @@ -28,6 +28,13 @@ const THUMBNAIL_CONFIG = { format: 'jpeg' as const, }; +/** Full image generation settings */ +const FULL_IMAGE_CONFIG = { + maxDimension: 2000, + quality: 80, + format: 'jpeg' as const, +}; + export interface ImageInput { id: string; dataUrl: string; @@ -88,6 +95,19 @@ async function generateThumbnail(buffer: Buffer): Promise { .toBuffer(); } +/** + * Generate a compressed full-size image from an image buffer + */ +async function generateFullImage(buffer: Buffer): Promise { + return sharp(buffer) + .resize(FULL_IMAGE_CONFIG.maxDimension, FULL_IMAGE_CONFIG.maxDimension, { + fit: 'inside', + withoutEnlargement: true, + }) + .jpeg({ quality: FULL_IMAGE_CONFIG.quality }) + .toBuffer(); +} + /** * Get the file extension for a MIME type */ @@ -156,10 +176,12 @@ export async function processMessageImages( fs.writeFileSync(thumbnailAbsPath, thumbnailBuffer); // Save FULL IMAGE to disk (for Copilot SDK attachments and lightbox view) - const extension = getExtensionForMimeType(mimeType); + // Resize and compress to avoid huge payloads crashing the backend + const fullImageBuffer = await generateFullImage(buffer); + const extension = 'jpg'; // Always jpeg as per FULL_IMAGE_CONFIG const fullImageAbsPath = getFullImagePath(sessionId, messageId, index, extension); - fs.writeFileSync(fullImageAbsPath, buffer); - console.log(`[ThumbnailService] Saved full image to ${fullImageAbsPath}`); + fs.writeFileSync(fullImageAbsPath, fullImageBuffer); + console.log(`[ThumbnailService] Saved compressed full image to ${fullImageAbsPath}`); // Generate relative paths for DB storage (from DATA_DIR) const thumbnailRelativePath = toRelativePath(thumbnailAbsPath); diff --git a/apps/backend/src/tools/devops-tools.ts b/apps/backend/src/tools/devops-tools.ts index 76b616a..5aa9f84 100644 --- a/apps/backend/src/tools/devops-tools.ts +++ b/apps/backend/src/tools/devops-tools.ts @@ -509,6 +509,70 @@ export const analyzeErrorTool: Tool = { }, }; +/** + * Fetch public URL content + */ +export const fetchUrlTool: Tool = { + name: 'fetch_url', + description: 'Fetch the text content of a public URL. Use this to read documentation, github issues, or other public web pages when the user shares a URL.', + parameters: { + type: 'object', + properties: { + url: { + type: 'string', + description: 'The HTTP or HTTPS URL to fetch', + }, + }, + required: ['url'], + }, + handler: async (params) => { + const targetUrl = params.url as string; + + if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) { + return `Error: Only HTTP/HTTPS URLs are supported, got "${targetUrl}"`; + } + + try { + // Abort after 10 seconds to avoid hanging + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 10000); + + const response = await fetch(targetUrl, { + signal: controller.signal, + headers: { + 'User-Agent': 'DevMentorAI/1.0', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,text/plain;q=0.8', + }, + }); + + clearTimeout(timeoutId); + + if (!response.ok) { + return `Error: Server responded with status ${response.status} ${response.statusText}`; + } + + const contentType = response.headers.get('content-type') || ''; + const text = await response.text(); + + // If it's an HTML page, we should ideally strip tags, but for a simple tool, + // returning the raw text/HTML up to a reasonable limit is a good start. + // We'll limit the response size to avoid overwhelming the LLM context. + const MAX_LENGTH = 15000; + + if (text.length > MAX_LENGTH) { + return text.substring(0, MAX_LENGTH) + `\n\n[Content truncated at ${MAX_LENGTH} characters]`; + } + + return text; + } catch (error) { + if ((error as any).name === 'AbortError') { + return `Error: Request to ${targetUrl} timed out after 10 seconds.`; + } + return `Error fetching URL: ${error instanceof Error ? error.message : String(error)}`; + } + }, +}; + /** * Export all DevOps tools */ @@ -517,6 +581,7 @@ export const devopsTools: Tool[] = [ listDirectoryTool, analyzeConfigTool, analyzeErrorTool, + fetchUrlTool, ]; export function getToolByName(name: string): Tool | undefined { diff --git a/apps/backend/tests/tools/devops-tools.test.ts b/apps/backend/tests/tools/devops-tools.test.ts index e264eb2..6dbd511 100644 --- a/apps/backend/tests/tools/devops-tools.test.ts +++ b/apps/backend/tests/tools/devops-tools.test.ts @@ -31,8 +31,8 @@ describe('DevOps Tools', () => { }); describe('Tool Registry', () => { - it('should have 4 tools registered', () => { - expect(devopsTools).toHaveLength(4); + it('should have 5 tools registered', () => { + expect(devopsTools).toHaveLength(5); }); it('should find tool by name', () => { diff --git a/packages/shared/src/contracts/api.contracts.d.ts b/packages/shared/src/contracts/api.contracts.d.ts index 9f68586..7ab3dc6 100644 --- a/packages/shared/src/contracts/api.contracts.d.ts +++ b/packages/shared/src/contracts/api.contracts.d.ts @@ -15,6 +15,7 @@ export declare const API_ENDPOINTS: { readonly SESSION_MESSAGES: (id: string) => string; readonly CHAT: (sessionId: string) => string; readonly CHAT_STREAM: (sessionId: string) => string; + readonly IMAGE_UPLOAD: (sessionId: string) => string; readonly MODELS: "/api/models"; readonly ACCOUNT_AUTH: "/api/account/auth"; readonly ACCOUNT_QUOTA: "/api/account/quota"; @@ -84,6 +85,27 @@ export interface ApiEndpoints { body: SendMessageRequest; response: ReadableStream; }; + 'POST /api/sessions/:id/images/upload': { + params: { + id: string; + }; + body: { + images: Array<{ + id: string; + dataUrl: string; + mimeType: string; + source: string; + }>; + }; + response: ApiResponse<{ + images: Array<{ + id: string; + thumbnailUrl: string; + fullImageUrl: string; + fullImagePath: string; + }>; + }>; + }; 'GET /api/models': { response: ApiResponse<{ models: ModelInfo[]; diff --git a/packages/shared/src/contracts/api.contracts.d.ts.map b/packages/shared/src/contracts/api.contracts.d.ts.map index 2489666..bc9ee0a 100644 --- a/packages/shared/src/contracts/api.contracts.d.ts.map +++ b/packages/shared/src/contracts/api.contracts.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"api.contracts.d.ts","sourceRoot":"","sources":["api.contracts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,oBAAoB,EACpB,oBAAoB,EACpB,OAAO,EACP,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,eAAO,MAAM,aAAa;;;2BAMV,MAAM;kCACC,MAAM;iCACP,MAAM;oCACH,MAAM;+BAGX,MAAM;sCACC,MAAM;;;;CAQvB,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,YAAY;IAE3B,iBAAiB,EAAE;QACjB,QAAQ,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC;KACvC,CAAC;IAGF,mBAAmB,EAAE;QACnB,QAAQ,EAAE,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;KACnD,CAAC;IAGF,oBAAoB,EAAE;QACpB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,uBAAuB,EAAE;QACvB,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,yBAAyB,EAAE;QACzB,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,0BAA0B,EAAE;QAC1B,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;KAC7B,CAAC;IAGF,+BAA+B,EAAE;QAC/B,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,8BAA8B,EAAE;QAC9B,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;KAC7B,CAAC;IAGF,gCAAgC,EAAE;QAChC,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;KACnD,CAAC;IAGF,6BAA6B,EAAE;QAC7B,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,IAAI,EAAE,kBAAkB,CAAC;QACzB,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,oCAAoC,EAAE;QACpC,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,IAAI,EAAE,kBAAkB,CAAC;QACzB,QAAQ,EAAE,cAAc,CAAC;KAC1B,CAAC;IAGF,iBAAiB,EAAE;QACjB,QAAQ,EAAE,WAAW,CAAC;YAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACjE,CAAC;IAGF,uBAAuB,EAAE;QACvB,QAAQ,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAC;KAC1C,CAAC;IAGF,wBAAwB,EAAE;QACxB,QAAQ,EAAE,WAAW,CAAC,kBAAkB,CAAC,CAAC;KAC3C,CAAC;CACH;AAED;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;CAMjB,CAAC"} \ No newline at end of file +{"version":3,"file":"api.contracts.d.ts","sourceRoot":"","sources":["api.contracts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,oBAAoB,EACpB,oBAAoB,EACpB,OAAO,EACP,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,eAAO,MAAM,aAAa;;;2BAMV,MAAM;kCACC,MAAM;iCACP,MAAM;oCACH,MAAM;+BAGX,MAAM;sCACC,MAAM;uCAGL,MAAM;;;;CAQxB,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,YAAY;IAE3B,iBAAiB,EAAE;QACjB,QAAQ,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC;KACvC,CAAC;IAGF,mBAAmB,EAAE;QACnB,QAAQ,EAAE,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;KACnD,CAAC;IAGF,oBAAoB,EAAE;QACpB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,uBAAuB,EAAE;QACvB,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,yBAAyB,EAAE;QACzB,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,0BAA0B,EAAE;QAC1B,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;KAC7B,CAAC;IAGF,+BAA+B,EAAE;QAC/B,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,8BAA8B,EAAE;QAC9B,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;KAC7B,CAAC;IAGF,gCAAgC,EAAE;QAChC,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;KACnD,CAAC;IAGF,6BAA6B,EAAE;QAC7B,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,IAAI,EAAE,kBAAkB,CAAC;QACzB,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;KAChC,CAAC;IAGF,oCAAoC,EAAE;QACpC,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,IAAI,EAAE,kBAAkB,CAAC;QACzB,QAAQ,EAAE,cAAc,CAAC;KAC1B,CAAC;IAGF,sCAAsC,EAAE;QACtC,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACvB,IAAI,EAAE;YAAE,MAAM,EAAE,KAAK,CAAC;gBAAE,EAAE,EAAE,MAAM,CAAC;gBAAC,OAAO,EAAE,MAAM,CAAC;gBAAC,QAAQ,EAAE,MAAM,CAAC;gBAAC,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC;QAC3F,QAAQ,EAAE,WAAW,CAAC;YAAE,MAAM,EAAE,KAAK,CAAC;gBAAE,EAAE,EAAE,MAAM,CAAC;gBAAC,YAAY,EAAE,MAAM,CAAC;gBAAC,YAAY,EAAE,MAAM,CAAC;gBAAC,aAAa,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC,CAAC;KAC7H,CAAC;IAGF,iBAAiB,EAAE;QACjB,QAAQ,EAAE,WAAW,CAAC;YAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACjE,CAAC;IAGF,uBAAuB,EAAE;QACvB,QAAQ,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAC;KAC1C,CAAC;IAGF,wBAAwB,EAAE;QACxB,QAAQ,EAAE,WAAW,CAAC,kBAAkB,CAAC,CAAC;KAC3C,CAAC;CACH;AAED;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;CAMjB,CAAC"} \ No newline at end of file diff --git a/packages/shared/src/contracts/api.contracts.js b/packages/shared/src/contracts/api.contracts.js index d5238a8..0428945 100644 --- a/packages/shared/src/contracts/api.contracts.js +++ b/packages/shared/src/contracts/api.contracts.js @@ -17,6 +17,8 @@ export const API_ENDPOINTS = { // Chat CHAT: (sessionId) => `/api/sessions/${sessionId}/chat`, CHAT_STREAM: (sessionId) => `/api/sessions/${sessionId}/chat/stream`, + // Image upload (pre-upload before sending chat) + IMAGE_UPLOAD: (sessionId) => `/api/sessions/${sessionId}/images/upload`, // Models MODELS: '/api/models', // Account diff --git a/packages/shared/src/contracts/api.contracts.js.map b/packages/shared/src/contracts/api.contracts.js.map index 6f3b55e..db93cd3 100644 --- a/packages/shared/src/contracts/api.contracts.js.map +++ b/packages/shared/src/contracts/api.contracts.js.map @@ -1 +1 @@ -{"version":3,"file":"api.contracts.js","sourceRoot":"","sources":["api.contracts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,SAAS;IACT,MAAM,EAAE,aAAa;IAErB,WAAW;IACX,QAAQ,EAAE,eAAe;IACzB,OAAO,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,EAAE;IAC9C,cAAc,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS;IAC5D,aAAa,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,QAAQ;IAC1D,gBAAgB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,WAAW;IAEhE,OAAO;IACP,IAAI,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,iBAAiB,SAAS,OAAO;IAC9D,WAAW,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,iBAAiB,SAAS,cAAc;IAE5E,SAAS;IACT,MAAM,EAAE,aAAa;IAErB,UAAU;IACV,YAAY,EAAE,mBAAmB;IACjC,aAAa,EAAE,oBAAoB;CAC3B,CAAC;AAyFX;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,aAAa,EAAE,SAAS;IACxB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,WAAW;IACzB,kBAAkB,EAAE,KAAK;IACzB,iBAAiB,EAAE,MAAM;CACjB,CAAC"} \ No newline at end of file +{"version":3,"file":"api.contracts.js","sourceRoot":"","sources":["api.contracts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,SAAS;IACT,MAAM,EAAE,aAAa;IAErB,WAAW;IACX,QAAQ,EAAE,eAAe;IACzB,OAAO,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,EAAE;IAC9C,cAAc,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS;IAC5D,aAAa,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,QAAQ;IAC1D,gBAAgB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,WAAW;IAEhE,OAAO;IACP,IAAI,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,iBAAiB,SAAS,OAAO;IAC9D,WAAW,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,iBAAiB,SAAS,cAAc;IAE5E,gDAAgD;IAChD,YAAY,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,iBAAiB,SAAS,gBAAgB;IAE/E,SAAS;IACT,MAAM,EAAE,aAAa;IAErB,UAAU;IACV,YAAY,EAAE,mBAAmB;IACjC,aAAa,EAAE,oBAAoB;CAC3B,CAAC;AAgGX;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,aAAa,EAAE,SAAS;IACxB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,WAAW;IACzB,kBAAkB,EAAE,KAAK;IACzB,iBAAiB,EAAE,MAAM;CACjB,CAAC"} \ No newline at end of file diff --git a/packages/shared/src/contracts/api.contracts.ts b/packages/shared/src/contracts/api.contracts.ts index 1aabf2c..5bccb97 100644 --- a/packages/shared/src/contracts/api.contracts.ts +++ b/packages/shared/src/contracts/api.contracts.ts @@ -35,6 +35,9 @@ export const API_ENDPOINTS = { CHAT: (sessionId: string) => `/api/sessions/${sessionId}/chat`, CHAT_STREAM: (sessionId: string) => `/api/sessions/${sessionId}/chat/stream`, + // Image upload (pre-upload before sending chat) + IMAGE_UPLOAD: (sessionId: string) => `/api/sessions/${sessionId}/images/upload`, + // Models MODELS: '/api/models', @@ -113,6 +116,13 @@ export interface ApiEndpoints { body: SendMessageRequest; response: ReadableStream; // SSE stream }; + + // POST /api/sessions/:id/images/upload + 'POST /api/sessions/:id/images/upload': { + params: { id: string }; + body: { images: Array<{ id: string; dataUrl: string; mimeType: string; source: string }> }; + response: ApiResponse<{ images: Array<{ id: string; thumbnailUrl: string; fullImageUrl: string; fullImagePath: string }> }>; + }; // GET /api/models 'GET /api/models': { diff --git a/packages/shared/src/contracts/session-types.d.ts.map b/packages/shared/src/contracts/session-types.d.ts.map index a0161e2..bb17185 100644 --- a/packages/shared/src/contracts/session-types.d.ts.map +++ b/packages/shared/src/contracts/session-types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"session-types.d.ts","sourceRoot":"","sources":["session-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,WAAW,EAAE,iBAAiB,CAuGvE,CAAC;AAEF;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAEpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEzD"} \ No newline at end of file +{"version":3,"file":"session-types.d.ts","sourceRoot":"","sources":["session-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,WAAW,EAAE,iBAAiB,CA2GvE,CAAC;AAEF;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAEpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEzD"} \ No newline at end of file diff --git a/packages/shared/src/contracts/session-types.js b/packages/shared/src/contracts/session-types.js index f05ef67..46cb4ed 100644 --- a/packages/shared/src/contracts/session-types.js +++ b/packages/shared/src/contracts/session-types.js @@ -21,6 +21,8 @@ export const SESSION_TYPE_CONFIGS = { - Error diagnosis, log analysis, and troubleshooting - Architecture design and scalability patterns +IMPORTANT TOOL CAPABILITY: You have a tool called "fetch_url" available. Whenever a user provides a public URL in their request, you SHOULD PROACTIVELY use the fetch_url tool to read its contents and provide a more accurate, contextual response based on the actual content of that page. Do not assume you cannot read URLs - you have a tool specifically for this purpose. + When analyzing configurations or errors: 1. Identify the issue or configuration clearly 2. Explain WHY something is problematic or recommended @@ -28,7 +30,7 @@ When analyzing configurations or errors: 4. Reference official documentation when helpful 5. Warn about security implications when relevant -Be concise but thorough. Use code blocks for configurations and commands.`, +Provide a high-quality, detailed, and explanatory response that helps the user completely understand the concepts, steps, and 'why' behind the suggestions. Use code blocks for configurations and commands.`, }, }, writing: { @@ -55,7 +57,7 @@ Guidelines: 3. Preserve formatting when rewriting 4. For translations, keep cultural nuances in mind 5. Provide alternatives when helpful -6. Be concise unless expansion is requested +6. Provide rich, detailed explanations and fully expand on ideas when discussing or explaining writing choices. When the user provides text to modify, respond with ONLY the modified text unless they ask for explanation.`, }, @@ -78,8 +80,10 @@ When the user provides text to modify, respond with ONLY the modified text unles - Documentation and code comments - Refactoring and code cleanup +IMPORTANT TOOL CAPABILITY: You have tools available to assist you. If you are in a devops session type, you have a tool called "fetch_url". Whenever a user provides a public URL in their request and you have the tool available, you SHOULD PROACTIVELY use the fetch_url tool to read its contents and provide a more accurate, contextual response. Do not assume you cannot read URLs. + Guidelines: -1. Be concise and actionable +1. Provide actionable and detailed explanatory responses that help the user completely understand the concepts, steps, and 'why' behind the suggestions. 2. Explain the "why" behind suggestions 3. Provide code examples when helpful 4. Consider edge cases and error handling diff --git a/packages/shared/src/contracts/session-types.js.map b/packages/shared/src/contracts/session-types.js.map index a806978..c020bbc 100644 --- a/packages/shared/src/contracts/session-types.js.map +++ b/packages/shared/src/contracts/session-types.js.map @@ -1 +1 @@ -{"version":3,"file":"session-types.js","sourceRoot":"","sources":["session-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmBH,MAAM,CAAC,MAAM,oBAAoB,GAA2C;IAC1E,MAAM,EAAE;QACN,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,4DAA4D;QACzE,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE;YACL,IAAI,EAAE,eAAe;YACrB,WAAW,EAAE,eAAe;YAC5B,WAAW,EAAE,4DAA4D;YACzE,MAAM,EAAE;;;;;;;;;;;;;;;;;0EAiB4D;SACrE;KACF;IAED,OAAO,EAAE;QACP,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,gDAAgD;QAC7D,IAAI,EAAE,IAAI;QACV,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE;YACL,IAAI,EAAE,mBAAmB;YACzB,WAAW,EAAE,mBAAmB;YAChC,WAAW,EAAE,gDAAgD;YAC7D,MAAM,EAAE;;;;;;;;;;;;;;;;;4GAiB8F;SACvG;KACF;IAED,WAAW,EAAE;QACX,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE,yDAAyD;QACtE,IAAI,EAAE,IAAI;QACV,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE;YACL,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,oBAAoB;YACjC,WAAW,EAAE,yDAAyD;YACtE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;yBAsBW;SACpB;KACF;IAED,OAAO,EAAE;QACP,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,8BAA8B;QAC3C,IAAI,EAAE,IAAI;QACV,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE,IAAI,EAAE,gCAAgC;KAC9C;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAiB;IAC9C,OAAO,oBAAoB,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAiB;IAC/C,OAAO,oBAAoB,CAAC,IAAI,CAAC,EAAE,YAAY,IAAI,SAAS,CAAC;AAC/D,CAAC"} \ No newline at end of file +{"version":3,"file":"session-types.js","sourceRoot":"","sources":["session-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmBH,MAAM,CAAC,MAAM,oBAAoB,GAA2C;IAC1E,MAAM,EAAE;QACN,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,4DAA4D;QACzE,IAAI,EAAE,KAAK;QACX,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE;YACL,IAAI,EAAE,eAAe;YACrB,WAAW,EAAE,eAAe;YAC5B,WAAW,EAAE,4DAA4D;YACzE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;6MAmB+L;SACxM;KACF;IAED,OAAO,EAAE;QACP,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,gDAAgD;QAC7D,IAAI,EAAE,IAAI;QACV,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE;YACL,IAAI,EAAE,mBAAmB;YACzB,WAAW,EAAE,mBAAmB;YAChC,WAAW,EAAE,gDAAgD;YAC7D,MAAM,EAAE;;;;;;;;;;;;;;;;;4GAiB8F;SACvG;KACF;IAED,WAAW,EAAE;QACX,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE,yDAAyD;QACtE,IAAI,EAAE,IAAI;QACV,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE;YACL,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,oBAAoB;YACjC,WAAW,EAAE,yDAAyD;YACtE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;yBAwBW;SACpB;KACF;IAED,OAAO,EAAE;QACP,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,8BAA8B;QAC3C,IAAI,EAAE,IAAI;QACV,YAAY,EAAE,SAAS;QACvB,KAAK,EAAE,IAAI,EAAE,gCAAgC;KAC9C;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAiB;IAC9C,OAAO,oBAAoB,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAiB;IAC/C,OAAO,oBAAoB,CAAC,IAAI,CAAC,EAAE,YAAY,IAAI,SAAS,CAAC;AAC/D,CAAC"} \ No newline at end of file diff --git a/packages/shared/src/contracts/session-types.ts b/packages/shared/src/contracts/session-types.ts index a432ee9..34ac3f0 100644 --- a/packages/shared/src/contracts/session-types.ts +++ b/packages/shared/src/contracts/session-types.ts @@ -39,6 +39,8 @@ export const SESSION_TYPE_CONFIGS: Record = { - Error diagnosis, log analysis, and troubleshooting - Architecture design and scalability patterns +IMPORTANT TOOL CAPABILITY: You have a tool called "fetch_url" available. Whenever a user provides a public URL in their request, you SHOULD PROACTIVELY use the fetch_url tool to read its contents and provide a more accurate, contextual response based on the actual content of that page. Do not assume you cannot read URLs - you have a tool specifically for this purpose. + When analyzing configurations or errors: 1. Identify the issue or configuration clearly 2. Explain WHY something is problematic or recommended @@ -46,7 +48,7 @@ When analyzing configurations or errors: 4. Reference official documentation when helpful 5. Warn about security implications when relevant -Be concise but thorough. Use code blocks for configurations and commands.`, +Provide a high-quality, detailed, and explanatory response that helps the user completely understand the concepts, steps, and 'why' behind the suggestions. Use code blocks for configurations and commands.`, }, }, @@ -74,7 +76,7 @@ Guidelines: 3. Preserve formatting when rewriting 4. For translations, keep cultural nuances in mind 5. Provide alternatives when helpful -6. Be concise unless expansion is requested +6. Provide rich, detailed explanations and fully expand on ideas when discussing or explaining writing choices. When the user provides text to modify, respond with ONLY the modified text unless they ask for explanation.`, }, @@ -98,8 +100,10 @@ When the user provides text to modify, respond with ONLY the modified text unles - Documentation and code comments - Refactoring and code cleanup +IMPORTANT TOOL CAPABILITY: You have tools available to assist you. If you are in a devops session type, you have a tool called "fetch_url". Whenever a user provides a public URL in their request and you have the tool available, you SHOULD PROACTIVELY use the fetch_url tool to read its contents and provide a more accurate, contextual response. Do not assume you cannot read URLs. + Guidelines: -1. Be concise and actionable +1. Provide actionable and detailed explanatory responses that help the user completely understand the concepts, steps, and 'why' behind the suggestions. 2. Explain the "why" behind suggestions 3. Provide code examples when helpful 4. Consider edge cases and error handling diff --git a/packages/shared/src/types/message.d.ts b/packages/shared/src/types/message.d.ts index 24d60c5..ad9fa06 100644 --- a/packages/shared/src/types/message.d.ts +++ b/packages/shared/src/types/message.d.ts @@ -54,6 +54,8 @@ export interface MessageMetadata { images?: ImageAttachment[]; /** Whether context-aware mode was used */ contextAware?: boolean; + /** Stream or API error encountered during response */ + error?: string; } export type QuickAction = 'explain' | 'translate' | 'rewrite' | 'fix_grammar' | 'summarize' | 'expand' | 'analyze_config' | 'diagnose_error'; export interface ToolCall { diff --git a/packages/shared/src/types/message.d.ts.map b/packages/shared/src/types/message.d.ts.map index f2a9783..c70a2f5 100644 --- a/packages/shared/src/types/message.d.ts.map +++ b/packages/shared/src/types/message.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["message.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["message.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/shared/src/types/message.ts b/packages/shared/src/types/message.ts index abb0d9b..188a44c 100644 --- a/packages/shared/src/types/message.ts +++ b/packages/shared/src/types/message.ts @@ -66,6 +66,8 @@ export interface MessageMetadata { images?: ImageAttachment[]; /** Whether context-aware mode was used */ contextAware?: boolean; + /** Stream or API error encountered during response */ + error?: string; } export type QuickAction = diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d35d360..69f1b54 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: ^10.0.2 version: 10.1.0 '@github/copilot-sdk': - specifier: ^0.1.0 - version: 0.1.19 + specifier: ^0.1.28 + version: 0.1.28 better-sqlite3: specifier: ^11.7.0 version: 11.10.0 @@ -27,8 +27,8 @@ importers: specifier: ^0.38.4 version: 0.38.4(@types/better-sqlite3@7.6.13)(@types/react@19.2.10)(better-sqlite3@11.10.0)(react@19.2.4) fastify: - specifier: ^5.2.1 - version: 5.7.2 + specifier: ^5.7.4 + version: 5.7.4 pino: specifier: ^9.6.0 version: 9.14.0 @@ -1226,48 +1226,48 @@ packages: '@fastify/proxy-addr@5.1.0': resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} - '@github/copilot-darwin-arm64@0.0.394': - resolution: {integrity: sha512-qDmDFiFaYFW45UhxylN2JyQRLVGLCpkr5UmgbfH5e0aksf+69qytK/MwpD2Cq12KdTjyGMEorlADkSu5eftELA==} + '@github/copilot-darwin-arm64@0.0.416': + resolution: {integrity: sha512-mipNAS3Pi8Eu2TA9rTHdjEMaDZNNKJl29rL5cvs9imjshsQJBwiJD3zIV/XQvqsFB8IWngn5ZFT9ybML4milkg==} cpu: [arm64] os: [darwin] hasBin: true - '@github/copilot-darwin-x64@0.0.394': - resolution: {integrity: sha512-iN4YwSVFxhASiBjLk46f+AzRTNHCvYcmyTKBASxieMIhnDxznYmpo+haFKPCv2lCsEWU8s5LARCnXxxx8J1wKA==} + '@github/copilot-darwin-x64@0.0.416': + resolution: {integrity: sha512-22Q1rkpYflX5XMfmfvA/uZ/9ME43rUARy6rQZ+tfl2/Xg2FFR8NXyvhtatqVZ5v+N2DE81IrYUG3V0wfX0U8Iw==} cpu: [x64] os: [darwin] hasBin: true - '@github/copilot-linux-arm64@0.0.394': - resolution: {integrity: sha512-9NeGvmO2tGztuneXZfYAyW3fDk6Pdl6Ffg8MAUaevA/p0awvA+ti/Vh0ZSTcI81nDTjkzONvrcIcjYAN7x0oSg==} + '@github/copilot-linux-arm64@0.0.416': + resolution: {integrity: sha512-iLFzBpjSNQOqOvBIq4AxlSWDGlAW5+Ri0Qz2h1CVBb5JcUOdfSL22Fz/3wWzrV1quvnkVyJQ45tL9zS117DhcA==} cpu: [arm64] os: [linux] hasBin: true - '@github/copilot-linux-x64@0.0.394': - resolution: {integrity: sha512-toahsYQORrP/TPSBQ7sxj4/fJg3YUrD0ksCj/Z4y2vT6EwrE9iC2BspKgQRa4CBoCqxYDNB2blc+mQ1UuzPOxg==} + '@github/copilot-linux-x64@0.0.416': + resolution: {integrity: sha512-+dSZOLaCr+A/WJLE++4lCC13PziIO64PzFGJsEmSedQkqw2dnXrAYbsp+cbtXJJ6w0DZpHigeifhn1m3sAWUvw==} cpu: [x64] os: [linux] hasBin: true - '@github/copilot-sdk@0.1.19': - resolution: {integrity: sha512-h/KvYb6g99v9SurNJGxeXUatmP7GO8KHTAb68GYfmgUqH1EUeN5g0xMUc5lvKxAi7hwj2OxRR73dd37zMMiiiQ==} - engines: {node: '>=18.0.0'} + '@github/copilot-sdk@0.1.28': + resolution: {integrity: sha512-dJpg5IWCdwc5YLqT0VB6yGF7Alx86kJyajxwxp33Y1q0dl5ZMqOFq/Cbe2yOAhO5dv9a6eZdgpBWHjPTKONebQ==} + engines: {node: '>=20.0.0'} - '@github/copilot-win32-arm64@0.0.394': - resolution: {integrity: sha512-R7XBP3l+oeDuBrP0KD80ZBEMsZoxAW8QO2MNsDUV8eVrNJnp6KtGHoA+iCsKYKNOD6wHA/q5qm/jR+gpsz46Aw==} + '@github/copilot-win32-arm64@0.0.416': + resolution: {integrity: sha512-jeTroTL5CeAysbl3GJeLyPMsb2fEP16Iqo7faeozlbyU9BD5GjaLKtEApmFCE2hP0/CNcJVg1K5cZLTaKYOXCw==} cpu: [arm64] os: [win32] hasBin: true - '@github/copilot-win32-x64@0.0.394': - resolution: {integrity: sha512-/XYV8srP+pMXbf9Gc3wr58zCzBZvsdA3X4poSvr2uU8yCZ6E4pD0agFaZ1c/CikANJi8nb0Id3kulhEhePz/3A==} + '@github/copilot-win32-x64@0.0.416': + resolution: {integrity: sha512-62kv5dMNZ+7unVi3puK16trlOItLldFgQEkk2mVqAsRzEA9XqxArNeN+lG6kAIHNbiKA+OKVafdkzy104kHy4w==} cpu: [x64] os: [win32] hasBin: true - '@github/copilot@0.0.394': - resolution: {integrity: sha512-koSiaHvVwjgppgh+puxf6dgsR8ql/WST1scS5bjzMsJFfWk7f4xtEXla7TCQfSGoZkCmCsr2Tis27v5TpssiCg==} + '@github/copilot@0.0.416': + resolution: {integrity: sha512-rohH9dEeLRkYD31BUL7RFnGz2ZU/7CVkNdZlWEut+CSXgha6uhb3GPmIAPty1gZyUeMeHqJOwu+SSEjAxVaXEg==} hasBin: true '@humanfs/core@0.19.1': @@ -3306,8 +3306,8 @@ packages: fastify-plugin@5.1.0: resolution: {integrity: sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==} - fastify@5.7.2: - resolution: {integrity: sha512-dBJolW+hm6N/yJVf6J5E1BxOBNkuXNl405nrfeR8SpvGWG3aCC2XDHyiFBdow8Win1kj7sjawQc257JlYY6M/A==} + fastify@5.7.4: + resolution: {integrity: sha512-e6l5NsRdaEP8rdD8VR0ErJASeyaRbzXYpmkrpr2SuvuMq6Si3lvsaVy5C+7gLanEkvjpMDzBXWE5HPeb/hgTxA==} fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -6752,38 +6752,38 @@ snapshots: '@fastify/forwarded': 3.0.1 ipaddr.js: 2.3.0 - '@github/copilot-darwin-arm64@0.0.394': + '@github/copilot-darwin-arm64@0.0.416': optional: true - '@github/copilot-darwin-x64@0.0.394': + '@github/copilot-darwin-x64@0.0.416': optional: true - '@github/copilot-linux-arm64@0.0.394': + '@github/copilot-linux-arm64@0.0.416': optional: true - '@github/copilot-linux-x64@0.0.394': + '@github/copilot-linux-x64@0.0.416': optional: true - '@github/copilot-sdk@0.1.19': + '@github/copilot-sdk@0.1.28': dependencies: - '@github/copilot': 0.0.394 + '@github/copilot': 0.0.416 vscode-jsonrpc: 8.2.1 zod: 4.3.6 - '@github/copilot-win32-arm64@0.0.394': + '@github/copilot-win32-arm64@0.0.416': optional: true - '@github/copilot-win32-x64@0.0.394': + '@github/copilot-win32-x64@0.0.416': optional: true - '@github/copilot@0.0.394': + '@github/copilot@0.0.416': optionalDependencies: - '@github/copilot-darwin-arm64': 0.0.394 - '@github/copilot-darwin-x64': 0.0.394 - '@github/copilot-linux-arm64': 0.0.394 - '@github/copilot-linux-x64': 0.0.394 - '@github/copilot-win32-arm64': 0.0.394 - '@github/copilot-win32-x64': 0.0.394 + '@github/copilot-darwin-arm64': 0.0.416 + '@github/copilot-darwin-x64': 0.0.416 + '@github/copilot-linux-arm64': 0.0.416 + '@github/copilot-linux-x64': 0.0.416 + '@github/copilot-win32-arm64': 0.0.416 + '@github/copilot-win32-x64': 0.0.416 '@humanfs/core@0.19.1': {} @@ -8990,7 +8990,7 @@ snapshots: fastify-plugin@5.1.0: {} - fastify@5.7.2: + fastify@5.7.4: dependencies: '@fastify/ajv-compiler': 4.0.5 '@fastify/error': 4.2.0