feat: add runtime context awareness — system.info tool + date/time in system prompt
- assembleSystemPrompt() now injects '# Runtime Context' with current date/time - New system.info tool: date, time, hostname, platform, arch, uptime, memory, Node.js version - Tool available in all profiles (minimal/messaging/coding/full) - 983 tests passing (+7 new)
This commit is contained in:
+20
-11
@@ -24,7 +24,7 @@ describe('assembleSystemPrompt', () => {
|
||||
const dir = makeTempDir();
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir] });
|
||||
|
||||
expect(result.prompt).toBe(
|
||||
expect(result.prompt).toContain(
|
||||
'You are Flynn, a helpful personal AI assistant. Be direct, concise, and helpful. Use markdown when it improves readability.',
|
||||
);
|
||||
expect(result.loadedFiles).toEqual([]);
|
||||
@@ -36,7 +36,7 @@ describe('assembleSystemPrompt', () => {
|
||||
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir] });
|
||||
|
||||
expect(result.prompt).toBe('You are Flynn.');
|
||||
expect(result.prompt).toContain('You are Flynn.');
|
||||
expect(result.loadedFiles).toHaveLength(1);
|
||||
expect(result.loadedFiles[0]).toContain('SOUL.md');
|
||||
});
|
||||
@@ -47,7 +47,7 @@ describe('assembleSystemPrompt', () => {
|
||||
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir] });
|
||||
|
||||
expect(result.prompt).toBe('# Agent Instructions\n\nFollow these rules.');
|
||||
expect(result.prompt).toContain('# Agent Instructions\n\nFollow these rules.');
|
||||
expect(result.loadedFiles).toHaveLength(1);
|
||||
expect(result.loadedFiles[0]).toContain('AGENTS.md');
|
||||
});
|
||||
@@ -62,7 +62,7 @@ describe('assembleSystemPrompt', () => {
|
||||
|
||||
expect(result.loadedFiles).toHaveLength(3);
|
||||
// Verify correct ordering: SOUL → AGENTS → USER
|
||||
expect(result.prompt).toBe(
|
||||
expect(result.prompt).toContain(
|
||||
'I am Flynn.\n\n# Agent Instructions\n\nBe helpful.\n\n# User Context\n\nUser likes cats.',
|
||||
);
|
||||
});
|
||||
@@ -75,7 +75,7 @@ describe('assembleSystemPrompt', () => {
|
||||
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir1, dir2] });
|
||||
|
||||
expect(result.prompt).toBe('Primary identity.');
|
||||
expect(result.prompt).toContain('Primary identity.');
|
||||
expect(result.loadedFiles).toHaveLength(1);
|
||||
expect(result.loadedFiles[0]).toContain(dir1);
|
||||
});
|
||||
@@ -87,7 +87,7 @@ describe('assembleSystemPrompt', () => {
|
||||
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir1, dir2] });
|
||||
|
||||
expect(result.prompt).toBe('Fallback identity.');
|
||||
expect(result.prompt).toContain('Fallback identity.');
|
||||
expect(result.loadedFiles[0]).toContain(dir2);
|
||||
});
|
||||
|
||||
@@ -102,7 +102,7 @@ describe('assembleSystemPrompt', () => {
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.prompt).toBe(
|
||||
expect(result.prompt).toContain(
|
||||
'Base identity.\n\n# Custom Rules\n\nAlways be polite.',
|
||||
);
|
||||
});
|
||||
@@ -114,7 +114,7 @@ describe('assembleSystemPrompt', () => {
|
||||
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir] });
|
||||
|
||||
expect(result.prompt).toBe(
|
||||
expect(result.prompt).toContain(
|
||||
'You are Flynn, a helpful personal AI assistant. Be direct, concise, and helpful. Use markdown when it improves readability.',
|
||||
);
|
||||
expect(result.loadedFiles).toEqual([]);
|
||||
@@ -132,7 +132,7 @@ describe('assembleSystemPrompt', () => {
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.prompt).toBe(
|
||||
expect(result.prompt).toContain(
|
||||
'Base identity.\n\n# Populated\n\nHas content.',
|
||||
);
|
||||
});
|
||||
@@ -161,7 +161,7 @@ describe('assembleSystemPrompt', () => {
|
||||
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir] });
|
||||
|
||||
expect(result.prompt).toBe('I am Flynn.');
|
||||
expect(result.prompt).toContain('I am Flynn.');
|
||||
});
|
||||
|
||||
it('mixes files from different search directories', () => {
|
||||
@@ -173,6 +173,15 @@ describe('assembleSystemPrompt', () => {
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir1, dir2] });
|
||||
|
||||
expect(result.loadedFiles).toHaveLength(2);
|
||||
expect(result.prompt).toBe('Primary soul.\n\n# Agent Instructions\n\nAgent rules.');
|
||||
expect(result.prompt).toContain('Primary soul.\n\n# Agent Instructions\n\nAgent rules.');
|
||||
});
|
||||
|
||||
it('always includes Runtime Context section', () => {
|
||||
const dir = makeTempDir();
|
||||
writeFileSync(join(dir, 'SOUL.md'), 'I am Flynn.');
|
||||
const result = assembleSystemPrompt({ searchDirs: [dir] });
|
||||
expect(result.prompt).toContain('# Runtime Context');
|
||||
expect(result.prompt).toContain('Current date:');
|
||||
expect(result.prompt).toContain('Current time:');
|
||||
});
|
||||
});
|
||||
|
||||
+20
-3
@@ -63,10 +63,27 @@ export function assembleSystemPrompt(config: PromptTemplateConfig): PromptTempla
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback if nothing was loaded
|
||||
if (sections.length === 0) {
|
||||
// Inject current date/time as runtime context
|
||||
const now = new Date();
|
||||
const dateStr = now.toLocaleDateString('en-US', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
});
|
||||
const timeStr = now.toLocaleTimeString('en-US', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
timeZoneName: 'short',
|
||||
hour12: false,
|
||||
});
|
||||
const runtimeContext = `# Runtime Context\n\nCurrent date: ${dateStr}\nCurrent time: ${timeStr}`;
|
||||
sections.push(runtimeContext);
|
||||
|
||||
// Fallback if only the runtime context was loaded (no actual prompt files)
|
||||
if (sections.length === 1) {
|
||||
return {
|
||||
prompt: 'You are Flynn, a helpful personal AI assistant. Be direct, concise, and helpful. Use markdown when it improves readability.',
|
||||
prompt: `You are Flynn, a helpful personal AI assistant. Be direct, concise, and helpful. Use markdown when it improves readability.\n\n${runtimeContext}`,
|
||||
loadedFiles: [],
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user