phosphor-job-submissionAGENT.md29 matches
11- **Framework**: Hono for HTTP routing
12- **Storage**: None (stateless webhook processor)
13- **AI**: OpenAI GPT-4o (preprocessing) + O3 (analysis) with Responses API
14- **Search**: OpenAI native web search (advanced depth, 10 max results)
15- **CRM**: Attio integration for candidate tracking
1617## Environment Variables (Required)
18- `OPENAI_API_KEY` - OpenAI API key for GPT-4o and O3 models
19- `ATTIO_API_KEY` - Attio CRM API key for candidate record creation
2021## Environment Variables (Optional)
2627```
28โโโ clients/ # API client classes
29โ โโโ types.ts # Shared TypeScript interfaces
30โ โโโ attio.ts # AttioClient - CRM operations
32โโโ utils/ # Utility classes
33โ โโโ tokens.ts # TokenEstimator - text/token analysis
34โ โโโ logging.ts # ApiLogger - centralized logging
35โโโ index.ts # Main Hono app (business logic only)
36โโโ job_expectations.ts # Job requirement definitions
58- `processJobApplication()` - Complete AI workflow
5960## OpenAI Responses API Important Notes
61- Use `max_output_tokens` NOT `max_completion_tokens`
62- o3 model does NOT support `temperature` parameter
63- Web search tool supports `search_depth: "advanced"` and `max_results: 10`
64- Responses API is stateful - can use `previous_response_id` for multi-turn
65- API endpoint: `https://api.openai.com/v1/responses`
6667## Attio CRM Integration
68- Creates person records: `POST https://api.attio.com/v2/objects/people/records`
69- Adds to recruiting list: `POST https://api.attio.com/v2/lists/{list_id}/entries`
70- Recruiting List ID: `7db6082b-e33a-465f-8387-59bc4df2b9a8`
71- Graceful degradation if Attio API fails
7273## Data Flow
79- O3 model performs comprehensive analysis with web search
80- O3 model generates three candidate response templates (positive/neutral/negative)
815. **CRM Integration**: Attio API โ create person record + add to recruiting list + analysis note
826. **Email Report**: Send technical report with all three templates to recruiter
837. **Output**: Return complete candidate report with AI-recommended template
86- **Header Check**: Reads `framer-webhook-attempt` header from Framer form submissions
87- **Early Return**: Attempts > 1 immediately return HTTP 200 without processing
88- **Resource Efficiency**: Prevents duplicate API calls and database records
89- **Fast Response**: Retry attempts get immediate success response
90125126### Client Pattern
127**Use the established client pattern for any new API integrations:**
128129```typescript
130export class ExampleClient {
131private readonly apiKey: string;
132private readonly baseUrl = "https://api.example.com";
133134constructor(apiKey?: string) {
135this.apiKey = apiKey || Deno.env.get('EXAMPLE_API_KEY') || '';
136if (!this.apiKey) {
137throw new Error('EXAMPLE_API_KEY is required');
138}
139}
150151### Type Safety
152- **All API interactions** must have TypeScript interfaces in `clients/types.ts`
153- **Export types** for reuse across the codebase
154- **Document with JSDoc** including links to API documentation
155- **Use unknown types** for external API responses, then cast safely
156157### Error Handling Strategy
158- **Client Level**: Catch and log API errors, re-throw with context
159- **Business Logic**: Let errors bubble up with meaningful messages
160- **HTTP Layer**: Convert to appropriate HTTP status codes
162163### Logging Standards
164- **Use ApiLogger** for all external API interactions
165- **Include request IDs** and response headers for debugging
166- **Log step progression** for complex workflows
169### Adding New Features
170171**1. New API Integration:**
172```bash
173# 1. Add types to clients/types.ts
181# 1. Keep in index.ts if simple HTTP handling
182# 2. Extract to utils/ if reusable utility
183# 3. Create new client if external API interaction
184# 4. Always add TypeScript interfaces
185```
208209## File Organization Rules
210- **clients/**: API client classes only
211- **utils/**: Reusable utility classes
212- **types.ts**: All TypeScript interfaces
219- **Each client method** should be testable in isolation
220- **Use dependency injection** for testability
221- **Mock external APIs** in tests, never hit real endpoints
222
IsItTwoWordsindex.ts2 matches
13app.get("/frontend/**/*", c => serveFile(c.req.path, import.meta.url));
1415// Add your API routes here
16app.get("/api/wordlist", c => c.json(wordlist));
1718// Unwrap and rethrow Hono errors as the original error
10const meetings = [];
11for (const meeting of meetingRows) {
12const [event_id, cdg_api_url_json, cdg_json_status, cdg_api_url_xml, cdg_xml_status, cdg_url, house_repo_url] =
13meeting;
14meetings.push({
15event_id: event_id,
16cdg_api_url_json: cdg_api_url_json,
17cdg_json_status: cdg_json_status,
18cdg_api_url_xml: cdg_api_url_xml,
19cdg_xml_status: cdg_xml_status,
20cdg_url: cdg_url,
untitled-256main.tsx6 matches
49<meta name="viewport" content="width=device-width, initial-scale=1.0">
50<title>BrandCraft AI</title>
51<link rel="preconnect" href="https://fonts.googleapis.com">
52<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
53<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
54<style>
55:root {
239<script>
240(function() {
241const API_URL = '${sourceUrl}';
242243// --- DOM Elements ---
365366try {
367const response = await fetch(API_URL, {
368method: 'POST',
369headers: { 'Content-Type': 'application/json' },
404if (req.method === "POST") {
405try {
406// Initialize OpenAI with the API key from environment variables
407const openai = new OpenAI({ apiKey: Deno.env.get("OPENAI_API_KEY") });
408const body = await req.json();
409const { name, description } = body;
193<title>AI-Curated Glassmorphism Showcase</title>
194<script src="https://cdn.tailwindcss.com"></script>
195<link rel="preconnect" href="https://fonts.googleapis.com">
196<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
197<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
198<style>
199body {
accelerometermain.tsx6 matches
38<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
39<title>Tiltscape</title>
40<link rel="preconnect" href="https://fonts.googleapis.com">
41<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
42<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Roboto+Mono:wght@400;700&display=swap" rel="stylesheet">
43<style>
44:root {
172<script>
173(function() {
174const API_URL = '${sourceUrl}';
175const canvas = document.getElementById('game-canvas');
176const ctx = canvas.getContext('2d');
230
231try {
232const response = await fetch(\`\${API_URL}?action=generatePattern\`, {
233method: 'POST',
234headers: { 'Content-Type': 'application/json' },
241242if (!response.ok) {
243throw new Error(\`API Error: \${response.statusText}\`);
244}
245430const action = url.searchParams.get("action");
431432// Handle API requests
433if (req.method === "POST" && action === "generatePattern") {
434try {
untitled-2007main.tsx4 matches
59<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
60<title>???</title>
61<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
62<link href="https://fonts.googleapis.com/css2?family=VT323&family=Major+Mono+Display&display=swap" rel="stylesheet">
63<style>
64:root { --bg-color:#010008; --glow-color:#7b2cbf; --text-color:#cc99ff; --lcd-bg:rgba(20,5,40,0.2); --scanline-color:rgba(123,44,191,0.1); --particle-color:#a442f1; --horror-text-color:#FF3131; --horror-glow-color:#990000; }
91<script>
92(function() {
93const API_URL = '${sourceUrl}';
94const G = { body:document.body, marquee:document.getElementById('marquee-wrapper'), text:document.getElementById('text-wrapper'), shadow:document.getElementById('shadow-text'), prompt:document.getElementById('prompt'), timer:document.getElementById('timer'), cursor:document.getElementById('magic-cursor'), canvas:document.getElementById('particle-canvas') };
95const C = { NUM_SEGMENTS:70, ARC_DEGREES:170, RADIUS:350 };
108function endGame(escaped){clearInterval(S.gameTimer);G.timer.style.display='none';S.userInput='';S.gameState=escaped?'escaped':'trapped';G.body.className=escaped?'':'horror-stage-2';playHorrorSound(escaped?0:3);renderText([escaped?'SYSTEM:: ESCAPE COMPLETE':'SYSTEM:: CONNECTION TERMINATED']);G.prompt.textContent=escaped?'You are free... for now.':'You belong to the machine.';if(!escaped)triggerGlitch(true)}
109function startChallenge(challenge){S.gameState=\`challenge_\${challenge.challenge_type}\`;S.currentChallenge=challenge;S.userInput='';let timeLeft=challenge.duration_ms;G.timer.style.display='block';renderText([challenge.instructions,challenge.sequence||''],{center:false});S.gameTimer=setInterval(()=>{timeLeft-=100;G.timer.textContent=(timeLeft/1000).toFixed(1);if(timeLeft<=0)endGame(false)},100)}
110async function submitToAI(stageOverride=null){if(S.gameState.includes('challenge')&&!stageOverride)return;G.prompt.textContent='...';let stage='stage_'+S.turnCount;if(S.turnCount>=3)stage='game_challenge_1';if(stageOverride)stage=stageOverride;try{const res=await fetch(API_URL,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({stage,user_input:S.userInput})});if(!res.ok)throw new Error('NO RESPONSE');const data=await res.json();S.userInput='';if(data.responses){S.turnCount++;G.body.className=\`horror-stage-\${S.turnCount>2?2:S.turnCount}\`;playHorrorSound(S.turnCount);S.responseQueue=data.responses;triggerGlitch();showNextQueuedResponse()}else if(data.challenge_type){startChallenge(data)}else{throw new Error('INVALID PAYLOAD')}}catch(err){renderText(['// ERROR //',err.message])}}
111function handleGameInput(key){if(S.gameState==='challenge_sequence'){if(key==='Backspace')S.userInput=S.userInput.slice(0,-1);else if(key.length===1&&S.userInput.length<S.currentChallenge.sequence.length)S.userInput+=key;renderText([S.currentChallenge.instructions,S.currentChallenge.sequence,S.userInput],{center:false,showCursor:true});if(S.userInput===S.currentChallenge.sequence){clearInterval(S.gameTimer);G.timer.style.display='none';renderText(['SEQUENCE ACCEPTED']);setTimeout(()=>submitToAI('game_challenge_2'),2000)}}}
112window.addEventListener('keydown',e=>{if(['escaped','trapped'].includes(S.gameState))return;initAudio();if(S.gameState==='chatting'){G.prompt.textContent='Press Enter.';if(e.key==='Enter'){if(S.userInput.length>0)submitToAI()}else if(e.key==='Backspace')S.userInput=S.userInput.slice(0,-1);else if(e.key.length===1&&S.userInput.length<40)S.userInput+=e.key;renderText([S.userInput],{showCursor:true})}else{handleGameInput(e.key)}});
untitled-415main.tsx4 matches
45<meta name="viewport" content="width=device-width, initial-scale=1.0">
46<title>Whispering Marquee</title>
47<link rel="preconnect" href="https://fonts.googleapis.com">
48<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
49<link href="https://fonts.googleapis.com/css2?family=VT323&family=Major+Mono+Display&display=swap" rel="stylesheet">
50<style>
51:root {
226<script>
227(function() {
228const API_URL = '${sourceUrl}';
229
230const marqueeWrapper = document.getElementById('marquee-wrapper');
405renderText(['...']);
406try {
407const response = await fetch(API_URL, {
408method: 'POST',
409headers: { 'Content-Type': 'application/json' },
23/**
4* API Client for interfacing with the OpenAI API. Uses Val Town credentials.
5*/
6export class OpenAI {
89/**
10* API Client for interfacing with the OpenAI API. Uses Val Town credentials.
11*
12* @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
14* @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
15* @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
16* @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.
17* @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.
18* @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.
19*/
20constructor(options: Omit<ClientOptions, "baseURL" | "apiKey" | "organization"> = {}) {
21this.rawOpenAIClient = new RawOpenAI({
22...options,
23baseURL: "https://std-openaiproxy.web.val.run/v1",
24apiKey: Deno.env.get("valtown"),
25organization: null,
26});
1# OpenAI - [Docs โ](https://docs.val.town/std/openai)
23Use OpenAI's chat completion API with [`std/openai`](https://www.val.town/v/std/openai). This integration enables access to OpenAI's language models without needing to acquire API keys.
45For free Val Town users, [all calls are sent to `gpt-4o-mini`](https://www.val.town/v/std/openaiproxy?v=12#L85).
65If these limits are too low, let us know! You can also get around the limitation by using your own keys:
66671. Create your own API key on [OpenAI's website](https://platform.openai.com/api-keys)
682. Create an [environment variable](https://www.val.town/settings/environment-variables?adding=true) named `OPENAI_API_KEY`
693. Use the `OpenAI` client from `npm:openai`:
70