Slices 2-4: Work becomes executable
Domain primitives: versioned WorkDefinition/DesignPacket with risk, questions, and approval gates; lifecycle transition table with invalidation rules; Resolver (Run/Attempt/outcomes/CodingKitV0); provider-neutral HarnessRuntime with normalized events and a deterministic FakeHarnessLive that always reaches a terminal classification and never claims implementation. Convex durable model: workDefinitions, workQuestions, workApprovals, designPackets, workSlices, workRuns, workAttempts, workAttemptEvents tables; broadened works.status union; generalized workEvents with optional signalId, referenceId, and payloadJson. Authenticated commands for definition request/ save/revise/approve, question answer/withdraw, design save/revise/approve, and simulated execution start/cancel/retry with leased attempts, checkpointed events, and expired-lease reconciliation. Private work-planner FLUE agent with proposal-only tools (definition, design, question). Convex validates and stores every proposal; FLUE never approves or advances Work. Expanded Work card with Outcome, Design, and Build sections wired to the new mutations. Slice 1 conversation and provenance preserved.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { parseAgentEnv } from "@code/env/agent";
|
||||
import { defineTool } from "@flue/runtime";
|
||||
import { ConvexHttpClient } from "convex/browser";
|
||||
import { makeFunctionReference } from "convex/server";
|
||||
import * as v from "valibot";
|
||||
|
||||
const submitDefinitionRef = makeFunctionReference<
|
||||
"mutation",
|
||||
{ workId: string; payloadJson: string; token: string },
|
||||
{ version: number }
|
||||
>("workPlanning:submitDefinitionProposal");
|
||||
const submitDesignRef = makeFunctionReference<
|
||||
"mutation",
|
||||
{ workId: string; payloadJson: string; token: string },
|
||||
{ version: number }
|
||||
>("workPlanning:submitDesignProposal");
|
||||
const submitQuestionRef = makeFunctionReference<
|
||||
"mutation",
|
||||
{ workId: string; questionJson: string; token: string },
|
||||
{ accepted: boolean }
|
||||
>("workPlanning:submitQuestion");
|
||||
|
||||
export const createWorkPlannerTools = (
|
||||
runtimeEnv: Record<string, string | undefined>
|
||||
) => {
|
||||
const env = parseAgentEnv(runtimeEnv);
|
||||
const client = new ConvexHttpClient(env.CONVEX_URL);
|
||||
const token = env.FLUE_DB_TOKEN;
|
||||
return [
|
||||
defineTool({
|
||||
description:
|
||||
"Submit a versioned Work Definition proposal. This never approves the Definition.",
|
||||
input: v.object({ definitionJson: v.string(), workId: v.string() }),
|
||||
name: "submit_definition_proposal",
|
||||
async run({ input }) {
|
||||
return await client.mutation(submitDefinitionRef, {
|
||||
payloadJson: input.definitionJson,
|
||||
token,
|
||||
workId: input.workId,
|
||||
});
|
||||
},
|
||||
}),
|
||||
defineTool({
|
||||
description:
|
||||
"Submit a Design Packet with observable independently verifiable slices. This never approves the Design.",
|
||||
input: v.object({ designJson: v.string(), workId: v.string() }),
|
||||
name: "submit_design_proposal",
|
||||
async run({ input }) {
|
||||
return await client.mutation(submitDesignRef, {
|
||||
payloadJson: input.designJson,
|
||||
token,
|
||||
workId: input.workId,
|
||||
});
|
||||
},
|
||||
}),
|
||||
defineTool({
|
||||
description: "Submit one structured question for human attention.",
|
||||
input: v.object({ questionJson: v.string(), workId: v.string() }),
|
||||
name: "submit_question",
|
||||
async run({ input }) {
|
||||
return await client.mutation(submitQuestionRef, {
|
||||
questionJson: input.questionJson,
|
||||
token,
|
||||
workId: input.workId,
|
||||
});
|
||||
},
|
||||
}),
|
||||
];
|
||||
};
|
||||
Reference in New Issue
Block a user