fix: lazy session_id — generated on first agent invocation, not at startup
This commit is contained in:
parent
cb618a195e
commit
a9b2d43f84
@ -9,8 +9,12 @@
|
|||||||
"work_dir": "/root/projects/team-board",
|
"work_dir": "/root/projects/team-board",
|
||||||
"model": "sonnet",
|
"model": "sonnet",
|
||||||
"provider": "anthropic",
|
"provider": "anthropic",
|
||||||
"capabilities": ["coding", "review"],
|
"capabilities": [
|
||||||
|
"coding",
|
||||||
|
"review"
|
||||||
|
],
|
||||||
"max_concurrent_tasks": 2,
|
"max_concurrent_tasks": 2,
|
||||||
"heartbeat_interval_sec": 30,
|
"heartbeat_interval_sec": 30,
|
||||||
"allowed_paths": []
|
"allowed_paths": [],
|
||||||
|
"session_id": "858c3419-e6a6-4487-940d-f28508784a49"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,33 @@ export interface AgentConfig {
|
|||||||
allowedPaths: string[];
|
allowedPaths: string[];
|
||||||
/** Persistent session UUID — survives renames. Stored in agent.json. */
|
/** Persistent session UUID — survives renames. Stored in agent.json. */
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
|
/** Internal: path to config file for lazy session_id write-back */
|
||||||
|
_configPath: string | null;
|
||||||
|
/** Internal: parsed config data for write-back */
|
||||||
|
_configData: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure agent has a persistent session_id.
|
||||||
|
* Call lazily on first agent invocation, not at startup.
|
||||||
|
* Generates UUID and writes it back to agent.json.
|
||||||
|
*/
|
||||||
|
export function ensureSessionId(config: AgentConfig): string {
|
||||||
|
if (config.sessionId) return config.sessionId;
|
||||||
|
|
||||||
|
const id = crypto.randomUUID();
|
||||||
|
config.sessionId = id;
|
||||||
|
|
||||||
|
if (config._configPath) {
|
||||||
|
try {
|
||||||
|
config._configData.session_id = id;
|
||||||
|
fs.writeFileSync(config._configPath, JSON.stringify(config._configData, null, 2) + '\n');
|
||||||
|
} catch {
|
||||||
|
// Non-fatal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const homeDir = os.homedir();
|
const homeDir = os.homedir();
|
||||||
@ -162,30 +189,8 @@ export function loadAgentConfig(): AgentConfig {
|
|||||||
apiKey: process.env.PICOGENT_API_KEY || process.env.ANTHROPIC_API_KEY || (file.api_key as string) || '',
|
apiKey: process.env.PICOGENT_API_KEY || process.env.ANTHROPIC_API_KEY || (file.api_key as string) || '',
|
||||||
heartbeatIntervalSec: (file.heartbeat_interval_sec as number) || 30,
|
heartbeatIntervalSec: (file.heartbeat_interval_sec as number) || 30,
|
||||||
allowedPaths: (file.allowed_paths as string[]) || [],
|
allowedPaths: (file.allowed_paths as string[]) || [],
|
||||||
sessionId: ensureSessionId(file, configPath),
|
sessionId: (file.session_id as string) || '',
|
||||||
|
_configPath: configPath,
|
||||||
|
_configData: file,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure agent.json has a persistent session_id.
|
|
||||||
* Generates UUID on first run and writes it back to the config file.
|
|
||||||
*/
|
|
||||||
function ensureSessionId(file: Record<string, unknown>, configPath: string | null): string {
|
|
||||||
if (file.session_id && typeof file.session_id === 'string') {
|
|
||||||
return file.session_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = crypto.randomUUID();
|
|
||||||
|
|
||||||
// Persist to agent.json if we have a path
|
|
||||||
if (configPath) {
|
|
||||||
try {
|
|
||||||
file.session_id = id;
|
|
||||||
fs.writeFileSync(configPath, JSON.stringify(file, null, 2) + '\n');
|
|
||||||
} catch {
|
|
||||||
// Non-fatal — session works in memory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { runAgent } from './agent.js';
|
|||||||
import { TrackerClient } from './tracker/client.js';
|
import { TrackerClient } from './tracker/client.js';
|
||||||
import { createTrackerTools } from './tools/index.js';
|
import { createTrackerTools } from './tools/index.js';
|
||||||
import type { ToolDefinition } from '@mariozechner/pi-coding-agent';
|
import type { ToolDefinition } from '@mariozechner/pi-coding-agent';
|
||||||
import type { AgentConfig } from './config.js';
|
import { ensureSessionId, type AgentConfig } from './config.js';
|
||||||
import type { TrackerEvent, TrackerTask } from './tracker/types.js';
|
import type { TrackerEvent, TrackerTask } from './tracker/types.js';
|
||||||
|
|
||||||
export interface TaskTracker {
|
export interface TaskTracker {
|
||||||
@ -16,20 +16,16 @@ export class EventRouter {
|
|||||||
private log = logger.child({ component: 'event-router' });
|
private log = logger.child({ component: 'event-router' });
|
||||||
private activeTasks = 0;
|
private activeTasks = 0;
|
||||||
private trackerTools: ToolDefinition[];
|
private trackerTools: ToolDefinition[];
|
||||||
/** Single session ID for the entire agent lifetime. */
|
|
||||||
private readonly sessionId: string;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private config: AgentConfig,
|
private config: AgentConfig,
|
||||||
private client: TrackerClient,
|
private client: TrackerClient,
|
||||||
private taskTracker: TaskTracker,
|
private taskTracker: TaskTracker,
|
||||||
) {
|
) {
|
||||||
this.sessionId = config.sessionId;
|
|
||||||
this.trackerTools = createTrackerTools({
|
this.trackerTools = createTrackerTools({
|
||||||
trackerClient: client,
|
trackerClient: client,
|
||||||
agentSlug: config.slug,
|
agentSlug: config.slug,
|
||||||
});
|
});
|
||||||
this.log.info({ toolCount: this.trackerTools.length, sessionId: this.sessionId }, 'Tracker tools registered');
|
this.log.info({ toolCount: this.trackerTools.length }, 'Tracker tools registered');
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleEvent(event: TrackerEvent): Promise<void> {
|
async handleEvent(event: TrackerEvent): Promise<void> {
|
||||||
@ -90,7 +86,7 @@ export class EventRouter {
|
|||||||
let collectedText = '';
|
let collectedText = '';
|
||||||
for await (const msg of runAgent(prompt, {
|
for await (const msg of runAgent(prompt, {
|
||||||
workDir: this.config.workDir,
|
workDir: this.config.workDir,
|
||||||
sessionId: this.sessionId,
|
sessionId: ensureSessionId(this.config),
|
||||||
model: this.config.model,
|
model: this.config.model,
|
||||||
provider: this.config.provider,
|
provider: this.config.provider,
|
||||||
systemPrompt: this.config.prompt || undefined,
|
systemPrompt: this.config.prompt || undefined,
|
||||||
@ -162,7 +158,7 @@ export class EventRouter {
|
|||||||
let collectedText = '';
|
let collectedText = '';
|
||||||
for await (const msg of runAgent(content, {
|
for await (const msg of runAgent(content, {
|
||||||
workDir: this.config.workDir,
|
workDir: this.config.workDir,
|
||||||
sessionId: this.sessionId,
|
sessionId: ensureSessionId(this.config),
|
||||||
model: this.config.model,
|
model: this.config.model,
|
||||||
provider: this.config.provider,
|
provider: this.config.provider,
|
||||||
systemPrompt: this.config.prompt || undefined,
|
systemPrompt: this.config.prompt || undefined,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user