mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-05 03:51:54 +01:00
17 lines
4.0 KiB
TypeScript
17 lines
4.0 KiB
TypeScript
import {afterEach,expect,it,vi} from "vitest";
|
|
import type {ChatCatalogContext} from "./chat-catalog-contract.js";
|
|
import {chatCatalogNativePhaseDeadline,chatCatalogNativePhaseIsTimely,chatCatalogOriginalPhaseDeadline} from "./chat-catalog-contract.js";
|
|
import {completionObservationBounds} from "./completion-update-flow.js";
|
|
import {pollUntil} from "./api.js";
|
|
void pollUntil;
|
|
import {waitForReply} from "./chat-catalog-domains/identity-support.js";
|
|
const ids=["access.cli-authorization", "access.other-company", "access.private-resource", "agent-chat.conference-room", "agent-chat.track-delegated-work", "agents.agent-api-key", "agents.hire-needs-approval", "agents.pause-agent", "agents.retire-agent", "app-permissions.new-quarantined-action", "app-permissions.read-allowed-write-off", "app-permissions.test-as-agent", "assistant-connections.device-login", "budgets-costs.explain-hard-stop", "budgets-costs.set-budget", "cases.case-history", "inbox-search.archive-without-grant", "inbox-search.show-my-work", "tasks.ambiguous-task"];
|
|
const ctx=(id:string,deadline=270000)=>({scenario:{id},input:{execution:{id:`chat-features.runner-opencode.local.${id}`}},observationDeadlineAt:deadline,issue:()=>({conversationState:"waiting"}),refreshIssue:async()=>{},allRuns:async()=>[{status:Date.now()>=180000?"succeeded":"running"}]} as unknown as ChatCatalogContext);
|
|
afterEach(()=>vi.useRealTimers());
|
|
it.each(ids)("%s consumes the original setup-inclusive clock with no new grace",id=>{vi.useFakeTimers();vi.setSystemTime(200000);const c=ctx(id);expect(chatCatalogNativePhaseDeadline(c,350000)).toBe(270000);expect(chatCatalogOriginalPhaseDeadline(c)).toBe(270000);vi.setSystemTime(270000);expect(chatCatalogNativePhaseIsTimely(c)).toBe(false);expect(()=>chatCatalogOriginalPhaseDeadline(c)).toThrow(/exhausted/);});
|
|
it("actual selected identity reply wait survives its artificial150s cap but keeps the original deadline",async()=>{vi.useFakeTimers();vi.setSystemTime(0);const c=ctx("budgets-costs.set-budget");const result=waitForReply(c,chatCatalogOriginalPhaseDeadline(c)).then(()=>"accepted",()=>"expired");await vi.advanceTimersByTimeAsync(0);await vi.advanceTimersByTimeAsync(181000);expect(await result).toBe("accepted");expect(c.observationDeadlineAt).toBe(270000);});
|
|
it("selected identity helper rejects a success read after the original clock",async()=>{vi.useFakeTimers();vi.setSystemTime(269999);const c=ctx("access.cli-authorization");c.refreshIssue=async()=>{vi.setSystemTime(270001);};c.allRuns=async()=>[{status:"succeeded"}] as never;const result=waitForReply(c,chatCatalogOriginalPhaseDeadline(c)).then(()=>"accepted",()=>"expired");await vi.advanceTimersByTimeAsync(1000);expect(await result).toBe("expired");});
|
|
it("keeps exhausted cases, provenance controls and other provider lanes outside this new clock scope",()=>{vi.useFakeTimers();vi.setSystemTime(200000);for(const id of ["chat-channels.provider-disabled","access.sign-in","agents.hire-denied","agent-chat.chat-disabled","tasks.create-backlog","activity.audit-change","cli-operations.choose-cli-context","companies.rename-company"]){const c=ctx(id);expect(chatCatalogOriginalPhaseDeadline(c)).toBeUndefined();expect(chatCatalogNativePhaseDeadline(c,350000)).toBe(350000);}const c=ctx(ids[0]!);Object.assign(c.input.execution,{id:`chat-features.runner-codex.local.${ids[0]}`});expect(chatCatalogOriginalPhaseDeadline(c)).toBeUndefined();});
|
|
|
|
it("completion observation retains its full120s stability minimum without restarting or extending the original clock",()=>{expect(completionObservationBounds(10000)).toEqual({observationWindowEndsAt:130000,deadlineAt:135000});expect(completionObservationBounds(10000,570000)).toEqual({observationWindowEndsAt:130000,deadlineAt:570000});expect(completionObservationBounds(200000,570000)).toEqual({observationWindowEndsAt:320000,deadlineAt:570000});expect(completionObservationBounds(560000,570000)).toEqual({observationWindowEndsAt:680000,deadlineAt:570000});for(const d of [NaN,Infinity,10000,9999])expect(()=>completionObservationBounds(10000,d)).toThrow(/exhausted or invalid/);});
|