@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
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.INFRASTRUCTURE_ACCESS_LEVEL = exports.TOOL_ACCESS_GRANT_TTL_MS = exports.TOOL_ACCESS_APPROVAL_TTL_MS = exports.RESERVED_ACCESS_VAR_KEYS = exports.HOST_APPROVED_APPROVAL_ID_VAR = exports.DIRECT_USER_INVOCATION_VAR = exports.ASSISTANT_ID_VAR = exports.ACCESS_ASSISTANT_ID_VAR = void 0;
|
|
4
|
+
exports.decideToolAccess = decideToolAccess;
|
|
5
|
+
exports.canInvokeAssistant = canInvokeAssistant;
|
|
6
|
+
exports.hashToolArgs = hashToolArgs;
|
|
7
|
+
exports.annotateToolAccessDescription = annotateToolAccessDescription;
|
|
8
|
+
exports.recordAccessLevel = recordAccessLevel;
|
|
9
|
+
exports.resolveDelegatedAccessLevel = resolveDelegatedAccessLevel;
|
|
10
|
+
exports.isReservedAccessVarName = isReservedAccessVarName;
|
|
11
|
+
exports.threadRootMessageId = threadRootMessageId;
|
|
12
|
+
exports.approvalRequiredResult = approvalRequiredResult;
|
|
13
|
+
exports.omitEphemeralAccessVars = omitEphemeralAccessVars;
|
|
14
|
+
exports.omitReservedAccessVars = omitReservedAccessVars;
|
|
15
|
+
exports.inheritAccessVars = inheritAccessVars;
|
|
16
|
+
const keys_1 = require("../keys");
|
|
17
|
+
const access_level_1 = require("./access-level");
|
|
18
|
+
/** Workflow-run var naming the Assistant whose delegated authority applies. */
|
|
19
|
+
exports.ACCESS_ASSISTANT_ID_VAR = "accessAssistantId";
|
|
20
|
+
/** Workflow-run var used as a display / fallback Assistant id. */
|
|
21
|
+
exports.ASSISTANT_ID_VAR = "assistantId";
|
|
22
|
+
/** Workflow-run var set when the user invoked a tool directly (CLI/UI/RPC). */
|
|
23
|
+
exports.DIRECT_USER_INVOCATION_VAR = "directUserInvocation";
|
|
24
|
+
/** Workflow-run var pointing at a host-consumed approval that authorizes this run. */
|
|
25
|
+
exports.HOST_APPROVED_APPROVAL_ID_VAR = "hostApprovedApprovalId";
|
|
26
|
+
/**
|
|
27
|
+
* Host-owned access keys. Models must not set these via `set-variable` or
|
|
28
|
+
* `run-a-workflow` child vars.
|
|
29
|
+
*/
|
|
30
|
+
exports.RESERVED_ACCESS_VAR_KEYS = [
|
|
31
|
+
exports.ACCESS_ASSISTANT_ID_VAR,
|
|
32
|
+
exports.ASSISTANT_ID_VAR,
|
|
33
|
+
exports.DIRECT_USER_INVOCATION_VAR,
|
|
34
|
+
exports.HOST_APPROVED_APPROVAL_ID_VAR,
|
|
35
|
+
];
|
|
36
|
+
/** How long a pending approval stays actionable. */
|
|
37
|
+
exports.TOOL_ACCESS_APPROVAL_TTL_MS = 15 * 60 * 1000;
|
|
38
|
+
/** How long an approved thread- or context-scoped grant remains reusable. */
|
|
39
|
+
exports.TOOL_ACCESS_GRANT_TTL_MS = 15 * 60 * 1000;
|
|
40
|
+
/**
|
|
41
|
+
* Decide whether a tool may run automatically, needs step-up approval, or is denied.
|
|
42
|
+
*
|
|
43
|
+
* Policy (`U` user, `A` Assistant, `T` tool):
|
|
44
|
+
* - Direct user invocation: allow when `T <= U`, otherwise deny.
|
|
45
|
+
* - Assistant invocation: deny when `T > U`; allow when `T <= A` or a matching
|
|
46
|
+
* grant exists; require approval when `A < T <= U`.
|
|
47
|
+
*
|
|
48
|
+
* @param args.userAccessLevel - Current user's group/personal access.
|
|
49
|
+
* @param args.toolAccessLevel - Required level declared on the tool.
|
|
50
|
+
* @param args.assistantAccessLevel - Assistant delegated level; omit for direct user calls.
|
|
51
|
+
* @param args.hasMatchingGrant - True when a reusable scoped grant already covers this call.
|
|
52
|
+
*/
|
|
53
|
+
function decideToolAccess(args) {
|
|
54
|
+
const userAccessLevel = (0, access_level_1.resolveAccessLevel)(args.userAccessLevel);
|
|
55
|
+
const toolAccessLevel = (0, access_level_1.resolveAccessLevel)(args.toolAccessLevel);
|
|
56
|
+
const toolLabel = `${(0, access_level_1.getAccessLevelLabel)(toolAccessLevel)} (${toolAccessLevel})`;
|
|
57
|
+
const userLabel = `${(0, access_level_1.getAccessLevelLabel)(userAccessLevel)} (${userAccessLevel})`;
|
|
58
|
+
if (toolAccessLevel > userAccessLevel) {
|
|
59
|
+
return {
|
|
60
|
+
kind: "deny",
|
|
61
|
+
reason: `Tool requires ${toolLabel}, but the current user has ${userLabel}.`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (args.assistantAccessLevel == null) {
|
|
65
|
+
return { kind: "allow" };
|
|
66
|
+
}
|
|
67
|
+
const assistantAccessLevel = (0, access_level_1.resolveAccessLevel)(args.assistantAccessLevel);
|
|
68
|
+
if (args.hasMatchingGrant || toolAccessLevel <= assistantAccessLevel) {
|
|
69
|
+
return { kind: "allow" };
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
kind: "approval_required",
|
|
73
|
+
reason: `Tool requires ${toolLabel}. ${(0, access_level_1.getAccessLevelLabel)(assistantAccessLevel)} (${assistantAccessLevel}) can request it; ${userLabel} must approve.`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Return whether a user may invoke an Assistant in the current context.
|
|
78
|
+
*
|
|
79
|
+
* @param userAccessLevel - Current user's access.
|
|
80
|
+
* @param assistantAccessLevel - Assistant minimum / delegated level.
|
|
81
|
+
*/
|
|
82
|
+
function canInvokeAssistant(userAccessLevel, assistantAccessLevel) {
|
|
83
|
+
return (0, access_level_1.resolveAccessLevel)(userAccessLevel) >= (0, access_level_1.resolveAccessLevel)(assistantAccessLevel);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Canonical hash of tool arguments used to bind one-time approvals.
|
|
87
|
+
*
|
|
88
|
+
* @param args - Tool input object; `undefined` hashes as an empty object.
|
|
89
|
+
*/
|
|
90
|
+
function hashToolArgs(args) {
|
|
91
|
+
return (0, keys_1.hashObject)(args && typeof args === "object" && !Array.isArray(args) ? args : {});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Append the required access level to a model-facing tool description.
|
|
95
|
+
*
|
|
96
|
+
* @param usageDescription - Existing tool usage text.
|
|
97
|
+
* @param accessLevel - Required level, already resolved or raw.
|
|
98
|
+
*/
|
|
99
|
+
function annotateToolAccessDescription(usageDescription, accessLevel) {
|
|
100
|
+
const level = (0, access_level_1.resolveAccessLevel)(accessLevel);
|
|
101
|
+
const annotation = `Required access level: ${(0, access_level_1.getAccessLevelLabel)(level)} (${level}).`;
|
|
102
|
+
if (usageDescription.includes("Required access level:")) {
|
|
103
|
+
return usageDescription;
|
|
104
|
+
}
|
|
105
|
+
return `${usageDescription}\n\n${annotation}`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Return the fail-closed access level for a record that may omit the field.
|
|
109
|
+
*
|
|
110
|
+
* @param record - Tool or Assistant-like object.
|
|
111
|
+
*/
|
|
112
|
+
function recordAccessLevel(record) {
|
|
113
|
+
return record?.accessLevel == null
|
|
114
|
+
? access_level_1.DEFAULT_ACCESS_LEVEL
|
|
115
|
+
: (0, access_level_1.resolveAccessLevel)(record.accessLevel);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Choose the delegated Assistant ceiling for a run.
|
|
119
|
+
*
|
|
120
|
+
* Direct user calls have no Assistant ceiling (`undefined`). Otherwise only
|
|
121
|
+
* levels from existing Assistant records are considered; a missing record
|
|
122
|
+
* does not default to Self. When both an access-assistant and the run default
|
|
123
|
+
* resolve, the lower level wins so vars cannot escalate past the host-owned
|
|
124
|
+
* default Assistant.
|
|
125
|
+
*
|
|
126
|
+
* @returns `undefined` for direct user calls; otherwise 0–100 (`0` if none resolve).
|
|
127
|
+
*/
|
|
128
|
+
function resolveDelegatedAccessLevel(args) {
|
|
129
|
+
if (args.directUser) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
const levels = [];
|
|
133
|
+
if (args.accessAssistantLevel != null) {
|
|
134
|
+
levels.push((0, access_level_1.resolveAccessLevel)(args.accessAssistantLevel));
|
|
135
|
+
}
|
|
136
|
+
if (args.defaultAssistantLevel != null) {
|
|
137
|
+
levels.push((0, access_level_1.resolveAccessLevel)(args.defaultAssistantLevel));
|
|
138
|
+
}
|
|
139
|
+
if (levels.length === 0) {
|
|
140
|
+
return access_level_1.AccessLevel.None;
|
|
141
|
+
}
|
|
142
|
+
return Math.min(...levels);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Return whether `name` is a host-owned access-control workflow var.
|
|
146
|
+
*
|
|
147
|
+
* @param name - Candidate variable name.
|
|
148
|
+
*/
|
|
149
|
+
function isReservedAccessVarName(name) {
|
|
150
|
+
return exports.RESERVED_ACCESS_VAR_KEYS.includes(name);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Return the thread root id for a message: its parent, or itself if it is the root.
|
|
154
|
+
*
|
|
155
|
+
* Thread-scoped grants must key off this id so a follow-up reply in the same
|
|
156
|
+
* thread matches the original approval.
|
|
157
|
+
*
|
|
158
|
+
* @param message - Message or message-like object; `undefined` returns `undefined`.
|
|
159
|
+
*/
|
|
160
|
+
function threadRootMessageId(message) {
|
|
161
|
+
if (!message) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
return message.messageParentId || message.messageId;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build the model-visible payload for a pending approval.
|
|
168
|
+
*/
|
|
169
|
+
function approvalRequiredResult(args) {
|
|
170
|
+
return {
|
|
171
|
+
status: "approval_required",
|
|
172
|
+
approvalId: args.approvalId,
|
|
173
|
+
toolId: args.toolId,
|
|
174
|
+
toolName: args.toolName,
|
|
175
|
+
requiredAccessLevel: args.requiredAccessLevel,
|
|
176
|
+
requiredAccessLabel: (0, access_level_1.getAccessLevelLabel)(args.requiredAccessLevel),
|
|
177
|
+
message: args.message,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/** Workflow plumbing / assistant-runner tools that must not block invocation. */
|
|
181
|
+
exports.INFRASTRUCTURE_ACCESS_LEVEL = access_level_1.AccessLevel.None;
|
|
182
|
+
/**
|
|
183
|
+
* Remove one-shot host access tickets from a vars object.
|
|
184
|
+
*
|
|
185
|
+
* `directUserInvocation` and `hostApprovedApprovalId` authorize a single
|
|
186
|
+
* workflow run. Persisting them on a thread message lets later calls reuse a
|
|
187
|
+
* once-approval or skip Assistant-level checks.
|
|
188
|
+
*
|
|
189
|
+
* @param vars - Workflow or message vars; `undefined` becomes `{}`.
|
|
190
|
+
*/
|
|
191
|
+
function omitEphemeralAccessVars(vars) {
|
|
192
|
+
if (!vars) {
|
|
193
|
+
return {};
|
|
194
|
+
}
|
|
195
|
+
const next = { ...vars };
|
|
196
|
+
delete next[exports.DIRECT_USER_INVOCATION_VAR];
|
|
197
|
+
delete next[exports.HOST_APPROVED_APPROVAL_ID_VAR];
|
|
198
|
+
return next;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Strip every host-owned access key, including Assistant identity vars.
|
|
202
|
+
*
|
|
203
|
+
* Use this before showing vars to a model or copying caller-supplied child
|
|
204
|
+
* vars onto a nested run.
|
|
205
|
+
*
|
|
206
|
+
* @param vars - Workflow or message vars; `undefined` becomes `{}`.
|
|
207
|
+
*/
|
|
208
|
+
function omitReservedAccessVars(vars) {
|
|
209
|
+
const next = omitEphemeralAccessVars(vars);
|
|
210
|
+
delete next[exports.ACCESS_ASSISTANT_ID_VAR];
|
|
211
|
+
delete next[exports.ASSISTANT_ID_VAR];
|
|
212
|
+
return next;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Copy access-authority vars onto a child workflow so nested runs cannot escalate.
|
|
216
|
+
*
|
|
217
|
+
* Caller-supplied reserved keys are stripped. The child keeps the parent's
|
|
218
|
+
* Assistant id and whether the *parent* was a direct user invocation.
|
|
219
|
+
*
|
|
220
|
+
* @param parentVars - Parent workflow vars.
|
|
221
|
+
* @param parentDefaultAssistantId - Parent run's default Assistant.
|
|
222
|
+
* @param childVars - Vars about to be stored on the child.
|
|
223
|
+
*/
|
|
224
|
+
function inheritAccessVars(parentVars, parentDefaultAssistantId, childVars) {
|
|
225
|
+
const vars = parentVars || {};
|
|
226
|
+
const parentAccessId = (typeof vars[exports.ACCESS_ASSISTANT_ID_VAR] === "string" && vars[exports.ACCESS_ASSISTANT_ID_VAR]) ||
|
|
227
|
+
(typeof vars[exports.ASSISTANT_ID_VAR] === "string" && vars[exports.ASSISTANT_ID_VAR]) ||
|
|
228
|
+
parentDefaultAssistantId;
|
|
229
|
+
return {
|
|
230
|
+
...omitReservedAccessVars(childVars),
|
|
231
|
+
[exports.ACCESS_ASSISTANT_ID_VAR]: parentAccessId,
|
|
232
|
+
[exports.ASSISTANT_ID_VAR]: parentAccessId,
|
|
233
|
+
[exports.DIRECT_USER_INVOCATION_VAR]: vars[exports.DIRECT_USER_INVOCATION_VAR] ?? false,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const access_level_1 = require("./access-level");
|
|
4
|
+
const tool_access_1 = require("./tool-access");
|
|
5
|
+
describe("decideToolAccess", () => {
|
|
6
|
+
it("allows a direct user call at or below their ceiling", () => {
|
|
7
|
+
expect((0, tool_access_1.decideToolAccess)({
|
|
8
|
+
userAccessLevel: access_level_1.AccessLevel.Self,
|
|
9
|
+
toolAccessLevel: access_level_1.AccessLevel.Admin,
|
|
10
|
+
}).kind).toBe("allow");
|
|
11
|
+
});
|
|
12
|
+
it("denies a tool above the user ceiling", () => {
|
|
13
|
+
const decision = (0, tool_access_1.decideToolAccess)({
|
|
14
|
+
userAccessLevel: access_level_1.AccessLevel.Writer,
|
|
15
|
+
toolAccessLevel: access_level_1.AccessLevel.Admin,
|
|
16
|
+
assistantAccessLevel: access_level_1.AccessLevel.Writer,
|
|
17
|
+
});
|
|
18
|
+
expect(decision.kind).toBe("deny");
|
|
19
|
+
});
|
|
20
|
+
it("allows an Assistant to run tools at or below its level", () => {
|
|
21
|
+
expect((0, tool_access_1.decideToolAccess)({
|
|
22
|
+
userAccessLevel: access_level_1.AccessLevel.Self,
|
|
23
|
+
assistantAccessLevel: access_level_1.AccessLevel.Writer,
|
|
24
|
+
toolAccessLevel: access_level_1.AccessLevel.Writer,
|
|
25
|
+
}).kind).toBe("allow");
|
|
26
|
+
});
|
|
27
|
+
it("requires approval when A < T <= U", () => {
|
|
28
|
+
const decision = (0, tool_access_1.decideToolAccess)({
|
|
29
|
+
userAccessLevel: access_level_1.AccessLevel.Self,
|
|
30
|
+
assistantAccessLevel: access_level_1.AccessLevel.Writer,
|
|
31
|
+
toolAccessLevel: access_level_1.AccessLevel.Admin,
|
|
32
|
+
});
|
|
33
|
+
expect(decision.kind).toBe("approval_required");
|
|
34
|
+
});
|
|
35
|
+
it("allows a matching grant to skip another prompt", () => {
|
|
36
|
+
expect((0, tool_access_1.decideToolAccess)({
|
|
37
|
+
userAccessLevel: access_level_1.AccessLevel.Self,
|
|
38
|
+
assistantAccessLevel: access_level_1.AccessLevel.Writer,
|
|
39
|
+
toolAccessLevel: access_level_1.AccessLevel.Admin,
|
|
40
|
+
hasMatchingGrant: true,
|
|
41
|
+
}).kind).toBe("allow");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe("canInvokeAssistant", () => {
|
|
45
|
+
it("denies users below the Assistant level", () => {
|
|
46
|
+
expect((0, tool_access_1.canInvokeAssistant)(access_level_1.AccessLevel.Writer, access_level_1.AccessLevel.Admin)).toBe(false);
|
|
47
|
+
expect((0, tool_access_1.canInvokeAssistant)(access_level_1.AccessLevel.Admin, access_level_1.AccessLevel.Admin)).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe("hashToolArgs", () => {
|
|
51
|
+
it("is stable for key order", () => {
|
|
52
|
+
expect((0, tool_access_1.hashToolArgs)({ b: 1, a: 2 })).toBe((0, tool_access_1.hashToolArgs)({ a: 2, b: 1 }));
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe("annotateToolAccessDescription", () => {
|
|
56
|
+
it("appends the required level once", () => {
|
|
57
|
+
const once = (0, tool_access_1.annotateToolAccessDescription)("Does a thing.", 40);
|
|
58
|
+
expect(once).toContain("Writer (40)");
|
|
59
|
+
expect((0, tool_access_1.annotateToolAccessDescription)(once, 40)).toBe(once);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe("recordAccessLevel", () => {
|
|
63
|
+
it("defaults missing records to 100", () => {
|
|
64
|
+
expect((0, tool_access_1.recordAccessLevel)(undefined)).toBe(100);
|
|
65
|
+
expect((0, tool_access_1.recordAccessLevel)({})).toBe(100);
|
|
66
|
+
expect((0, tool_access_1.recordAccessLevel)({ accessLevel: 20 })).toBe(20);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe("resolveDelegatedAccessLevel", () => {
|
|
70
|
+
it("omits an Assistant ceiling for direct user calls", () => {
|
|
71
|
+
expect((0, tool_access_1.resolveDelegatedAccessLevel)({
|
|
72
|
+
directUser: true,
|
|
73
|
+
accessAssistantLevel: access_level_1.AccessLevel.Writer,
|
|
74
|
+
defaultAssistantLevel: access_level_1.AccessLevel.Writer,
|
|
75
|
+
})).toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
it("takes the lower of access-assistant and default Assistant", () => {
|
|
78
|
+
expect((0, tool_access_1.resolveDelegatedAccessLevel)({
|
|
79
|
+
directUser: false,
|
|
80
|
+
accessAssistantLevel: access_level_1.AccessLevel.Admin,
|
|
81
|
+
defaultAssistantLevel: access_level_1.AccessLevel.Writer,
|
|
82
|
+
})).toBe(access_level_1.AccessLevel.Writer);
|
|
83
|
+
});
|
|
84
|
+
it("fails closed to None when no Assistant record resolved", () => {
|
|
85
|
+
expect((0, tool_access_1.resolveDelegatedAccessLevel)({ directUser: false })).toBe(access_level_1.AccessLevel.None);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe("threadRootMessageId", () => {
|
|
89
|
+
it("uses the parent when present and the message itself when it is the root", () => {
|
|
90
|
+
expect((0, tool_access_1.threadRootMessageId)({
|
|
91
|
+
messageId: "00reply0000000000000000001",
|
|
92
|
+
messageParentId: "00root00000000000000000001",
|
|
93
|
+
})).toBe("00root00000000000000000001");
|
|
94
|
+
expect((0, tool_access_1.threadRootMessageId)({ messageId: "00root00000000000000000001" })).toBe("00root00000000000000000001");
|
|
95
|
+
expect((0, tool_access_1.threadRootMessageId)(undefined)).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("isReservedAccessVarName", () => {
|
|
99
|
+
it("matches host-owned access keys only", () => {
|
|
100
|
+
expect((0, tool_access_1.isReservedAccessVarName)(tool_access_1.DIRECT_USER_INVOCATION_VAR)).toBe(true);
|
|
101
|
+
expect((0, tool_access_1.isReservedAccessVarName)(tool_access_1.ASSISTANT_ID_VAR)).toBe(true);
|
|
102
|
+
expect((0, tool_access_1.isReservedAccessVarName)("cwd")).toBe(false);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe("omitEphemeralAccessVars", () => {
|
|
106
|
+
it("strips one-shot host tickets and leaves other vars", () => {
|
|
107
|
+
expect((0, tool_access_1.omitEphemeralAccessVars)({
|
|
108
|
+
cwd: "/tmp",
|
|
109
|
+
[tool_access_1.DIRECT_USER_INVOCATION_VAR]: true,
|
|
110
|
+
[tool_access_1.HOST_APPROVED_APPROVAL_ID_VAR]: "00testapproval0000000001",
|
|
111
|
+
})).toEqual({ cwd: "/tmp" });
|
|
112
|
+
expect((0, tool_access_1.omitEphemeralAccessVars)(undefined)).toEqual({});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe("omitReservedAccessVars", () => {
|
|
116
|
+
it("strips Assistant identity as well as host tickets", () => {
|
|
117
|
+
expect((0, tool_access_1.omitReservedAccessVars)({
|
|
118
|
+
cwd: "/tmp",
|
|
119
|
+
[tool_access_1.ACCESS_ASSISTANT_ID_VAR]: "assistant-a",
|
|
120
|
+
[tool_access_1.ASSISTANT_ID_VAR]: "assistant-a",
|
|
121
|
+
[tool_access_1.DIRECT_USER_INVOCATION_VAR]: true,
|
|
122
|
+
})).toEqual({ cwd: "/tmp" });
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
describe("inheritAccessVars", () => {
|
|
126
|
+
it("copies parent authority and does not let child vars escalate", () => {
|
|
127
|
+
const inherited = (0, tool_access_1.inheritAccessVars)({ [tool_access_1.ACCESS_ASSISTANT_ID_VAR]: "assistant-a", [tool_access_1.DIRECT_USER_INVOCATION_VAR]: false }, "assistant-parent", { [tool_access_1.ACCESS_ASSISTANT_ID_VAR]: "assistant-b", [tool_access_1.DIRECT_USER_INVOCATION_VAR]: true, foo: 1 });
|
|
128
|
+
expect(inherited[tool_access_1.ACCESS_ASSISTANT_ID_VAR]).toBe("assistant-a");
|
|
129
|
+
expect(inherited[tool_access_1.ASSISTANT_ID_VAR]).toBe("assistant-a");
|
|
130
|
+
expect(inherited[tool_access_1.DIRECT_USER_INVOCATION_VAR]).toBe(false);
|
|
131
|
+
expect(inherited.foo).toBe(1);
|
|
132
|
+
});
|
|
133
|
+
it("does not copy a host-approved approval id onto the child", () => {
|
|
134
|
+
const inherited = (0, tool_access_1.inheritAccessVars)({ [tool_access_1.HOST_APPROVED_APPROVAL_ID_VAR]: "00parentapproval00000001" }, "assistant-parent", { [tool_access_1.HOST_APPROVED_APPROVAL_ID_VAR]: "00childapproval000000001", foo: 1 });
|
|
135
|
+
expect(inherited[tool_access_1.HOST_APPROVED_APPROVAL_ID_VAR]).toBeUndefined();
|
|
136
|
+
expect(inherited.foo).toBe(1);
|
|
137
|
+
});
|
|
138
|
+
it("ignores a child-supplied assistantId", () => {
|
|
139
|
+
const inherited = (0, tool_access_1.inheritAccessVars)({ [tool_access_1.ACCESS_ASSISTANT_ID_VAR]: "assistant-a" }, "assistant-parent", {
|
|
140
|
+
[tool_access_1.ASSISTANT_ID_VAR]: "assistant-admin",
|
|
141
|
+
foo: 1,
|
|
142
|
+
});
|
|
143
|
+
expect(inherited[tool_access_1.ASSISTANT_ID_VAR]).toBe("assistant-a");
|
|
144
|
+
expect(inherited[tool_access_1.ACCESS_ASSISTANT_ID_VAR]).toBe("assistant-a");
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
describe("approvalRequiredResult", () => {
|
|
148
|
+
it("includes a model-visible status", () => {
|
|
149
|
+
const result = (0, tool_access_1.approvalRequiredResult)({
|
|
150
|
+
approvalId: "000peers0tacapprove000001",
|
|
151
|
+
toolId: "000peers0tool00000sendmsg",
|
|
152
|
+
toolName: "send-message",
|
|
153
|
+
requiredAccessLevel: 60,
|
|
154
|
+
message: "Needs approval",
|
|
155
|
+
});
|
|
156
|
+
expect(result.status).toBe("approval_required");
|
|
157
|
+
expect(result.requiredAccessLabel).toBe("Admin");
|
|
158
|
+
});
|
|
159
|
+
});
|
package/dist/data/tools.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { DataContext } from "../context/data-context";
|
|
3
|
+
/** Shape of a tool input, output, or config schema. */
|
|
3
4
|
export declare enum IOSchemaType {
|
|
4
5
|
none = "none",
|
|
5
6
|
simple = "simple",
|
|
6
7
|
complex = "complex"
|
|
7
8
|
}
|
|
9
|
+
/** Zod schema for {@link IOSchema}. */
|
|
8
10
|
export declare const ioSchema: z.ZodObject<{
|
|
9
11
|
type: z.ZodNativeEnum<typeof IOSchemaType>;
|
|
10
12
|
fields: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -55,7 +57,9 @@ export declare const ioSchema: z.ZodObject<{
|
|
|
55
57
|
subType?: string | undefined;
|
|
56
58
|
}[] | undefined;
|
|
57
59
|
}>;
|
|
60
|
+
/** Field list plus complexity for a tool IO surface. */
|
|
58
61
|
export type IOSchema = z.infer<typeof ioSchema>;
|
|
62
|
+
/** Zod schema for a persisted {@link ITool} row. */
|
|
59
63
|
export declare const toolSchema: z.ZodObject<{
|
|
60
64
|
toolId: z.ZodEffects<z.ZodString, string, string>;
|
|
61
65
|
name: z.ZodString;
|
|
@@ -215,6 +219,7 @@ export declare const toolSchema: z.ZodObject<{
|
|
|
215
219
|
codeRepository: z.ZodOptional<z.ZodString>;
|
|
216
220
|
isAssistantRunner: z.ZodOptional<z.ZodBoolean>;
|
|
217
221
|
packageId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
222
|
+
accessLevel: z.ZodDefault<z.ZodNumber>;
|
|
218
223
|
}, "strip", z.ZodTypeAny, {
|
|
219
224
|
code: string;
|
|
220
225
|
name: string;
|
|
@@ -244,6 +249,7 @@ export declare const toolSchema: z.ZodObject<{
|
|
|
244
249
|
subType?: string | undefined;
|
|
245
250
|
}[];
|
|
246
251
|
};
|
|
252
|
+
accessLevel: number;
|
|
247
253
|
packageId?: string | undefined;
|
|
248
254
|
detailedDescription?: string | undefined;
|
|
249
255
|
configSchema?: {
|
|
@@ -305,14 +311,22 @@ export declare const toolSchema: z.ZodObject<{
|
|
|
305
311
|
} | undefined;
|
|
306
312
|
codeRepository?: string | undefined;
|
|
307
313
|
isAssistantRunner?: boolean | undefined;
|
|
314
|
+
accessLevel?: number | undefined;
|
|
308
315
|
}>;
|
|
316
|
+
/** A tool definition stored in the Tools table. */
|
|
309
317
|
export type ITool = z.infer<typeof toolSchema>;
|
|
318
|
+
/** Runnable tool: persisted metadata plus the in-memory implementation. */
|
|
310
319
|
export interface IToolInstance {
|
|
311
320
|
tool: ITool;
|
|
312
321
|
toolFn: (...args: any[]) => any;
|
|
313
322
|
inputSchema?: z.ZodObject<any>;
|
|
314
323
|
outputSchema?: z.ZodObject<any>;
|
|
315
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Accessor for the Tools table.
|
|
327
|
+
*
|
|
328
|
+
* @param dataContext - Optional data context; defaults to the current singleton.
|
|
329
|
+
*/
|
|
316
330
|
export declare function Tools(dataContext?: DataContext): import("..").Table<{
|
|
317
331
|
code: string;
|
|
318
332
|
name: string;
|
|
@@ -342,6 +356,7 @@ export declare function Tools(dataContext?: DataContext): import("..").Table<{
|
|
|
342
356
|
subType?: string | undefined;
|
|
343
357
|
}[];
|
|
344
358
|
};
|
|
359
|
+
accessLevel: number;
|
|
345
360
|
packageId?: string | undefined;
|
|
346
361
|
detailedDescription?: string | undefined;
|
|
347
362
|
configSchema?: {
|
package/dist/data/tools.js
CHANGED
|
@@ -6,18 +6,22 @@ const zod_1 = require("zod");
|
|
|
6
6
|
const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
7
7
|
const field_type_1 = require("../types/field-type");
|
|
8
8
|
const zod_types_1 = require("../types/zod-types");
|
|
9
|
+
const access_level_1 = require("./access-level");
|
|
9
10
|
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
10
11
|
const types_1 = require("./orm/types");
|
|
12
|
+
/** Shape of a tool input, output, or config schema. */
|
|
11
13
|
var IOSchemaType;
|
|
12
14
|
(function (IOSchemaType) {
|
|
13
15
|
IOSchemaType["none"] = "none";
|
|
14
16
|
IOSchemaType["simple"] = "simple";
|
|
15
17
|
IOSchemaType["complex"] = "complex";
|
|
16
18
|
})(IOSchemaType || (exports.IOSchemaType = IOSchemaType = {}));
|
|
19
|
+
/** Zod schema for {@link IOSchema}. */
|
|
17
20
|
exports.ioSchema = zod_1.z.object({
|
|
18
21
|
type: zod_1.z.nativeEnum(IOSchemaType),
|
|
19
22
|
fields: field_type_1.fieldSchema.array().default([]),
|
|
20
23
|
});
|
|
24
|
+
/** Zod schema for a persisted {@link ITool} row. */
|
|
21
25
|
exports.toolSchema = zod_1.z.object({
|
|
22
26
|
toolId: zod_types_1.zodPeerId,
|
|
23
27
|
name: zod_1.z.string().describe("The name of the tool"),
|
|
@@ -44,6 +48,7 @@ exports.toolSchema = zod_1.z.object({
|
|
|
44
48
|
.optional()
|
|
45
49
|
.describe("Whether this tool is a model that can be used to run an assistant"),
|
|
46
50
|
packageId: zod_types_1.zodPeerId.optional().describe("The package that installed this tool, if any"),
|
|
51
|
+
accessLevel: access_level_1.accessLevelSchema.describe("Required access level (0-100) to run this tool. Unclassified tools default to 100 (Self)."),
|
|
47
52
|
});
|
|
48
53
|
const metaData = {
|
|
49
54
|
name: "Tools",
|
|
@@ -52,8 +57,14 @@ const metaData = {
|
|
|
52
57
|
fields: (0, types_1.schemaToFields)(exports.toolSchema),
|
|
53
58
|
iconClassName: "bi bi-tools",
|
|
54
59
|
indexes: [{ fields: ["name"] }, { fields: ["isAssistantRunner"] }],
|
|
60
|
+
versionNumber: 1,
|
|
55
61
|
};
|
|
56
62
|
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.toolSchema);
|
|
63
|
+
/**
|
|
64
|
+
* Accessor for the Tools table.
|
|
65
|
+
*
|
|
66
|
+
* @param dataContext - Optional data context; defaults to the current singleton.
|
|
67
|
+
*/
|
|
57
68
|
function Tools(dataContext) {
|
|
58
69
|
return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, exports.toolSchema);
|
|
59
70
|
}
|
|
@@ -29,8 +29,8 @@ export declare const workflowLogSchema: z.ZodObject<{
|
|
|
29
29
|
resultObject: z.ZodOptional<z.ZodUnion<[z.ZodObject<{}, "strip", z.ZodAny, z.objectOutputType<{}, z.ZodAny, "strip">, z.objectInputType<{}, z.ZodAny, "strip">>, z.ZodArray<z.ZodAny, "many">]>>;
|
|
30
30
|
isError: z.ZodOptional<z.ZodBoolean>;
|
|
31
31
|
}, "strip", z.ZodTypeAny, {
|
|
32
|
-
workflowLogId: string;
|
|
33
32
|
workflowRunId: string;
|
|
33
|
+
workflowLogId: string;
|
|
34
34
|
contextId: string;
|
|
35
35
|
logDT: Date;
|
|
36
36
|
logText: string;
|
|
@@ -47,13 +47,13 @@ export declare const workflowLogSchema: z.ZodObject<{
|
|
|
47
47
|
resultObject?: any[] | z.objectOutputType<{}, z.ZodAny, "strip"> | undefined;
|
|
48
48
|
isError?: boolean | undefined;
|
|
49
49
|
}, {
|
|
50
|
-
workflowLogId: string;
|
|
51
50
|
workflowRunId: string;
|
|
51
|
+
workflowLogId: string;
|
|
52
52
|
contextId: string;
|
|
53
53
|
logText: string;
|
|
54
54
|
toolId?: string | undefined;
|
|
55
|
-
logDT?: Date | undefined;
|
|
56
55
|
result?: string | undefined;
|
|
56
|
+
logDT?: Date | undefined;
|
|
57
57
|
instruction?: {
|
|
58
58
|
markdown?: string | undefined;
|
|
59
59
|
onError?: string | undefined;
|
|
@@ -67,8 +67,8 @@ export declare const workflowLogSchema: z.ZodObject<{
|
|
|
67
67
|
}>;
|
|
68
68
|
export type IWorkflowLog = z.infer<typeof workflowLogSchema>;
|
|
69
69
|
export declare function WorkflowLogs(dataContext?: DataContext): import("..").Table<{
|
|
70
|
-
workflowLogId: string;
|
|
71
70
|
workflowRunId: string;
|
|
71
|
+
workflowLogId: string;
|
|
72
72
|
contextId: string;
|
|
73
73
|
logDT: Date;
|
|
74
74
|
logText: string;
|
|
@@ -86,8 +86,8 @@ export declare function WorkflowLogs(dataContext?: DataContext): import("..").Ta
|
|
|
86
86
|
isError?: boolean | undefined;
|
|
87
87
|
}>;
|
|
88
88
|
export declare const getLogger: (workflowRunId: string, contextId: string) => (logData: string | Omit<Partial<IWorkflowLog>, "workflowRunId" | "workflowLogId">) => Promise<{
|
|
89
|
-
workflowLogId: string;
|
|
90
89
|
workflowRunId: string;
|
|
90
|
+
workflowLogId: string;
|
|
91
91
|
contextId: string;
|
|
92
92
|
logDT: Date;
|
|
93
93
|
logText: string;
|
|
@@ -33,6 +33,7 @@ export declare const workflowRunSchema: z.ZodObject<{
|
|
|
33
33
|
defaultAssistantId: z.ZodEffects<z.ZodString, string, string>;
|
|
34
34
|
}, "strip", z.ZodTypeAny, {
|
|
35
35
|
createdAt: Date;
|
|
36
|
+
workflowRunId: string;
|
|
36
37
|
defaultAssistantId: string;
|
|
37
38
|
instructions: {
|
|
38
39
|
markdown?: string | undefined;
|
|
@@ -40,7 +41,6 @@ export declare const workflowRunSchema: z.ZodObject<{
|
|
|
40
41
|
directCallToolId?: string | undefined;
|
|
41
42
|
subWorkflowId?: string | undefined;
|
|
42
43
|
}[];
|
|
43
|
-
workflowRunId: string;
|
|
44
44
|
parentMessageId: string;
|
|
45
45
|
currentInstructionIndex: number;
|
|
46
46
|
instructionResults: any[];
|
|
@@ -54,8 +54,8 @@ export declare const workflowRunSchema: z.ZodObject<{
|
|
|
54
54
|
completedAt?: Date | undefined;
|
|
55
55
|
parentWorkflowRunId?: string | undefined;
|
|
56
56
|
}, {
|
|
57
|
-
defaultAssistantId: string;
|
|
58
57
|
workflowRunId: string;
|
|
58
|
+
defaultAssistantId: string;
|
|
59
59
|
parentMessageId: string;
|
|
60
60
|
createdAt?: Date | undefined;
|
|
61
61
|
workflowId?: string | undefined;
|
|
@@ -715,14 +715,14 @@ export declare const pairingApprovalContentsSchema: z.ZodObject<{
|
|
|
715
715
|
role: "source" | "destination";
|
|
716
716
|
version: 1;
|
|
717
717
|
expiresAt: number;
|
|
718
|
-
transcriptHash: string;
|
|
719
718
|
approvalId: string;
|
|
719
|
+
transcriptHash: string;
|
|
720
720
|
}, {
|
|
721
721
|
role: "source" | "destination";
|
|
722
722
|
version: 1;
|
|
723
723
|
expiresAt: number;
|
|
724
|
-
transcriptHash: string;
|
|
725
724
|
approvalId: string;
|
|
725
|
+
transcriptHash: string;
|
|
726
726
|
}>;
|
|
727
727
|
/** Contents of a signed pairing approval. */
|
|
728
728
|
export type PairingApprovalContents = z.infer<typeof pairingApprovalContentsSchema>;
|
|
@@ -738,14 +738,14 @@ export declare const signedPairingApprovalSchema: z.ZodObject<{
|
|
|
738
738
|
role: "source" | "destination";
|
|
739
739
|
version: 1;
|
|
740
740
|
expiresAt: number;
|
|
741
|
-
transcriptHash: string;
|
|
742
741
|
approvalId: string;
|
|
742
|
+
transcriptHash: string;
|
|
743
743
|
}, {
|
|
744
744
|
role: "source" | "destination";
|
|
745
745
|
version: 1;
|
|
746
746
|
expiresAt: number;
|
|
747
|
-
transcriptHash: string;
|
|
748
747
|
approvalId: string;
|
|
748
|
+
transcriptHash: string;
|
|
749
749
|
}>;
|
|
750
750
|
signature: z.ZodString;
|
|
751
751
|
publicKey: z.ZodString;
|
|
@@ -756,8 +756,8 @@ export declare const signedPairingApprovalSchema: z.ZodObject<{
|
|
|
756
756
|
role: "source" | "destination";
|
|
757
757
|
version: 1;
|
|
758
758
|
expiresAt: number;
|
|
759
|
-
transcriptHash: string;
|
|
760
759
|
approvalId: string;
|
|
760
|
+
transcriptHash: string;
|
|
761
761
|
};
|
|
762
762
|
}, {
|
|
763
763
|
publicKey: string;
|
|
@@ -766,8 +766,8 @@ export declare const signedPairingApprovalSchema: z.ZodObject<{
|
|
|
766
766
|
role: "source" | "destination";
|
|
767
767
|
version: 1;
|
|
768
768
|
expiresAt: number;
|
|
769
|
-
transcriptHash: string;
|
|
770
769
|
approvalId: string;
|
|
770
|
+
transcriptHash: string;
|
|
771
771
|
};
|
|
772
772
|
}>;
|
|
773
773
|
/** Signed approval bound to one transcript and endpoint identity. */
|
package/dist/system-ids.d.ts
CHANGED
|
@@ -4,12 +4,19 @@ export declare const peersRootUserId = "000peers0user000000000001";
|
|
|
4
4
|
export declare const defaultAssistantId = "000peers0bot00000000shell";
|
|
5
5
|
/** Stable ID of the bundled OpenCode assistant. */
|
|
6
6
|
export declare const openCodeAssistantId = "00mlwl2km2opencode0000001";
|
|
7
|
+
/** Stable ID of the built-in Admin assistant. */
|
|
8
|
+
export declare const adminAssistantId = "000peers0bot00000000admin";
|
|
7
9
|
/** Stable ID of the default assistant-runner tool. */
|
|
8
10
|
export declare const defaultAssistantRunnerToolId = "000peers0tool00000runner1";
|
|
9
11
|
/** Stable ID of the built-in send-message tool. */
|
|
10
12
|
export declare const defaultSendMessageToolId = "000peers0tool00000sendmsg";
|
|
11
13
|
/** Stable ID of the built-in workflow runner tool. */
|
|
12
14
|
export declare const runWorkflowToolId = "000peers0tool0runworkflow";
|
|
15
|
+
/**
|
|
16
|
+
* Stable ID of the local read-only `query-database` system tool.
|
|
17
|
+
* Distinct from Device Operations contract `queryDatabase`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const queryDatabaseToolId = "000peers0tool00querydb001";
|
|
13
20
|
/** Stable package ID of the bundled peers-core package. */
|
|
14
21
|
export declare const peersCorePackageId = "00mh0wlipjixk2gqmurbwee0o";
|
|
15
22
|
/** Canonical source repository for peers-core. */
|
|
@@ -36,3 +43,14 @@ export declare const deviceOperationsContractId = "00mriijkhq94msfe9m2j6quwp";
|
|
|
36
43
|
export declare const networkDiagnosticsContractId = "00ms1yb50w29oi116uwwrg7rl";
|
|
37
44
|
/** Contract id for explicit local network and synchronization control operations. */
|
|
38
45
|
export declare const networkControlContractId = "00ms1yb50yj9w5qbytl69qfht";
|
|
46
|
+
/**
|
|
47
|
+
* Contract id for the local-only tool-access approval control surface.
|
|
48
|
+
* Not available over device-to-device connections.
|
|
49
|
+
*/
|
|
50
|
+
export declare const toolAccessControlContractId = "000peers0toolaccessctl0001";
|
|
51
|
+
/** Stable IDs for tools in System Tool Access Control v1. */
|
|
52
|
+
export declare const toolAccessControlToolIds: {
|
|
53
|
+
readonly approve: "000peers0tacapprove000001";
|
|
54
|
+
readonly reject: "000peers0tacreject0000001";
|
|
55
|
+
readonly listPending: "000peers0taclist000000001";
|
|
56
|
+
};
|