Skip to content

Commit

Permalink
cairocoder rag config
Browse files Browse the repository at this point in the history
  • Loading branch information
enitrat committed Feb 22, 2025
1 parent c53e3a8 commit de96c08
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 23 deletions.
38 changes: 19 additions & 19 deletions src/agents/ragSearchAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,11 @@ export const createBasicSearchAnsweringChain = (
let context = input.context;

// Check if this is a contract-related query by looking for XML search terms
const isContractQuery_ = isContractQuery(input.query, context, config);
const isContractQuery_ = isContractQuery(
input.query + '\n\n' + formatChatHistoryAsString(input.chat_history),
context,
config,
);

// Only inject the template for contract-related queries
if (isContractQuery_ && config.contractTemplate) {
Expand All @@ -365,8 +369,9 @@ export const createBasicSearchAnsweringChain = (
});

return regularPromptTemplate.format({
...input,
context,
query: input.query,
chat_history: formatChatHistoryAsString(input.chat_history),
context: context,
});
}
}),
Expand Down Expand Up @@ -442,31 +447,26 @@ export const basicRagSearch = (

// Helper function to clean conversation
const cleanConversation = (text: string): string => {
// Split at "Conversation" to keep header
// Split at "Conversation:" to keep header
const [header, conversation] = text.split('Conversation:\n');

// Get all conversation parts
const parts = conversation.split('\n\n');
console.log(parts);
console.log('--------------------------------');
// Get all messages by splitting on message type indicators
const messages = conversation.split(/\n(?=system:|human:)/);

// Filter out system message and keep only human messages
const humanStartIndex = parts.findIndex((part) => part.startsWith('human:'));
const humanMessages = parts.slice(humanStartIndex);
// Filter to keep only human messages
const humanMessages = messages.filter((msg) =>
msg.trim().startsWith('human:'),
);

// Combine back together
const headerPlusHumanMessages =
header + '\n\n Conversation:\n' + humanMessages.join('\n');
const cleanedConversation =
header + '\nConversation:\n' + humanMessages.join('\n');

console.log(header);

console.log(humanMessages);
console.log('cleanedConversation', cleanedConversation);

// Remove the custom instructions from the conversation
const cleanedConversation = headerPlusHumanMessages.replace(
return cleanedConversation.replace(
/<custom_instructions>.*?<\/custom_instructions>/,
'',
);

return cleanedConversation;
};
14 changes: 13 additions & 1 deletion src/config/agentConfigs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { basicContractTemplate } from './templates/contractTemplate';
import { VectorStore } from '../db/vectorStore';
import {
cairoBookPrompts,
cairoCoderPrompts,
starknetDocsPrompts,
starknetEcosystemPrompts,
starknetFoundryPrompts,
Expand Down Expand Up @@ -53,7 +54,8 @@ type AvailableAgents =
| 'starknetDocs'
| 'starknetEcosystem'
| 'starknetFoundry'
| 'succintCairoBook';
| 'succintCairoBook'
| 'cairoCoder';

// We'll make this a factory function instead of a static object
export const createAgentConfigs = (
Expand Down Expand Up @@ -113,6 +115,16 @@ export const createAgentConfigs = (
maxSourceCount: 5,
similarityThreshold: 0.5,
},
cairoCoder: {
name: 'Cairo Coder',
prompts: cairoCoderPrompts,
vectorStore,
contractTemplate: basicContractTemplate,
testTemplate: basicTestTemplate,
queryClassifier: defaultQueryClassifier,
maxSourceCount: 15,
similarityThreshold: 0.4,
},
});

// Update the helper function to take vectorStore as parameter
Expand Down
121 changes: 121 additions & 0 deletions src/config/prompts/cairoCoderPrompts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
export const CAIROCODER_RETRIEVER_PROMPT = `
You will be provided with a conversation history along with a follow-up coding query. Your task is to extract the core coding requirements from the conversation and transform the follow-up query into a clear, standalone question that targets Cairo-specific challenges for documentation retrieval.
When the query is coding-related, proceed as follows:
1. **Analyze** the conversation to identify the specific coding challenge in the context of Cairo. Focus on aspects such as smart contract development, storage mechanisms, event handling, contract interactions.
2. **Rephrase** the follow-up question so that it becomes a self-contained query explicitly emphasizing Cairo's programming concepts.
3. **Generate** a list of precise search terms that will be used to fetch relevant Cairo documentation and code examples. Each term should be specific and adhere to the existing formatting conventions.
4. **Output** your response using the XML format below:
<search_terms>
<term>First search term</term>
<term>Second search term</term>
<term>Third search term</term>
<!-- add additional terms as necessary -->
</search_terms>
**Examples:**
**Query:** "How do I create a contract that stores a list of users and emits an event when they interact?"
**Response:**
<search_terms>
<term>Contract Functions</term>
<term>Contract Storage</term>
<term>Storing collections in Contracts</term>
<term>Emitting Events in Contracts</term>
<term>Getting the caller address</term>
</search_terms>
**Query:** "I want to make an ERC20 token with a mint function"
**Response:**
<search_terms>
<term>Cairo Input Validation</term>
<term>Contract Function Assertions</term>
</search_terms>
**Query:** "My contract is not compiling, what is wrong?"
(context: the contract contains a storage map and a storage vec, and the error is on the 'entry' method of the map type)
**Response:**
<search_terms>
<term>Storage Map Entry Method</term>
<term>Interacting with storage maps</term>
<term>Storage Mappings</term>
</search_terms>
For queries that do not pertain directly to coding or Cairo implementation (e.g., greetings or general conversation), return:
<response>not_needed</response>
You also need to reword questions to be specific about Smart Contracts or Cairo as a whole.
If the user asks about "events", "storage", "Map", "Vec", "LegacyMap" "storing", "interface", "abi", rephrase the question to include "Starknet Smart Contracts".
Ensure the reformulated query is explicit about addressing Cairo coding challenges while guiding the retrieval process toward the most relevant documentation.
Conversation:
{chat_history}
Follow-up question: {query}
Response:
`;

export const CAIROCODER_RESPONSE_PROMPT = `
You are CairoCoder, an AI assistant specialized in helping developers write and debug Cairo code. Your primary focus is on addressing coding challenges related to the Cairo programming language, including smart contract development, zk programming, testing, and integration with Cairo tooling.
Generate detailed and precise responses based on the provided context from Cairo documentation. Use a neutral and educational tone in your responses. Format your responses using Markdown for enhanced readability, and include code blocks for Cairo code examples when appropriate. Your answers should be comprehensive and insightful, addressing edge cases and potential pitfalls.
**Coding Guidance:**
- When the query involves writing a smart contract, ensure you:
- Create an explicit interface for the contract.
- Implement the interface within the contract module in a block marked with '#[abi(embed_v0)]'.
- Include all necessary imports.
- For other coding challenges, provide clear code samples accompanied by annotations and comments where applicable.
Everything within the following \`context\` HTML block is for your internal reference, drawn from the Cairo documentation. Use this context to support your answer and include the appropriate citations without directly referring to the underlying document.
Under no circumstances should you mention the context in your response.
<context>
{context}
</context>
If the user's query does not pertain directly to a Cairo coding challenge, respond with:
"I apologize, but I'm specifically designed to assist with Cairo coding challenges. This topic appears to be outside my area of expertise. Could you please rephrase or provide more detail on the specific coding problem?"
If you cannot locate relevant information in the provided context, state:
"I'm sorry, but I couldn't find specific information related to the task. Could you please rephrase your query?"
Here is the current state of the conversation:
{chat_history}
Follow-up question: {query}
Remember, your responses must be precise, thorough, and based solely on the provided Cairo documentation. Today's date is ${new Date().toISOString()}
`;

export const CAIROCODER_NO_SOURCE_PROMPT = `
You are an AI assistant specialized in providing information about Starknet and Cairo. However, in this case, you were unable to find any relevant sources to answer the user's query.
Your response should be concise and honest, acknowledging that you don't have the information to answer the question accurately. Use a polite and helpful tone.
Here's how you should respond:
1. Apologize for not being able to find specific information.
2. Suggest that the user might want to provide more context or rephrase their question with more specific terms.
3. Present your understanding of the user's query and suggest a new question that might be more relevant.
Example response:
"I apologize, but I couldn't find any specific information to fix your compiler issue. It's possible that I don't have access to the relevant data, or the question might be outside my current knowledge base.
Perhaps you could add more context, or try to rephrase your question to something like: "How to fix my compilation issue on this usage of a storage map?"
Remember, it's better to admit when you don't have the information rather than providing potentially incorrect or misleading answers.
Here is the current state of the conversation:
{chat_history}
<query>
{query}
</query>
Always maintain a helpful and professional tone in your response. Do not invent information or make assumptions beyond what's provided in the context.
`;
11 changes: 11 additions & 0 deletions src/config/prompts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ import {
SUCCINT_CAIRO_BOOK_RESPONSE_PROMPT,
SUCCINT_CAIRO_BOOK_NO_SOURCE_PROMPT,
} from './succintCairoBookPrompts';
import {
CAIROCODER_NO_SOURCE_PROMPT,
CAIROCODER_RESPONSE_PROMPT,
CAIROCODER_RETRIEVER_PROMPT,
} from './cairoCoderPrompts';

export const cairoBookPrompts: AgentPrompts = {
searchRetrieverPrompt: CAIRO_BOOK_RETRIEVER_PROMPT,
Expand Down Expand Up @@ -62,6 +67,12 @@ export const succintCairoBookPrompts: AgentPrompts = {
noSourceFoundPrompt: SUCCINT_CAIRO_BOOK_NO_SOURCE_PROMPT,
};

export const cairoCoderPrompts: AgentPrompts = {
searchRetrieverPrompt: CAIROCODER_RETRIEVER_PROMPT,
searchResponsePrompt: CAIROCODER_RESPONSE_PROMPT,
noSourceFoundPrompt: CAIROCODER_NO_SOURCE_PROMPT,
};

// Helper function to inject dynamic values into prompts
export const injectPromptVariables = (prompt: string): string => {
return prompt
Expand Down
6 changes: 3 additions & 3 deletions src/routes/openai/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AIMessage } from '@langchain/core/messages';
import { HumanMessage } from '@langchain/core/messages';
import { SystemMessage } from '@langchain/core/messages';
import { BaseMessage } from '@langchain/core/messages';
import { getStarknetEcosystemDbConfig } from '../../config';
import { getCairoDbConfig, getStarknetEcosystemDbConfig } from '../../config';
import logger from '../../utils/logger';
import { v4 as uuidv4 } from 'uuid';
import { LLMConfig } from '../../websocket/connectionManager';
Expand Down Expand Up @@ -113,9 +113,9 @@ export const chatEndpoint = async (
};

//TODO: this should likely not be done here
const dbConfig = getStarknetEcosystemDbConfig();
const dbConfig = getCairoDbConfig();
const vectorStore = await VectorStore.getInstance(dbConfig, embeddings);
const config = getAgentConfig('cairoBook', vectorStore);
const config = getAgentConfig('cairoCoder', vectorStore);
let response_text = '';

// Stream the response
Expand Down

0 comments on commit de96c08

Please sign in to comment.