@byok-sdk/client 0.5.0 → 0.6.1
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 +91 -1
- package/dist/adapters/index.js +183 -34
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/pi/events.d.ts +1 -1
- package/dist/adapters/pi/mcp-config.d.ts +1 -0
- package/dist/adapters/pi/mcp-extension.js +25 -0
- package/dist/adapters/pi/mcp-extension.js.map +1 -0
- package/dist/adapters/pi/permission-mapping.d.ts +1 -1
- package/dist/adapters/pi/pi-adapter.d.ts +5 -0
- package/dist/adapters/pi/resolve-extensions.d.ts +11 -0
- package/dist/agent-home.d.ts +106 -0
- package/dist/bin/byok-agent.js +12902 -9340
- package/dist/bin/byok-agent.js.map +1 -1
- package/dist/bin/byok-approval-mcp.js.map +1 -1
- package/dist/bin/commands/toolsets.d.ts +8 -0
- package/dist/bin/config.d.ts +3 -1
- package/dist/bin/format.d.ts +5 -1
- package/dist/bin/official-release.d.ts +1 -0
- package/dist/bin/version.d.ts +2 -0
- package/dist/daemon/agent-content-audit-store.d.ts +35 -0
- package/dist/daemon/agent-content-read.d.ts +169 -0
- package/dist/daemon/agent-egress-controller.d.ts +76 -0
- package/dist/daemon/agent-egress-policy.d.ts +36 -0
- package/dist/daemon/agent-egress-sanitizer.d.ts +38 -0
- package/dist/daemon/agent-egress-spool.d.ts +116 -0
- package/dist/daemon/agent-session-handoff-store.d.ts +82 -0
- package/dist/daemon/blob-client.d.ts +6 -2
- package/dist/daemon/connection-manager.d.ts +4 -2
- package/dist/daemon/control-protocol.d.ts +12 -0
- package/dist/daemon/create-daemon.d.ts +83 -3
- package/dist/daemon/long-poll-transport.d.ts +60 -0
- package/dist/daemon/presence-publisher.d.ts +9 -3
- package/dist/daemon/task-runner.d.ts +73 -4
- package/dist/daemon/toolset-registry.d.ts +30 -0
- package/dist/daemon/url.d.ts +21 -0
- package/dist/daemon/ws-transport.d.ts +32 -5
- package/dist/index.d.ts +14 -2
- package/dist/index.js +12682 -9191
- package/dist/index.js.map +1 -1
- package/dist/release-identity.d.ts +15 -0
- package/dist/types.d.ts +44 -0
- package/package.json +7 -5
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import type { RuntimeId } from '@byok-sdk/protocol';
|
|
1
|
+
import type { AgentEgressPolicy, RuntimeId } from '@byok-sdk/protocol';
|
|
2
2
|
import type { PermissionPolicy } from '@byok-sdk/protocol';
|
|
3
|
-
import type { RuntimeAdapter, GitWorkspaceConfig, McpToolsetConfig } from '../types';
|
|
3
|
+
import type { RuntimeAdapter, GitWorkspaceConfig, McpToolsetConfig, McpToolsetObservation, McpToolsetRegistryStatus, McpToolsetReloadReceipt } from '../types';
|
|
4
|
+
import { type AgentHomeProjection } from '../agent-home';
|
|
5
|
+
import type { AgentRef } from '../agent-home';
|
|
6
|
+
import { type LocalAgentReleaseIdentity } from '../release-identity';
|
|
4
7
|
import type { BackoffOptions, LivenessOptions } from './ws-transport';
|
|
5
8
|
import { type OperationalHealthSnapshot } from './operational-health';
|
|
6
9
|
import { type DaemonEventListener, type DaemonTaskInfo, type Unsubscribe } from './observer';
|
|
@@ -12,6 +15,10 @@ import { type JournalOpenFaultSeam } from './journal/sqlite-support';
|
|
|
12
15
|
import { LocalStoragePressureEngine, type LocalStoragePolicyInput } from './journal/storage-policy';
|
|
13
16
|
import { type ResultDocumentExtractor } from './task-runner';
|
|
14
17
|
import { type ProgressBatcherOptions } from './progress-batcher';
|
|
18
|
+
import { type AgentEgressReliableAppendResult } from './agent-egress-controller';
|
|
19
|
+
import { type AgentEgressStatus } from './agent-egress-policy';
|
|
20
|
+
import { type AgentEgressSanitizer } from './agent-egress-sanitizer';
|
|
21
|
+
import { type AgentContentReadRoot } from './agent-content-read';
|
|
15
22
|
/**
|
|
16
23
|
* Optional white-label product display info — purely opaque passthrough
|
|
17
24
|
* (never interpreted, validated, or rendered by the daemon itself). Carried
|
|
@@ -83,12 +90,34 @@ export interface HostedJournalConfig {
|
|
|
83
90
|
storagePolicy?: LocalStoragePolicyInput;
|
|
84
91
|
}
|
|
85
92
|
export interface DaemonConfig {
|
|
93
|
+
/** Distribution-owned application release; observability only, never a protocol/capability gate. */
|
|
94
|
+
localAgentRelease: LocalAgentReleaseIdentity;
|
|
86
95
|
productName: string;
|
|
87
96
|
productId: string;
|
|
88
97
|
serverUrl: string;
|
|
89
98
|
deviceName?: string;
|
|
90
99
|
workspaceRoot: string;
|
|
91
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* Strict Agent execution boundary. The host selects one absolute branded
|
|
102
|
+
* storage root; the SDK alone composes `agents/<agentId>`, initializes the
|
|
103
|
+
* durable home, and binds it as runtime cwd. `projection` may write opaque,
|
|
104
|
+
* redacted host content into the canonical home supplied by the SDK.
|
|
105
|
+
*/
|
|
106
|
+
agentHome?: {
|
|
107
|
+
hostStorageRoot: string;
|
|
108
|
+
projection?: AgentHomeProjection;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Explicit Agent-local/cloud egress selection. Omission still enforces the
|
|
112
|
+
* SDK metadata/status projection, but does not advertise or admit the new
|
|
113
|
+
* policy/reliable protocol surface.
|
|
114
|
+
*/
|
|
115
|
+
agentEgress?: AgentEgressConfig;
|
|
116
|
+
/**
|
|
117
|
+
* Disabled by default. Enables local-only Git checkpoint repositories for
|
|
118
|
+
* legacy task workspaces. Mutually exclusive with `agentHome`: strict Agent
|
|
119
|
+
* execution has one canonical workspace authority.
|
|
120
|
+
*/
|
|
92
121
|
gitWorkspace?: GitWorkspaceConfig;
|
|
93
122
|
/** Disabled by default. Enables the durable local task journal — see {@link HostedJournalConfig}. */
|
|
94
123
|
hostedJournal?: HostedJournalConfig;
|
|
@@ -317,6 +346,45 @@ export interface DaemonConfig {
|
|
|
317
346
|
*/
|
|
318
347
|
deviceAssertion?: DeviceAssertionConfig;
|
|
319
348
|
}
|
|
349
|
+
export interface AgentEgressConfig {
|
|
350
|
+
/** Authenticated deployment tenant bound into every local reliable record. */
|
|
351
|
+
tenantId: string;
|
|
352
|
+
/** Exact policy the daemon is willing to consume from an Agent offer. */
|
|
353
|
+
policy: AgentEgressPolicy;
|
|
354
|
+
/** Named redaction hook for explicit contentful trajectory only. */
|
|
355
|
+
sanitizer?: AgentEgressSanitizer;
|
|
356
|
+
/**
|
|
357
|
+
* Device-local additions required to make one server-selected transfer
|
|
358
|
+
* policy executable. These values only supplement `policy.transfers`: a
|
|
359
|
+
* locally configured surface never enables a server-disabled transfer, and
|
|
360
|
+
* cannot widen its maxBytes or MIME authority.
|
|
361
|
+
*/
|
|
362
|
+
contentRead?: AgentContentReadConfig;
|
|
363
|
+
}
|
|
364
|
+
/** Local root and text handling authority for one independently-gated surface. */
|
|
365
|
+
export interface AgentContentReadSurfaceConfig {
|
|
366
|
+
readonly root: AgentContentReadRoot;
|
|
367
|
+
readonly maxTextBytes: number;
|
|
368
|
+
readonly textMimeTypes: readonly string[];
|
|
369
|
+
readonly sensitiveNames?: readonly string[];
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Host-local portions of the content-read contract. The audit ledger has no
|
|
373
|
+
* host path option: SDK composition fixes it per Agent home.
|
|
374
|
+
*/
|
|
375
|
+
export interface AgentContentReadConfig {
|
|
376
|
+
readonly workspace?: AgentContentReadSurfaceConfig;
|
|
377
|
+
readonly transcript?: AgentContentReadSurfaceConfig;
|
|
378
|
+
readonly artifact?: AgentContentReadSurfaceConfig;
|
|
379
|
+
readonly runtimeAllowlistedRoots?: readonly string[];
|
|
380
|
+
}
|
|
381
|
+
export interface AgentReliableEgressInput {
|
|
382
|
+
agentRef: AgentRef;
|
|
383
|
+
sessionRef: string;
|
|
384
|
+
payload: unknown;
|
|
385
|
+
taskId?: string;
|
|
386
|
+
eventId?: string;
|
|
387
|
+
}
|
|
320
388
|
/**
|
|
321
389
|
* Plan `device-assertion-broker`. Two fields, both about what this daemon will
|
|
322
390
|
* refuse.
|
|
@@ -366,6 +434,8 @@ export interface PresenceConfig {
|
|
|
366
434
|
minimumIntervalMs?: number;
|
|
367
435
|
}
|
|
368
436
|
export interface DaemonStatus {
|
|
437
|
+
/** Process-immutable Local Agent application release captured at construction. */
|
|
438
|
+
localAgentRelease: Readonly<LocalAgentReleaseIdentity>;
|
|
369
439
|
paired: boolean;
|
|
370
440
|
connected: boolean;
|
|
371
441
|
/** True once the connection has fallen back to long-poll (protocol §8) — transport info only (finding F6): long-poll is a full transport, so work still proceeds normally while this holds; outbound envelopes POST to /byok/messages instead of going out over WS. */
|
|
@@ -378,12 +448,22 @@ export interface DaemonStatus {
|
|
|
378
448
|
branding?: DaemonBranding;
|
|
379
449
|
/** Local lifecycle/retry budget, separate from transport fallback state. */
|
|
380
450
|
operationalHealth: OperationalHealthSnapshot;
|
|
451
|
+
/** Redacted, content-addressed device-local MCP registry status. */
|
|
452
|
+
toolsets: McpToolsetRegistryStatus;
|
|
453
|
+
/** Content-free egress lane watermarks and typed last-drop facts. */
|
|
454
|
+
egress: AgentEgressStatus;
|
|
381
455
|
}
|
|
382
456
|
export interface Daemon {
|
|
383
457
|
pair(pairingCode: string): Promise<DeviceRecord>;
|
|
384
458
|
start(): Promise<void>;
|
|
385
459
|
stop(): Promise<void>;
|
|
386
460
|
status(): DaemonStatus;
|
|
461
|
+
/** Append one sanitized reliable record before its first transport attempt. */
|
|
462
|
+
publishReliableAgentEgress?(input: AgentReliableEgressInput): Promise<AgentEgressReliableAppendResult>;
|
|
463
|
+
/** Atomically replace the local registry when its current revision matches. */
|
|
464
|
+
reloadMcpToolsets(mcpToolsets: Record<string, McpToolsetConfig> | undefined, expectedRevision: string): McpToolsetReloadReceipt;
|
|
465
|
+
/** Record one explicit host-owned lifecycle observation for a configured toolset. */
|
|
466
|
+
reportMcpToolsetObservation(toolsetId: string, expectedDefinitionRevision: string, observation: McpToolsetObservation): void;
|
|
387
467
|
/**
|
|
388
468
|
* M3-2a: local observability — subscribe to live `DaemonEvent`s (task
|
|
389
469
|
* feed, connection/pairing state changes, runtime-detection results) as
|
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
import { type Envelope } from '@byok-sdk/protocol';
|
|
2
2
|
import { AuthManager } from './auth-manager';
|
|
3
|
+
import { type TransportEndpoint } from './url';
|
|
4
|
+
/**
|
|
5
|
+
* A long-poll request failed in a way that today told the caller only
|
|
6
|
+
* `false`/"retry in 2s" — this names WHICH of the transport's two routes it
|
|
7
|
+
* was and what the server said, so a stuck fallback loop is diagnosable
|
|
8
|
+
* without a packet capture.
|
|
9
|
+
*
|
|
10
|
+
* Scope (review finding — honest attribution): this type represents ONLY an
|
|
11
|
+
* actual route request/response cycle failing. Anything that happens BEFORE
|
|
12
|
+
* the request exists — in practice credential acquisition
|
|
13
|
+
* (`AuthManager.getValidAccessToken`) — is not a route failure and is never
|
|
14
|
+
* reported as one; neither is {@link DeviceRevokedError}, which is a device
|
|
15
|
+
* lifecycle fact rather than something the route did. See
|
|
16
|
+
* `LongPollClient.loop`/`postBatch` for where that boundary is drawn.
|
|
17
|
+
*
|
|
18
|
+
* `status` is the HTTP status of the response the route produced, INCLUDING
|
|
19
|
+
* the case where the response arrived intact and its body then failed to read
|
|
20
|
+
* or parse (a 200 whose payload is malformed is still a 200 — the parse error
|
|
21
|
+
* rides in `cause`). `undefined` means no response was ever produced: the
|
|
22
|
+
* `fetch` itself rejected (DNS/TLS/connection failure, abort). The underlying
|
|
23
|
+
* error is kept in `cause` rather than flattened into the message, so nothing
|
|
24
|
+
* about the original failure is lost.
|
|
25
|
+
*/
|
|
26
|
+
export declare class LongPollRouteError extends Error {
|
|
27
|
+
readonly endpoint: TransportEndpoint;
|
|
28
|
+
readonly status: number | undefined;
|
|
29
|
+
constructor(endpoint: TransportEndpoint, status: number | undefined, cause: unknown);
|
|
30
|
+
}
|
|
3
31
|
export interface LongPollClientOptions {
|
|
4
32
|
serverUrl: string;
|
|
5
33
|
auth: AuthManager;
|
|
@@ -131,7 +159,39 @@ export declare class LongPollClient {
|
|
|
131
159
|
* eviction bookkeeping for a case this unlikely.
|
|
132
160
|
*/
|
|
133
161
|
private readonly warnedValidationFailureSeqs;
|
|
162
|
+
/**
|
|
163
|
+
* `path:status` keys this loop has already warned about — same one-warn-per-key
|
|
164
|
+
* discipline (and same rare-path soft-cap reset) as
|
|
165
|
+
* {@link warnedValidationFailureSeqs}, and for the same reason: an
|
|
166
|
+
* unreachable or misconfigured route fails again every `retryDelayMs` (2s
|
|
167
|
+
* by default) for as long as the fallback is engaged, so an unguarded warn
|
|
168
|
+
* would bury every other line in the log within a minute. Keyed by route
|
|
169
|
+
* AND status so a route that starts failing differently (503 -> 401) still
|
|
170
|
+
* warns once for the new condition.
|
|
171
|
+
*/
|
|
172
|
+
private readonly warnedRouteFailures;
|
|
173
|
+
/**
|
|
174
|
+
* Both routes this transport can fail against, built once (see
|
|
175
|
+
* {@link describeEndpoint} for why constructing them in one place is what
|
|
176
|
+
* keeps credentials out of every diagnostic derived from them).
|
|
177
|
+
*/
|
|
178
|
+
private readonly eventsEndpoint;
|
|
179
|
+
private readonly messagesEndpoint;
|
|
134
180
|
constructor(opts: LongPollClientOptions);
|
|
181
|
+
/**
|
|
182
|
+
* One warn per `path:status`, carrying the typed {@link LongPollRouteError}
|
|
183
|
+
* as the second argument so a caller inspecting the log (or a test) reads
|
|
184
|
+
* the route off the error rather than re-parsing the message.
|
|
185
|
+
*/
|
|
186
|
+
private warnRouteFailure;
|
|
187
|
+
/**
|
|
188
|
+
* {@link DeviceRevokedError} is a device lifecycle fact, not a route
|
|
189
|
+
* failure: it stops this loop outright (retrying cannot help) and is
|
|
190
|
+
* deliberately reported through `onRevoked` ONLY — never additionally as a
|
|
191
|
+
* {@link LongPollRouteError}. Returns whether the error was that case, so
|
|
192
|
+
* each call site can skip its route-failure warn for it.
|
|
193
|
+
*/
|
|
194
|
+
private noteRevoked;
|
|
135
195
|
start(): void;
|
|
136
196
|
stop(): void;
|
|
137
197
|
/**
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* publisher permanently — there is no recourse but a fresh `pair()`, so
|
|
25
25
|
* retrying would be a pure spin.
|
|
26
26
|
*/
|
|
27
|
-
import { type ToolsetId } from '@byok-sdk/protocol';
|
|
27
|
+
import { type RuntimeInfo, type ToolsetId } from '@byok-sdk/protocol';
|
|
28
28
|
import type { AuthManager } from './auth-manager';
|
|
29
29
|
/**
|
|
30
30
|
* Client-side defaults, chosen against the hosted defaults
|
|
@@ -57,8 +57,14 @@ export declare function assertPresenceHeartbeatCadence(cadence: {
|
|
|
57
57
|
export interface PresencePublisherOptions {
|
|
58
58
|
serverUrl: string;
|
|
59
59
|
auth: AuthManager;
|
|
60
|
-
/**
|
|
61
|
-
|
|
60
|
+
/** Reads current sorted logical IDs only; executable definitions and credentials remain device-local. */
|
|
61
|
+
getConfiguredToolsets?: () => readonly ToolsetId[];
|
|
62
|
+
/** U4a Local Agent release version; never inferred from the host package. */
|
|
63
|
+
clientVersion?: string;
|
|
64
|
+
/** The same runtime/auth snapshot sent in `conn.hello`. */
|
|
65
|
+
runtimes?: readonly RuntimeInfo[];
|
|
66
|
+
/** The same protocol-version snapshot sent in `conn.hello`. */
|
|
67
|
+
protocolVersions?: readonly number[];
|
|
62
68
|
/** Heartbeat cadence. Must sit strictly between {@link PresencePublisherOptions.minimumIntervalMs} and {@link PresencePublisherOptions.ttlMs}. */
|
|
63
69
|
intervalMs?: number;
|
|
64
70
|
/** The deployment's presence hint TTL, as this daemon understands it. Only used to validate the cadence. */
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import { type Envelope, type PermissionPolicy, type RuntimeId, type TaskOfferPayload, type TaskOfferWithToolsetsPayload } from '@byok-sdk/protocol';
|
|
1
|
+
import { type AgentEgressPolicy, type Envelope, type PermissionPolicy, type RuntimeId, type TaskOfferPayload, type TaskOfferForAgentPayload, type TaskOfferForAgentWithEgressPayload, type TaskOfferWithToolsetsPayload } from '@byok-sdk/protocol';
|
|
2
2
|
import { type McpToolsetConfig, type RuntimeAdapter } from '../types';
|
|
3
|
+
import { AgentHomeManager, type AgentRef } from '../agent-home';
|
|
4
|
+
import { AgentSessionHandoffStore, type AgentTerminalCause } from './agent-session-handoff-store';
|
|
3
5
|
import { type RuntimeDisposalStage } from '../runtime-failure';
|
|
4
6
|
import { type ApprovalDecision, type ApprovalOrigin, type ApprovalRegistry } from './approvals';
|
|
5
7
|
import type { BlobResolver } from './blob-client';
|
|
6
8
|
import type { TaskQueueWatermark } from './control-protocol';
|
|
9
|
+
import type { LocalAgentReleaseIdentity } from '../release-identity';
|
|
7
10
|
import { type ProgressBatcherOptions } from './progress-batcher';
|
|
8
11
|
import type { SessionWorkspaceStore } from './session-workspace-store';
|
|
9
12
|
import type { GitWorkspaceManager, GitWorkspaceObservation } from './git-workspace';
|
|
10
13
|
import type { GitWorkspaceStore, GitWorkspacePhase } from './git-workspace-store';
|
|
14
|
+
import type { AgentEgressController } from './agent-egress-controller';
|
|
11
15
|
/**
|
|
12
16
|
* M4 Phase 3: default wait for `requestApproval` (see its own doc comment)
|
|
13
17
|
* before force-resolving an unanswered out-of-band approval as a fail-closed
|
|
@@ -40,6 +44,8 @@ export declare const DEFAULT_APPROVAL_TIMEOUT_MS: number;
|
|
|
40
44
|
* `DaemonOverrides.shutdown.taskInterruptTimeoutMs` — see `create-daemon.ts`).
|
|
41
45
|
*/
|
|
42
46
|
export declare const DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS = 5000;
|
|
47
|
+
/** Bounded retry before terminal publication degrades observably. */
|
|
48
|
+
export declare const AGENT_TERMINAL_EVIDENCE_MAX_ATTEMPTS = 3;
|
|
43
49
|
/**
|
|
44
50
|
* M4 Phase 4 (fold-in from the P3 gate): bound on how many `requestApproval`
|
|
45
51
|
* calls may sit QUEUED (not yet dispatched — see that method's own doc
|
|
@@ -183,10 +189,18 @@ export interface TaskRunnerDeps {
|
|
|
183
189
|
runtimeEnvironment?: Record<string, {
|
|
184
190
|
allow?: string[];
|
|
185
191
|
}>;
|
|
186
|
-
/**
|
|
187
|
-
|
|
192
|
+
/** Reads the daemon's current validated device-local registry once per offer. */
|
|
193
|
+
getMcpToolsets?: () => ReadonlyMap<string, McpToolsetConfig>;
|
|
188
194
|
permissionDefaults?: PermissionPolicy;
|
|
189
195
|
workspaceRoot: string;
|
|
196
|
+
/** Strict Agent offer authority. Absent means legacy offers never resolve an Agent home. */
|
|
197
|
+
agentHome?: AgentHomeManager;
|
|
198
|
+
/** Exact host-selected policy accepted by `task.offer_for_agent_with_egress`. */
|
|
199
|
+
agentEgressPolicy?: Readonly<AgentEgressPolicy>;
|
|
200
|
+
/** Always-present projection/sanitizer consumer; it defaults to metadata-only. */
|
|
201
|
+
agentEgress?: AgentEgressController;
|
|
202
|
+
/** Durable exact-match Agent session handoff authority. */
|
|
203
|
+
agentSessionHandoffs?: AgentSessionHandoffStore;
|
|
190
204
|
deviceId: string;
|
|
191
205
|
send: (envelope: Envelope) => void;
|
|
192
206
|
blobClient: BlobResolver;
|
|
@@ -215,6 +229,22 @@ export interface TaskRunnerDeps {
|
|
|
215
229
|
stage: RuntimeDisposalStage;
|
|
216
230
|
reason: string;
|
|
217
231
|
}) => void;
|
|
232
|
+
/**
|
|
233
|
+
* Local audit signal emitted only after bounded Agent-home terminal
|
|
234
|
+
* evidence retries are exhausted. The wire terminal still proceeds so a
|
|
235
|
+
* cloud task cannot remain Claimed/Running forever behind auxiliary local
|
|
236
|
+
* storage failure.
|
|
237
|
+
*/
|
|
238
|
+
onAgentTerminalEvidenceFailure?: (event: {
|
|
239
|
+
taskId: string;
|
|
240
|
+
agentRef: AgentRef;
|
|
241
|
+
runtimeId: string;
|
|
242
|
+
cwd: string;
|
|
243
|
+
cause: AgentTerminalCause;
|
|
244
|
+
reason?: string;
|
|
245
|
+
attempts: number;
|
|
246
|
+
error: string;
|
|
247
|
+
}) => void;
|
|
218
248
|
/**
|
|
219
249
|
* M4 Phase 3: this daemon's control-socket identity + the shared registry
|
|
220
250
|
* backing the control socket's own `approvals.list`/`approvals.resolve`
|
|
@@ -226,6 +256,14 @@ export interface TaskRunnerDeps {
|
|
|
226
256
|
approvalRegistry: ApprovalRegistry;
|
|
227
257
|
storeDir: string;
|
|
228
258
|
productId: string;
|
|
259
|
+
/**
|
|
260
|
+
* The already-resolved, process-immutable U4a Local Agent release identity.
|
|
261
|
+
* `TaskRunner` only consumes this value; it never creates, normalizes, or
|
|
262
|
+
* revalidates a second version authority. It remains optional for direct
|
|
263
|
+
* internal harnesses and old embedders: absence omits terminal usage rather
|
|
264
|
+
* than fabricating a client version.
|
|
265
|
+
*/
|
|
266
|
+
localAgentRelease?: Readonly<LocalAgentReleaseIdentity>;
|
|
229
267
|
/** Default `requestApproval` timeout — see {@link DEFAULT_APPROVAL_TIMEOUT_MS}. */
|
|
230
268
|
approvalTimeoutMs?: number;
|
|
231
269
|
/**
|
|
@@ -328,7 +366,7 @@ export type AdmissionGuardDecision = {
|
|
|
328
366
|
readonly reason: string;
|
|
329
367
|
readonly retryable: boolean;
|
|
330
368
|
};
|
|
331
|
-
type AcceptedOfferPayload = TaskOfferPayload | TaskOfferWithToolsetsPayload;
|
|
369
|
+
type AcceptedOfferPayload = TaskOfferPayload | TaskOfferWithToolsetsPayload | TaskOfferForAgentPayload | TaskOfferForAgentWithEgressPayload;
|
|
332
370
|
/**
|
|
333
371
|
* Per-connection task orchestration: offer -> (decline | prepare -> seal ->
|
|
334
372
|
* claim -> prepared operation -> started) -> seq-ordered progress batches -> complete/fail/
|
|
@@ -453,6 +491,12 @@ export declare class TaskRunner {
|
|
|
453
491
|
private stoppingOffers;
|
|
454
492
|
constructor(deps: TaskRunnerDeps);
|
|
455
493
|
get activeTaskCount(): number;
|
|
494
|
+
/**
|
|
495
|
+
* Transport-boundary classification for the currently active task. Legacy
|
|
496
|
+
* tasks and plain Agent-home offers are deliberately false: the additive
|
|
497
|
+
* egress contract must never reclassify their existing wire semantics.
|
|
498
|
+
*/
|
|
499
|
+
usesAgentEgress(taskId: string): boolean;
|
|
456
500
|
/** M5 batch-3 (workstream 2): effective `maxTaskOutputBytes` cap for this daemon — see {@link DEFAULT_MAX_TASK_OUTPUT_BYTES}'s own doc comment. */
|
|
457
501
|
private get maxTaskOutputBytes();
|
|
458
502
|
/**
|
|
@@ -888,6 +932,27 @@ export declare class TaskRunner {
|
|
|
888
932
|
/** Pre-claim, fail-closed rejection (protocol §3.2) — never claims first. */
|
|
889
933
|
private decline;
|
|
890
934
|
private fail;
|
|
935
|
+
/**
|
|
936
|
+
* Claimed Agent failures before ActiveTask registration still carry the
|
|
937
|
+
* exact AgentRef and normally have Agent-local, fsynced terminal evidence
|
|
938
|
+
* first. A bounded storage failure degrades observably but cannot strand
|
|
939
|
+
* the already-claimed cloud task forever; the exact terminal still goes on
|
|
940
|
+
* the wire and handleOffer's finally block releases the lease.
|
|
941
|
+
*/
|
|
942
|
+
private failClaimedAgent;
|
|
943
|
+
/**
|
|
944
|
+
* Build the optional terminal observation from facts this running daemon
|
|
945
|
+
* actually has. No offered `dispatchSelection` is echoed here: it is a
|
|
946
|
+
* requested execution target, not an adapter-reported provider/model fact.
|
|
947
|
+
* The bundled adapter event contracts currently expose token observations
|
|
948
|
+
* (Codex and Claude) but no provider/model observation, so those keys stay
|
|
949
|
+
* absent. Pi exposes no native usage observation, so its terminal payload
|
|
950
|
+
* omits this optional block rather than fabricating a usage observation from
|
|
951
|
+
* independently known runtime, elapsed duration, or Local Agent version.
|
|
952
|
+
*/
|
|
953
|
+
private terminalInferenceUsagePayload;
|
|
954
|
+
/** Exact Agent identity projection for claim/terminal wire payloads. */
|
|
955
|
+
private agentTerminalPayload;
|
|
891
956
|
/**
|
|
892
957
|
* additive-minor (`task.complete.document`): the whole daemon-side gate
|
|
893
958
|
* between a configured {@link ResultDocumentExtractor} and the wire —
|
|
@@ -946,6 +1011,10 @@ export declare class TaskRunner {
|
|
|
946
1011
|
private hasResultDocumentCapability;
|
|
947
1012
|
private observeGit;
|
|
948
1013
|
private updateGitPhaseBestEffort;
|
|
1014
|
+
/** Persist Agent terminal truth before wire when local storage is available. */
|
|
1015
|
+
private persistAgentTerminalEvidence;
|
|
1016
|
+
private retryAgentTerminalEvidence;
|
|
1017
|
+
private reportAgentTerminalEvidenceFailure;
|
|
949
1018
|
private finish;
|
|
950
1019
|
private reserveSemanticTerminal;
|
|
951
1020
|
/** M3-B: bounded insert for `finishedTaskIds` — see its class-level doc comment and `MAX_TRACKED_TASK_IDS`. Evicts the oldest (first-inserted) entry once over cap, same idiom as `ConnectionHub.checkAndRecordDuplicate` (packages/server/src/hub.ts). */
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ToolsetId } from '@byok-sdk/protocol';
|
|
2
|
+
import type { McpToolsetConfig, McpToolsetObservation, McpToolsetRegistryStatus, McpToolsetReloadReceipt } from '../types';
|
|
3
|
+
export type McpToolsetConfigInput = Record<string, McpToolsetConfig> | undefined;
|
|
4
|
+
export interface McpToolsetRegistrySnapshot {
|
|
5
|
+
revision: string;
|
|
6
|
+
toolsets: ReadonlyMap<string, McpToolsetConfig>;
|
|
7
|
+
configuredToolsets: readonly ToolsetId[];
|
|
8
|
+
}
|
|
9
|
+
export declare class McpToolsetRevisionConflictError extends Error {
|
|
10
|
+
readonly expectedRevision: string;
|
|
11
|
+
readonly actualRevision: string;
|
|
12
|
+
constructor(expectedRevision: string, actualRevision: string);
|
|
13
|
+
}
|
|
14
|
+
export declare class McpToolsetDefinitionRevisionConflictError extends Error {
|
|
15
|
+
readonly toolsetId: string;
|
|
16
|
+
readonly expectedRevision: string;
|
|
17
|
+
readonly actualRevision: string;
|
|
18
|
+
constructor(toolsetId: string, expectedRevision: string, actualRevision: string);
|
|
19
|
+
}
|
|
20
|
+
/** Single mutable owner of immutable-at-a-time device-local toolset snapshots. */
|
|
21
|
+
export declare class McpToolsetRegistry {
|
|
22
|
+
private state;
|
|
23
|
+
private observations;
|
|
24
|
+
constructor(configured?: McpToolsetConfigInput);
|
|
25
|
+
snapshot(): McpToolsetRegistrySnapshot;
|
|
26
|
+
status(): McpToolsetRegistryStatus;
|
|
27
|
+
reload(configured: McpToolsetConfigInput, expectedRevision: string): McpToolsetReloadReceipt;
|
|
28
|
+
report(toolsetId: string, expectedDefinitionRevision: string, observation: McpToolsetObservation): void;
|
|
29
|
+
private statusRows;
|
|
30
|
+
}
|
package/dist/daemon/url.d.ts
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
export declare function toHttpBase(serverUrl: string): string;
|
|
3
3
|
/** Derive the `/byok/ws` WebSocket URL from a configured `serverUrl`. */
|
|
4
4
|
export declare function toWsUrl(serverUrl: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Which route a transport diagnostic is about, in the only two fields that
|
|
7
|
+
* are safe to keep: the host (with port) and the path.
|
|
8
|
+
*
|
|
9
|
+
* Both are read off a parsed `URL` in {@link describeEndpoint}, so the
|
|
10
|
+
* redaction is STRUCTURAL rather than a scrub pass — userinfo, query and
|
|
11
|
+
* fragment are the only places a bearer token or a presigned signature ever
|
|
12
|
+
* travels in this SDK, and none of the three survive the projection onto
|
|
13
|
+
* these two fields. There is exactly one construction site, so a future
|
|
14
|
+
* diagnostic cannot accidentally reintroduce a credential-bearing component
|
|
15
|
+
* by formatting a raw URL of its own.
|
|
16
|
+
*/
|
|
17
|
+
export interface TransportEndpoint {
|
|
18
|
+
readonly transport: 'ws' | 'long-poll';
|
|
19
|
+
/** `URL.host` — hostname plus port when non-default. Never userinfo. */
|
|
20
|
+
readonly host: string;
|
|
21
|
+
/** `URL.pathname` — no query, no fragment. */
|
|
22
|
+
readonly path: string;
|
|
23
|
+
}
|
|
24
|
+
/** The single construction site for {@link TransportEndpoint} — see that interface's own doc comment for why it is the only one. */
|
|
25
|
+
export declare function describeEndpoint(transport: TransportEndpoint['transport'], url: string | URL): TransportEndpoint;
|
|
5
26
|
/**
|
|
6
27
|
* M5: thrown by {@link assertServerUrlAllowed} — see that function's own doc
|
|
7
28
|
* comment for the full allow/deny rule this names. Deliberately ONE error
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { type CapabilityFlag, type Envelope, type RuntimeInfo, type ToolsetId } from '@byok-sdk/protocol';
|
|
2
|
+
import { type TransportEndpoint } from './url';
|
|
2
3
|
export type ConnectionState = 'connecting' | 'open' | 'closed' | 'degraded' | 'revoked';
|
|
3
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* The WS upgrade itself was rejected with a non-101 HTTP status (e.g. 401 for
|
|
6
|
+
* an expired/invalid bearer token). Surfaced via `onConnectOutcome` so
|
|
7
|
+
* `ConnectionManager` can force a reactive token renewal before the next
|
|
8
|
+
* attempt (protocol §6.2, "reactively on 401").
|
|
9
|
+
*
|
|
10
|
+
* Carries the {@link TransportEndpoint} the rejected upgrade was aimed at, so
|
|
11
|
+
* a 401 in a log names WHICH server and path refused it instead of leaving
|
|
12
|
+
* the reader to guess between a stale `serverUrl` and a genuinely expired
|
|
13
|
+
* token. The endpoint's own construction is what keeps the bearer token out
|
|
14
|
+
* of this message — see {@link describeEndpoint}.
|
|
15
|
+
*/
|
|
4
16
|
export declare class WsUnexpectedStatusError extends Error {
|
|
5
17
|
readonly status: number;
|
|
6
|
-
|
|
18
|
+
readonly endpoint: TransportEndpoint;
|
|
19
|
+
constructor(status: number, endpoint: TransportEndpoint);
|
|
7
20
|
}
|
|
8
21
|
export interface BackoffOptions {
|
|
9
22
|
baseMs?: number;
|
|
@@ -23,10 +36,12 @@ export interface WsTransportOptions {
|
|
|
23
36
|
deviceId: string;
|
|
24
37
|
productId: string;
|
|
25
38
|
capabilities: CapabilityFlag[];
|
|
39
|
+
/** U4a Local Agent release version; the sole client-version authority. */
|
|
40
|
+
clientVersion?: string;
|
|
26
41
|
/** Detected runtimes, sent on every `conn.hello` (protocol §10 gap #4/#11). */
|
|
27
42
|
runtimes?: RuntimeInfo[];
|
|
28
|
-
/**
|
|
29
|
-
|
|
43
|
+
/** Reads current sorted logical IDs for every hello; no executable definition crosses the wire. */
|
|
44
|
+
getConfiguredToolsets?: () => readonly ToolsetId[];
|
|
30
45
|
/** The redelivery cursor to send as `conn.hello.cursor` (protocol §9) — read fresh on every connect so a value learned mid-connection is used on the next reconnect. */
|
|
31
46
|
getCursor?: () => number | undefined;
|
|
32
47
|
onEnvelope: (envelope: Envelope) => void;
|
|
@@ -49,13 +64,25 @@ export interface WsTransportOptions {
|
|
|
49
64
|
* and the causing error when the attempt failed before a socket even
|
|
50
65
|
* opened (e.g. `getToken()` rejecting). Used by `ConnectionManager` to
|
|
51
66
|
* count consecutive failures for the long-poll fallback (protocol §8).
|
|
67
|
+
*
|
|
68
|
+
* `endpoint` names the route this attempt was aimed at (computed once per
|
|
69
|
+
* `openSocket()`, so every outcome site reports the same one) — a
|
|
70
|
+
* consecutive-failure count in a log is only actionable once it says WHICH
|
|
71
|
+
* server kept refusing.
|
|
52
72
|
*/
|
|
53
|
-
onConnectOutcome?: (acked: boolean, err
|
|
73
|
+
onConnectOutcome?: (acked: boolean, err: unknown, endpoint: TransportEndpoint) => void;
|
|
54
74
|
backoff?: BackoffOptions;
|
|
55
75
|
liveness?: LivenessOptions;
|
|
56
76
|
/** Deterministic automatic reconnect delay. Manual `connect({auto:false})` never reaches this scheduler. */
|
|
57
77
|
reconnectDelayMs?: (attempt: number, baseDelayMs: number) => number;
|
|
58
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* One canonical authenticated capability snapshot for both transports.
|
|
81
|
+
* Long-poll sends this envelope through `POST /byok/messages`; WS sends the
|
|
82
|
+
* same shape as its opening frame. Keeping construction here prevents one
|
|
83
|
+
* transport from silently omitting a newly added daemon capability.
|
|
84
|
+
*/
|
|
85
|
+
export declare function createConnectionHelloEnvelope(opts: Pick<WsTransportOptions, 'deviceId' | 'productId' | 'capabilities' | 'clientVersion' | 'runtimes' | 'getConfiguredToolsets' | 'getCursor'>): Envelope;
|
|
59
86
|
/**
|
|
60
87
|
* The daemon's outbound-only WS connection: opens, sends `conn.hello`, waits
|
|
61
88
|
* for `conn.ack`, and reconnects with capped exponential backoff + jitter on
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
export type { RuntimeAdapter, RuntimeAdapterDescriptor, RuntimeAdapterPrepareInput, RuntimeAdapterPrepareResult, RuntimeAdapterRejectedOperation, RuntimeAdapterPreparedOperation, PreparedRuntimeOperation, RuntimeOperationManifest, RuntimeOperationStartInput, RuntimeCapabilities, RuntimeDetectResult, Session, GitWorkspaceConfig, McpStdioServerConfig, McpToolsetConfig, } from './types';
|
|
1
|
+
export type { RuntimeAdapter, RuntimeAdapterDescriptor, RuntimeAdapterPrepareInput, RuntimeAdapterPrepareResult, RuntimeAdapterRejectedOperation, RuntimeAdapterPreparedOperation, PreparedRuntimeOperation, RuntimeOperationManifest, RuntimeOperationStartInput, RuntimeCapabilities, RuntimeDetectResult, Session, GitWorkspaceConfig, McpStdioServerConfig, McpToolsetConfig, McpToolsetLifecycleState, McpToolsetObservation, McpToolsetStatus, McpToolsetRegistryStatus, McpToolsetReloadReceipt, AgentEgressPolicy, } from './types';
|
|
2
|
+
export type { AgentRef } from './agent-home';
|
|
3
|
+
export { AgentHomeError, AgentRefValidationError, AgentHomeResolutionError, AgentHomeCollisionError, AgentHomeBusyError, AgentHomeLeaseCorruptError, AgentHomeLayout, AgentHomeLeaseManager, AgentHomeManager, createAgentHomeProjection, stableAgentHomeOwnerId, validateAgentRef, } from './agent-home';
|
|
4
|
+
export { AgentSessionHandoffStore, AgentSessionHandoffStoreError, AgentSessionHandoffCorruptError, AgentSessionHandoffMismatchError, } from './daemon/agent-session-handoff-store';
|
|
5
|
+
export type { AgentSessionHandoff, AgentSessionHandoffMatch, AgentTaskTerminalEvidence, AgentTaskTerminalMatch, AgentTerminalCause, } from './daemon/agent-session-handoff-store';
|
|
6
|
+
export type { AgentHomeResolution, AgentHomeProjection, AgentHomeProjectionInput, AgentHomeProjectionFunction, AgentHomeLease, AgentHomeBinding, } from './agent-home';
|
|
2
7
|
export { PolicyUnsupportedError, SteerUnsupportedError, freezeRuntimeAdapterDescriptor, sealRuntimeOperationManifest } from './types';
|
|
3
8
|
export type { RuntimeEnvironmentRequirements } from './daemon/environment';
|
|
9
|
+
export { resolveLocalAgentReleaseIdentity } from './release-identity';
|
|
10
|
+
export type { LocalAgentReleaseIdentity } from './release-identity';
|
|
4
11
|
export { RuntimeExecutionFailure, RuntimeDisposalFailure, RUNTIME_ADAPTER_CONTRACT_VIOLATION_REASON, isRuntimeDisposalFailure, isRuntimeExecutionFailure, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, } from './runtime-failure';
|
|
5
12
|
export type { RuntimeExecutionFailureInput, RuntimeDisposalFailureInput, RuntimeDisposalStage, RuntimeFailureCategory, RuntimeFailurePhase, RuntimeFailureProjection, RuntimeRetryDisposition, } from './runtime-failure';
|
|
6
13
|
export { GitWorkspaceManager, GitWorkspaceError, isGitWorkspaceConfig, prependGitWorkspaceGuidance } from './daemon/git-workspace';
|
|
@@ -8,7 +15,12 @@ export type { GitWorkspaceObservation, GitWorkspaceLease, GitWorkspaceOptions, G
|
|
|
8
15
|
export { GitWorkspaceStore } from './daemon/git-workspace-store';
|
|
9
16
|
export type { GitWorkspaceLedger, GitWorkspaceLedgerRecord, GitWorkspacePhase } from './daemon/git-workspace-store';
|
|
10
17
|
export { createDaemon, createDaemonWithAdapters } from './daemon/create-daemon';
|
|
11
|
-
export type { Daemon, DaemonConfig, DaemonStatus, DaemonOverrides, DaemonBranding, HostedJournalConfig, DeviceAssertionConfig } from './daemon/create-daemon';
|
|
18
|
+
export type { Daemon, DaemonConfig, DaemonStatus, DaemonOverrides, DaemonBranding, HostedJournalConfig, DeviceAssertionConfig, AgentEgressConfig, AgentContentReadConfig, AgentContentReadSurfaceConfig, AgentReliableEgressInput, } from './daemon/create-daemon';
|
|
19
|
+
export type { AgentEgressDropReceipt, AgentEgressLaneStatus, AgentEgressStatus, } from './daemon/agent-egress-policy';
|
|
20
|
+
export type { AgentEgressSanitizer, AgentEgressSanitizerContext } from './daemon/agent-egress-sanitizer';
|
|
21
|
+
export { AGENT_CONTENT_READ_CAPABILITIES, AGENT_CONTENT_READ_CAPABILITY_WORKSPACE, AGENT_CONTENT_READ_CAPABILITY_TRANSCRIPT, AGENT_CONTENT_READ_CAPABILITY_ARTIFACT, } from './daemon/agent-content-read';
|
|
22
|
+
export type { AgentContentReadSurface, AgentContentReadDecision, AgentContentReadReason, AgentContentReadRoot, AgentContentReadPolicy, AgentContentReadPolicySelection, AgentContentReadRequest, AgentContentReadResult, AgentContentReadAllowed, AgentContentReadDenied, AgentContentSessionIdentity, AgentContentAuditReceipt, } from './daemon/agent-content-read';
|
|
23
|
+
export { McpToolsetRevisionConflictError, McpToolsetDefinitionRevisionConflictError, } from './daemon/toolset-registry';
|
|
12
24
|
export type { ProgressBatcherOptions } from './daemon/progress-batcher';
|
|
13
25
|
/**
|
|
14
26
|
* Plan `device-assertion-broker`: the ONLY control-socket capability this
|