@folsom/fuse 0.37.1 → 0.41.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/dist/index.d.ts +866 -64
- package/dist/index.js +673 -57
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,51 +1,3 @@
|
|
|
1
|
-
/** A minimal fetch signature, satisfied by the global fetch and most polyfills. */
|
|
2
|
-
type FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>;
|
|
3
|
-
/** Per-call options accepted by every service method. */
|
|
4
|
-
interface CallOptions {
|
|
5
|
-
/** Abort the request (and, for events, the stream). */
|
|
6
|
-
signal?: AbortSignal;
|
|
7
|
-
}
|
|
8
|
-
interface TransportConfig {
|
|
9
|
-
baseUrl: string;
|
|
10
|
-
token?: string;
|
|
11
|
-
fetch?: FetchLike;
|
|
12
|
-
userAgent?: string;
|
|
13
|
-
requestId?: () => string;
|
|
14
|
-
timeoutMs?: number;
|
|
15
|
-
headers?: Record<string, string>;
|
|
16
|
-
}
|
|
17
|
-
type Query = Record<string, string | undefined>;
|
|
18
|
-
interface RequestSpec {
|
|
19
|
-
query?: Query;
|
|
20
|
-
body?: unknown;
|
|
21
|
-
signal?: AbortSignal;
|
|
22
|
-
}
|
|
23
|
-
declare class Transport {
|
|
24
|
-
private readonly baseUrl;
|
|
25
|
-
private readonly token?;
|
|
26
|
-
private readonly fetchImpl;
|
|
27
|
-
private readonly userAgent?;
|
|
28
|
-
private readonly requestId?;
|
|
29
|
-
private readonly timeoutMs?;
|
|
30
|
-
private readonly defaultHeaders?;
|
|
31
|
-
constructor(cfg: TransportConfig);
|
|
32
|
-
/** Perform a request and decode a JSON response body. */
|
|
33
|
-
json<T>(method: string, path: string, spec?: RequestSpec): Promise<T>;
|
|
34
|
-
/** Perform a request that returns no body (e.g. 204 actions). */
|
|
35
|
-
noContent(method: string, path: string, spec?: RequestSpec): Promise<void>;
|
|
36
|
-
/**
|
|
37
|
-
* Open a long-lived stream (SSE). Applies NO timeout — only the caller's
|
|
38
|
-
* signal cancels it — and checks the status eagerly so connect-time errors
|
|
39
|
-
* (404/401/...) surface as a FuseApiError before any iteration.
|
|
40
|
-
*/
|
|
41
|
-
stream(path: string, query: Query | undefined, signal?: AbortSignal): Promise<Response>;
|
|
42
|
-
private execute;
|
|
43
|
-
private buildUrl;
|
|
44
|
-
private buildHeaders;
|
|
45
|
-
private decodeJson;
|
|
46
|
-
private withTimeout;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
1
|
/** Spec is the hardware/runtime spec for a microVM. */
|
|
50
2
|
interface Spec {
|
|
51
3
|
cpus?: number;
|
|
@@ -261,11 +213,16 @@ interface Health {
|
|
|
261
213
|
interface EgressSpec {
|
|
262
214
|
/** "direct" (the default) or "proxy". */
|
|
263
215
|
mode?: string;
|
|
264
|
-
/** Proxy backend, required when mode is "proxy" (
|
|
265
|
-
* "
|
|
216
|
+
/** Proxy backend, required when mode is "proxy" ("cloudflare-warp",
|
|
217
|
+
* "wireguard", or "mock" for local development). */
|
|
266
218
|
provider?: string;
|
|
267
219
|
/** "socks5" (the default for proxy) or "http". */
|
|
268
220
|
protocol?: string;
|
|
221
|
+
/** Name of an entry in the request's secrets holding the provider's
|
|
222
|
+
* credential, for a provider that takes one: "wireguard" reads a base64
|
|
223
|
+
* wg-quick config. The value goes to the host's egress backend only and is
|
|
224
|
+
* left out of the secrets the guest receives. */
|
|
225
|
+
secret?: string;
|
|
269
226
|
}
|
|
270
227
|
/**
|
|
271
228
|
* EgressStatus is how the environment's outbound traffic is actually routed.
|
|
@@ -318,6 +275,9 @@ interface CreateRequest {
|
|
|
318
275
|
/** Graphical session geometry. Omit it for an environment with no desktop,
|
|
319
276
|
* in which case a desktop image keeps its baked default geometry. */
|
|
320
277
|
desktop?: DesktopSpec;
|
|
278
|
+
/** Human-in-the-loop policy. Omit it for an environment that cannot raise
|
|
279
|
+
* interventions. */
|
|
280
|
+
hitl?: HitlSpec;
|
|
321
281
|
}
|
|
322
282
|
/** EnvironmentInfo is the server's view of a single microVM. */
|
|
323
283
|
interface EnvironmentInfo {
|
|
@@ -386,6 +346,18 @@ interface ExecRequest {
|
|
|
386
346
|
* default; the server clamps anything above its ceiling.
|
|
387
347
|
*/
|
|
388
348
|
timeout_ms?: number;
|
|
349
|
+
/**
|
|
350
|
+
* Wait for a human when a hitl gate holds the exec (202), or when a
|
|
351
|
+
* human holds the environment (423, a takeover or a pending stall), then
|
|
352
|
+
* run (the default). false throws a PendingInterventionError or a
|
|
353
|
+
* LockedError at once instead. Not sent on the wire.
|
|
354
|
+
*/
|
|
355
|
+
wait?: boolean;
|
|
356
|
+
/**
|
|
357
|
+
* Called with the pending intervention when a gate holds the exec, before
|
|
358
|
+
* waiting on it. It overrides the client's onHeld. Not sent on the wire.
|
|
359
|
+
*/
|
|
360
|
+
onHeld?: (held: Intervention) => void;
|
|
389
361
|
}
|
|
390
362
|
/**
|
|
391
363
|
* ExecResult is the outcome of a guest command.
|
|
@@ -493,7 +465,9 @@ interface Snapshot {
|
|
|
493
465
|
* those bytes is intact, and nothing more: it is not a cross-build
|
|
494
466
|
* identity, because two builds of the same recipe produce different rootfs
|
|
495
467
|
* bytes (timestamps, inode ordering, package caches). It can never be used
|
|
496
|
-
* as a cache key.
|
|
468
|
+
* as a cache key. The live snapshot a migrate takes in its final pause on
|
|
469
|
+
* an xfs or btrfs host is the exception: its digest is a sha256 of its
|
|
470
|
+
* per-block hash table, not of the rootfs file. */
|
|
497
471
|
digest?: string;
|
|
498
472
|
/** Whether this artifact is the rootfs alone (`"disk"`), or the rootfs plus
|
|
499
473
|
* the guest's memory and vCPU state (`"live"`). Restoring a disk snapshot
|
|
@@ -527,6 +501,14 @@ interface HostCapacity {
|
|
|
527
501
|
arch?: string;
|
|
528
502
|
gpus?: number;
|
|
529
503
|
gpu_kind?: string;
|
|
504
|
+
/** The firecracker release the host agent reports it runs ("v1.17.0").
|
|
505
|
+
* Probed at registration (a declared value is ignored) and only set on
|
|
506
|
+
* capacity. Live migration needs both hosts on the same release. Omitted
|
|
507
|
+
* on qemu hosts and older agents. */
|
|
508
|
+
firecracker?: string;
|
|
509
|
+
/** The firecracker release the host's fc-agent.py pins. Differs from
|
|
510
|
+
* firecracker when the host has not run fc-update since the pin moved. */
|
|
511
|
+
firecracker_pinned?: string;
|
|
530
512
|
/** Fractional GPU capacity: MIG instance count by profile name (e.g.
|
|
531
513
|
* {"1g.10gb": 4}). Like gpus, it requires backend "qemu". When the host
|
|
532
514
|
* reports per-instance MIG inventory (mig_instances), this map is a derived
|
|
@@ -608,7 +590,31 @@ interface APIKey {
|
|
|
608
590
|
created_at: string;
|
|
609
591
|
last_used_at?: string;
|
|
610
592
|
revoked_at?: string;
|
|
593
|
+
/** The hitl scopes the key holds. Absent for a full-access key. */
|
|
594
|
+
scopes?: string[];
|
|
595
|
+
/** The environment a scoped key is limited to (and its forks). */
|
|
596
|
+
env_id?: string;
|
|
597
|
+
/** RFC 3339 timestamp. Scoped keys always expire. */
|
|
598
|
+
expires_at?: string;
|
|
599
|
+
/** The actor the key is pinned to, if any. */
|
|
600
|
+
actor?: ActorLabel;
|
|
601
|
+
created_by?: string;
|
|
602
|
+
}
|
|
603
|
+
/** ActorLabel is an actor as a caller names it: an opaque id (at most 128
|
|
604
|
+
* bytes) and an optional display name. */
|
|
605
|
+
interface ActorLabel {
|
|
606
|
+
id: string;
|
|
607
|
+
name?: string;
|
|
611
608
|
}
|
|
609
|
+
/** Hitl scopes a key can be minted with. */
|
|
610
|
+
declare const HitlScope: {
|
|
611
|
+
readonly Read: "hitl:read";
|
|
612
|
+
readonly Decide: "hitl:decide";
|
|
613
|
+
readonly Secret: "hitl:secret";
|
|
614
|
+
readonly Takeover: "hitl:takeover";
|
|
615
|
+
readonly ActAs: "hitl:act-as";
|
|
616
|
+
};
|
|
617
|
+
type HitlScope = (typeof HitlScope)[keyof typeof HitlScope];
|
|
612
618
|
/**
|
|
613
619
|
* CreatedAPIKey is returned by apiKeys.create. `key` is the raw secret and is
|
|
614
620
|
* unrecoverable after this response.
|
|
@@ -643,6 +649,477 @@ declare const HealthState: {
|
|
|
643
649
|
readonly Failing: "failing";
|
|
644
650
|
};
|
|
645
651
|
type HealthState = (typeof HealthState)[keyof typeof HealthState];
|
|
652
|
+
/** HitlSpec is the human-in-the-loop policy an environment is created with. */
|
|
653
|
+
interface HitlSpec {
|
|
654
|
+
/** Default deadline for every intervention, 10 to 86400. Omitted means 600. */
|
|
655
|
+
timeout_seconds?: number;
|
|
656
|
+
/** "reject" (the default) or "allow". */
|
|
657
|
+
on_timeout?: string;
|
|
658
|
+
/** The request kinds the agent may raise. */
|
|
659
|
+
requests: HitlRequests;
|
|
660
|
+
/** Refuse decisions made without a pinned or asserted actor. */
|
|
661
|
+
require_actor?: boolean;
|
|
662
|
+
/** Webhooks told about every intervention and audit event. */
|
|
663
|
+
notify?: HitlWebhook[];
|
|
664
|
+
/** Gates hold, record or deny exec, lifecycle and computer actions, and
|
|
665
|
+
* raise stall and expiry signals. */
|
|
666
|
+
gates?: HitlGate[];
|
|
667
|
+
/** Allowlist mode for exec. */
|
|
668
|
+
exec?: HitlExecPolicy;
|
|
669
|
+
}
|
|
670
|
+
/** HitlGate is one enforced gate. */
|
|
671
|
+
interface HitlGate {
|
|
672
|
+
name: string;
|
|
673
|
+
/** HitlKind.Exec, HitlKind.Lifecycle, HitlKind.Computer, HitlKind.Stall
|
|
674
|
+
* or HitlKind.Expiry. */
|
|
675
|
+
on: string;
|
|
676
|
+
match: HitlGateMatch;
|
|
677
|
+
/** One of GateMode; ask is the default. */
|
|
678
|
+
mode?: string;
|
|
679
|
+
/** The default reach of an approval: "once", "env" or "ttl:<duration>". */
|
|
680
|
+
grant?: string;
|
|
681
|
+
timeout_seconds?: number;
|
|
682
|
+
/** Returned on a deny and shown to the human on an ask. */
|
|
683
|
+
reason?: string;
|
|
684
|
+
/** A webhook asked allow, deny or ask before a human sees an ask gate's
|
|
685
|
+
* action. A failure or timeout means ask. */
|
|
686
|
+
decide?: HitlDecider;
|
|
687
|
+
}
|
|
688
|
+
/** HitlDecider is a gate's decider. secret names an entry in the create
|
|
689
|
+
* request's secrets; its value signs each call (Fuse-Signature). */
|
|
690
|
+
interface HitlDecider {
|
|
691
|
+
url: string;
|
|
692
|
+
secret: string;
|
|
693
|
+
}
|
|
694
|
+
/** HitlGateMatch selects the actions a gate applies to. Every field set must
|
|
695
|
+
* match. */
|
|
696
|
+
interface HitlGateMatch {
|
|
697
|
+
/** Matches the basename of argv[0] after env, sudo, nice, timeout, xargs,
|
|
698
|
+
* nohup and stdbuf are stripped. */
|
|
699
|
+
program?: string[];
|
|
700
|
+
/** Matches when these appear in argv in this order. */
|
|
701
|
+
args?: string[];
|
|
702
|
+
/** Matches any opaque shell exec. */
|
|
703
|
+
shell?: boolean;
|
|
704
|
+
/** Matches lifecycle actions (one of LifecycleAction) or, on a computer
|
|
705
|
+
* gate, computer action names ("type", "key", "left_click", ...). */
|
|
706
|
+
action?: string[];
|
|
707
|
+
/** Matches a computer "type" whose text contains any entry, ignoring
|
|
708
|
+
* case. */
|
|
709
|
+
text_contains?: string[];
|
|
710
|
+
/** Raises a stall after this many consecutive non-zero exec exits
|
|
711
|
+
* (on: "stall"). */
|
|
712
|
+
failures?: number;
|
|
713
|
+
/** Raises a stall after this long with no exec or computer call
|
|
714
|
+
* (on: "stall"). */
|
|
715
|
+
quiet_seconds?: number;
|
|
716
|
+
/** Raises an expiry this long before the idle_timeout or max_runtime reap
|
|
717
|
+
* (on: "expiry"). */
|
|
718
|
+
before_seconds?: number;
|
|
719
|
+
}
|
|
720
|
+
/** HitlExecPolicy is allowlist mode for exec: a program not in allow is held
|
|
721
|
+
* with default ("ask" or "deny"), interpreters and shells included. */
|
|
722
|
+
interface HitlExecPolicy {
|
|
723
|
+
default: string;
|
|
724
|
+
allow: string[];
|
|
725
|
+
}
|
|
726
|
+
/** ExecPayload is a held exec. */
|
|
727
|
+
interface ExecPayload {
|
|
728
|
+
argv: string[];
|
|
729
|
+
shell?: string;
|
|
730
|
+
timeout_ms?: number;
|
|
731
|
+
}
|
|
732
|
+
/** ComputerPayload is a held computer action. input is the body as sent. */
|
|
733
|
+
interface ComputerPayload {
|
|
734
|
+
action: string;
|
|
735
|
+
text?: string;
|
|
736
|
+
input: unknown;
|
|
737
|
+
}
|
|
738
|
+
/** DeciderNote is what a gate's decider said when it sent an action on to a
|
|
739
|
+
* human: verdict "ask" with its reason, or the error fuse fell through on. */
|
|
740
|
+
interface DeciderNote {
|
|
741
|
+
/** One of DeciderVerdict. */
|
|
742
|
+
verdict: string;
|
|
743
|
+
reason?: string;
|
|
744
|
+
error?: string;
|
|
745
|
+
}
|
|
746
|
+
/** InterventionReview is a review request. content is the file as fuse read
|
|
747
|
+
* it at request time when path is set. */
|
|
748
|
+
interface InterventionReview {
|
|
749
|
+
path?: string;
|
|
750
|
+
content: string;
|
|
751
|
+
/** One of ReviewFormat. */
|
|
752
|
+
format: string;
|
|
753
|
+
message?: string;
|
|
754
|
+
truncated?: boolean;
|
|
755
|
+
}
|
|
756
|
+
/** LifecyclePayload is a held environment action. */
|
|
757
|
+
interface LifecyclePayload {
|
|
758
|
+
/** One of LifecycleAction. */
|
|
759
|
+
action: string;
|
|
760
|
+
}
|
|
761
|
+
/** InterventionResult is what running an approved gated action produced. */
|
|
762
|
+
interface InterventionResult {
|
|
763
|
+
exec?: ExecResult;
|
|
764
|
+
computer?: ComputerResult;
|
|
765
|
+
env_id?: string;
|
|
766
|
+
snapshot_id?: string;
|
|
767
|
+
error?: string;
|
|
768
|
+
/** RFC 3339 timestamp. */
|
|
769
|
+
finished_at: string;
|
|
770
|
+
}
|
|
771
|
+
/** HitlWebhook is one hitl.notify target. `secret` names an entry of the
|
|
772
|
+
* create request's secrets; its value signs each delivery with HMAC-SHA256
|
|
773
|
+
* in the Fuse-Signature header. */
|
|
774
|
+
interface HitlWebhook {
|
|
775
|
+
url: string;
|
|
776
|
+
secret: string;
|
|
777
|
+
}
|
|
778
|
+
/** HitlRequests declares the allowed request kinds. Present means allowed;
|
|
779
|
+
* set ask (to {}) to allow asks. */
|
|
780
|
+
interface HitlRequests {
|
|
781
|
+
ask?: HitlAskRequests;
|
|
782
|
+
secret?: HitlSecretRequests;
|
|
783
|
+
takeover?: HitlTakeoverRequests;
|
|
784
|
+
review?: HitlReviewRequests;
|
|
785
|
+
}
|
|
786
|
+
/** HitlReviewRequests configures review requests. Present means allowed. */
|
|
787
|
+
type HitlReviewRequests = Record<string, never>;
|
|
788
|
+
/** HitlSecretRequests declares where a secret may land. The agent names one
|
|
789
|
+
* of these targets; it can never choose a path or variable of its own. */
|
|
790
|
+
interface HitlSecretRequests {
|
|
791
|
+
targets: HitlSecretTarget[];
|
|
792
|
+
}
|
|
793
|
+
/** HitlSecretTarget is one declared destination: exactly one of env (a
|
|
794
|
+
* variable later execs see) or file (an absolute guest path, written 0600).
|
|
795
|
+
* label is what the human is shown first. */
|
|
796
|
+
interface HitlSecretTarget {
|
|
797
|
+
env?: string;
|
|
798
|
+
file?: string;
|
|
799
|
+
label: string;
|
|
800
|
+
}
|
|
801
|
+
/** HitlTakeoverRequests declares the ways a human may take over: "terminal"
|
|
802
|
+
* and "desktop" (which needs a desktop block). Empty means terminal. */
|
|
803
|
+
interface HitlTakeoverRequests {
|
|
804
|
+
via?: string[];
|
|
805
|
+
}
|
|
806
|
+
/** HitlAskRequests configures ask requests. Present means allowed. */
|
|
807
|
+
type HitlAskRequests = Record<string, never>;
|
|
808
|
+
/** Actor is who raised or decided an intervention: "master", "key:<id>", or
|
|
809
|
+
* "system" for fuse itself (expiry, cancel on destroy). */
|
|
810
|
+
interface Actor {
|
|
811
|
+
id: string;
|
|
812
|
+
name?: string;
|
|
813
|
+
/** "key", "system" or "decider". */
|
|
814
|
+
source: string;
|
|
815
|
+
key_id?: string;
|
|
816
|
+
}
|
|
817
|
+
/** InterventionPayload is what was asked, attempted or noticed: a question
|
|
818
|
+
* for an ask, the held exec or lifecycle action for a gate, a secret or
|
|
819
|
+
* takeover request, or a signal. */
|
|
820
|
+
interface InterventionPayload {
|
|
821
|
+
question?: string;
|
|
822
|
+
choices?: string[];
|
|
823
|
+
exec?: ExecPayload;
|
|
824
|
+
lifecycle?: LifecyclePayload;
|
|
825
|
+
/** Set for a secret request only. */
|
|
826
|
+
secret?: InterventionSecret;
|
|
827
|
+
/** Set for a takeover only. */
|
|
828
|
+
takeover?: InterventionTakeover;
|
|
829
|
+
/** What fuse saw, for a stall or expiry. */
|
|
830
|
+
signal?: InterventionSignal;
|
|
831
|
+
/** The held computer action. */
|
|
832
|
+
computer?: ComputerPayload;
|
|
833
|
+
/** What is up for review. */
|
|
834
|
+
review?: InterventionReview;
|
|
835
|
+
/** The gate decider's note on an action it escalated. */
|
|
836
|
+
decider?: DeciderNote;
|
|
837
|
+
}
|
|
838
|
+
/** InterventionSecret is a secret request. label comes from the Fusefile and
|
|
839
|
+
* is what a human should read first; message is the agent's own text. The
|
|
840
|
+
* value is never part of any intervention. */
|
|
841
|
+
interface InterventionSecret {
|
|
842
|
+
target: string;
|
|
843
|
+
label: string;
|
|
844
|
+
message?: string;
|
|
845
|
+
}
|
|
846
|
+
/** InterventionTakeover is a takeover. holder and started_at are set while a
|
|
847
|
+
* human holds the environment, which is also when the agent's exec and
|
|
848
|
+
* computer calls get 423. */
|
|
849
|
+
interface InterventionTakeover {
|
|
850
|
+
via: string;
|
|
851
|
+
reason?: string;
|
|
852
|
+
holder?: Actor;
|
|
853
|
+
/** RFC 3339 timestamp. */
|
|
854
|
+
started_at?: string;
|
|
855
|
+
}
|
|
856
|
+
/** InterventionSignal is what fuse noticed on its own. A stall carries the
|
|
857
|
+
* failure run or the quiet time; an expiry carries the reaper due and when,
|
|
858
|
+
* and once approved the time the environment is kept until. */
|
|
859
|
+
interface InterventionSignal {
|
|
860
|
+
failures?: number;
|
|
861
|
+
last_exit_code?: number;
|
|
862
|
+
quiet_seconds?: number;
|
|
863
|
+
/** "idle_timeout" or "max_runtime". */
|
|
864
|
+
reaper?: string;
|
|
865
|
+
/** RFC 3339 timestamp. */
|
|
866
|
+
reap_at?: string;
|
|
867
|
+
/** RFC 3339 timestamp. */
|
|
868
|
+
extended_until?: string;
|
|
869
|
+
}
|
|
870
|
+
/** InterventionDecision is how an intervention resolved. An expired one
|
|
871
|
+
* carries the on_timeout outcome and a cancelled one a reject. */
|
|
872
|
+
interface InterventionDecision {
|
|
873
|
+
/** "approve" or "reject". */
|
|
874
|
+
outcome: string;
|
|
875
|
+
answer?: string;
|
|
876
|
+
reason?: string;
|
|
877
|
+
decided_by: Actor;
|
|
878
|
+
decided_at: string;
|
|
879
|
+
/** The argv the approver replaced a held exec's with. */
|
|
880
|
+
edited_argv?: string[];
|
|
881
|
+
/** The text the approver replaced a held type's with. */
|
|
882
|
+
edited_text?: string;
|
|
883
|
+
/** How far an approval of a gated action reaches. */
|
|
884
|
+
grant?: string;
|
|
885
|
+
}
|
|
886
|
+
/** Intervention is one request for a human. */
|
|
887
|
+
interface Intervention {
|
|
888
|
+
id: string;
|
|
889
|
+
env_id: string;
|
|
890
|
+
kind: string;
|
|
891
|
+
/** Names the gate that raised it; absent for a request. */
|
|
892
|
+
gate?: string;
|
|
893
|
+
/** The gate's mode (one of GateMode). notify and deny records are born
|
|
894
|
+
* terminal. */
|
|
895
|
+
mode?: string;
|
|
896
|
+
/** One of InterventionState. */
|
|
897
|
+
state: string;
|
|
898
|
+
payload: InterventionPayload;
|
|
899
|
+
triggered_by: Actor;
|
|
900
|
+
/** RFC 3339 timestamp. */
|
|
901
|
+
deadline: string;
|
|
902
|
+
on_timeout: string;
|
|
903
|
+
/** Set on every terminal intervention. */
|
|
904
|
+
decision?: InterventionDecision;
|
|
905
|
+
/** Set once an approved gated action has been performed. */
|
|
906
|
+
result?: InterventionResult;
|
|
907
|
+
created_at: string;
|
|
908
|
+
updated_at: string;
|
|
909
|
+
}
|
|
910
|
+
/** AuditEntry is one row of the hash-chained hitl audit log. It holds who
|
|
911
|
+
* did what and when, never intervention content. Hashes are hex. */
|
|
912
|
+
interface AuditEntry {
|
|
913
|
+
seq: number;
|
|
914
|
+
/** One of AuditEvent. */
|
|
915
|
+
event: string;
|
|
916
|
+
intervention_id?: string;
|
|
917
|
+
env_id?: string;
|
|
918
|
+
actor: Actor;
|
|
919
|
+
remote_addr?: string;
|
|
920
|
+
/** Links a takeover_session row to its cast; fetch it with
|
|
921
|
+
* interventions.getRecording. */
|
|
922
|
+
recording_id?: string;
|
|
923
|
+
/** RFC 3339 timestamp. */
|
|
924
|
+
at: string;
|
|
925
|
+
prev_hash: string;
|
|
926
|
+
hash: string;
|
|
927
|
+
}
|
|
928
|
+
/** Audit log events. */
|
|
929
|
+
declare const AuditEvent: {
|
|
930
|
+
readonly Raised: "raised";
|
|
931
|
+
readonly Decided: "decided";
|
|
932
|
+
readonly Expired: "expired";
|
|
933
|
+
readonly Cancelled: "cancelled";
|
|
934
|
+
readonly InviteMinted: "invite_minted";
|
|
935
|
+
readonly InviteUsed: "invite_used";
|
|
936
|
+
readonly GrantCreated: "grant_created";
|
|
937
|
+
readonly GrantUsed: "grant_used";
|
|
938
|
+
readonly SecretAnswered: "secret_answered";
|
|
939
|
+
readonly TakeoverStarted: "takeover_started";
|
|
940
|
+
readonly TakeoverEnded: "takeover_ended";
|
|
941
|
+
readonly TakeoverSession: "takeover_session";
|
|
942
|
+
};
|
|
943
|
+
type AuditEvent = (typeof AuditEvent)[keyof typeof AuditEvent];
|
|
944
|
+
/** Intervention kinds: ask is a request, exec and lifecycle are the gate
|
|
945
|
+
* surfaces. */
|
|
946
|
+
declare const HitlKind: {
|
|
947
|
+
readonly Ask: "ask";
|
|
948
|
+
readonly Exec: "exec";
|
|
949
|
+
readonly Lifecycle: "lifecycle";
|
|
950
|
+
readonly Computer: "computer";
|
|
951
|
+
readonly Review: "review";
|
|
952
|
+
readonly Secret: "secret";
|
|
953
|
+
readonly Takeover: "takeover";
|
|
954
|
+
readonly Stall: "stall";
|
|
955
|
+
readonly Expiry: "expiry";
|
|
956
|
+
};
|
|
957
|
+
type HitlKind = (typeof HitlKind)[keyof typeof HitlKind];
|
|
958
|
+
/** Gate modes. */
|
|
959
|
+
declare const GateMode: {
|
|
960
|
+
readonly Ask: "ask";
|
|
961
|
+
readonly Notify: "notify";
|
|
962
|
+
readonly Deny: "deny";
|
|
963
|
+
};
|
|
964
|
+
type GateMode = (typeof GateMode)[keyof typeof GateMode];
|
|
965
|
+
/** Decider verdicts. */
|
|
966
|
+
declare const DeciderVerdict: {
|
|
967
|
+
readonly Allow: "allow";
|
|
968
|
+
readonly Deny: "deny";
|
|
969
|
+
readonly Ask: "ask";
|
|
970
|
+
};
|
|
971
|
+
type DeciderVerdict = (typeof DeciderVerdict)[keyof typeof DeciderVerdict];
|
|
972
|
+
/** The actor source a decider's decision records. */
|
|
973
|
+
declare const ACTOR_SOURCE_DECIDER = "decider";
|
|
974
|
+
/** Review formats. */
|
|
975
|
+
declare const ReviewFormat: {
|
|
976
|
+
readonly Text: "text";
|
|
977
|
+
readonly Diff: "diff";
|
|
978
|
+
};
|
|
979
|
+
type ReviewFormat = (typeof ReviewFormat)[keyof typeof ReviewFormat];
|
|
980
|
+
/** Takeover modes: terminal gives the human a shell, desktop the live
|
|
981
|
+
* desktop view (it needs a desktop block). */
|
|
982
|
+
declare const TakeoverVia: {
|
|
983
|
+
readonly Terminal: "terminal";
|
|
984
|
+
readonly Desktop: "desktop";
|
|
985
|
+
};
|
|
986
|
+
type TakeoverVia = (typeof TakeoverVia)[keyof typeof TakeoverVia];
|
|
987
|
+
/** Lifecycle actions a gate can hold. */
|
|
988
|
+
declare const LifecycleAction: {
|
|
989
|
+
readonly Destroy: "destroy";
|
|
990
|
+
readonly Fork: "fork";
|
|
991
|
+
readonly Migrate: "migrate";
|
|
992
|
+
readonly Drain: "drain";
|
|
993
|
+
readonly Snapshot: "snapshot";
|
|
994
|
+
readonly RotateToken: "rotate-token";
|
|
995
|
+
};
|
|
996
|
+
type LifecycleAction = (typeof LifecycleAction)[keyof typeof LifecycleAction];
|
|
997
|
+
/** The gate name the exec allowlist reports. */
|
|
998
|
+
declare const ALLOWLIST_GATE = "exec.allowlist";
|
|
999
|
+
/** Intervention states. pending is the only non-terminal one. */
|
|
1000
|
+
declare const InterventionState: {
|
|
1001
|
+
readonly Pending: "pending";
|
|
1002
|
+
readonly Approved: "approved";
|
|
1003
|
+
readonly Rejected: "rejected";
|
|
1004
|
+
readonly Expired: "expired";
|
|
1005
|
+
readonly Cancelled: "cancelled";
|
|
1006
|
+
};
|
|
1007
|
+
type InterventionState = (typeof InterventionState)[keyof typeof InterventionState];
|
|
1008
|
+
/** Intervention outcomes. Every terminal intervention carries one. */
|
|
1009
|
+
declare const InterventionOutcome: {
|
|
1010
|
+
readonly Approve: "approve";
|
|
1011
|
+
readonly Reject: "reject";
|
|
1012
|
+
};
|
|
1013
|
+
type InterventionOutcome = (typeof InterventionOutcome)[keyof typeof InterventionOutcome];
|
|
1014
|
+
/** isInterventionTerminal reports whether the intervention is resolved. */
|
|
1015
|
+
declare function isInterventionTerminal(i: Intervention | undefined): boolean;
|
|
1016
|
+
/** isInterventionApproved reports whether the intervention resolved as
|
|
1017
|
+
* approve, which includes an expiry under on_timeout: allow. */
|
|
1018
|
+
declare function isInterventionApproved(i: Intervention | undefined): boolean;
|
|
1019
|
+
/** isInterventionSettled reports whether a caller has its final answer:
|
|
1020
|
+
* resolved, and for an approved gated action that fuse performs, performed
|
|
1021
|
+
* (with the outcome on result). */
|
|
1022
|
+
declare function isInterventionSettled(i: Intervention | undefined): boolean;
|
|
1023
|
+
|
|
1024
|
+
/** A minimal fetch signature, satisfied by the global fetch and most polyfills. */
|
|
1025
|
+
type FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>;
|
|
1026
|
+
/** Per-call options accepted by every service method. */
|
|
1027
|
+
interface CallOptions {
|
|
1028
|
+
/** Abort the request (and, for events, the stream). */
|
|
1029
|
+
signal?: AbortSignal;
|
|
1030
|
+
}
|
|
1031
|
+
interface TransportConfig {
|
|
1032
|
+
baseUrl: string;
|
|
1033
|
+
token?: string;
|
|
1034
|
+
fetch?: FetchLike;
|
|
1035
|
+
userAgent?: string;
|
|
1036
|
+
requestId?: () => string;
|
|
1037
|
+
timeoutMs?: number;
|
|
1038
|
+
headers?: Record<string, string>;
|
|
1039
|
+
actor?: ActorLabel;
|
|
1040
|
+
hitlNoWait?: boolean;
|
|
1041
|
+
onHeld?: (held: Intervention) => void;
|
|
1042
|
+
}
|
|
1043
|
+
/** Gated is the answer to a call a hitl gate may hold: the action's own
|
|
1044
|
+
* response body, or the held intervention of a 202. */
|
|
1045
|
+
type Gated<T> = {
|
|
1046
|
+
held: Intervention;
|
|
1047
|
+
} | {
|
|
1048
|
+
held?: undefined;
|
|
1049
|
+
value: T;
|
|
1050
|
+
};
|
|
1051
|
+
type Query = Record<string, string | undefined>;
|
|
1052
|
+
interface RequestSpec {
|
|
1053
|
+
query?: Query;
|
|
1054
|
+
body?: unknown;
|
|
1055
|
+
signal?: AbortSignal;
|
|
1056
|
+
}
|
|
1057
|
+
declare class Transport {
|
|
1058
|
+
private readonly baseUrl;
|
|
1059
|
+
private readonly token?;
|
|
1060
|
+
private readonly fetchImpl;
|
|
1061
|
+
private readonly userAgent?;
|
|
1062
|
+
private readonly requestId?;
|
|
1063
|
+
private readonly timeoutMs?;
|
|
1064
|
+
private readonly defaultHeaders?;
|
|
1065
|
+
private readonly actor?;
|
|
1066
|
+
/** The client's hitl wait options. */
|
|
1067
|
+
readonly hitlNoWait: boolean;
|
|
1068
|
+
readonly onHeld?: (held: Intervention) => void;
|
|
1069
|
+
constructor(cfg: TransportConfig);
|
|
1070
|
+
/** Perform a request and decode a JSON response body. */
|
|
1071
|
+
json<T>(method: string, path: string, spec?: RequestSpec): Promise<T>;
|
|
1072
|
+
/**
|
|
1073
|
+
* Perform a call a hitl gate may hold. A 202 answers with the held
|
|
1074
|
+
* intervention; anything else 2xx with the action's own (possibly empty)
|
|
1075
|
+
* body.
|
|
1076
|
+
*/
|
|
1077
|
+
gated<T>(method: string, path: string, spec?: RequestSpec): Promise<Gated<T>>;
|
|
1078
|
+
/** Like noContent for a call a hitl gate may hold: it resolves to the held
|
|
1079
|
+
* intervention of a 202, or undefined when the action itself answered. */
|
|
1080
|
+
gatedNoContent(method: string, path: string, spec?: RequestSpec): Promise<Intervention | undefined>;
|
|
1081
|
+
/** Perform a request and return the response body as text. */
|
|
1082
|
+
text(method: string, path: string, spec?: RequestSpec): Promise<string>;
|
|
1083
|
+
private decodeHeld;
|
|
1084
|
+
/** Perform a request that returns no body (e.g. 204 actions). */
|
|
1085
|
+
noContent(method: string, path: string, spec?: RequestSpec): Promise<void>;
|
|
1086
|
+
/**
|
|
1087
|
+
* Open a long-lived stream (SSE). Applies NO timeout — only the caller's
|
|
1088
|
+
* signal cancels it — and checks the status eagerly so connect-time errors
|
|
1089
|
+
* (404/401/...) surface as a FuseApiError before any iteration.
|
|
1090
|
+
*/
|
|
1091
|
+
stream(path: string, query: Query | undefined, signal?: AbortSignal): Promise<Response>;
|
|
1092
|
+
private execute;
|
|
1093
|
+
private buildUrl;
|
|
1094
|
+
private buildHeaders;
|
|
1095
|
+
private decodeJson;
|
|
1096
|
+
private withTimeout;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/** Per-call options for calls a takeover can lock or a gate can hold
|
|
1100
|
+
* (computer actions). */
|
|
1101
|
+
interface LockedCallOptions extends CallOptions {
|
|
1102
|
+
/** Wait out a takeover or a pending stall, and a gate's hold (the
|
|
1103
|
+
* default). false throws a LockedError or a PendingInterventionError at
|
|
1104
|
+
* once instead. */
|
|
1105
|
+
wait?: boolean;
|
|
1106
|
+
/** Called with the pending intervention when a gate holds the action,
|
|
1107
|
+
* before waiting on it. It overrides the client's onHeld. */
|
|
1108
|
+
onHeld?: (held: Intervention) => void;
|
|
1109
|
+
}
|
|
1110
|
+
/** Body for environments.takeover. */
|
|
1111
|
+
interface TakeoverOptions {
|
|
1112
|
+
/** How to take over: TakeoverVia.Terminal (the default) or
|
|
1113
|
+
* TakeoverVia.Desktop. */
|
|
1114
|
+
via?: string;
|
|
1115
|
+
/** Recorded when no agent request is pending to claim. */
|
|
1116
|
+
reason?: string;
|
|
1117
|
+
}
|
|
1118
|
+
/** Body for environments.release. */
|
|
1119
|
+
interface ReleaseOptions {
|
|
1120
|
+
/** Handed back to the agent as the takeover's answer. */
|
|
1121
|
+
note?: string;
|
|
1122
|
+
}
|
|
646
1123
|
|
|
647
1124
|
/** Filters (and pagination) for environments.list / environments.listPage. */
|
|
648
1125
|
interface ListEnvironmentsOptions {
|
|
@@ -662,6 +1139,57 @@ interface EnvironmentPage {
|
|
|
662
1139
|
/** Empty/undefined once there are no more results. */
|
|
663
1140
|
nextCursor?: string;
|
|
664
1141
|
}
|
|
1142
|
+
/** What environments.requestHuman sends. */
|
|
1143
|
+
interface HumanRequest {
|
|
1144
|
+
/** The request kind: "ask" (the default), "secret", "takeover" or
|
|
1145
|
+
* "review". */
|
|
1146
|
+
kind?: string;
|
|
1147
|
+
/** What the human is asked (ask). */
|
|
1148
|
+
question?: string;
|
|
1149
|
+
/** Restricts the answer to one of these (ask). */
|
|
1150
|
+
choices?: string[];
|
|
1151
|
+
/** A declared secret target: its env name or file path (secret). */
|
|
1152
|
+
target?: string;
|
|
1153
|
+
/** The agent's text shown under the target's label (secret), or with the
|
|
1154
|
+
* content up for review (review). */
|
|
1155
|
+
message?: string;
|
|
1156
|
+
/** How the human takes over: "terminal" or "desktop" (takeover). */
|
|
1157
|
+
via?: string;
|
|
1158
|
+
/** Why the agent wants a human to take over (takeover). */
|
|
1159
|
+
reason?: string;
|
|
1160
|
+
/** An absolute guest file to review; exclusive with content (review). */
|
|
1161
|
+
path?: string;
|
|
1162
|
+
/** Inline text or a diff to review (review). */
|
|
1163
|
+
content?: string;
|
|
1164
|
+
/** ReviewFormat.Text or ReviewFormat.Diff; unset guesses (review). */
|
|
1165
|
+
format?: string;
|
|
1166
|
+
/** Shortens the policy's deadline. It can never extend it. */
|
|
1167
|
+
timeoutSeconds?: number;
|
|
1168
|
+
/** Wait for a decision (the default). false returns the pending
|
|
1169
|
+
* intervention at once; wait on it later with interventions.wait. */
|
|
1170
|
+
wait?: boolean;
|
|
1171
|
+
}
|
|
1172
|
+
/** What environments.requestReview sends: exactly one of path and content. */
|
|
1173
|
+
interface ReviewRequest {
|
|
1174
|
+
/** An absolute guest file; fuse reads it at request time. */
|
|
1175
|
+
path?: string;
|
|
1176
|
+
/** Inline text or a diff. */
|
|
1177
|
+
content?: string;
|
|
1178
|
+
/** ReviewFormat.Text or ReviewFormat.Diff; unset guesses. */
|
|
1179
|
+
format?: string;
|
|
1180
|
+
message?: string;
|
|
1181
|
+
timeoutSeconds?: number;
|
|
1182
|
+
/** Wait for the verdict (the default). false returns at once with the
|
|
1183
|
+
* pending intervention and approved false. */
|
|
1184
|
+
wait?: boolean;
|
|
1185
|
+
}
|
|
1186
|
+
/** ReviewResult is a finished review. comments are the reviewer's, on
|
|
1187
|
+
* either outcome. */
|
|
1188
|
+
interface ReviewResult {
|
|
1189
|
+
approved: boolean;
|
|
1190
|
+
comments: string;
|
|
1191
|
+
intervention: Intervention;
|
|
1192
|
+
}
|
|
665
1193
|
/** EnvironmentsService manages microVM lifecycle. */
|
|
666
1194
|
declare class EnvironmentsService {
|
|
667
1195
|
private readonly t;
|
|
@@ -676,13 +1204,18 @@ declare class EnvironmentsService {
|
|
|
676
1204
|
get(vmId: string, opts?: CallOptions): Promise<EnvironmentInfo>;
|
|
677
1205
|
/** Provision a new environment. Blocks until running or creation fails. */
|
|
678
1206
|
create(body: CreateRequest, opts?: CallOptions): Promise<EnvironmentInfo>;
|
|
679
|
-
/** Fork an environment into a new one; returns the new environment.
|
|
1207
|
+
/** Fork an environment into a new one; returns the new environment. When a
|
|
1208
|
+
* hitl gate holds the fork, it waits for the decision and returns the
|
|
1209
|
+
* environment the orchestrator then forked. */
|
|
680
1210
|
fork(vmId: string, body?: ForkOptions, opts?: CallOptions): Promise<EnvironmentInfo>;
|
|
681
1211
|
/**
|
|
682
1212
|
* Migrate an environment to another host; returns the new environment. The
|
|
683
1213
|
* source is drained and destroyed once the new one is running.
|
|
684
1214
|
*/
|
|
685
1215
|
migrate(vmId: string, body?: MigrateOptions, opts?: CallOptions): Promise<EnvironmentInfo>;
|
|
1216
|
+
/** heldEnvironment waits out a held fork or migrate and returns the
|
|
1217
|
+
* environment it produced. */
|
|
1218
|
+
private heldEnvironment;
|
|
686
1219
|
/**
|
|
687
1220
|
* Run a command inside a running environment's guest and return its exit code
|
|
688
1221
|
* with stdout and stderr kept separate.
|
|
@@ -692,6 +1225,16 @@ declare class EnvironmentsService {
|
|
|
692
1225
|
*
|
|
693
1226
|
* Exec requires the master token.
|
|
694
1227
|
*
|
|
1228
|
+
* When a hitl gate holds the exec, exec waits for the decision (bounded
|
|
1229
|
+
* only by `opts.signal`); the orchestrator runs the approved (possibly
|
|
1230
|
+
* edited) argv and exec returns its result. A rejection throws an
|
|
1231
|
+
* InterventionRejectedError, a deny gate an error isHitlDenied matches.
|
|
1232
|
+
* `wait: false` throws a PendingInterventionError at once instead.
|
|
1233
|
+
*
|
|
1234
|
+
* While a human holds a takeover (or an ask-mode stall is pending) the
|
|
1235
|
+
* server answers 423; exec waits for that intervention to settle and runs
|
|
1236
|
+
* the command then. `wait: false` throws a LockedError at once instead.
|
|
1237
|
+
*
|
|
695
1238
|
* @example
|
|
696
1239
|
* const out = await client.environments.exec(id, { cmd: ["ls", "-l"] });
|
|
697
1240
|
* if (out.exit_code !== 0) console.error(out.stderr);
|
|
@@ -703,13 +1246,20 @@ declare class EnvironmentsService {
|
|
|
703
1246
|
* booted from a desktop image; on any other image the server answers 503
|
|
704
1247
|
* with a reason.
|
|
705
1248
|
*
|
|
1249
|
+
* Like exec, it waits out a takeover or a pending stall (a 423) and then
|
|
1250
|
+
* acts; `opts.wait: false` throws a LockedError at once instead. When a
|
|
1251
|
+
* computer gate holds the action (a 202), it waits for the decision and
|
|
1252
|
+
* returns what the orchestrator got performing it (with the human's edited
|
|
1253
|
+
* text, if any); a rejection throws an InterventionRejectedError, and
|
|
1254
|
+
* `opts.wait: false` throws a PendingInterventionError at once instead.
|
|
1255
|
+
*
|
|
706
1256
|
* @example
|
|
707
1257
|
* const res = await client.environments.computer(id, {
|
|
708
1258
|
* action: "left_click",
|
|
709
1259
|
* coordinate: [512, 384],
|
|
710
1260
|
* });
|
|
711
1261
|
*/
|
|
712
|
-
computer(vmId: string, action: ComputerAction, opts?:
|
|
1262
|
+
computer(vmId: string, action: ComputerAction, opts?: LockedCallOptions): Promise<ComputerResult>;
|
|
713
1263
|
/**
|
|
714
1264
|
* Execute one computer tool_use against the environment and shape the
|
|
715
1265
|
* answer for the Messages API: the tool_use block's `input` goes in
|
|
@@ -719,7 +1269,7 @@ declare class EnvironmentsService {
|
|
|
719
1269
|
* An action the environment refuses (a malformed coordinate, a display
|
|
720
1270
|
* that is not up) resolves to `is_error` content rather than throwing: the
|
|
721
1271
|
* agent loop should feed it to the model, which is the party that can
|
|
722
|
-
* correct it. A throw is reserved for failures the model cannot fix —
|
|
1272
|
+
* correct it. So does a hitl deny gate or a human rejecting a held action. A throw is reserved for failures the model cannot fix —
|
|
723
1273
|
* transport, auth, an unknown environment.
|
|
724
1274
|
*
|
|
725
1275
|
* @example
|
|
@@ -730,20 +1280,66 @@ declare class EnvironmentsService {
|
|
|
730
1280
|
* }
|
|
731
1281
|
* }
|
|
732
1282
|
*/
|
|
733
|
-
computerToolResult(vmId: string, input: unknown, opts?:
|
|
1283
|
+
computerToolResult(vmId: string, input: unknown, opts?: LockedCallOptions): Promise<ComputerToolResult>;
|
|
1284
|
+
private postComputer;
|
|
1285
|
+
/**
|
|
1286
|
+
* Ask a human for something the environment's hitl policy declares. By
|
|
1287
|
+
* default it waits (by long-polling) until the intervention resolves
|
|
1288
|
+
* (answered, rejected, expired or cancelled); read the result off the
|
|
1289
|
+
* returned intervention's decision. Pass `wait: false` to get the pending
|
|
1290
|
+
* handle instead. Pass `opts.signal` to stop waiting early.
|
|
1291
|
+
*
|
|
1292
|
+
* @example
|
|
1293
|
+
* const res = await client.environments.requestHuman(id, {
|
|
1294
|
+
* question: "deploy to prod?",
|
|
1295
|
+
* choices: ["yes", "no"],
|
|
1296
|
+
* });
|
|
1297
|
+
* if (isInterventionApproved(res)) console.log(res.decision?.answer);
|
|
1298
|
+
*/
|
|
1299
|
+
requestHuman(vmId: string, req: HumanRequest, opts?: CallOptions): Promise<Intervention>;
|
|
1300
|
+
/**
|
|
1301
|
+
* Submit a guest file or a text/diff blob for a human to approve or reject
|
|
1302
|
+
* with comments, and wait for the verdict. Needs hitl.requests.review.
|
|
1303
|
+
* With `wait: false` it returns at once with the pending intervention and
|
|
1304
|
+
* approved false.
|
|
1305
|
+
*
|
|
1306
|
+
* @example
|
|
1307
|
+
* const r = await client.environments.requestReview(id, {
|
|
1308
|
+
* content: diff,
|
|
1309
|
+
* format: ReviewFormat.Diff,
|
|
1310
|
+
* });
|
|
1311
|
+
* if (!r.approved) console.log(r.comments);
|
|
1312
|
+
*/
|
|
1313
|
+
requestReview(vmId: string, req: ReviewRequest, opts?: CallOptions): Promise<ReviewResult>;
|
|
1314
|
+
/**
|
|
1315
|
+
* Take over the environment as a human: claims the agent's pending
|
|
1316
|
+
* takeover request if there is one, else opens a new one. While held, the
|
|
1317
|
+
* agent's exec and computer calls wait. Returns the held intervention.
|
|
1318
|
+
* Needs the hitl:takeover scope; a conflict when someone else holds it.
|
|
1319
|
+
*/
|
|
1320
|
+
takeover(vmId: string, body?: TakeoverOptions, opts?: CallOptions): Promise<Intervention>;
|
|
1321
|
+
/**
|
|
1322
|
+
* End a takeover and hand the environment back to the agent. The note is
|
|
1323
|
+
* the takeover's answer. Returns the approved intervention; a conflict when
|
|
1324
|
+
* nothing is held.
|
|
1325
|
+
*/
|
|
1326
|
+
release(vmId: string, body?: ReleaseOptions, opts?: CallOptions): Promise<Intervention>;
|
|
734
1327
|
/** Report whether the environment has a live display and at what geometry.
|
|
735
1328
|
* up is false with a reason on an image with no desktop. */
|
|
736
1329
|
computerDisplay(vmId: string, opts?: CallOptions): Promise<ComputerDisplay>;
|
|
737
1330
|
/**
|
|
738
1331
|
* Phase-1 only: quiesces the guest workload and moves the environment to
|
|
739
1332
|
* "draining" so you can inspect its output, but does not destroy it. Call
|
|
740
|
-
* destroy() afterward to remove it
|
|
741
|
-
* undestroyed keeps running (and billing)
|
|
1333
|
+
* destroy() afterward to remove it. A drained environment left
|
|
1334
|
+
* undestroyed keeps running (and billing) until the orchestrator's
|
|
1335
|
+
* draining timeout (5m30s by default) passes, and then the orchestrator
|
|
1336
|
+
* destroys it.
|
|
742
1337
|
*/
|
|
743
1338
|
drain(vmId: string, opts?: CallOptions): Promise<EnvironmentInfo>;
|
|
744
1339
|
/** Rotate the per-VM credentials and push them to the guest. */
|
|
745
1340
|
rotateToken(vmId: string, opts?: CallOptions): Promise<void>;
|
|
746
|
-
/** Forcefully destroy an environment. Idempotent.
|
|
1341
|
+
/** Forcefully destroy an environment. Idempotent. When a hitl gate holds
|
|
1342
|
+
* the destroy, it waits for the decision. */
|
|
747
1343
|
destroy(vmId: string, opts?: CallOptions): Promise<void>;
|
|
748
1344
|
/**
|
|
749
1345
|
* Open the SSE event stream for an environment. The returned promise rejects
|
|
@@ -801,7 +1397,10 @@ declare class SnapshotsService {
|
|
|
801
1397
|
* be `"disk"` even for a `live: true` request that reached a host too old to
|
|
802
1398
|
* honour it. A caller that depends on the memory being there should check
|
|
803
1399
|
* it. `live: true` against a backend with no live-snapshot support throws a
|
|
804
|
-
* 501 `unimplemented`, not a conflict.
|
|
1400
|
+
* 501 `unimplemented`, not a conflict.
|
|
1401
|
+
*
|
|
1402
|
+
* When a hitl gate holds the snapshot, create waits for the decision and
|
|
1403
|
+
* returns the snapshot the orchestrator then took. */
|
|
805
1404
|
create(vmId: string, body?: SnapshotRequest, opts?: CallOptions): Promise<Snapshot>;
|
|
806
1405
|
/** List snapshots, optionally filtered. Transparently walks every result
|
|
807
1406
|
* page. For explicit single-page control (e.g. a cursor from a previous
|
|
@@ -869,6 +1468,19 @@ declare class HostsService {
|
|
|
869
1468
|
private action;
|
|
870
1469
|
}
|
|
871
1470
|
|
|
1471
|
+
/** Options for apiKeys.create. Naming scopes mints a key limited to the hitl
|
|
1472
|
+
* routes; it must expire (ttlSeconds, at most 86400). */
|
|
1473
|
+
interface CreateApiKeyOptions {
|
|
1474
|
+
label?: string;
|
|
1475
|
+
/** One or more of HitlScope. Omit for a full-access key. */
|
|
1476
|
+
scopes?: string[];
|
|
1477
|
+
/** Limit a scoped key to this environment and its forks. */
|
|
1478
|
+
envId?: string;
|
|
1479
|
+
/** Lifetime in seconds. */
|
|
1480
|
+
ttlSeconds?: number;
|
|
1481
|
+
/** Pin the key to this actor. */
|
|
1482
|
+
actor?: ActorLabel;
|
|
1483
|
+
}
|
|
872
1484
|
/**
|
|
873
1485
|
* ApiKeysService manages revocable API keys. These endpoints require the
|
|
874
1486
|
* master token; the server enforces this.
|
|
@@ -877,16 +1489,121 @@ declare class ApiKeysService {
|
|
|
877
1489
|
private readonly t;
|
|
878
1490
|
constructor(t: Transport);
|
|
879
1491
|
/**
|
|
880
|
-
* Issue a new API key.
|
|
881
|
-
* unrecoverable afterward.
|
|
1492
|
+
* Issue a new API key. Pass a label, or options for a scoped key. The raw
|
|
1493
|
+
* secret is returned once in `key` and is unrecoverable afterward.
|
|
882
1494
|
*/
|
|
883
|
-
create(
|
|
1495
|
+
create(labelOrOptions?: string | CreateApiKeyOptions, opts?: CallOptions): Promise<CreatedAPIKey>;
|
|
884
1496
|
/** List API key metadata. */
|
|
885
1497
|
list(opts?: CallOptions): Promise<APIKey[]>;
|
|
886
1498
|
/** Revoke the API key with the given id. */
|
|
887
1499
|
revoke(id: string, opts?: CallOptions): Promise<void>;
|
|
888
1500
|
}
|
|
889
1501
|
|
|
1502
|
+
/** Filters (and pagination) for interventions.list / interventions.listPage. */
|
|
1503
|
+
interface ListInterventionsOptions {
|
|
1504
|
+
/** Only interventions raised by this environment. */
|
|
1505
|
+
envId?: string;
|
|
1506
|
+
/** One of InterventionState. */
|
|
1507
|
+
state?: string;
|
|
1508
|
+
/** Only interventions raised or decided by this actor id. */
|
|
1509
|
+
actor?: string;
|
|
1510
|
+
/** Page size. Only consulted by listPage; list() always walks every page. */
|
|
1511
|
+
limit?: number;
|
|
1512
|
+
/** Opaque cursor from a previous listPage() call's nextCursor. */
|
|
1513
|
+
cursor?: string;
|
|
1514
|
+
}
|
|
1515
|
+
/** One page of interventions.listPage, plus the cursor to fetch the next one. */
|
|
1516
|
+
interface InterventionPage {
|
|
1517
|
+
interventions: Intervention[];
|
|
1518
|
+
/** Empty/undefined once there are no more results. */
|
|
1519
|
+
nextCursor?: string;
|
|
1520
|
+
}
|
|
1521
|
+
/** Filters (and pagination) for interventions.audit / interventions.auditPage. */
|
|
1522
|
+
interface AuditOptions {
|
|
1523
|
+
/** Only rows for this environment. */
|
|
1524
|
+
envId?: string;
|
|
1525
|
+
/** Only rows for this actor id. */
|
|
1526
|
+
actor?: string;
|
|
1527
|
+
/** An RFC 3339 time, or a duration like "24h" meaning that long ago. */
|
|
1528
|
+
since?: string;
|
|
1529
|
+
/** Page size. Only consulted by auditPage; audit() always walks every page. */
|
|
1530
|
+
limit?: number;
|
|
1531
|
+
/** Opaque cursor from a previous auditPage() call's nextCursor. */
|
|
1532
|
+
cursor?: string;
|
|
1533
|
+
}
|
|
1534
|
+
/** One page of interventions.auditPage, plus the cursor to fetch the next one. */
|
|
1535
|
+
interface AuditPage {
|
|
1536
|
+
entries: AuditEntry[];
|
|
1537
|
+
/** Empty/undefined once there are no more results. */
|
|
1538
|
+
nextCursor?: string;
|
|
1539
|
+
}
|
|
1540
|
+
/** Body for interventions.approve: an answer to an ask, or an approval of a
|
|
1541
|
+
* held exec or lifecycle action. */
|
|
1542
|
+
interface ApproveOptions {
|
|
1543
|
+
/** An ask needs an answer (one of its choices, when it has any). */
|
|
1544
|
+
answer?: string;
|
|
1545
|
+
reason?: string;
|
|
1546
|
+
/** Replaces a held exec's argv. It is re-checked against the deny gates,
|
|
1547
|
+
* and cannot be combined with grant. */
|
|
1548
|
+
editedArgv?: string[];
|
|
1549
|
+
/** Replaces a held computer "type" action's text. It is re-checked against
|
|
1550
|
+
* the deny gates, and cannot be combined with grant. */
|
|
1551
|
+
editedText?: string;
|
|
1552
|
+
/** "once", "env" or "ttl:<duration>"; unset takes the gate's default. */
|
|
1553
|
+
grant?: string;
|
|
1554
|
+
/** How long approving an expiry keeps the environment alive. Zero or unset
|
|
1555
|
+
* is one more full window of the reaper that was due. */
|
|
1556
|
+
extendSeconds?: number;
|
|
1557
|
+
}
|
|
1558
|
+
/** Body for interventions.reject. */
|
|
1559
|
+
interface RejectOptions {
|
|
1560
|
+
/** Fed back to the agent; the server fills one in when empty. */
|
|
1561
|
+
reason?: string;
|
|
1562
|
+
}
|
|
1563
|
+
/** InterventionsService reads and decides hitl interventions. */
|
|
1564
|
+
declare class InterventionsService {
|
|
1565
|
+
private readonly t;
|
|
1566
|
+
constructor(t: Transport);
|
|
1567
|
+
/** List every intervention matching options, oldest first, walking every
|
|
1568
|
+
* page. */
|
|
1569
|
+
list(options?: ListInterventionsOptions, opts?: CallOptions): Promise<Intervention[]>;
|
|
1570
|
+
/** List one page of interventions matching options. */
|
|
1571
|
+
listPage(options?: ListInterventionsOptions, opts?: CallOptions): Promise<InterventionPage>;
|
|
1572
|
+
/** List every hitl audit row matching options, oldest first, walking every
|
|
1573
|
+
* page. */
|
|
1574
|
+
audit(options?: AuditOptions, opts?: CallOptions): Promise<AuditEntry[]>;
|
|
1575
|
+
/** List one page of the hitl audit log matching options. */
|
|
1576
|
+
auditPage(options?: AuditOptions, opts?: CallOptions): Promise<AuditPage>;
|
|
1577
|
+
/** Fetch a takeover session's recording (an AuditEntry's recording_id):
|
|
1578
|
+
* asciinema v2 cast text for a terminal session, json (an input-action log
|
|
1579
|
+
* plus screenshots) for a desktop one. Needs the hitl:read scope. */
|
|
1580
|
+
getRecording(recordingId: string, opts?: CallOptions): Promise<string>;
|
|
1581
|
+
/** Fetch one intervention without waiting. */
|
|
1582
|
+
get(id: string, opts?: CallOptions): Promise<Intervention>;
|
|
1583
|
+
/**
|
|
1584
|
+
* Block until the intervention settles: resolved, and for an approved gated
|
|
1585
|
+
* action, performed, with the outcome on result. Every intervention has a deadline,
|
|
1586
|
+
* so this always returns eventually. A dropped connection or an
|
|
1587
|
+
* orchestrator restart is survived by polling again; the server, not the
|
|
1588
|
+
* connection, holds the state. Pass `opts.signal` to stop early.
|
|
1589
|
+
*/
|
|
1590
|
+
wait(id: string, opts?: CallOptions): Promise<Intervention>;
|
|
1591
|
+
/** Resolve a pending intervention as approved. For a held exec or
|
|
1592
|
+
* lifecycle action, the orchestrator then performs it (optionally with
|
|
1593
|
+
* body.editedArgv, or granting repeats with body.grant); wait on the id for
|
|
1594
|
+
* its result. Requires the master token. */
|
|
1595
|
+
approve(id: string, body?: ApproveOptions, opts?: CallOptions): Promise<Intervention>;
|
|
1596
|
+
/** Resolve a pending intervention as rejected. Requires the master token. */
|
|
1597
|
+
reject(id: string, body?: RejectOptions, opts?: CallOptions): Promise<Intervention>;
|
|
1598
|
+
/**
|
|
1599
|
+
* Answer a pending secret request. The value is written into the guest at
|
|
1600
|
+
* the declared target and dropped; fuse never stores, logs or returns it.
|
|
1601
|
+
* Needs the hitl:secret scope.
|
|
1602
|
+
*/
|
|
1603
|
+
answerSecret(id: string, value: string, opts?: CallOptions): Promise<Intervention>;
|
|
1604
|
+
private decide;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
890
1607
|
/** Options for constructing a FuseClient. */
|
|
891
1608
|
interface FuseClientOptions {
|
|
892
1609
|
/** Base URL of the Fuse control plane, e.g. "https://fuse.example.com". Required. */
|
|
@@ -903,6 +1620,16 @@ interface FuseClientOptions {
|
|
|
903
1620
|
timeoutMs?: number;
|
|
904
1621
|
/** Extra default headers merged into every request. */
|
|
905
1622
|
headers?: Record<string, string>;
|
|
1623
|
+
/** The human this client acts for, sent as the Fuse-Actor and
|
|
1624
|
+
* Fuse-Actor-Name headers on every request. */
|
|
1625
|
+
actor?: ActorLabel;
|
|
1626
|
+
/** Make every hitl-gated call throw a PendingInterventionError at once
|
|
1627
|
+
* instead of waiting for the human. exec's `wait: false` does the same for
|
|
1628
|
+
* one exec. */
|
|
1629
|
+
hitlNoWait?: boolean;
|
|
1630
|
+
/** Called with the pending intervention whenever a gate holds a call,
|
|
1631
|
+
* before the call waits on it. exec's `onHeld` overrides it. */
|
|
1632
|
+
onHeld?: (held: Intervention) => void;
|
|
906
1633
|
}
|
|
907
1634
|
/**
|
|
908
1635
|
* FuseClient is the entry point for the Fuse API. It groups the resource
|
|
@@ -917,10 +1644,17 @@ declare class FuseClient {
|
|
|
917
1644
|
readonly snapshots: SnapshotsService;
|
|
918
1645
|
readonly hosts: HostsService;
|
|
919
1646
|
readonly apiKeys: ApiKeysService;
|
|
1647
|
+
readonly interventions: InterventionsService;
|
|
1648
|
+
private readonly options;
|
|
920
1649
|
constructor(options: FuseClientOptions);
|
|
1650
|
+
/**
|
|
1651
|
+
* withActor returns a copy of this client, with the same options otherwise,
|
|
1652
|
+
* that sends `actor` as the Fuse-Actor headers. This client is unchanged.
|
|
1653
|
+
*/
|
|
1654
|
+
withActor(actor: ActorLabel): FuseClient;
|
|
921
1655
|
}
|
|
922
1656
|
|
|
923
|
-
declare const VERSION = "0.
|
|
1657
|
+
declare const VERSION = "0.41.0";
|
|
924
1658
|
|
|
925
1659
|
/** Stable, machine-readable error codes returned by the server. */
|
|
926
1660
|
declare const ErrorCode: {
|
|
@@ -930,6 +1664,8 @@ declare const ErrorCode: {
|
|
|
930
1664
|
readonly Unavailable: "unavailable";
|
|
931
1665
|
readonly Internal: "internal";
|
|
932
1666
|
readonly Unauthorized: "unauthorized";
|
|
1667
|
+
readonly Forbidden: "forbidden";
|
|
1668
|
+
readonly Locked: "locked";
|
|
933
1669
|
};
|
|
934
1670
|
type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
935
1671
|
interface FuseApiErrorInit {
|
|
@@ -950,12 +1686,74 @@ declare class FuseApiError extends Error {
|
|
|
950
1686
|
readonly body?: string;
|
|
951
1687
|
constructor(init: FuseApiErrorInit);
|
|
952
1688
|
}
|
|
1689
|
+
/** Reasons a forbidden error carries in details.reason. */
|
|
1690
|
+
declare const ForbiddenReason: {
|
|
1691
|
+
readonly MissingScope: "missing_scope";
|
|
1692
|
+
readonly EnvScope: "env_scope";
|
|
1693
|
+
readonly SelfApproval: "self_approval";
|
|
1694
|
+
readonly ActorRequired: "actor_required";
|
|
1695
|
+
readonly ActorMismatch: "actor_mismatch";
|
|
1696
|
+
readonly ActorNotAllowed: "actor_not_allowed";
|
|
1697
|
+
readonly MintEscalation: "mint_escalation";
|
|
1698
|
+
/** A hitl deny gate (or the exec allowlist in deny mode) refused the
|
|
1699
|
+
* action. The message is the gate's reason; details.gate names the gate. */
|
|
1700
|
+
readonly HitlDenied: "hitl_denied";
|
|
1701
|
+
};
|
|
1702
|
+
type ForbiddenReason = (typeof ForbiddenReason)[keyof typeof ForbiddenReason];
|
|
1703
|
+
/**
|
|
1704
|
+
* ForbiddenError is a 403 forbidden response: the caller is authenticated
|
|
1705
|
+
* but not allowed. `reason` is one of ForbiddenReason (empty when the server
|
|
1706
|
+
* sent none) and `scope` names the missing scope for missing_scope.
|
|
1707
|
+
*/
|
|
1708
|
+
declare class ForbiddenError extends FuseApiError {
|
|
1709
|
+
readonly reason: string;
|
|
1710
|
+
readonly scope?: string;
|
|
1711
|
+
constructor(init: FuseApiErrorInit);
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* LockedError is a 423 locked response: a human holds the environment (a
|
|
1715
|
+
* takeover) or an ask-mode stall is pending, so agent exec and computer calls
|
|
1716
|
+
* are refused. exec and computer wait it out by default; this surfaces only
|
|
1717
|
+
* when waiting is off. Wait on `interventionId` with interventions.wait.
|
|
1718
|
+
*/
|
|
1719
|
+
declare class LockedError extends FuseApiError {
|
|
1720
|
+
readonly interventionId: string;
|
|
1721
|
+
/** "takeover" or "stall". */
|
|
1722
|
+
readonly kind: string;
|
|
1723
|
+
constructor(init: FuseApiErrorInit);
|
|
1724
|
+
}
|
|
1725
|
+
/** isLocked reports whether err is a 423 locked api error. */
|
|
1726
|
+
declare function isLocked(err: unknown): err is LockedError;
|
|
953
1727
|
/** FuseError is a transport, configuration, or decoding failure (not an API error). */
|
|
954
1728
|
declare class FuseError extends Error {
|
|
955
1729
|
constructor(message: string, options?: {
|
|
956
1730
|
cause?: unknown;
|
|
957
1731
|
});
|
|
958
1732
|
}
|
|
1733
|
+
/**
|
|
1734
|
+
* PendingInterventionError is thrown instead of waiting when a hitl gate held
|
|
1735
|
+
* the call and waiting is off (exec's `wait: false` or the client's
|
|
1736
|
+
* `hitlNoWait`). Wait on `intervention.id` with interventions.wait; the
|
|
1737
|
+
* outcome is on its result.
|
|
1738
|
+
*/
|
|
1739
|
+
declare class PendingInterventionError extends Error {
|
|
1740
|
+
readonly intervention: Intervention;
|
|
1741
|
+
constructor(intervention: Intervention);
|
|
1742
|
+
}
|
|
1743
|
+
/**
|
|
1744
|
+
* InterventionRejectedError is a held call a human rejected, or that expired
|
|
1745
|
+
* or was cancelled without approval. `intervention.decision.reason` is for
|
|
1746
|
+
* the agent to read and replan on.
|
|
1747
|
+
*/
|
|
1748
|
+
declare class InterventionRejectedError extends Error {
|
|
1749
|
+
readonly intervention: Intervention;
|
|
1750
|
+
constructor(intervention: Intervention);
|
|
1751
|
+
}
|
|
1752
|
+
/** HeldActionError is an approved held action fuse could not perform. */
|
|
1753
|
+
declare class HeldActionError extends Error {
|
|
1754
|
+
readonly intervention: Intervention;
|
|
1755
|
+
constructor(intervention: Intervention);
|
|
1756
|
+
}
|
|
959
1757
|
/** isFuseApiError is a type guard for FuseApiError. */
|
|
960
1758
|
declare function isFuseApiError(err: unknown): err is FuseApiError;
|
|
961
1759
|
/** isNotFound reports whether err is a not_found api error. */
|
|
@@ -964,9 +1762,13 @@ declare function isNotFound(err: unknown): boolean;
|
|
|
964
1762
|
declare function isConflict(err: unknown): boolean;
|
|
965
1763
|
/** isUnauthorized reports whether err is an unauthorized api error. */
|
|
966
1764
|
declare function isUnauthorized(err: unknown): boolean;
|
|
1765
|
+
/** isForbidden reports whether err is a forbidden api error. */
|
|
1766
|
+
declare function isForbidden(err: unknown): err is ForbiddenError;
|
|
1767
|
+
/** isHitlDenied reports whether err is an action a hitl gate denied. */
|
|
1768
|
+
declare function isHitlDenied(err: unknown): err is ForbiddenError;
|
|
967
1769
|
/** isInvalidArgument reports whether err is an invalid_argument api error. */
|
|
968
1770
|
declare function isInvalidArgument(err: unknown): boolean;
|
|
969
1771
|
/** isUnavailable reports whether err is an unavailable api error. */
|
|
970
1772
|
declare function isUnavailable(err: unknown): boolean;
|
|
971
1773
|
|
|
972
|
-
export { type APIKey, ApiKeysService, type CallOptions, type ComputerAction, type ComputerDisplay, type ComputerResult, type ComputerToolResult, type CreateRequest, type CreatedAPIKey, type DesktopSpec, type EgressHealth, type EgressSpec, type EgressStatus, type Endpoint, type EnvironmentInfo, EnvironmentsService, ErrorCode, type Event, type ExecRequest, type ExecResult, type ExposeSpec, type FetchLike, type ForkOptions, FuseApiError, type FuseApiErrorInit, FuseClient, type FuseClientOptions, FuseError, type GPUDevice, type Health, HealthState, type HealthcheckHttp, type HealthcheckSpec, type Host, type HostCapacity, HostsService, type ListEnvironmentsOptions, type ListSnapshotsOptions, type MIGInstance, type MigrateOptions, type RegisterHostRequest, type Snapshot, type SnapshotExport, type SnapshotRequest, SnapshotsService, type Spec, State, type ToolResultBlock, type ToolResultImageSource, VERSION, isConflict, isFuseApiError, isInvalidArgument, isNotFound, isTerminalState, isUnauthorized, isUnavailable };
|
|
1774
|
+
export { ACTOR_SOURCE_DECIDER, ALLOWLIST_GATE, type APIKey, type Actor, type ActorLabel, ApiKeysService, type ApproveOptions, type AuditEntry, AuditEvent, type AuditOptions, type AuditPage, type CallOptions, type ComputerAction, type ComputerDisplay, type ComputerPayload, type ComputerResult, type ComputerToolResult, type CreateApiKeyOptions, type CreateRequest, type CreatedAPIKey, type DeciderNote, DeciderVerdict, type DesktopSpec, type EgressHealth, type EgressSpec, type EgressStatus, type Endpoint, type EnvironmentInfo, EnvironmentsService, ErrorCode, type Event, type ExecPayload, type ExecRequest, type ExecResult, type ExposeSpec, type FetchLike, ForbiddenError, ForbiddenReason, type ForkOptions, FuseApiError, type FuseApiErrorInit, FuseClient, type FuseClientOptions, FuseError, type GPUDevice, GateMode, type Health, HealthState, type HealthcheckHttp, type HealthcheckSpec, HeldActionError, type HitlAskRequests, type HitlDecider, type HitlExecPolicy, type HitlGate, type HitlGateMatch, HitlKind, type HitlRequests, type HitlReviewRequests, HitlScope, type HitlSecretRequests, type HitlSecretTarget, type HitlSpec, type HitlTakeoverRequests, type HitlWebhook, type Host, type HostCapacity, HostsService, type HumanRequest, type Intervention, type InterventionDecision, InterventionOutcome, type InterventionPage, type InterventionPayload, InterventionRejectedError, type InterventionResult, type InterventionReview, type InterventionSecret, type InterventionSignal, InterventionState, type InterventionTakeover, InterventionsService, LifecycleAction, type LifecyclePayload, type ListEnvironmentsOptions, type ListInterventionsOptions, type ListSnapshotsOptions, type LockedCallOptions, LockedError, type MIGInstance, type MigrateOptions, PendingInterventionError, type RegisterHostRequest, type RejectOptions, type ReleaseOptions, ReviewFormat, type ReviewRequest, type ReviewResult, type Snapshot, type SnapshotExport, type SnapshotRequest, SnapshotsService, type Spec, State, type TakeoverOptions, TakeoverVia, type ToolResultBlock, type ToolResultImageSource, VERSION, isConflict, isForbidden, isFuseApiError, isHitlDenied, isInterventionApproved, isInterventionSettled, isInterventionTerminal, isInvalidArgument, isLocked, isNotFound, isTerminalState, isUnauthorized, isUnavailable };
|