feat(agent): add profile system and improve tools

- Add Agent Profile module for managing agent identity, soul, tools,
  memory, and bootstrap configuration
- Add profile CLI (pnpm agent:profile) for creating/listing/showing profiles
- Default sessionId to UUIDv7 instead of "default"
- Expose Agent.sessionId as public readonly property
- Improve exec/process tools error handling (no more crashes on spawn errors)
- Add 'output' action to process tool for reading stdout/stderr
- Better tool descriptions to guide agent in choosing exec vs process

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jiayuan 2026-01-30 02:47:30 +08:00
parent 46a6cb3061
commit 200b2cefda
15 changed files with 740 additions and 58 deletions

155
src/agent/profile/index.ts Normal file
View file

@ -0,0 +1,155 @@
/**
* Agent Profile
*
* agent
*/
import type { AgentProfile, CreateProfileOptions, ProfileManagerOptions } from "./types.js";
import { DEFAULT_TEMPLATES } from "./templates.js";
import {
ensureProfileDir,
getProfileDir,
loadProfile,
profileExists,
saveProfile,
} from "./storage.js";
export { type AgentProfile, type CreateProfileOptions, type ProfileManagerOptions } from "./types.js";
export { DEFAULT_TEMPLATES } from "./templates.js";
export { getProfileDir, profileExists } from "./storage.js";
/**
* Agent Profile
*
* @param profileId - Profile ID
* @param options -
* @returns AgentProfile
*/
export function createAgentProfile(
profileId: string,
options?: CreateProfileOptions,
): AgentProfile {
const { baseDir, useTemplates = true } = options ?? {};
// 确保目录存在
ensureProfileDir(profileId, { baseDir });
// 创建 profile
const profile: AgentProfile = {
id: profileId,
};
// 如果使用模板,填充默认内容
if (useTemplates) {
profile.soul = DEFAULT_TEMPLATES.soul;
profile.identity = DEFAULT_TEMPLATES.identity;
profile.tools = DEFAULT_TEMPLATES.tools;
profile.memory = DEFAULT_TEMPLATES.memory;
profile.bootstrap = DEFAULT_TEMPLATES.bootstrap;
// 保存到文件
saveProfile(profile, { baseDir });
}
return profile;
}
/**
* Agent Profile
*
* @param profileId - Profile ID
* @param options -
* @returns AgentProfile undefined
*/
export function loadAgentProfile(
profileId: string,
options?: { baseDir?: string | undefined },
): AgentProfile | undefined {
if (!profileExists(profileId, options)) {
return undefined;
}
return loadProfile(profileId, options);
}
/**
* Agent Profile
*
* @param profileId - Profile ID
* @param options -
* @returns AgentProfile
*/
export function getOrCreateAgentProfile(
profileId: string,
options?: CreateProfileOptions,
): AgentProfile {
const existing = loadAgentProfile(profileId, options);
if (existing) {
return existing;
}
return createAgentProfile(profileId, options);
}
/**
* Profile Manager - profile
*/
export class ProfileManager {
private readonly profileId: string;
private readonly baseDir: string | undefined;
private profile: AgentProfile | undefined;
constructor(options: ProfileManagerOptions) {
this.profileId = options.profileId;
this.baseDir = options.baseDir;
}
/** 获取 profile如果未加载则加载 */
getProfile(): AgentProfile | undefined {
if (!this.profile) {
this.profile = loadAgentProfile(this.profileId, { baseDir: this.baseDir });
}
return this.profile;
}
/** 获取或创建 profile */
getOrCreateProfile(useTemplates = true): AgentProfile {
if (!this.profile) {
this.profile = getOrCreateAgentProfile(this.profileId, {
baseDir: this.baseDir,
useTemplates,
});
}
return this.profile;
}
/** 构建 system prompt */
buildSystemPrompt(): string {
const profile = this.getProfile();
if (!profile) {
return "";
}
const parts: string[] = [];
if (profile.identity) {
parts.push(profile.identity);
}
if (profile.soul) {
parts.push(profile.soul);
}
if (profile.tools) {
parts.push(profile.tools);
}
if (profile.memory) {
parts.push(profile.memory);
}
if (profile.bootstrap) {
parts.push(profile.bootstrap);
}
return parts.join("\n\n");
}
}