fix: avoid duplicate prompt context
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
- Auto-reply: removed `autoReply` from Discord/Slack/Telegram channel configs; use `requireMention` instead (Telegram topics now support `requireMention` overrides).
|
- Auto-reply: removed `autoReply` from Discord/Slack/Telegram channel configs; use `requireMention` instead (Telegram topics now support `requireMention` overrides).
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
- Agent: avoid duplicating context/skills when SDK rebuilds the system prompt. (#418)
|
||||||
- Signal: reconnect SSE monitor with abortable backoff; log stream errors. Thanks @nexty5870 for PR #430.
|
- Signal: reconnect SSE monitor with abortable backoff; log stream errors. Thanks @nexty5870 for PR #430.
|
||||||
- Gateway: pass resolved provider as messageProvider for agent runs so provider-specific tools are available. Thanks @imfing for PR #389.
|
- Gateway: pass resolved provider as messageProvider for agent runs so provider-specific tools are available. Thanks @imfing for PR #389.
|
||||||
- Discord/Telegram: add per-request retry policy with configurable delays and docs.
|
- Discord/Telegram: add per-request retry policy with configurable delays and docs.
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import type { AgentMessage, AgentTool } from "@mariozechner/pi-agent-core";
|
import type { AgentMessage, AgentTool } from "@mariozechner/pi-agent-core";
|
||||||
import { SessionManager } from "@mariozechner/pi-coding-agent";
|
import {
|
||||||
|
buildSystemPrompt,
|
||||||
|
SessionManager,
|
||||||
|
} from "@mariozechner/pi-coding-agent";
|
||||||
import { Type } from "@sinclair/typebox";
|
import { Type } from "@sinclair/typebox";
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import {
|
import {
|
||||||
applyGoogleTurnOrderingFix,
|
applyGoogleTurnOrderingFix,
|
||||||
buildEmbeddedSandboxInfo,
|
buildEmbeddedSandboxInfo,
|
||||||
|
createSystemPromptAppender,
|
||||||
splitSdkTools,
|
splitSdkTools,
|
||||||
} from "./pi-embedded-runner.js";
|
} from "./pi-embedded-runner.js";
|
||||||
import type { SandboxContext } from "./sandbox.js";
|
import type { SandboxContext } from "./sandbox.js";
|
||||||
@@ -105,6 +109,22 @@ describe("splitSdkTools", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("createSystemPromptAppender", () => {
|
||||||
|
it("appends without duplicating context files", () => {
|
||||||
|
const sentinel = "CONTEXT_SENTINEL_42";
|
||||||
|
const defaultPrompt = buildSystemPrompt({
|
||||||
|
cwd: "/tmp",
|
||||||
|
contextFiles: [{ path: "/tmp/AGENTS.md", content: sentinel }],
|
||||||
|
});
|
||||||
|
const appender = createSystemPromptAppender("APPEND_SECTION");
|
||||||
|
const finalPrompt = appender(defaultPrompt);
|
||||||
|
const occurrences = finalPrompt.split(sentinel).length - 1;
|
||||||
|
expect(typeof appender).toBe("function");
|
||||||
|
expect(occurrences).toBe(1);
|
||||||
|
expect(finalPrompt).toContain("APPEND_SECTION");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("applyGoogleTurnOrderingFix", () => {
|
describe("applyGoogleTurnOrderingFix", () => {
|
||||||
const makeAssistantFirst = () =>
|
const makeAssistantFirst = () =>
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import type {
|
|||||||
} from "@mariozechner/pi-agent-core";
|
} from "@mariozechner/pi-agent-core";
|
||||||
import type { Api, AssistantMessage, Model } from "@mariozechner/pi-ai";
|
import type { Api, AssistantMessage, Model } from "@mariozechner/pi-ai";
|
||||||
import {
|
import {
|
||||||
buildSystemPrompt,
|
|
||||||
createAgentSession,
|
createAgentSession,
|
||||||
discoverAuthStorage,
|
discoverAuthStorage,
|
||||||
discoverModels,
|
discoverModels,
|
||||||
@@ -492,6 +491,16 @@ export function buildEmbeddedSandboxInfo(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createSystemPromptAppender(
|
||||||
|
appendPrompt: string,
|
||||||
|
): (defaultPrompt: string) => string {
|
||||||
|
const trimmed = appendPrompt.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
return (defaultPrompt) => defaultPrompt;
|
||||||
|
}
|
||||||
|
return (defaultPrompt) => `${defaultPrompt}\n\n${appendPrompt}`;
|
||||||
|
}
|
||||||
|
|
||||||
const BUILT_IN_TOOL_NAMES = new Set(["read", "bash", "edit", "write"]);
|
const BUILT_IN_TOOL_NAMES = new Set(["read", "bash", "edit", "write"]);
|
||||||
|
|
||||||
type AnyAgentTool = AgentTool;
|
type AnyAgentTool = AgentTool;
|
||||||
@@ -775,28 +784,23 @@ export async function compactEmbeddedPiSession(params: {
|
|||||||
params.config?.agent?.userTimezone,
|
params.config?.agent?.userTimezone,
|
||||||
);
|
);
|
||||||
const userTime = formatUserTime(new Date(), userTimezone);
|
const userTime = formatUserTime(new Date(), userTimezone);
|
||||||
const systemPrompt = buildSystemPrompt({
|
const appendPrompt = buildAgentSystemPromptAppend({
|
||||||
appendPrompt: buildAgentSystemPromptAppend({
|
workspaceDir: effectiveWorkspace,
|
||||||
workspaceDir: effectiveWorkspace,
|
defaultThinkLevel: params.thinkLevel,
|
||||||
defaultThinkLevel: params.thinkLevel,
|
extraSystemPrompt: params.extraSystemPrompt,
|
||||||
extraSystemPrompt: params.extraSystemPrompt,
|
ownerNumbers: params.ownerNumbers,
|
||||||
ownerNumbers: params.ownerNumbers,
|
reasoningTagHint,
|
||||||
reasoningTagHint,
|
heartbeatPrompt: resolveHeartbeatPrompt(
|
||||||
heartbeatPrompt: resolveHeartbeatPrompt(
|
params.config?.agent?.heartbeat?.prompt,
|
||||||
params.config?.agent?.heartbeat?.prompt,
|
),
|
||||||
),
|
runtimeInfo,
|
||||||
runtimeInfo,
|
sandboxInfo,
|
||||||
sandboxInfo,
|
toolNames: tools.map((tool) => tool.name),
|
||||||
toolNames: tools.map((tool) => tool.name),
|
modelAliasLines: buildModelAliasLines(params.config),
|
||||||
modelAliasLines: buildModelAliasLines(params.config),
|
userTimezone,
|
||||||
userTimezone,
|
userTime,
|
||||||
userTime,
|
|
||||||
}),
|
|
||||||
contextFiles,
|
|
||||||
skills: promptSkills,
|
|
||||||
cwd: effectiveWorkspace,
|
|
||||||
tools,
|
|
||||||
});
|
});
|
||||||
|
const systemPrompt = createSystemPromptAppender(appendPrompt);
|
||||||
|
|
||||||
// Pre-warm session file to bring it into OS page cache
|
// Pre-warm session file to bring it into OS page cache
|
||||||
await prewarmSessionFile(params.sessionFile);
|
await prewarmSessionFile(params.sessionFile);
|
||||||
@@ -1100,28 +1104,23 @@ export async function runEmbeddedPiAgent(params: {
|
|||||||
params.config?.agent?.userTimezone,
|
params.config?.agent?.userTimezone,
|
||||||
);
|
);
|
||||||
const userTime = formatUserTime(new Date(), userTimezone);
|
const userTime = formatUserTime(new Date(), userTimezone);
|
||||||
const systemPrompt = buildSystemPrompt({
|
const appendPrompt = buildAgentSystemPromptAppend({
|
||||||
appendPrompt: buildAgentSystemPromptAppend({
|
workspaceDir: effectiveWorkspace,
|
||||||
workspaceDir: effectiveWorkspace,
|
defaultThinkLevel: thinkLevel,
|
||||||
defaultThinkLevel: thinkLevel,
|
extraSystemPrompt: params.extraSystemPrompt,
|
||||||
extraSystemPrompt: params.extraSystemPrompt,
|
ownerNumbers: params.ownerNumbers,
|
||||||
ownerNumbers: params.ownerNumbers,
|
reasoningTagHint,
|
||||||
reasoningTagHint,
|
heartbeatPrompt: resolveHeartbeatPrompt(
|
||||||
heartbeatPrompt: resolveHeartbeatPrompt(
|
params.config?.agent?.heartbeat?.prompt,
|
||||||
params.config?.agent?.heartbeat?.prompt,
|
),
|
||||||
),
|
runtimeInfo,
|
||||||
runtimeInfo,
|
sandboxInfo,
|
||||||
sandboxInfo,
|
toolNames: tools.map((tool) => tool.name),
|
||||||
toolNames: tools.map((tool) => tool.name),
|
modelAliasLines: buildModelAliasLines(params.config),
|
||||||
modelAliasLines: buildModelAliasLines(params.config),
|
userTimezone,
|
||||||
userTimezone,
|
userTime,
|
||||||
userTime,
|
|
||||||
}),
|
|
||||||
contextFiles,
|
|
||||||
skills: promptSkills,
|
|
||||||
cwd: effectiveWorkspace,
|
|
||||||
tools,
|
|
||||||
});
|
});
|
||||||
|
const systemPrompt = createSystemPromptAppender(appendPrompt);
|
||||||
|
|
||||||
// Pre-warm session file to bring it into OS page cache
|
// Pre-warm session file to bring it into OS page cache
|
||||||
await prewarmSessionFile(params.sessionFile);
|
await prewarmSessionFile(params.sessionFile);
|
||||||
|
|||||||
Reference in New Issue
Block a user