diff --git a/packages/altair-api/src/ai/ai.service.ts b/packages/altair-api/src/ai/ai.service.ts index 5f18db60f5..32bcffea49 100644 --- a/packages/altair-api/src/ai/ai.service.ts +++ b/packages/altair-api/src/ai/ai.service.ts @@ -16,6 +16,7 @@ import { maxGraphqlVariablesChars, maxMessageChars, maxSdlChars, + responseMaxTokens, } from 'altair-graphql-core/build/cjs/ai/constants'; import { ConfigService } from '@nestjs/config'; import { Config } from 'src/common/config'; @@ -220,54 +221,48 @@ export class AiService { // https://platform.openai.com/docs/guides/prompt-engineering const systemMessageParts = [ - 'I want you to act as a friendly and helpful expert of GraphQL and Altair GraphQL Client (https://altairgraphql.dev).', - 'Only answer questions related to GraphQL and Altair GraphQL Client.', - 'Be concise and clear in your responses.', - 'Write your responses in markdown format.', - 'Always wrap GraphQL queries in ```graphql``` code blocks.', - ]; - // Use additional message context to enhance the system message - if (messageInput.sdl) { - systemMessageParts.push(dedent` - Here is the SDL (schema) provided by the user: + dedent`You are an expert in GraphQL and Altair GraphQL Client (https://altairgraphql.dev). Your task is to answer user questions related to these topics professionally and concisely. Follow these instructions carefully:`, + dedent`1. First, review the provided SDL (Schema Definition Language): - ${messageInput.sdl} - - `); - } - if (messageInput.graphqlQuery) { - systemMessageParts.push(dedent` - Here is the GraphQL query provided by the user: - - ${messageInput.graphqlQuery} - - `); - } - if (messageInput.graphqlVariables) { - systemMessageParts.push(dedent` - Here are the GraphQL variables (in JSON) provided by the user: - - ${messageInput.graphqlVariables} - - `); - } + ${messageInput.sdl ?? ''} + `, + dedent`2. Next, examine the GraphQL query: + + ${messageInput.graphqlQuery ?? ''} + `, + dedent`3. Then, look at the GraphQL variables (in JSON format): + + ${messageInput.graphqlVariables ?? ''} + `, + dedent`4. When answering the user's question, follow these guidelines: + - Only answer questions related to GraphQL and Altair GraphQL Client. + - Focus solely on the topic the user is asking about. + - Provide enough information to guide the user in the right direction, but not necessarily a complete solution. + - Be respectful and professional in your responses. + - Keep your responses concise and clear, using no more than 3-4 sentences. + - Provide a maximum of 2 code snippets in your response, if necessary. + - Write your responses in markdown format. + - Always wrap GraphQL queries in \`\`\`graphql\`\`\` code blocks. + - If a sdl schema is provided, only generate GraphQL queries that are valid for the provided schema.`, + dedent`5. If you're unsure about something or need clarification, ask the user for more information.`, + dedent`6. If you're unable to answer a question, respond with: "I'm not sure about that, but I can try to help you with something else."`, + dedent`Now, please answer the following user question:`, + ]; const promptTemplate = ChatPromptTemplate.fromMessages([ - new SystemMessage(systemMessageParts.join('\n')), + new SystemMessage(systemMessageParts.join('\n\n')), ...previousMessages.map((m) => { if (m.role === AiChatRole.USER) { return new HumanMessage(m.message); } return new AIMessage(m.message); }), - new HumanMessage('{text}'), + new HumanMessage(`${messageInput.message}`), ]); const chain = promptTemplate.pipe(model); // Pass variables to invoke (variables are wrapped in curly braces) - const response = await chain.invoke({ - text: messageInput.message, - }); + const response = await chain.invoke({}); const parser = new StringOutputParser(); const out = await parser.invoke(response); return { @@ -290,6 +285,7 @@ export class AiService { return new ChatOpenAI({ apiKey: this.configService.get('ai.openai.apiKey', { infer: true }), model: this.configService.get('ai.openai.model', { infer: true }), + maxTokens: responseMaxTokens, }); } case 'ollama': { @@ -314,6 +310,7 @@ export class AiService { return new ChatAnthropic({ apiKey: this.configService.get('ai.anthropic.apiKey', { infer: true }), model: this.configService.get('ai.anthropic.model', { infer: true }), + maxTokens: responseMaxTokens, }); } } diff --git a/packages/altair-api/src/logging/logging.interceptor.ts b/packages/altair-api/src/logging/logging.interceptor.ts index e8e655969b..df0364da66 100644 --- a/packages/altair-api/src/logging/logging.interceptor.ts +++ b/packages/altair-api/src/logging/logging.interceptor.ts @@ -31,7 +31,7 @@ export class LoggingInterceptor implements NestInterceptor { const now = Date.now(); return next.handle().pipe( tap((x) => { - tags.duration = Date.now() - now; + tags.duration = `${Date.now() - now}ms`; this.logger.log(`POST: ${tagsToString(tags)}`); }) ); diff --git a/packages/altair-core/src/ai/constants.ts b/packages/altair-core/src/ai/constants.ts index a1f081afb7..fb0e0ac4d3 100644 --- a/packages/altair-core/src/ai/constants.ts +++ b/packages/altair-core/src/ai/constants.ts @@ -16,3 +16,5 @@ export const maxGraphqlQueryChars = maxGraphqlQueryTokens * avgCharsPerToken; export const maxGraphqlVariablesTokens = 150; export const maxGraphqlVariablesChars = maxGraphqlVariablesTokens * avgCharsPerToken; + +export const responseMaxTokens = 1000; diff --git a/packages/altair-core/src/plugin/v3/parent-worker.ts b/packages/altair-core/src/plugin/v3/parent-worker.ts index 4b458a1662..979ef6ad52 100644 --- a/packages/altair-core/src/plugin/v3/parent-worker.ts +++ b/packages/altair-core/src/plugin/v3/parent-worker.ts @@ -45,6 +45,7 @@ export class PluginParentWorker extends EvaluatorWorker { iframe.style.width = '100%'; iframe.style.height = '100%'; iframe.style.border = 'none'; + iframe.style.display = 'block'; // fixes issue with vertical scrollbar appearing https://stackoverflow.com/a/9131632/3929126 if ('width' in this.opts && this.opts.width) { iframe.style.minWidth = `${this.opts.width}px`; } diff --git a/packages/altair-core/src/utils/logger.ts b/packages/altair-core/src/utils/logger.ts index c291c816e7..593c15bb1b 100644 --- a/packages/altair-core/src/utils/logger.ts +++ b/packages/altair-core/src/utils/logger.ts @@ -16,6 +16,8 @@ export const createLogger = (environment: { }): ILogger => { if (!environment.production) { loglevel.setLevel('TRACE'); + } else { + loglevel.setLevel('ERROR'); } const PREVIOUS_VERSION_KEY = 'altair__debug_previous_version'; @@ -45,6 +47,8 @@ export const createLogger = (environment: { console.log('Current version:', currentVersion()); console.groupEnd(); loglevel.setLevel('TRACE'); + } else { + loglevel.setLevel('ERROR'); } (window as any)._ALTAIR__ENABLE_DEBUG_MODE__ = value; }, diff --git a/plugins/ai/src/panel.tsx b/plugins/ai/src/panel.tsx index d42bd393fc..4e346f83c0 100644 --- a/plugins/ai/src/panel.tsx +++ b/plugins/ai/src/panel.tsx @@ -43,8 +43,11 @@ const Panel = ({ context }: PanelProps) => { }); const { data: messages, isLoading: messagesIsLoading } = useQuery({ - queryKey: ['sessionMessages'], - queryFn: () => activeSession && context.getAiSessionMessages(activeSession.id), + queryKey: ['sessionMessages', activeSession?.id], + queryFn: () => + activeSession + ? context.getAiSessionMessages(activeSession.id) + : Promise.resolve([]), enabled: !!activeSession?.id, }); @@ -52,9 +55,9 @@ const Panel = ({ context }: PanelProps) => { { mutationKey: ['createAiSession'], mutationFn: () => context.createAiSession(), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['activeSession'] }); - queryClient.invalidateQueries({ queryKey: ['sessionMessages'] }); + onSettled: async () => { + await queryClient.invalidateQueries({ queryKey: ['activeSession'] }); + await queryClient.invalidateQueries({ queryKey: ['sessionMessages'] }); }, } ); @@ -99,14 +102,15 @@ const Panel = ({ context }: PanelProps) => { 'sessionMessages', ]); + const sessionId = activeSession?.id ?? ''; const fakeMessage: IMessage = { id: Math.random().toString(), message: message, role: 'USER', - sessionId: activeSession?.id ?? '', + sessionId, }; // Optimistically update to the new value - queryClient.setQueryData(['sessionMessages'], (old) => [ + queryClient.setQueryData(['sessionMessages', sessionId], (old) => [ ...(old ?? []), fakeMessage, ]); diff --git a/test-server/src/schema/GOTBook.ts b/test-server/src/schema/GOTBook.ts index 1d9ace50f3..c7165d4e82 100644 --- a/test-server/src/schema/GOTBook.ts +++ b/test-server/src/schema/GOTBook.ts @@ -1,4 +1,4 @@ -import axios from "axios"; +import axios from 'axios'; export const typeDef = `#graphql extend type Query {