@gajae-code/coding-agent 0.12.19 → 0.12.20
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/CHANGELOG.md +20 -9
- package/dist/types/commands/gc.d.ts +4 -0
- package/dist/types/commands/sdk.d.ts +66 -0
- package/dist/types/config/settings-schema.d.ts +34 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +97 -1
- package/dist/types/modes/acp/acp-agent.d.ts +33 -1
- package/dist/types/modes/components/bash-execution.d.ts +7 -0
- package/dist/types/modes/components/eval-execution.d.ts +7 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +10 -1
- package/dist/types/sdk/acp/adapter.d.ts +9 -17
- package/dist/types/sdk/acp/index.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +93 -1
- package/dist/types/sdk/broker/ensure.d.ts +17 -0
- package/dist/types/sdk/broker/index.d.ts +1 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +10 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +81 -2
- package/dist/types/sdk/broker/startup-budget.d.ts +44 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +7 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +11 -1
- package/dist/types/sdk/bus/discord-daemon.d.ts +1 -0
- package/dist/types/sdk/bus/index.d.ts +20 -9
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -6
- package/dist/types/sdk/bus/slack-daemon.d.ts +2 -2
- package/dist/types/sdk/host/query/revision-store.d.ts +5 -0
- package/dist/types/sdk/host/session-runtime.d.ts +4 -0
- package/dist/types/sdk/lifecycle-session.d.ts +13 -2
- package/dist/types/sdk/prompt-failure.d.ts +13 -0
- package/dist/types/sdk/prompt-watchdog.d.ts +82 -0
- package/dist/types/sdk/session-reconnect.d.ts +20 -0
- package/dist/types/sdk/startup-capability.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +14 -4
- package/dist/types/session/blob-store.d.ts +32 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +40 -2
- package/dist/types/session/internal/session-memory-sidecar.d.ts +881 -0
- package/dist/types/session/session-manager.d.ts +301 -27
- package/dist/types/session/session-storage.d.ts +170 -0
- package/dist/types/task/executor.d.ts +2 -1
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tui/output-block.d.ts +6 -0
- package/package.json +8 -8
- package/src/cli/args.ts +75 -34
- package/src/commands/acp.ts +7 -1
- package/src/commands/gc.ts +31 -2
- package/src/commands/sdk.ts +141 -7
- package/src/config/settings-schema.ts +43 -0
- package/src/coordinator-mcp/server.ts +6 -1
- package/src/export/html/index.ts +83 -39
- package/src/gjc-runtime/gc-runtime.ts +1283 -4
- package/src/internal-urls/docs-index.generated.ts +1 -1
- package/src/internal-urls/local-protocol.ts +14 -0
- package/src/main.ts +40 -9
- package/src/modes/acp/acp-agent.ts +564 -37
- package/src/modes/acp/terminal-auth.ts +2 -2
- package/src/modes/components/bash-execution.ts +14 -0
- package/src/modes/components/eval-execution.ts +14 -0
- package/src/modes/controllers/command-controller.ts +63 -8
- package/src/modes/utils/ui-helpers.ts +81 -11
- package/src/sdk/acp/adapter.ts +46 -45
- package/src/sdk/acp/index.ts +1 -1
- package/src/sdk/broker/broker.ts +392 -11
- package/src/sdk/broker/ensure.ts +131 -61
- package/src/sdk/broker/index.ts +1 -0
- package/src/sdk/broker/lifecycle-ledger.ts +59 -5
- package/src/sdk/broker/lifecycle.ts +278 -63
- package/src/sdk/broker/startup-budget.ts +103 -0
- package/src/sdk/bus/chat-daemon-control.ts +9 -3
- package/src/sdk/bus/chat-daemon-runtime.ts +565 -29
- package/src/sdk/bus/conversation-store.ts +1 -1
- package/src/sdk/bus/discord-daemon.ts +2 -1
- package/src/sdk/bus/discord-live-provider.ts +34 -6
- package/src/sdk/bus/index.ts +118 -20
- package/src/sdk/bus/kind-aware-reconciliation.ts +2 -1
- package/src/sdk/bus/prompt-reconciliation.ts +4 -9
- package/src/sdk/bus/slack-daemon.ts +91 -18
- package/src/sdk/cli/session-cli.ts +8 -1
- package/src/sdk/host/query/handlers.ts +1 -1
- package/src/sdk/host/query/revision-store.ts +48 -12
- package/src/sdk/host/session-runtime.test.ts +50 -0
- package/src/sdk/host/session-runtime.ts +12 -2
- package/src/sdk/lifecycle-session.ts +26 -3
- package/src/sdk/mcp/server.ts +6 -1
- package/src/sdk/prompt-failure.ts +42 -0
- package/src/sdk/prompt-watchdog.ts +162 -0
- package/src/sdk/session-reconnect.ts +43 -0
- package/src/sdk/startup-capability.ts +13 -4
- package/src/session/agent-session.ts +525 -222
- package/src/session/blob-store.ts +89 -0
- package/src/session/internal/managed-session-scope.ts +36 -26
- package/src/session/internal/managed-session-storage.ts +303 -32
- package/src/session/internal/session-memory-sidecar.ts +2160 -0
- package/src/session/session-manager.ts +7027 -394
- package/src/session/session-storage.ts +1134 -11
- package/src/task/executor.ts +17 -4
- package/src/tools/bash.ts +109 -7
- package/src/tools/find.ts +55 -26
- package/src/tools/todo-contract.ts +40 -8
- package/src/tui/output-block.ts +11 -1
|
@@ -92,18 +92,27 @@ export interface LifecycleLedgerLimits {
|
|
|
92
92
|
maxBytes?: number;
|
|
93
93
|
maxLineBytes?: number;
|
|
94
94
|
maxRows?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Cap for the `.corrupt` quarantine sidecar. Reaching it rotates one
|
|
97
|
+
* generation aside instead of appending forever.
|
|
98
|
+
*/
|
|
99
|
+
maxCorruptBytes?: number;
|
|
95
100
|
}
|
|
96
101
|
export declare class LifecycleLedger {
|
|
97
102
|
#private;
|
|
98
103
|
constructor(agentDir: string, limits?: LifecycleLedgerLimits);
|
|
99
104
|
open(): Promise<this>;
|
|
100
105
|
/**
|
|
101
|
-
* Reads terminal
|
|
106
|
+
* Reads the durable terminal record for one request without recovering or changing the ledger.
|
|
102
107
|
*
|
|
103
108
|
* This intentionally accepts an unrelated unterminated final write: concurrent
|
|
104
109
|
* appenders may have started a different row after this request's synced terminal
|
|
105
110
|
* row. Complete rows are still decoded and validated strictly, and any incomplete
|
|
106
111
|
* tail that identifies this request withholds proof.
|
|
112
|
+
*
|
|
113
|
+
* `terminal_uncertain` is a durable terminal record too: an operation that concluded
|
|
114
|
+
* uncertainly persists that conclusion, and refusing to read it back would report a
|
|
115
|
+
* synced row as unpersisted and replace its true reason with a generic one.
|
|
107
116
|
*/
|
|
108
117
|
readTerminal(identity: string, requestHash: string): Promise<LifecycleLedgerEntry | undefined>;
|
|
109
118
|
get warnings(): readonly string[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SessionLifecycleMcpServer } from "../acp/mcp";
|
|
2
|
-
import type
|
|
2
|
+
import { type SdkStartupFailure, type SdkStartupRollbackResult } from "../startup-capability";
|
|
3
3
|
import type { Broker, BrokerCleanupEvidence, BrokerResponse } from "./broker";
|
|
4
4
|
import type { LifecycleDurableEffectsReceipt, LifecycleStartupFailureReceipt } from "./lifecycle-ledger";
|
|
5
5
|
import { type ProcessIncarnationCommandRunner, type ProcessIncarnationOptions, parseDarwinProcessIncarnation, processIncarnation } from "./process-incarnation";
|
|
@@ -15,7 +15,7 @@ export interface LifecycleDeadlines {
|
|
|
15
15
|
export declare function deriveLifecycleDeadlines(receivedAt: number, requestedReadinessTimeoutMs: number): LifecycleDeadlines;
|
|
16
16
|
export interface LifecycleTiming {
|
|
17
17
|
now(): number;
|
|
18
|
-
sleep(ms: number): Promise<void>;
|
|
18
|
+
sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
19
19
|
}
|
|
20
20
|
type LifecycleCommand = SdkInternalSpawnCommand | {
|
|
21
21
|
file: string;
|
|
@@ -117,3 +117,82 @@ export interface LifecycleExecutionOutcome {
|
|
|
117
117
|
}
|
|
118
118
|
/** Returns the response together with every durable lifecycle fact needed for truthful replay. */
|
|
119
119
|
export declare function executeLifecycle(broker: Broker, operation: string, input: Input, identity: string, cleanup?: CleanupEvidence): Promise<LifecycleExecutionOutcome>;
|
|
120
|
+
/**
|
|
121
|
+
* The live client/socket subscription count of the SDK session endpoint this
|
|
122
|
+
* process serves, or `undefined` while this process serves no endpoint.
|
|
123
|
+
*
|
|
124
|
+
* Only the SDK session runtime owns the real socket table, so it publishes a
|
|
125
|
+
* reader here instead of every consumer re-deriving attachment from the OS.
|
|
126
|
+
* Consumers must treat `undefined` as "no evidence" and never as "detached".
|
|
127
|
+
*/
|
|
128
|
+
export type SessionHostAttachmentReader = () => number;
|
|
129
|
+
/** What one serving runtime reports about itself while its transport is up. */
|
|
130
|
+
export interface SessionHostRuntimeEvidence {
|
|
131
|
+
/** This runtime's own live SDK client/socket subscription count. */
|
|
132
|
+
attachedClients: SessionHostAttachmentReader;
|
|
133
|
+
/** Whether this runtime currently has agent work in flight. */
|
|
134
|
+
workInFlight: () => boolean;
|
|
135
|
+
}
|
|
136
|
+
/** One runtime's live publication, retractable only by its owner. */
|
|
137
|
+
export interface SessionHostRuntimePublication {
|
|
138
|
+
/**
|
|
139
|
+
* Withdraws the evidence this handle published. Idempotent, and never able
|
|
140
|
+
* to touch a sibling runtime's evidence.
|
|
141
|
+
*/
|
|
142
|
+
retract(): void;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Publishes this runtime's own liveness evidence for the lifetime of its
|
|
146
|
+
* transport. Retraction goes through the returned handle, so a runtime can only
|
|
147
|
+
* ever withdraw evidence it owns.
|
|
148
|
+
*/
|
|
149
|
+
export declare function publishSessionHostRuntimeEvidence(evidence: SessionHostRuntimeEvidence): SessionHostRuntimePublication;
|
|
150
|
+
/**
|
|
151
|
+
* This process's currently attached SDK client count, summed across every
|
|
152
|
+
* serving runtime, or `undefined` when no runtime publishes a readable count
|
|
153
|
+
* (before startup, after teardown, or when every reader itself fails). Never
|
|
154
|
+
* guesses: absence of a reader is absence of evidence.
|
|
155
|
+
*/
|
|
156
|
+
export declare function sessionHostAttachedClients(): number | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* Whether any runtime in this process has agent work in flight right now.
|
|
159
|
+
*
|
|
160
|
+
* Positive evidence only: a runtime that publishes nothing, or whose reader
|
|
161
|
+
* fails, reports no work, so this can never keep an abandoned host alive.
|
|
162
|
+
*/
|
|
163
|
+
export declare function sessionHostWorkInFlight(): boolean;
|
|
164
|
+
/**
|
|
165
|
+
* How often a live broker re-checks its own session registrations against OS
|
|
166
|
+
* process liveness.
|
|
167
|
+
*
|
|
168
|
+
* This sweep can never disturb healthy work: a registration is only dropped
|
|
169
|
+
* when `process.kill(pid, 0)` proves the exact published pid is gone, and a
|
|
170
|
+
* working host answers that probe for its entire life no matter how long a turn
|
|
171
|
+
* runs. One minute keeps `gjc_sessions`/`session.get_endpoint` from advertising
|
|
172
|
+
* a corpse for longer than a single poll while costing one index refresh per
|
|
173
|
+
* minute on an otherwise idle broker.
|
|
174
|
+
*/
|
|
175
|
+
export declare const BROKER_DEAD_REGISTRATION_SWEEP_MS = 60000;
|
|
176
|
+
/** One reaped registration, as recorded by {@link reapDeadSessionRegistrations}. */
|
|
177
|
+
export interface ReapedSessionRegistration {
|
|
178
|
+
sessionId: string;
|
|
179
|
+
pid: number;
|
|
180
|
+
endpointGeneration: number;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Drops every indexed session registration whose host process is provably gone.
|
|
184
|
+
*
|
|
185
|
+
* Liveness is the session index's own `alive(pid)` probe (`listSessions().live`),
|
|
186
|
+
* which reports live for both a running pid and an EPERM pid, so an alien or
|
|
187
|
+
* unreadable process is never mistaken for a dead one. Registrations already
|
|
188
|
+
* marked `terminalUncertain` are left alone: their disposition belongs to the
|
|
189
|
+
* terminal-uncertainty reconciliation path, and silently dropping them would
|
|
190
|
+
* turn a fail-closed `session.close`/`session.delete` refusal into `not_found`.
|
|
191
|
+
*/
|
|
192
|
+
export declare function reapDeadSessionRegistrations(broker: Pick<Broker, "index">): Promise<ReapedSessionRegistration[]>;
|
|
193
|
+
/**
|
|
194
|
+
* Runs {@link reapDeadSessionRegistrations} on {@link BROKER_DEAD_REGISTRATION_SWEEP_MS}.
|
|
195
|
+
* The timer is unref'd, so it never keeps an otherwise idle broker process alive.
|
|
196
|
+
* Returns a disposer.
|
|
197
|
+
*/
|
|
198
|
+
export declare function startBrokerDeadRegistrationSweep(broker: Pick<Broker, "index">, intervalMs?: number): () => void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Readiness budget the broker grants a lifecycle request that does not size one itself. */
|
|
2
|
+
export declare const DEFAULT_READINESS_TIMEOUT_MS = 10000;
|
|
3
|
+
export declare const MIN_READINESS_TIMEOUT_MS = 4000;
|
|
4
|
+
export declare const MAX_READINESS_TIMEOUT_MS = 60000;
|
|
5
|
+
export declare function isValidReadinessTimeoutMs(value: unknown): value is number;
|
|
6
|
+
export declare const READINESS_TIMEOUT_INVALID_MESSAGE = "readinessTimeoutMs must be an integer between 4000 and 60000.";
|
|
7
|
+
/**
|
|
8
|
+
* Sleep until the duration elapses or the caller cancels the wait. Queue admission
|
|
9
|
+
* uses this so a granted or refused waiter does not retain its cutoff timer for the
|
|
10
|
+
* rest of the readiness budget.
|
|
11
|
+
*/
|
|
12
|
+
export declare function cancellableSleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Whether a broker operation waits in the host-startup admission queue before it runs.
|
|
15
|
+
* Only these spawn a host, so only these can be parked behind a full queue; the other
|
|
16
|
+
* lifecycle operations start their readiness clock as soon as they are received.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isStartupLifecycleOperation(operation: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Bounded time a lifecycle startup may wait for a host-startup admission slot. It
|
|
21
|
+
* is the readiness budget itself: a startup still queued after that long has spent
|
|
22
|
+
* the whole window the request was sized for, so refusing it beats launching a host
|
|
23
|
+
* that is already late.
|
|
24
|
+
*/
|
|
25
|
+
export declare function startupQueueWaitMs(requestedReadinessTimeoutMs: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* Broker-side wall clock a lifecycle startup may consume: the admission wait plus
|
|
28
|
+
* the readiness budget, which is granted fresh at admission and so is never shortened
|
|
29
|
+
* by queueing. Callers MUST size their own request deadline against this rather than
|
|
30
|
+
* `readinessTimeoutMs` alone, or a request admitted late fails client-side while the
|
|
31
|
+
* broker keeps running it to a durably persisted terminal result.
|
|
32
|
+
*/
|
|
33
|
+
export declare function lifecycleStartupBudgetMs(requestedReadinessTimeoutMs: number): number;
|
|
34
|
+
/**
|
|
35
|
+
* Request deadline a caller MUST grant a broker operation, or `undefined` when the
|
|
36
|
+
* operation carries no readiness budget of its own and the client default already
|
|
37
|
+
* covers it.
|
|
38
|
+
*
|
|
39
|
+
* A request that omits `readinessTimeoutMs` is sized against the broker's default
|
|
40
|
+
* rather than left unextended: the broker queues it for exactly as long as one that
|
|
41
|
+
* asked, so the common path would otherwise fail client-side while the broker runs
|
|
42
|
+
* the startup to a durably persisted terminal result.
|
|
43
|
+
*/
|
|
44
|
+
export declare function lifecycleRequestTimeoutMs(operation: string, input: Record<string, unknown>): number | undefined;
|
|
@@ -38,7 +38,13 @@ export type ChatDaemonAction = "stop" | "reload";
|
|
|
38
38
|
* them against an exact owner tuple, so an owner at an earlier generation may
|
|
39
39
|
* not serve or answer a request captured against this contract. Discord
|
|
40
40
|
* generation 27 / slack generation 26 move shared exact unlink and process-
|
|
41
|
-
* incarnation authority behind lazy native bindings.
|
|
41
|
+
* incarnation authority behind lazy native bindings. Discord generation 28 /
|
|
42
|
+
* slack generation 27 dial attached-session clients on the long-lived session
|
|
43
|
+
* reconnect budget, so an owner at an earlier generation gives up reconnecting
|
|
44
|
+
* before the host heartbeat TTL expires and permanently loses its attachment. Discord
|
|
45
|
+
* generation 29 / slack generation 28 advance the replay cursor only after a frame is
|
|
46
|
+
* published, so an owner at an earlier generation acknowledges an event before delivering
|
|
47
|
+
* it and loses that event for good the first time a surface refuses it.
|
|
42
48
|
*/
|
|
43
49
|
export declare const CHAT_DAEMON_GENERATIONS: Readonly<Record<ChatDaemonKind, number>>;
|
|
44
50
|
export declare function chatDaemonGeneration(kind: ChatDaemonKind): number;
|
|
@@ -28,7 +28,17 @@ export interface ChatDaemonRuntimeConfig {
|
|
|
28
28
|
}
|
|
29
29
|
export interface ChatDaemonSdkClient {
|
|
30
30
|
onFrame(handler: (frame: Record<string, unknown>) => void): () => void;
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Announces that a replacement socket is live. Optional because command-scoped
|
|
33
|
+
* clients (the broker client, one-shot doubles) never outlive one socket, while
|
|
34
|
+
* every long-lived attachment's client carries it.
|
|
35
|
+
*/
|
|
36
|
+
onReconnect?(handler: () => void): () => void;
|
|
37
|
+
/** Re-dials a retired socket; a no-op on a live one. */
|
|
38
|
+
connect?(): Promise<void>;
|
|
39
|
+
request(frame: Record<string, unknown>, options?: {
|
|
40
|
+
timeoutMs?: number;
|
|
41
|
+
}): Promise<Record<string, unknown>>;
|
|
32
42
|
close(): Promise<void>;
|
|
33
43
|
send(frame: Record<string, unknown>): void;
|
|
34
44
|
}
|
|
@@ -31,6 +31,7 @@ export interface DiscordNotificationInput {
|
|
|
31
31
|
threadName?: string;
|
|
32
32
|
actionId?: string;
|
|
33
33
|
options?: string[];
|
|
34
|
+
publicationId?: string;
|
|
34
35
|
}
|
|
35
36
|
/** SDK-only Discord threaded notification daemon. It owns no AgentSession and never retains endpoint credentials. */
|
|
36
37
|
export declare class DiscordNotificationDaemon {
|
|
@@ -26,6 +26,7 @@ import type { ExtensionAPI, ExtensionContext } from "../../extensibility/extensi
|
|
|
26
26
|
import { type WorkflowGateEmitter, type WorkflowGateTerminalProof } from "../../modes/shared/agent-wire/workflow-gate-broker";
|
|
27
27
|
import type { AgentSessionEvent } from "../../session/agent-session";
|
|
28
28
|
import type { AskAnswerSource, AskAnswerSourceResult, AskRemoteControl } from "../../tools";
|
|
29
|
+
import { type SessionHostRuntimePublication } from "../broker/lifecycle";
|
|
29
30
|
import { type SessionSdkHost } from "../host";
|
|
30
31
|
import { CursorRegistry, RevisionStore } from "../host/query";
|
|
31
32
|
import { type SdkPromptTerminalOutcome } from "../prompt-status";
|
|
@@ -35,6 +36,22 @@ import { NotificationSessionController } from "./session-control";
|
|
|
35
36
|
import { type EnsureDaemonResult, type RegisterNotificationRootResult } from "./telegram-daemon";
|
|
36
37
|
export type { IdentityControlSuccessPathInput, IdentityControlTerminalPathInput, TerminalSendOutcome, } from "./control-drain-lease";
|
|
37
38
|
export { isNativeControlDrainAvailable, runIdentityControlSuccessPath, runIdentityControlTerminalPath, } from "./control-drain-lease";
|
|
39
|
+
type PromptTerminalDiagnostic = {
|
|
40
|
+
reason?: unknown;
|
|
41
|
+
loopStopReason?: string;
|
|
42
|
+
assistantStopReason?: string;
|
|
43
|
+
errorKind?: string;
|
|
44
|
+
intentionalCancellation?: boolean;
|
|
45
|
+
};
|
|
46
|
+
type PromptTerminalExtra = {
|
|
47
|
+
finalText?: string;
|
|
48
|
+
error?: {
|
|
49
|
+
code: string;
|
|
50
|
+
message: string;
|
|
51
|
+
};
|
|
52
|
+
diagnostic?: PromptTerminalDiagnostic;
|
|
53
|
+
diagnosticAlreadyLogged?: boolean;
|
|
54
|
+
};
|
|
38
55
|
export declare function formatPromptSettlementDiagnostic(proof: Extract<RunSettlementProof, {
|
|
39
56
|
status: "unfenced";
|
|
40
57
|
}>, now?: number): string;
|
|
@@ -357,6 +374,8 @@ interface SessionRuntime {
|
|
|
357
374
|
/** Terminal cleanup proof retained across retries; each owner is released at most once after proof. */
|
|
358
375
|
hostStopped: boolean;
|
|
359
376
|
serverStopped: boolean;
|
|
377
|
+
/** This runtime's own host-liveness publication; only its teardown may retract it. */
|
|
378
|
+
evidencePublication?: SessionHostRuntimePublication;
|
|
360
379
|
brokerRegistrationReleased: boolean;
|
|
361
380
|
/** Managed Telegram root registration released during terminal teardown. */
|
|
362
381
|
notificationRootRegistration?: {
|
|
@@ -392,15 +411,7 @@ interface SessionRuntime {
|
|
|
392
411
|
terminalizePrompt: (correlation: {
|
|
393
412
|
commandId: string;
|
|
394
413
|
turnId: string;
|
|
395
|
-
}, outcome: SdkPromptTerminalOutcome, extra?:
|
|
396
|
-
finalText?: string;
|
|
397
|
-
}) => Promise<void>;
|
|
398
|
-
/** Records a correlated prompt terminal boundary after agent unwind. */
|
|
399
|
-
/** Atomically claims a correlated prompt terminal boundary after agent unwind. */
|
|
400
|
-
recordPromptTerminal: (correlation: {
|
|
401
|
-
commandId: string;
|
|
402
|
-
turnId: string;
|
|
403
|
-
} | undefined) => boolean;
|
|
414
|
+
}, outcome: SdkPromptTerminalOutcome, extra?: PromptTerminalExtra) => Promise<void>;
|
|
404
415
|
/** Transitions the authoritative reconciliation record at lifecycle ingress; terminal outcomes settle once. */
|
|
405
416
|
notePromptReconciliation: (correlation: {
|
|
406
417
|
commandId: string;
|
|
@@ -18,10 +18,11 @@
|
|
|
18
18
|
* retained and must never be reused as a retry mechanism.
|
|
19
19
|
* - Terminal transitions settle once: the first terminal outcome wins.
|
|
20
20
|
*/
|
|
21
|
+
import { PROMPT_FAILURE_CODE_MAX, sanitizePromptFailure } from "../prompt-failure";
|
|
22
|
+
export { PROMPT_FAILURE_CODE_MAX, sanitizePromptFailure };
|
|
21
23
|
export declare const PROMPT_RECONCILIATION_ACTIVE_CAPACITY = 128;
|
|
22
24
|
export declare const PROMPT_RECONCILIATION_TERMINAL_CAPACITY = 256;
|
|
23
25
|
export declare const PROMPT_RECONCILIATION_TERMINAL_TTL_MS: number;
|
|
24
|
-
export declare const PROMPT_FAILURE_CODE_MAX = 64;
|
|
25
26
|
export type PromptReconciliationStatus = "accepted" | "in_flight" | "terminal_ok" | "failed";
|
|
26
27
|
export interface PromptCorrelation {
|
|
27
28
|
commandId: string;
|
|
@@ -96,11 +97,6 @@ export interface PromptReconciliation {
|
|
|
96
97
|
cleanup(): void;
|
|
97
98
|
activeCount(): number;
|
|
98
99
|
}
|
|
99
|
-
/** Safe-token code capped at 64; arbitrary failure text is never retained. */
|
|
100
|
-
export declare function sanitizePromptFailure(error: unknown): {
|
|
101
|
-
code: string;
|
|
102
|
-
message: string;
|
|
103
|
-
};
|
|
104
100
|
export declare function createPromptReconciliation(options?: {
|
|
105
101
|
now?: () => number;
|
|
106
102
|
}): PromptReconciliation;
|
|
@@ -74,12 +74,12 @@ export declare class SlackNotificationDaemon {
|
|
|
74
74
|
*/
|
|
75
75
|
bindExistingRoot(sessionId: string, rootTs: string, commitAuthority?: () => Promise<boolean>): Promise<SlackConversation>;
|
|
76
76
|
/** Deliver a notification into the mapped root thread, creating that root once. */
|
|
77
|
-
notify(sessionId: string, body: string, actionId?: string, endpointGeneration?: number): Promise<SlackConversation>;
|
|
77
|
+
notify(sessionId: string, body: string, actionId?: string, endpointGeneration?: number, publicationId?: string): Promise<SlackConversation>;
|
|
78
78
|
/** Posts a safe command outcome to the active mapped root thread. */
|
|
79
79
|
postCommandResult(sessionId: string, content: string): Promise<boolean>;
|
|
80
80
|
resolveAction(sessionId: string, actionId: string): Promise<void>;
|
|
81
81
|
close(sessionId: string, marker?: string): Promise<boolean>;
|
|
82
|
-
resume(sessionId: string, body: string, endpointGeneration?: number): Promise<SlackConversation>;
|
|
82
|
+
resume(sessionId: string, body: string, endpointGeneration?: number, publicationId?: string): Promise<SlackConversation>;
|
|
83
83
|
findSession(sessionId: string, includeInactive: boolean): Promise<{
|
|
84
84
|
key: string;
|
|
85
85
|
record: SlackConversation;
|
|
@@ -40,6 +40,11 @@ export declare class RevisionStore {
|
|
|
40
40
|
complete: boolean;
|
|
41
41
|
offset: number;
|
|
42
42
|
} | undefined>;
|
|
43
|
+
readIndexedFieldRange(resourceKind: string, resourceId: string, id: string, itemId: string, field: string, offset: number, length: number): Promise<{
|
|
44
|
+
body: string;
|
|
45
|
+
complete: boolean;
|
|
46
|
+
offset: number;
|
|
47
|
+
} | undefined>;
|
|
43
48
|
describeIndexedItem(resourceKind: string, resourceId: string, id: string, offset: number): Promise<{
|
|
44
49
|
itemId?: string;
|
|
45
50
|
fields: string[];
|
|
@@ -90,6 +90,10 @@ export interface InvocationReconciliation {
|
|
|
90
90
|
}): unknown;
|
|
91
91
|
hydrate(): Promise<void>;
|
|
92
92
|
}
|
|
93
|
+
export declare function createInvocationReconciliation(options?: {
|
|
94
|
+
stateRoot?: string;
|
|
95
|
+
sessionId?: string;
|
|
96
|
+
}): InvocationReconciliation;
|
|
93
97
|
export interface SdkSurfaceFactoryOptions {
|
|
94
98
|
ctx: ExtensionContext;
|
|
95
99
|
id: string;
|
|
@@ -5,13 +5,24 @@ export type CreateLifecycleAgentSessionResult = {
|
|
|
5
5
|
session: AgentSession;
|
|
6
6
|
capability: SdkStartupCapability;
|
|
7
7
|
rollback: SdkStartupRollbackTracker;
|
|
8
|
+
/**
|
|
9
|
+
* Starts the memory backend that construction deliberately skipped. The
|
|
10
|
+
* caller MUST run it only after readiness is published.
|
|
11
|
+
*/
|
|
12
|
+
startDeferredMemoryBackend: () => Promise<void>;
|
|
8
13
|
} | {
|
|
9
14
|
capability: SdkStartupCapability;
|
|
10
15
|
rollback: SdkStartupRollbackTracker;
|
|
11
16
|
failure: SdkStartupFailure;
|
|
12
17
|
};
|
|
13
|
-
/**
|
|
14
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Options accepted by lifecycle-only session construction.
|
|
20
|
+
*
|
|
21
|
+
* `deferMemoryBackendStartup` is not accepted: lifecycle sessions are launched
|
|
22
|
+
* by the broker under a fixed readiness deadline, and memory startup runs
|
|
23
|
+
* unbounded LLM work, so deferral is an invariant rather than a caller choice.
|
|
24
|
+
*/
|
|
25
|
+
export type CreateLifecycleAgentSessionOptions = Omit<CreateAgentSessionOptions, "deferMemoryBackendStartup"> & {
|
|
15
26
|
/**
|
|
16
27
|
* Startup budget for ACP lifecycle MCP launches, in milliseconds. Set only
|
|
17
28
|
* when the lifecycle request supplies `mcpServers`; ordinary consumers keep
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe failure shaping shared by SDK transports and reconciliation stores.
|
|
3
|
+
* Provider error text is retained only in the local diagnostic log; wire and
|
|
4
|
+
* persisted reconciliation details expose a fixed redacted message.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PROMPT_FAILURE_CODE_MAX = 64;
|
|
7
|
+
/** Safe-token code capped at 64; arbitrary failure text is never retained. */
|
|
8
|
+
export declare function sanitizePromptFailure(error: unknown): {
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
};
|
|
12
|
+
/** Best-effort local diagnostic text that never crosses the SDK boundary. */
|
|
13
|
+
export declare function formatPromptFailureForLocalLog(error: unknown): string;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inactivity bound for a prompt whose session host has no tool call in flight: after
|
|
3
|
+
* this much silence the host is treated as having stopped producing, so the prompt is
|
|
4
|
+
* settled instead of hanging the client forever.
|
|
5
|
+
*
|
|
6
|
+
* Every step of a live turn emits a frame (`agent_start`, message events, tool events,
|
|
7
|
+
* `agent_end`), so this bound only has to exceed the longest frame-free gap a healthy
|
|
8
|
+
* turn can produce *with nothing executing*: one model round trip, from the request
|
|
9
|
+
* leaving the host to the first streamed event coming back, possibly straddling a
|
|
10
|
+
* transport reconnect.
|
|
11
|
+
*
|
|
12
|
+
* `TOOL_TIMEOUTS` is this runtime's own statement of how long a single unattended step
|
|
13
|
+
* may block before it is declared stuck, and its slowest **default**
|
|
14
|
+
* ({@link DEFAULT_TOOL_RUNTIME_MS}) is the longest such wait nobody explicitly opted
|
|
15
|
+
* into. That is well above the agent's own model-stream watchdog (120s idle / 100s
|
|
16
|
+
* first event in `packages/ai/src/utils/idle-iterator.ts`), which aborts a stalled
|
|
17
|
+
* provider stream and republishes it as an error frame — itself a frame — long before
|
|
18
|
+
* this bound. {@link SDK_RECONNECT_BUDGET_MS} is added on top so a reconnect landing
|
|
19
|
+
* inside that gap cannot trip it either. Two providers widen their first-event
|
|
20
|
+
* fallback past this bound (alibaba-token-plan 600s, kimi-code 300s); a turn that
|
|
21
|
+
* emits nothing at all for this long on those is reported as abandoned rather than
|
|
22
|
+
* left `running`, and the session still accepts the next prompt.
|
|
23
|
+
*
|
|
24
|
+
* {@link MAX_TOOL_RUNTIME_MS} is deliberately *not* used here. `max` is what a caller
|
|
25
|
+
* may request, not what tools take, so sizing every gap for it produced a 63min bound
|
|
26
|
+
* that could never act as a safety net. Turns that legitimately reach that ceiling are
|
|
27
|
+
* covered by {@link ACP_PROMPT_TOOL_ACTIVITY_TIMEOUT_MS} instead, which is gated on
|
|
28
|
+
* evidence that a tool is actually executing.
|
|
29
|
+
*/
|
|
30
|
+
export declare const ACP_PROMPT_INACTIVITY_TIMEOUT_MS: number;
|
|
31
|
+
/**
|
|
32
|
+
* Inactivity bound that applies only while the session host has an unfinished tool
|
|
33
|
+
* call — a `tool_execution_start`/`tool_execution_update` with no matching
|
|
34
|
+
* `tool_execution_end`.
|
|
35
|
+
*
|
|
36
|
+
* A long `bash` is protected by the evidence that it is running, not by a constant
|
|
37
|
+
* sized for the worst case, so this wide bound stands only for as long as that
|
|
38
|
+
* evidence does. It still terminates: no tool call may outlive
|
|
39
|
+
* {@link MAX_TOOL_RUNTIME_MS}, after which the host must publish `tool_execution_end`,
|
|
40
|
+
* so a host that dies mid-tool is still reported (one reconnect budget later).
|
|
41
|
+
*/
|
|
42
|
+
export declare const ACP_PROMPT_TOOL_ACTIVITY_TIMEOUT_MS: number;
|
|
43
|
+
/**
|
|
44
|
+
* Inactivity bound that applies while a prompt is awaiting the model: a provider call is in
|
|
45
|
+
* flight and has not produced the first frame of its response yet.
|
|
46
|
+
*
|
|
47
|
+
* Tool execution had evidence and model inference did not, so a turn thinking after
|
|
48
|
+
* `agent_start` looked exactly like a dead producer and was killed at
|
|
49
|
+
* {@link ACP_PROMPT_INACTIVITY_TIMEOUT_MS}. Inference gets the same evidence-based
|
|
50
|
+
* tolerance: the wide bound stands only as long as a model call is observably unanswered.
|
|
51
|
+
*
|
|
52
|
+
* It still terminates. A provider stream that yields nothing within
|
|
53
|
+
* {@link MAX_PROVIDER_FIRST_EVENT_TIMEOUT_MS} is aborted by the agent's own stream watchdog,
|
|
54
|
+
* which republishes as an error/retry frame, so a host that dies mid-inference is still
|
|
55
|
+
* reported one reconnect budget later.
|
|
56
|
+
*/
|
|
57
|
+
export declare const ACP_PROMPT_INFERENCE_TIMEOUT_MS: number;
|
|
58
|
+
/**
|
|
59
|
+
* Per-prompt view of what the session host is observably doing: which tool calls it has
|
|
60
|
+
* started but not finished, and whether it is waiting on a model call. Inbound frames are
|
|
61
|
+
* the only evidence the ACP side has, so "a tool is running" means exactly "a start was
|
|
62
|
+
* observed and its end was not", and "awaiting the model" means exactly "a model call was
|
|
63
|
+
* dispatched and nothing from its response has been observed".
|
|
64
|
+
*/
|
|
65
|
+
export declare class PromptActivity {
|
|
66
|
+
#private;
|
|
67
|
+
/** Folds one inbound frame's lifecycle event into the in-flight tool and model state. */
|
|
68
|
+
observe(eventType: string | undefined, toolCallId: string | undefined, messageRole: string | undefined): void;
|
|
69
|
+
/** True while at least one started tool call has not reported an end. */
|
|
70
|
+
get running(): boolean;
|
|
71
|
+
/** True while a dispatched model call has not produced the first frame of its response. */
|
|
72
|
+
get awaitingModel(): boolean;
|
|
73
|
+
/** Bound that applies to the next frame-free gap, given what is observably executing. */
|
|
74
|
+
get inactivityBoundMs(): number;
|
|
75
|
+
}
|
|
76
|
+
/** Timer surface behind the prompt watchdog; tests substitute a virtual clock. */
|
|
77
|
+
export interface PromptWatchdogClock {
|
|
78
|
+
now(): number;
|
|
79
|
+
/** Runs `handler` after `delayMs`; the returned callback cancels the pending run. */
|
|
80
|
+
schedule(handler: () => void, delayMs: number): () => void;
|
|
81
|
+
}
|
|
82
|
+
export declare const systemPromptWatchdogClock: PromptWatchdogClock;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SdkClientOptions } from "./client";
|
|
2
|
+
type SessionReconnectOptions = Required<Pick<SdkClientOptions, "reconnectAttempts" | "reconnectBackoffMs" | "reconnectMaxBackoffMs">>;
|
|
3
|
+
/**
|
|
4
|
+
* Reconnect budget for every long-lived SDK session client: ACP sessions and the
|
|
5
|
+
* chat daemon's attached sessions alike. Named for the ACP session that first
|
|
6
|
+
* needed it; it lives here because both live under the same host reaper and the
|
|
7
|
+
* bus layer must not import the ACP layer to reach it.
|
|
8
|
+
*
|
|
9
|
+
* Invariant: the client's total reconnect budget must outlive the host heartbeat
|
|
10
|
+
* TTL ({@link HEARTBEAT_TTL_MS}). The SDK host drops a session whose client has
|
|
11
|
+
* not ponged within that TTL, so a client that gives up reconnecting sooner turns
|
|
12
|
+
* every stall the host reaps into a permanently lost session ("SDK WebSocket
|
|
13
|
+
* reconnect attempts exhausted"). The transport defaults (3 attempts at 25ms base
|
|
14
|
+
* = 175ms total) are correct only for one-shot request clients.
|
|
15
|
+
*
|
|
16
|
+
* Backoff ramps 250 -> 500 -> 1000 and then holds at the 2s cap, so individual
|
|
17
|
+
* sleeps stay short and recovery is prompt once the host answers again.
|
|
18
|
+
*/
|
|
19
|
+
export declare const ACP_SESSION_RECONNECT: SessionReconnectOptions;
|
|
20
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ModelProfileErrorCode, type ModelProfileErrorDetails } from "../config/model-profile-contract";
|
|
2
2
|
export type SdkStartupPhase = "registration" | "startup";
|
|
3
|
-
export type SdkStartupReason = "disabled" | "ineligible" | "factory_absent" | "runner_absent" | "pending" | "failed";
|
|
3
|
+
export type SdkStartupReason = "disabled" | "ineligible" | "factory_absent" | "runner_absent" | "admission_timeout" | "pending" | "failed";
|
|
4
4
|
export interface SdkStartupFailure {
|
|
5
5
|
phase: SdkStartupPhase;
|
|
6
6
|
reason: SdkStartupReason;
|
|
@@ -110,7 +110,8 @@ import type { ClientBridge, ClientBridgePermissionOption, ClientBridgePermission
|
|
|
110
110
|
import { type ContributionPrepOptions, type ContributionPrepResult } from "./contribution-prep";
|
|
111
111
|
import type { MemoryGuardRestoreResult } from "./memory-guard-checkpoint-participant";
|
|
112
112
|
import { type CustomMessage } from "./messages";
|
|
113
|
-
import type { BranchSummaryEntry, CompactionEntry, NewSessionOptions, PreparedNewSession, RecoveryHydrationContext, RecoveryHydrationPromotionFence, SessionContext,
|
|
113
|
+
import type { BranchSummaryEntry, CompactionEntry, NewSessionOptions, PreparedNewSession, RecoveryHydrationContext, RecoveryHydrationPromotionFence, SessionContext, SessionManagerCloseOutcome, SessionMemoryStats } from "./session-manager";
|
|
114
|
+
import { SessionManager } from "./session-manager";
|
|
114
115
|
import { ToolChoiceQueue } from "./tool-choice-queue";
|
|
115
116
|
import { YieldQueue } from "./yield-queue";
|
|
116
117
|
/** Session-specific events that extend the core AgentEvent */
|
|
@@ -385,8 +386,8 @@ export interface PromptOptions {
|
|
|
385
386
|
*/
|
|
386
387
|
onPreflightAccepted?: () => void;
|
|
387
388
|
/**
|
|
388
|
-
* Awaitable durable-accept fence. Called after preflight and before
|
|
389
|
-
*
|
|
389
|
+
* Awaitable durable-accept fence. Called after preflight and immediately before
|
|
390
|
+
* agent execution begins. SDK bus installs a closure that fsyncs acceptance.
|
|
390
391
|
*/
|
|
391
392
|
onPreflightAcceptCommit?: () => void | Promise<void>;
|
|
392
393
|
/** Skill-only: prepared metadata before the durable fence (path/lineCount/cleanedArgs). */
|
|
@@ -444,6 +445,7 @@ export interface SessionStats {
|
|
|
444
445
|
premiumRequests: number;
|
|
445
446
|
cost: number;
|
|
446
447
|
costBreakdown?: Usage["cost"];
|
|
448
|
+
sessionMemory: SessionMemoryStats;
|
|
447
449
|
}
|
|
448
450
|
export type EphemeralTurnPurpose = "btw" | "background";
|
|
449
451
|
interface EphemeralTurnBaseArgs {
|
|
@@ -560,7 +562,7 @@ export declare class StreamingEditFileCache {
|
|
|
560
562
|
export declare class AgentSession {
|
|
561
563
|
#private;
|
|
562
564
|
readonly agent: Agent;
|
|
563
|
-
|
|
565
|
+
sessionManager: SessionManager;
|
|
564
566
|
readonly settings: Settings;
|
|
565
567
|
readonly memoryBackend: LazyService<MemoryBackend>;
|
|
566
568
|
readonly notificationSessionController: NotificationSessionController | undefined;
|
|
@@ -1363,9 +1365,12 @@ export declare class AgentSession {
|
|
|
1363
1365
|
* @param command The bash command to execute
|
|
1364
1366
|
* @param onChunk Optional streaming callback for output
|
|
1365
1367
|
* @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)
|
|
1368
|
+
* @param options.onPersisted Called once the execution's message is in session state
|
|
1369
|
+
* (immediately when idle, at the post-turn flush while streaming)
|
|
1366
1370
|
*/
|
|
1367
1371
|
executeBash(command: string, onChunk?: (chunk: string) => void, options?: {
|
|
1368
1372
|
excludeFromContext?: boolean;
|
|
1373
|
+
onPersisted?: () => void;
|
|
1369
1374
|
}): Promise<BashResult>;
|
|
1370
1375
|
/**
|
|
1371
1376
|
* Record a bash execution result in session history.
|
|
@@ -1373,6 +1378,7 @@ export declare class AgentSession {
|
|
|
1373
1378
|
*/
|
|
1374
1379
|
recordBashResult(command: string, result: BashResult, options?: {
|
|
1375
1380
|
excludeFromContext?: boolean;
|
|
1381
|
+
onPersisted?: () => void;
|
|
1376
1382
|
}): void;
|
|
1377
1383
|
/**
|
|
1378
1384
|
* Cancel running bash command.
|
|
@@ -1388,9 +1394,12 @@ export declare class AgentSession {
|
|
|
1388
1394
|
* @param code The Python code to execute
|
|
1389
1395
|
* @param onChunk Optional streaming callback for output
|
|
1390
1396
|
* @param options.excludeFromContext If true, execution won't be sent to LLM ($$ prefix)
|
|
1397
|
+
* @param options.onPersisted Called once the execution's message is in session state
|
|
1398
|
+
* (immediately when idle, at the post-turn flush while streaming)
|
|
1391
1399
|
*/
|
|
1392
1400
|
executePython(code: string, onChunk?: (chunk: string) => void, options?: {
|
|
1393
1401
|
excludeFromContext?: boolean;
|
|
1402
|
+
onPersisted?: () => void;
|
|
1394
1403
|
}): Promise<PythonResult>;
|
|
1395
1404
|
assertEvalExecutionAllowed(): void;
|
|
1396
1405
|
/**
|
|
@@ -1402,6 +1411,7 @@ export declare class AgentSession {
|
|
|
1402
1411
|
*/
|
|
1403
1412
|
recordPythonResult(code: string, result: PythonResult, options?: {
|
|
1404
1413
|
excludeFromContext?: boolean;
|
|
1414
|
+
onPersisted?: () => void;
|
|
1405
1415
|
}): void;
|
|
1406
1416
|
/**
|
|
1407
1417
|
* Cancel running Python execution.
|
|
@@ -210,4 +210,36 @@ export declare function resolveResidentImageDataSync(blobStore: BlobStore, data:
|
|
|
210
210
|
sessionId?: string;
|
|
211
211
|
sessionFile?: string;
|
|
212
212
|
}): string;
|
|
213
|
+
/** One canonical blob file (`<blobsDir>/<sha256-hex>`) observed on disk. */
|
|
214
|
+
export interface CanonicalBlobEntry {
|
|
215
|
+
readonly hash: string;
|
|
216
|
+
readonly path: string;
|
|
217
|
+
readonly bytes: number;
|
|
218
|
+
readonly mtimeMs: number;
|
|
219
|
+
}
|
|
220
|
+
/** Longest possible `blob:sha256:<hash>` reference, used to bound chunked scans. */
|
|
221
|
+
export declare const BLOB_REFERENCE_MAX_LENGTH: number;
|
|
222
|
+
/** Collect every `blob:sha256:<hash>` reference that appears in `text`. */
|
|
223
|
+
export declare function collectBlobReferences(text: string, into: Set<string>): void;
|
|
224
|
+
/**
|
|
225
|
+
* List canonical blob files. Anything that is not a plain, owner-visible regular
|
|
226
|
+
* file named after its own hash (temp files, symlinks, subdirectories) is
|
|
227
|
+
* skipped: a sweep must never reason about entries it cannot classify.
|
|
228
|
+
*/
|
|
229
|
+
export declare function listCanonicalBlobs(dir: string): Promise<CanonicalBlobEntry[]>;
|
|
230
|
+
/**
|
|
231
|
+
* Remove one canonical blob, fail-closed on identity drift. The entry captured
|
|
232
|
+
* at scan time must still describe the file at unlink time (same inode, size and
|
|
233
|
+
* mtime, still a single-link regular file), otherwise the blob is left in place.
|
|
234
|
+
*
|
|
235
|
+
* `failed` distinguishes an actual IO failure (which a caller should surface as
|
|
236
|
+
* a failed reclaim) from a revalidation refusal (which is an ordinary KEEP).
|
|
237
|
+
*/
|
|
238
|
+
export declare function removeCanonicalBlob(entry: CanonicalBlobEntry): Promise<{
|
|
239
|
+
removed: true;
|
|
240
|
+
} | {
|
|
241
|
+
removed: false;
|
|
242
|
+
reason: string;
|
|
243
|
+
failed?: true;
|
|
244
|
+
}>;
|
|
213
245
|
export {};
|