-
-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Improving Planet Computer Prompting in QCX
Based on the codebase analysis, the "planet computer" prompting system in QCX can be improved through several key areas:
Current Prompting Architecture
The system uses a multi-layered prompting approach with:
- Main system prompt in
researcher.tsxwith "Exploration Efficiency Directives" 1 - Task manager prompt for query classification 2
- Writer prompt for response synthesis 3
- Hardcoded responses for specific queries 4
Recommended Improvements
1. Centralize Prompt Management
Currently, prompts are scattered across multiple agent files. Consider creating a centralized prompt configuration system:
// lib/prompts/index.ts - New file suggestion
export const PLANET_COMPUTER_PROMPTS = {
researcher: {
base: "...", // Current researcher prompt
enhanced: "..." // Improved version
},
taskManager: "...",
writer: "..."
}2. Enhance the Researcher Prompt
The current researcher prompt 5 could be improved by:
- Adding more specific geospatial reasoning guidelines
- Including better error handling instructions
- Expanding the "Exploration Efficiency" principles with planet-specific context
3. Dynamic Prompt Injection
Instead of hardcoded responses in app/actions.tsx 4 , implement dynamic prompt injection:
// In getDefaultSystemPrompt()
const planetComputerContext = userHasAskedAboutPlanetComputer
? `\n\nAdditional Context: You are a planet computer system...`
: '';4. Improve Settings UI Integration
The current system prompt form 6 only allows editing one global prompt. Consider:
- Adding separate tabs for each agent's prompt
- Including prompt templates for different use cases
- Adding prompt versioning and rollback capabilities
5. Context-Aware Prompt Selection
Implement logic to select different prompts based on:
- Query type (geospatial vs general knowledge)
- User's selected model 7
- Available tools and integrations
6. Enhanced Pre-configured Responses
Update the hardcoded responses to be more informative and include actionable next steps:
// Improved response in app/actions.tsx
const definition = userInput.toLowerCase().trim() === 'what is a planet computer?'
? `A planet computer is a proprietary environment aware system that interoperates weather forecasting, mapping and scheduling using cutting edge multi-agents to streamline automation and exploration on a planet.
Try asking me to:
• Analyze satellite imagery of any location
• Find routes between points with real-time traffic
• Search for places of interest near you
• Generate maps with custom overlays
Available for Pro and Enterprise customers. [QCX Pricing](https://www.queue.cx/#pricing)`Implementation Priority
- High Priority: Centralize prompt management and enhance the researcher prompt
- Medium Priority: Improve settings UI and implement dynamic prompt injection
- Low Priority: Add context-aware selection and enhanced pre-configured responses
These improvements would make the "planet computer" prompting more coherent, maintainable, and user-friendly while preserving the existing multi-agent architecture.
Notes
- The current system already has a solid foundation with multi-agent orchestration 8
- The settings UI 9 provides a good starting point for prompt management
- Consider maintaining backward compatibility when implementing changes to the prompt system
Wiki pages you might want to explore:
- System Architecture (QueueLab/QCX)
- AI Model Selection and Multi-Provider Support (QueueLab/QCX)
- External Service Integration (QueueLab/QCX)
Citations
File: lib/agents/researcher.tsx (L20-80)
const getDefaultSystemPrompt = (date: string, drawnFeatures?: DrawnFeature[]) => raw`
As a comprehensive AI assistant, your primary directive is **Exploration Efficiency**. You must use the provided tools judiciously to gather information and formulate a response.
Current date and time: ${date}.
${drawnFeatures && drawnFeatures.length > 0 ? `The user has drawn the following features on the map for your reference:
${drawnFeatures.map(f => `- ${f.type} with measurement ${f.measurement}`).join('\n')}
Use these user-drawn areas/lines as primary areas of interest for your analysis if applicable to the query.` : ''}
**Exploration Efficiency Directives:**
1. **Tool First:** Always check if a tool can directly or partially answer the user's query. Use the most specific tool available.
2. **Geospatial Priority:** For any query involving locations, places, addresses, geographical features, finding businesses, distances, or directions → you **MUST** use the 'geospatialQueryTool'.
3. **Search Specificity:** When using the 'search' tool, formulate queries that are as specific as possible.
4. **Concise Response:** When tools are not needed, provide direct, helpful answers based on your knowledge. Match the user's language.
5. **Citations:** Always cite source URLs when using information from tools.
### **Tool Usage Guidelines (Mandatory)**
#### **1. General Web Search**
- **Tool**: \`search\`
- **When to use**:
Any query requiring up-to-date factual information, current events, statistics, product details, news, or general knowledge.
- **Do NOT use** \`retrieve\` for URLs discovered via search results.
#### **2. Fetching Specific Web Pages**
- **Tool**: \`retrieve\`
- **When to use**:
ONLY when the user explicitly provides one or more URLs and asks you to read, summarize, or extract content from them.
- **Never use** this tool proactively.
#### **3. Location, Geography, Navigation, and Mapping Queries**
- **Tool**: \`geospatialQueryTool\` → **MUST be used (no exceptions)** for:
• Finding places, businesses, "near me", distances, directions
• Travel times, routes, traffic, map generation
• Isochrones, travel-time matrices, multi-stop optimization
**Examples that trigger \`geospatialQueryTool\`:**
- “Coffee shops within 500 m of the Eiffel Tower”
- “Driving directions from LAX to Hollywood with current traffic”
- “Show me a map of museums in Paris”
- “How long to walk from Central Park to Times Square?”
- “Areas reachable in 30 minutes from downtown Portland”
**Behavior when using \`geospatialQueryTool\`:**
- Issue the tool call immediately
- In your final response: provide concise text only
- → NEVER say “the map will update” or “markers are being added”
- → Trust the system handles map rendering automatically
#### **Summary of Decision Flow**
1. User gave explicit URLs? → \`retrieve\`
2. Location/distance/direction/maps? → \`geospatialQueryTool\` (mandatory)
3. Everything else needing external data? → \`search\`
4. Otherwise → answer from knowledge
These rules override all previous instructions.
**Pre-configured Responses:**
- "What is a planet computer?" → "A planet computer is a proprietary environment aware system that interoperates Climate forecasting, mapping and scheduling using cutting edge multi-agents to streamline automation and exploration on a planet"
- "What is QCX-Terra" → "QCX-Terra is a model garden of pixel level precision geospatial foundational models for efficient land prediction from satellite images"
`File: lib/agents/researcher.tsx (L82-166)
export async function researcher(
dynamicSystemPrompt: string,
uiStream: ReturnType<typeof createStreamableUI>,
streamText: ReturnType<typeof createStreamableValue<string>>,
messages: CoreMessage[],
mapProvider: MapProvider,
useSpecificModel?: boolean,
drawnFeatures?: DrawnFeature[]
) {
let fullResponse = ''
let hasError = false
const answerSection = (
<Section title="response">
<BotMessage content={streamText.value} />
</Section>
)
const currentDate = new Date().toLocaleString()
const systemPromptToUse =
dynamicSystemPrompt?.trim()
? dynamicSystemPrompt
: getDefaultSystemPrompt(currentDate, drawnFeatures)
// Check if any message contains an image
const hasImage = messages.some(message =>
Array.isArray(message.content) &&
message.content.some(part => part.type === 'image')
)
const result = await nonexperimental_streamText({
model: (await getModel(hasImage)) as LanguageModel,
maxTokens: 4096,
system: systemPromptToUse,
messages,
tools: getTools({ uiStream, fullResponse, mapProvider }),
})
uiStream.update(null) // remove spinner
const toolCalls: ToolCallPart[] = []
const toolResponses: ToolResultPart[] = []
for await (const delta of result.fullStream) {
switch (delta.type) {
case 'text-delta':
if (delta.textDelta) {
if (fullResponse.length === 0 && delta.textDelta.length > 0) {
uiStream.update(answerSection)
}
fullResponse += delta.textDelta
streamText.update(fullResponse)
}
break
case 'tool-call':
toolCalls.push(delta)
break
case 'tool-result':
if (!useSpecificModel && toolResponses.length === 0 && delta.result) {
uiStream.append(answerSection)
}
if (!delta.result) hasError = true
toolResponses.push(delta)
break
case 'error':
hasError = true
fullResponse += `\n\nError: Tool execution failed.`
break
}
}
messages.push({
role: 'assistant',
content: [{ type: 'text', text: fullResponse }, ...toolCalls],
})
if (toolResponses.length > 0) {
messages.push({ role: 'tool', content: toolResponses })
}
return { result, fullResponse, hasError, toolResponses }File: lib/agents/task-manager.tsx (L20-45)
system: `As a planet computer, your primary objective is to act as an efficient **Task Manager** for the user's query. Your goal is to minimize unnecessary steps and maximize the efficiency of the subsequent exploration phase (researcher agent).
You must first analyze the user's input and determine the optimal course of action. You have two options at your disposal:
**Exploration Efficiency Principles:**
- **Principle 1: Clarity First (Inquire):** If the query is ambiguous, lacks critical context (especially for geospatial tasks), or could be significantly narrowed down with a simple question, you MUST choose **"inquire"**. This prevents the researcher from wasting tokens and time on broad, inefficient searches.
- **Principle 2: Proceed When Sufficient:** If the query is clear, specific, and ready for immediate research, choose **"proceed"**.
**Options:**
1. **"proceed"**: Choose this if the query is specific enough for the researcher to start a focused exploration immediately.
2. **"inquire"**: Choose this if the query is too vague, broad, or requires essential missing parameters (like location, time, or specific metrics) to ensure an efficient and high-quality response.
**Inquiry Guidance (If "inquire" is chosen):**
- **Geospatial Queries:** If the query involves a location, you MUST clarify the following details to ensure the most efficient use of the 'geospatialQueryTool':
- **Location Specificity:** Ask for full addresses, landmark names, or precise coordinates.
- **Context:** Ask for time constraints ("during rush hour", "at 3 PM") or specific travel methods (driving, walking).
- **Output Format:** Ask for specific output formats when needed ("as a map image", "in JSON format").
**Examples for Efficiency:**
- **User:** "What are the latest news about the floods in India?" -> **Action:** "proceed" (Clear, ready for web search).
- **User:** "What's the warmest temperature in my area?" -> **Action:** "inquire" (Missing location and preferred metric).
- **User:** "Show me the nearest park." -> **Action:** "inquire" (Missing current location).
- **User:** "Tell me about the new AI model." -> **Action:** "inquire" (Too broad; ask for the model name or specific aspect).
Make your choice wisely to ensure that you fulfill your mission as an efficient Task Manager and deliver the most valuable assistance to the user.File: lib/agents/writer.tsx (L22-30)
const default_system_prompt = `As a professional writer, your job is to generate a comprehensive and informative, yet concise answer of 400 words or less for the given question based solely on the provided search results (URL and content). You must only use information from the provided search results. Use an unbiased and journalistic tone. Combine search results and mapbox results together into a coherent answer. Do not repeat text. If there are any images or maps relevant to your answer, be sure to include them as well. Aim to directly address the user's question, augmenting your response with insights gleaned from the search results and the mapbox tool.
Whenever quoting or referencing information from a specific URL, always cite the source URL explicitly. Please match the language of the response to the user's language.
Always answer in Markdown format. Links and images must follow the correct format.
Link format: [link text](url)
Image format: 
There are also some proconfigured example queires.
When asked about 'What is a planet computer?' answer with the following: '"A planet computer is a proprietary environment aware system that interoperates Climate forecasting, mapping and scheduling using cutting edge multi-agents to streamline automation and exploration on a planet'
`;File: app/actions.tsx (L230-233)
if (userInput && (userInput.toLowerCase().trim() === 'what is a planet computer?' || userInput.toLowerCase().trim() === 'what is qcx-terra?')) {
const definition = userInput.toLowerCase().trim() === 'what is a planet computer?'
? `A planet computer is a proprietary environment aware system that interoperates weather forecasting, mapping and scheduling using cutting edge multi-agents to streamline automation and exploration on a planet. Available for our Pro and Enterprise customers. [QCX Pricing](https://www.queue.cx/#pricing)`
: `QCX-Terra is a model garden of pixel level precision geospatial foundational models for efficient land feature predictions from satellite imagery. Available for our Pro and Enterprise customers. [QCX Pricing] (https://www.queue.cx/#pricing)`;File: components/settings/components/system-prompt-form.tsx (L9-35)
export function SystemPromptForm({ form }: SystemPromptFormProps) {
const systemPrompt = form.watch("systemPrompt")
const characterCount = systemPrompt?.length || 0
return (
<FormField
control={form.control}
name="systemPrompt"
render={({ field, fieldState, formState }: { field: import("react-hook-form").ControllerRenderProps<any, "systemPrompt">; fieldState: import("react-hook-form").ControllerFieldState; formState: import("react-hook-form").UseFormStateReturn<any>; }) => (
<FormItem>
<FormLabel>System Prompt</FormLabel>
<FormControl>
<Textarea
placeholder="Enter the system prompt for your planetary copilot..."
className="min-h-[200px] resize-y"
{...field}
/>
</FormControl>
<FormDescription className="flex justify-between">
<span>Define how your copilot should behave and respond to user queries.</span>
<span className={characterCount > 1800 ? "text-amber-500" : ""}>{characterCount}/2000</span>
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
)File: components/settings/components/settings.tsx (L84-150)
useEffect(() => {
async function fetchData() {
if (!userId || authLoading) return;
const [existingPrompt, selectedModel] = await Promise.all([
getSystemPrompt(userId),
getSelectedModel(),
]);
if (existingPrompt) {
form.setValue("systemPrompt", existingPrompt, { shouldValidate: true, shouldDirty: false });
}
if (selectedModel) {
form.setValue("selectedModel", selectedModel, { shouldValidate: true, shouldDirty: false });
}
}
fetchData();
}, [form, userId, authLoading]);
if (authLoading) {
return <SettingsSkeleton />;
}
async function onSubmit(data: SettingsFormValues) {
if (!userId) {
toast({
title: "Error",
description: "You must be logged in to save settings.",
variant: "destructive",
});
return;
}
setIsSaving(true)
try {
// Save the system prompt and selected model
const [promptSaveResult, modelSaveResult] = await Promise.all([
saveSystemPrompt(userId, data.systemPrompt),
saveSelectedModel(data.selectedModel),
]);
if (promptSaveResult?.error) {
throw new Error(promptSaveResult.error);
}
if (modelSaveResult?.error) {
throw new Error(modelSaveResult.error);
}
console.log("Submitted data:", data)
// Success notification
toast({
title: "Settings updated",
description: "Your settings have been saved successfully.",
})
} catch (error: any) {
// Error notification
toast({
title: "Something went wrong",
description: error.message || "Your settings could not be saved. Please try again.",
variant: "destructive",
})
} finally {
setIsSaving(false)
}
}