feat(KB-630): inherit parent task models in subtasks
- Subtasks now inherit parent task's executor and validator model settings - When triage creates subtasks, modelProvider/modelId and validatorModelProvider/validatorModelId are copied from parent - Clean up legacy mission-store code (mission-store.ts, mission-types.ts, and related tests) - Add comprehensive tests for subtask model inheritance in triage, routes, and db - Remove obsolete changeset for missions-database-schema
This commit is contained in:
@@ -535,3 +535,111 @@ describe("requirePlanApproval setting", () => {
|
||||
expect(settings.requirePlanApproval).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("taskCreate tool model inheritance", () => {
|
||||
it("inherits parent task model settings when creating subtasks", async () => {
|
||||
const parentTask: Task = {
|
||||
id: "KB-001",
|
||||
description: "Parent task",
|
||||
column: "triage",
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
log: [],
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
modelProvider: "anthropic",
|
||||
modelId: "claude-sonnet-4-5",
|
||||
validatorModelProvider: "openai",
|
||||
validatorModelId: "gpt-4o",
|
||||
};
|
||||
|
||||
const createdSubtask: Task = {
|
||||
id: "KB-002",
|
||||
description: "Child task description",
|
||||
column: "triage",
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
log: [],
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
};
|
||||
|
||||
const store = createMockStore({
|
||||
getTask: vi.fn().mockResolvedValue(parentTask),
|
||||
createTask: vi.fn().mockResolvedValue(createdSubtask),
|
||||
});
|
||||
|
||||
// Simulate the taskCreate tool behavior
|
||||
const parentTaskId = "KB-001";
|
||||
const parentTaskResult = await store.getTask(parentTaskId);
|
||||
|
||||
await store.createTask({
|
||||
title: "Child Task",
|
||||
description: "Child task description",
|
||||
dependencies: [],
|
||||
column: "triage",
|
||||
modelProvider: parentTaskResult?.modelProvider,
|
||||
modelId: parentTaskResult?.modelId,
|
||||
validatorModelProvider: parentTaskResult?.validatorModelProvider,
|
||||
validatorModelId: parentTaskResult?.validatorModelId,
|
||||
});
|
||||
|
||||
expect(store.getTask).toHaveBeenCalledWith("KB-001");
|
||||
expect(store.createTask).toHaveBeenCalledWith(expect.objectContaining({
|
||||
title: "Child Task",
|
||||
modelProvider: "anthropic",
|
||||
modelId: "claude-sonnet-4-5",
|
||||
validatorModelProvider: "openai",
|
||||
validatorModelId: "gpt-4o",
|
||||
}));
|
||||
});
|
||||
|
||||
it("handles missing parent task gracefully when creating subtasks", async () => {
|
||||
const createdSubtask: Task = {
|
||||
id: "KB-002",
|
||||
description: "Child task description",
|
||||
column: "triage",
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
log: [],
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
};
|
||||
|
||||
const store = createMockStore({
|
||||
getTask: vi.fn().mockRejectedValue(new Error("Task not found")),
|
||||
createTask: vi.fn().mockResolvedValue(createdSubtask),
|
||||
});
|
||||
|
||||
// Simulate the taskCreate tool behavior with missing parent
|
||||
const parentTaskId = "KB-NONEXISTENT";
|
||||
let parentTask;
|
||||
try {
|
||||
parentTask = await store.getTask(parentTaskId);
|
||||
} catch {
|
||||
parentTask = undefined;
|
||||
}
|
||||
|
||||
await store.createTask({
|
||||
title: "Child Task",
|
||||
description: "Child task description",
|
||||
dependencies: [],
|
||||
column: "triage",
|
||||
modelProvider: parentTask?.modelProvider,
|
||||
modelId: parentTask?.modelId,
|
||||
validatorModelProvider: parentTask?.validatorModelProvider,
|
||||
validatorModelId: parentTask?.validatorModelId,
|
||||
});
|
||||
|
||||
expect(store.getTask).toHaveBeenCalledWith("KB-NONEXISTENT");
|
||||
expect(store.createTask).toHaveBeenCalledWith(expect.objectContaining({
|
||||
modelProvider: undefined,
|
||||
modelId: undefined,
|
||||
validatorModelProvider: undefined,
|
||||
validatorModelId: undefined,
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -788,11 +788,25 @@ export class TriageProcessor {
|
||||
}
|
||||
|
||||
try {
|
||||
// Fetch parent task to inherit model settings
|
||||
let parentTask: Awaited<ReturnType<typeof store.getTask>> | undefined;
|
||||
try {
|
||||
parentTask = await store.getTask(options.parentTaskId);
|
||||
} catch {
|
||||
// Parent task not found or error - proceed without inheritance
|
||||
parentTask = undefined;
|
||||
}
|
||||
|
||||
const newTask = await store.createTask({
|
||||
title: params.title,
|
||||
description: params.description,
|
||||
dependencies: params.dependencies || [],
|
||||
column: "triage",
|
||||
// Inherit parent's model settings if available
|
||||
modelProvider: parentTask?.modelProvider,
|
||||
modelId: parentTask?.modelId,
|
||||
validatorModelProvider: parentTask?.validatorModelProvider,
|
||||
validatorModelId: parentTask?.validatorModelId,
|
||||
});
|
||||
|
||||
// Track the created subtask
|
||||
|
||||
Reference in New Issue
Block a user