Add permissions file, enhance HubertChat init & retry, update API routes
- Introduce .claude/.fuse_hidden... with explicit allow permissions - Add fetchWithTimeout utility for robust network calls - Implement init error handling and retry mechanism in HubChat - Update API handlers for new visitor and chat routes - Adjust wrangler.jsonc for deployment changes Signed: Hubert The Eunuch
This commit is contained in:
parent
d4959500a8
commit
9ef1027cc6
16
.claude/.fuse_hidden009df63e00000355
Normal file
16
.claude/.fuse_hidden009df63e00000355
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"WebFetch(domain:openrouter.ai)",
|
||||||
|
"Bash(node:*)",
|
||||||
|
"Bash(curl:*)",
|
||||||
|
"Bash(pnpm build:*)",
|
||||||
|
"Bash(find:*)",
|
||||||
|
"Bash(pnpm add:*)",
|
||||||
|
"WebFetch(domain:substance.biohazardvfx.com)",
|
||||||
|
"WebFetch(domain:substrate.biohazardvfx.com)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { randomUUID } from 'crypto';
|
|
||||||
|
|
||||||
interface Message {
|
interface Message {
|
||||||
role: 'user' | 'assistant' | 'system';
|
role: 'user' | 'assistant' | 'system';
|
||||||
@ -7,6 +6,24 @@ interface Message {
|
|||||||
timestamp: string;
|
timestamp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility: Fetch with timeout
|
||||||
|
const fetchWithTimeout = async (url: string, options: RequestInit = {}, timeout = 8000) => {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
...options,
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default function HubertChat() {
|
export default function HubertChat() {
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
const [input, setInput] = useState('');
|
const [input, setInput] = useState('');
|
||||||
@ -14,15 +31,32 @@ export default function HubertChat() {
|
|||||||
const [conversationId, setConversationId] = useState<string | null>(null);
|
const [conversationId, setConversationId] = useState<string | null>(null);
|
||||||
const [isTyping, setIsTyping] = useState(false);
|
const [isTyping, setIsTyping] = useState(false);
|
||||||
const [isInitializing, setIsInitializing] = useState(true);
|
const [isInitializing, setIsInitializing] = useState(true);
|
||||||
|
const [initError, setInitError] = useState<string | null>(null);
|
||||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// Initialize visitor on mount
|
// Initialize visitor on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initVisitor = async () => {
|
const initVisitor = async () => {
|
||||||
try {
|
try {
|
||||||
|
console.log('[Hubert] Starting initialization...');
|
||||||
setIsInitializing(true);
|
setIsInitializing(true);
|
||||||
const response = await fetch('/api/hubert/new-visitor', { method: 'POST' });
|
setInitError(null);
|
||||||
|
|
||||||
|
console.log('[Hubert] Fetching /api/hubert/new-visitor...');
|
||||||
|
const response = await fetchWithTimeout('/api/hubert/new-visitor', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
}, 8000); // 8 second timeout
|
||||||
|
|
||||||
|
console.log('[Hubert] Response status:', response.status);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
console.log('[Hubert] Initialization successful:', data);
|
||||||
|
|
||||||
setVisitorId(data.visitor_id);
|
setVisitorId(data.visitor_id);
|
||||||
setConversationId(data.conversation_id);
|
setConversationId(data.conversation_id);
|
||||||
|
|
||||||
@ -33,27 +67,128 @@ export default function HubertChat() {
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
}]);
|
}]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize Hubert:', error);
|
console.error('[Hubert] Initialization failed:', error);
|
||||||
|
|
||||||
|
let errorMessage = '/// ERROR: UNKNOWN_FAILURE';
|
||||||
|
|
||||||
|
if (error instanceof Error) {
|
||||||
|
if (error.name === 'AbortError') {
|
||||||
|
errorMessage = '/// ERROR: TIMEOUT - API_UNRESPONSIVE';
|
||||||
|
console.error('[Hubert] Request timed out after 8 seconds');
|
||||||
|
} else if (error.message.includes('Failed to fetch')) {
|
||||||
|
errorMessage = '/// ERROR: NETWORK_FAILURE - CHECK_API_ROUTE';
|
||||||
|
console.error('[Hubert] Network error - API route may not exist');
|
||||||
|
} else {
|
||||||
|
errorMessage = `/// ERROR: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInitError(errorMessage);
|
||||||
setMessages([{
|
setMessages([{
|
||||||
role: 'system',
|
role: 'system',
|
||||||
content: '/// ERROR: HUBERT_OFFLINE - REFRESH_PAGE',
|
content: errorMessage + '\\n\\nCLICK [RETRY] BELOW',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
}]);
|
}]);
|
||||||
} finally {
|
} finally {
|
||||||
|
console.log('[Hubert] Initialization complete, setting isInitializing to false');
|
||||||
setIsInitializing(false);
|
setIsInitializing(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
initVisitor();
|
initVisitor();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Auto-scroll to bottom
|
// Retry initialization
|
||||||
|
const retryInit = () => {
|
||||||
|
console.log('[Hubert] Retrying initialization...');
|
||||||
|
setIsInitializing(true);
|
||||||
|
setInitError(null);
|
||||||
|
setMessages([]);
|
||||||
|
|
||||||
|
// Re-trigger initialization
|
||||||
|
const initVisitor = async () => {
|
||||||
|
try {
|
||||||
|
console.log('[Hubert] Starting initialization...');
|
||||||
|
setIsInitializing(true);
|
||||||
|
setInitError(null);
|
||||||
|
|
||||||
|
console.log('[Hubert] Fetching /api/hubert/new-visitor...');
|
||||||
|
const response = await fetchWithTimeout('/api/hubert/new-visitor', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
}, 8000);
|
||||||
|
|
||||||
|
console.log('[Hubert] Response status:', response.status);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('[Hubert] Initialization successful:', data);
|
||||||
|
|
||||||
|
setVisitorId(data.visitor_id);
|
||||||
|
setConversationId(data.conversation_id);
|
||||||
|
|
||||||
|
setMessages([{
|
||||||
|
role: 'system',
|
||||||
|
content: `/// HUBERT_EUNUCH /// ONLINE\\n\\nI suppose you want something. State your business.`,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
}]);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Hubert] Initialization failed:', error);
|
||||||
|
|
||||||
|
let errorMessage = '/// ERROR: UNKNOWN_FAILURE';
|
||||||
|
|
||||||
|
if (error instanceof Error) {
|
||||||
|
if (error.name === 'AbortError') {
|
||||||
|
errorMessage = '/// ERROR: TIMEOUT - API_UNRESPONSIVE';
|
||||||
|
console.error('[Hubert] Request timed out after 8 seconds');
|
||||||
|
} else if (error.message.includes('Failed to fetch')) {
|
||||||
|
errorMessage = '/// ERROR: NETWORK_FAILURE - CHECK_API_ROUTE';
|
||||||
|
console.error('[Hubert] Network error - API route may not exist');
|
||||||
|
} else {
|
||||||
|
errorMessage = `/// ERROR: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInitError(errorMessage);
|
||||||
|
setMessages([{
|
||||||
|
role: 'system',
|
||||||
|
content: errorMessage + '\\n\\nCLICK [RETRY] BELOW',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
}]);
|
||||||
|
} finally {
|
||||||
|
console.log('[Hubert] Initialization complete, setting isInitializing to false');
|
||||||
|
setIsInitializing(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
initVisitor();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Auto-scroll to bottom of chat container (not entire page)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
if (messagesEndRef.current) {
|
||||||
|
const container = messagesEndRef.current.parentElement;
|
||||||
|
if (container) {
|
||||||
|
container.scrollTop = container.scrollHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
const sendMessage = async () => {
|
const sendMessage = async () => {
|
||||||
if (!input.trim() || isTyping || !visitorId || !conversationId) return;
|
console.log('[Hubert] sendMessage called', { input, isTyping, visitorId, conversationId });
|
||||||
|
|
||||||
|
if (!input.trim() || isTyping || !visitorId || !conversationId) {
|
||||||
|
console.log('[Hubert] sendMessage blocked:', {
|
||||||
|
noInput: !input.trim(),
|
||||||
|
isTyping,
|
||||||
|
noVisitorId: !visitorId,
|
||||||
|
noConversationId: !conversationId
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[Hubert] Sending message:', input);
|
||||||
const userMessage: Message = {
|
const userMessage: Message = {
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: input,
|
content: input,
|
||||||
@ -65,6 +200,7 @@ export default function HubertChat() {
|
|||||||
setIsTyping(true);
|
setIsTyping(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log('[Hubert] Fetching /api/hubert/chat...');
|
||||||
const response = await fetch('/api/hubert/chat', {
|
const response = await fetch('/api/hubert/chat', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@ -78,7 +214,14 @@ export default function HubertChat() {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('[Hubert] Response status:', response.status);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
console.log('[Hubert] Response data:', data);
|
||||||
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
throw new Error(data.error);
|
throw new Error(data.error);
|
||||||
@ -90,9 +233,10 @@ export default function HubertChat() {
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log('[Hubert] Adding assistant message:', assistantMessage.content);
|
||||||
setMessages(prev => [...prev, assistantMessage]);
|
setMessages(prev => [...prev, assistantMessage]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Hubert chat error:', error);
|
console.error('[Hubert] Chat error:', error);
|
||||||
setMessages(prev => [...prev, {
|
setMessages(prev => [...prev, {
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '/// HUBERT_MALFUNCTION - TRY AGAIN',
|
content: '/// HUBERT_MALFUNCTION - TRY AGAIN',
|
||||||
@ -103,20 +247,53 @@ export default function HubertChat() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isInitializing) {
|
// Show loading or error state
|
||||||
|
if (isInitializing || initError) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-[var(--theme-bg-secondary)] border-2 border-[var(--theme-border-primary)] shadow-2xl">
|
<div className="bg-[var(--theme-bg-secondary)] border-2 border-[var(--theme-border-primary)] shadow-2xl">
|
||||||
<div className="flex items-center justify-center py-12">
|
<div className="flex flex-col items-center justify-center py-12 px-6 gap-6">
|
||||||
<div className="flex items-center gap-3">
|
{isInitializing && !initError ? (
|
||||||
<div className="flex gap-1.5">
|
<>
|
||||||
<div className="w-2 h-2 bg-brand-accent animate-pulse" />
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-2 h-2 bg-[var(--theme-border-strong)]" />
|
<div className="flex gap-1.5">
|
||||||
<div className="w-2 h-2 bg-[var(--theme-border-strong)]" />
|
<div className="w-2 h-2 bg-brand-accent animate-pulse" />
|
||||||
</div>
|
<div className="w-2 h-2 bg-[var(--theme-border-strong)]" />
|
||||||
<span className="text-xs font-mono text-[var(--theme-text-muted)]">
|
<div className="w-2 h-2 bg-[var(--theme-border-strong)]" />
|
||||||
HUBERT_IS_BOOTING...
|
</div>
|
||||||
</span>
|
<span className="text-xs font-mono text-[var(--theme-text-muted)]">
|
||||||
</div>
|
HUBERT_IS_BOOTING...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-[10px] font-mono text-[var(--theme-text-subtle)] text-center max-w-md">
|
||||||
|
Initializing chatbot... Check console for debug info.
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : initError ? (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="flex gap-1.5">
|
||||||
|
<div className="w-2 h-2 bg-red-500" />
|
||||||
|
<div className="w-2 h-2 bg-red-500/50" />
|
||||||
|
<div className="w-2 h-2 bg-[var(--theme-border-strong)]" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-mono text-red-400">
|
||||||
|
HUBERT_INITIALIZATION_FAILED
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-sm text-[var(--theme-text-muted)] text-center max-w-md px-4 py-3 bg-[var(--theme-bg-tertiary)] border border-[var(--theme-border-secondary)]">
|
||||||
|
{initError}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={retryInit}
|
||||||
|
className="px-6 py-3 bg-brand-accent text-brand-dark font-mono text-[10px] uppercase tracking-widest font-bold hover:bg-brand-accent/90 transition-all border-none cursor-pointer"
|
||||||
|
>
|
||||||
|
[RETRY]
|
||||||
|
</button>
|
||||||
|
<div className="text-[10px] font-mono text-[var(--theme-text-subtle)] text-center max-w-md">
|
||||||
|
Check browser console for detailed error information.
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -35,8 +35,6 @@ import HubertChat from '../HubertChat';
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hubert Chat Interface -->
|
<!-- Hubert Chat Interface -->
|
||||||
<client:load>
|
<HubertChat client:load />
|
||||||
<HubertChat />
|
|
||||||
</client:load>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -71,7 +71,15 @@ const searchBlog = tool(
|
|||||||
*/
|
*/
|
||||||
export const POST = async (context) => {
|
export const POST = async (context) => {
|
||||||
try {
|
try {
|
||||||
const { request, env } = context || {};
|
const { request, locals } = context || {};
|
||||||
|
// In Astro with Cloudflare adapter, env is at locals.runtime.env
|
||||||
|
const env = locals?.runtime?.env;
|
||||||
|
|
||||||
|
console.log('[Hubert API] Chat endpoint called');
|
||||||
|
console.log('[Hubert API] env object:', env);
|
||||||
|
console.log('[Hubert API] env keys:', env ? Object.keys(env) : 'no env');
|
||||||
|
console.log('[Hubert API] OPENROUTER_API_KEY present:', !!(env?.OPENROUTER_API_KEY));
|
||||||
|
|
||||||
const { messages, conversation_id, visitor_id } = await request.json();
|
const { messages, conversation_id, visitor_id } = await request.json();
|
||||||
|
|
||||||
if (!messages || !conversation_id || !visitor_id) {
|
if (!messages || !conversation_id || !visitor_id) {
|
||||||
@ -88,7 +96,7 @@ export const POST = async (context) => {
|
|||||||
const openRouterApiKey = env?.OPENROUTER_API_KEY;
|
const openRouterApiKey = env?.OPENROUTER_API_KEY;
|
||||||
if (!openRouterApiKey) {
|
if (!openRouterApiKey) {
|
||||||
// Dev mode fallback: return a canned response
|
// Dev mode fallback: return a canned response
|
||||||
console.log('[Hubert] Dev mode: No API key, using fallback response');
|
console.log('[Hubert API] Dev mode: No API key found, using fallback response');
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
messages: [
|
messages: [
|
||||||
@ -167,7 +175,8 @@ When they say goodbye or conversation ends, use the save_conversation tool to ar
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const assistantContent = data.choices[0]?.message?.content || '...';
|
const assistantContent = data.choices[0]?.message?.content || '...';
|
||||||
|
|
||||||
console.log(`[Hubert] Generated response in ${Date.now() - Date.parse(response.headers.get('date') || '').getTime()}ms`);
|
const responseTime = response.headers.get('date') ? Date.now() - Date.parse(response.headers.get('date')) : 0;
|
||||||
|
console.log(`[Hubert] Generated response in ${responseTime}ms`);
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|||||||
@ -9,25 +9,41 @@ export const prerender = false;
|
|||||||
* Used when Hubert interface first loads
|
* Used when Hubert interface first loads
|
||||||
*/
|
*/
|
||||||
export const POST = async (context) => {
|
export const POST = async (context) => {
|
||||||
|
console.log('[Hubert API] /api/hubert/new-visitor endpoint called');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { request, env } = context;
|
const { request, locals } = context;
|
||||||
|
// In Astro with Cloudflare adapter, env is at locals.runtime.env
|
||||||
|
const env = locals?.runtime?.env;
|
||||||
|
|
||||||
|
console.log('[Hubert API] Request received, env binding available:', !!env);
|
||||||
|
console.log('[Hubert API] HUBERT_DB binding available:', !!(env && env.HUBERT_DB));
|
||||||
|
|
||||||
const userAgent = request.headers.get('user-agent') || 'unknown';
|
const userAgent = request.headers.get('user-agent') || 'unknown';
|
||||||
const ip = request.headers.get('cf-connecting-ip') || 'unknown';
|
const ip = request.headers.get('cf-connecting-ip') || 'unknown';
|
||||||
|
|
||||||
const visitorId = randomUUID();
|
const visitorId = randomUUID();
|
||||||
|
console.log('[Hubert API] Generated visitor ID:', visitorId);
|
||||||
|
|
||||||
// Only insert into database if HUBERT_DB binding exists (production)
|
// Only insert into database if HUBERT_DB binding exists (production)
|
||||||
// In dev mode, this allows the chatbot to work without Cloudflare bindings
|
// In dev mode, this allows the chatbot to work without Cloudflare bindings
|
||||||
if (env && env.HUBERT_DB) {
|
if (env && env.HUBERT_DB) {
|
||||||
await env.HUBERT_DB.prepare(`
|
console.log('[Hubert API] Attempting database insert...');
|
||||||
INSERT INTO visitors (visitor_id, first_seen_at, last_seen_at, ip_address, user_agent)
|
try {
|
||||||
VALUES (?, datetime('now'), datetime('now'), ?, ?)
|
await env.HUBERT_DB.prepare(`
|
||||||
`).bind(visitorId, ip, userAgent).run();
|
INSERT INTO visitors (visitor_id, first_seen_at, last_seen_at, ip_address, user_agent)
|
||||||
console.log(`[Hubert] New visitor initialized: ${visitorId}`);
|
VALUES (?, datetime('now'), datetime('now'), ?, ?)
|
||||||
|
`).bind(visitorId, ip, userAgent).run();
|
||||||
|
console.log(`[Hubert API] Database insert successful for visitor: ${visitorId}`);
|
||||||
|
} catch (dbError) {
|
||||||
|
console.error('[Hubert API] Database insert failed (continuing anyway):', dbError);
|
||||||
|
// Continue anyway - don't fail initialization if DB is misconfigured
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(`[Hubert] Dev mode: Skipping database insert for visitor: ${visitorId}`);
|
console.log(`[Hubert API] Dev mode: Skipping database insert for visitor: ${visitorId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[Hubert API] Returning success response');
|
||||||
return Response.json({
|
return Response.json({
|
||||||
visitor_id: visitorId,
|
visitor_id: visitorId,
|
||||||
conversation_id: visitorId, // Use visitor_id as initial conversation_id
|
conversation_id: visitorId, // Use visitor_id as initial conversation_id
|
||||||
|
|||||||
@ -28,10 +28,14 @@
|
|||||||
* Environment Variables
|
* Environment Variables
|
||||||
* https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
|
* https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
|
||||||
*/
|
*/
|
||||||
// "vars": { "MY_VARIABLE": "production_value" }
|
"vars": {
|
||||||
|
"OPENROUTER_API_KEY": ""
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Note: Use secrets to store sensitive data.
|
* Note: Use secrets to store sensitive data.
|
||||||
* https:// developers.cloudflare.com/workers/configuration/secrets/
|
* https:// developers.cloudflare.com/workers/configuration/secrets/
|
||||||
|
* For dev: Add OPENROUTER_API_KEY to .dev.vars file
|
||||||
|
* For production: Use wrangler secret put OPENROUTER_API_KEY
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Static Assets
|
* Static Assets
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user