edgegate-mcp 0.4.1 → 0.8.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/README.md +27 -3
- package/dist/client.d.ts +43 -1
- package/dist/client.js +83 -0
- package/dist/client.js.map +1 -1
- package/dist/server.js +178 -0
- package/dist/server.js.map +1 -1
- package/dist/tools/change_member_role.d.ts +18 -0
- package/dist/tools/change_member_role.js +61 -0
- package/dist/tools/change_member_role.js.map +1 -0
- package/dist/tools/check_byo_bucket.d.ts +12 -0
- package/dist/tools/check_byo_bucket.js +89 -0
- package/dist/tools/check_byo_bucket.js.map +1 -0
- package/dist/tools/check_status.d.ts +2 -2
- package/dist/tools/compare_runs.d.ts +2 -2
- package/dist/tools/connect_huggingface.d.ts +15 -0
- package/dist/tools/connect_huggingface.js +83 -0
- package/dist/tools/connect_huggingface.js.map +1 -0
- package/dist/tools/connect_qaihub.d.ts +15 -0
- package/dist/tools/connect_qaihub.js +62 -0
- package/dist/tools/connect_qaihub.js.map +1 -0
- package/dist/tools/create_api_key.d.ts +18 -0
- package/dist/tools/create_api_key.js +73 -0
- package/dist/tools/create_api_key.js.map +1 -0
- package/dist/tools/create_pipeline.d.ts +34 -4
- package/dist/tools/create_pipeline.js +31 -0
- package/dist/tools/create_pipeline.js.map +1 -1
- package/dist/tools/create_workspace.d.ts +12 -0
- package/dist/tools/create_workspace.js +51 -0
- package/dist/tools/create_workspace.js.map +1 -0
- package/dist/tools/disconnect_byo_bucket.d.ts +12 -0
- package/dist/tools/disconnect_byo_bucket.js +90 -0
- package/dist/tools/disconnect_byo_bucket.js.map +1 -0
- package/dist/tools/disconnect_huggingface.d.ts +12 -0
- package/dist/tools/disconnect_huggingface.js +44 -0
- package/dist/tools/disconnect_huggingface.js.map +1 -0
- package/dist/tools/disconnect_qaihub.d.ts +12 -0
- package/dist/tools/disconnect_qaihub.js +42 -0
- package/dist/tools/disconnect_qaihub.js.map +1 -0
- package/dist/tools/export_run_report.d.ts +2 -2
- package/dist/tools/get_audit_report.d.ts +2 -2
- package/dist/tools/get_byo_audit.d.ts +27 -0
- package/dist/tools/get_byo_audit.js +125 -0
- package/dist/tools/get_byo_audit.js.map +1 -0
- package/dist/tools/get_huggingface_integration.d.ts +12 -0
- package/dist/tools/get_huggingface_integration.js +52 -0
- package/dist/tools/get_huggingface_integration.js.map +1 -0
- package/dist/tools/get_qaihub_integration.d.ts +12 -0
- package/dist/tools/get_qaihub_integration.js +52 -0
- package/dist/tools/get_qaihub_integration.js.map +1 -0
- package/dist/tools/get_report.d.ts +1 -1
- package/dist/tools/invite_member.d.ts +18 -0
- package/dist/tools/invite_member.js +85 -0
- package/dist/tools/invite_member.js.map +1 -0
- package/dist/tools/list_api_keys.d.ts +12 -0
- package/dist/tools/list_api_keys.js +51 -0
- package/dist/tools/list_api_keys.js.map +1 -0
- package/dist/tools/list_members.d.ts +12 -0
- package/dist/tools/list_members.js +43 -0
- package/dist/tools/list_members.js.map +1 -0
- package/dist/tools/register_byo_artifact.d.ts +27 -0
- package/dist/tools/register_byo_artifact.js +122 -0
- package/dist/tools/register_byo_artifact.js.map +1 -0
- package/dist/tools/register_byo_bucket.d.ts +24 -0
- package/dist/tools/register_byo_bucket.js +143 -0
- package/dist/tools/register_byo_bucket.js.map +1 -0
- package/dist/tools/remove_member.d.ts +15 -0
- package/dist/tools/remove_member.js +64 -0
- package/dist/tools/remove_member.js.map +1 -0
- package/dist/tools/revoke_api_key.d.ts +15 -0
- package/dist/tools/revoke_api_key.js +49 -0
- package/dist/tools/revoke_api_key.js.map +1 -0
- package/dist/types.d.ts +169 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/plugin.json +7 -2
- package/skills/edgegate-byo-storage.md +148 -0
- package/skills/edgegate-connect-huggingface.md +64 -0
- package/skills/edgegate-connect-qaihub.md +56 -0
- package/skills/edgegate-import.md +2 -2
- package/skills/edgegate-init.md +17 -0
- package/skills/edgegate-members.md +51 -0
- package/skills/edgegate-workspace-setup.md +74 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { EdgeGateClient } from "../client.js";
|
|
3
|
+
import type { ToolResult } from "./setup_workspace.js";
|
|
4
|
+
export declare const revokeApiKeyInputSchema: z.ZodObject<{
|
|
5
|
+
workspace_id: z.ZodString;
|
|
6
|
+
key_id: z.ZodString;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
workspace_id: string;
|
|
9
|
+
key_id: string;
|
|
10
|
+
}, {
|
|
11
|
+
workspace_id: string;
|
|
12
|
+
key_id: string;
|
|
13
|
+
}>;
|
|
14
|
+
export type RevokeApiKeyInput = z.infer<typeof revokeApiKeyInputSchema>;
|
|
15
|
+
export declare function revokeApiKeyHandler(client: EdgeGateClient, input: RevokeApiKeyInput): Promise<ToolResult>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { EdgeGateError } from "../client.js";
|
|
3
|
+
export const revokeApiKeyInputSchema = z.object({
|
|
4
|
+
workspace_id: z.string().uuid(),
|
|
5
|
+
key_id: z
|
|
6
|
+
.string()
|
|
7
|
+
.uuid()
|
|
8
|
+
.describe("UUID of the key to revoke (the `id` field from `edgegate_list_api_keys`). " +
|
|
9
|
+
"This is destructive and immediate — any CI job or client still using " +
|
|
10
|
+
"the plaintext will fail authentication on the next request."),
|
|
11
|
+
});
|
|
12
|
+
export async function revokeApiKeyHandler(client, input) {
|
|
13
|
+
try {
|
|
14
|
+
await client.revokeApiKey(input.workspace_id, input.key_id);
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: [
|
|
20
|
+
`Revoked API key \`${input.key_id}\`.`,
|
|
21
|
+
``,
|
|
22
|
+
`The key is now rejected for all future requests. The audit trail (last_used_at, revoked_at) is preserved on the row — you can still see it in \`edgegate_list_api_keys\`.`,
|
|
23
|
+
].join("\n"),
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
if (err instanceof EdgeGateError) {
|
|
30
|
+
if (err.status === 404) {
|
|
31
|
+
return {
|
|
32
|
+
isError: true,
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: `API key \`${input.key_id}\` not found in this workspace (or already revoked).`,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
isError: true,
|
|
43
|
+
content: [{ type: "text", text: `EdgeGate returned ${err.status}: ${err.detail}` }],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=revoke_api_key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revoke_api_key.js","sourceRoot":"","sources":["../../src/tools/revoke_api_key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAkB,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7D,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IAC/B,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,IAAI,EAAE;SACN,QAAQ,CACP,4EAA4E;QAC1E,uEAAuE;QACvE,6DAA6D,CAChE;CACJ,CAAC,CAAC;AAIH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,KAAwB;IAExB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAC5D,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;wBACJ,qBAAqB,KAAK,CAAC,MAAM,KAAK;wBACtC,EAAE;wBACF,2KAA2K;qBAC5K,CAAC,IAAI,CAAC,IAAI,CAAC;iBACb;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YACjC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvB,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,aAAa,KAAK,CAAC,MAAM,sDAAsD;yBACtF;qBACF;iBACF,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;aACpF,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
export type UUID = string;
|
|
2
|
+
/** Supported dtypes for AI Hub compile input tensors. */
|
|
3
|
+
export type InputSpecDtype = "float32" | "float16" | "int64" | "int32" | "bool";
|
|
4
|
+
/**
|
|
5
|
+
* Explicit shape + dtype for one named model input.
|
|
6
|
+
* Passed as `input_specs` on pipeline create/update to override the default
|
|
7
|
+
* AI Hub auto-detect or PR-#40 auto-resolve behaviour.
|
|
8
|
+
*
|
|
9
|
+
* Example (BERT-family):
|
|
10
|
+
* { shape: [1, 128], dtype: "int64" }
|
|
11
|
+
*/
|
|
12
|
+
export interface InputSpec {
|
|
13
|
+
/** Tensor shape (1–8 positive integers). */
|
|
14
|
+
shape: number[];
|
|
15
|
+
/** Element dtype. Defaults to "float32" when omitted. */
|
|
16
|
+
dtype: InputSpecDtype;
|
|
17
|
+
}
|
|
2
18
|
export interface Workspace {
|
|
3
19
|
id: UUID;
|
|
4
20
|
name: string;
|
|
@@ -84,6 +100,74 @@ export interface WorkflowTemplate {
|
|
|
84
100
|
api_url: string;
|
|
85
101
|
secret_names: string[];
|
|
86
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Returned by GET /integrations/huggingface — status without the token.
|
|
105
|
+
* The plaintext token is never echoed; only the last 4 chars + lifecycle
|
|
106
|
+
* fields are visible after the initial connect/rotate call.
|
|
107
|
+
*/
|
|
108
|
+
export interface HuggingFaceIntegrationStatus {
|
|
109
|
+
id: UUID;
|
|
110
|
+
provider: "huggingface";
|
|
111
|
+
status: "active" | "disabled";
|
|
112
|
+
token_last4: string;
|
|
113
|
+
created_at: string;
|
|
114
|
+
updated_at: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returned by POST /integrations/huggingface and the rotate endpoint.
|
|
118
|
+
* Includes the whoami account name/type so the caller can confirm the
|
|
119
|
+
* right account was connected, without leaking the secret.
|
|
120
|
+
*/
|
|
121
|
+
export interface HuggingFaceConnectResponse extends HuggingFaceIntegrationStatus {
|
|
122
|
+
account_name: string;
|
|
123
|
+
account_type: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Returned by GET / POST / PUT on /integrations/qaihub.
|
|
127
|
+
* The plaintext token is never echoed; only token_last4 is visible.
|
|
128
|
+
*/
|
|
129
|
+
export interface QaihubIntegration {
|
|
130
|
+
id: UUID;
|
|
131
|
+
provider: "qaihub";
|
|
132
|
+
status: "active" | "disabled";
|
|
133
|
+
token_last4: string;
|
|
134
|
+
created_at: string;
|
|
135
|
+
updated_at: string;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Returned by POST /workspaces/{ws}/api-keys.
|
|
139
|
+
* `plaintext` is the only time the full key is visible — the caller must
|
|
140
|
+
* persist it immediately; the backend stores only a bcrypt hash.
|
|
141
|
+
*/
|
|
142
|
+
export interface APIKeyCreatedResponse {
|
|
143
|
+
id: UUID;
|
|
144
|
+
plaintext: string;
|
|
145
|
+
name: string;
|
|
146
|
+
prefix: string;
|
|
147
|
+
suffix: string;
|
|
148
|
+
created_at: string;
|
|
149
|
+
expires_at: string | null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Returned by GET /workspaces/{ws}/api-keys (one row per key).
|
|
153
|
+
* Includes lifecycle fields but never the plaintext or the hash.
|
|
154
|
+
*/
|
|
155
|
+
export interface APIKeyListItem {
|
|
156
|
+
id: UUID;
|
|
157
|
+
name: string;
|
|
158
|
+
prefix: string;
|
|
159
|
+
suffix: string;
|
|
160
|
+
last_used_at: string | null;
|
|
161
|
+
expires_at: string | null;
|
|
162
|
+
revoked_at: string | null;
|
|
163
|
+
created_at: string;
|
|
164
|
+
}
|
|
165
|
+
export type WorkspaceRole = "owner" | "admin" | "viewer";
|
|
166
|
+
export interface Member {
|
|
167
|
+
user_id: UUID;
|
|
168
|
+
email: string;
|
|
169
|
+
role: WorkspaceRole;
|
|
170
|
+
}
|
|
87
171
|
/** @deprecated Not used — audit-report endpoint does not exist; use RunBundle instead. */
|
|
88
172
|
export interface AuditReport {
|
|
89
173
|
url?: string;
|
|
@@ -185,3 +269,88 @@ export interface PromptPackCreateBody {
|
|
|
185
269
|
version: string;
|
|
186
270
|
content: PromptPackContent;
|
|
187
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Workspace's customer-owned S3 bucket grant. Returned by every grant
|
|
274
|
+
* endpoint (register / get / verify / rotate-external-id).
|
|
275
|
+
*
|
|
276
|
+
* `external_id` is shown in EVERY response — it's the value the customer
|
|
277
|
+
* has to paste into their IAM role trust policy's `sts:ExternalId`
|
|
278
|
+
* condition. We don't treat it like a secret because the trust policy
|
|
279
|
+
* already pins our AWS account as the only principal that can use it.
|
|
280
|
+
*
|
|
281
|
+
* `status` semantics: "active" = last probe passed; "failed" = last probe
|
|
282
|
+
* raised (with `last_verify_error` populated); "revoked" = grant was
|
|
283
|
+
* explicitly deleted (404 on /grants thereafter).
|
|
284
|
+
*/
|
|
285
|
+
export interface ByoGrant {
|
|
286
|
+
id: UUID;
|
|
287
|
+
workspace_id: UUID;
|
|
288
|
+
role_arn: string;
|
|
289
|
+
external_id: UUID;
|
|
290
|
+
bucket: string;
|
|
291
|
+
region: string;
|
|
292
|
+
kms_key_id: string | null;
|
|
293
|
+
status: "active" | "revoked" | "failed";
|
|
294
|
+
last_verified_at: string | null;
|
|
295
|
+
last_verify_error: string | null;
|
|
296
|
+
created_at: string;
|
|
297
|
+
updated_at: string;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Request body for POST /v1/workspaces/{ws}/artifacts/byo.
|
|
301
|
+
* Registers an existing S3 URI in the customer's grant-registered bucket
|
|
302
|
+
* as an Artifact pointer. EdgeGate does NOT upload bytes — it HeadObjects
|
|
303
|
+
* the URI to confirm existence + capture size/etag.
|
|
304
|
+
*/
|
|
305
|
+
export interface ByoArtifactRegisterRequest {
|
|
306
|
+
s3_uri: string;
|
|
307
|
+
expected_sha256?: string;
|
|
308
|
+
expected_size?: number;
|
|
309
|
+
kind?: string;
|
|
310
|
+
original_filename?: string;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* One row from the workspace's append-only `byo_storage_audit` table.
|
|
314
|
+
* `aws_request_id` is the join key for cross-referencing the customer's
|
|
315
|
+
* own CloudTrail. Nullable fields are by design for events that don't
|
|
316
|
+
* produce them (verify_probe has no run_id/artifact_id, etc.).
|
|
317
|
+
*/
|
|
318
|
+
export interface ByoAuditEntry {
|
|
319
|
+
id: number;
|
|
320
|
+
event_type: string;
|
|
321
|
+
aws_request_id: string;
|
|
322
|
+
role_arn: string;
|
|
323
|
+
bucket: string;
|
|
324
|
+
s3_key: string | null;
|
|
325
|
+
bytes_read: number | null;
|
|
326
|
+
worker_hostname: string | null;
|
|
327
|
+
outcome: string;
|
|
328
|
+
error_code: string | null;
|
|
329
|
+
artifact_id: UUID | null;
|
|
330
|
+
run_id: UUID | null;
|
|
331
|
+
ts: string;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Paginated audit-log page. `next_cursor === null` means the response
|
|
335
|
+
* contained the last page. Pass the value back as the `cursor` query
|
|
336
|
+
* param to fetch the next page.
|
|
337
|
+
*/
|
|
338
|
+
export interface ByoAuditPage {
|
|
339
|
+
entries: ByoAuditEntry[];
|
|
340
|
+
next_cursor: number | null;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Returned by POST /artifacts and POST /artifacts/byo. Mirrors the
|
|
344
|
+
* backend `ArtifactResponse` schema. `storage_url` for BYO artifacts is
|
|
345
|
+
* `byo-s3://{bucket}/{key}` rather than the managed `s3://...` form.
|
|
346
|
+
*/
|
|
347
|
+
export interface ArtifactResponse {
|
|
348
|
+
id: UUID;
|
|
349
|
+
kind: string;
|
|
350
|
+
sha256: string;
|
|
351
|
+
size_bytes: number;
|
|
352
|
+
original_filename: string | null;
|
|
353
|
+
storage_url: string;
|
|
354
|
+
created_at: string;
|
|
355
|
+
expires_at: string | null;
|
|
356
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
2
|
-
export declare const USER_AGENT = "edgegate-mcp/0.
|
|
1
|
+
export declare const VERSION = "0.8.0";
|
|
2
|
+
export declare const USER_AGENT = "edgegate-mcp/0.8.0";
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "edgegate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Edge-AI regression gates from Claude Code — set up CI, run benchmarks, compare runs, export reports, and fetch audit bundles from any prompt.",
|
|
5
5
|
"author": "Frozo / EdgeGate",
|
|
6
6
|
"homepage": "https://edgegate.frozo.ai",
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"skills/edgegate-compare.md",
|
|
26
26
|
"skills/edgegate-export.md",
|
|
27
27
|
"skills/edgegate-import.md",
|
|
28
|
-
"skills/edgegate-promptpacks.md"
|
|
28
|
+
"skills/edgegate-promptpacks.md",
|
|
29
|
+
"skills/edgegate-connect-huggingface.md",
|
|
30
|
+
"skills/edgegate-connect-qaihub.md",
|
|
31
|
+
"skills/edgegate-workspace-setup.md",
|
|
32
|
+
"skills/edgegate-members.md",
|
|
33
|
+
"skills/edgegate-byo-storage.md"
|
|
29
34
|
]
|
|
30
35
|
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: edgegate-byo-storage
|
|
3
|
+
description: Wire up BYO (bring-your-own) S3 storage for an Enterprise EdgeGate workspace — register the IAM role + bucket grant, verify the readiness probe, register the first artifact directly from the customer's bucket, and confirm the audit trail. Use when the user is on the Enterprise plan and wants model bytes to live in their own AWS account.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /edgegate-byo-storage
|
|
7
|
+
|
|
8
|
+
This is the **Enterprise BYO storage onboarding** flow. The whole point of
|
|
9
|
+
BYO is that model bytes never leave the customer's AWS account — EdgeGate's
|
|
10
|
+
workers AssumeRole into their account and read directly from their bucket.
|
|
11
|
+
|
|
12
|
+
Use this skill once per workspace, after the customer's security/IAM team
|
|
13
|
+
has provisioned the role + bucket.
|
|
14
|
+
|
|
15
|
+
## When to use
|
|
16
|
+
|
|
17
|
+
- The workspace is on the **Enterprise plan** (BYO storage 402s otherwise).
|
|
18
|
+
- The user has (or wants to provision) their own S3 bucket and IAM role.
|
|
19
|
+
- The user is migrating an existing workspace from EdgeGate-managed storage
|
|
20
|
+
to BYO, or onboarding a brand-new Enterprise workspace.
|
|
21
|
+
|
|
22
|
+
If the workspace isn't Enterprise yet, send them to
|
|
23
|
+
<https://edgegate.frozo.ai/enterprise> first — none of the
|
|
24
|
+
`edgegate_*_byo_*` tools will work until BYO is enabled on the plan.
|
|
25
|
+
|
|
26
|
+
## Pre-flight (AWS side — the user does this in their account)
|
|
27
|
+
|
|
28
|
+
You can't do this part for them, but you can hand them the exact spec:
|
|
29
|
+
|
|
30
|
+
1. **Provision the IAM role.** The fastest path is the EdgeGate
|
|
31
|
+
CloudFormation Launch Stack — link them to it from
|
|
32
|
+
<https://edgegate.frozo.ai/workspace/{workspace_id}/settings#byo-storage>.
|
|
33
|
+
(A Terraform module is also published; ask the customer which their
|
|
34
|
+
security team prefers.) The stack creates:
|
|
35
|
+
- The IAM role with `sts:AssumeRole` trusted to EdgeGate's AWS account.
|
|
36
|
+
- The S3 bucket policy granting that role `s3:GetObject` + `ListBucket`
|
|
37
|
+
scoped to the bucket only.
|
|
38
|
+
- (Optional) KMS key policy granting `kms:Decrypt` if the bucket uses
|
|
39
|
+
SSE-KMS.
|
|
40
|
+
2. **Capture** the `role_arn`, `bucket` name, `region`, and (if applicable)
|
|
41
|
+
`kms_key_id`. The trust policy's `sts:ExternalId` is left as a
|
|
42
|
+
placeholder — EdgeGate mints the real one in step 1 below and the
|
|
43
|
+
customer pastes it back.
|
|
44
|
+
|
|
45
|
+
If they want the raw IAM JSON instead of CloudFormation/Terraform, point
|
|
46
|
+
them at `docs/byo-storage-onboarding.md` in the backend repo or the
|
|
47
|
+
dashboard's "Show raw policies" link.
|
|
48
|
+
|
|
49
|
+
## Steps
|
|
50
|
+
|
|
51
|
+
1. **Register the grant.** Call
|
|
52
|
+
`edgegate_register_byo_bucket({ workspace_id, role_arn, bucket, region, kms_key_id? })`.
|
|
53
|
+
The response includes an `external_id` UUID — capture it.
|
|
54
|
+
|
|
55
|
+
2. **Paste the External ID into the IAM role trust policy.** Tell the
|
|
56
|
+
user, in plain English: "Open your IAM role in the AWS console, edit
|
|
57
|
+
the trust relationship, and replace the placeholder ExternalId with
|
|
58
|
+
`<external_id>`." Until they do this, AssumeRole will fail with
|
|
59
|
+
`BYO_ASSUME_ROLE_FAILED`.
|
|
60
|
+
|
|
61
|
+
The CloudFormation stack supports passing the External ID as a
|
|
62
|
+
parameter — point them at that if they used the stack.
|
|
63
|
+
|
|
64
|
+
3. **Verify the probe.** After the user confirms the trust policy edit
|
|
65
|
+
is saved, call `edgegate_check_byo_bucket({ workspace_id })`. Expect
|
|
66
|
+
`status: "active"`. If `status: "failed"`, the response's checklist
|
|
67
|
+
covers every typed `BYO_*` error code — read the `last_verify_error`
|
|
68
|
+
to the user, suggest the matching fix, then re-run `check`.
|
|
69
|
+
|
|
70
|
+
4. **Register the first artifact.** Pick (or ask for) an existing model
|
|
71
|
+
in the bucket. Call:
|
|
72
|
+
```
|
|
73
|
+
edgegate_register_byo_artifact({
|
|
74
|
+
workspace_id,
|
|
75
|
+
s3_uri: "s3://<bucket>/<key>.onnx",
|
|
76
|
+
expected_sha256: "<optional but recommended>",
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
Capture the returned `artifact_id`. EdgeGate did NOT download the
|
|
80
|
+
bytes — it only HeadObject'd the URI to confirm the key exists and
|
|
81
|
+
capture size + etag. The storage URL in the response will start with
|
|
82
|
+
`byo-s3://` (not `s3://`) — that's how downstream tooling routes
|
|
83
|
+
reads through the BYO service rather than EdgeGate's managed S3.
|
|
84
|
+
|
|
85
|
+
5. **Trigger the first run.** Run the artifact against an existing
|
|
86
|
+
pipeline so the customer sees the end-to-end flow work:
|
|
87
|
+
```
|
|
88
|
+
edgegate_run_gate({
|
|
89
|
+
workspace_id,
|
|
90
|
+
pipeline_id: "<existing pipeline>",
|
|
91
|
+
model_artifact_id: "<artifact_id from step 4>",
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
Poll with `edgegate_check_status` until it terminates.
|
|
95
|
+
|
|
96
|
+
6. **Show them the audit trail.** Call
|
|
97
|
+
`edgegate_get_byo_audit({ workspace_id, run_id: "<run_id from step 5>" })`.
|
|
98
|
+
The table includes one row per S3 / STS call with the
|
|
99
|
+
`aws_request_id`. Tell the user: "Cross-reference these against your
|
|
100
|
+
own CloudTrail in the same time window — every read should match."
|
|
101
|
+
This is the trust handshake the customer's security team will ask
|
|
102
|
+
for.
|
|
103
|
+
|
|
104
|
+
7. **Recap + next.** Summarize:
|
|
105
|
+
- Grant: `active`, bucket=`<name>`, region=`<region>`
|
|
106
|
+
- First artifact registered + first run executed
|
|
107
|
+
- Audit log accessible via `edgegate_get_byo_audit`
|
|
108
|
+
|
|
109
|
+
Next concrete actions:
|
|
110
|
+
- "Migrate more artifacts: `edgegate_register_byo_artifact` per s3_uri"
|
|
111
|
+
- "Schedule periodic audit pulls into your SIEM (we can stream via API)"
|
|
112
|
+
- "Rotate the External ID at any time via the dashboard"
|
|
113
|
+
|
|
114
|
+
## Failure modes
|
|
115
|
+
|
|
116
|
+
- **Register grant → 402.** Workspace is not on Enterprise. Send them to
|
|
117
|
+
<https://edgegate.frozo.ai/enterprise>.
|
|
118
|
+
- **Register grant → 409.** A grant already exists. We deliberately do
|
|
119
|
+
NOT auto-rotate — the existing grant may belong to a role the customer
|
|
120
|
+
doesn't want overwritten. Inspect with `edgegate_check_byo_bucket`,
|
|
121
|
+
then either keep it or `edgegate_disconnect_byo_bucket` and re-register.
|
|
122
|
+
External-ID-only rotation is available via the dashboard.
|
|
123
|
+
- **Check probe → status=failed with BYO_ASSUME_ROLE_FAILED.** External
|
|
124
|
+
ID drift between EdgeGate and the role's trust policy. Re-paste the
|
|
125
|
+
current external_id (visible via `edgegate_check_byo_bucket` or the
|
|
126
|
+
dashboard) into the trust policy's `sts:ExternalId` condition.
|
|
127
|
+
- **Check probe → BYO_KMS_ACCESS_DENIED.** SSE-KMS bucket but the role
|
|
128
|
+
is missing `kms:Decrypt` on the key. Add the role principal to the
|
|
129
|
+
KMS key policy.
|
|
130
|
+
- **Check probe → BYO_REGION_MISMATCH.** The bucket lives in a different
|
|
131
|
+
region than the `region` you registered. Disconnect and re-register
|
|
132
|
+
with the correct region.
|
|
133
|
+
- **Register artifact → 400 bucket mismatch.** The s3_uri points at a
|
|
134
|
+
bucket that isn't this workspace's registered one. Cross-bucket
|
|
135
|
+
pointers are forbidden — register the right bucket (or move the
|
|
136
|
+
object).
|
|
137
|
+
- **Register artifact → 400 BYO_OBJECT_NOT_FOUND.** The key is mistyped
|
|
138
|
+
or the role's bucket policy denies `ListBucket`/`GetObject` on that
|
|
139
|
+
prefix. HeadObject failures pass through with the typed code.
|
|
140
|
+
- **Disconnect → 409.** Artifacts still reference the grant. The
|
|
141
|
+
response lists the safe paths forward (drop the artifacts first, or
|
|
142
|
+
rotate the External ID via dashboard if that's what you actually
|
|
143
|
+
wanted).
|
|
144
|
+
- **Mid-run revocation** (customer revokes the role mid-run): the
|
|
145
|
+
in-flight cells complete, the rest fail with
|
|
146
|
+
`BYO_ASSUME_ROLE_FAILED`, the run terminates as `failed` (not
|
|
147
|
+
`error`) with the partial-success cells preserved in the bundle.
|
|
148
|
+
This is by design — re-grant + re-run picks up cleanly.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: edgegate-connect-huggingface
|
|
3
|
+
description: Connect a personal HuggingFace token to the active workspace so EdgeGate can import private, gated, or Qualcomm-org repos. Walk the user through generating a token, confirming the account, and remembering that rotation is non-disruptive.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /edgegate-connect-huggingface
|
|
7
|
+
|
|
8
|
+
Use this skill when the user wants to import a HuggingFace model that the
|
|
9
|
+
anonymous endpoint can't reach — common cases:
|
|
10
|
+
|
|
11
|
+
- `qualcomm/*` (Qualcomm's own optimized model org)
|
|
12
|
+
- `Intel/*` and many `Xenova/*` repos
|
|
13
|
+
- The user's own private repository
|
|
14
|
+
- Any gated model (Llama family, some image models, etc.) the user has access to
|
|
15
|
+
|
|
16
|
+
The workspace integration encrypts the token at rest using the same KMS as the
|
|
17
|
+
AI Hub token; it is never echoed in plaintext after the initial connect.
|
|
18
|
+
|
|
19
|
+
## Steps
|
|
20
|
+
|
|
21
|
+
1. **Confirm the active workspace.** If you don't already know which workspace
|
|
22
|
+
the user is operating on, call `edgegate_setup_workspace` first.
|
|
23
|
+
|
|
24
|
+
2. **Check whether a token is already connected.** Call
|
|
25
|
+
`edgegate_get_huggingface_integration`. If a token is already active,
|
|
26
|
+
confirm with the user whether they want to **rotate** (replace) it before
|
|
27
|
+
asking for a new one.
|
|
28
|
+
|
|
29
|
+
3. **Walk the user through generating a token** if they don't already have one.
|
|
30
|
+
- Open <https://huggingface.co/settings/tokens>
|
|
31
|
+
- Click **Create new token**
|
|
32
|
+
- Default scope is `Read` — that's enough for the import flow
|
|
33
|
+
- Copy the token. It starts with `hf_…` and is shown exactly once
|
|
34
|
+
|
|
35
|
+
4. **Call `edgegate_connect_huggingface`** with the token. The tool validates
|
|
36
|
+
it against HF's `whoami` endpoint before storing, so a typo'd or revoked
|
|
37
|
+
token surfaces as a clean 400 with guidance — not a silent failure later
|
|
38
|
+
during import.
|
|
39
|
+
|
|
40
|
+
5. **Confirm.** The tool response includes the HF `account_name` and
|
|
41
|
+
`account_type`. Confirm that matches the user's expectation — for example,
|
|
42
|
+
if they meant to use their org account but the response shows their
|
|
43
|
+
personal handle, offer to rotate with the right token.
|
|
44
|
+
|
|
45
|
+
6. **Move on.** Tell the user the integration is live and that they can now
|
|
46
|
+
call `edgegate_import_huggingface_model` against any repo their token can
|
|
47
|
+
read (including the Qualcomm org).
|
|
48
|
+
|
|
49
|
+
## Failure modes
|
|
50
|
+
|
|
51
|
+
- **400 "does not look like a HuggingFace token"** — they pasted something
|
|
52
|
+
that doesn't start with `hf_` or `api_`. Direct them back to
|
|
53
|
+
<https://huggingface.co/settings/tokens>.
|
|
54
|
+
- **400 "HuggingFace rejected the token"** — token is real-shaped but HF
|
|
55
|
+
returned 401. Common causes: typo, copied truncated value, token revoked.
|
|
56
|
+
Suggest regenerating.
|
|
57
|
+
- **409 conflict** — the tool auto-rotates on conflict, so this shouldn't
|
|
58
|
+
bubble up. If it does, the rotation also failed; surface the error.
|
|
59
|
+
|
|
60
|
+
## Removing the integration
|
|
61
|
+
|
|
62
|
+
If the user wants to remove the token (offboarding, key rotation policy,
|
|
63
|
+
account change), call `edgegate_disconnect_huggingface`. The encrypted token
|
|
64
|
+
is deleted; future imports fall back to anonymous access.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: edgegate-connect-qaihub
|
|
3
|
+
description: Connect a Qualcomm AI Hub API token to the active EdgeGate workspace so runs can compile and profile models on real Snapdragon devices. Required before any pipeline can actually execute.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /edgegate-connect-qaihub
|
|
7
|
+
|
|
8
|
+
Use this skill when the user is setting up a new EdgeGate workspace, has just
|
|
9
|
+
created one with `edgegate_create_workspace`, or is seeing runs fail with
|
|
10
|
+
`NO_AIHUB_TOKEN`.
|
|
11
|
+
|
|
12
|
+
Qualcomm AI Hub is the device cloud EdgeGate uses behind the scenes — every
|
|
13
|
+
compile + profile + inference job runs against a real Snapdragon device there.
|
|
14
|
+
Without a token connected, the worker can't talk to Hub, so runs that reach the
|
|
15
|
+
worker fail fast.
|
|
16
|
+
|
|
17
|
+
## Steps
|
|
18
|
+
|
|
19
|
+
1. **Confirm the active workspace.** If you don't already know which workspace,
|
|
20
|
+
call `edgegate_setup_workspace` first.
|
|
21
|
+
|
|
22
|
+
2. **Check whether a token is already connected.** Call
|
|
23
|
+
`edgegate_get_qaihub_integration`. If the response says **active** with a
|
|
24
|
+
`token_last4`, ask the user whether they want to **rotate** (replace) the
|
|
25
|
+
existing token before continuing. If the response is 404, they need to
|
|
26
|
+
connect for the first time.
|
|
27
|
+
|
|
28
|
+
3. **Walk the user through generating a Qualcomm AI Hub token** if they don't
|
|
29
|
+
already have one:
|
|
30
|
+
- Open <https://app.aihub.qualcomm.com/account/api-token>
|
|
31
|
+
- Click **Generate new token** (or copy the existing one if shown)
|
|
32
|
+
- The token is a long alphanumeric string; copy it
|
|
33
|
+
|
|
34
|
+
4. **Call `edgegate_connect_qaihub`** with the token. The backend stores it
|
|
35
|
+
under envelope encryption using the workspace KMS — the plaintext is
|
|
36
|
+
never returned again, and only `token_last4` is visible afterwards.
|
|
37
|
+
|
|
38
|
+
5. **Confirm + next step.** Tell the user the integration is live. If this is
|
|
39
|
+
their first connection, suggest:
|
|
40
|
+
- `edgegate_create_promptpack` (if they need a new promptpack)
|
|
41
|
+
- `edgegate_create_pipeline` to define their first regression gate
|
|
42
|
+
|
|
43
|
+
## Failure modes
|
|
44
|
+
|
|
45
|
+
- **Already exists (409 conflict)** — the tool transparently rotates instead
|
|
46
|
+
of failing, so the user shouldn't see this. If it does bubble up, the
|
|
47
|
+
rotation also failed and the backend error message comes through.
|
|
48
|
+
- **500 from Qualcomm AI Hub itself** — usually a transient outage at Hub
|
|
49
|
+
(`https://app.aihub.qualcomm.com`). Ask the user to retry in a minute.
|
|
50
|
+
|
|
51
|
+
## Removing the integration
|
|
52
|
+
|
|
53
|
+
If the user wants to disconnect (offboarding, key rotation policy, account
|
|
54
|
+
change), call `edgegate_disconnect_qaihub`. The encrypted token is deleted
|
|
55
|
+
and new runs in the workspace fail with `NO_AIHUB_TOKEN` until a fresh
|
|
56
|
+
token is connected.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: edgegate-import
|
|
3
|
-
description: Import a
|
|
3
|
+
description: Import a Hugging Face model (ONNX) into EdgeGate. Use when the user says "import model from huggingface", "pull this HF model", or references an "<owner>/<name>" repo they want to gate. Supports both anonymous (public repos) and personal-token (private / gated / qualcomm-org repos via /edgegate-connect-huggingface) flows.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /edgegate-import
|
|
@@ -45,5 +45,5 @@ Use this skill when the user says any of:
|
|
|
45
45
|
## Failure modes
|
|
46
46
|
|
|
47
47
|
- **"no ONNX file found"** — The repo doesn't contain a pre-built ONNX. EdgeGate v1 only supports repos with a pre-built ONNX file. Point the user to the dashboard upload flow for converting their own model: `https://edgegate.frozo.ai/workspace/<id>/models`.
|
|
48
|
-
- **"private repo"** —
|
|
48
|
+
- **"private repo" / 401 from HuggingFace** — The anonymous endpoint can't read the repo (gated org like `qualcomm/*`, the user's own private repo, or a gated Llama family model). Offer to run `/edgegate-connect-huggingface` to attach a personal HF token to the workspace; once connected the same import call will succeed.
|
|
49
49
|
- **402 — plan limit** — Direct the user to `https://edgegate.frozo.ai/pricing` to upgrade.
|
package/skills/edgegate-init.md
CHANGED
|
@@ -13,6 +13,10 @@ Goal of this skill: take the user from "I have a model file" to "every PR is aut
|
|
|
13
13
|
|
|
14
14
|
1. **Confirm workspace.** Call `edgegate_setup_workspace` with no args. Present the list. Ask the user which one to use; if they say "the first one", pick `result[0].id`. Confirm before continuing.
|
|
15
15
|
|
|
16
|
+
If the list is empty OR the user wants a new workspace for this project, route to `/edgegate-workspace-setup` instead — that flow creates the workspace, connects Qualcomm AI Hub, optionally mints an API key for CI, and optionally invites teammates, all from chat.
|
|
17
|
+
|
|
18
|
+
If they have a workspace but it's missing the Qualcomm AI Hub integration (runs would fail with `NO_AIHUB_TOKEN`), run `/edgegate-connect-qaihub` first.
|
|
19
|
+
|
|
16
20
|
2. **Define the pipeline.** Ask the user:
|
|
17
21
|
- "Which model file do you want to gate? (path or artifact_id)"
|
|
18
22
|
- "Which Snapdragon devices? (default: Samsung Galaxy S24, Galaxy S23)"
|
|
@@ -20,6 +24,8 @@ Goal of this skill: take the user from "I have a model file" to "every PR is aut
|
|
|
20
24
|
|
|
21
25
|
If they hand you a file path (e.g. `./model.onnx`), tell them they need to upload it via the dashboard first to get an artifact_id (the MCP tool does not handle uploads in v1.0). Link: `https://edgegate.frozo.ai/workspace/{workspace_id}/models`.
|
|
22
26
|
|
|
27
|
+
If they hand you a HuggingFace repo id (e.g. `microsoft/resnet-50`), call `edgegate_import_huggingface_model` to import it and get an artifact_id back. If the repo is private / gated / from the Qualcomm org, the import will 401 — offer to run `/edgegate-connect-huggingface` to attach a personal HF token to the workspace, then retry the import.
|
|
28
|
+
|
|
23
29
|
If they hand you an artifact_id, proceed to `edgegate_create_pipeline`.
|
|
24
30
|
|
|
25
31
|
3. **Trigger the first run.** Call `edgegate_run_gate` with the workspace_id + new pipeline_id. Tell the user the run_id. Note that runs take 3-5 min per device.
|
|
@@ -28,6 +34,17 @@ Goal of this skill: take the user from "I have a model file" to "every PR is aut
|
|
|
28
34
|
|
|
29
35
|
5. **Confirm.** Tell the user what's now set up: workspace `<name>`, pipeline `<name>`, run `<id>` in flight, and (if applicable) GitHub Action wired.
|
|
30
36
|
|
|
37
|
+
## Input shape overrides (`input_specs`)
|
|
38
|
+
|
|
39
|
+
If creating a pipeline for a text or audio model, the backend auto-resolves dynamic shapes
|
|
40
|
+
(defaults: batch=1, sequence=128). If those defaults don't fit — long-context LLM, custom
|
|
41
|
+
audio model, or mixed-input model — pass `input_specs` explicitly with the right shape per input.
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
- Long-context BERT (seq_len=512): `{ input_ids: { shape: [1, 512], dtype: "int64" }, attention_mask: { shape: [1, 512], dtype: "int64" } }`
|
|
45
|
+
- Audio model (mel-spectrogram): `{ mel_features: { shape: [1, 80, 3000], dtype: "float32" } }`
|
|
46
|
+
- Image model: omit entirely — the backend reads static shapes from the ONNX file.
|
|
47
|
+
|
|
31
48
|
## Failure modes
|
|
32
49
|
|
|
33
50
|
- **No workspaces.** The API key may have been revoked. Direct the user to `https://edgegate.frozo.ai/workspace/<id>/settings#api-keys` to generate a fresh key.
|