feat(FN-3249): apply run status icon color style (+3 more)
Commits merged: - fix(FN-3249): apply run status icon color style - fix(FN-3249): address workflow revision dashboard accessibility feedback - feat(FN-3249): complete Step 5 — document assigned execution ownership - feat(FN-3249): complete Step 2 — durable assigned-agent execution ownership Files changed: .changeset/fn-3249-assigned-executor-ownership.md | 5 + docs/agents.md | 15 +++ packages/core/src/__tests__/agent-store.test.ts | 28 +++++ packages/core/src/agent-store.ts | 34 ++++-- .../dashboard/app/components/AgentDetailView.css | 5 + .../dashboard/app/components/AgentDetailView.tsx | 2 +- packages/dashboard/app/components/AgentsView.tsx | 2 + .../runtimes/__tests__/in-process-runtime.test.ts | 125 ++++++++++++++++++--- packages/engine/src/runtimes/in-process-runtime.ts | 108 +++++++++++------- 9 files changed, 260 insertions(+), 64 deletions(-) Fusion-Task-Id: FN-3249
This commit is contained in:
@@ -1639,6 +1639,34 @@ describe("AgentStore", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("syncExecutionTaskLink", () => {
|
||||
it("updates taskId without emitting assignment events", async () => {
|
||||
const agent = await store.createAgent({ name: "Runtime Owner", role: "executor" });
|
||||
const assignedHandler = vi.fn();
|
||||
store.on("agent:assigned", assignedHandler);
|
||||
|
||||
const updated = await store.syncExecutionTaskLink(agent.id, "FN-3249");
|
||||
|
||||
expect(updated.taskId).toBe("FN-3249");
|
||||
expect(assignedHandler).not.toHaveBeenCalled();
|
||||
|
||||
const fetched = await store.getAgent(agent.id);
|
||||
expect(fetched?.taskId).toBe("FN-3249");
|
||||
});
|
||||
|
||||
it("clears taskId without emitting assignment events", async () => {
|
||||
const agent = await store.createAgent({ name: "Runtime Owner 2", role: "executor" });
|
||||
await store.syncExecutionTaskLink(agent.id, "FN-1111");
|
||||
|
||||
const assignedHandler = vi.fn();
|
||||
store.on("agent:assigned", assignedHandler);
|
||||
|
||||
const updated = await store.syncExecutionTaskLink(agent.id, undefined);
|
||||
expect(updated.taskId).toBeUndefined();
|
||||
expect(assignedHandler).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("checkout leasing", () => {
|
||||
let taskStore: TaskStore;
|
||||
let holderId: string;
|
||||
|
||||
@@ -1185,6 +1185,29 @@ export class AgentStore extends EventEmitter {
|
||||
* @returns The updated agent
|
||||
*/
|
||||
async assignTask(agentId: string, taskId: string | undefined, runContext?: RunMutationContext): Promise<Agent> {
|
||||
const updated = await this.syncExecutionTaskLink(agentId, taskId);
|
||||
|
||||
// Emit agent:assigned only when assigning a task (not when clearing)
|
||||
if (taskId !== undefined) {
|
||||
this.emit("agent:assigned", updated, taskId);
|
||||
}
|
||||
|
||||
// Log the assignment to the task when a non-empty taskId is provided
|
||||
if (taskId && this.taskStore) {
|
||||
await this.taskStore.logEntry(taskId, `Task assigned to agent ${agentId}`, undefined, runContext);
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize execution task ownership on an agent without firing
|
||||
* assignment-side effects (`agent:assigned`, task assignment logs).
|
||||
*
|
||||
* Used by runtime execution bookkeeping so durable assigned agents can
|
||||
* reflect active task ownership without triggering heartbeat assignment wakeups.
|
||||
*/
|
||||
async syncExecutionTaskLink(agentId: string, taskId: string | undefined): Promise<Agent> {
|
||||
return this.withLock(agentId, async () => {
|
||||
const agent = await this.getAgent(agentId);
|
||||
if (!agent) {
|
||||
@@ -1199,17 +1222,6 @@ export class AgentStore extends EventEmitter {
|
||||
|
||||
await this.writeAgent(updated);
|
||||
this.emit("agent:updated", updated);
|
||||
|
||||
// Emit agent:assigned only when assigning a task (not when clearing)
|
||||
if (taskId !== undefined) {
|
||||
this.emit("agent:assigned", updated, taskId);
|
||||
}
|
||||
|
||||
// Log the assignment to the task when a non-empty taskId is provided
|
||||
if (taskId && this.taskStore) {
|
||||
await this.taskStore.logEntry(taskId, `Task assigned to agent ${agentId}`, undefined, runContext);
|
||||
}
|
||||
|
||||
return updated;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user