257 lines · 7.5 KB · TypeScript
RawDownload
import { EMPTY_V2_ITEM_SUPPORT } from "@t3tools/client-runtime/state/item-support";import {  CheckpointId,  CheckpointScopeId,  NodeId,  ProviderDriverKind,  ProviderInstanceId,  RunId,  ThreadId,  TurnItemId,  type OrchestrationV2ProjectedTurnItem,  type OrchestrationV2TurnItem,} from "@t3tools/contracts";import * as DateTime from "effect/DateTime";import { describe, expect, it } from "vite-plus/test"; import { buildThreadFeed, type ThreadFeedActivity } from "./threadActivity";import { buildThreadActivityInspector } from "./threadActivityInspector"; const threadId = ThreadId.make("thread-1");const sourceThreadId = ThreadId.make("thread-source");const runId = RunId.make("run-1");const nodeId = NodeId.make("node-1");const startedAt = DateTime.makeUnsafe("2026-06-20T00:00:00.000Z");const completedAt = DateTime.makeUnsafe("2026-06-20T00:00:02.000Z"); function itemBase(id: string) {  return {    id: TurnItemId.make(id),    threadId,    runId,    nodeId,    providerThreadId: null,    providerTurnId: null,    nativeItemRef: null,    parentItemId: null,    ordinal: 0,    status: "completed" as const,    title: null,    startedAt,    completedAt,    updatedAt: completedAt,  };} function activityFor(item: OrchestrationV2TurnItem): ThreadFeedActivity {  const row: OrchestrationV2ProjectedTurnItem = {    position: 0,    visibility: "inherited",    sourceThreadId,    sourceItemId: item.id,    item,  };  const group = buildThreadFeed([row])[0];  if (group?.type !== "activity-group" || !group.activities[0]) {    throw new Error("Expected an activity group");  }  return group.activities[0];} describe("buildThreadActivityInspector", () => {  it("presents command lifecycle, execution support, output, and exit state", () => {    const item: OrchestrationV2TurnItem = {      ...itemBase("command"),      type: "command_execution",      input: "vp check",      output: "all checks passed",      exitCode: 0,    };    const support = {      ...EMPTY_V2_ITEM_SUPPORT,      item,      run: { status: "completed" } as never,      attempts: [        {          id: "attempt-1",          attemptOrdinal: 1,          status: "superseded",          reason: "initial",        },        {          id: "attempt-2",          attemptOrdinal: 2,          status: "completed",          reason: "steering_restart",        },      ] as never,      node: { kind: "tool_call", status: "completed" } as never,      providerSession: {        status: "ready",        model: "gpt-5.4",        cwd: "/workspace/project",      } as never,    };     const model = buildThreadActivityInspector(activityFor(item), support, sourceThreadId);    expect(model.fields).toEqual(      expect.arrayContaining([        { label: "Duration", value: "2.0s" },        { label: "Run", value: "completed" },        { label: "Working directory", value: "/workspace/project" },        { label: "Visibility", value: "inherited" },      ]),    );    expect(model.blocks).toEqual(      expect.arrayContaining([        expect.objectContaining({ label: "Command", value: "vp check" }),        expect.objectContaining({ label: "Output", value: "all checks passed" }),        expect.objectContaining({ label: "Exit", value: "Process exited with code 0" }),        expect.objectContaining({ label: "Attempt history" }),      ]),    );  });   it("exposes file and web result provenance plus dynamic structured data", () => {    const fileSearch: OrchestrationV2TurnItem = {      ...itemBase("file-search"),      type: "file_search",      pattern: "resolveSession",      results: [{ fileName: "src/session.ts", line: 42, preview: "function resolveSession()" }],    };    const fileModel = buildThreadActivityInspector(      activityFor(fileSearch),      EMPTY_V2_ITEM_SUPPORT,      sourceThreadId,    );    expect(fileModel.fileLinks).toEqual([      {        label: "src/session.ts — function resolveSession()",        path: "src/session.ts",        line: 42,      },    ]);     const webSearch: OrchestrationV2TurnItem = {      ...itemBase("web-search"),      type: "web_search",      patterns: ["Effect Schema docs"],      results: [        { title: "Schema", url: "https://effect.website/docs/schema", snippet: "Typed schemas" },      ],    };    const webModel = buildThreadActivityInspector(      activityFor(webSearch),      EMPTY_V2_ITEM_SUPPORT,      sourceThreadId,    );    expect(webModel.webLinks).toEqual([      { label: "Schema", url: "https://effect.website/docs/schema" },    ]);    expect(webModel.blocks).toEqual(      expect.arrayContaining([        expect.objectContaining({ label: "Schema", value: "Typed schemas" }),      ]),    );     const dynamicTool: OrchestrationV2TurnItem = {      ...itemBase("dynamic"),      type: "dynamic_tool",      toolName: "custom",      input: { nested: { value: 1 } },      output: { ok: true },    };    const dynamicModel = buildThreadActivityInspector(      activityFor(dynamicTool),      EMPTY_V2_ITEM_SUPPORT,      sourceThreadId,    );    expect(dynamicModel.blocks).toEqual(      expect.arrayContaining([        expect.objectContaining({ label: "Input", value: expect.stringContaining('"nested"') }),        expect.objectContaining({ label: "Output", value: expect.stringContaining('"ok"') }),      ]),    );    expect(dynamicModel.structuredDetails).toContain('"type": "dynamic_tool"');  });   it("enables rollback only for the matching ready checkpoint", () => {    const checkpointId = CheckpointId.make("checkpoint-1");    const scopeId = CheckpointScopeId.make("scope-1");    const item: OrchestrationV2TurnItem = {      ...itemBase("checkpoint"),      type: "checkpoint",      checkpointId,      scopeId,      files: [{ path: "src/main.ts", kind: "modified", additions: 2, deletions: 1 }],    };    const checkpoint = { id: checkpointId, scopeId, status: "ready" } as never;    const model = buildThreadActivityInspector(      activityFor(item),      {        ...EMPTY_V2_ITEM_SUPPORT,        item,        checkpoint,      },      sourceThreadId,    );     expect(model.canRollback).toBe(true);    expect(model.rollbackTarget).toEqual({      threadId: sourceThreadId,      checkpointId,      scopeId,    });     const inheritedModel = buildThreadActivityInspector(      activityFor(item),      {        ...EMPTY_V2_ITEM_SUPPORT,        item,        checkpoint,      },      ThreadId.make("child-thread"),    );    expect(inheritedModel.canRollback).toBe(false);    expect(inheritedModel.rollbackTarget).toBeNull();  });   it("prefers live subagent progress from supporting state", () => {    const item: OrchestrationV2TurnItem = {      ...itemBase("subagent"),      type: "subagent",      subagentId: nodeId,      origin: "provider_native",      driver: ProviderDriverKind.make("claude"),      providerInstanceId: ProviderInstanceId.make("claude"),      childThreadId: null,      prompt: "Audit the reducer",      progress: "Starting",      result: null,    };    const model = buildThreadActivityInspector(      activityFor(item),      {        ...EMPTY_V2_ITEM_SUPPORT,        item,        subagent: {          origin: "provider_native",          status: "running",          progress: "Reading projection tests",          result: null,        } as never,      },      sourceThreadId,    );     expect(model.fields).toContainEqual({      label: "Delegated task",      value: "provider native · running",    });    expect(model.blocks).toContainEqual({      label: "Progress",      value: "Reading projection tests",      monospaced: false,    });  });});