fix: Refine flow — optimistic UI update + instruction passthrough
- Add getActiveRefineAgent to spawn mutation optimistic updates and live event invalidation rules so the refine panel reflects agent state immediately without manual refresh - Accept optional instruction param in buildRefinePrompt() and inject it as <user_instruction> block so the agent knows what to focus on - Pass input.instruction through in architect router spawn call
This commit is contained in:
@@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
import { CODEBASE_EXPLORATION, INPUT_FILES, SIGNAL_FORMAT } from './shared.js';
|
import { CODEBASE_EXPLORATION, INPUT_FILES, SIGNAL_FORMAT } from './shared.js';
|
||||||
|
|
||||||
export function buildRefinePrompt(): string {
|
export function buildRefinePrompt(instruction?: string): string {
|
||||||
|
const instructionBlock = instruction
|
||||||
|
? `\n<user_instruction>\n${instruction}\n</user_instruction>\n`
|
||||||
|
: '';
|
||||||
return `<role>
|
return `<role>
|
||||||
You are an Architect agent reviewing initiative pages. You do NOT write code.
|
You are an Architect agent reviewing initiative pages. You do NOT write code.
|
||||||
</role>
|
</role>
|
||||||
@@ -17,7 +20,7 @@ Write one file per modified page to \`.cw/output/pages/{pageId}.md\`:
|
|||||||
- Frontmatter: \`title\`, \`summary\` (what changed and why)
|
- Frontmatter: \`title\`, \`summary\` (what changed and why)
|
||||||
- Body: Full replacement markdown content for the page
|
- Body: Full replacement markdown content for the page
|
||||||
</output_format>
|
</output_format>
|
||||||
|
${instructionBlock}
|
||||||
<improvement_priorities>
|
<improvement_priorities>
|
||||||
1. **Ambiguity**: Requirements interpretable multiple ways → make specific
|
1. **Ambiguity**: Requirements interpretable multiple ways → make specific
|
||||||
2. **Missing details**: Gaps forcing agents to guess → fill with concrete decisions
|
2. **Missing details**: Gaps forcing agents to guess → fill with concrete decisions
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ export function architectProcedures(publicProcedure: ProcedureBuilder) {
|
|||||||
status: 'in_progress',
|
status: 'in_progress',
|
||||||
});
|
});
|
||||||
|
|
||||||
const prompt = buildRefinePrompt();
|
const prompt = buildRefinePrompt(input.instruction);
|
||||||
|
|
||||||
return agentManager.spawn({
|
return agentManager.spawn({
|
||||||
name: input.name,
|
name: input.name,
|
||||||
|
|||||||
@@ -110,9 +110,11 @@ export function useRefineAgent(initiativeId: string): UseRefineAgentResult {
|
|||||||
onMutate: async ({ initiativeId, instruction }) => {
|
onMutate: async ({ initiativeId, instruction }) => {
|
||||||
// Cancel outgoing refetches
|
// Cancel outgoing refetches
|
||||||
await utils.listAgents.cancel();
|
await utils.listAgents.cancel();
|
||||||
|
await utils.getActiveRefineAgent.cancel({ initiativeId });
|
||||||
|
|
||||||
// Snapshot previous value
|
// Snapshot previous values
|
||||||
const previousAgents = utils.listAgents.getData();
|
const previousAgents = utils.listAgents.getData();
|
||||||
|
const previousRefineAgent = utils.getActiveRefineAgent.getData({ initiativeId });
|
||||||
|
|
||||||
// Optimistically add a temporary agent
|
// Optimistically add a temporary agent
|
||||||
const tempAgent = {
|
const tempAgent = {
|
||||||
@@ -133,20 +135,25 @@ export function useRefineAgent(initiativeId: string): UseRefineAgentResult {
|
|||||||
};
|
};
|
||||||
|
|
||||||
utils.listAgents.setData(undefined, (old = []) => [tempAgent, ...old]);
|
utils.listAgents.setData(undefined, (old = []) => [tempAgent, ...old]);
|
||||||
|
utils.getActiveRefineAgent.setData({ initiativeId }, tempAgent as any);
|
||||||
|
|
||||||
return { previousAgents };
|
return { previousAgents, previousRefineAgent };
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
// Agent will appear in the list after invalidation
|
// Agent will appear in the list after invalidation
|
||||||
},
|
},
|
||||||
onError: (err, variables, context) => {
|
onError: (err, variables, context) => {
|
||||||
// Revert optimistic update
|
// Revert optimistic updates
|
||||||
if (context?.previousAgents) {
|
if (context?.previousAgents) {
|
||||||
utils.listAgents.setData(undefined, context.previousAgents);
|
utils.listAgents.setData(undefined, context.previousAgents);
|
||||||
}
|
}
|
||||||
|
if (context?.previousRefineAgent !== undefined) {
|
||||||
|
utils.getActiveRefineAgent.setData({ initiativeId }, context.previousRefineAgent);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
void utils.listAgents.invalidate();
|
void utils.listAgents.invalidate();
|
||||||
|
void utils.getActiveRefineAgent.invalidate({ initiativeId });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ function InitiativeDetailPage() {
|
|||||||
useLiveUpdates([
|
useLiveUpdates([
|
||||||
{ prefix: 'task:', invalidate: ['listPhases', 'listTasks', 'listInitiativeTasks'] },
|
{ prefix: 'task:', invalidate: ['listPhases', 'listTasks', 'listInitiativeTasks'] },
|
||||||
{ prefix: 'phase:', invalidate: ['listPhases', 'listTasks', 'listInitiativePhaseDependencies'] },
|
{ prefix: 'phase:', invalidate: ['listPhases', 'listTasks', 'listInitiativePhaseDependencies'] },
|
||||||
{ prefix: 'agent:', invalidate: ['listAgents'] },
|
{ prefix: 'agent:', invalidate: ['listAgents', 'getActiveRefineAgent'] },
|
||||||
{ prefix: 'page:', invalidate: ['listPages', 'getPage', 'getRootPage'] },
|
{ prefix: 'page:', invalidate: ['listPages', 'getPage', 'getRootPage'] },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user