@leaflow/sdk 0.0.0-dev.496.g35e57c5 → 0.0.0-dev.498.gdfc2667
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/fleet/v1/generated/functions.d.ts +11 -8
- package/dist/fleet/v1/generated/functions.js +11 -8
- package/dist/fleet/v1/generated/models.d.ts +32 -18
- package/dist/fleet/v1/generated/models.js +1 -1
- package/dist/fleet/v1/generated/schemas.zod.d.ts +12 -16
- package/dist/fleet/v1/generated/schemas.zod.js +32 -13
- package/dist/fleet/v1/generated/validators/callToolRequest.zod.d.ts +2 -8
- package/dist/fleet/v1/generated/validators/callToolRequest.zod.js +6 -2
- package/dist/fleet/v1/generated/validators/toolDescriptor.zod.d.ts +5 -8
- package/dist/fleet/v1/generated/validators/toolDescriptor.zod.js +9 -3
- package/dist/fleet/v1/generated/validators/toolList.zod.d.ts +4 -8
- package/package.json +1 -1
- package/dist/fleet/v1/generated/validators/toolRef.zod.d.ts +0 -257
- package/dist/fleet/v1/generated/validators/toolRef.zod.js +0 -257
|
@@ -554,7 +554,9 @@ export type listToolsResponse = listToolsResponseSuccess | listToolsResponseErro
|
|
|
554
554
|
export declare const getListToolsUrl: (machineId: string, params: ListToolsParams) => string;
|
|
555
555
|
/**
|
|
556
556
|
* Queries Agent's builtin tools and the caller's configured MCP servers live. No directory,
|
|
557
|
-
* result or image is cached.
|
|
557
|
+
* result or image is cached. Each tool has one callable name: builtin tools are named
|
|
558
|
+
* computer.*, MCP tools are named `<server>__<tool>`; source only filters the list and is not
|
|
559
|
+
* part of a tool's identity. Requires fleet:machines.login; builtin capabilities retain
|
|
558
560
|
* their native policies and read-only restrictions. Ensures or reuses the caller's single
|
|
559
561
|
* open graphical session, without launching a desktop environment. The client instance is
|
|
560
562
|
* a UUID generated once per running client, not an authorization credential. Each request
|
|
@@ -583,18 +585,19 @@ export type callToolResponse = callToolResponseSuccess | callToolResponseError;
|
|
|
583
585
|
export declare const getCallToolUrl: (machineId: string) => string;
|
|
584
586
|
/**
|
|
585
587
|
* Uses the same current permissions, directory account and graphical session as list-tools.
|
|
586
|
-
* Listing is not a precondition: callers may use a previously discovered
|
|
588
|
+
* Listing is not a precondition: callers may use a previously discovered tool name, and this
|
|
587
589
|
* operation never sends a discovery request or refreshes schemas before executing it.
|
|
588
590
|
* A removed tool or MCP server returns TOOL_NOT_FOUND, as does a direct builtin computer.*
|
|
589
591
|
* call while virtual desktop capability is unavailable. Actual permission errors remain
|
|
590
592
|
* permission errors; a missing target window is not a missing tool. Use list-tools only when
|
|
591
593
|
* discovery or refresh is needed, and do not cache or reuse execution results.
|
|
592
|
-
*
|
|
593
|
-
* object is at most 256 KiB. The complete result is at most
|
|
594
|
-
* with each encoded image at most 4 MiB; images are converted
|
|
595
|
-
* boundary, without recompression or persistence. Cancellation is
|
|
596
|
-
* disconnect or failed response does not prove that side effects did
|
|
597
|
-
* automatically replay. operation_id only correlates live activity, not
|
|
594
|
+
* The name selects exactly one tool: builtin tools are computer.*, MCP tools are
|
|
595
|
+
* `<server>__<tool>`. The arguments object is at most 256 KiB. The complete result is at most
|
|
596
|
+
* 8 MiB in the protobuf transport, with each encoded image at most 4 MiB; images are converted
|
|
597
|
+
* to base64 once at this JSON boundary, without recompression or persistence. Cancellation is
|
|
598
|
+
* propagated. A timeout, disconnect or failed response does not prove that side effects did
|
|
599
|
+
* not happen; do not automatically replay. operation_id only correlates live activity, not
|
|
600
|
+
* idempotency.
|
|
598
601
|
* @summary Call a live builtin or external MCP tool
|
|
599
602
|
*/
|
|
600
603
|
export declare const callTool: (machineId: string, callToolRequest: CallToolRequest, options?: RequestInit, fetchFn?: typeof globalThis.fetch) => Promise<callToolResponse>;
|
|
@@ -344,7 +344,9 @@ export const getListToolsUrl = (machineId, params) => {
|
|
|
344
344
|
};
|
|
345
345
|
/**
|
|
346
346
|
* Queries Agent's builtin tools and the caller's configured MCP servers live. No directory,
|
|
347
|
-
* result or image is cached.
|
|
347
|
+
* result or image is cached. Each tool has one callable name: builtin tools are named
|
|
348
|
+
* computer.*, MCP tools are named `<server>__<tool>`; source only filters the list and is not
|
|
349
|
+
* part of a tool's identity. Requires fleet:machines.login; builtin capabilities retain
|
|
348
350
|
* their native policies and read-only restrictions. Ensures or reuses the caller's single
|
|
349
351
|
* open graphical session, without launching a desktop environment. The client instance is
|
|
350
352
|
* a UUID generated once per running client, not an authorization credential. Each request
|
|
@@ -368,18 +370,19 @@ export const getCallToolUrl = (machineId) => {
|
|
|
368
370
|
};
|
|
369
371
|
/**
|
|
370
372
|
* Uses the same current permissions, directory account and graphical session as list-tools.
|
|
371
|
-
* Listing is not a precondition: callers may use a previously discovered
|
|
373
|
+
* Listing is not a precondition: callers may use a previously discovered tool name, and this
|
|
372
374
|
* operation never sends a discovery request or refreshes schemas before executing it.
|
|
373
375
|
* A removed tool or MCP server returns TOOL_NOT_FOUND, as does a direct builtin computer.*
|
|
374
376
|
* call while virtual desktop capability is unavailable. Actual permission errors remain
|
|
375
377
|
* permission errors; a missing target window is not a missing tool. Use list-tools only when
|
|
376
378
|
* discovery or refresh is needed, and do not cache or reuse execution results.
|
|
377
|
-
*
|
|
378
|
-
* object is at most 256 KiB. The complete result is at most
|
|
379
|
-
* with each encoded image at most 4 MiB; images are converted
|
|
380
|
-
* boundary, without recompression or persistence. Cancellation is
|
|
381
|
-
* disconnect or failed response does not prove that side effects did
|
|
382
|
-
* automatically replay. operation_id only correlates live activity, not
|
|
379
|
+
* The name selects exactly one tool: builtin tools are computer.*, MCP tools are
|
|
380
|
+
* `<server>__<tool>`. The arguments object is at most 256 KiB. The complete result is at most
|
|
381
|
+
* 8 MiB in the protobuf transport, with each encoded image at most 4 MiB; images are converted
|
|
382
|
+
* to base64 once at this JSON boundary, without recompression or persistence. Cancellation is
|
|
383
|
+
* propagated. A timeout, disconnect or failed response does not prove that side effects did
|
|
384
|
+
* not happen; do not automatically replay. operation_id only correlates live activity, not
|
|
385
|
+
* idempotency.
|
|
383
386
|
* @summary Call a live builtin or external MCP tool
|
|
384
387
|
*/
|
|
385
388
|
export const callTool = async (machineId, callToolRequest, options, fetchFn) => {
|
|
@@ -979,25 +979,14 @@ export interface SendMcpRequestResponse {
|
|
|
979
979
|
/** The server's JSON-RPC 2.0 response, with the id of the request */
|
|
980
980
|
response: SendMcpRequestResponseResponse;
|
|
981
981
|
}
|
|
982
|
-
|
|
983
|
-
|
|
982
|
+
/**
|
|
983
|
+
* Whether the tool is builtin or comes from an MCP server. For filtering only.
|
|
984
|
+
*/
|
|
985
|
+
export type ToolDescriptorSource = (typeof ToolDescriptorSource)[keyof typeof ToolDescriptorSource];
|
|
986
|
+
export declare const ToolDescriptorSource: {
|
|
984
987
|
readonly builtin: "builtin";
|
|
985
988
|
readonly mcp: "mcp";
|
|
986
989
|
};
|
|
987
|
-
export interface ToolRef {
|
|
988
|
-
source: ToolRefSource;
|
|
989
|
-
/**
|
|
990
|
-
* @minLength 1
|
|
991
|
-
* @maxLength 128
|
|
992
|
-
*/
|
|
993
|
-
name: string;
|
|
994
|
-
/**
|
|
995
|
-
* Required only for mcp; forbidden for builtin
|
|
996
|
-
* @minLength 1
|
|
997
|
-
* @maxLength 64
|
|
998
|
-
*/
|
|
999
|
-
server?: string;
|
|
1000
|
-
}
|
|
1001
990
|
export type ToolDescriptorInputSchema = {
|
|
1002
991
|
[key: string]: unknown;
|
|
1003
992
|
};
|
|
@@ -1011,8 +1000,15 @@ export type ToolDescriptorMetadata = {
|
|
|
1011
1000
|
[key: string]: unknown;
|
|
1012
1001
|
};
|
|
1013
1002
|
export interface ToolDescriptor {
|
|
1014
|
-
|
|
1003
|
+
/**
|
|
1004
|
+
* The name to call it by. Builtin tools are named computer.*; MCP tools are named
|
|
1005
|
+
* `<server>__<tool>`, so a name selects exactly one tool.
|
|
1006
|
+
* @minLength 1
|
|
1007
|
+
* @maxLength 194
|
|
1008
|
+
*/
|
|
1015
1009
|
name: string;
|
|
1010
|
+
/** Whether the tool is builtin or comes from an MCP server. For filtering only. */
|
|
1011
|
+
source: ToolDescriptorSource;
|
|
1016
1012
|
title: string;
|
|
1017
1013
|
description: string;
|
|
1018
1014
|
input_schema: ToolDescriptorInputSchema;
|
|
@@ -1045,7 +1041,13 @@ export type CallToolRequestArguments = {
|
|
|
1045
1041
|
};
|
|
1046
1042
|
export interface CallToolRequest {
|
|
1047
1043
|
client_instance_id: string;
|
|
1048
|
-
|
|
1044
|
+
/**
|
|
1045
|
+
* The name from list-tools. Builtin tools are computer.*; MCP tools are
|
|
1046
|
+
* `<server>__<tool>`. The name selects the tool; source is not part of the call.
|
|
1047
|
+
* @minLength 1
|
|
1048
|
+
* @maxLength 194
|
|
1049
|
+
*/
|
|
1050
|
+
tool: string;
|
|
1049
1051
|
/** A JSON object, at most 256 KiB when encoded */
|
|
1050
1052
|
arguments: CallToolRequestArguments;
|
|
1051
1053
|
read_only?: boolean;
|
|
@@ -1539,16 +1541,28 @@ export type DeleteMcpServerParams = {
|
|
|
1539
1541
|
expected_revision?: string;
|
|
1540
1542
|
};
|
|
1541
1543
|
export type ListToolsParams = {
|
|
1544
|
+
/**
|
|
1545
|
+
* A UUID generated once per running client and reused for its lifetime. It separates
|
|
1546
|
+
* concurrent callers of the same user and is not an authorization credential.
|
|
1547
|
+
*/
|
|
1542
1548
|
client_instance_id: string;
|
|
1549
|
+
/**
|
|
1550
|
+
* Return only tools of this source. A filter, not part of a tool's identity.
|
|
1551
|
+
*/
|
|
1543
1552
|
source?: ListToolsSource;
|
|
1544
1553
|
/**
|
|
1554
|
+
* Return only this MCP server's tools.
|
|
1545
1555
|
* @maxLength 64
|
|
1546
1556
|
*/
|
|
1547
1557
|
mcp_server?: string;
|
|
1548
1558
|
/**
|
|
1559
|
+
* Words that each must occur in a tool's name, title or description, ignoring case.
|
|
1549
1560
|
* @maxLength 256
|
|
1550
1561
|
*/
|
|
1551
1562
|
query?: string;
|
|
1563
|
+
/**
|
|
1564
|
+
* Sign the control authorization as read-only, so mutating tools are refused.
|
|
1565
|
+
*/
|
|
1552
1566
|
read_only?: boolean;
|
|
1553
1567
|
/**
|
|
1554
1568
|
* @minimum 1
|
|
@@ -445,7 +445,9 @@ export declare const DeleteMcpServerQueryParams: zod.ZodObject<{
|
|
|
445
445
|
}, zod.z.core.$strict>;
|
|
446
446
|
/**
|
|
447
447
|
* Queries Agent's builtin tools and the caller's configured MCP servers live. No directory,
|
|
448
|
-
* result or image is cached.
|
|
448
|
+
* result or image is cached. Each tool has one callable name: builtin tools are named
|
|
449
|
+
* computer.*, MCP tools are named `<server>__<tool>`; source only filters the list and is not
|
|
450
|
+
* part of a tool's identity. Requires fleet:machines.login; builtin capabilities retain
|
|
449
451
|
* their native policies and read-only restrictions. Ensures or reuses the caller's single
|
|
450
452
|
* open graphical session, without launching a desktop environment. The client instance is
|
|
451
453
|
* a UUID generated once per running client, not an authorization credential. Each request
|
|
@@ -480,18 +482,19 @@ export declare const ListToolsQueryParams: zod.ZodObject<{
|
|
|
480
482
|
}, zod.z.core.$strict>;
|
|
481
483
|
/**
|
|
482
484
|
* Uses the same current permissions, directory account and graphical session as list-tools.
|
|
483
|
-
* Listing is not a precondition: callers may use a previously discovered
|
|
485
|
+
* Listing is not a precondition: callers may use a previously discovered tool name, and this
|
|
484
486
|
* operation never sends a discovery request or refreshes schemas before executing it.
|
|
485
487
|
* A removed tool or MCP server returns TOOL_NOT_FOUND, as does a direct builtin computer.*
|
|
486
488
|
* call while virtual desktop capability is unavailable. Actual permission errors remain
|
|
487
489
|
* permission errors; a missing target window is not a missing tool. Use list-tools only when
|
|
488
490
|
* discovery or refresh is needed, and do not cache or reuse execution results.
|
|
489
|
-
*
|
|
490
|
-
* object is at most 256 KiB. The complete result is at most
|
|
491
|
-
* with each encoded image at most 4 MiB; images are converted
|
|
492
|
-
* boundary, without recompression or persistence. Cancellation is
|
|
493
|
-
* disconnect or failed response does not prove that side effects did
|
|
494
|
-
* automatically replay. operation_id only correlates live activity, not
|
|
491
|
+
* The name selects exactly one tool: builtin tools are computer.*, MCP tools are
|
|
492
|
+
* `<server>__<tool>`. The arguments object is at most 256 KiB. The complete result is at most
|
|
493
|
+
* 8 MiB in the protobuf transport, with each encoded image at most 4 MiB; images are converted
|
|
494
|
+
* to base64 once at this JSON boundary, without recompression or persistence. Cancellation is
|
|
495
|
+
* propagated. A timeout, disconnect or failed response does not prove that side effects did
|
|
496
|
+
* not happen; do not automatically replay. operation_id only correlates live activity, not
|
|
497
|
+
* idempotency.
|
|
495
498
|
* @summary Call a live builtin or external MCP tool
|
|
496
499
|
*/
|
|
497
500
|
export declare const CallToolParams: zod.ZodObject<{
|
|
@@ -499,14 +502,7 @@ export declare const CallToolParams: zod.ZodObject<{
|
|
|
499
502
|
}, zod.z.core.$strict>;
|
|
500
503
|
export declare const CallToolBody: zod.ZodObject<{
|
|
501
504
|
client_instance_id: zod.ZodUUID;
|
|
502
|
-
tool: zod.
|
|
503
|
-
source: zod.ZodEnum<{
|
|
504
|
-
builtin: "builtin";
|
|
505
|
-
mcp: "mcp";
|
|
506
|
-
}>;
|
|
507
|
-
name: zod.ZodString;
|
|
508
|
-
server: zod.ZodOptional<zod.ZodString>;
|
|
509
|
-
}, zod.z.core.$strict>;
|
|
505
|
+
tool: zod.ZodString;
|
|
510
506
|
arguments: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
|
|
511
507
|
read_only: zod.ZodDefault<zod.ZodBoolean>;
|
|
512
508
|
timeout_seconds: zod.ZodDefault<zod.ZodInt>;
|
|
@@ -478,7 +478,9 @@ export const DeleteMcpServerQueryParams = zod.strictObject({
|
|
|
478
478
|
});
|
|
479
479
|
/**
|
|
480
480
|
* Queries Agent's builtin tools and the caller's configured MCP servers live. No directory,
|
|
481
|
-
* result or image is cached.
|
|
481
|
+
* result or image is cached. Each tool has one callable name: builtin tools are named
|
|
482
|
+
* computer.*, MCP tools are named `<server>__<tool>`; source only filters the list and is not
|
|
483
|
+
* part of a tool's identity. Requires fleet:machines.login; builtin capabilities retain
|
|
482
484
|
* their native policies and read-only restrictions. Ensures or reuses the caller's single
|
|
483
485
|
* open graphical session, without launching a desktop environment. The client instance is
|
|
484
486
|
* a UUID generated once per running client, not an authorization credential. Each request
|
|
@@ -499,28 +501,45 @@ export const listToolsQueryPageSizeDefault = 100;
|
|
|
499
501
|
export const listToolsQueryPageSizeMax = 100;
|
|
500
502
|
export const listToolsQueryPageTokenMax = 4096;
|
|
501
503
|
export const ListToolsQueryParams = zod.strictObject({
|
|
502
|
-
client_instance_id: zod
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
504
|
+
client_instance_id: zod
|
|
505
|
+
.uuid()
|
|
506
|
+
.describe("A UUID generated once per running client and reused for its lifetime. It separates\nconcurrent callers of the same user and is not an authorization credential."),
|
|
507
|
+
source: zod
|
|
508
|
+
.enum(["all", "builtin", "mcp"])
|
|
509
|
+
.default(listToolsQuerySourceDefault)
|
|
510
|
+
.describe("Return only tools of this source. A filter, not part of a tool's identity."),
|
|
511
|
+
mcp_server: zod
|
|
512
|
+
.string()
|
|
513
|
+
.max(listToolsQueryMcpServerMax)
|
|
514
|
+
.optional()
|
|
515
|
+
.describe("Return only this MCP server's tools."),
|
|
516
|
+
query: zod
|
|
517
|
+
.string()
|
|
518
|
+
.max(listToolsQueryQueryMax)
|
|
519
|
+
.optional()
|
|
520
|
+
.describe("Words that each must occur in a tool's name, title or description, ignoring case."),
|
|
521
|
+
read_only: zod
|
|
522
|
+
.boolean()
|
|
523
|
+
.default(listToolsQueryReadOnlyDefault)
|
|
524
|
+
.describe("Sign the control authorization as read-only, so mutating tools are refused."),
|
|
507
525
|
page_size: zod.int().min(1).max(listToolsQueryPageSizeMax).default(listToolsQueryPageSizeDefault),
|
|
508
526
|
page_token: zod.string().max(listToolsQueryPageTokenMax).optional(),
|
|
509
527
|
});
|
|
510
528
|
/**
|
|
511
529
|
* Uses the same current permissions, directory account and graphical session as list-tools.
|
|
512
|
-
* Listing is not a precondition: callers may use a previously discovered
|
|
530
|
+
* Listing is not a precondition: callers may use a previously discovered tool name, and this
|
|
513
531
|
* operation never sends a discovery request or refreshes schemas before executing it.
|
|
514
532
|
* A removed tool or MCP server returns TOOL_NOT_FOUND, as does a direct builtin computer.*
|
|
515
533
|
* call while virtual desktop capability is unavailable. Actual permission errors remain
|
|
516
534
|
* permission errors; a missing target window is not a missing tool. Use list-tools only when
|
|
517
535
|
* discovery or refresh is needed, and do not cache or reuse execution results.
|
|
518
|
-
*
|
|
519
|
-
* object is at most 256 KiB. The complete result is at most
|
|
520
|
-
* with each encoded image at most 4 MiB; images are converted
|
|
521
|
-
* boundary, without recompression or persistence. Cancellation is
|
|
522
|
-
* disconnect or failed response does not prove that side effects did
|
|
523
|
-
* automatically replay. operation_id only correlates live activity, not
|
|
536
|
+
* The name selects exactly one tool: builtin tools are computer.*, MCP tools are
|
|
537
|
+
* `<server>__<tool>`. The arguments object is at most 256 KiB. The complete result is at most
|
|
538
|
+
* 8 MiB in the protobuf transport, with each encoded image at most 4 MiB; images are converted
|
|
539
|
+
* to base64 once at this JSON boundary, without recompression or persistence. Cancellation is
|
|
540
|
+
* propagated. A timeout, disconnect or failed response does not prove that side effects did
|
|
541
|
+
* not happen; do not automatically replay. operation_id only correlates live activity, not
|
|
542
|
+
* idempotency.
|
|
524
543
|
* @summary Call a live builtin or external MCP tool
|
|
525
544
|
*/
|
|
526
545
|
export const CallToolParams = zod.strictObject({
|
|
@@ -243,19 +243,13 @@
|
|
|
243
243
|
* OpenAPI spec version: 1.0.0
|
|
244
244
|
*/
|
|
245
245
|
import * as zod from "zod";
|
|
246
|
+
export declare const callToolRequestToolMax = 194;
|
|
246
247
|
export declare const callToolRequestReadOnlyDefault = false;
|
|
247
248
|
export declare const callToolRequestTimeoutSecondsDefault = 60;
|
|
248
249
|
export declare const callToolRequestTimeoutSecondsMax = 240;
|
|
249
250
|
export declare const CallToolRequest: zod.ZodObject<{
|
|
250
251
|
client_instance_id: zod.ZodUUID;
|
|
251
|
-
tool: zod.
|
|
252
|
-
source: zod.ZodEnum<{
|
|
253
|
-
builtin: "builtin";
|
|
254
|
-
mcp: "mcp";
|
|
255
|
-
}>;
|
|
256
|
-
name: zod.ZodString;
|
|
257
|
-
server: zod.ZodOptional<zod.ZodString>;
|
|
258
|
-
}, zod.z.core.$strict>;
|
|
252
|
+
tool: zod.ZodString;
|
|
259
253
|
arguments: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
|
|
260
254
|
read_only: zod.ZodDefault<zod.ZodBoolean>;
|
|
261
255
|
timeout_seconds: zod.ZodDefault<zod.ZodInt>;
|
|
@@ -243,13 +243,17 @@
|
|
|
243
243
|
* OpenAPI spec version: 1.0.0
|
|
244
244
|
*/
|
|
245
245
|
import * as zod from "zod";
|
|
246
|
-
|
|
246
|
+
export const callToolRequestToolMax = 194;
|
|
247
247
|
export const callToolRequestReadOnlyDefault = false;
|
|
248
248
|
export const callToolRequestTimeoutSecondsDefault = 60;
|
|
249
249
|
export const callToolRequestTimeoutSecondsMax = 240;
|
|
250
250
|
export const CallToolRequest = zod.strictObject({
|
|
251
251
|
client_instance_id: zod.uuid(),
|
|
252
|
-
tool:
|
|
252
|
+
tool: zod
|
|
253
|
+
.string()
|
|
254
|
+
.min(1)
|
|
255
|
+
.max(callToolRequestToolMax)
|
|
256
|
+
.describe("The name from list-tools. Builtin tools are computer.*; MCP tools are\n`<server>__<tool>`. The name selects the tool; source is not part of the call."),
|
|
253
257
|
arguments: zod
|
|
254
258
|
.record(zod.string(), zod.unknown())
|
|
255
259
|
.describe("A JSON object, at most 256 KiB when encoded"),
|
|
@@ -243,16 +243,13 @@
|
|
|
243
243
|
* OpenAPI spec version: 1.0.0
|
|
244
244
|
*/
|
|
245
245
|
import * as zod from "zod";
|
|
246
|
+
export declare const toolDescriptorNameMax = 194;
|
|
246
247
|
export declare const ToolDescriptor: zod.ZodObject<{
|
|
247
|
-
tool: zod.ZodObject<{
|
|
248
|
-
source: zod.ZodEnum<{
|
|
249
|
-
builtin: "builtin";
|
|
250
|
-
mcp: "mcp";
|
|
251
|
-
}>;
|
|
252
|
-
name: zod.ZodString;
|
|
253
|
-
server: zod.ZodOptional<zod.ZodString>;
|
|
254
|
-
}, zod.z.core.$strict>;
|
|
255
248
|
name: zod.ZodString;
|
|
249
|
+
source: zod.ZodEnum<{
|
|
250
|
+
builtin: "builtin";
|
|
251
|
+
mcp: "mcp";
|
|
252
|
+
}>;
|
|
256
253
|
title: zod.ZodString;
|
|
257
254
|
description: zod.ZodString;
|
|
258
255
|
input_schema: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
|
|
@@ -243,10 +243,16 @@
|
|
|
243
243
|
* OpenAPI spec version: 1.0.0
|
|
244
244
|
*/
|
|
245
245
|
import * as zod from "zod";
|
|
246
|
-
|
|
246
|
+
export const toolDescriptorNameMax = 194;
|
|
247
247
|
export const ToolDescriptor = zod.strictObject({
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
name: zod
|
|
249
|
+
.string()
|
|
250
|
+
.min(1)
|
|
251
|
+
.max(toolDescriptorNameMax)
|
|
252
|
+
.describe("The name to call it by. Builtin tools are named computer.*; MCP tools are named\n`<server>__<tool>`, so a name selects exactly one tool."),
|
|
253
|
+
source: zod
|
|
254
|
+
.enum(["builtin", "mcp"])
|
|
255
|
+
.describe("Whether the tool is builtin or comes from an MCP server. For filtering only."),
|
|
250
256
|
title: zod.string(),
|
|
251
257
|
description: zod.string(),
|
|
252
258
|
input_schema: zod.record(zod.string(), zod.unknown()),
|
|
@@ -246,15 +246,11 @@ import * as zod from "zod";
|
|
|
246
246
|
export declare const ToolList: zod.ZodObject<{
|
|
247
247
|
session_id: zod.ZodString;
|
|
248
248
|
items: zod.ZodArray<zod.ZodObject<{
|
|
249
|
-
tool: zod.ZodObject<{
|
|
250
|
-
source: zod.ZodEnum<{
|
|
251
|
-
builtin: "builtin";
|
|
252
|
-
mcp: "mcp";
|
|
253
|
-
}>;
|
|
254
|
-
name: zod.ZodString;
|
|
255
|
-
server: zod.ZodOptional<zod.ZodString>;
|
|
256
|
-
}, zod.z.core.$strict>;
|
|
257
249
|
name: zod.ZodString;
|
|
250
|
+
source: zod.ZodEnum<{
|
|
251
|
+
builtin: "builtin";
|
|
252
|
+
mcp: "mcp";
|
|
253
|
+
}>;
|
|
258
254
|
title: zod.ZodString;
|
|
259
255
|
description: zod.ZodString;
|
|
260
256
|
input_schema: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
|
package/package.json
CHANGED
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generated by orval 🍺
|
|
3
|
-
* Do not edit manually.
|
|
4
|
-
* Leaflow Fleet API
|
|
5
|
-
* Machines that run the Leaflow Fleet Agent (`leaflow-fleet-agent`): adding machines, the
|
|
6
|
-
* accounts and groups that log in to them, running commands, opening and closing sessions, with
|
|
7
|
-
* or without a desktop, and admitting participants to them.
|
|
8
|
-
*
|
|
9
|
-
* ## What this API sees
|
|
10
|
-
*
|
|
11
|
-
* This API coordinates. It admits participants to sessions and passes the signaling of their
|
|
12
|
-
* PeerConnections, but everything a session shows or receives — terminals, files, the screen,
|
|
13
|
-
* input, the clipboard, printing and privilege approvals on a participant — travels end to end
|
|
14
|
-
* between the participant and the session, encrypted with keys that never leave them. The
|
|
15
|
-
* platform sees which machine, which session and who is connected, and nothing of what happens
|
|
16
|
-
* inside.
|
|
17
|
-
*
|
|
18
|
-
* Commands and privilege requests decided on the platform are the exception: the platform passes
|
|
19
|
-
* a command and its output between the caller and the machine, and keeps the command line of a
|
|
20
|
-
* privilege request it asks the owner about; it sees both.
|
|
21
|
-
*
|
|
22
|
-
* ## Authentication
|
|
23
|
-
*
|
|
24
|
-
* Every request carries a scoped token; see the `bearerAuth` security scheme.
|
|
25
|
-
*
|
|
26
|
-
* **Neither the path nor the headers carry a `project_id`**: the current project is determined by
|
|
27
|
-
* the token.
|
|
28
|
-
*
|
|
29
|
-
* ## Adding a machine
|
|
30
|
-
*
|
|
31
|
-
* 1. Install the Agent and run `leaflow-fleet-agent daemon enroll` on the machine. The command
|
|
32
|
-
* carries no secret. The machine shows a pairing code such as `7K2QM-9XWTD`.
|
|
33
|
-
* 2. Find the request with `GET /api/v1/enrollments:find?pairing_code=…`. Compare its `hostname`
|
|
34
|
-
* and `source_address` with the machine in front of you: the pairing code is not a secret,
|
|
35
|
-
* and anyone can request enrollment.
|
|
36
|
-
* 3. Approve it with `POST /api/v1/enrollments/{enrollmentId}:approve`. The machine joins the
|
|
37
|
-
* current project within its next polling interval.
|
|
38
|
-
*
|
|
39
|
-
* ## Adding a machine without interaction
|
|
40
|
-
*
|
|
41
|
-
* A machine that is set up unattended, such as by cloud-init on first boot, joins with a
|
|
42
|
-
* registration token instead of a pairing code:
|
|
43
|
-
*
|
|
44
|
-
* 1. Create a registration with `POST /api/v1/machine-registrations`. It reserves a machine in
|
|
45
|
-
* the current project under the given name and returns its `machine_id` and a `token`. The
|
|
46
|
-
* token is returned only in this response.
|
|
47
|
-
* 2. Give the token to the machine in a file that only root can read, and run
|
|
48
|
-
* `leaflow-fleet-agent daemon enroll --url <control endpoint> --token-file <path>`. The
|
|
49
|
-
* machine joins the current project as `machine_id` at once, and the Agent deletes the file.
|
|
50
|
-
*
|
|
51
|
-
* A token enrolls one machine once, and only until the registration expires. Anyone who reads
|
|
52
|
-
* the token before the machine uses it can enroll a key of their own instead, so pass it only
|
|
53
|
-
* to the machine, keep its lifetime short, and compare the `public_key` of the used
|
|
54
|
-
* registration with the key the machine shows when that matters. Revoke a registration that
|
|
55
|
-
* will not be used with `DELETE /api/v1/machine-registrations/{registrationId}`.
|
|
56
|
-
*
|
|
57
|
-
* ## Trusting a machine's key
|
|
58
|
-
*
|
|
59
|
-
* Each machine has an Ed25519 key that it generates itself and that never leaves it. Participants
|
|
60
|
-
* verify that key end to end before they exchange any data with a session, so a client must
|
|
61
|
-
* decide which key belongs to a machine without relying on any party in between:
|
|
62
|
-
*
|
|
63
|
-
* - When approving an enrollment, recompute the pairing code from `public_key` and compare it
|
|
64
|
-
* with the code the machine shows. The code is derived as documented for
|
|
65
|
-
* `EnrollMachineResponse.pairing_code` in `leaflow/fleet/machine/v1/machine.proto`.
|
|
66
|
-
* Approve only when they match, and remember the key for the machine.
|
|
67
|
-
* - On any other client, remember the key the first time it connects to the machine, and
|
|
68
|
-
* refuse to continue whenever the machine later proves a different key. The fingerprint can
|
|
69
|
-
* be compared with the one the Agent prints on the machine.
|
|
70
|
-
*
|
|
71
|
-
* A machine that is reinstalled enrolls again as a new machine with a new key.
|
|
72
|
-
*
|
|
73
|
-
* ## Features
|
|
74
|
-
*
|
|
75
|
-
* A machine reports what it offers in `features`, each named after the protocol package that
|
|
76
|
-
* defines it:
|
|
77
|
-
*
|
|
78
|
-
* - `leaflow.fleet.directory.v1`: the accounts of the project's members and the project's groups
|
|
79
|
-
* exist on the machine; members log in over SSH with their keys and become root through sudo
|
|
80
|
-
* as their permissions allow;
|
|
81
|
-
* - `leaflow.fleet.command.v1`: running commands;
|
|
82
|
-
* - `leaflow.fleet.mcp.v1`: the MCP servers each account configures on the machine, local ones
|
|
83
|
-
* and remote ones it connects to;
|
|
84
|
-
* - `leaflow.fleet.host.v1`: terminal sessions, with programs, files, ports, sound, devices,
|
|
85
|
-
* printers and privilege approvals;
|
|
86
|
-
* - `leaflow.fleet.virtualdesktop.host.v1`: sessions with a graphical backend;
|
|
87
|
-
* - `leaflow.fleet.tool.v1`: live session tools. Builtin `computer.*` tools are exposed only while
|
|
88
|
-
* the virtual desktop capability is actually available; MCP is a separate source.
|
|
89
|
-
*
|
|
90
|
-
* A graphical backend does not require a full desktop environment. Terminal logins, commands
|
|
91
|
-
* and MCP server initialization prepare or reuse the account's lightweight graphical context,
|
|
92
|
-
* in addition to their own session or job. Configuration reads and writes do not initialize a
|
|
93
|
-
* server and do not require this preparation. A request that needs a feature the machine does
|
|
94
|
-
* not report available fails with `FEATURE_UNAVAILABLE`, whose `metadata.feature` names it.
|
|
95
|
-
*
|
|
96
|
-
* ## Directory
|
|
97
|
-
*
|
|
98
|
-
* Every user has one account, as with Google Cloud OS Login: a username and a uid that are the
|
|
99
|
-
* same on every machine of every project. The account is created the first time the user may log
|
|
100
|
-
* in to a machine or opens a session; its username comes from the email address, such as
|
|
101
|
-
* `alice_example_com` for `alice@example.com`, and its owner can change it. A project's machines
|
|
102
|
-
* know the accounts of the project's members and the groups the project defines. A member who
|
|
103
|
-
* leaves the project can no longer log in, and files keep their owner.
|
|
104
|
-
*
|
|
105
|
-
* Who may log in to which machines, and who may become root there through sudo, are permissions
|
|
106
|
-
* of the project's roles: `fleet:machines.login` and `fleet:machines.admin`, each for all
|
|
107
|
-
* machines or for chosen ones. Changes reach the machines within about a minute, and every login
|
|
108
|
-
* and elevation is checked against the current permissions while the machine is connected. To
|
|
109
|
-
* keep a member out of some machines, deny them `fleet:machines.login` on those machines.
|
|
110
|
-
* Elevation through sudo is never approved by a password; see "Approving sudo".
|
|
111
|
-
*
|
|
112
|
-
* Members log in over SSH with the SSH keys of their own accounts (`/account/v1/me/ssh-keys` on
|
|
113
|
-
* the account API), while they may log in to the machine.
|
|
114
|
-
*
|
|
115
|
-
* Machines resolve directory accounts and groups themselves and never write them into their local
|
|
116
|
-
* account files. A local account or group that already uses a name or id of the directory keeps
|
|
117
|
-
* it, and the machine records the conflict among its events.
|
|
118
|
-
*
|
|
119
|
-
* ## Running commands
|
|
120
|
-
*
|
|
121
|
-
* `POST /api/v1/machines/{machineId}:runCommand` runs one command line on the machine as the
|
|
122
|
-
* caller's account, as `ssh machine 'command'` would, but without SSH: the machine needs no open
|
|
123
|
-
* port, no distributed key and no address the caller can reach. Like logging in, it requires
|
|
124
|
-
* `fleet:machines.login` on the machine. Inside the command, `sudo` works without a prompt for
|
|
125
|
-
* a caller with `fleet:machines.admin` on the machine: the request approves the elevation.
|
|
126
|
-
*
|
|
127
|
-
* ## MCP servers
|
|
128
|
-
*
|
|
129
|
-
* A machine that offers `leaflow.fleet.mcp.v1` reaches the MCP servers its accounts configure:
|
|
130
|
-
* servers it runs itself and remote servers it connects to. Each account configures them in
|
|
131
|
-
* `~/.local/share/leaflow/agent/mcp.json` in its home directory, in the `mcpServers` format other
|
|
132
|
-
* MCP clients use, by hand or through this API; the machine picks up every change by itself.
|
|
133
|
-
* The caller's servers run as the caller's account, and the requests below act on them only.
|
|
134
|
-
*
|
|
135
|
-
* The configuration stays on the machine. The values of `env` and `headers` often hold
|
|
136
|
-
* credentials: this API writes them, and they then pass through the platform, but never returns
|
|
137
|
-
* them. Arguments, URLs, tool arguments and tool results pass through the platform as they are.
|
|
138
|
-
*
|
|
139
|
-
* ## Approving sudo
|
|
140
|
-
*
|
|
141
|
-
* An account may become root through sudo on a machine while its user has
|
|
142
|
-
* `fleet:machines.admin` there. Each elevation is approved, in the first of these ways that
|
|
143
|
-
* applies:
|
|
144
|
-
*
|
|
145
|
-
* - inside a command run through this API, by the request itself;
|
|
146
|
-
* - by the user's automatic approval for the machine, for a while or until removed
|
|
147
|
-
* (`PUT /api/v1/machines/{machineId}/privilege-auto-approval`), in one of two modes:
|
|
148
|
-
* - `automatic_review`, the recommended one: a large language model reviews each request and
|
|
149
|
-
* approves or denies it with a reason. It stops most dangerous requests, but not all of
|
|
150
|
-
* them. Each review is a request to Canopy, the model platform, through the project's
|
|
151
|
-
* Canopy service, and may incur Canopy charges; the project needs Canopy enabled. A
|
|
152
|
-
* request that cannot be reviewed, such as when the project has not enabled Canopy or the
|
|
153
|
-
* review does not complete in time, is denied with a reason saying so;
|
|
154
|
-
* - `always_approve`: every request is approved at once. This is dangerous: any program that
|
|
155
|
-
* runs as the account, such as a script or an AI agent, becomes root without anyone being
|
|
156
|
-
* asked;
|
|
157
|
-
* - by the user, on any of their devices, for a request listed by `GET /api/v1/privilege-requests`
|
|
158
|
-
* (`POST …:approve` or `…:deny`), or on a participant of the session the asking process belongs
|
|
159
|
-
* to. A request nobody decides expires, and sudo fails.
|
|
160
|
-
*
|
|
161
|
-
* A denied sudo shows whoever ran it the reason, when the denial gave one.
|
|
162
|
-
*
|
|
163
|
-
* Requests reach the user's devices as they happen through EventBus: the event
|
|
164
|
-
* `leaflow.fleet.privilege.requested` when one waits for the user and
|
|
165
|
-
* `leaflow.fleet.privilege.decided` when it ends, each addressed to the user in the current
|
|
166
|
-
* project and carrying the request's `id`. Requests decided without asking the user raise
|
|
167
|
-
* neither. A client that subscribes to them needs no polling; one that does not can list the
|
|
168
|
-
* pending requests.
|
|
169
|
-
*
|
|
170
|
-
* ## Connections that drop
|
|
171
|
-
*
|
|
172
|
-
* A machine's Agent and a session's process each keep a connection to the service, and on a poor
|
|
173
|
-
* network it may drop and come back within seconds. Requests do not fail for that:
|
|
174
|
-
*
|
|
175
|
-
* - A request that needs the machine or the session's process waits while it connects again,
|
|
176
|
-
* for as long as the request would wait for its answer, and fails with `MACHINE_OFFLINE` or
|
|
177
|
-
* `SESSION_UNAVAILABLE` only when it does not come back in that time.
|
|
178
|
-
* - What the machine or the session's process received before its connection dropped, such as a
|
|
179
|
-
* command or a session being opened, goes on, and its result is returned once it has
|
|
180
|
-
* connected again within that time.
|
|
181
|
-
*
|
|
182
|
-
* A machine stays `online` for up to a minute after its connection was lost, while its Agent
|
|
183
|
-
* connects again; a machine whose Agent stops is offline at once.
|
|
184
|
-
*
|
|
185
|
-
* ## Operations that do not exist
|
|
186
|
-
*
|
|
187
|
-
* Some resources lack an operation on purpose:
|
|
188
|
-
*
|
|
189
|
-
* - Accounts are created when they are first needed and are never deleted, so that files keep
|
|
190
|
-
* their owner.
|
|
191
|
-
* - Enrollment requests are made only by machines.
|
|
192
|
-
* - A machine registration cannot be changed; revoke it and create another.
|
|
193
|
-
* - Machine events are a log: they are listed, never changed, and kept for 30 days.
|
|
194
|
-
* - A privilege request is decided only by the user whose account asks, or on a participant of
|
|
195
|
-
* the session it comes from.
|
|
196
|
-
*
|
|
197
|
-
* ## Joining a session
|
|
198
|
-
*
|
|
199
|
-
* 1. Have an Ed25519 key, for as long as the client wants: one per participant or one kept by
|
|
200
|
-
* the client. The private key must never leave the client; in a browser, use a
|
|
201
|
-
* non-extractable WebCrypto key.
|
|
202
|
-
* 2. Get the ICE servers with `GET /api/v1/sessions/{sessionId}/rtc-configuration`, create a
|
|
203
|
-
* PeerConnection with them and its data channels (`leaflow/fleet/transport/v1/transport.proto`)
|
|
204
|
-
* and make an offer. Wait briefly for ICE candidates, such as until gathering completes or
|
|
205
|
-
* one second has passed, so that the offer carries them.
|
|
206
|
-
* 3. Join with `POST /api/v1/sessions/{sessionId}/participants`, sending the public key and the
|
|
207
|
-
* offer. The answer carries the participant's signed authorization, the keys the service
|
|
208
|
-
* signs with, and the first PeerConnection: the session's SDP answer, the ICE candidates it
|
|
209
|
-
* has passed so far and the signed PeerAuthorization. Pass candidates gathered later with
|
|
210
|
-
* `POST …/participants/{participantId}/peer-connections/{peerConnectionId}/candidates`, and
|
|
211
|
-
* read the session's later ones with
|
|
212
|
-
* `GET …/participants/{participantId}/peer-connections/{peerConnectionId}` until
|
|
213
|
-
* `candidates_complete`.
|
|
214
|
-
* 4. Renew the participant with `POST …/participants/{participantId}:renew` well before
|
|
215
|
-
* `lease_expires_at`, every 15 seconds, presenting the PeerAuthorization of each
|
|
216
|
-
* PeerConnection; the answer renews them. A participant whose lease runs out ends, and its
|
|
217
|
-
* PeerConnections stop within 30 seconds of their last lease.
|
|
218
|
-
* 5. When a path fails, start another PeerConnection with
|
|
219
|
-
* `POST …/participants/{participantId}/peer-connections` and move the connection to it with
|
|
220
|
-
* `:prepareMigration` and `:commitMigration`. Abandon a PeerConnection that does not
|
|
221
|
-
* connect with `DELETE …/peer-connections/{peerConnectionId}`.
|
|
222
|
-
* 6. Leave with `DELETE …/participants/{participantId}`.
|
|
223
|
-
*
|
|
224
|
-
* Signaling travels only through these requests; a participant holds no other connection to
|
|
225
|
-
* the service.
|
|
226
|
-
*
|
|
227
|
-
* What a participant may do in a session is decided when it is created, from the caller's
|
|
228
|
-
* permissions and what the request asks for, and does not change afterwards. Participants are not
|
|
229
|
-
* told apart by kind: a person in a browser and a program that operates the session are both
|
|
230
|
-
* participants, named by the `client_name` they choose, and either can be disconnected.
|
|
231
|
-
*
|
|
232
|
-
* Every participant that ends, including through `DELETE`, is announced through EventBus as
|
|
233
|
-
* `leaflow.fleet.participant.ended`, addressed to its user in the current project, with its
|
|
234
|
-
* `session_id`, `participant_id` (a decimal string) and `reason`: `left` when its user ended it,
|
|
235
|
-
* `removed` when someone else did, `lease_expired` when it was not renewed in time,
|
|
236
|
-
* `session_ended` when its session ended, `session_process_lost` when the session's process did
|
|
237
|
-
* not come back in time, `permission_revoked` when a permission it was created with was revoked
|
|
238
|
-
* from its user, `membership_ended` when its user is no longer a member of the project,
|
|
239
|
-
* `user_inactive` when its user's account was suspended or banned or its deletion was requested,
|
|
240
|
-
* `project_deletion_requested` when deletion of the project was requested, `machine_removed` when
|
|
241
|
-
* its machine was removed, or `key_revoked` when the key that signed its authorization was
|
|
242
|
-
* revoked. A participant whose creation failed is not announced.
|
|
243
|
-
* OpenAPI spec version: 1.0.0
|
|
244
|
-
*/
|
|
245
|
-
import * as zod from "zod";
|
|
246
|
-
export declare const toolRefNameMax = 128;
|
|
247
|
-
export declare const toolRefServerMax = 64;
|
|
248
|
-
export declare const ToolRef: zod.ZodObject<{
|
|
249
|
-
source: zod.ZodEnum<{
|
|
250
|
-
builtin: "builtin";
|
|
251
|
-
mcp: "mcp";
|
|
252
|
-
}>;
|
|
253
|
-
name: zod.ZodString;
|
|
254
|
-
server: zod.ZodOptional<zod.ZodString>;
|
|
255
|
-
}, zod.z.core.$strict>;
|
|
256
|
-
export type ToolRef = zod.input<typeof ToolRef>;
|
|
257
|
-
export type ToolRefOutput = zod.output<typeof ToolRef>;
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generated by orval 🍺
|
|
3
|
-
* Do not edit manually.
|
|
4
|
-
* Leaflow Fleet API
|
|
5
|
-
* Machines that run the Leaflow Fleet Agent (`leaflow-fleet-agent`): adding machines, the
|
|
6
|
-
* accounts and groups that log in to them, running commands, opening and closing sessions, with
|
|
7
|
-
* or without a desktop, and admitting participants to them.
|
|
8
|
-
*
|
|
9
|
-
* ## What this API sees
|
|
10
|
-
*
|
|
11
|
-
* This API coordinates. It admits participants to sessions and passes the signaling of their
|
|
12
|
-
* PeerConnections, but everything a session shows or receives — terminals, files, the screen,
|
|
13
|
-
* input, the clipboard, printing and privilege approvals on a participant — travels end to end
|
|
14
|
-
* between the participant and the session, encrypted with keys that never leave them. The
|
|
15
|
-
* platform sees which machine, which session and who is connected, and nothing of what happens
|
|
16
|
-
* inside.
|
|
17
|
-
*
|
|
18
|
-
* Commands and privilege requests decided on the platform are the exception: the platform passes
|
|
19
|
-
* a command and its output between the caller and the machine, and keeps the command line of a
|
|
20
|
-
* privilege request it asks the owner about; it sees both.
|
|
21
|
-
*
|
|
22
|
-
* ## Authentication
|
|
23
|
-
*
|
|
24
|
-
* Every request carries a scoped token; see the `bearerAuth` security scheme.
|
|
25
|
-
*
|
|
26
|
-
* **Neither the path nor the headers carry a `project_id`**: the current project is determined by
|
|
27
|
-
* the token.
|
|
28
|
-
*
|
|
29
|
-
* ## Adding a machine
|
|
30
|
-
*
|
|
31
|
-
* 1. Install the Agent and run `leaflow-fleet-agent daemon enroll` on the machine. The command
|
|
32
|
-
* carries no secret. The machine shows a pairing code such as `7K2QM-9XWTD`.
|
|
33
|
-
* 2. Find the request with `GET /api/v1/enrollments:find?pairing_code=…`. Compare its `hostname`
|
|
34
|
-
* and `source_address` with the machine in front of you: the pairing code is not a secret,
|
|
35
|
-
* and anyone can request enrollment.
|
|
36
|
-
* 3. Approve it with `POST /api/v1/enrollments/{enrollmentId}:approve`. The machine joins the
|
|
37
|
-
* current project within its next polling interval.
|
|
38
|
-
*
|
|
39
|
-
* ## Adding a machine without interaction
|
|
40
|
-
*
|
|
41
|
-
* A machine that is set up unattended, such as by cloud-init on first boot, joins with a
|
|
42
|
-
* registration token instead of a pairing code:
|
|
43
|
-
*
|
|
44
|
-
* 1. Create a registration with `POST /api/v1/machine-registrations`. It reserves a machine in
|
|
45
|
-
* the current project under the given name and returns its `machine_id` and a `token`. The
|
|
46
|
-
* token is returned only in this response.
|
|
47
|
-
* 2. Give the token to the machine in a file that only root can read, and run
|
|
48
|
-
* `leaflow-fleet-agent daemon enroll --url <control endpoint> --token-file <path>`. The
|
|
49
|
-
* machine joins the current project as `machine_id` at once, and the Agent deletes the file.
|
|
50
|
-
*
|
|
51
|
-
* A token enrolls one machine once, and only until the registration expires. Anyone who reads
|
|
52
|
-
* the token before the machine uses it can enroll a key of their own instead, so pass it only
|
|
53
|
-
* to the machine, keep its lifetime short, and compare the `public_key` of the used
|
|
54
|
-
* registration with the key the machine shows when that matters. Revoke a registration that
|
|
55
|
-
* will not be used with `DELETE /api/v1/machine-registrations/{registrationId}`.
|
|
56
|
-
*
|
|
57
|
-
* ## Trusting a machine's key
|
|
58
|
-
*
|
|
59
|
-
* Each machine has an Ed25519 key that it generates itself and that never leaves it. Participants
|
|
60
|
-
* verify that key end to end before they exchange any data with a session, so a client must
|
|
61
|
-
* decide which key belongs to a machine without relying on any party in between:
|
|
62
|
-
*
|
|
63
|
-
* - When approving an enrollment, recompute the pairing code from `public_key` and compare it
|
|
64
|
-
* with the code the machine shows. The code is derived as documented for
|
|
65
|
-
* `EnrollMachineResponse.pairing_code` in `leaflow/fleet/machine/v1/machine.proto`.
|
|
66
|
-
* Approve only when they match, and remember the key for the machine.
|
|
67
|
-
* - On any other client, remember the key the first time it connects to the machine, and
|
|
68
|
-
* refuse to continue whenever the machine later proves a different key. The fingerprint can
|
|
69
|
-
* be compared with the one the Agent prints on the machine.
|
|
70
|
-
*
|
|
71
|
-
* A machine that is reinstalled enrolls again as a new machine with a new key.
|
|
72
|
-
*
|
|
73
|
-
* ## Features
|
|
74
|
-
*
|
|
75
|
-
* A machine reports what it offers in `features`, each named after the protocol package that
|
|
76
|
-
* defines it:
|
|
77
|
-
*
|
|
78
|
-
* - `leaflow.fleet.directory.v1`: the accounts of the project's members and the project's groups
|
|
79
|
-
* exist on the machine; members log in over SSH with their keys and become root through sudo
|
|
80
|
-
* as their permissions allow;
|
|
81
|
-
* - `leaflow.fleet.command.v1`: running commands;
|
|
82
|
-
* - `leaflow.fleet.mcp.v1`: the MCP servers each account configures on the machine, local ones
|
|
83
|
-
* and remote ones it connects to;
|
|
84
|
-
* - `leaflow.fleet.host.v1`: terminal sessions, with programs, files, ports, sound, devices,
|
|
85
|
-
* printers and privilege approvals;
|
|
86
|
-
* - `leaflow.fleet.virtualdesktop.host.v1`: sessions with a graphical backend;
|
|
87
|
-
* - `leaflow.fleet.tool.v1`: live session tools. Builtin `computer.*` tools are exposed only while
|
|
88
|
-
* the virtual desktop capability is actually available; MCP is a separate source.
|
|
89
|
-
*
|
|
90
|
-
* A graphical backend does not require a full desktop environment. Terminal logins, commands
|
|
91
|
-
* and MCP server initialization prepare or reuse the account's lightweight graphical context,
|
|
92
|
-
* in addition to their own session or job. Configuration reads and writes do not initialize a
|
|
93
|
-
* server and do not require this preparation. A request that needs a feature the machine does
|
|
94
|
-
* not report available fails with `FEATURE_UNAVAILABLE`, whose `metadata.feature` names it.
|
|
95
|
-
*
|
|
96
|
-
* ## Directory
|
|
97
|
-
*
|
|
98
|
-
* Every user has one account, as with Google Cloud OS Login: a username and a uid that are the
|
|
99
|
-
* same on every machine of every project. The account is created the first time the user may log
|
|
100
|
-
* in to a machine or opens a session; its username comes from the email address, such as
|
|
101
|
-
* `alice_example_com` for `alice@example.com`, and its owner can change it. A project's machines
|
|
102
|
-
* know the accounts of the project's members and the groups the project defines. A member who
|
|
103
|
-
* leaves the project can no longer log in, and files keep their owner.
|
|
104
|
-
*
|
|
105
|
-
* Who may log in to which machines, and who may become root there through sudo, are permissions
|
|
106
|
-
* of the project's roles: `fleet:machines.login` and `fleet:machines.admin`, each for all
|
|
107
|
-
* machines or for chosen ones. Changes reach the machines within about a minute, and every login
|
|
108
|
-
* and elevation is checked against the current permissions while the machine is connected. To
|
|
109
|
-
* keep a member out of some machines, deny them `fleet:machines.login` on those machines.
|
|
110
|
-
* Elevation through sudo is never approved by a password; see "Approving sudo".
|
|
111
|
-
*
|
|
112
|
-
* Members log in over SSH with the SSH keys of their own accounts (`/account/v1/me/ssh-keys` on
|
|
113
|
-
* the account API), while they may log in to the machine.
|
|
114
|
-
*
|
|
115
|
-
* Machines resolve directory accounts and groups themselves and never write them into their local
|
|
116
|
-
* account files. A local account or group that already uses a name or id of the directory keeps
|
|
117
|
-
* it, and the machine records the conflict among its events.
|
|
118
|
-
*
|
|
119
|
-
* ## Running commands
|
|
120
|
-
*
|
|
121
|
-
* `POST /api/v1/machines/{machineId}:runCommand` runs one command line on the machine as the
|
|
122
|
-
* caller's account, as `ssh machine 'command'` would, but without SSH: the machine needs no open
|
|
123
|
-
* port, no distributed key and no address the caller can reach. Like logging in, it requires
|
|
124
|
-
* `fleet:machines.login` on the machine. Inside the command, `sudo` works without a prompt for
|
|
125
|
-
* a caller with `fleet:machines.admin` on the machine: the request approves the elevation.
|
|
126
|
-
*
|
|
127
|
-
* ## MCP servers
|
|
128
|
-
*
|
|
129
|
-
* A machine that offers `leaflow.fleet.mcp.v1` reaches the MCP servers its accounts configure:
|
|
130
|
-
* servers it runs itself and remote servers it connects to. Each account configures them in
|
|
131
|
-
* `~/.local/share/leaflow/agent/mcp.json` in its home directory, in the `mcpServers` format other
|
|
132
|
-
* MCP clients use, by hand or through this API; the machine picks up every change by itself.
|
|
133
|
-
* The caller's servers run as the caller's account, and the requests below act on them only.
|
|
134
|
-
*
|
|
135
|
-
* The configuration stays on the machine. The values of `env` and `headers` often hold
|
|
136
|
-
* credentials: this API writes them, and they then pass through the platform, but never returns
|
|
137
|
-
* them. Arguments, URLs, tool arguments and tool results pass through the platform as they are.
|
|
138
|
-
*
|
|
139
|
-
* ## Approving sudo
|
|
140
|
-
*
|
|
141
|
-
* An account may become root through sudo on a machine while its user has
|
|
142
|
-
* `fleet:machines.admin` there. Each elevation is approved, in the first of these ways that
|
|
143
|
-
* applies:
|
|
144
|
-
*
|
|
145
|
-
* - inside a command run through this API, by the request itself;
|
|
146
|
-
* - by the user's automatic approval for the machine, for a while or until removed
|
|
147
|
-
* (`PUT /api/v1/machines/{machineId}/privilege-auto-approval`), in one of two modes:
|
|
148
|
-
* - `automatic_review`, the recommended one: a large language model reviews each request and
|
|
149
|
-
* approves or denies it with a reason. It stops most dangerous requests, but not all of
|
|
150
|
-
* them. Each review is a request to Canopy, the model platform, through the project's
|
|
151
|
-
* Canopy service, and may incur Canopy charges; the project needs Canopy enabled. A
|
|
152
|
-
* request that cannot be reviewed, such as when the project has not enabled Canopy or the
|
|
153
|
-
* review does not complete in time, is denied with a reason saying so;
|
|
154
|
-
* - `always_approve`: every request is approved at once. This is dangerous: any program that
|
|
155
|
-
* runs as the account, such as a script or an AI agent, becomes root without anyone being
|
|
156
|
-
* asked;
|
|
157
|
-
* - by the user, on any of their devices, for a request listed by `GET /api/v1/privilege-requests`
|
|
158
|
-
* (`POST …:approve` or `…:deny`), or on a participant of the session the asking process belongs
|
|
159
|
-
* to. A request nobody decides expires, and sudo fails.
|
|
160
|
-
*
|
|
161
|
-
* A denied sudo shows whoever ran it the reason, when the denial gave one.
|
|
162
|
-
*
|
|
163
|
-
* Requests reach the user's devices as they happen through EventBus: the event
|
|
164
|
-
* `leaflow.fleet.privilege.requested` when one waits for the user and
|
|
165
|
-
* `leaflow.fleet.privilege.decided` when it ends, each addressed to the user in the current
|
|
166
|
-
* project and carrying the request's `id`. Requests decided without asking the user raise
|
|
167
|
-
* neither. A client that subscribes to them needs no polling; one that does not can list the
|
|
168
|
-
* pending requests.
|
|
169
|
-
*
|
|
170
|
-
* ## Connections that drop
|
|
171
|
-
*
|
|
172
|
-
* A machine's Agent and a session's process each keep a connection to the service, and on a poor
|
|
173
|
-
* network it may drop and come back within seconds. Requests do not fail for that:
|
|
174
|
-
*
|
|
175
|
-
* - A request that needs the machine or the session's process waits while it connects again,
|
|
176
|
-
* for as long as the request would wait for its answer, and fails with `MACHINE_OFFLINE` or
|
|
177
|
-
* `SESSION_UNAVAILABLE` only when it does not come back in that time.
|
|
178
|
-
* - What the machine or the session's process received before its connection dropped, such as a
|
|
179
|
-
* command or a session being opened, goes on, and its result is returned once it has
|
|
180
|
-
* connected again within that time.
|
|
181
|
-
*
|
|
182
|
-
* A machine stays `online` for up to a minute after its connection was lost, while its Agent
|
|
183
|
-
* connects again; a machine whose Agent stops is offline at once.
|
|
184
|
-
*
|
|
185
|
-
* ## Operations that do not exist
|
|
186
|
-
*
|
|
187
|
-
* Some resources lack an operation on purpose:
|
|
188
|
-
*
|
|
189
|
-
* - Accounts are created when they are first needed and are never deleted, so that files keep
|
|
190
|
-
* their owner.
|
|
191
|
-
* - Enrollment requests are made only by machines.
|
|
192
|
-
* - A machine registration cannot be changed; revoke it and create another.
|
|
193
|
-
* - Machine events are a log: they are listed, never changed, and kept for 30 days.
|
|
194
|
-
* - A privilege request is decided only by the user whose account asks, or on a participant of
|
|
195
|
-
* the session it comes from.
|
|
196
|
-
*
|
|
197
|
-
* ## Joining a session
|
|
198
|
-
*
|
|
199
|
-
* 1. Have an Ed25519 key, for as long as the client wants: one per participant or one kept by
|
|
200
|
-
* the client. The private key must never leave the client; in a browser, use a
|
|
201
|
-
* non-extractable WebCrypto key.
|
|
202
|
-
* 2. Get the ICE servers with `GET /api/v1/sessions/{sessionId}/rtc-configuration`, create a
|
|
203
|
-
* PeerConnection with them and its data channels (`leaflow/fleet/transport/v1/transport.proto`)
|
|
204
|
-
* and make an offer. Wait briefly for ICE candidates, such as until gathering completes or
|
|
205
|
-
* one second has passed, so that the offer carries them.
|
|
206
|
-
* 3. Join with `POST /api/v1/sessions/{sessionId}/participants`, sending the public key and the
|
|
207
|
-
* offer. The answer carries the participant's signed authorization, the keys the service
|
|
208
|
-
* signs with, and the first PeerConnection: the session's SDP answer, the ICE candidates it
|
|
209
|
-
* has passed so far and the signed PeerAuthorization. Pass candidates gathered later with
|
|
210
|
-
* `POST …/participants/{participantId}/peer-connections/{peerConnectionId}/candidates`, and
|
|
211
|
-
* read the session's later ones with
|
|
212
|
-
* `GET …/participants/{participantId}/peer-connections/{peerConnectionId}` until
|
|
213
|
-
* `candidates_complete`.
|
|
214
|
-
* 4. Renew the participant with `POST …/participants/{participantId}:renew` well before
|
|
215
|
-
* `lease_expires_at`, every 15 seconds, presenting the PeerAuthorization of each
|
|
216
|
-
* PeerConnection; the answer renews them. A participant whose lease runs out ends, and its
|
|
217
|
-
* PeerConnections stop within 30 seconds of their last lease.
|
|
218
|
-
* 5. When a path fails, start another PeerConnection with
|
|
219
|
-
* `POST …/participants/{participantId}/peer-connections` and move the connection to it with
|
|
220
|
-
* `:prepareMigration` and `:commitMigration`. Abandon a PeerConnection that does not
|
|
221
|
-
* connect with `DELETE …/peer-connections/{peerConnectionId}`.
|
|
222
|
-
* 6. Leave with `DELETE …/participants/{participantId}`.
|
|
223
|
-
*
|
|
224
|
-
* Signaling travels only through these requests; a participant holds no other connection to
|
|
225
|
-
* the service.
|
|
226
|
-
*
|
|
227
|
-
* What a participant may do in a session is decided when it is created, from the caller's
|
|
228
|
-
* permissions and what the request asks for, and does not change afterwards. Participants are not
|
|
229
|
-
* told apart by kind: a person in a browser and a program that operates the session are both
|
|
230
|
-
* participants, named by the `client_name` they choose, and either can be disconnected.
|
|
231
|
-
*
|
|
232
|
-
* Every participant that ends, including through `DELETE`, is announced through EventBus as
|
|
233
|
-
* `leaflow.fleet.participant.ended`, addressed to its user in the current project, with its
|
|
234
|
-
* `session_id`, `participant_id` (a decimal string) and `reason`: `left` when its user ended it,
|
|
235
|
-
* `removed` when someone else did, `lease_expired` when it was not renewed in time,
|
|
236
|
-
* `session_ended` when its session ended, `session_process_lost` when the session's process did
|
|
237
|
-
* not come back in time, `permission_revoked` when a permission it was created with was revoked
|
|
238
|
-
* from its user, `membership_ended` when its user is no longer a member of the project,
|
|
239
|
-
* `user_inactive` when its user's account was suspended or banned or its deletion was requested,
|
|
240
|
-
* `project_deletion_requested` when deletion of the project was requested, `machine_removed` when
|
|
241
|
-
* its machine was removed, or `key_revoked` when the key that signed its authorization was
|
|
242
|
-
* revoked. A participant whose creation failed is not announced.
|
|
243
|
-
* OpenAPI spec version: 1.0.0
|
|
244
|
-
*/
|
|
245
|
-
import * as zod from "zod";
|
|
246
|
-
export const toolRefNameMax = 128;
|
|
247
|
-
export const toolRefServerMax = 64;
|
|
248
|
-
export const ToolRef = zod.strictObject({
|
|
249
|
-
source: zod.enum(["builtin", "mcp"]),
|
|
250
|
-
name: zod.string().min(1).max(toolRefNameMax),
|
|
251
|
-
server: zod
|
|
252
|
-
.string()
|
|
253
|
-
.min(1)
|
|
254
|
-
.max(toolRefServerMax)
|
|
255
|
-
.optional()
|
|
256
|
-
.describe("Required only for mcp; forbidden for builtin"),
|
|
257
|
-
});
|