@threahq/remote-session 0.1.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.
@@ -0,0 +1,6 @@
1
+ import type { RemoteSession } from "./session.js";
2
+ export declare function fireIdleTimeout(session: RemoteSession, invocationId: string): Promise<void>;
3
+ export declare function gate(): {
4
+ promise: Promise<void>;
5
+ open: () => void;
6
+ };
@@ -0,0 +1,14 @@
1
+ export type ToolTraceSectionLabel = "Arguments" | "Output" | "Error output" | "Details";
2
+ export interface ToolTraceSection {
3
+ label: ToolTraceSectionLabel;
4
+ body: string;
5
+ lang: string | null;
6
+ }
7
+ /**
8
+ * Serialize a structured tool trace under the step content limit, trimming the
9
+ * largest section first (the same algorithm as pi-remote and claude-code-remote).
10
+ */
11
+ export declare function toolTraceContent(params: {
12
+ headline: string;
13
+ sections: ToolTraceSection[];
14
+ }): string;
@@ -0,0 +1,149 @@
1
+ import type { SealedReplyBody } from "@threahq/bot-runtime-client";
2
+ import type { ClaimedInvocation } from "./client.js";
3
+ /** Exact failed POST bytes and id, retained because an ambiguous failure may have committed. */
4
+ export type PreparedPost = {
5
+ kind: "plaintext";
6
+ seq: number;
7
+ text: string;
8
+ retryKey?: string;
9
+ body: {
10
+ instanceId: string;
11
+ claimToken: string;
12
+ content: string;
13
+ clientMessageId: string;
14
+ metadata: Record<string, unknown>;
15
+ };
16
+ } | {
17
+ kind: "sealed";
18
+ seq: number;
19
+ text: string;
20
+ retryKey?: string;
21
+ body: SealedReplyBody;
22
+ attachmentIds: string[];
23
+ };
24
+ export interface PostIntent {
25
+ text: string;
26
+ retryKey?: string;
27
+ retry?: PreparedPost;
28
+ }
29
+ export type PlaintextCompletionBody = {
30
+ instanceId: string;
31
+ claimToken: string;
32
+ sourceRevision: number;
33
+ metadata: Record<string, unknown>;
34
+ } & ({
35
+ finalMessageMarkdown: string;
36
+ } | {
37
+ noResponse: true;
38
+ });
39
+ export type SealedCompletionBody = ({
40
+ reply: SealedReplyBody & {
41
+ attachmentIds?: string[];
42
+ };
43
+ } | {
44
+ noResponse: true;
45
+ }) & {
46
+ sourceRevision: number;
47
+ };
48
+ export type PreparedCompletionWire = {
49
+ kind: "plaintext";
50
+ body: PlaintextCompletionBody;
51
+ } | {
52
+ kind: "sealed";
53
+ callbackToken: string;
54
+ body: SealedCompletionBody;
55
+ };
56
+ export type PreparedClose = {
57
+ reason: "reply";
58
+ sourceText: string;
59
+ wire: PreparedCompletionWire;
60
+ } | {
61
+ reason: "timeout";
62
+ wire: PreparedCompletionWire;
63
+ };
64
+ export type CloseRequest = {
65
+ kind: "reply";
66
+ text: string;
67
+ } | {
68
+ kind: "timeout";
69
+ };
70
+ export type RouteState = "open" | "closing" | "closed";
71
+ export declare class RouteRevokedError extends Error {
72
+ }
73
+ /**
74
+ * One claimed invocation's delivery route. The session's maps and queued posts
75
+ * share this object so reserved ids survive state transitions. Route death has
76
+ * three private signals with distinct meanings — `state` (turn protocol
77
+ * progress), `revoked` (this session stopped speaking for the stream), and
78
+ * `terminal` (the server refused the route for good) — mutated only through
79
+ * the named transitions below; `generation` fences a route created before a
80
+ * session teardown (`isFenced`).
81
+ */
82
+ export declare class TurnRoute {
83
+ readonly invocation: ClaimedInvocation;
84
+ /** Registration order distinguishes an older route from a newer owner of the same stream. */
85
+ readonly order: number;
86
+ /** The session lifecycle this route belongs to; a bump fences it out for good. */
87
+ readonly generation: number;
88
+ sentCount: number;
89
+ /** The accepted final reply's exact text, for idempotent reply retries. */
90
+ replyText?: string;
91
+ /** Exact close body retained after an ambiguous completion. */
92
+ prepared?: PreparedClose;
93
+ /** The completion currently on the wire, so shutdown can settle it instead of racing it. */
94
+ closing?: Promise<unknown>;
95
+ deadline?: ReturnType<typeof setTimeout>;
96
+ readonly pending: Map<number, PreparedPost>;
97
+ /** Source-backed inputs folded into this turn; they close with it and fail with it. */
98
+ contributors: ClaimedInvocation[];
99
+ /** Aborts the completion on the wire when any folded source changes underneath it. */
100
+ readonly execution: AbortController;
101
+ /** FIFO tail: every post on this route runs behind it, in call order. */
102
+ private tail;
103
+ /** Highest sequence handed out. Reserved before the write, so a failure spends it. */
104
+ private reservedSeq;
105
+ /** Bumped on every (re-)arm, so a fired timeout queued behind a post can tell it is stale. */
106
+ private deadlineGeneration;
107
+ private stateValue;
108
+ private revokedFlag;
109
+ private terminalFlag;
110
+ private readonly idleTimeoutMs;
111
+ private readonly onIdleDeadline;
112
+ constructor(options: {
113
+ invocation: ClaimedInvocation;
114
+ order: number;
115
+ generation: number;
116
+ idleTimeoutMs: number;
117
+ onIdleDeadline: (route: TurnRoute, deadlineGeneration: number) => void;
118
+ contributors?: ClaimedInvocation[];
119
+ });
120
+ get state(): RouteState;
121
+ get revoked(): boolean;
122
+ get terminal(): boolean;
123
+ isFenced(lifecycle: number): boolean;
124
+ /** FIFO allocation keeps concurrent posts on distinct ids and orders them against completion. */
125
+ enqueue<T>(task: () => Promise<T>): Promise<T>;
126
+ /** Snapshot retry intent before queueing so concurrent callers cannot adopt each other's failure. */
127
+ snapshotIntent(text: string, retryKey?: string): PostIntent;
128
+ /** An ambiguous failure reserves its id and exact bytes; changed text takes the next id. */
129
+ claimSeq(retry: PreparedPost | undefined): number;
130
+ rememberFailedPost(seq: number, prepared: PreparedPost, lifecycle: number): void;
131
+ recordLandedPost(seq: number, prepared: PreparedPost): void;
132
+ /** The source changed under a prepared body: never replay bytes sealed or revisioned against the old input. */
133
+ discardPrepared(): void;
134
+ /** This session stopped speaking for the route's stream; pending retries and the deadline die with it. */
135
+ revoke(): void;
136
+ /** The server refused the route for good: drop write credentials and every pending payload. */
137
+ markTerminal(): void;
138
+ beginClosing(): void;
139
+ markClosed(): void;
140
+ settleClosed(replyText: string | undefined): void;
141
+ reopen(prepared: PreparedClose | undefined): void;
142
+ /** Track the completion on the wire so shutdown can settle it instead of racing it. */
143
+ trackClosing<T>(task: Promise<T>): Promise<T>;
144
+ armIdleTimeout(): void;
145
+ /** Reset the idle timeout after a sign of life. */
146
+ touchIdleTimeout(): void;
147
+ isCurrentDeadline(deadlineGeneration: number): boolean;
148
+ private clearDeadline;
149
+ }