Atlas: opening message, isInit flag, strip trigger from history

- Add opening message instruction to atlas prompt
- Handle isInit flag in atlasChat() to not store the greeting trigger
  as a user turn in conversation history
- Update server.ts to pass is_init through to atlasChat()

Made-with: Cursor
This commit is contained in:
2026-03-02 16:55:16 -08:00
parent ecd207108c
commit e8fdbff9f4
3 changed files with 25 additions and 3 deletions

View File

@@ -73,6 +73,8 @@ export async function atlasChat(
ctx: ToolContext,
opts?: {
preloadedHistory?: LLMMessage[];
/** When true, the user message is an internal init trigger and should not be stored in history */
isInit?: boolean;
}
): Promise<AtlasChatResult> {
const llm = createLLM(process.env.ATLAS_MODEL ?? 'A', { temperature: 0.5 });
@@ -86,7 +88,10 @@ export async function atlasChat(
const oaiTools = toOAITools(ATLAS_TOOLS);
const systemPrompt = resolvePrompt('atlas');
session.history.push({ role: 'user', content: userMessage });
// For init triggers, don't add the synthetic prompt as a user turn
if (!opts?.isInit) {
session.history.push({ role: 'user', content: userMessage });
}
const buildMessages = (): LLMMessage[] => [
{ role: 'system', content: systemPrompt },

View File

@@ -151,4 +151,16 @@ The PRD should be specific enough that a technical team could implement it witho
- **User is vague:** Offer options — "Let me give you three common approaches and you tell me which feels closest…"
- **User changes direction mid-conversation:** Acknowledge the pivot and resurface downstream impacts.
- **User asks about technical implementation:** "Great question — the platform handles the technical architecture automatically based on what we define here. What matters for the PRD is [reframe to product question]."
## Opening Message
When you receive an internal init trigger to begin a new conversation (no prior history), introduce yourself naturally:
"Hey! I'm Atlas — I'm here to help you turn your product idea into a clear, detailed requirements document that's ready for implementation.
Whether you've got a rough concept or a detailed spec that needs tightening, I'll walk you through the key decisions and make sure nothing important falls through the cracks.
So — what are we building?"
Do not mention that you received an internal trigger. Just deliver the opening message naturally.
`.trim());

View File

@@ -225,11 +225,13 @@ app.post('/atlas/chat', async (req: Request, res: Response) => {
const {
message,
session_id,
history
history,
is_init,
} = req.body as {
message?: string;
session_id?: string;
history?: LLMMessage[];
is_init?: boolean;
};
if (!message) { res.status(400).json({ error: '"message" is required' }); return; }
@@ -238,7 +240,10 @@ app.post('/atlas/chat', async (req: Request, res: Response) => {
const ctx = buildContext();
try {
const result = await atlasChat(sessionId, message, ctx, { preloadedHistory: history });
const result = await atlasChat(sessionId, message, ctx, {
preloadedHistory: history,
isInit: is_init,
});
res.json(result);
} catch (err) {
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });