Welcome back! In the previous chapter, Command Execution Lifecycle, we learned how the application receives a command like /rename MyProject and executes it.
But what if the user is feeling lazy? What if they just type /rename and hit Enter, expecting the computer to figure out a good name for them?
In this chapter, we will explore AI-Driven Content Generation. We will look at how we treat an Artificial Intelligence model not just as a chatbot, but as a silent "function" that performs cognitive tasks for us.
Imagine you are writing a book. You write the chapters, but you are terrible at coming up with titles. So, you hire a quick, specialized editor.
In our project, the file generateSessionName.ts is that editor.
Instead of writing complex code to analyze keywords (which is hard!), we simply send the conversation to a Language Model (specifically "Haiku," a fast and lightweight model) and ask it to summarize the context into a string.
The User types /rename (with no arguments).
Our goal is to look at the last few messages in the chat, understand the topic (e.g., debugging a login page), and automatically generate a title like debug-login-page.
To make an AI behave like a function, we must give it strict instructions. We don't want it to say, "Here is a suggestion: debug-login." We want just the data.
AI models usually speak in paragraphs. To use the output in our code, we force the AI to reply in JSON format. This ensures we get a predictable object we can use immediately.
Let's look at how we implement this "Editor" logic in generateSessionName.ts.
First, we define our function. It accepts the conversation history (messages) as input.
// generateSessionName.ts
import { queryHaiku } from '../../services/api/claude.js'
export async function generateSessionName(
messages: Message[],
signal: AbortSignal
): Promise<string | null> {
// Logic begins...
Explanation:
This function returns a Promise<string | null>. It will either give us a name string or null if something goes wrong (like a network error).
The messages array contains complex objects with timestamps and IDs. The AI only needs the text.
// Convert the complex message list into a simple text string
const conversationText = extractConversationText(messages)
// If the chat is empty, we can't summarize it!
if (!conversationText) {
return null
}
Explanation:
We use a helper extractConversationText to turn the chat history into a single block of text that the AI can read.
We need to tell the AI exactly what to do. We want a specific format: "kebab-case" (words separated by hyphens).
const prompt = [
'Generate a short kebab-case name (2-4 words) that captures the main topic.',
'Use lowercase words separated by hyphens.',
'Examples: "fix-login-bug", "add-auth-feature".',
'Return JSON with a "name" field.',
]
Explanation: This acts as the "Job Description" for our AI editor. By giving examples, we ensure the AI understands exactly the style we want.
Now we send the request to the API. Notice the outputFormat.
const result = await queryHaiku({
systemPrompt: asSystemPrompt(prompt), // Our rules
userPrompt: conversationText, // The content to summarize
outputFormat: { // Force structured data
type: 'json_schema',
schema: {
type: 'object',
properties: { name: { type: 'string' } },
required: ['name'],
},
},
signal,
})
Explanation:
This is the magic moment. We call queryHaiku.
name property."The AI sends back a response. Even though we asked for JSON, we must carefully check it (parse it) to ensure it's valid.
const content = extractTextContent(result.message.content)
const response = safeParseJSON(content)
// Check if we actually got a string back
if (response && response.name) {
return response.name // Returns "fix-login-bug"
}
return null
Explanation:
safeParseJSON attempts to turn the text response into a JavaScript object. If it succeeds, we return the name. If the AI hallucinated or the network failed, we return null.
Let's visualize the flow of data when this function is called. It is a "Ping-Pong" operation between our app and the AI Service.
queryHaiku?You might wonder why we specifically use a model called "Haiku."
In this specific module, we use a "Fail Silently" strategy.
} catch (error) {
// Log it for developers to see, but don't crash the app
logForDebugging(`generateSessionName failed: ${error}`)
// Just return null so the app can fall back to a default name
return null
}
Explanation:
If the internet goes down or the API times out, we don't want the user to see a scary error popup just because an auto-rename failed. We log the error in the background and simply return null. The command logic (from Chapter 2) will handle the null gracefully (perhaps by leaving the name unchanged).
In this chapter, we learned:
json_schema ensures the AI returns code-readable data, not conversational fluff.Now we have a command that runs, and an AI that generates data for it. But when the name changes, how does the rest of the application know? How does the sidebar update instantly?
We need to discuss how data flows through the application's memory.
Next Chapter: Application State Management
Generated by Code IQ