@peers-app/peers-sdk 0.22.0 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context/user-context-singleton.d.ts +42 -0
- package/dist/context/user-context-singleton.js +45 -0
- package/dist/contracts/__tests__/contract-proxy.test.js +51 -1
- package/dist/contracts/__tests__/contract-resolvers.test.js +30 -0
- package/dist/contracts/__tests__/playground.test.js +5 -2
- package/dist/contracts/__tests__/system-contracts.test.js +3 -0
- package/dist/contracts/contract-proxy.d.ts +6 -0
- package/dist/contracts/contract-proxy.js +34 -0
- package/dist/contracts/contract-resolvers.js +9 -1
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +5 -2
- package/dist/contracts/system/index.d.ts +2 -0
- package/dist/contracts/system/index.js +5 -1
- package/dist/contracts/system/tool-access-control-contract.d.ts +35 -0
- package/dist/contracts/system/tool-access-control-contract.js +70 -0
- package/dist/data/access-level.d.ts +72 -0
- package/dist/data/access-level.js +109 -0
- package/dist/data/access-level.test.d.ts +1 -0
- package/dist/data/access-level.test.js +53 -0
- package/dist/data/assistants.d.ts +24 -0
- package/dist/data/assistants.js +21 -0
- package/dist/data/group-member-roles.d.ts +9 -0
- package/dist/data/group-member-roles.js +9 -0
- package/dist/data/group-permissions.d.ts +55 -1
- package/dist/data/group-permissions.js +76 -6
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.js +3 -0
- package/dist/data/orm/sql.data-source.d.ts +10 -0
- package/dist/data/orm/sql.data-source.js +48 -30
- package/dist/data/orm/sql.data-source.test.js +13 -0
- package/dist/data/package-version-resolver.test.js +2 -0
- package/dist/data/tool-access-approvals.d.ts +126 -0
- package/dist/data/tool-access-approvals.js +86 -0
- package/dist/data/tool-access.d.ts +162 -0
- package/dist/data/tool-access.js +235 -0
- package/dist/data/tool-access.test.d.ts +1 -0
- package/dist/data/tool-access.test.js +159 -0
- package/dist/data/tools.d.ts +15 -0
- package/dist/data/tools.js +11 -0
- package/dist/data/workflow-logs.d.ts +5 -5
- package/dist/data/workflow-runs.d.ts +2 -2
- package/dist/device-pairing/types.d.ts +6 -6
- package/dist/system-ids.d.ts +18 -0
- package/dist/system-ids.js +19 -1
- package/package.json +1 -1
|
@@ -245,13 +245,7 @@ class SQLDataSource {
|
|
|
245
245
|
// @ts-expect-error - need to figure out how to get typescript to understand what's going on here
|
|
246
246
|
record[this.metaData.primaryKeyName] = (0, utils_1.newid)();
|
|
247
247
|
}
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
this.schema.parse(record);
|
|
251
|
-
}
|
|
252
|
-
catch (e) {
|
|
253
|
-
throw new Error(`Validation on insert failed for ${this.tableName}: ${e}`);
|
|
254
|
-
}
|
|
248
|
+
this.applySchemaDefaults(record);
|
|
255
249
|
const fields = this.metaData.fields.map((field) => `"${field.name}"`).join(", ");
|
|
256
250
|
const values = this.metaData.fields.map((field) => jsValueToSqlValue(record[field.name]));
|
|
257
251
|
const placeholders = values.map((_v) => "?").join(", ");
|
|
@@ -265,16 +259,14 @@ class SQLDataSource {
|
|
|
265
259
|
// @ts-expect-error - need to figure out how to get typescript to understand what's going on here
|
|
266
260
|
record[this.metaData.primaryKeyName] = (0, utils_1.newid)();
|
|
267
261
|
}
|
|
268
|
-
// validate data
|
|
269
262
|
this.schema.parse(record);
|
|
270
263
|
const primaryKey = record[this.metaData.primaryKeyName];
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
.map((field) => jsValueToSqlValue(record[field.name]));
|
|
264
|
+
const updateFields = this.fieldsForUpdate(record);
|
|
265
|
+
if (updateFields.length === 0) {
|
|
266
|
+
return record;
|
|
267
|
+
}
|
|
268
|
+
const fields = updateFields.map((field) => `"${field.name}" = ?`).join(",\n");
|
|
269
|
+
const values = updateFields.map((field) => jsValueToSqlValue(record[field.name]));
|
|
278
270
|
const sql = [
|
|
279
271
|
`UPDATE "${this.tableName}"`,
|
|
280
272
|
`SET ${fields}`,
|
|
@@ -299,6 +291,40 @@ class SQLDataSource {
|
|
|
299
291
|
const sql = `DELETE FROM "${this.tableName}"`;
|
|
300
292
|
await this.db.exec(sql, []);
|
|
301
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Validate `record` and copy Zod defaults onto missing keys so NOT NULL
|
|
296
|
+
* columns (for example `accessLevel`) are written on insert.
|
|
297
|
+
*/
|
|
298
|
+
applySchemaDefaults(record) {
|
|
299
|
+
let parsed;
|
|
300
|
+
try {
|
|
301
|
+
parsed = this.schema.parse(record);
|
|
302
|
+
}
|
|
303
|
+
catch (e) {
|
|
304
|
+
throw new Error(`Validation on insert failed for ${this.tableName}: ${e}`);
|
|
305
|
+
}
|
|
306
|
+
const writable = record;
|
|
307
|
+
for (const field of this.metaData.fields) {
|
|
308
|
+
if (writable[field.name] === undefined && parsed[field.name] !== undefined) {
|
|
309
|
+
writable[field.name] = parsed[field.name];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Columns to SET on update. Required fields that are missing are omitted so
|
|
315
|
+
* older peers without a new column do not overwrite a local value with NULL.
|
|
316
|
+
*/
|
|
317
|
+
fieldsForUpdate(record) {
|
|
318
|
+
return this.metaData.fields.filter((field) => {
|
|
319
|
+
if (field.name === this.metaData.primaryKeyName) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
if (record[field.name] === undefined && !field.optional) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
return true;
|
|
326
|
+
});
|
|
327
|
+
}
|
|
302
328
|
initRecord(data = {}) {
|
|
303
329
|
const defaults = {};
|
|
304
330
|
for (const field of this.metaData.fields) {
|
|
@@ -323,13 +349,7 @@ class SQLDataSource {
|
|
|
323
349
|
// @ts-expect-error - need to figure out how to get typescript to understand what's going on here
|
|
324
350
|
record[this.metaData.primaryKeyName] = (0, utils_1.newid)();
|
|
325
351
|
}
|
|
326
|
-
|
|
327
|
-
try {
|
|
328
|
-
this.schema.parse(record);
|
|
329
|
-
}
|
|
330
|
-
catch (e) {
|
|
331
|
-
throw new Error(`Validation on insert failed for ${this.tableName}: ${e}`);
|
|
332
|
-
}
|
|
352
|
+
this.applySchemaDefaults(record);
|
|
333
353
|
const fields = this.metaData.fields.map((field) => `"${field.name}"`).join(", ");
|
|
334
354
|
const values = this.metaData.fields.map((field) => jsValueToSqlValue(record[field.name]));
|
|
335
355
|
const placeholders = values.map((_v) => "?").join(", ");
|
|
@@ -346,16 +366,14 @@ class SQLDataSource {
|
|
|
346
366
|
// @ts-expect-error - need to figure out how to get typescript to understand what's going on here
|
|
347
367
|
record[this.metaData.primaryKeyName] = (0, utils_1.newid)();
|
|
348
368
|
}
|
|
349
|
-
// validate data
|
|
350
369
|
this.schema.parse(record);
|
|
351
370
|
const primaryKey = record[this.metaData.primaryKeyName];
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
.map((field) => jsValueToSqlValue(record[field.name]));
|
|
371
|
+
const updateFields = this.fieldsForUpdate(record);
|
|
372
|
+
if (updateFields.length === 0) {
|
|
373
|
+
return record;
|
|
374
|
+
}
|
|
375
|
+
const fields = updateFields.map((field) => `"${field.name}" = ?`).join(",\n");
|
|
376
|
+
const values = updateFields.map((field) => jsValueToSqlValue(record[field.name]));
|
|
359
377
|
const sql = [
|
|
360
378
|
`UPDATE "${this.tableName}"`,
|
|
361
379
|
`SET ${fields}`,
|
|
@@ -205,6 +205,19 @@ describe("table", () => {
|
|
|
205
205
|
newTask.title = "Test Task";
|
|
206
206
|
expect(() => TasksTable.schema.parse(newTask)).not.toThrow();
|
|
207
207
|
});
|
|
208
|
+
it("applies schema defaults on insert and preserves required fields on partial update", async () => {
|
|
209
|
+
const inserted = await TasksTable.insert({ title: "Defaulted body" });
|
|
210
|
+
expect(inserted.body).toBe("");
|
|
211
|
+
const stored = await TasksTable.get(inserted.taskId);
|
|
212
|
+
expect(stored?.body).toBe("");
|
|
213
|
+
await TasksTable.update({
|
|
214
|
+
taskId: inserted.taskId,
|
|
215
|
+
title: "Renamed",
|
|
216
|
+
});
|
|
217
|
+
const afterUpdate = await TasksTable.get(inserted.taskId);
|
|
218
|
+
expect(afterUpdate?.title).toBe("Renamed");
|
|
219
|
+
expect(afterUpdate?.body).toBe("");
|
|
220
|
+
});
|
|
208
221
|
afterAll(async () => {
|
|
209
222
|
await TasksTable.dropTableIfExists();
|
|
210
223
|
await TasksTable.db.close();
|
|
@@ -7,6 +7,7 @@ const SQLiteDB = require("better-sqlite3");
|
|
|
7
7
|
const user_context_1 = require("../context/user-context");
|
|
8
8
|
const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
9
9
|
const utils_1 = require("../utils");
|
|
10
|
+
const access_level_1 = require("./access-level");
|
|
10
11
|
const assistants_1 = require("./assistants");
|
|
11
12
|
const group_member_roles_1 = require("./group-member-roles");
|
|
12
13
|
const groups_1 = require("./groups");
|
|
@@ -375,6 +376,7 @@ describe("resolveDevicePackageVersion — expected behavior (control)", () => {
|
|
|
375
376
|
const savedAssistant = await (0, assistants_1.Assistants)(dc).get(testAssistantId);
|
|
376
377
|
expect(savedAssistant).toBeDefined();
|
|
377
378
|
expect(savedAssistant?.name).toBe("Upgrade Test Assistant");
|
|
379
|
+
expect(savedAssistant?.accessLevel).toBe(access_level_1.DEFAULT_ACCESS_LEVEL);
|
|
378
380
|
const savedWorkflow = await (0, workflows_1.Workflows)(dc).get(testWorkflowId);
|
|
379
381
|
expect(savedWorkflow).toBeDefined();
|
|
380
382
|
expect(savedWorkflow?.name).toBe("Upgrade Test Workflow");
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { DataContext } from "../context/data-context";
|
|
3
|
+
/** Lifecycle of a tool-access approval request or reusable grant. */
|
|
4
|
+
export declare enum ToolAccessApprovalStatus {
|
|
5
|
+
pending = "pending",
|
|
6
|
+
approved = "approved",
|
|
7
|
+
executed = "executed",
|
|
8
|
+
rejected = "rejected",
|
|
9
|
+
expired = "expired",
|
|
10
|
+
failed = "failed"
|
|
11
|
+
}
|
|
12
|
+
/** How far a granted approval applies after the first execution. */
|
|
13
|
+
export declare enum ToolAccessApprovalScope {
|
|
14
|
+
once = "once",
|
|
15
|
+
thread = "thread",
|
|
16
|
+
context = "context"
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Local-only record of a step-up tool approval.
|
|
20
|
+
*
|
|
21
|
+
* Stores identifiers, a frozen argument hash, and sanitized preview text.
|
|
22
|
+
* Do not put secrets, tokens, or raw log bodies in this table.
|
|
23
|
+
*/
|
|
24
|
+
export declare const toolAccessApprovalSchema: z.ZodObject<{
|
|
25
|
+
toolAccessApprovalId: z.ZodEffects<z.ZodString, string, string>;
|
|
26
|
+
userId: z.ZodEffects<z.ZodString, string, string>;
|
|
27
|
+
assistantId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
28
|
+
toolId: z.ZodEffects<z.ZodString, string, string>;
|
|
29
|
+
toolName: z.ZodString;
|
|
30
|
+
dataContextId: z.ZodString;
|
|
31
|
+
workflowRunId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
32
|
+
threadMessageId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
33
|
+
workflowLogId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
34
|
+
argsHash: z.ZodString;
|
|
35
|
+
argsPreview: z.ZodDefault<z.ZodString>;
|
|
36
|
+
frozenArgs: z.ZodObject<{}, "strip", z.ZodAny, z.objectOutputType<{}, z.ZodAny, "strip">, z.objectInputType<{}, z.ZodAny, "strip">>;
|
|
37
|
+
requiredAccessLevel: z.ZodDefault<z.ZodNumber>;
|
|
38
|
+
scope: z.ZodDefault<z.ZodNativeEnum<typeof ToolAccessApprovalScope>>;
|
|
39
|
+
status: z.ZodDefault<z.ZodNativeEnum<typeof ToolAccessApprovalStatus>>;
|
|
40
|
+
nonce: z.ZodString;
|
|
41
|
+
expiresAt: z.ZodDate;
|
|
42
|
+
createdAt: z.ZodDefault<z.ZodDate>;
|
|
43
|
+
decidedAt: z.ZodOptional<z.ZodDate>;
|
|
44
|
+
executedAt: z.ZodOptional<z.ZodDate>;
|
|
45
|
+
resultSummary: z.ZodOptional<z.ZodString>;
|
|
46
|
+
}, "strip", z.ZodTypeAny, {
|
|
47
|
+
nonce: string;
|
|
48
|
+
status: ToolAccessApprovalStatus;
|
|
49
|
+
scope: ToolAccessApprovalScope;
|
|
50
|
+
userId: string;
|
|
51
|
+
expiresAt: Date;
|
|
52
|
+
toolId: string;
|
|
53
|
+
createdAt: Date;
|
|
54
|
+
dataContextId: string;
|
|
55
|
+
toolAccessApprovalId: string;
|
|
56
|
+
toolName: string;
|
|
57
|
+
argsHash: string;
|
|
58
|
+
argsPreview: string;
|
|
59
|
+
frozenArgs: {} & {
|
|
60
|
+
[k: string]: any;
|
|
61
|
+
};
|
|
62
|
+
requiredAccessLevel: number;
|
|
63
|
+
assistantId?: string | undefined;
|
|
64
|
+
threadMessageId?: string | undefined;
|
|
65
|
+
workflowRunId?: string | undefined;
|
|
66
|
+
workflowLogId?: string | undefined;
|
|
67
|
+
decidedAt?: Date | undefined;
|
|
68
|
+
executedAt?: Date | undefined;
|
|
69
|
+
resultSummary?: string | undefined;
|
|
70
|
+
}, {
|
|
71
|
+
nonce: string;
|
|
72
|
+
userId: string;
|
|
73
|
+
expiresAt: Date;
|
|
74
|
+
toolId: string;
|
|
75
|
+
dataContextId: string;
|
|
76
|
+
toolAccessApprovalId: string;
|
|
77
|
+
toolName: string;
|
|
78
|
+
argsHash: string;
|
|
79
|
+
frozenArgs: {} & {
|
|
80
|
+
[k: string]: any;
|
|
81
|
+
};
|
|
82
|
+
status?: ToolAccessApprovalStatus | undefined;
|
|
83
|
+
scope?: ToolAccessApprovalScope | undefined;
|
|
84
|
+
assistantId?: string | undefined;
|
|
85
|
+
createdAt?: Date | undefined;
|
|
86
|
+
threadMessageId?: string | undefined;
|
|
87
|
+
workflowRunId?: string | undefined;
|
|
88
|
+
workflowLogId?: string | undefined;
|
|
89
|
+
argsPreview?: string | undefined;
|
|
90
|
+
requiredAccessLevel?: number | undefined;
|
|
91
|
+
decidedAt?: Date | undefined;
|
|
92
|
+
executedAt?: Date | undefined;
|
|
93
|
+
resultSummary?: string | undefined;
|
|
94
|
+
}>;
|
|
95
|
+
/** A local-only tool-access approval or grant. */
|
|
96
|
+
export type IToolAccessApproval = z.infer<typeof toolAccessApprovalSchema>;
|
|
97
|
+
/**
|
|
98
|
+
* Accessor for the local-only {@link ToolAccessApprovals} table.
|
|
99
|
+
*
|
|
100
|
+
* @param dataContext - Optional data context; defaults to the current singleton.
|
|
101
|
+
*/
|
|
102
|
+
export declare function ToolAccessApprovals(dataContext?: DataContext): import("..").Table<{
|
|
103
|
+
nonce: string;
|
|
104
|
+
status: ToolAccessApprovalStatus;
|
|
105
|
+
scope: ToolAccessApprovalScope;
|
|
106
|
+
userId: string;
|
|
107
|
+
expiresAt: Date;
|
|
108
|
+
toolId: string;
|
|
109
|
+
createdAt: Date;
|
|
110
|
+
dataContextId: string;
|
|
111
|
+
toolAccessApprovalId: string;
|
|
112
|
+
toolName: string;
|
|
113
|
+
argsHash: string;
|
|
114
|
+
argsPreview: string;
|
|
115
|
+
frozenArgs: {} & {
|
|
116
|
+
[k: string]: any;
|
|
117
|
+
};
|
|
118
|
+
requiredAccessLevel: number;
|
|
119
|
+
assistantId?: string | undefined;
|
|
120
|
+
threadMessageId?: string | undefined;
|
|
121
|
+
workflowRunId?: string | undefined;
|
|
122
|
+
workflowLogId?: string | undefined;
|
|
123
|
+
decidedAt?: Date | undefined;
|
|
124
|
+
executedAt?: Date | undefined;
|
|
125
|
+
resultSummary?: string | undefined;
|
|
126
|
+
}>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toolAccessApprovalSchema = exports.ToolAccessApprovalScope = exports.ToolAccessApprovalStatus = void 0;
|
|
4
|
+
exports.ToolAccessApprovals = ToolAccessApprovals;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
7
|
+
const zod_types_1 = require("../types/zod-types");
|
|
8
|
+
const access_level_1 = require("./access-level");
|
|
9
|
+
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
10
|
+
const types_1 = require("./orm/types");
|
|
11
|
+
/** Lifecycle of a tool-access approval request or reusable grant. */
|
|
12
|
+
var ToolAccessApprovalStatus;
|
|
13
|
+
(function (ToolAccessApprovalStatus) {
|
|
14
|
+
ToolAccessApprovalStatus["pending"] = "pending";
|
|
15
|
+
ToolAccessApprovalStatus["approved"] = "approved";
|
|
16
|
+
ToolAccessApprovalStatus["executed"] = "executed";
|
|
17
|
+
ToolAccessApprovalStatus["rejected"] = "rejected";
|
|
18
|
+
ToolAccessApprovalStatus["expired"] = "expired";
|
|
19
|
+
ToolAccessApprovalStatus["failed"] = "failed";
|
|
20
|
+
})(ToolAccessApprovalStatus || (exports.ToolAccessApprovalStatus = ToolAccessApprovalStatus = {}));
|
|
21
|
+
/** How far a granted approval applies after the first execution. */
|
|
22
|
+
var ToolAccessApprovalScope;
|
|
23
|
+
(function (ToolAccessApprovalScope) {
|
|
24
|
+
ToolAccessApprovalScope["once"] = "once";
|
|
25
|
+
ToolAccessApprovalScope["thread"] = "thread";
|
|
26
|
+
ToolAccessApprovalScope["context"] = "context";
|
|
27
|
+
})(ToolAccessApprovalScope || (exports.ToolAccessApprovalScope = ToolAccessApprovalScope = {}));
|
|
28
|
+
/**
|
|
29
|
+
* Local-only record of a step-up tool approval.
|
|
30
|
+
*
|
|
31
|
+
* Stores identifiers, a frozen argument hash, and sanitized preview text.
|
|
32
|
+
* Do not put secrets, tokens, or raw log bodies in this table.
|
|
33
|
+
*/
|
|
34
|
+
exports.toolAccessApprovalSchema = zod_1.z.object({
|
|
35
|
+
toolAccessApprovalId: zod_types_1.zodPeerId,
|
|
36
|
+
userId: zod_types_1.zodPeerId.describe("User who must approve and who requested the elevation"),
|
|
37
|
+
assistantId: zod_types_1.zodPeerId
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Assistant that requested the tool; omitted for direct user calls"),
|
|
40
|
+
toolId: zod_types_1.zodPeerId,
|
|
41
|
+
toolName: zod_1.z.string().describe("Display name of the tool at request time"),
|
|
42
|
+
dataContextId: zod_1.z.string().describe("Data context the tool would run in"),
|
|
43
|
+
workflowRunId: zod_types_1.zodPeerId.optional(),
|
|
44
|
+
threadMessageId: zod_types_1.zodPeerId
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("User message / thread root that owns the workflow"),
|
|
47
|
+
workflowLogId: zod_types_1.zodPeerId.optional(),
|
|
48
|
+
argsHash: zod_1.z.string().describe("Canonical hash of the frozen tool arguments"),
|
|
49
|
+
argsPreview: zod_1.z
|
|
50
|
+
.string()
|
|
51
|
+
.default("")
|
|
52
|
+
.describe("Sanitized, truncated argument summary for the approval card"),
|
|
53
|
+
frozenArgs: zod_types_1.zodAnyObject.describe("Frozen arguments executed on approve; no secrets"),
|
|
54
|
+
requiredAccessLevel: access_level_1.accessLevelSchema,
|
|
55
|
+
scope: zod_1.z.nativeEnum(ToolAccessApprovalScope).default(ToolAccessApprovalScope.once),
|
|
56
|
+
status: zod_1.z.nativeEnum(ToolAccessApprovalStatus).default(ToolAccessApprovalStatus.pending),
|
|
57
|
+
nonce: zod_1.z.string().describe("Single-use token; empty after consume"),
|
|
58
|
+
expiresAt: zod_1.z.date(),
|
|
59
|
+
createdAt: zod_1.z.date().default(() => new Date()),
|
|
60
|
+
decidedAt: zod_1.z.date().optional(),
|
|
61
|
+
executedAt: zod_1.z.date().optional(),
|
|
62
|
+
resultSummary: zod_1.z.string().optional().describe("Sanitized outcome after execute or deny"),
|
|
63
|
+
});
|
|
64
|
+
const metaData = {
|
|
65
|
+
name: "ToolAccessApprovals",
|
|
66
|
+
description: "Local-only pending and granted step-up approvals for privileged tools.",
|
|
67
|
+
primaryKeyName: "toolAccessApprovalId",
|
|
68
|
+
fields: (0, types_1.schemaToFields)(exports.toolAccessApprovalSchema),
|
|
69
|
+
iconClassName: "bi bi-shield-lock",
|
|
70
|
+
localOnly: true,
|
|
71
|
+
indexes: [
|
|
72
|
+
{ fields: ["threadMessageId"] },
|
|
73
|
+
{ fields: ["workflowRunId"] },
|
|
74
|
+
{ fields: ["status"] },
|
|
75
|
+
{ fields: ["toolId"] },
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.toolAccessApprovalSchema);
|
|
79
|
+
/**
|
|
80
|
+
* Accessor for the local-only {@link ToolAccessApprovals} table.
|
|
81
|
+
*
|
|
82
|
+
* @param dataContext - Optional data context; defaults to the current singleton.
|
|
83
|
+
*/
|
|
84
|
+
function ToolAccessApprovals(dataContext) {
|
|
85
|
+
return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, exports.toolAccessApprovalSchema);
|
|
86
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/** Workflow-run var naming the Assistant whose delegated authority applies. */
|
|
2
|
+
export declare const ACCESS_ASSISTANT_ID_VAR = "accessAssistantId";
|
|
3
|
+
/** Workflow-run var used as a display / fallback Assistant id. */
|
|
4
|
+
export declare const ASSISTANT_ID_VAR = "assistantId";
|
|
5
|
+
/** Workflow-run var set when the user invoked a tool directly (CLI/UI/RPC). */
|
|
6
|
+
export declare const DIRECT_USER_INVOCATION_VAR = "directUserInvocation";
|
|
7
|
+
/** Workflow-run var pointing at a host-consumed approval that authorizes this run. */
|
|
8
|
+
export declare const HOST_APPROVED_APPROVAL_ID_VAR = "hostApprovedApprovalId";
|
|
9
|
+
/**
|
|
10
|
+
* Host-owned access keys. Models must not set these via `set-variable` or
|
|
11
|
+
* `run-a-workflow` child vars.
|
|
12
|
+
*/
|
|
13
|
+
export declare const RESERVED_ACCESS_VAR_KEYS: readonly ["accessAssistantId", "assistantId", "directUserInvocation", "hostApprovedApprovalId"];
|
|
14
|
+
/** How long a pending approval stays actionable. */
|
|
15
|
+
export declare const TOOL_ACCESS_APPROVAL_TTL_MS: number;
|
|
16
|
+
/** How long an approved thread- or context-scoped grant remains reusable. */
|
|
17
|
+
export declare const TOOL_ACCESS_GRANT_TTL_MS: number;
|
|
18
|
+
/** Outcome of {@link decideToolAccess}. */
|
|
19
|
+
export type ToolAccessDecision = {
|
|
20
|
+
kind: "allow";
|
|
21
|
+
} | {
|
|
22
|
+
kind: "deny";
|
|
23
|
+
reason: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "approval_required";
|
|
26
|
+
reason: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Decide whether a tool may run automatically, needs step-up approval, or is denied.
|
|
30
|
+
*
|
|
31
|
+
* Policy (`U` user, `A` Assistant, `T` tool):
|
|
32
|
+
* - Direct user invocation: allow when `T <= U`, otherwise deny.
|
|
33
|
+
* - Assistant invocation: deny when `T > U`; allow when `T <= A` or a matching
|
|
34
|
+
* grant exists; require approval when `A < T <= U`.
|
|
35
|
+
*
|
|
36
|
+
* @param args.userAccessLevel - Current user's group/personal access.
|
|
37
|
+
* @param args.toolAccessLevel - Required level declared on the tool.
|
|
38
|
+
* @param args.assistantAccessLevel - Assistant delegated level; omit for direct user calls.
|
|
39
|
+
* @param args.hasMatchingGrant - True when a reusable scoped grant already covers this call.
|
|
40
|
+
*/
|
|
41
|
+
export declare function decideToolAccess(args: {
|
|
42
|
+
userAccessLevel: number;
|
|
43
|
+
toolAccessLevel: number;
|
|
44
|
+
assistantAccessLevel?: number;
|
|
45
|
+
hasMatchingGrant?: boolean;
|
|
46
|
+
}): ToolAccessDecision;
|
|
47
|
+
/**
|
|
48
|
+
* Return whether a user may invoke an Assistant in the current context.
|
|
49
|
+
*
|
|
50
|
+
* @param userAccessLevel - Current user's access.
|
|
51
|
+
* @param assistantAccessLevel - Assistant minimum / delegated level.
|
|
52
|
+
*/
|
|
53
|
+
export declare function canInvokeAssistant(userAccessLevel: number, assistantAccessLevel: number): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Canonical hash of tool arguments used to bind one-time approvals.
|
|
56
|
+
*
|
|
57
|
+
* @param args - Tool input object; `undefined` hashes as an empty object.
|
|
58
|
+
*/
|
|
59
|
+
export declare function hashToolArgs(args: Record<string, unknown> | undefined): string;
|
|
60
|
+
/**
|
|
61
|
+
* Append the required access level to a model-facing tool description.
|
|
62
|
+
*
|
|
63
|
+
* @param usageDescription - Existing tool usage text.
|
|
64
|
+
* @param accessLevel - Required level, already resolved or raw.
|
|
65
|
+
*/
|
|
66
|
+
export declare function annotateToolAccessDescription(usageDescription: string, accessLevel: unknown): string;
|
|
67
|
+
/**
|
|
68
|
+
* Return the fail-closed access level for a record that may omit the field.
|
|
69
|
+
*
|
|
70
|
+
* @param record - Tool or Assistant-like object.
|
|
71
|
+
*/
|
|
72
|
+
export declare function recordAccessLevel(record: {
|
|
73
|
+
accessLevel?: unknown;
|
|
74
|
+
} | undefined): number;
|
|
75
|
+
/**
|
|
76
|
+
* Choose the delegated Assistant ceiling for a run.
|
|
77
|
+
*
|
|
78
|
+
* Direct user calls have no Assistant ceiling (`undefined`). Otherwise only
|
|
79
|
+
* levels from existing Assistant records are considered; a missing record
|
|
80
|
+
* does not default to Self. When both an access-assistant and the run default
|
|
81
|
+
* resolve, the lower level wins so vars cannot escalate past the host-owned
|
|
82
|
+
* default Assistant.
|
|
83
|
+
*
|
|
84
|
+
* @returns `undefined` for direct user calls; otherwise 0–100 (`0` if none resolve).
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveDelegatedAccessLevel(args: {
|
|
87
|
+
directUser: boolean;
|
|
88
|
+
accessAssistantLevel?: number;
|
|
89
|
+
defaultAssistantLevel?: number;
|
|
90
|
+
}): number | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Return whether `name` is a host-owned access-control workflow var.
|
|
93
|
+
*
|
|
94
|
+
* @param name - Candidate variable name.
|
|
95
|
+
*/
|
|
96
|
+
export declare function isReservedAccessVarName(name: string): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Return the thread root id for a message: its parent, or itself if it is the root.
|
|
99
|
+
*
|
|
100
|
+
* Thread-scoped grants must key off this id so a follow-up reply in the same
|
|
101
|
+
* thread matches the original approval.
|
|
102
|
+
*
|
|
103
|
+
* @param message - Message or message-like object; `undefined` returns `undefined`.
|
|
104
|
+
*/
|
|
105
|
+
export declare function threadRootMessageId(message: {
|
|
106
|
+
messageId?: string;
|
|
107
|
+
messageParentId?: string;
|
|
108
|
+
} | undefined): string | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Structured result returned to a model when a tool needs user approval.
|
|
111
|
+
*/
|
|
112
|
+
export interface IToolAccessApprovalRequiredResult {
|
|
113
|
+
status: "approval_required";
|
|
114
|
+
approvalId: string;
|
|
115
|
+
toolId: string;
|
|
116
|
+
toolName: string;
|
|
117
|
+
requiredAccessLevel: number;
|
|
118
|
+
requiredAccessLabel: string;
|
|
119
|
+
message: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build the model-visible payload for a pending approval.
|
|
123
|
+
*/
|
|
124
|
+
export declare function approvalRequiredResult(args: {
|
|
125
|
+
approvalId: string;
|
|
126
|
+
toolId: string;
|
|
127
|
+
toolName: string;
|
|
128
|
+
requiredAccessLevel: number;
|
|
129
|
+
message: string;
|
|
130
|
+
}): IToolAccessApprovalRequiredResult;
|
|
131
|
+
/** Workflow plumbing / assistant-runner tools that must not block invocation. */
|
|
132
|
+
export declare const INFRASTRUCTURE_ACCESS_LEVEL: 0;
|
|
133
|
+
/**
|
|
134
|
+
* Remove one-shot host access tickets from a vars object.
|
|
135
|
+
*
|
|
136
|
+
* `directUserInvocation` and `hostApprovedApprovalId` authorize a single
|
|
137
|
+
* workflow run. Persisting them on a thread message lets later calls reuse a
|
|
138
|
+
* once-approval or skip Assistant-level checks.
|
|
139
|
+
*
|
|
140
|
+
* @param vars - Workflow or message vars; `undefined` becomes `{}`.
|
|
141
|
+
*/
|
|
142
|
+
export declare function omitEphemeralAccessVars(vars: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
143
|
+
/**
|
|
144
|
+
* Strip every host-owned access key, including Assistant identity vars.
|
|
145
|
+
*
|
|
146
|
+
* Use this before showing vars to a model or copying caller-supplied child
|
|
147
|
+
* vars onto a nested run.
|
|
148
|
+
*
|
|
149
|
+
* @param vars - Workflow or message vars; `undefined` becomes `{}`.
|
|
150
|
+
*/
|
|
151
|
+
export declare function omitReservedAccessVars(vars: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
152
|
+
/**
|
|
153
|
+
* Copy access-authority vars onto a child workflow so nested runs cannot escalate.
|
|
154
|
+
*
|
|
155
|
+
* Caller-supplied reserved keys are stripped. The child keeps the parent's
|
|
156
|
+
* Assistant id and whether the *parent* was a direct user invocation.
|
|
157
|
+
*
|
|
158
|
+
* @param parentVars - Parent workflow vars.
|
|
159
|
+
* @param parentDefaultAssistantId - Parent run's default Assistant.
|
|
160
|
+
* @param childVars - Vars about to be stored on the child.
|
|
161
|
+
*/
|
|
162
|
+
export declare function inheritAccessVars(parentVars: Record<string, unknown> | undefined, parentDefaultAssistantId: string | undefined, childVars: Record<string, unknown>): Record<string, unknown>;
|