fix: remove chained dispatch from work_finish - heartbeat only pickup path (#156)

This commit is contained in:
Lauren ten Hoor
2026-02-13 17:50:50 +08:00
parent c5c5e29e8f
commit 9dc5c66ce9
2 changed files with 2 additions and 42 deletions

View File

@@ -4,11 +4,10 @@
* Eliminates repeated boilerplate across tools: workspace validation, * Eliminates repeated boilerplate across tools: workspace validation,
* project resolution, provider creation. * project resolution, provider creation.
*/ */
import type { OpenClawPluginApi, PluginRuntime } from "openclaw/plugin-sdk"; import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
import type { ToolContext } from "./types.js"; import type { ToolContext } from "./types.js";
import { readProjects, getProject, type Project, type ProjectsData } from "./projects.js"; import { readProjects, getProject, type Project, type ProjectsData } from "./projects.js";
import { createProvider, type ProviderWithType } from "./providers/index.js"; import { createProvider, type ProviderWithType } from "./providers/index.js";
import { projectTick, type TickAction } from "./services/tick.js";
/** /**
* Require workspaceDir from context or throw a clear error. * Require workspaceDir from context or throw a clear error.
@@ -48,34 +47,3 @@ export async function resolveProvider(project: Project): Promise<ProviderWithTyp
export function getPluginConfig(api: OpenClawPluginApi): Record<string, unknown> | undefined { export function getPluginConfig(api: OpenClawPluginApi): Record<string, unknown> | undefined {
return api.pluginConfig as Record<string, unknown> | undefined; return api.pluginConfig as Record<string, unknown> | undefined;
} }
/**
* Run projectTick (non-fatal). Notifications are now handled by dispatchTask.
* Returns the pickups array (empty on failure).
*/
export async function tickAndNotify(opts: {
workspaceDir: string;
groupId: string;
agentId?: string;
pluginConfig?: Record<string, unknown>;
sessionKey?: string;
targetRole?: "dev" | "qa";
/** Plugin runtime for direct API access (avoids CLI subprocess timeouts) */
runtime?: PluginRuntime;
}): Promise<TickAction[]> {
try {
const result = await projectTick({
workspaceDir: opts.workspaceDir,
groupId: opts.groupId,
agentId: opts.agentId,
pluginConfig: opts.pluginConfig,
sessionKey: opts.sessionKey,
targetRole: opts.targetRole,
runtime: opts.runtime,
});
return result.pickups;
} catch {
/* non-fatal: tick failure shouldn't break the caller */
return [];
}
}

View File

@@ -10,7 +10,7 @@ import type { ToolContext } from "../types.js";
import { getWorker, resolveRepoPath } from "../projects.js"; import { getWorker, resolveRepoPath } from "../projects.js";
import { executeCompletion, getRule, NEXT_STATE } from "../services/pipeline.js"; import { executeCompletion, getRule, NEXT_STATE } from "../services/pipeline.js";
import { log as auditLog } from "../audit.js"; import { log as auditLog } from "../audit.js";
import { requireWorkspaceDir, resolveProject, resolveProvider, getPluginConfig, tickAndNotify } from "../tool-helpers.js"; import { requireWorkspaceDir, resolveProject, resolveProvider, getPluginConfig } from "../tool-helpers.js";
export function createWorkFinishTool(api: OpenClawPluginApi) { export function createWorkFinishTool(api: OpenClawPluginApi) {
return (ctx: ToolContext) => ({ return (ctx: ToolContext) => ({
@@ -73,18 +73,10 @@ export function createWorkFinishTool(api: OpenClawPluginApi) {
...completion, ...completion,
}; };
// Tick: fill free slots (notifications handled by dispatchTask with runtime)
const tickPickups = await tickAndNotify({
workspaceDir, groupId, agentId: ctx.agentId, pluginConfig, sessionKey: ctx.sessionKey,
runtime: api.runtime,
});
if (tickPickups.length) output.tickPickups = tickPickups;
// Audit // Audit
await auditLog(workspaceDir, "work_finish", { await auditLog(workspaceDir, "work_finish", {
project: project.name, groupId, issue: issueId, role, result, project: project.name, groupId, issue: issueId, role, result,
summary: summary ?? null, labelTransition: completion.labelTransition, summary: summary ?? null, labelTransition: completion.labelTransition,
tickPickups: tickPickups.length,
}); });
return jsonResult(output); return jsonResult(output);