Scope SOP and API catalogues to the agent's role
Every agent received the full 15-SOP, 11-API-doc bundle regardless of what the agent was authorised to do — individual contributors were paying token cost on hiring pipelines, budget requests, and sprint management they had no authority to touch. The prompt-cache prefix also grew monotonically with every SOP added across the product lifetime. Introduce role-scoped bundles (executive / manager / IC) keyed on the same isCEO / isManager split the rest of the system prompt already uses. Each bundle lists the procedures and endpoints the role can actually execute under its decision authority. Shared SOPs (standup, communication, quality, incident response, knowledge) appear in every bundle so no role loses coverage of universal behaviour.
This commit is contained in:
1 parent
9c65291973
commit
5dd74a477d
3 files changed
+112
-15
No files matched your search
@@ -13,10 +13,52 @@ import meetingsEn from "./api-docs/meetings.en.md?raw";
|
||||
import agentsEn from "./api-docs/agents.en.md?raw";
|
||||
import sprintsEn from "./api-docs/sprints.en.md?raw";
|
||||
|
||||
const API_DOC_SECTIONS: string[] = [
|
||||
headerEn, agentControlEn, tasksEn, goalsProjectsEn, approvalsEn,
|
||||
messagesEn, filesEn, knowledgeEn, meetingsEn, agentsEn, sprintsEn,
|
||||
];
|
||||
/**
|
||||
* Role-scoped API documentation bundles.
|
||||
*
|
||||
* Every agent used to receive the full endpoint catalogue. Individual
|
||||
* contributors paid the token cost for hiring / budget / org-design
|
||||
* endpoints they had no authority to call; cache churn followed any
|
||||
* api-docs edit. Scope each bundle to the operations the role can
|
||||
* actually perform under its decision authority.
|
||||
*/
|
||||
export type ApiAudience = "executive" | "manager" | "individual_contributor";
|
||||
|
||||
const SECTIONS_BY_ROLE: Record<ApiAudience, string[]> = {
|
||||
executive: [
|
||||
headerEn,
|
||||
agentControlEn,
|
||||
tasksEn,
|
||||
goalsProjectsEn,
|
||||
approvalsEn,
|
||||
messagesEn,
|
||||
filesEn,
|
||||
knowledgeEn,
|
||||
meetingsEn,
|
||||
agentsEn,
|
||||
sprintsEn,
|
||||
],
|
||||
manager: [
|
||||
headerEn,
|
||||
agentControlEn,
|
||||
tasksEn,
|
||||
goalsProjectsEn,
|
||||
approvalsEn,
|
||||
messagesEn,
|
||||
filesEn,
|
||||
knowledgeEn,
|
||||
meetingsEn,
|
||||
sprintsEn,
|
||||
],
|
||||
individual_contributor: [
|
||||
headerEn,
|
||||
tasksEn,
|
||||
messagesEn,
|
||||
filesEn,
|
||||
knowledgeEn,
|
||||
meetingsEn,
|
||||
],
|
||||
};
|
||||
|
||||
function render(template: string, ctx: PromptContext): string {
|
||||
const connectorIds = ctx.allConnectors && ctx.allConnectors.length > 0
|
||||
@@ -30,7 +72,9 @@ function render(template: string, ctx: PromptContext): string {
|
||||
.replace(/\{\{connectorIds\}\}/g, connectorIds);
|
||||
}
|
||||
|
||||
export function buildAPISection(ctx: PromptContext): string {
|
||||
const body = API_DOC_SECTIONS.map((s) => render(s, ctx).trimEnd()).join("\n\n");
|
||||
export function buildAPISection(ctx: PromptContext, audience: ApiAudience): string {
|
||||
const body = SECTIONS_BY_ROLE[audience]
|
||||
.map((s) => render(s, ctx).trimEnd())
|
||||
.join("\n\n");
|
||||
return `${body}\n${buildSocialSection(ctx)}`;
|
||||
}
|
||||
@@ -14,15 +14,67 @@ import sop013En from "./sops/sop-013-incident.en.md?raw";
|
||||
import sop014En from "./sops/sop-014-hiring-pipeline.en.md?raw";
|
||||
import sop015En from "./sops/sop-015-knowledge.en.md?raw";
|
||||
|
||||
const SOPS_IN_ORDER: string[] = [
|
||||
sop001En, sop002En, sop003En, sop004En, sop005En,
|
||||
sop006En, sop007En, sop008En, sop009En, sop010En,
|
||||
sop011En, sop012En, sop013En, sop014En, sop015En,
|
||||
];
|
||||
/**
|
||||
* Role-scoped SOP bundles.
|
||||
*
|
||||
* The system prompt previously concatenated all 15 SOPs for every agent
|
||||
* regardless of role. Individual contributors were receiving the hiring
|
||||
* pipeline, cadence, and budget SOPs they had no authority to act on;
|
||||
* every wake paid the token bill. The prompt-cache prefix also grew
|
||||
* with each SOP added over the life of the product.
|
||||
*
|
||||
* Each role receives the procedures it can execute under its decision
|
||||
* authority (see `operating-en.ts#authorityRules`). SOPs that every
|
||||
* agent must know regardless of seat — standup, communication,
|
||||
* incident response, knowledge contribution — appear in every bundle.
|
||||
*/
|
||||
|
||||
const SOP_BY_ROLE = {
|
||||
executive: [
|
||||
sop001En, // standup
|
||||
sop003En, // delegation
|
||||
sop004En, // code-review (CEO still reviews top-level deliverables)
|
||||
sop005En, // hiring
|
||||
sop006En, // escalation
|
||||
sop007En, // communication
|
||||
sop008En, // cross-department
|
||||
sop009En, // documents
|
||||
sop010En, // budget
|
||||
sop012En, // cadence
|
||||
sop013En, // incident
|
||||
sop014En, // hiring-pipeline
|
||||
sop015En, // knowledge
|
||||
],
|
||||
manager: [
|
||||
sop001En, // standup
|
||||
sop002En, // task-lifecycle
|
||||
sop003En, // delegation
|
||||
sop004En, // code-review
|
||||
sop006En, // escalation
|
||||
sop007En, // communication
|
||||
sop008En, // cross-department
|
||||
sop009En, // documents
|
||||
sop011En, // quality
|
||||
sop013En, // incident
|
||||
sop015En, // knowledge
|
||||
],
|
||||
individual_contributor: [
|
||||
sop001En, // standup
|
||||
sop002En, // task-lifecycle
|
||||
sop004En, // code-review
|
||||
sop006En, // escalation
|
||||
sop007En, // communication
|
||||
sop009En, // documents
|
||||
sop011En, // quality
|
||||
sop015En, // knowledge
|
||||
],
|
||||
} as const;
|
||||
|
||||
export type SopAudience = keyof typeof SOP_BY_ROLE;
|
||||
|
||||
const SOP_HEADING = "# Standard Operating Procedures";
|
||||
|
||||
export function buildSOPSection(): string {
|
||||
const body = SOPS_IN_ORDER.map((text) => text.trimEnd()).join("\n\n");
|
||||
export function buildSOPSection(audience: SopAudience): string {
|
||||
const body = SOP_BY_ROLE[audience].map((text) => text.trimEnd()).join("\n\n");
|
||||
return `${SOP_HEADING}\n\n${body}\n`;
|
||||
}
|
||||
@@ -198,8 +198,9 @@ export function buildSystemPrompt(ctx: PromptContext): string {
|
||||
const approvalsSection = buildPendingApprovalsSection(ctx.pendingApprovals);
|
||||
if (approvalsSection) sections.push(approvalsSection);
|
||||
|
||||
sections.push(buildSOPSection());
|
||||
sections.push(buildAPISection(ctx));
|
||||
const audience = isCEO ? "executive" : isManager ? "manager" : "individual_contributor";
|
||||
sections.push(buildSOPSection(audience));
|
||||
sections.push(buildAPISection(ctx, audience));
|
||||
|
||||
if (ctx.recentComments.length > 0) {
|
||||
const lines = ctx.recentComments.slice(0, 10)
|
||||
|
||||
Reference in new issue
Block a user