update draft issue

This commit is contained in:
2026-08-15 23:24:06 +05:30
parent b349f2db61
commit 69b38abced
8 changed files with 753 additions and 25 deletions

View File

@@ -7,6 +7,10 @@ import {
matchOwliverSkill, owliverSkillsForContext, presentable, resolveOwliverResponse,
responseTitle, summaryLines,
} from '@/lib/skills/owliverResolver';
import {
draftActions, draftContinuedReply, explainWeightsReply, matchDraftIntent, noDraftReply,
resolveDraft, weightsFromQuestion, weightsReply, weightsUnchangedReply, whichDraftReply,
} from '@/lib/skills/draftFlow';
import {
appliedToday, askWhichPosition, assignmentPreview, assignmentToExecute, availability,
candidateDetail, candidateMatches, candidateRoute, interviewReady, matchWorkforceIntent,
@@ -707,12 +711,121 @@ function resolveSkill({
};
}
/**
* A draft question, resolved against the position records the panel holds.
*
* Returns an intent the panel executes. The two that write — generating a
* description and setting weights, plus publishing — carry a `perform` block
* rather than performing anything here: this module stays pure, and the write
* goes through the mutation the Create Position form already uses.
*/
function resolveDraftAction(question, workforce, positionId = null) {
const action = matchDraftIntent(question);
if (!action) return null;
const positions = workforce.positions || [];
/* `positionId` is the record a control was built from — the Continue button on
a card, or a chip this flow wrote. It settles the question before any
guessing from the wording starts. */
const { position, ambiguous } = resolveDraft(
question, positions, workforce.currentPositionId, positionId
);
if (ambiguous) return { kind: 'draft', ...whichDraftReply(ambiguous) };
/**
* Nothing resolved. Only a question explicitly about drafts is answered with
* "there are none" — everything else is handed back.
*
* "Summarize these vetting weights" on the Create Position form is a question
* about the form, and the page has answered it since long before drafts could
* be continued here. Claiming it because it contains the word "weights" and
* then reporting that no draft exists would be this flow taking a question it
* cannot answer.
*/
if (!position) {
return action === 'continue' || action === 'list'
? { kind: 'draft', doc: noDraftReply() }
: null;
}
switch (action) {
/* One draft is continued; several are offered by name. Either way the
answer is here, and neither opens a form. */
case 'list':
return positions.filter((p) => p.status === 'draft').length > 1
? { kind: 'draft', ...whichDraftReply(positions.filter((p) => p.status === 'draft')) }
: {
kind: 'draft',
doc: draftContinuedReply(position),
followUp: draftActions(position),
};
case 'continue':
return {
kind: 'draft',
doc: draftContinuedReply(position),
/* Never "continue" again — the reply *is* the continuation. */
followUp: draftActions(position),
};
case 'show_weights':
return { kind: 'draft', doc: weightsReply(position), followUp: draftActions(position) };
case 'explain_weights':
return { kind: 'draft', doc: explainWeightsReply(position), followUp: draftActions(position) };
case 'set_weights': {
const next = weightsFromQuestion(question, position);
if (!next) {
return { kind: 'draft', doc: weightsUnchangedReply(position), followUp: draftActions(position) };
}
return { kind: 'draft', perform: { action: 'set_weights', position, weights: next } };
}
case 'generate_description':
return { kind: 'draft', perform: { action: 'generate_description', position } };
case 'publish':
return position.status === 'draft'
? { kind: 'draft', perform: { action: 'publish', position } }
: {
kind: 'draft',
doc: doc(text(`**${position.title}** is already published.`)),
followUp: draftActions(position),
};
default:
return null;
}
}
export function resolveIntent({
question, contextId, disabledSkills = [], customSkills = [], roles = [], skillCategories = [],
courses = [], workforce = null, skillContext = null,
/* The record the control that raised this question was built from, when there
was one. Only the draft flow reads it; a typed question carries none and
resolves exactly as it always did. */
positionId = null,
}) {
const context = ASSISTANT_CONTEXTS[contextId] ?? null;
/**
* 1. Finishing a draft, wherever the reader is standing.
*
* Ahead of everything else because these questions name a record and an act
* on it — continuing, generating, weighting, publishing — and every other
* matcher would read them as words about positions in general. It runs only
* where the panel actually has the positions to act on.
*/
/* Resolved even where the panel carries no workforce: a question about
continuing a draft is answered in the panel or answered as "there is no
draft", never handed to keyword routing — which is what used to send
"Continue the Bartender draft" into the authoring form, because Create
Position lists `position` and `role` among its topics. */
const draftIntent = resolveDraftAction(question, workforce || { positions: [] }, positionId);
if (draftIntent) return draftIntent;
/* 2. Current page skills — specific triggers, ahead of the general reader. */
const skill = resolveSkill({
question, contextId, disabledSkills, customSkills, roles, skillCategories, courses,