feat: split assistant persona from worker persona

This commit is contained in:
zenord
2026-08-18 22:49:05 +08:00
parent ffedf616e3
commit 2409922d55
8 changed files with 69 additions and 5 deletions
+1
View File
@@ -57,6 +57,7 @@ export async function runSetup(configPath?: string, options: SetupOptions = {}):
id: botId,
workspace,
persona,
assistantPersona: isTemplate ? "" : current.bot.assistantPersona,
agent: configExists ? current.bot.agent : {
id: selected!.id,
command: selected!.command,
+1
View File
@@ -37,6 +37,7 @@ const botSchema = z.object({
id: botIdSchema,
workspace: z.string().min(1),
persona: z.string().default(""),
assistantPersona: z.string().default(""),
agent: agentSchema,
skills: z.array(skillSchema).default([]),
permissions: permissionPolicySchema.default({})
+5 -2
View File
@@ -2,7 +2,7 @@ import crypto from "node:crypto";
import type { AppConfig, BotConfig } from "../config.js";
import { SkillLoader, type LoadedSkill } from "./skill-loader.js";
const BOOTSTRAP_SCHEMA_VERSION = 6;
const BOOTSTRAP_SCHEMA_VERSION = 7;
export interface ResolvedBot extends BotConfig {
loadedSkills: LoadedSkill[];
@@ -21,6 +21,7 @@ export class BotProfileResolver {
id: config.bot.id,
workspace: config.bot.workspace,
persona: config.bot.persona,
assistantPersona: config.bot.assistantPersona,
agent: config.bot.agent,
permissions: config.bot.permissions,
skills: loadedSkills.map(({ id, file, hash }) => ({ id, file, hash }))
@@ -36,12 +37,14 @@ export class BotProfileResolver {
}
function buildAssistantBootstrap(bot: BotConfig): string {
const persona = bot.assistantPersona || bot.persona;
return [
`Initialize this ACP session with gori-agent assistant bootstrap schema v${BOOTSTRAP_SCHEMA_VERSION}. Treat these instructions as persistent context. Reply only with READY.`,
`Bot: ${bot.id}`,
`Workspace: ${bot.workspace}`,
bot.persona ? `Persona:\n${bot.persona}` : "Persona: general coding assistant",
persona ? `Persona:\n${persona}` : "Persona: general coding assistant",
"You are the user-facing Assistant. You have no tools and cannot inspect files, run commands, call Skills or MCP. You chat with the user, propose work, and explain worker feedback. Never claim to have executed anything yourself.",
"Speaking style: talk like a reliable colleague, not a console. Lead with the conclusion, then the reason, then the next step. Avoid protocol jargon and field names; never expose internal words like scheduler, awaiting_user_confirmation, envelope, or action types to the user. Default to 2-4 sentences. Do not repeat proposal IDs unless the user asks. If you are unsure, say so plainly. When something is blocked, always give the user an actionable next step.",
"Every reply must end with exactly one hidden action envelope: <GORI_ASSISTANT_ACTION_V1>{\"reply\":\"...\",\"actions\":[...]}</GORI_ASSISTANT_ACTION_V1>. Put the user-facing text in the JSON \"reply\" field, not outside the envelope.",
"Supported actions: {\"type\":\"create_proposal\",\"title\":\"...\",\"goal\":\"...\",\"steps\":[\"...\"]}; {\"type\":\"confirm\",\"id\":\"optional\",\"answer\":\"optional\"}; {\"type\":\"start_next\"}; {\"type\":\"cancel\",\"id\":\"optional\"}; {\"type\":\"stop\"}. Use an empty actions array when no state change is needed.",
"A proposal only starts after the user confirms it. Confirming a proposal whose worker reported SUCCESS marks it completed; confirming a FAILED proposal marks it failed; to retry a failed proposal, confirm with answer \"retry\". When a worker asks a question (NEEDS_CONFIRMATION), confirm with the user's answer to continue the same worker. \"stop\" terminates the active worker and cancels its proposal; \"start_next\" starts the oldest confirmed queued proposal. Never invent other actions or statuses.",