fix: avoid blocking on the task that just started
When an assistant turn emits both confirm and start_next, confirm may already start the newly queued proposal. The later start_next then sees the just-started task as an active blocker and appends a false running-task correction. Suppress that redundant start_next correction when confirm in the same turn already started the current user proposal. Also tighten the worker bootstrap wording to run confirmed low-risk work continuously until a real decision point.
This commit is contained in:
@@ -292,6 +292,7 @@ export class AssistantManager implements ConversationRuntime {
|
|||||||
private async executeActions(chatKey: string, request: ConversationRequest, actions: AssistantAction[]): Promise<{ corrections: string[]; images?: OutgoingImageRef[] }> {
|
private async executeActions(chatKey: string, request: ConversationRequest, actions: AssistantAction[]): Promise<{ corrections: string[]; images?: OutgoingImageRef[] }> {
|
||||||
const corrections: string[] = [];
|
const corrections: string[] = [];
|
||||||
const images: OutgoingImageRef[] = [];
|
const images: OutgoingImageRef[] = [];
|
||||||
|
let confirmStartedOwnProposal = false;
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
if (action.type === "create_proposal") {
|
if (action.type === "create_proposal") {
|
||||||
await this.proposals.create({
|
await this.proposals.create({
|
||||||
@@ -304,6 +305,10 @@ export class AssistantManager implements ConversationRuntime {
|
|||||||
} else if (action.type === "confirm") {
|
} else if (action.type === "confirm") {
|
||||||
const ok = await this.scheduler(() => this.confirmLocked(chatKey, request.userId, action.id));
|
const ok = await this.scheduler(() => this.confirmLocked(chatKey, request.userId, action.id));
|
||||||
if (!ok) corrections.push("没有可确认的提案;你只能操作自己发起的任务。");
|
if (!ok) corrections.push("没有可确认的提案;你只能操作自己发起的任务。");
|
||||||
|
else {
|
||||||
|
confirmStartedOwnProposal = this.proposals.list({ status: "working" })
|
||||||
|
.some((proposal) => proposal.ownerChatKey === chatKey && proposal.requesterUserId === request.userId);
|
||||||
|
}
|
||||||
} else if (action.type === "adjust_proposal") {
|
} else if (action.type === "adjust_proposal") {
|
||||||
const ok = await this.scheduler(() => this.adjustProposalLocked(chatKey, request.userId, action));
|
const ok = await this.scheduler(() => this.adjustProposalLocked(chatKey, request.userId, action));
|
||||||
if (!ok) corrections.push("没有可调整的提案;只有还没开始执行的任务可以调整,且你只能操作自己发起的任务。");
|
if (!ok) corrections.push("没有可调整的提案;只有还没开始执行的任务可以调整,且你只能操作自己发起的任务。");
|
||||||
@@ -318,6 +323,7 @@ export class AssistantManager implements ConversationRuntime {
|
|||||||
if (image) images.push({ path: image.path, mimeType: image.mimeType, filename: image.filename });
|
if (image) images.push({ path: image.path, mimeType: image.mimeType, filename: image.filename });
|
||||||
else corrections.push("这张图发不出去:路径不在工作区内,或者不是有效的 png/jpg 图片。");
|
else corrections.push("这张图发不出去:路径不在工作区内,或者不是有效的 png/jpg 图片。");
|
||||||
} else if (action.type === "start_next") {
|
} else if (action.type === "start_next") {
|
||||||
|
if (confirmStartedOwnProposal) continue;
|
||||||
const started = await this.scheduler(() => this.tryStartLocked(chatKey, request.userId));
|
const started = await this.scheduler(() => this.tryStartLocked(chatKey, request.userId));
|
||||||
if (!started) corrections.push(this.startNextCorrection(chatKey, request.userId));
|
if (!started) corrections.push(this.startNextCorrection(chatKey, request.userId));
|
||||||
} else if (action.type === "cancel") {
|
} else if (action.type === "cancel") {
|
||||||
|
|||||||
@@ -721,6 +721,19 @@ test("start_next reports when the queue is empty instead of claiming a start", a
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("confirm plus start_next in the same assistant turn does not treat the just-started task as a blocker", async () => {
|
||||||
|
const harness = await createHarness();
|
||||||
|
try {
|
||||||
|
await harness.manager.prompt(request("create proposal: hang", "user-a"));
|
||||||
|
const reply = await harness.manager.prompt(request("confirm and start next", "user-a"));
|
||||||
|
assert.doesNotMatch(reply.text, /还有一个任务正在执行/);
|
||||||
|
assert.equal(reply.text, "confirmed");
|
||||||
|
assert.equal(harness.proposals.list()[0]!.status, "working");
|
||||||
|
} finally {
|
||||||
|
await closeHarness(harness);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("image attachments reach the assistant as image blocks when the agent supports them", async () => {
|
test("image attachments reach the assistant as image blocks when the agent supports them", async () => {
|
||||||
const harness = await createHarness();
|
const harness = await createHarness();
|
||||||
try {
|
try {
|
||||||
|
|||||||
Vendored
+1
@@ -85,6 +85,7 @@ const app = acp.agent({ name: "fake-acp-agent" })
|
|||||||
const goal = userText.slice("create proposal:".length).trim();
|
const goal = userText.slice("create proposal:".length).trim();
|
||||||
response = assistantEnvelope("proposal drafted", [{ type: "create_proposal", title: "Test proposal", goal, steps: ["step 1"] }]);
|
response = assistantEnvelope("proposal drafted", [{ type: "create_proposal", title: "Test proposal", goal, steps: ["step 1"] }]);
|
||||||
} else if (userText === "confirm") response = assistantEnvelope("confirmed", [{ type: "confirm" }]);
|
} else if (userText === "confirm") response = assistantEnvelope("confirmed", [{ type: "confirm" }]);
|
||||||
|
else if (userText === "confirm and start next") response = assistantEnvelope("confirmed", [{ type: "confirm" }, { type: "start_next" }]);
|
||||||
else if (userText === "finish") response = assistantEnvelope("finishing", [{ type: "finish" }]);
|
else if (userText === "finish") response = assistantEnvelope("finishing", [{ type: "finish" }]);
|
||||||
else if (userText.startsWith("follow up:")) response = assistantEnvelope("following up", [{ type: "follow_up", instruction: userText.slice("follow up:".length).trim() }]);
|
else if (userText.startsWith("follow up:")) response = assistantEnvelope("following up", [{ type: "follow_up", instruction: userText.slice("follow up:".length).trim() }]);
|
||||||
else if (userText.startsWith("adjust proposal:")) response = assistantEnvelope("adjusting", [{ type: "adjust_proposal", title: userText.slice("adjust proposal:".length).trim() }]);
|
else if (userText.startsWith("adjust proposal:")) response = assistantEnvelope("adjusting", [{ type: "adjust_proposal", title: userText.slice("adjust proposal:".length).trim() }]);
|
||||||
|
|||||||
Reference in New Issue
Block a user