Skip to content

Commit 06144e9

Browse files
feat(oracle): build gemini oracle wrappers for wgsl generation
1 parent e8068b7 commit 06144e9

2 files changed

Lines changed: 113 additions & 0 deletions

File tree

adapters/oracle/oracle_client.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { parseOracleOutput, ParsedOracleResponse } from './parser';
2+
// import { GoogleGenAI } from '@google/genai'; // Assuming this is installed
3+
4+
const SYSTEM_PROMPT = `
5+
You are the MANIFOLD Gemini Oracle.
6+
Your task is to generate valid WGSL shader code for a compute pass in a voxel/cellular automata simulation.
7+
8+
### The 6-Channel Material Tensor
9+
The terrain is defined by a 6-channel state tensor (Float32):
10+
- \`density\`: Physical mass.
11+
- \`cohesion\`: Structural integrity (rock=high, sand=low).
12+
- \`permeability\`: Ability for fluids to pass through.
13+
- \`water\`: Mobile fluid mass.
14+
- \`sediment\`: Mobile solid mass.
15+
- \`oxidation\`: Chemical state (age).
16+
17+
### Rules
18+
1. You must output exactly one \`\`\`wgsl block containing the shader.
19+
2. If you mutate \`water\` or \`sand\` using flux mechanics, you must mark \`flux_producer: true\`.
20+
3. You must output exactly one \`\`\`yaml block listing the channels you read from and write to.
21+
22+
Example YAML:
23+
\`\`\`yaml
24+
reads: [water, permeability]
25+
writes: [water, sand]
26+
flux_producer: true
27+
\`\`\`
28+
`;
29+
30+
export class GeminiOracle {
31+
// private ai: GoogleGenAI;
32+
33+
constructor(apiKey: string) {
34+
// this.ai = new GoogleGenAI({ apiKey });
35+
console.log("Initialized Gemini Oracle with System Prompt constraints.");
36+
}
37+
38+
public async generateModule(prompt: string): Promise<ParsedOracleResponse> {
39+
console.log(`[Oracle] Prompting Gemini: "${prompt}"`);
40+
41+
// MOCK API CALL for now, simulating Gemini response
42+
// const response = await this.ai.models.generateContent({
43+
// model: 'gemini-2.5-flash',
44+
// contents: prompt,
45+
// config: { systemInstruction: SYSTEM_PROMPT }
46+
// });
47+
// const text = response.text;
48+
49+
const mockResponseText = `
50+
Here is your requested operator.
51+
\`\`\`wgsl
52+
@compute @workgroup_size(64)
53+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
54+
// Oracle generated code here
55+
let current_water = state.water[idx];
56+
state.water[idx] = current_water * 0.99; // Evaporation
57+
}
58+
\`\`\`
59+
60+
\`\`\`yaml
61+
reads: [water]
62+
writes: [water]
63+
flux_producer: false
64+
\`\`\`
65+
`;
66+
67+
return parseOracleOutput(mockResponseText);
68+
}
69+
}

adapters/oracle/parser.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
export interface ParsedOracleResponse {
2+
wgslSource: string;
3+
reads: string[];
4+
writes: string[];
5+
flux_producer: boolean;
6+
}
7+
8+
export function parseOracleOutput(markdownResponse: string): ParsedOracleResponse {
9+
// 1. Extract WGSL block
10+
const wgslMatch = markdownResponse.match(/```wgsl\n([\s\S]*?)\n```/);
11+
if (!wgslMatch) {
12+
throw new Error("Oracle failed to provide a valid ```wgsl block.");
13+
}
14+
const wgslSource = wgslMatch[1];
15+
16+
// 2. Extract YAML dependency block
17+
const yamlMatch = markdownResponse.match(/```yaml\n([\s\S]*?)\n```/);
18+
if (!yamlMatch) {
19+
throw new Error("Oracle failed to provide a valid ```yaml block for I/O tracking.");
20+
}
21+
22+
// Very lightweight YAML extraction for the arrays
23+
const yamlString = yamlMatch[1];
24+
25+
const extractArray = (key: string) => {
26+
const regex = new RegExp(`${key}:\s*\\[(.*?)\\]`);
27+
const match = yamlString.match(regex);
28+
if (!match) return [];
29+
return match[1].split(',').map(s => s.trim().replace(/['"]/g, '')).filter(s => s.length > 0);
30+
};
31+
32+
const reads = extractArray('reads');
33+
const writes = extractArray('writes');
34+
35+
const fluxMatch = yamlString.match(/flux_producer:\s*(true|false)/);
36+
const flux_producer = fluxMatch ? fluxMatch[1] === 'true' : false;
37+
38+
return {
39+
wgslSource,
40+
reads,
41+
writes,
42+
flux_producer
43+
};
44+
}

0 commit comments

Comments
 (0)