Skip to content

Commit 9750801

Browse files
MaxLinCodeclaude
andcommitted
Fix phantom pending_write_operation on reply_only turns; rename missingSlots to missingFields
- turn-router: only build resolvedOperation when policy.action !== "reply_only"; informational and follow_up_reply turns were creating a synthetic PendingWriteOperation that overwrote any real in-progress write workflow in discourse state - core/index: rename turnInterpretationSchema field missingSlots → missingFields to match the PendingWriteOperation naming introduced in phase 1 - update tests to assert reply_only turns produce no resolvedOperation, and fix missingSlots references in conversation-state.test.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 85ebd75 commit 9750801

4 files changed

Lines changed: 20 additions & 17 deletions

File tree

apps/web/src/lib/server/conversation-state.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ describe("deriveConversationReplyState", () => {
6262
confidence: 0.58,
6363
resolvedEntityIds: [],
6464
ambiguity: "high",
65-
missingSlots: ["time"],
65+
missingFields: ["time"],
6666
},
6767
reply: "What time should I schedule the Malaysia trip planning?",
6868
userTurnText: "schedule malaysia trip planning tomorrow",
@@ -122,7 +122,7 @@ describe("deriveConversationReplyState", () => {
122122
confidence: 0.42,
123123
resolvedEntityIds: [],
124124
ambiguity: "high",
125-
missingSlots: ["unknown"],
125+
missingFields: ["unknown"],
126126
},
127127
reply: "Can you clarify what you want me to change?",
128128
userTurnText: "do it",
@@ -225,7 +225,7 @@ describe("deriveConversationReplyState", () => {
225225
confidence: 0.58,
226226
resolvedEntityIds: [],
227227
ambiguity: "high",
228-
missingSlots: ["time"],
228+
missingFields: ["time"],
229229
},
230230
reply: "What time should I schedule it?",
231231
userTurnText: "schedule gym tomorrow",

apps/web/src/lib/server/turn-router.test.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ describe("turn router", () => {
172172
});
173173
});
174174

175-
it("includes resolvedOperation with empty resolvedFields for non-planning turns", async () => {
175+
it("does not set resolvedOperation for reply_only turns", async () => {
176176
mockClassification({
177177
turnType: "informational",
178178
confidence: 0.93,
@@ -184,10 +184,8 @@ describe("turn router", () => {
184184
recentTurns: [],
185185
});
186186

187-
expect(result.policy.resolvedOperation).toMatchObject({
188-
operationKind: "plan",
189-
resolvedFields: {},
190-
});
187+
expect(result.policy.action).toBe("reply_only");
188+
expect(result.policy.resolvedOperation).toBeUndefined();
191189
});
192190

193191
it("includes resolvedOperation with extracted fields for planning_request", async () => {

apps/web/src/lib/server/turn-router.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,18 @@ export async function routeMessageTurn(
117117
routingContext: input,
118118
});
119119

120-
// Assemble the resolved PendingWriteOperation to carry through to state persistence.
121-
const resolvedOperation = buildResolvedOperation(
122-
operationKind,
123-
commitResult,
124-
priorOperation,
125-
input.normalizedText,
126-
);
120+
// Assemble the resolved PendingWriteOperation for any turn that advances or maintains
121+
// a write workflow. reply_only turns must not create or overwrite pending_write_operation
122+
// in discourse state — they carry no write intent.
123+
const resolvedOperation =
124+
policy.action !== "reply_only"
125+
? buildResolvedOperation(
126+
operationKind,
127+
commitResult,
128+
priorOperation,
129+
input.normalizedText,
130+
)
131+
: undefined;
127132

128133
// Build interpretation for backward compatibility
129134
const interpretation = buildInterpretation(classification, commitResult);
@@ -187,7 +192,7 @@ function buildInterpretation(
187192
),
188193
}
189194
: {}),
190-
...(allMissingFields.length > 0 ? { missingSlots: allMissingFields } : {}),
195+
...(allMissingFields.length > 0 ? { missingFields: allMissingFields } : {}),
191196
};
192197
}
193198

packages/core/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ export const turnInterpretationSchema = z.object({
925925
resolvedProposalId: z.string().min(1).optional(),
926926
ambiguity: turnAmbiguitySchema,
927927
ambiguityReason: z.string().min(1).optional(),
928-
missingSlots: z.array(z.string().min(1)).optional(),
928+
missingFields: z.array(z.string().min(1)).optional(),
929929
notes: z.array(z.string().min(1)).optional(),
930930
});
931931

0 commit comments

Comments
 (0)