diff --git a/.changeset/fix-date-hallucination.md b/.changeset/fix-date-hallucination.md new file mode 100644 index 000000000..5350787cf --- /dev/null +++ b/.changeset/fix-date-hallucination.md @@ -0,0 +1,5 @@ +--- +'@bradygaster/squad-sdk': patch +--- + +Fix date hallucination in spawned agents by injecting current ISO timestamp into prompts. Replace hardcoded 2025 dates in scribe-charter templates with dynamic placeholders. \ No newline at end of file diff --git a/packages/squad-cli/templates/scribe-charter.md b/packages/squad-cli/templates/scribe-charter.md index a2031d072..0ddb2dc88 100644 --- a/packages/squad-cli/templates/scribe-charter.md +++ b/packages/squad-cli/templates/scribe-charter.md @@ -211,11 +211,11 @@ After every substantial work session: │ ├── river-jwt-auth.md │ └── kai-component-lib.md ├── orchestration-log/ # Per-spawn log entries -│ ├── 2025-07-01T10-00-river.md -│ └── 2025-07-01T10-00-kai.md +│ ├── {timestamp}-river.md +│ └── {timestamp}-kai.md ├── log/ # Session history — searchable record -│ ├── 2025-07-01-setup.md -│ └── 2025-07-02-api.md +│ ├── {date}-setup.md +│ └── {date}-api.md └── agents/ ├── kai/history.md # Kai's personal knowledge ├── river/history.md # River's personal knowledge diff --git a/packages/squad-sdk/src/coordinator/fan-out.ts b/packages/squad-sdk/src/coordinator/fan-out.ts index 7fd9ab4e2..ff1a4fbef 100644 --- a/packages/squad-sdk/src/coordinator/fan-out.ts +++ b/packages/squad-sdk/src/coordinator/fan-out.ts @@ -12,6 +12,7 @@ import type { AgentCharter } from '../agents/index.js'; import type { EventBus } from '../client/event-bus.js'; import type { SessionPool } from '../client/session-pool.js'; + // --- Spawn Configuration --- export interface AgentSpawnConfig { @@ -185,6 +186,10 @@ async function spawnSingle( function buildInitialPrompt(config: AgentSpawnConfig): string { const parts: string[] = []; + // Inject current date so spawned agents know the real date/time. + // Without this, LLMs hallucinate dates (especially the year). + parts.push(`**Current Date:** ${new Date().toISOString()}`); + if (config.priority && config.priority !== 'normal') { parts.push(`**Priority:** ${config.priority.toUpperCase()}`); } diff --git a/packages/squad-sdk/templates/scribe-charter.md b/packages/squad-sdk/templates/scribe-charter.md index a2031d072..0ddb2dc88 100644 --- a/packages/squad-sdk/templates/scribe-charter.md +++ b/packages/squad-sdk/templates/scribe-charter.md @@ -211,11 +211,11 @@ After every substantial work session: │ ├── river-jwt-auth.md │ └── kai-component-lib.md ├── orchestration-log/ # Per-spawn log entries -│ ├── 2025-07-01T10-00-river.md -│ └── 2025-07-01T10-00-kai.md +│ ├── {timestamp}-river.md +│ └── {timestamp}-kai.md ├── log/ # Session history — searchable record -│ ├── 2025-07-01-setup.md -│ └── 2025-07-02-api.md +│ ├── {date}-setup.md +│ └── {date}-api.md └── agents/ ├── kai/history.md # Kai's personal knowledge ├── river/history.md # River's personal knowledge diff --git a/templates/scribe-charter.md b/templates/scribe-charter.md index a2031d072..0ddb2dc88 100644 --- a/templates/scribe-charter.md +++ b/templates/scribe-charter.md @@ -211,11 +211,11 @@ After every substantial work session: │ ├── river-jwt-auth.md │ └── kai-component-lib.md ├── orchestration-log/ # Per-spawn log entries -│ ├── 2025-07-01T10-00-river.md -│ └── 2025-07-01T10-00-kai.md +│ ├── {timestamp}-river.md +│ └── {timestamp}-kai.md ├── log/ # Session history — searchable record -│ ├── 2025-07-01-setup.md -│ └── 2025-07-02-api.md +│ ├── {date}-setup.md +│ └── {date}-api.md └── agents/ ├── kai/history.md # Kai's personal knowledge ├── river/history.md # River's personal knowledge diff --git a/test/fan-out.test.ts b/test/fan-out.test.ts index cc0fbd054..074a74856 100644 --- a/test/fan-out.test.ts +++ b/test/fan-out.test.ts @@ -120,6 +120,27 @@ describe('spawnParallel', () => { expect(sentPrompt).toContain('Related to PRD-5'); }); + it('should include current date in prompt', async () => { + const configs: AgentSpawnConfig[] = [ + { agentName: 'fenster', task: 'Build feature' }, + ]; + + const results = await spawnParallel(configs, mockDeps); + + expect(results[0].status).toBe('success'); + + const createSessionMock = mockDeps.createSession as any; + const mockSession = await createSessionMock.mock.results[0].value; + const sentPrompt = mockSession.sendMessage.mock.calls[0][0].prompt; + + // Prompt must contain a Current Date with ISO timestamp + expect(sentPrompt).toContain('**Current Date:**'); + const dateMatch = sentPrompt.match(/\*\*Current Date:\*\*\s*(\S+)/); + expect(dateMatch).not.toBeNull(); + const timestamp = dateMatch![1]; + expect(timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/); + }); + it('should handle model overrides', async () => { const configs: AgentSpawnConfig[] = [ {