SYP Start Your Path

Module 3: JavaScript & AI Development

The final chapter — using everything from this course (async JS, fetch, Node backends) to build with modern AI models.

Calling AI APIs from JavaScript

AI providers expose their models over a plain HTTP API — calling one from JavaScript uses exactly the fetch + async/await patterns from Module 2:

async function askAI(userMessage) {
  const response = await fetch("https://api.example.com/v1/messages", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${process.env.API_KEY}` // never expose this in frontend code
    },
    body: JSON.stringify({
      model: "some-model",
      messages: [{ role: "user", content: userMessage }]
    })
  });
  const data = await response.json();
  return data.content;
}

Important: API keys must stay on a Node.js backend (Module 3's earlier chapters) — never call an AI API with a secret key directly from frontend/browser JavaScript, where anyone could read it from the network tab (Module 2's security chapter).

Streaming Responses & Chat Interfaces

AI responses often stream back token-by-token, so the user sees words appear progressively instead of waiting for the whole answer:

async function streamAI(userMessage, onChunk) {
  const response = await fetch("/api/chat", {
    method: "POST",
    body: JSON.stringify({ message: userMessage })
  });

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    onChunk(decoder.decode(value)); // update the UI with each new chunk
  }
}

A chat interface tracks a conversation history — an array of messages, each with a role — and sends the whole history with every new request, since the AI has no memory of its own between calls:

let conversation = [
  { role: "system", content: "You are a helpful assistant." }, // sets overall behavior
  { role: "user", content: "What's the capital of France?" },
  { role: "assistant", content: "Paris." },
  { role: "user", content: "And its population?" } // the new message being sent
];

Function & Tool Calling

Modern AI models can be given a list of available "tools" (functions) with a description of what each does — the model decides when to call one, and your code actually runs it:

const tools = [{
  name: "get_weather",
  description: "Get the current weather for a city",
  parameters: { city: "string" }
}];

// The AI's response may include a tool call instead of plain text
if (aiResponse.tool_call) {
  const { name, arguments: args } = aiResponse.tool_call;
  if (name === "get_weather") {
    const weather = await getWeather(args.city); // your actual function
    // send the result back to the AI to continue the conversation
  }
}

Structured output asks the model to respond in a strict format (like JSON matching a schema) instead of free-form text — useful when the response needs to be reliably parsed by code.

Embeddings, RAG & AI Agents

Embeddings convert text into a list of numbers (a vector) that captures its meaning — similar text produces similar vectors, which is how semantic search works:

const embedding = await getEmbedding("How do I reset my password?");
// [0.021, -0.153, 0.884, ...] — stored in a vector database for later similarity search

RAG (Retrieval-Augmented Generation) uses this to ground AI answers in real data: search a vector database for text relevant to the user's question, then include that text in the prompt sent to the AI, so it answers using real, current information instead of relying only on what it learned during training.

Frontend
   ↓ user question
Backend
   ↓ embed the question, search vector database for relevant chunks
   ↓ build a prompt: [relevant chunks] + [user question]
AI model
   ↑ answer grounded in the retrieved data

An AI agent extends this with a loop: the AI can call tools, see the results, and decide on its own what to do next — repeating until the task is done, rather than answering in a single pass:

while (!taskComplete) {
  const response = await callAI(conversation, tools);
  if (response.tool_call) {
    const result = await runTool(response.tool_call);
    conversation.push({ role: "tool", content: result });
  } else {
    taskComplete = true; // the AI produced a final answer, no more tools needed
  }
}

AI SDKs & Providers

Rather than calling raw HTTP APIs by hand, most projects use an SDK:

Major AI providers — OpenAI, Anthropic, Google Gemini, and others — expose broadly similar HTTP APIs (a list of messages in, a response out), so switching providers is often a matter of changing the request format, not rewriting the whole app. Puter.js is an example of a platform that bundles cloud storage, AI access, and other services behind a single JavaScript SDK, letting a static frontend call AI models directly without running your own backend at all.