fix(FN-4396): support token budget fields in updateTask

Fusion-Task-Id: FN-4396
Fusion-Task-Lineage: 3839210b-b443-410d-a476-aa81128c739a
This commit is contained in:
Fusion
2026-05-14 07:47:31 -07:00
committed by gsxdsm
parent c857bea62c
commit f8dcc7bb63
2 changed files with 22 additions and 14 deletions

View File

@@ -145,23 +145,16 @@ describe("TaskStore", () => {
const created = await harness.store().createTask({
description: "Token budget fields",
});
(harness.store() as any).db.prepare(`
UPDATE tasks
SET tokenBudgetSoftAlertedAt = ?,
tokenBudgetHardAlertedAt = ?,
tokenBudgetOverride = ?
WHERE id = ?
`).run(
"2026-05-14T01:00:00.000Z",
"2026-05-14T01:05:00.000Z",
JSON.stringify({
await harness.store().updateTask(created.id, {
tokenBudgetSoftAlertedAt: "2026-05-14T01:00:00.000Z",
tokenBudgetHardAlertedAt: "2026-05-14T01:05:00.000Z",
tokenBudgetOverride: {
soft: 1_000_000,
hard: 2_000_000,
raisedAt: "2026-05-14T01:06:00.000Z",
reason: "manual override",
}),
created.id,
);
},
});
const reloaded = await harness.store().getTask(created.id);
expect(reloaded.tokenBudgetSoftAlertedAt).toBe("2026-05-14T01:00:00.000Z");

View File

@@ -3911,7 +3911,7 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
async updateTask(
id: string,
updates: { title?: string; description?: string; priority?: TaskPriority | null; prompt?: string; worktree?: string | null; status?: string | null; dependencies?: string[]; steps?: import("./types.js").TaskStep[]; currentStep?: number; blockedBy?: string | null; assignedAgentId?: string | null; pausedByAgentId?: string | null; pausedReason?: string | null; dispatchStormCount?: number | null; lastDispatchAt?: string | null; assigneeUserId?: string | null; scopeOverride?: boolean | null; scopeOverrideReason?: string | null; nodeId?: string | null; effectiveNodeId?: string | null; effectiveNodeSource?: string | null; checkedOutBy?: string | null; checkedOutAt?: string | null; checkoutNodeId?: string | null; checkoutRunId?: string | null; checkoutLeaseRenewedAt?: string | null; checkoutLeaseEpoch?: number | null; paused?: boolean; baseBranch?: string | null; branch?: string | null; executionStartBranch?: string | null; baseCommitSha?: string | null; size?: "S" | "M" | "L"; reviewLevel?: number; executionMode?: import("./types.js").ExecutionMode | null; mergeRetries?: number; workflowStepRetries?: number; stuckKillCount?: number | null; postReviewFixCount?: number | null; recoveryRetryCount?: number | null; taskDoneRetryCount?: number | null; verificationFailureCount?: number | null; mergeConflictBounceCount?: number | null; mergeAuditBounceCount?: number | null; nextRecoveryAt?: string | null; enabledWorkflowSteps?: string[]; modelProvider?: string | null; modelId?: string | null; validatorModelProvider?: string | null; validatorModelId?: string | null; planningModelProvider?: string | null; planningModelId?: string | null; thinkingLevel?: string | null; error?: string | null; summary?: string | null; sessionFile?: string | null; executionStartedAt?: string | null; executionCompletedAt?: string | null; review?: import("./types.js").TaskReview | null; reviewState?: import("./types.js").TaskReviewState | null; workflowStepResults?: import("./types.js").WorkflowStepResult[] | null; mergeDetails?: import("./types.js").MergeDetails | null; sourceIssue?: import("./types.js").TaskSourceIssue | null; githubTracking?: import("./types.js").TaskGithubTracking | null; tokenUsage?: import("./types.js").TaskTokenUsage | null; modifiedFiles?: string[] | null; missionId?: string | null; sliceId?: string | null },
updates: { title?: string; description?: string; priority?: TaskPriority | null; prompt?: string; worktree?: string | null; status?: string | null; dependencies?: string[]; steps?: import("./types.js").TaskStep[]; currentStep?: number; blockedBy?: string | null; assignedAgentId?: string | null; pausedByAgentId?: string | null; pausedReason?: string | null; tokenBudgetSoftAlertedAt?: string | null; tokenBudgetHardAlertedAt?: string | null; tokenBudgetOverride?: import("./types.js").TaskTokenBudgetOverride | null; dispatchStormCount?: number | null; lastDispatchAt?: string | null; assigneeUserId?: string | null; scopeOverride?: boolean | null; scopeOverrideReason?: string | null; nodeId?: string | null; effectiveNodeId?: string | null; effectiveNodeSource?: string | null; checkedOutBy?: string | null; checkedOutAt?: string | null; checkoutNodeId?: string | null; checkoutRunId?: string | null; checkoutLeaseRenewedAt?: string | null; checkoutLeaseEpoch?: number | null; paused?: boolean; baseBranch?: string | null; branch?: string | null; executionStartBranch?: string | null; baseCommitSha?: string | null; size?: "S" | "M" | "L"; reviewLevel?: number; executionMode?: import("./types.js").ExecutionMode | null; mergeRetries?: number; workflowStepRetries?: number; stuckKillCount?: number | null; postReviewFixCount?: number | null; recoveryRetryCount?: number | null; taskDoneRetryCount?: number | null; verificationFailureCount?: number | null; mergeConflictBounceCount?: number | null; mergeAuditBounceCount?: number | null; nextRecoveryAt?: string | null; enabledWorkflowSteps?: string[]; modelProvider?: string | null; modelId?: string | null; validatorModelProvider?: string | null; validatorModelId?: string | null; planningModelProvider?: string | null; planningModelId?: string | null; thinkingLevel?: string | null; error?: string | null; summary?: string | null; sessionFile?: string | null; executionStartedAt?: string | null; executionCompletedAt?: string | null; review?: import("./types.js").TaskReview | null; reviewState?: import("./types.js").TaskReviewState | null; workflowStepResults?: import("./types.js").WorkflowStepResult[] | null; mergeDetails?: import("./types.js").MergeDetails | null; sourceIssue?: import("./types.js").TaskSourceIssue | null; githubTracking?: import("./types.js").TaskGithubTracking | null; tokenUsage?: import("./types.js").TaskTokenUsage | null; modifiedFiles?: string[] | null; missionId?: string | null; sliceId?: string | null },
runContext?: RunMutationContext,
): Promise<Task> {
return this.withTaskLock(id, async () => {
@@ -4044,6 +4044,21 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
} else if (updates.pausedReason !== undefined) {
task.pausedReason = updates.pausedReason;
}
if (updates.tokenBudgetSoftAlertedAt === null) {
task.tokenBudgetSoftAlertedAt = undefined;
} else if (updates.tokenBudgetSoftAlertedAt !== undefined) {
task.tokenBudgetSoftAlertedAt = updates.tokenBudgetSoftAlertedAt;
}
if (updates.tokenBudgetHardAlertedAt === null) {
task.tokenBudgetHardAlertedAt = undefined;
} else if (updates.tokenBudgetHardAlertedAt !== undefined) {
task.tokenBudgetHardAlertedAt = updates.tokenBudgetHardAlertedAt;
}
if (updates.tokenBudgetOverride === null) {
task.tokenBudgetOverride = undefined;
} else if (updates.tokenBudgetOverride !== undefined) {
task.tokenBudgetOverride = updates.tokenBudgetOverride;
}
if (updates.dispatchStormCount === null) {
task.dispatchStormCount = undefined;
} else if (updates.dispatchStormCount !== undefined) {