@usecontextlayer/pi-durable-assistant-ui 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,83 +1,68 @@
1
- <div align="center">
2
-
3
1
  # Pi Durable for Assistant UI
4
2
 
5
- Render [Pi Durable](https://github.com/earendil-works/pi/tree/v1.5.0/packages/durable) conversations with [Assistant UI](https://www.assistant-ui.com) while Pi owns history and execution.
6
-
7
- </div>
8
-
9
- ```tsx
10
- import type { ReactNode } from "react";
11
- import { AssistantRuntimeProvider } from "@assistant-ui/react";
12
- import { createHttpPiClient, usePiRuntime } from "@usecontextlayer/pi-durable-assistant-ui";
13
- const client = createHttpPiClient({ baseUrl: "/api" });
14
- ```
15
-
16
- ```tsx
17
- export function PiChat({ children }: { children: ReactNode }) {
18
- const { runtime } = usePiRuntime({ client });
19
- return <AssistantRuntimeProvider runtime={runtime}>{children}</AssistantRuntimeProvider>;
20
- }
21
- ```
3
+ Render native Pi Durable conversations through Assistant UI. Pi owns durable history, execution, submissions and configuration; Assistant UI owns thread navigation, drafts, initialization and directory pagination.
22
4
 
23
- - **Use Assistant UI components.** The hook supplies an `ExternalStoreRuntime` for your thread, composer, and conversation list.
24
- - **Keep Pi as the source of truth.** One thread maps to one native conversation. The browser stores no second durable transcript and runs no model.
25
- - **Reconnect to ongoing work.** Streaming, earlier history, and reconnect gaps use native Pi views and `ConversationTranscript`. Closing a subscription does not cancel execution.
26
- - **Choose your host.** Implement `PiClient` or use the included HTTP/SSE client with the demo's protocol. The adapter has no dependency on the demo's Node/SQLite host.
5
+ ## Build and consume
27
6
 
28
- ## Install
7
+ From the repository root:
29
8
 
30
9
  ```sh
31
- pnpm add @usecontextlayer/pi-durable-assistant-ui @assistant-ui/react@0.15.32 react@19 react-dom@19
10
+ pnpm install --frozen-lockfile
11
+ pnpm exec turbo run build --filter=@usecontextlayer/pi-durable-assistant-ui
12
+ pnpm --dir packages/adapter pack
32
13
  ```
33
14
 
34
- The package builds as ESM with TypeScript declarations. It requires React 19 and `@assistant-ui/react` 0.15.32; Pi Durable, Pi AI, and Chord are pinned to 1.5.0. Keep the client instance stable, as in the example above, and render your Assistant UI components inside `PiChat`. This package supplies the runtime integration, not the demo's components or server.
15
+ Install the resulting tarball into your application, together with React 19, `@assistant-ui/react` compatible with `^0.15.32`, and Pi Durable compatible with `^1.5.0`. Pi Durable is a peer because native branded identifiers cross the host boundary. The checkout pins its verification dependencies in pnpm-lock.yaml. The adapter builds as ESM with TypeScript declarations and does not depend on the demo's Node/SQLite host.
35
16
 
36
- ## Build from source
17
+ ```tsx
18
+ import { AssistantRuntimeProvider } from "@assistant-ui/react";
19
+ import {
20
+ createHttpPiDurableClient,
21
+ usePiDurableRuntime,
22
+ } from "@usecontextlayer/pi-durable-assistant-ui";
37
23
 
38
- From the workspace root, build and pack it:
24
+ const client = createHttpPiDurableClient({ baseUrl: "/api" });
39
25
 
40
- ```sh
41
- pnpm exec turbo run build --filter=@usecontextlayer/pi-durable-assistant-ui
42
- pnpm --dir packages/adapter pack
26
+ export function PiChat({ children }: { children: React.ReactNode }) {
27
+ const runtime = usePiDurableRuntime({ client });
28
+ return <AssistantRuntimeProvider runtime={runtime}>{children}</AssistantRuntimeProvider>;
29
+ }
43
30
  ```
44
31
 
45
- Install the resulting tarball in your application and supply the React and Assistant UI peers.
46
-
47
- ## Runtime and actions
32
+ Keep the client stable. `usePiDurableRuntime` returns the standard Assistant UI runtime, so thread selection and directory actions use Assistant UI's APIs and primitives. Pass a controlled native `threadId` and `onThreadIdChange` to connect navigation to a URL. New threads are framework drafts until their first send initializes a native conversation. Assistant UI's temporary local identifiers remain internal; the canonical remote ID is the string representation of the native Pi conversation ID. Forks select their own native conversation as another thread.
48
33
 
49
- `usePiRuntime` returns `{ runtime, state, actions }`. `state` exposes the native conversation directory, selected ID, merged transcript view, rendered messages, running/connection/loading state, errors, and metadata. `actions` exposes conversation selection and creation, earlier-history loading, submissions, continuation, steering, withdrawal, configuration, cancellation, forks, reset, and compaction where the client supports them.
34
+ The remote runtime retains visited thread runtimes until its lifecycle releases them. Each initialized thread owns a `PiDurableConversation`, its native `ConversationTranscript`, conversation observation and optional metadata observation. Closing an observation never cancels agent execution. Directory pages load on demand; the adapter reads metadata only for that page and does not rescan the entire directory after every answer.
50
35
 
51
- Pass `initialConversationId` to reopen a native conversation, for example an ID saved in your URL. It applies when the store is constructed; later navigation uses `actions.selectConversation(id)`. `whenBusy` selects Pi's `followUp`, `steer`, or `reject` submission behavior.
36
+ ## Native state and actions
52
37
 
53
- For use outside React, `PiRuntimeStore` exposes the same actions with `start`, `stop`, `subscribe`, and `getSnapshot`. `projectConversation` supplies the pure message projection.
38
+ Inside `AssistantRuntimeProvider`, `usePiDurable()` reads the current thread's `{ conversation, state }` extras. `conversation` is undefined for a draft; otherwise its ID and all its actions are bound to one native conversation. `state` contains the merged native view, metadata, transport connection/loading state and an error when one is reported. Native controls can use submission, continuation, steering, withdrawal, cancellation, configuration, forks, reset, compaction and earlier-history operations where the host supplies them.
54
39
 
55
- ## Host contract
40
+ For direct non-React observation, construct `new PiDurableConversation(client, id, pageSize)`, subscribe with `subscribe`/`getSnapshot`, then call `start` and `stop`. It has no selection method or global directory. Edit and regeneration return a native fork and target both the context write and continuation explicitly at that fork; the React integration then asks Assistant UI to select it.
56
41
 
57
- `PiClient` is a structural interface whose optional methods describe host capabilities. Assistant UI callbacks are enabled only when the corresponding capability exists. The included `createHttpPiClient` returns `Required<PiClient>` and expects the demo's native-operation routes: an ordinary Pi host does not acquire those routes simply by installing this package.
42
+ ## Host contract and observation
58
43
 
59
- The HTTP watch carries an initial `ConversationView` and subsequent Chord operations over SSE. Pi's `ConversationTranscript` merges the bounded live view with earlier history and supplies reconnect windows. The host owns execution independently of each browser's watch.
44
+ Implement the structural `PiDurableClient` or use `createHttpPiDurableClient` with the demo protocol. Installing the adapter does not install server routes. Optional client methods describe host extensions; titles, feedback, suggestions, uploads and human input require the corresponding host implementation.
60
45
 
61
- Conversation and entry IDs remain Pi's IDs; their string representations are UI keys. Live generation uses a native task-derived key until its immutable entry arrives. Projection matches tool results by native call ID, retains partial output, separates foreground generation from after-run activity, and leaves internal instruction entries out of chat. Raw history remains available through `state.view`.
46
+ `watch` returns Pi/Chord's standard asynchronous watch handle: current immutable `value`, `start`, `stop` and terminal `closed` outcome. HTTP carries an initial view, native Chord operations, recoverable source failures and terminal outcomes over one shared SSE connection per client. Logical subscriptions are tagged independently so retained thread runtimes do not exhaust browser HTTP connection limits. It reconstructs the same watch contract in the browser using Chord. Transport reconnection status remains separate from source termination. Native acquisition failures and terminal outcomes close the source rather than retrying indefinitely. Resume windows come from the thread's native transcript.
62
47
 
63
- `SerializedAgentChange` carries JSON configuration with registered tool, extension, and model-tool names. The host resolves those names before native configuration; omitted fields are unchanged and `null` clears a field.
48
+ `watchMetadata`, when supplied, observes the host's native metadata document. The demo uses a conversation document for title, feedback keyed by native entry ID and static suggestions, with checkpoints on updates. The native creation hook initializes the document for each conversation, including forks. Native conversation views do not include arbitrary custom documents. Metadata changes update mounted conversations live; an observed title change refreshes Assistant UI's directory through its reload API. Newly created conversations from another client appear on explicit directory refresh. The optional batch metadata operation accepts only the IDs in the requested directory page.
64
49
 
65
- ## Edits and forks
50
+ `SerializedAgentChange` carries JSON tool, extension and model-tool names; the host resolves those names into registered native definitions. Omitted fields remain unchanged and null clears a field. Host-specific registry and execution-environment choices remain outside the adapter.
66
51
 
67
- Editing forks at the original input, records a native context replacement, and continues the new conversation. Regeneration forks at the selected answer, omits it from the fork's model context through a native context edit, and continues. The original immutable history stays available.
52
+ ## Message semantics
68
53
 
69
- Each native fork is a separate thread. No hidden in-thread branch store or `setMessages` callback overwrites Pi history.
54
+ The projection uses native entry IDs, joins tool results by native call ID and marks transient live messages optimistic so Assistant UI can evict them when committed entries arrive. Tool output is distinct from its UI-only artifact; native image output remains available as model content. The exported `PiDurableHumanInputDetails` artifact contract (native task ID, prompt, pending/answered status and answered response) becomes a text tool-approval request, and `onRespondToToolApproval` calls the host response operation for the native task. A response does not fabricate a browser-side tool result.
70
55
 
71
- ## Attachments and extensions
56
+ Reset and compaction notices are named `pi-context` data parts. Consumers register their own data renderer; the demo supplies one. Native entry guards classify those notices. Committed-history projection is memoized separately from live execution so unchanged message objects survive streaming updates. The pure `projectConversation` export remains available for non-React consumers.
72
57
 
73
- Pass `createPiAttachmentAdapter(client.uploadFile)` as the hook's `attachments` option when the host supports uploads. Uploads happen on send. `PiUploadResult` requires only `name` and `content`, an array of native Pi input blocks: images can remain image blocks; other files can be paths readable by native tools. The adapter returns Assistant UI's standard `CompleteAttachment`. The host owns storage; paths, download URLs, sizes and content types are not required by the adapter. Removing a draft attachment does not delete an uploaded workspace file.
58
+ ## Queue and unsupported operations
74
59
 
75
- The hook accepts Assistant UI's `speech`, `dictation`, and `feedback` adapters. For browser voice controls, use `WebSpeechSynthesisAdapter` and support-gated `WebSpeechDictationAdapter` from Assistant UI. No speech provider is built into this package; browser support and permissions remain the consumer's responsibility.
60
+ The standard composer can send during a run through a queue adapter backed by Pi's native inbox. Assistant UI's normal busy send steers; `aui.composer().send({ steer: false })` enqueues a follow-up. Queue items retain native submission IDs, and removing one withdraws that submission. Pi owns processing and cancellation behavior; the adapter does not drain a second queue.
76
61
 
77
- The optional `respondToHumanInput` client operation sends a response to a host's durable human-interaction extension. It answers the native task rather than fabricating a browser-side tool result.
62
+ Pi Durable 1.5.0 has no native queue move/edit, permanent conversation deletion, archive or unarchive operation. Required delete, archive and queue move/edit methods reject explicitly; optional unarchive is omitted so Assistant UI reports that capability as unavailable. The demo exposes none of those controls. Archive is not simulated with a custom document. Withdrawal followed by another submission remains two distinct native operations with a new ID. Unsupported operations never report success.
78
63
 
79
- ## Titles, archive, and feedback
64
+ ## Attachments, feedback and voice
80
65
 
81
- Optional metadata methods support titles, archive state, feedback keyed by native entry ID, and suggestions. The demo persists these in a native Pi conversation document. Such custom metadata is not included in `ConversationView.docs`, so the adapter reads it explicitly. Archiving preserves history; no permanent-delete operation is invented.
66
+ `createPiDurableAttachmentAdapter(client.uploadFile)` uses Assistant UI's attachment lifecycle and returns `CompleteAttachment`. The uploader supplies a name and native Pi input blocks; host storage paths, download URLs and content types remain host concerns. Removing a draft attachment does not delete an uploaded file from the host workspace.
82
67
 
83
- The directory follows native pagination and loads metadata in bulk. Starting observation and completing observed work refresh the directory; connecting or reconnecting the selected conversation refreshes its metadata. Mutations publish the host's returned metadata. There is no cross-browser subscription for the directory or metadata: changes made elsewhere appear on the next applicable read or explicit refresh. Messages and execution remain live through the conversation watch. `state.metadata` uses stringified native conversation IDs as keys.
68
+ Pass Assistant UI's `speech`, `dictation`, `attachments` and optional `feedback` adapters directly to the runtime hook. Without a feedback override, the native host feedback extension is used when available. Browser speech and dictation use Assistant UI's official adapters and support checks; actual microphone capture and audible playback remain device-dependent and unverified in this project.
@@ -1,5 +1,5 @@
1
1
  import type { AttachmentAdapter } from "@assistant-ui/react";
2
- import type { PiUploadResult } from "./client.js";
2
+ import type { PiDurableUploadResult } from "./client.js";
3
3
  /** Uploads at send time; the host decides which native Pi input represents the file. */
4
- export declare function createPiAttachmentAdapter(upload: (file: File, signal?: AbortSignal) => Promise<PiUploadResult>): AttachmentAdapter;
4
+ export declare function createPiDurableAttachmentAdapter(upload: (file: File, signal?: AbortSignal) => Promise<PiDurableUploadResult>): AttachmentAdapter;
5
5
  //# sourceMappingURL=attachments.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../src/attachments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAsB,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,wFAAwF;AACxF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,cAAc,CAAC,GAAG,iBAAiB,CAoBlI"}
1
+ {"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../src/attachments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAsB,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,wFAAwF;AACxF,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,qBAAqB,CAAC,GAAG,iBAAiB,CAoBhJ"}
@@ -1,5 +1,5 @@
1
1
  /** Uploads at send time; the host decides which native Pi input represents the file. */
2
- export function createPiAttachmentAdapter(upload) {
2
+ export function createPiDurableAttachmentAdapter(upload) {
3
3
  return {
4
4
  accept: "*",
5
5
  async add({ file }) {
package/dist/client.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { type Op } from "@earendil-works/chord/delta";
2
+ import { type WatchHandle, type WatchEnd } from "@earendil-works/chord";
2
3
  import type { ConversationCreateOptions, ConversationId, ConversationQuery, ConversationRecord, ConversationView, ConversationWindow, ConversationAbortOptions, ContextView, AgentState, CompactionResult, Cursor, EntryQuery, EntryRecord, EntryId, Page, SubmissionDraft, SubmissionId, SubmissionRecord, TaskId, UserInput, Harness, HarnessInspection } from "@earendil-works/pi-durable";
3
4
  import type { ConversationMetadata, ConversationMetadataPatch } from "./metadata.js";
4
5
  /** JSON form of Pi's stored configuration; the host resolves registry names. */
@@ -8,32 +9,60 @@ export type SerializedAgentChange = {
8
9
  export type SerializedConversationCreateOptions = Omit<ConversationCreateOptions, "agent" | "init"> & {
9
10
  agent?: SerializedAgentChange;
10
11
  };
11
- export type HttpPiWatchFrame = {
12
+ export type HttpPiDurableWatchFrame<T = ConversationView> = {
12
13
  type: "view";
13
- view: ConversationView;
14
+ view: T;
14
15
  } | {
15
16
  type: "ops";
16
17
  ops: readonly Op[];
18
+ } | {
19
+ type: "failed";
20
+ error: string;
21
+ } | {
22
+ type: "end";
23
+ kind: WatchEnd["kind"];
24
+ error?: string;
25
+ };
26
+ export type HttpPiDurableWatchSubscription = {
27
+ subscriptionId: number;
28
+ id: ConversationId;
29
+ kind: "conversation" | "metadata";
30
+ window?: ConversationWindow;
17
31
  };
18
- export type PiConnectionState = "idle" | "connecting" | "connected" | "reconnecting";
19
- export interface PiWatchOptions {
32
+ export type HttpPiDurableWatchEnvelope = {
33
+ subscriptionId: number;
34
+ frame: HttpPiDurableWatchFrame<unknown>;
35
+ };
36
+ export type PiDurableConnectionState = "idle" | "connecting" | "connected" | "reconnecting" | "closed";
37
+ export interface PiDurableWatchOptions {
20
38
  window?: () => ConversationWindow | undefined;
21
- onConnection?: (state: PiConnectionState) => void;
22
- onError?: (error: Error) => void;
39
+ onConnection?: (state: PiDurableConnectionState) => void;
40
+ signal?: AbortSignal;
23
41
  }
24
- export interface PiUploadResult {
42
+ export type PiDurableHumanInputDetails = {
43
+ type: "human-input";
44
+ taskId: TaskId;
45
+ prompt: string;
46
+ } & ({
47
+ status: "pending";
48
+ } | {
49
+ status: "answered";
50
+ response: string;
51
+ });
52
+ export interface PiDurableUploadResult {
25
53
  name: string;
26
54
  content: Exclude<UserInput, string>;
27
55
  }
28
56
  /** The native operations a browser needs, with server execution context already bound. */
29
- export interface PiClient {
57
+ export interface PiDurableClient {
30
58
  listConversations(query?: ConversationQuery, limit?: number, cursor?: Cursor): Promise<Page<ConversationRecord, Cursor>>;
31
59
  createConversation(options?: SerializedConversationCreateOptions): Promise<ConversationRecord>;
32
60
  getConversationView(id: ConversationId): Promise<ConversationView>;
33
61
  entries(id: ConversationId, query: Omit<EntryQuery, "conversationId">, limit: number, cursor?: Cursor, signal?: AbortSignal): Promise<Page<EntryRecord, Cursor>>;
34
62
  submit(id: ConversationId, submission: SubmissionDraft): Promise<SubmissionRecord>;
35
63
  getSubmission(id: SubmissionId): Promise<SubmissionRecord>;
36
- watch(id: ConversationId, onView: (view: ConversationView) => void, options?: PiWatchOptions): () => void;
64
+ watch(id: ConversationId, options?: PiDurableWatchOptions): Promise<WatchHandle<ConversationView>>;
65
+ watchMetadata?(id: ConversationId, signal?: AbortSignal): Promise<WatchHandle<ConversationMetadata>>;
37
66
  configure?(id: ConversationId, change: SerializedAgentChange): Promise<void>;
38
67
  abort?(id: ConversationId, options?: ConversationAbortOptions): Promise<void>;
39
68
  abortSubmission?(id: SubmissionId): ReturnType<Harness["abortSubmission"]>;
@@ -41,19 +70,19 @@ export interface PiClient {
41
70
  compact?(id: ConversationId, instructions?: string): Promise<TaskId<CompactionResult>>;
42
71
  fork?(id: ConversationId, at: EntryId, options?: SerializedConversationCreateOptions): Promise<ConversationRecord>;
43
72
  context?(id: ConversationId, at?: EntryId): Promise<ContextView>;
44
- uploadFile?(file: File, signal?: AbortSignal): Promise<PiUploadResult>;
73
+ uploadFile?(file: File, signal?: AbortSignal): Promise<PiDurableUploadResult>;
45
74
  respondToHumanInput?(taskId: TaskId, response: string): Promise<void>;
46
75
  inspect?(): Promise<HarnessInspection>;
47
- listMetadata?(): Promise<Record<string, ConversationMetadata>>;
76
+ listMetadata?(ids: readonly ConversationId[]): Promise<Record<string, ConversationMetadata>>;
48
77
  getMetadata?(id: ConversationId): Promise<ConversationMetadata>;
49
78
  updateMetadata?(id: ConversationId, patch: ConversationMetadataPatch): Promise<ConversationMetadata>;
50
79
  setFeedback?(id: ConversationId, entryId: EntryId, rating: "positive" | "negative" | null): Promise<ConversationMetadata>;
51
80
  }
52
- export interface HttpPiClientOptions {
81
+ export interface HttpPiDurableClientOptions {
53
82
  baseUrl?: string;
54
83
  fetch?: typeof globalThis.fetch;
55
84
  eventSource?: (url: string) => EventSource;
56
85
  reconnectDelayMs?: number;
57
86
  }
58
- export declare function createHttpPiClient(options?: HttpPiClientOptions): Required<PiClient>;
87
+ export declare function createHttpPiDurableClient(options?: HttpPiDurableClientOptions): Required<PiDurableClient>;
59
88
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,8 +1,50 @@
1
1
  import { applyImmutable } from "@earendil-works/chord/delta";
2
- export function createHttpPiClient(options = {}) {
2
+ import { Watch } from "@earendil-works/chord";
3
+ import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
4
+ export function createHttpPiDurableClient(options = {}) {
3
5
  const baseUrl = (options.baseUrl ?? "/api").replace(/\/$/, "");
4
6
  const fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
5
7
  const openEvents = options.eventSource ?? ((url) => new EventSource(url));
8
+ const subscriptions = new Map();
9
+ let nextSubscriptionId = 0;
10
+ let source;
11
+ let retry;
12
+ let connectQueued = false;
13
+ function scheduleConnect() {
14
+ clearTimeout(retry);
15
+ if (connectQueued)
16
+ return;
17
+ connectQueued = true;
18
+ queueMicrotask(() => { connectQueued = false; connect(); });
19
+ }
20
+ function connect() {
21
+ source?.close();
22
+ source = undefined;
23
+ if (subscriptions.size === 0)
24
+ return;
25
+ for (const subscription of subscriptions.values())
26
+ subscription.connection("connecting");
27
+ const connection = openEvents(url("/watch", { subscriptions: [...subscriptions.values()].map((subscription) => subscription.request()) }));
28
+ source = connection;
29
+ connection.onmessage = (event) => {
30
+ try {
31
+ const { subscriptionId, frame } = JSON.parse(event.data);
32
+ subscriptions.get(subscriptionId)?.receive(frame);
33
+ }
34
+ catch (error) {
35
+ connection.close();
36
+ for (const subscription of subscriptions.values())
37
+ subscription.receive({ type: "end", kind: "failed", error: error instanceof Error ? error.message : String(error) });
38
+ }
39
+ };
40
+ connection.onerror = () => {
41
+ connection.close();
42
+ for (const subscription of subscriptions.values())
43
+ subscription.connection("reconnecting");
44
+ if (subscriptions.size > 0)
45
+ retry = setTimeout(connect, options.reconnectDelayMs ?? 500);
46
+ };
47
+ }
6
48
  function url(path, query = {}) {
7
49
  const params = new URLSearchParams();
8
50
  for (const [key, value] of Object.entries(query)) {
@@ -38,57 +80,86 @@ export function createHttpPiClient(options = {}) {
38
80
  fork: (id, at, forkOptions = { ownership: { kind: "ownerless" } }) => post(`/conversations/${id}/fork`, { at, ...forkOptions }),
39
81
  context: (id, at) => request(`/conversations/${id}/context`, undefined, { at }),
40
82
  uploadFile: (file, signal) => request("/files", { method: "POST", headers: { "content-type": file.type || "application/octet-stream" }, body: file, signal }, { name: file.name }),
41
- respondToHumanInput: async (taskId, response) => { await post(`/interactions/${taskId}`, { response }); },
83
+ respondToHumanInput: async (taskId, response) => { await post(`/human-input/${taskId}`, { response }); },
42
84
  inspect: () => request("/inspect"),
43
- listMetadata: () => request("/conversations/metadata"),
85
+ listMetadata: (ids) => post("/conversations/metadata", { ids }),
44
86
  getMetadata: (id) => request(`/conversations/${id}/metadata`),
45
87
  updateMetadata: (id, patch) => request(`/conversations/${id}/metadata`, { method: "PATCH", headers: { "content-type": "application/json" }, body: JSON.stringify(patch) }),
46
88
  setFeedback: (id, entryId, rating) => post(`/conversations/${id}/feedback`, { entryId, rating }),
47
- watch(id, onView, watchOptions = {}) {
48
- let source;
49
- let retry;
50
- let stopped = false;
51
- let connectedBefore = false;
52
- function connect() {
53
- if (stopped)
54
- return;
55
- watchOptions.onConnection?.(connectedBefore ? "reconnecting" : "connecting");
56
- const connection = openEvents(url(`/conversations/${id}/watch`, { window: watchOptions.window?.() }));
57
- source = connection;
58
- let view;
59
- connection.onmessage = (event) => {
89
+ watch: (id, watchOptions = {}) => openWatch(id, "conversation", watchOptions),
90
+ watchMetadata: (id, signal) => openWatch(id, "metadata", { signal }),
91
+ };
92
+ function openWatch(id, kind, watchOptions) {
93
+ return new Promise((resolve, reject) => {
94
+ const subscriptionId = ++nextSubscriptionId;
95
+ let observation;
96
+ let value;
97
+ function dispose() {
98
+ subscriptions.delete(subscriptionId);
99
+ watchOptions.signal?.removeEventListener("abort", abort);
100
+ scheduleConnect();
101
+ }
102
+ function abort() {
103
+ dispose();
104
+ if (observation)
105
+ observation.abort();
106
+ else
107
+ reject(watchOptions.signal?.reason ?? new DOMException("Observation aborted", "AbortError"));
108
+ }
109
+ subscriptions.set(subscriptionId, {
110
+ request: () => ({ subscriptionId, id, kind, window: watchOptions.window?.() }),
111
+ connection: (state) => watchOptions.onConnection?.(state === "connecting" && observation ? "reconnecting" : state),
112
+ receive(raw) {
60
113
  try {
61
- const frame = JSON.parse(event.data);
114
+ const frame = raw;
115
+ if (frame.type === "end") {
116
+ dispose();
117
+ watchOptions.onConnection?.("closed");
118
+ const error = new Error(frame.error ?? `Pi observation ended: ${frame.kind}`);
119
+ if (!observation)
120
+ reject(error);
121
+ else
122
+ observation.end(frame.kind === "failed" || frame.kind === "listener_error" ? { kind: frame.kind, error } : { kind: frame.kind });
123
+ return;
124
+ }
125
+ if (frame.type === "failed") {
126
+ if (!observation)
127
+ throw new Error(frame.error);
128
+ observation.fail(new Error(frame.error), BACKGROUND_CONTEXT);
129
+ return;
130
+ }
62
131
  if (frame.type === "view")
63
- view = frame.view;
132
+ value = frame.view;
64
133
  else {
65
- if (!view)
134
+ if (!observation)
66
135
  throw new Error("Pi watch sent changes before its initial view");
67
- view = applyImmutable(view, frame.ops);
136
+ value = applyImmutable(value, frame.ops);
137
+ }
138
+ if (!observation) {
139
+ observation = new Watch(value, dispose, console.error);
140
+ resolve(observation);
141
+ }
142
+ else {
143
+ observation.advance({ kind: "value", value, ops: frame.type === "ops" ? frame.ops : [["r", value]], retired: false }, BACKGROUND_CONTEXT);
68
144
  }
69
- connectedBefore = true;
70
145
  watchOptions.onConnection?.("connected");
71
- onView(view);
72
146
  }
73
- catch (cause) {
74
- watchOptions.onError?.(cause instanceof Error ? cause : new Error(String(cause)));
75
- connection.close();
147
+ catch (error) {
148
+ dispose();
149
+ watchOptions.onConnection?.("closed");
150
+ if (observation)
151
+ observation.end({ kind: "failed", error });
152
+ else
153
+ reject(error);
76
154
  }
77
- };
78
- connection.onerror = () => {
79
- connection.close();
80
- if (stopped)
81
- return;
82
- watchOptions.onConnection?.("reconnecting");
83
- retry = setTimeout(connect, options.reconnectDelayMs ?? 500);
84
- };
155
+ },
156
+ });
157
+ if (watchOptions.signal?.aborted)
158
+ abort();
159
+ else {
160
+ watchOptions.signal?.addEventListener("abort", abort, { once: true });
161
+ scheduleConnect();
85
162
  }
86
- connect();
87
- return () => {
88
- stopped = true;
89
- clearTimeout(retry);
90
- source?.close();
91
- };
92
- },
93
- };
163
+ });
164
+ }
94
165
  }
@@ -0,0 +1,44 @@
1
+ import { ConversationTranscript, type ConversationId, type EntryId, type SubmissionDraft, type TranscriptView } from "@earendil-works/pi-durable";
2
+ import type { AppendMessage } from "@assistant-ui/react";
3
+ import type { PiDurableClient, PiDurableConnectionState, SerializedAgentChange } from "./client.js";
4
+ import { type ConversationMetadata } from "./metadata.js";
5
+ export interface PiDurableConversationState {
6
+ readonly view: TranscriptView | undefined;
7
+ readonly metadata: ConversationMetadata;
8
+ readonly connection: PiDurableConnectionState;
9
+ readonly isLoading: boolean;
10
+ readonly error: Error | undefined;
11
+ }
12
+ /** Disposable observation and actions permanently bound to one native conversation. */
13
+ export declare class PiDurableConversation {
14
+ #private;
15
+ readonly client: PiDurableClient;
16
+ readonly id: ConversationId;
17
+ readonly transcript: ConversationTranscript;
18
+ constructor(client: PiDurableClient, id: ConversationId, pageSize?: number);
19
+ getSnapshot: () => PiDurableConversationState;
20
+ subscribe: (listener: () => void) => (() => void);
21
+ reportError: (error: unknown) => void;
22
+ start: () => void;
23
+ stop: () => void;
24
+ reload: () => void;
25
+ submit: (draft: SubmissionDraft) => Promise<import("@earendil-works/pi-durable").SubmissionRecord>;
26
+ continue: () => Promise<import("@earendil-works/pi-durable").SubmissionRecord>;
27
+ steer: (content: Extract<SubmissionDraft, {
28
+ type: "input";
29
+ }>["content"]) => Promise<import("@earendil-works/pi-durable").SubmissionRecord>;
30
+ followUp: (content: Extract<SubmissionDraft, {
31
+ type: "input";
32
+ }>["content"]) => Promise<import("@earendil-works/pi-durable").SubmissionRecord>;
33
+ cancel: () => Promise<void>;
34
+ abortSubmission: (id: Parameters<NonNullable<PiDurableClient["abortSubmission"]>>[0]) => Promise<"aborted" | "already_placed" | "not_found" | "settled">;
35
+ configure: (change: SerializedAgentChange) => Promise<void>;
36
+ reset: (handoff?: string) => Promise<void>;
37
+ compact: (instructions?: string) => Promise<import("@earendil-works/pi-durable").TaskId<import("@earendil-works/pi-durable").CompactionResult>>;
38
+ forkAt: (at: EntryId) => Promise<import("@earendil-works/pi-durable").ConversationRecord>;
39
+ edit: (message: AppendMessage) => Promise<import("@earendil-works/pi-durable").ConversationRecord>;
40
+ regenerate: (parentId: string | null) => Promise<import("@earendil-works/pi-durable").ConversationRecord>;
41
+ loadEarlier: () => Promise<void>;
42
+ setFeedback: (messageId: string, rating: "positive" | "negative") => Promise<void>;
43
+ }
44
+ //# sourceMappingURL=conversation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../src/conversation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,KAAK,cAAc,EAAyB,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACzK,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpG,OAAO,EAA+B,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGvF,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;CACnC;AAED,uFAAuF;AACvF,qBAAa,qBAAqB;;IAMpB,QAAQ,CAAC,MAAM,EAAE,eAAe;IAAE,QAAQ,CAAC,EAAE,EAAE,cAAc;IALzE,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAK5C,YAAqB,MAAM,EAAE,eAAe,EAAW,EAAE,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM,EAE3F;IAED,WAAW,QAAO,0BAA0B,CAAgB;IAC5D,SAAS,aAAc,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAG9C;IAOF,WAAW,UAAW,OAAO,UAE3B;IAEF,KAAK,QAAO,IAAI,CAkCd;IAOF,IAAI,QAAO,IAAI,CAGb;IAEF,MAAM,QAAO,IAAI,CAAmC;IACpD,MAAM,UAAW,eAAe,oEAAwC;IACxE,QAAQ,uEAA2C;IACnD,KAAK,YAAa,OAAO,CAAC,eAAe,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC,SAAS,CAAC,oEAAgE;IACxI,QAAQ,YAAa,OAAO,CAAC,eAAe,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC,SAAS,CAAC,oEAAmE;IAE9I,MAAM,sBAGJ;IACF,eAAe,OAAQ,UAAU,CAAC,WAAW,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,qEAGnF;IACF,SAAS,WAAY,qBAAqB,mBAGxC;IACF,KAAK,aAAc,MAAM,mBAGvB;IACF,OAAO,kBAAmB,MAAM,iHAG9B;IACF,MAAM,OAAQ,OAAO,sEAGnB;IAEF,IAAI,YAAmB,aAAa,sEAOlC;IAEF,UAAU,aAAoB,MAAM,GAAG,IAAI,sEAUzC;IAEF,WAAW,sBAGT;IAEF,WAAW,cAAqB,MAAM,UAAU,UAAU,GAAG,UAAU,mBAGrE;CACH"}