diff --git a/.changeset/static-environment-section.md b/.changeset/static-environment-section.md new file mode 100644 index 00000000..498348c3 --- /dev/null +++ b/.changeset/static-environment-section.md @@ -0,0 +1,6 @@ +--- +"@perstack/runtime": patch +"perstack": patch +--- + +Remove dynamic content from system prompt to improve cross-run prefix caching diff --git a/packages/runtime/src/messages/instruction-message.ts b/packages/runtime/src/messages/instruction-message.ts index 602aab98..c14c109e 100644 --- a/packages/runtime/src/messages/instruction-message.ts +++ b/packages/runtime/src/messages/instruction-message.ts @@ -1,12 +1,10 @@ +import os from "node:os" import { createId } from "@paralleldrive/cuid2" import { type Expert, type InstructionMessage, isCoordinatorExpert } from "@perstack/core" import { dedent } from "ts-dedent" -function getEnvironmentSection(startedAt: number): string { - const lines = [ - `- Current time: ${new Date(startedAt).toISOString()}`, - `- Working directory: ${process.cwd()}`, - ] +function getEnvironmentSection(): string { + const lines = [`- Platform: ${os.platform()} ${os.release()} (${os.arch()})`] if (process.env.PERSTACK_SANDBOX === "1") { lines.push( "- Sandbox: This is an isolated container environment (Ubuntu). You can freely install packages with `sudo apt-get install` and run arbitrary commands without affecting the host system.", @@ -15,18 +13,18 @@ function getEnvironmentSection(startedAt: number): string { return `Environment:\n${lines.join("\n")}` } -function getDelegateMetaInstruction(startedAt: number): string { +function getDelegateMetaInstruction(): string { return dedent` Before starting work, investigate the workspace and understand the current state. Then use the todo tool to create a plan of action. Work through the todos step by step, marking each completed as you go. When the task is complete, call attemptCompletion with a result parameter containing your final response. When you cannot help, call attemptCompletion without a result. - ${getEnvironmentSection(startedAt)} + ${getEnvironmentSection()} ` } -function getCoordinatorMetaInstruction(startedAt: number): string { +function getCoordinatorMetaInstruction(): string { return dedent` Your role: - Act as the coordinator for the given task: define the task, set goals, and delegate. @@ -62,14 +60,14 @@ function getCoordinatorMetaInstruction(startedAt: number): string { When the task is complete, call attemptCompletion with a result parameter containing your final response. When you cannot help, call attemptCompletion without a result. - ${getEnvironmentSection(startedAt)} + ${getEnvironmentSection()} ` } -export function createInstructionMessage(expert: Expert, startedAt: number): InstructionMessage { +export function createInstructionMessage(expert: Expert): InstructionMessage { const metaInstruction = isCoordinatorExpert(expert.name) - ? getCoordinatorMetaInstruction(startedAt) - : getDelegateMetaInstruction(startedAt) + ? getCoordinatorMetaInstruction() + : getDelegateMetaInstruction() const preamble = dedent` You are Perstack, an AI expert that tackles tasks requested by users by utilizing all available tools. diff --git a/packages/runtime/src/messages/message.test.ts b/packages/runtime/src/messages/message.test.ts index 43b5a35f..93b1b4ed 100644 --- a/packages/runtime/src/messages/message.test.ts +++ b/packages/runtime/src/messages/message.test.ts @@ -551,8 +551,6 @@ describe("@perstack/messages: message", () => { }) describe("@perstack/messages: instruction-message", () => { - const startedAt = 1700000000000 - describe("createInstructionMessage", () => { it("creates instruction message with preamble and expert instruction as separate parts", () => { const expert = { @@ -566,7 +564,7 @@ describe("@perstack/messages: instruction-message", () => { runtime: ["local" as const], minRuntimeVersion: "v1.0" as const, } - const result = createInstructionMessage(expert, startedAt) + const result = createInstructionMessage(expert) expect(result.type).toBe("instructionMessage") expect(result.cache).toBeUndefined() expect(result.contents).toHaveLength(2) @@ -600,7 +598,7 @@ describe("@perstack/messages: instruction-message", () => { runtime: ["local" as const], minRuntimeVersion: "v1.0" as const, } - const result = createInstructionMessage(expert, startedAt) + const result = createInstructionMessage(expert) expect(result.contents).toHaveLength(3) expect(result.contents[2].text).toContain("Always use this skill carefully.") expect(result.contents[2].text).toContain('"test-skill" skill rules:') @@ -628,11 +626,11 @@ describe("@perstack/messages: instruction-message", () => { runtime: ["local" as const], minRuntimeVersion: "v1.0" as const, } - const result = createInstructionMessage(expert, startedAt) + const result = createInstructionMessage(expert) expect(result.contents).toHaveLength(2) }) - it("uses startedAt for timestamp in instruction", () => { + it("includes platform info in environment section", () => { const expert = { key: "test-expert", name: "Test Expert", @@ -644,8 +642,8 @@ describe("@perstack/messages: instruction-message", () => { runtime: ["local" as const], minRuntimeVersion: "v1.0" as const, } - const result = createInstructionMessage(expert, startedAt) - expect(result.contents[0].text).toContain("2023-11-14T22:13:20.000Z") + const result = createInstructionMessage(expert) + expect(result.contents[0].text).toContain("Platform:") }) }) }) diff --git a/packages/runtime/src/state-machine/states/init.ts b/packages/runtime/src/state-machine/states/init.ts index 05022436..1af4cca0 100644 --- a/packages/runtime/src/state-machine/states/init.ts +++ b/packages/runtime/src/state-machine/states/init.ts @@ -34,7 +34,7 @@ export async function initLogic({ return startRun(setting, checkpoint, { initialCheckpoint: checkpoint, inputMessages: [ - createInstructionMessage(expert, setting.startedAt), + createInstructionMessage(expert), createUserMessage([{ type: "textPart", text: setting.input.text }]), ], model: setting.model,