mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-18 19:50:38 +09:00
Merge branch 'master' into fix/configurable-claimed-api-key-path
This commit is contained in:
commit
c171ff901c
165 changed files with 11349 additions and 1649 deletions
|
|
@ -21,7 +21,7 @@ Core fields:
|
|||
- chrome (boolean, optional): pass --chrome when running Claude
|
||||
- promptTemplate (string, optional): run prompt template
|
||||
- maxTurnsPerRun (number, optional): max turns for one run
|
||||
- dangerouslySkipPermissions (boolean, optional): pass --dangerously-skip-permissions to claude
|
||||
- dangerouslySkipPermissions (boolean, optional, default true): pass --dangerously-skip-permissions to claude; defaults to true because Paperclip runs Claude in headless --print mode where interactive permission prompts cannot be answered
|
||||
- command (string, optional): defaults to "claude"
|
||||
- extraArgs (string[], optional): additional CLI args
|
||||
- env (object, optional): KEY=VALUE environment variables
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import {
|
|||
ensurePathInEnv,
|
||||
resolveCommandForLogs,
|
||||
renderTemplate,
|
||||
renderPaperclipWakePrompt,
|
||||
stringifyPaperclipWakePayload,
|
||||
runChildProcess,
|
||||
} from "@paperclipai/adapter-utils/server-utils";
|
||||
import {
|
||||
|
|
@ -170,6 +172,7 @@ async function buildClaudeRuntimeConfig(input: ClaudeExecutionInput): Promise<Cl
|
|||
const linkedIssueIds = Array.isArray(context.issueIds)
|
||||
? context.issueIds.filter((value): value is string => typeof value === "string" && value.trim().length > 0)
|
||||
: [];
|
||||
const wakePayloadJson = stringifyPaperclipWakePayload(context.paperclipWake);
|
||||
|
||||
if (wakeTaskId) {
|
||||
env.PAPERCLIP_TASK_ID = wakeTaskId;
|
||||
|
|
@ -189,6 +192,9 @@ async function buildClaudeRuntimeConfig(input: ClaudeExecutionInput): Promise<Cl
|
|||
if (linkedIssueIds.length > 0) {
|
||||
env.PAPERCLIP_LINKED_ISSUE_IDS = linkedIssueIds.join(",");
|
||||
}
|
||||
if (wakePayloadJson) {
|
||||
env.PAPERCLIP_WAKE_PAYLOAD_JSON = wakePayloadJson;
|
||||
}
|
||||
if (effectiveWorkspaceCwd) {
|
||||
env.PAPERCLIP_WORKSPACE_CWD = effectiveWorkspaceCwd;
|
||||
}
|
||||
|
|
@ -317,7 +323,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
const effort = asString(config.effort, "");
|
||||
const chrome = asBoolean(config.chrome, false);
|
||||
const maxTurns = asNumber(config.maxTurnsPerRun, 0);
|
||||
const dangerouslySkipPermissions = asBoolean(config.dangerouslySkipPermissions, false);
|
||||
const dangerouslySkipPermissions = asBoolean(config.dangerouslySkipPermissions, true);
|
||||
const instructionsFilePath = asString(config.instructionsFilePath, "").trim();
|
||||
const instructionsFileDir = instructionsFilePath ? `${path.dirname(instructionsFilePath)}/` : "";
|
||||
const commandNotes = instructionsFilePath
|
||||
|
|
@ -398,20 +404,24 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
run: { id: runId, source: "on_demand" },
|
||||
context,
|
||||
};
|
||||
const renderedPrompt = renderTemplate(promptTemplate, templateData);
|
||||
const renderedBootstrapPrompt =
|
||||
!sessionId && bootstrapPromptTemplate.trim().length > 0
|
||||
? renderTemplate(bootstrapPromptTemplate, templateData).trim()
|
||||
: "";
|
||||
const wakePrompt = renderPaperclipWakePrompt(context.paperclipWake, { resumedSession: Boolean(sessionId) });
|
||||
const shouldUseResumeDeltaPrompt = Boolean(sessionId) && wakePrompt.length > 0;
|
||||
const renderedPrompt = shouldUseResumeDeltaPrompt ? "" : renderTemplate(promptTemplate, templateData);
|
||||
const sessionHandoffNote = asString(context.paperclipSessionHandoffMarkdown, "").trim();
|
||||
const prompt = joinPromptSections([
|
||||
renderedBootstrapPrompt,
|
||||
wakePrompt,
|
||||
sessionHandoffNote,
|
||||
renderedPrompt,
|
||||
]);
|
||||
const promptMetrics = {
|
||||
promptChars: prompt.length,
|
||||
bootstrapPromptChars: renderedBootstrapPrompt.length,
|
||||
wakePromptChars: wakePrompt.length,
|
||||
sessionHandoffChars: sessionHandoffNote.length,
|
||||
heartbeatPromptChars: renderedPrompt.length,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export async function testEnvironment(
|
|||
const effort = asString(config.effort, "").trim();
|
||||
const chrome = asBoolean(config.chrome, false);
|
||||
const maxTurns = asNumber(config.maxTurnsPerRun, 0);
|
||||
const dangerouslySkipPermissions = asBoolean(config.dangerouslySkipPermissions, false);
|
||||
const dangerouslySkipPermissions = asBoolean(config.dangerouslySkipPermissions, true);
|
||||
const extraArgs = (() => {
|
||||
const fromExtraArgs = asStringArray(config.extraArgs);
|
||||
if (fromExtraArgs.length > 0) return fromExtraArgs;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import {
|
|||
resolveCommandForLogs,
|
||||
resolvePaperclipDesiredSkillNames,
|
||||
renderTemplate,
|
||||
renderPaperclipWakePrompt,
|
||||
stringifyPaperclipWakePayload,
|
||||
joinPromptSections,
|
||||
runChildProcess,
|
||||
} from "@paperclipai/adapter-utils/server-utils";
|
||||
|
|
@ -313,6 +315,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
const linkedIssueIds = Array.isArray(context.issueIds)
|
||||
? context.issueIds.filter((value): value is string => typeof value === "string" && value.trim().length > 0)
|
||||
: [];
|
||||
const wakePayloadJson = stringifyPaperclipWakePayload(context.paperclipWake);
|
||||
if (wakeTaskId) {
|
||||
env.PAPERCLIP_TASK_ID = wakeTaskId;
|
||||
}
|
||||
|
|
@ -331,6 +334,9 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
if (linkedIssueIds.length > 0) {
|
||||
env.PAPERCLIP_LINKED_ISSUE_IDS = linkedIssueIds.join(",");
|
||||
}
|
||||
if (wakePayloadJson) {
|
||||
env.PAPERCLIP_WAKE_PAYLOAD_JSON = wakePayloadJson;
|
||||
}
|
||||
if (effectiveWorkspaceCwd) {
|
||||
env.PAPERCLIP_WORKSPACE_CWD = effectiveWorkspaceCwd;
|
||||
}
|
||||
|
|
@ -434,11 +440,36 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
}
|
||||
const repoAgentsNote =
|
||||
"Codex exec automatically applies repo-scoped AGENTS.md instructions from the current workspace; Paperclip does not currently suppress that discovery.";
|
||||
const bootstrapPromptTemplate = asString(config.bootstrapPromptTemplate, "");
|
||||
const templateData = {
|
||||
agentId: agent.id,
|
||||
companyId: agent.companyId,
|
||||
runId,
|
||||
company: { id: agent.companyId },
|
||||
agent,
|
||||
run: { id: runId, source: "on_demand" },
|
||||
context,
|
||||
};
|
||||
const renderedBootstrapPrompt =
|
||||
!sessionId && bootstrapPromptTemplate.trim().length > 0
|
||||
? renderTemplate(bootstrapPromptTemplate, templateData).trim()
|
||||
: "";
|
||||
const wakePrompt = renderPaperclipWakePrompt(context.paperclipWake, { resumedSession: Boolean(sessionId) });
|
||||
const shouldUseResumeDeltaPrompt = Boolean(sessionId) && wakePrompt.length > 0;
|
||||
const promptInstructionsPrefix = shouldUseResumeDeltaPrompt ? "" : instructionsPrefix;
|
||||
instructionsChars = promptInstructionsPrefix.length;
|
||||
const commandNotes = (() => {
|
||||
if (!instructionsFilePath) {
|
||||
return [repoAgentsNote];
|
||||
}
|
||||
if (instructionsPrefix.length > 0) {
|
||||
if (shouldUseResumeDeltaPrompt) {
|
||||
return [
|
||||
`Loaded agent instructions from ${instructionsFilePath}`,
|
||||
"Skipped stdin instruction reinjection because an existing Codex session is being resumed with a wake delta.",
|
||||
repoAgentsNote,
|
||||
];
|
||||
}
|
||||
return [
|
||||
`Loaded agent instructions from ${instructionsFilePath}`,
|
||||
`Prepended instructions + path directive to stdin prompt (relative references from ${instructionsDir}).`,
|
||||
|
|
@ -450,25 +481,12 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
repoAgentsNote,
|
||||
];
|
||||
})();
|
||||
const bootstrapPromptTemplate = asString(config.bootstrapPromptTemplate, "");
|
||||
const templateData = {
|
||||
agentId: agent.id,
|
||||
companyId: agent.companyId,
|
||||
runId,
|
||||
company: { id: agent.companyId },
|
||||
agent,
|
||||
run: { id: runId, source: "on_demand" },
|
||||
context,
|
||||
};
|
||||
const renderedPrompt = renderTemplate(promptTemplate, templateData);
|
||||
const renderedBootstrapPrompt =
|
||||
!sessionId && bootstrapPromptTemplate.trim().length > 0
|
||||
? renderTemplate(bootstrapPromptTemplate, templateData).trim()
|
||||
: "";
|
||||
const renderedPrompt = shouldUseResumeDeltaPrompt ? "" : renderTemplate(promptTemplate, templateData);
|
||||
const sessionHandoffNote = asString(context.paperclipSessionHandoffMarkdown, "").trim();
|
||||
const prompt = joinPromptSections([
|
||||
instructionsPrefix,
|
||||
promptInstructionsPrefix,
|
||||
renderedBootstrapPrompt,
|
||||
wakePrompt,
|
||||
sessionHandoffNote,
|
||||
renderedPrompt,
|
||||
]);
|
||||
|
|
@ -476,6 +494,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
promptChars: prompt.length,
|
||||
instructionsChars,
|
||||
bootstrapPromptChars: renderedBootstrapPrompt.length,
|
||||
wakePromptChars: wakePrompt.length,
|
||||
sessionHandoffChars: sessionHandoffNote.length,
|
||||
heartbeatPromptChars: renderedPrompt.length,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import {
|
|||
resolvePaperclipDesiredSkillNames,
|
||||
removeMaintainerOnlySkillSymlinks,
|
||||
renderTemplate,
|
||||
renderPaperclipWakePrompt,
|
||||
stringifyPaperclipWakePayload,
|
||||
joinPromptSections,
|
||||
runChildProcess,
|
||||
} from "@paperclipai/adapter-utils/server-utils";
|
||||
|
|
@ -219,6 +221,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
const linkedIssueIds = Array.isArray(context.issueIds)
|
||||
? context.issueIds.filter((value): value is string => typeof value === "string" && value.trim().length > 0)
|
||||
: [];
|
||||
const wakePayloadJson = stringifyPaperclipWakePayload(context.paperclipWake);
|
||||
if (wakeTaskId) {
|
||||
env.PAPERCLIP_TASK_ID = wakeTaskId;
|
||||
}
|
||||
|
|
@ -237,6 +240,9 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
if (linkedIssueIds.length > 0) {
|
||||
env.PAPERCLIP_LINKED_ISSUE_IDS = linkedIssueIds.join(",");
|
||||
}
|
||||
if (wakePayloadJson) {
|
||||
env.PAPERCLIP_WAKE_PAYLOAD_JSON = wakePayloadJson;
|
||||
}
|
||||
if (effectiveWorkspaceCwd) {
|
||||
env.PAPERCLIP_WORKSPACE_CWD = effectiveWorkspaceCwd;
|
||||
}
|
||||
|
|
@ -352,16 +358,19 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
run: { id: runId, source: "on_demand" },
|
||||
context,
|
||||
};
|
||||
const renderedPrompt = renderTemplate(promptTemplate, templateData);
|
||||
const renderedBootstrapPrompt =
|
||||
!sessionId && bootstrapPromptTemplate.trim().length > 0
|
||||
? renderTemplate(bootstrapPromptTemplate, templateData).trim()
|
||||
: "";
|
||||
const wakePrompt = renderPaperclipWakePrompt(context.paperclipWake, { resumedSession: Boolean(sessionId) });
|
||||
const shouldUseResumeDeltaPrompt = Boolean(sessionId) && wakePrompt.length > 0;
|
||||
const renderedPrompt = shouldUseResumeDeltaPrompt ? "" : renderTemplate(promptTemplate, templateData);
|
||||
const sessionHandoffNote = asString(context.paperclipSessionHandoffMarkdown, "").trim();
|
||||
const paperclipEnvNote = renderPaperclipEnvNote(env);
|
||||
const prompt = joinPromptSections([
|
||||
instructionsPrefix,
|
||||
renderedBootstrapPrompt,
|
||||
wakePrompt,
|
||||
sessionHandoffNote,
|
||||
paperclipEnvNote,
|
||||
renderedPrompt,
|
||||
|
|
@ -370,6 +379,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
promptChars: prompt.length,
|
||||
instructionsChars,
|
||||
bootstrapPromptChars: renderedBootstrapPrompt.length,
|
||||
wakePromptChars: wakePrompt.length,
|
||||
sessionHandoffChars: sessionHandoffNote.length,
|
||||
runtimeNoteChars: paperclipEnvNote.length,
|
||||
heartbeatPromptChars: renderedPrompt.length,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import {
|
|||
removeMaintainerOnlySkillSymlinks,
|
||||
parseObject,
|
||||
renderTemplate,
|
||||
renderPaperclipWakePrompt,
|
||||
stringifyPaperclipWakePayload,
|
||||
runChildProcess,
|
||||
} from "@paperclipai/adapter-utils/server-utils";
|
||||
import { DEFAULT_GEMINI_LOCAL_MODEL } from "../index.js";
|
||||
|
|
@ -193,12 +195,14 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
const linkedIssueIds = Array.isArray(context.issueIds)
|
||||
? context.issueIds.filter((value): value is string => typeof value === "string" && value.trim().length > 0)
|
||||
: [];
|
||||
const wakePayloadJson = stringifyPaperclipWakePayload(context.paperclipWake);
|
||||
if (wakeTaskId) env.PAPERCLIP_TASK_ID = wakeTaskId;
|
||||
if (wakeReason) env.PAPERCLIP_WAKE_REASON = wakeReason;
|
||||
if (wakeCommentId) env.PAPERCLIP_WAKE_COMMENT_ID = wakeCommentId;
|
||||
if (approvalId) env.PAPERCLIP_APPROVAL_ID = approvalId;
|
||||
if (approvalStatus) env.PAPERCLIP_APPROVAL_STATUS = approvalStatus;
|
||||
if (linkedIssueIds.length > 0) env.PAPERCLIP_LINKED_ISSUE_IDS = linkedIssueIds.join(",");
|
||||
if (wakePayloadJson) env.PAPERCLIP_WAKE_PAYLOAD_JSON = wakePayloadJson;
|
||||
if (effectiveWorkspaceCwd) env.PAPERCLIP_WORKSPACE_CWD = effectiveWorkspaceCwd;
|
||||
if (workspaceSource) env.PAPERCLIP_WORKSPACE_SOURCE = workspaceSource;
|
||||
if (workspaceId) env.PAPERCLIP_WORKSPACE_ID = workspaceId;
|
||||
|
|
@ -295,17 +299,20 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
run: { id: runId, source: "on_demand" },
|
||||
context,
|
||||
};
|
||||
const renderedPrompt = renderTemplate(promptTemplate, templateData);
|
||||
const renderedBootstrapPrompt =
|
||||
!sessionId && bootstrapPromptTemplate.trim().length > 0
|
||||
? renderTemplate(bootstrapPromptTemplate, templateData).trim()
|
||||
: "";
|
||||
const wakePrompt = renderPaperclipWakePrompt(context.paperclipWake, { resumedSession: Boolean(sessionId) });
|
||||
const shouldUseResumeDeltaPrompt = Boolean(sessionId) && wakePrompt.length > 0;
|
||||
const renderedPrompt = shouldUseResumeDeltaPrompt ? "" : renderTemplate(promptTemplate, templateData);
|
||||
const sessionHandoffNote = asString(context.paperclipSessionHandoffMarkdown, "").trim();
|
||||
const paperclipEnvNote = renderPaperclipEnvNote(env);
|
||||
const apiAccessNote = renderApiAccessNote(env);
|
||||
const prompt = joinPromptSections([
|
||||
instructionsPrefix,
|
||||
renderedBootstrapPrompt,
|
||||
wakePrompt,
|
||||
sessionHandoffNote,
|
||||
paperclipEnvNote,
|
||||
apiAccessNote,
|
||||
|
|
@ -315,6 +322,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
promptChars: prompt.length,
|
||||
instructionsChars: instructionsPrefix.length,
|
||||
bootstrapPromptChars: renderedBootstrapPrompt.length,
|
||||
wakePromptChars: wakePrompt.length,
|
||||
sessionHandoffChars: sessionHandoffNote.length,
|
||||
runtimeNoteChars: paperclipEnvNote.length + apiAccessNote.length,
|
||||
heartbeatPromptChars: renderedPrompt.length,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,14 @@ import type {
|
|||
AdapterExecutionResult,
|
||||
AdapterRuntimeServiceReport,
|
||||
} from "@paperclipai/adapter-utils";
|
||||
import { asNumber, asString, buildPaperclipEnv, parseObject } from "@paperclipai/adapter-utils/server-utils";
|
||||
import {
|
||||
asNumber,
|
||||
asString,
|
||||
buildPaperclipEnv,
|
||||
parseObject,
|
||||
renderPaperclipWakePrompt,
|
||||
stringifyPaperclipWakePayload,
|
||||
} from "@paperclipai/adapter-utils/server-utils";
|
||||
import crypto, { randomUUID } from "node:crypto";
|
||||
import { WebSocket } from "ws";
|
||||
|
||||
|
|
@ -341,7 +348,12 @@ function buildPaperclipEnvForWake(ctx: AdapterExecutionContext, wakePayload: Wak
|
|||
return paperclipEnv;
|
||||
}
|
||||
|
||||
function buildWakeText(payload: WakePayload, paperclipEnv: Record<string, string>, claimedApiKeyPath: string): string {
|
||||
function buildWakeText(
|
||||
payload: WakePayload,
|
||||
paperclipEnv: Record<string, string>,
|
||||
structuredWakePrompt: string,
|
||||
): string {
|
||||
const claimedApiKeyPath = "~/.openclaw/workspace/paperclip-claimed-api-key.json";
|
||||
const orderedKeys = [
|
||||
"PAPERCLIP_RUN_ID",
|
||||
"PAPERCLIP_AGENT_ID",
|
||||
|
|
@ -409,6 +421,12 @@ function buildWakeText(payload: WakePayload, paperclipEnv: Record<string, string
|
|||
"- POST /api/issues/{issueId}/comments",
|
||||
"- PATCH /api/issues/{issueId}",
|
||||
"- POST /api/companies/{companyId}/issues (when asked to create a new issue)",
|
||||
...(structuredWakePrompt
|
||||
? [
|
||||
"",
|
||||
structuredWakePrompt,
|
||||
]
|
||||
: []),
|
||||
"",
|
||||
"Complete the workflow in this run.",
|
||||
];
|
||||
|
|
@ -420,6 +438,17 @@ function appendWakeText(baseText: string, wakeText: string): string {
|
|||
return trimmedBase.length > 0 ? `${trimmedBase}\n\n${wakeText}` : wakeText;
|
||||
}
|
||||
|
||||
function joinWakePayloadSections(structuredWakePrompt: string, structuredWakeJson: string): string {
|
||||
const sections = [
|
||||
structuredWakePrompt.trim(),
|
||||
"Structured wake payload JSON:",
|
||||
"```json",
|
||||
structuredWakeJson,
|
||||
"```",
|
||||
].filter((entry) => entry.trim().length > 0);
|
||||
return sections.join("\n");
|
||||
}
|
||||
|
||||
function buildStandardPaperclipPayload(
|
||||
ctx: AdapterExecutionContext,
|
||||
wakePayload: WakePayload,
|
||||
|
|
@ -452,6 +481,10 @@ function buildStandardPaperclipPayload(
|
|||
approvalStatus: wakePayload.approvalStatus,
|
||||
apiUrl: paperclipEnv.PAPERCLIP_API_URL ?? null,
|
||||
};
|
||||
const structuredWake = parseObject(ctx.context.paperclipWake);
|
||||
if (Object.keys(structuredWake).length > 0) {
|
||||
standardPaperclip.wake = structuredWake;
|
||||
}
|
||||
|
||||
if (workspace) {
|
||||
standardPaperclip.workspace = workspace;
|
||||
|
|
@ -1058,8 +1091,15 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
|
||||
const wakePayload = buildWakePayload(ctx);
|
||||
const paperclipEnv = buildPaperclipEnvForWake(ctx, wakePayload);
|
||||
const claimedApiKeyPath = resolveClaimedApiKeyPath(ctx.config.claimedApiKeyPath);
|
||||
const wakeText = buildWakeText(wakePayload, paperclipEnv, claimedApiKeyPath);
|
||||
const structuredWakePrompt = renderPaperclipWakePrompt(ctx.context.paperclipWake);
|
||||
const structuredWakeJson = stringifyPaperclipWakePayload(ctx.context.paperclipWake);
|
||||
const wakeText = buildWakeText(
|
||||
wakePayload,
|
||||
paperclipEnv,
|
||||
structuredWakeJson
|
||||
? joinWakePayloadSections(structuredWakePrompt, structuredWakeJson)
|
||||
: structuredWakePrompt,
|
||||
);
|
||||
|
||||
const sessionKeyStrategy = normalizeSessionKeyStrategy(ctx.config.sessionKeyStrategy);
|
||||
const configuredSessionKey = nonEmpty(ctx.config.sessionKey);
|
||||
|
|
@ -1081,6 +1121,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
idempotencyKey: ctx.runId,
|
||||
};
|
||||
delete agentParams.text;
|
||||
agentParams.paperclip = paperclipPayload;
|
||||
|
||||
const configuredAgentId = nonEmpty(ctx.config.agentId);
|
||||
if (configuredAgentId && !nonEmpty(agentParams.agentId)) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import {
|
|||
ensurePathInEnv,
|
||||
resolveCommandForLogs,
|
||||
renderTemplate,
|
||||
renderPaperclipWakePrompt,
|
||||
stringifyPaperclipWakePayload,
|
||||
runChildProcess,
|
||||
readPaperclipRuntimeSkillEntries,
|
||||
resolvePaperclipDesiredSkillNames,
|
||||
|
|
@ -154,12 +156,14 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
const linkedIssueIds = Array.isArray(context.issueIds)
|
||||
? context.issueIds.filter((value): value is string => typeof value === "string" && value.trim().length > 0)
|
||||
: [];
|
||||
const wakePayloadJson = stringifyPaperclipWakePayload(context.paperclipWake);
|
||||
if (wakeTaskId) env.PAPERCLIP_TASK_ID = wakeTaskId;
|
||||
if (wakeReason) env.PAPERCLIP_WAKE_REASON = wakeReason;
|
||||
if (wakeCommentId) env.PAPERCLIP_WAKE_COMMENT_ID = wakeCommentId;
|
||||
if (approvalId) env.PAPERCLIP_APPROVAL_ID = approvalId;
|
||||
if (approvalStatus) env.PAPERCLIP_APPROVAL_STATUS = approvalStatus;
|
||||
if (linkedIssueIds.length > 0) env.PAPERCLIP_LINKED_ISSUE_IDS = linkedIssueIds.join(",");
|
||||
if (wakePayloadJson) env.PAPERCLIP_WAKE_PAYLOAD_JSON = wakePayloadJson;
|
||||
if (effectiveWorkspaceCwd) env.PAPERCLIP_WORKSPACE_CWD = effectiveWorkspaceCwd;
|
||||
if (workspaceSource) env.PAPERCLIP_WORKSPACE_SOURCE = workspaceSource;
|
||||
if (workspaceId) env.PAPERCLIP_WORKSPACE_ID = workspaceId;
|
||||
|
|
@ -222,7 +226,6 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
`[paperclip] OpenCode session "${runtimeSessionId}" was saved for cwd "${runtimeSessionCwd}" and will not be resumed in "${cwd}".\n`,
|
||||
);
|
||||
}
|
||||
|
||||
const instructionsFilePath = asString(config.instructionsFilePath, "").trim();
|
||||
const resolvedInstructionsFilePath = instructionsFilePath
|
||||
? path.resolve(cwd, instructionsFilePath)
|
||||
|
|
@ -271,15 +274,18 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
run: { id: runId, source: "on_demand" },
|
||||
context,
|
||||
};
|
||||
const renderedPrompt = renderTemplate(promptTemplate, templateData);
|
||||
const renderedBootstrapPrompt =
|
||||
!sessionId && bootstrapPromptTemplate.trim().length > 0
|
||||
? renderTemplate(bootstrapPromptTemplate, templateData).trim()
|
||||
: "";
|
||||
const wakePrompt = renderPaperclipWakePrompt(context.paperclipWake, { resumedSession: Boolean(sessionId) });
|
||||
const shouldUseResumeDeltaPrompt = Boolean(sessionId) && wakePrompt.length > 0;
|
||||
const renderedPrompt = shouldUseResumeDeltaPrompt ? "" : renderTemplate(promptTemplate, templateData);
|
||||
const sessionHandoffNote = asString(context.paperclipSessionHandoffMarkdown, "").trim();
|
||||
const prompt = joinPromptSections([
|
||||
instructionsPrefix,
|
||||
renderedBootstrapPrompt,
|
||||
wakePrompt,
|
||||
sessionHandoffNote,
|
||||
renderedPrompt,
|
||||
]);
|
||||
|
|
@ -287,6 +293,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
promptChars: prompt.length,
|
||||
instructionsChars: instructionsPrefix.length,
|
||||
bootstrapPromptChars: renderedBootstrapPrompt.length,
|
||||
wakePromptChars: wakePrompt.length,
|
||||
sessionHandoffChars: sessionHandoffNote.length,
|
||||
heartbeatPromptChars: renderedPrompt.length,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import {
|
|||
resolvePaperclipDesiredSkillNames,
|
||||
removeMaintainerOnlySkillSymlinks,
|
||||
renderTemplate,
|
||||
renderPaperclipWakePrompt,
|
||||
stringifyPaperclipWakePayload,
|
||||
runChildProcess,
|
||||
} from "@paperclipai/adapter-utils/server-utils";
|
||||
import { isPiUnknownSessionError, parsePiJsonl } from "./parse.js";
|
||||
|
|
@ -177,6 +179,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
const linkedIssueIds = Array.isArray(context.issueIds)
|
||||
? context.issueIds.filter((value): value is string => typeof value === "string" && value.trim().length > 0)
|
||||
: [];
|
||||
const wakePayloadJson = stringifyPaperclipWakePayload(context.paperclipWake);
|
||||
|
||||
if (wakeTaskId) env.PAPERCLIP_TASK_ID = wakeTaskId;
|
||||
if (wakeReason) env.PAPERCLIP_WAKE_REASON = wakeReason;
|
||||
|
|
@ -184,6 +187,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
if (approvalId) env.PAPERCLIP_APPROVAL_ID = approvalId;
|
||||
if (approvalStatus) env.PAPERCLIP_APPROVAL_STATUS = approvalStatus;
|
||||
if (linkedIssueIds.length > 0) env.PAPERCLIP_LINKED_ISSUE_IDS = linkedIssueIds.join(",");
|
||||
if (wakePayloadJson) env.PAPERCLIP_WAKE_PAYLOAD_JSON = wakePayloadJson;
|
||||
if (workspaceCwd) env.PAPERCLIP_WORKSPACE_CWD = workspaceCwd;
|
||||
if (workspaceSource) env.PAPERCLIP_WORKSPACE_SOURCE = workspaceSource;
|
||||
if (workspaceId) env.PAPERCLIP_WORKSPACE_ID = workspaceId;
|
||||
|
|
@ -298,14 +302,17 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
context,
|
||||
};
|
||||
const renderedSystemPromptExtension = renderTemplate(systemPromptExtension, templateData);
|
||||
const renderedHeartbeatPrompt = renderTemplate(promptTemplate, templateData);
|
||||
const renderedBootstrapPrompt =
|
||||
!canResumeSession && bootstrapPromptTemplate.trim().length > 0
|
||||
? renderTemplate(bootstrapPromptTemplate, templateData).trim()
|
||||
: "";
|
||||
const wakePrompt = renderPaperclipWakePrompt(context.paperclipWake, { resumedSession: canResumeSession });
|
||||
const shouldUseResumeDeltaPrompt = canResumeSession && wakePrompt.length > 0;
|
||||
const renderedHeartbeatPrompt = shouldUseResumeDeltaPrompt ? "" : renderTemplate(promptTemplate, templateData);
|
||||
const sessionHandoffNote = asString(context.paperclipSessionHandoffMarkdown, "").trim();
|
||||
const userPrompt = joinPromptSections([
|
||||
renderedBootstrapPrompt,
|
||||
wakePrompt,
|
||||
sessionHandoffNote,
|
||||
renderedHeartbeatPrompt,
|
||||
]);
|
||||
|
|
@ -313,6 +320,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||
systemPromptChars: renderedSystemPromptExtension.length,
|
||||
promptChars: userPrompt.length,
|
||||
bootstrapPromptChars: renderedBootstrapPrompt.length,
|
||||
wakePromptChars: wakePrompt.length,
|
||||
sessionHandoffChars: sessionHandoffNote.length,
|
||||
heartbeatPromptChars: renderedHeartbeatPrompt.length,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue