fix: 用 Aipod prompt 禁止 Artificer 递归派单
This commit is contained in:
@@ -124,7 +124,11 @@ spec:
|
||||
lfs: false
|
||||
payloadDefaults:
|
||||
title: Artificer distributed development task
|
||||
prompt: Follow the bundled dad-dev and UniDesk skills. Report progress to the relevant GitHub issue before risky or long operations.
|
||||
prompt: |-
|
||||
你就是当前已派发任务的 Artificer 执行者,必须直接在 primary workspace 完成被分配的调查、修改、测试和 PR。
|
||||
禁止通过 `agentrun create`、`agentrun apply`、`agentrun dispatch`、Code Queue 或任何等价入口创建或派发另一个 Artificer 来完成当前任务。
|
||||
允许只读查询 AgentRun task、session 和 run 状态;只读查询不属于二次派单。
|
||||
遵循随资源包提供的 dad-dev 与 UniDesk skills;执行高风险或长时间操作前,先向相关 GitHub issue 报告进展。
|
||||
references: []
|
||||
metadata:
|
||||
aipod: Artificer
|
||||
|
||||
@@ -136,7 +136,9 @@ export function renderAipodSpec(record: AipodSpecRecord, input: RenderAipodInput
|
||||
const metadata = mergeRecords(spec.metadata, input.metadata, { aipod: record.name, aipodSpecHash: record.specHash, aipodImageRef: imageRef });
|
||||
const inputPayload = input.payload === undefined ? undefined : validateAipodPayload(input.payload, "aipodRender.payload");
|
||||
const payload = mergeRecords(spec.payloadDefaults, inputPayload);
|
||||
if (typeof input.prompt === "string" && input.prompt.trim().length > 0) payload.prompt = input.prompt;
|
||||
const defaultPrompt = nonEmptyText(spec.payloadDefaults?.prompt);
|
||||
const userPrompt = nonEmptyText(input.prompt) ?? nonEmptyText(inputPayload?.prompt);
|
||||
if (userPrompt !== null) payload.prompt = defaultPrompt === null ? userPrompt : `${defaultPrompt}\n\n${userPrompt}`;
|
||||
applyEffectiveModelPayload(payload, effectiveModel);
|
||||
const sessionRef = renderSessionRef(spec.sessionRef ?? null, input, record, payload);
|
||||
const queueTask = validateCreateQueueTask({
|
||||
@@ -443,6 +445,10 @@ function stringValue(value: unknown): string | null {
|
||||
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
||||
}
|
||||
|
||||
function nonEmptyText(value: unknown): string | null {
|
||||
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
||||
}
|
||||
|
||||
function isJsonRecord(value: unknown): value is JsonRecord {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { parseAipodSpecYaml, renderAipodSpec } from "../../common/aipod-specs.js";
|
||||
import type { JsonRecord } from "../../common/types.js";
|
||||
import type { SelfTestCase } from "../harness.js";
|
||||
|
||||
const selfTest: SelfTestCase = async (context) => {
|
||||
const source = path.join(context.root, "config", "aipods", "artificer.yaml");
|
||||
const spec = parseAipodSpecYaml(await readFile(source, "utf8"), source);
|
||||
const userPrompt = "调查 Monitor issue #1888 的迁移失败。\n保留这段用户业务提示的完整内容。";
|
||||
const rendered = renderAipodSpec({
|
||||
name: spec.metadata.name,
|
||||
spec,
|
||||
specHash: "selftest-artificer-nonrecursive-prompt",
|
||||
source,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
}, { prompt: userPrompt });
|
||||
const effectivePrompt = String(((rendered.queueTask as JsonRecord).payload as JsonRecord).prompt);
|
||||
|
||||
assert.match(effectivePrompt, /当前已派发任务的 Artificer 执行者/u);
|
||||
assert.match(effectivePrompt, /agentrun create/u);
|
||||
assert.match(effectivePrompt, /agentrun apply/u);
|
||||
assert.match(effectivePrompt, /agentrun dispatch/u);
|
||||
assert.match(effectivePrompt, /Code Queue/u);
|
||||
assert.match(effectivePrompt, /只读查询 AgentRun task、session 和 run 状态/u);
|
||||
assert.equal(effectivePrompt.endsWith(userPrompt), true, "rendered prompt must preserve the complete user business prompt");
|
||||
assert.equal(effectivePrompt.split(userPrompt).length - 1, 1, "rendered prompt must include the user business prompt exactly once");
|
||||
|
||||
return { name: "artificer-nonrecursive-prompt", tests: ["artificer-yaml-nonrecursive-prompt-render", "artificer-user-prompt-preserved"] };
|
||||
};
|
||||
|
||||
export default selfTest;
|
||||
Reference in New Issue
Block a user