Skip to content

Commit 9a1bdba

Browse files
committed
Fix unresolved slots overriding prior slots
1 parent 90d6c35 commit 9a1bdba

2 files changed

Lines changed: 56 additions & 22 deletions

File tree

packages/core/src/commit-policy.test.ts

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { describe, expect, it } from "vitest";
22

33
import type { CommitPolicyInput } from "./commit-policy";
44
import { applyCommitPolicy } from "./commit-policy";
5-
import type { WriteContract } from "./index";
5+
import type { TimeSpec, WriteContract } from "./index";
6+
7+
function t(hour: number, minute: number): TimeSpec {
8+
return { kind: "absolute", hour, minute };
9+
}
610

711
const defaultContract: WriteContract = {
812
requiredSlots: ["day", "time"],
@@ -26,7 +30,7 @@ describe("applyCommitPolicy", () => {
2630
const result = applyCommitPolicy(
2731
buildInput({
2832
turnType: "informational",
29-
extractedValues: { time: "15:00" },
33+
extractedValues: { time: t(15, 0) },
3034
confidence: { time: 0.95 },
3135
}),
3236
);
@@ -38,7 +42,7 @@ describe("applyCommitPolicy", () => {
3842
const result = applyCommitPolicy(
3943
buildInput({
4044
turnType: "confirmation",
41-
extractedValues: { time: "15:00" },
45+
extractedValues: { time: t(15, 0) },
4246
confidence: { time: 0.95 },
4347
}),
4448
);
@@ -50,12 +54,12 @@ describe("applyCommitPolicy", () => {
5054
const result = applyCommitPolicy(
5155
buildInput({
5256
turnType: "planning_request",
53-
extractedValues: { time: "17:00", day: "tomorrow" },
57+
extractedValues: { time: t(17, 0), day: "tomorrow" },
5458
confidence: { time: 0.9, day: 0.85 },
5559
}),
5660
);
5761

58-
expect(result.committedSlots.time).toBe("17:00");
62+
expect(result.committedSlots.time).toEqual(t(17, 0));
5963
expect(result.committedSlots.day).toBe("tomorrow");
6064
expect(result.needsClarification).toEqual([]);
6165
});
@@ -64,7 +68,7 @@ describe("applyCommitPolicy", () => {
6468
const result = applyCommitPolicy(
6569
buildInput({
6670
turnType: "planning_request",
67-
extractedValues: { time: "17:00" },
71+
extractedValues: { time: t(17, 0) },
6872
confidence: { time: 0.6 },
6973
}),
7074
);
@@ -77,27 +81,27 @@ describe("applyCommitPolicy", () => {
7781
const result = applyCommitPolicy(
7882
buildInput({
7983
turnType: "clarification_answer",
80-
extractedValues: { time: "15:00" },
84+
extractedValues: { time: t(15, 0) },
8185
confidence: { time: 0.8 },
82-
priorResolvedSlots: { time: "14:00" },
86+
priorResolvedSlots: { time: t(14, 0) },
8387
}),
8488
);
8589

86-
expect(result.committedSlots.time).toBe("14:00");
90+
expect(result.committedSlots.time).toEqual(t(14, 0));
8791
expect(result.needsClarification).toContain("time");
8892
});
8993

9094
it("commits correction at or above correction threshold", () => {
9195
const result = applyCommitPolicy(
9296
buildInput({
9397
turnType: "clarification_answer",
94-
extractedValues: { time: "15:00" },
98+
extractedValues: { time: t(15, 0) },
9599
confidence: { time: 0.92 },
96-
priorResolvedSlots: { time: "14:00" },
100+
priorResolvedSlots: { time: t(14, 0) },
97101
}),
98102
);
99103

100-
expect(result.committedSlots.time).toBe("15:00");
104+
expect(result.committedSlots.time).toEqual(t(15, 0));
101105
expect(result.needsClarification).not.toContain("time");
102106
});
103107

@@ -120,7 +124,7 @@ describe("applyCommitPolicy", () => {
120124
turnType: "planning_request",
121125
extractedValues: { day: "friday" },
122126
confidence: { day: 0.9 },
123-
priorResolvedSlots: { time: "14:00", day: "tomorrow" },
127+
priorResolvedSlots: { time: t(14, 0), day: "tomorrow" },
124128
activeContract: { requiredSlots: ["day", "time"], intentKind: "edit" },
125129
priorContract: { requiredSlots: ["day", "time"], intentKind: "plan" },
126130
}),
@@ -136,13 +140,13 @@ describe("applyCommitPolicy", () => {
136140
turnType: "planning_request",
137141
extractedValues: { day: "friday" },
138142
confidence: { day: 0.9 },
139-
priorResolvedSlots: { time: "14:00" },
143+
priorResolvedSlots: { time: t(14, 0) },
140144
activeContract: { requiredSlots: ["day", "time"], intentKind: "plan" },
141145
priorContract: { requiredSlots: ["day"], intentKind: "plan" },
142146
}),
143147
);
144148

145-
expect(result.committedSlots.time).toBe("14:00");
149+
expect(result.committedSlots.time).toEqual(t(14, 0));
146150
expect(result.committedSlots.day).toBe("friday");
147151
});
148152

@@ -179,35 +183,35 @@ describe("applyCommitPolicy", () => {
179183
const result = applyCommitPolicy(
180184
buildInput({
181185
turnType: "clarification_answer",
182-
extractedValues: { time: "17:00" },
186+
extractedValues: { time: t(17, 0) },
183187
confidence: { time: 0.9 },
184188
priorResolvedSlots: { day: "tomorrow" },
185189
}),
186190
);
187191

188192
expect(result.committedSlots.day).toBe("tomorrow");
189-
expect(result.committedSlots.time).toBe("17:00");
193+
expect(result.committedSlots.time).toEqual(t(17, 0));
190194
});
191195

192196
it("commits slots for edit_request turn type", () => {
193197
const result = applyCommitPolicy(
194198
buildInput({
195199
turnType: "edit_request",
196-
extractedValues: { time: "10:00" },
200+
extractedValues: { time: t(10, 0) },
197201
confidence: { time: 0.88 },
198202
activeContract: { requiredSlots: ["time"], intentKind: "edit" },
199203
}),
200204
);
201205

202-
expect(result.committedSlots.time).toBe("10:00");
206+
expect(result.committedSlots.time).toEqual(t(10, 0));
203207
expect(result.missingSlots).toEqual([]);
204208
});
205209

206210
it("treats missing confidence as zero", () => {
207211
const result = applyCommitPolicy(
208212
buildInput({
209213
turnType: "planning_request",
210-
extractedValues: { time: "17:00" },
214+
extractedValues: { time: t(17, 0) },
211215
confidence: {},
212216
}),
213217
);
@@ -216,6 +220,22 @@ describe("applyCommitPolicy", () => {
216220
expect(result.needsClarification).toContain("time");
217221
});
218222

223+
it("does not flag unresolvable slot that is already resolved from prior turn", () => {
224+
const result = applyCommitPolicy(
225+
buildInput({
226+
turnType: "clarification_answer",
227+
extractedValues: { day: "friday" },
228+
confidence: { day: 0.9 },
229+
unresolvable: ["time"],
230+
priorResolvedSlots: { time: t(14, 0) },
231+
}),
232+
);
233+
234+
expect(result.committedSlots.time).toEqual(t(14, 0));
235+
expect(result.needsClarification).not.toContain("time");
236+
expect(result.committedSlots.day).toBe("friday");
237+
});
238+
219239
it("handles unresolvable slots not in extractedValues", () => {
220240
const result = applyCommitPolicy(
221241
buildInput({

packages/core/src/commit-policy.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import type {
22
ResolvedSlots,
33
SlotKey,
4+
TimeSpec,
45
TurnInterpretation,
56
WriteContract,
67
} from "./index";
8+
import { timeSpecsEqual } from "./time-spec";
79

810
export type CommitPolicyInput = {
911
turnType: TurnInterpretation["turnType"];
@@ -76,7 +78,8 @@ export function applyCommitPolicy(
7678
}
7779

7880
const priorValue = priorSlots[slot];
79-
const isCorrection = priorValue !== undefined && priorValue !== value;
81+
const isCorrection =
82+
priorValue !== undefined && !slotValuesEqual(slot, priorValue, value);
8083
if (isCorrection && slotConfidence < CORRECTION_THRESHOLD) {
8184
needsClarification.push(slot);
8285
continue;
@@ -86,7 +89,11 @@ export function applyCommitPolicy(
8689
}
8790

8891
for (const slot of unresolvable) {
89-
if (!slotKeys.includes(slot) && !needsClarification.includes(slot)) {
92+
if (
93+
!slotKeys.includes(slot) &&
94+
!needsClarification.includes(slot) &&
95+
committedSlots[slot] === undefined
96+
) {
9097
needsClarification.push(slot);
9198
}
9299
}
@@ -104,3 +111,10 @@ function deriveMissingSlots(
104111
): SlotKey[] {
105112
return contract.requiredSlots.filter((slot) => committed[slot] === undefined);
106113
}
114+
115+
function slotValuesEqual(slot: SlotKey, a: unknown, b: unknown): boolean {
116+
if (slot === "time" && a && b) {
117+
return timeSpecsEqual(a as TimeSpec, b as TimeSpec);
118+
}
119+
return a === b;
120+
}

0 commit comments

Comments
 (0)