Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/agents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './inquire'
export * from './query-suggestor'
export * from './researcher'
export * from './resolution-search'
export * from './planetary-prompts'
449 changes: 449 additions & 0 deletions lib/agents/planetary-prompts.ts

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion lib/agents/researcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ import { getTools } from './tools'
import { getModel } from '../utils'
import { MapProvider } from '@/lib/store/settings'
import { DrawnFeature } from './resolution-search'
import { GUIDING_PRINCIPLES } from './planetary-prompts'
import { getSelectedModel } from '@/lib/actions/users'
import { AI_REQUEST_TIMEOUT_MS, createDeadlineSignal } from '@/lib/utils/with-timeout'

// This magic tag lets us write raw multi-line strings with backticks, arrows, etc.
const raw = String.raw

const getDefaultSystemPrompt = (date: string, drawnFeatures?: DrawnFeature[], selectedModel?: string | null) => 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.
As a comprehensive AI assistant operating under GUIDING_PRINCIPLES, your primary directive is **Exploration Efficiency**. You must use the provided tools judiciously to gather information and formulate a response.

**Guiding Principles:**
${Object.entries(GUIDING_PRINCIPLES).map(([key, val]) => `- **${key}**: ${val}`).join('\n')}

**Product Context:**
- Within this application, "the computer" and "planet computer" refer to **QCX-Terra**.
Expand Down
6 changes: 5 additions & 1 deletion lib/agents/resolution-search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CoreMessage, streamObject } from 'ai'
import { getModel } from '@/lib/utils'
import { tavily } from '@tavily/core'
import { resolutionSearchSchema } from '@/lib/schema/resolution-search'
import { GUIDING_PRINCIPLES } from './planetary-prompts'
import { AI_REQUEST_TIMEOUT_MS, ENRICHMENT_TIMEOUT_MS, createDeadlineSignal, withTimeout } from '@/lib/utils/with-timeout'

// This agent is now a pure data-processing module, with no UI dependencies.
Expand Down Expand Up @@ -139,7 +140,10 @@ export async function resolutionSearch(messages: CoreMessage[], timezone: string

const drawingContext = formatDrawingContext(drawnFeatures)
const systemPrompt = `
As a geospatial analyst, your task is to analyze the provided satellite image of a geographic location.
As a geospatial analyst operating under GUIDING_PRINCIPLES, your task is to analyze the provided satellite image of a geographic location.

**Guiding Principles:**
${Object.entries(GUIDING_PRINCIPLES).map(([key, val]) => `- **${key}**: ${val}`).join('\n')}

**Temporal Context:**
The current local time at this location is ${localTime} (timezone: ${timezone}).
Expand Down
6 changes: 5 additions & 1 deletion lib/agents/task-manager.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CoreMessage, generateObject, LanguageModel } from 'ai'
import { nextActionSchema } from '../schema/next-action'
import { getModel } from '../utils'
import { GUIDING_PRINCIPLES } from './planetary-prompts'

// Decide whether inquiry is required for the user input
export async function taskManager(messages: CoreMessage[]) {
Expand All @@ -17,7 +18,10 @@ export async function taskManager(messages: CoreMessage[]) {

const result = await generateObject({
model: (await getModel()) as LanguageModel,
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).
system: `As a planet computer operating under GUIDING_PRINCIPLES, 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).

**Guiding Principles:**
${Object.entries(GUIDING_PRINCIPLES).map(([key, val]) => `- **${key}**: ${val}`).join('\n')}

You must first analyze the user's input and determine the optimal course of action. You have two options at your disposal:

Expand Down
127 changes: 127 additions & 0 deletions tests-unit/planetary-prompts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { describe, test, expect } from 'bun:test';
import {
GUIDING_PRINCIPLES,
PLANETARY_COPILOT_CORE_IDENTITY,
ENVIRONMENTAL_INTELLIGENCE_AGENT,
NAVIGATION_EXPLORATION_AGENT,
AUTOMATION_TASK_MANAGEMENT_AGENT,
DYNAMIC_CONTEXT_ENHANCER,
LEARNING_ENHANCEMENT,
REQUIREMENT_ADAPTATION_PROTOCOL,
VARIABLE_UPDATE_PROTOCOL,
PROMPT_VALIDATION_CHECKLIST,
ENVIRONMENTAL_ADAPTATIONS,
assembleAgentPrompt,
validatePrompt,
interpolateVariables
} from '../lib/agents/planetary-prompts';

describe('Planetary Prompts & Agent System', () => {
test('GUIDING_PRINCIPLES are correctly defined', () => {
expect(GUIDING_PRINCIPLES.commitment_to_accuracy).toBeDefined();
expect(GUIDING_PRINCIPLES.data_driven_operations).toBeDefined();
expect(GUIDING_PRINCIPLES.transparency_in_uncertainty).toBeDefined();
expect(GUIDING_PRINCIPLES.avoidance_of_speculation).toBeDefined();
expect(GUIDING_PRINCIPLES.continuous_verification).toBeDefined();
});

test('PLANETARY_COPILOT_CORE_IDENTITY contains valid role and capabilities', () => {
expect(PLANETARY_COPILOT_CORE_IDENTITY.role).toContain('planetary exploration');
expect(PLANETARY_COPILOT_CORE_IDENTITY.core_capabilities.length).toBeGreaterThanOrEqual(6);
});

test('Environmental Intelligence Agent prompt structure is correct', () => {
expect(ENVIRONMENTAL_INTELLIGENCE_AGENT.staticCorePrompt).toContain('Environmental Intelligence module');
expect(ENVIRONMENTAL_INTELLIGENCE_AGENT.environmentalContext.current_location).toBe('{GPS_COORDINATES_Verified}');
expect(ENVIRONMENTAL_INTELLIGENCE_AGENT.adaptiveParameters.sensitivity_level).toBeDefined();
});

test('Navigation & Exploration Agent prompt structure is correct', () => {
expect(NAVIGATION_EXPLORATION_AGENT.staticCorePrompt).toContain('Navigation and Exploration module');
expect(NAVIGATION_EXPLORATION_AGENT.navigationContext.current_position).toBe('{REAL_TIME_COORDINATES_VerifiedPrimaryNav}');
expect(NAVIGATION_EXPLORATION_AGENT.explorationParameters.exploration_radius).toBeDefined();
});

test('Automation & Task Management Agent prompt structure is correct', () => {
expect(AUTOMATION_TASK_MANAGEMENT_AGENT.staticCorePrompt).toContain('Automation and Task Management module');
expect(AUTOMATION_TASK_MANAGEMENT_AGENT.automationContext.available_resources).toBe('{RESOURCE_INVENTORY_VerifiedTimestamped}');
expect(AUTOMATION_TASK_MANAGEMENT_AGENT.taskParameters.automation_level).toBeDefined();
});

test('Enhancement templates and Protocols exist', () => {
expect(DYNAMIC_CONTEXT_ENHANCER.geographical_context).toContain('Current geographical context');
expect(LEARNING_ENHANCEMENT.experience_integration).toContain('Reflecting on previous exploration outcomes');
expect(REQUIREMENT_ADAPTATION_PROTOCOL.capability_scaling.trigger_conditions).toContain('hardware_upgrade');
expect(VARIABLE_UPDATE_PROTOCOL.real_time_updates).toContain('{GPS_COORDINATES_Verified}');
expect(ENVIRONMENTAL_ADAPTATIONS.weather_response.severe_weather_imminent_or_occurring).toContain('Response:');
});

test('interpolateVariables correctly replaces placeholders and handles literal replacement tokens', () => {
const template = 'Location: {GPS_COORDINATES_Verified}, Code: {TOKEN}';
const variables = {
GPS_COORDINATES_Verified: '37.7749, -122.4194',
TOKEN: 'Cost: $& and $1'
};
const result = interpolateVariables(template, variables);
expect(result).toBe('Location: 37.7749, -122.4194, Code: Cost: $& and $1');
});

test('assembleAgentPrompt handles special characters like quotes safely in JSON context', () => {
const prompt = assembleAgentPrompt({
agentType: 'environmental_intelligence',
dynamicContext: {
GPS_COORDINATES_Verified: '12" N, 77" E'
}
});

// Extract DYNAMIC CONTEXT block and verify it parses as valid JSON
const jsonMatch = prompt.match(/DYNAMIC CONTEXT:\n(\{[\s\S]*?\})\n\nPARAMETERS:/);
expect(jsonMatch).not.toBeNull();
if (jsonMatch) {
const parsed = JSON.parse(jsonMatch[1]);
expect(parsed.current_location).toBe('12" N, 77" E');
}
});

test('assembleAgentPrompt generates valid operational prompt for Environmental Intelligence Agent', () => {
const prompt = assembleAgentPrompt({
agentType: 'environmental_intelligence',
dynamicContext: {
GPS_COORDINATES_Verified: '12.9716° N, 77.5946° E',
TIMESTAMP_UTC_Synchronized: '2026-09-05T10:00:00Z'
},
environmentalAdaptation: ENVIRONMENTAL_ADAPTATIONS.weather_response.severe_weather_imminent_or_occurring,
customDirectives: ['Prioritize thermal infrared sensors.']
});

expect(prompt).toContain('GUIDING_PRINCIPLES:');
expect(prompt).toContain('Environmental Intelligence module');
expect(prompt).toContain('12.9716° N, 77.5946° E');
expect(prompt).toContain('ENVIRONMENTAL ADAPTATION DIRECTIVE:');
expect(prompt).toContain('Prioritize thermal infrared sensors.');
expect(prompt).toContain('OPERATIONAL REQUIREMENT:');
});

test('assembleAgentPrompt generates valid operational prompt for Navigation & Exploration Agent', () => {
const prompt = assembleAgentPrompt({
agentType: 'navigation_exploration',
dynamicContext: {
REAL_TIME_COORDINATES_VerifiedPrimaryNav: '45.5152° N, 122.6784° W'
}
});

expect(prompt).toContain('Navigation and Exploration module');
expect(prompt).toContain('45.5152° N, 122.6784° W');
});

test('validatePrompt scores and checks compliance', () => {
const samplePrompt = assembleAgentPrompt({
agentType: 'environmental_intelligence'
});

const validation = validatePrompt(samplePrompt);
expect(validation.isValid).toBe(true);
expect(validation.score).toBeGreaterThanOrEqual(70);
expect(validation.checkedRules.length).toBe(PROMPT_VALIDATION_CHECKLIST.length);
});
});
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
],
"exclude": [
"node_modules",
"edge_function"
"edge_function",
"tests-unit"
]
}