CSV handling
This commit is contained in:
@@ -38,6 +38,49 @@ specific dollar amounts.`
|
||||
|
||||
const MODEL = process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-5'
|
||||
|
||||
// File uploaded to the Anthropic Console / Files API that the agent should
|
||||
// consult on every call.
|
||||
const KNOWLEDGE_FILE_ID =
|
||||
process.env.ANTHROPIC_KNOWLEDGE_FILE_ID || 'file_011Cawv1SPNaknuMmyDtM1S7'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Module-scoped singletons (reused across warm Lambda invocations)
|
||||
// ---------------------------------------------------------------------------
|
||||
// Netlify keeps the function process alive between invocations as long as it
|
||||
// stays warm, so anything declared at module scope persists. We lazily build
|
||||
// the Anthropic client and download the knowledge file exactly once per
|
||||
// cold start, then reuse them for the lifetime of the container.
|
||||
|
||||
let _client
|
||||
function getClient() {
|
||||
if (_client) return _client
|
||||
if (!process.env.ANTHROPIC_API_KEY) {
|
||||
throw new Error('Server is missing ANTHROPIC_API_KEY')
|
||||
}
|
||||
_client = new Anthropic({
|
||||
apiKey: process.env.ANTHROPIC_API_KEY,
|
||||
// Required while the Files API is in beta.
|
||||
defaultHeaders: { 'anthropic-beta': 'files-api-2025-04-14' },
|
||||
})
|
||||
return _client
|
||||
}
|
||||
|
||||
// Cache the in-flight promise so concurrent requests during a cold start
|
||||
// share a single download instead of fetching the CSV N times.
|
||||
let _knowledgeFilePromise
|
||||
function loadKnowledgeFile() {
|
||||
if (_knowledgeFilePromise) return _knowledgeFilePromise
|
||||
_knowledgeFilePromise = (async () => {
|
||||
const resp = await getClient().beta.files.download(KNOWLEDGE_FILE_ID)
|
||||
return await resp.text()
|
||||
})().catch((err) => {
|
||||
// Reset on failure so the next request can retry.
|
||||
_knowledgeFilePromise = undefined
|
||||
throw err
|
||||
})
|
||||
return _knowledgeFilePromise
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handler
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -68,12 +111,20 @@ export default async (req /*, context */) => {
|
||||
return new Response('Invalid station website URL', { status: 400 })
|
||||
}
|
||||
|
||||
if (!process.env.ANTHROPIC_API_KEY) {
|
||||
return new Response('Server is missing ANTHROPIC_API_KEY', { status: 500 })
|
||||
let client
|
||||
let knowledgeFileText
|
||||
try {
|
||||
client = getClient()
|
||||
// First call after a cold start awaits the download; subsequent calls
|
||||
// resolve immediately from the cached promise.
|
||||
knowledgeFileText = await loadKnowledgeFile()
|
||||
} catch (err) {
|
||||
return new Response(
|
||||
`Failed to initialize agent: ${err.message || err}`,
|
||||
{ status: 500 },
|
||||
)
|
||||
}
|
||||
|
||||
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
|
||||
|
||||
const userMessage = `Here is a new public media station intake:
|
||||
|
||||
- Submitter Name: ${userName}
|
||||
@@ -93,7 +144,27 @@ Please draft the funding outlook brief described in your instructions.`
|
||||
model: MODEL,
|
||||
max_tokens: 10000,
|
||||
system: SYSTEM_PROMPT,
|
||||
messages: [{ role: 'user', content: userMessage }],
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'document',
|
||||
source: {
|
||||
type: 'text',
|
||||
media_type: 'text/plain',
|
||||
data: knowledgeFileText,
|
||||
},
|
||||
title: 'Funder knowledge base (CSV)',
|
||||
citations: { enabled: true },
|
||||
// Cache the tokenized CSV on Anthropic's side for ~5 minutes
|
||||
// so repeat requests pay ~10% of input-token cost for it.
|
||||
cache_control: { type: 'ephemeral' },
|
||||
},
|
||||
{ type: 'text', text: userMessage },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
if (AGENT_ID && AGENT_ID !== 'YOUR_AGENT_ID_HERE') {
|
||||
streamArgs.agent_id = AGENT_ID
|
||||
|
||||
Reference in New Issue
Block a user