@okrlinkhub/agent-bridge 0.2.0 → 2.0.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/README.md +132 -122
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +108 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/client/index.d.ts +54 -262
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +188 -539
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +4 -8
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +75 -257
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/agentBridgeUtils.d.ts +9 -0
- package/dist/component/agentBridgeUtils.d.ts.map +1 -0
- package/dist/component/agentBridgeUtils.js +36 -0
- package/dist/component/agentBridgeUtils.js.map +1 -0
- package/dist/component/agents.d.ts +30 -0
- package/dist/component/agents.d.ts.map +1 -0
- package/dist/component/agents.js +124 -0
- package/dist/component/agents.js.map +1 -0
- package/dist/component/gateway.d.ts +46 -51
- package/dist/component/gateway.d.ts.map +1 -1
- package/dist/component/gateway.js +176 -227
- package/dist/component/gateway.js.map +1 -1
- package/dist/component/permissions.d.ts +30 -84
- package/dist/component/permissions.d.ts.map +1 -1
- package/dist/component/permissions.js +80 -203
- package/dist/component/permissions.js.map +1 -1
- package/dist/component/schema.d.ts +58 -223
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +32 -126
- package/dist/component/schema.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +2 -3
- package/dist/react/index.js.map +1 -1
- package/package.json +3 -2
- package/src/cli/init.ts +124 -0
- package/src/client/index.test.ts +147 -0
- package/src/client/index.ts +310 -790
- package/src/component/_generated/api.ts +4 -8
- package/src/component/_generated/component.ts +75 -310
- package/src/component/agentBridgeUtils.ts +56 -0
- package/src/component/agents.ts +138 -0
- package/src/component/gateway.ts +213 -279
- package/src/component/permissions.ts +89 -259
- package/src/component/schema.ts +34 -146
- package/src/react/index.ts +5 -6
- package/dist/component/channels.d.ts +0 -83
- package/dist/component/channels.d.ts.map +0 -1
- package/dist/component/channels.js +0 -288
- package/dist/component/channels.js.map +0 -1
- package/dist/component/circuitBreaker.d.ts +0 -73
- package/dist/component/circuitBreaker.d.ts.map +0 -1
- package/dist/component/circuitBreaker.js +0 -216
- package/dist/component/circuitBreaker.js.map +0 -1
- package/dist/component/provisioning.d.ts +0 -87
- package/dist/component/provisioning.d.ts.map +0 -1
- package/dist/component/provisioning.js +0 -343
- package/dist/component/provisioning.js.map +0 -1
- package/dist/component/registry.d.ts +0 -46
- package/dist/component/registry.d.ts.map +0 -1
- package/dist/component/registry.js +0 -121
- package/dist/component/registry.js.map +0 -1
- package/src/component/channels.ts +0 -374
- package/src/component/circuitBreaker.ts +0 -250
- package/src/component/provisioning.ts +0 -402
- package/src/component/registry.ts +0 -152
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { v } from "convex/values";
|
|
2
|
-
import { mutation, query
|
|
2
|
+
import { mutation, query } from "./_generated/server.js";
|
|
3
|
+
import { patternMatchesAvailableFunctions } from "./agentBridgeUtils.js";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const permissionResultValidator = v.object({
|
|
5
|
+
const permissionRuleValidator = v.object({
|
|
6
|
+
pattern: v.string(),
|
|
7
7
|
permission: v.union(
|
|
8
8
|
v.literal("allow"),
|
|
9
9
|
v.literal("deny"),
|
|
@@ -12,180 +12,57 @@ const permissionResultValidator = v.object({
|
|
|
12
12
|
rateLimitConfig: v.optional(
|
|
13
13
|
v.object({
|
|
14
14
|
requestsPerHour: v.number(),
|
|
15
|
-
tokenBudget: v.number(),
|
|
15
|
+
tokenBudget: v.optional(v.number()),
|
|
16
16
|
}),
|
|
17
17
|
),
|
|
18
|
-
matchedPattern: v.optional(v.string()),
|
|
19
18
|
});
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Calculate specificity score for a pattern.
|
|
25
|
-
* More specific patterns (longer fixed prefix before the first wildcard)
|
|
26
|
-
* get higher scores.
|
|
27
|
-
*/
|
|
28
|
-
function patternSpecificity(pattern: string): number {
|
|
29
|
-
const wildcardIndex = pattern.indexOf("*");
|
|
30
|
-
if (wildcardIndex === -1) return pattern.length;
|
|
31
|
-
return wildcardIndex;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Check if a function name matches a permission pattern.
|
|
36
|
-
* Supports "*" as a wildcard that matches any characters.
|
|
37
|
-
* Examples: "okr:*" matches "okr:getObjectives", "*" matches anything.
|
|
38
|
-
*/
|
|
39
|
-
function matchesPattern(functionName: string, pattern: string): boolean {
|
|
40
|
-
if (pattern === "*") return true;
|
|
41
|
-
// Escape regex special chars except *, then replace * with .*
|
|
42
|
-
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
43
|
-
const regexStr = "^" + escaped.replace(/\*/g, ".*") + "$";
|
|
44
|
-
const regex = new RegExp(regexStr);
|
|
45
|
-
return regex.test(functionName);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// --- Public functions ---
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Set a permission for an agent on a specific app.
|
|
52
|
-
* If a permission with the same agentId + appName + functionPattern exists, it is updated.
|
|
53
|
-
*/
|
|
54
|
-
export const setPermission = mutation({
|
|
20
|
+
export const setAgentPermissions = mutation({
|
|
55
21
|
args: {
|
|
56
|
-
agentId: v.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
permission: v.union(
|
|
60
|
-
v.literal("allow"),
|
|
61
|
-
v.literal("deny"),
|
|
62
|
-
v.literal("rate_limited"),
|
|
63
|
-
),
|
|
64
|
-
rateLimitConfig: v.optional(
|
|
65
|
-
v.object({
|
|
66
|
-
requestsPerHour: v.number(),
|
|
67
|
-
tokenBudget: v.number(),
|
|
68
|
-
}),
|
|
69
|
-
),
|
|
70
|
-
createdBy: v.string(),
|
|
22
|
+
agentId: v.id("agents"),
|
|
23
|
+
rules: v.array(permissionRuleValidator),
|
|
24
|
+
availableFunctionKeys: v.array(v.string()),
|
|
71
25
|
},
|
|
72
|
-
returns: v.
|
|
26
|
+
returns: v.number(),
|
|
73
27
|
handler: async (ctx, args) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
if (match) {
|
|
87
|
-
await ctx.db.patch(match._id, {
|
|
88
|
-
permission: args.permission,
|
|
89
|
-
rateLimitConfig: args.rateLimitConfig,
|
|
90
|
-
createdBy: args.createdBy,
|
|
91
|
-
createdAt: Date.now(),
|
|
92
|
-
});
|
|
93
|
-
return match._id;
|
|
28
|
+
for (const rule of args.rules) {
|
|
29
|
+
const isValid = patternMatchesAvailableFunctions(
|
|
30
|
+
rule.pattern,
|
|
31
|
+
args.availableFunctionKeys,
|
|
32
|
+
);
|
|
33
|
+
if (!isValid) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Pattern "${rule.pattern}" does not match any configured function`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
94
38
|
}
|
|
95
39
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
functionPattern: args.functionPattern,
|
|
100
|
-
permission: args.permission,
|
|
101
|
-
rateLimitConfig: args.rateLimitConfig,
|
|
102
|
-
createdAt: Date.now(),
|
|
103
|
-
createdBy: args.createdBy,
|
|
104
|
-
});
|
|
105
|
-
return id;
|
|
106
|
-
},
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Remove a specific permission.
|
|
111
|
-
*/
|
|
112
|
-
export const removePermission = mutation({
|
|
113
|
-
args: {
|
|
114
|
-
agentId: v.string(),
|
|
115
|
-
appName: v.string(),
|
|
116
|
-
functionPattern: v.string(),
|
|
117
|
-
},
|
|
118
|
-
returns: v.boolean(),
|
|
119
|
-
handler: async (ctx, args) => {
|
|
120
|
-
const perms = await ctx.db
|
|
121
|
-
.query("functionPermissions")
|
|
122
|
-
.withIndex("by_agent_and_app", (q) =>
|
|
123
|
-
q.eq("agentId", args.agentId).eq("appName", args.appName),
|
|
124
|
-
)
|
|
125
|
-
.collect();
|
|
126
|
-
|
|
127
|
-
const match = perms.find(
|
|
128
|
-
(p) => p.functionPattern === args.functionPattern,
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
if (!match) return false;
|
|
132
|
-
|
|
133
|
-
await ctx.db.delete(match._id);
|
|
134
|
-
return true;
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Check permission for a specific function call.
|
|
140
|
-
* Applies pattern matching with specificity ordering (most specific pattern wins).
|
|
141
|
-
* Default: deny if no matching pattern is found.
|
|
142
|
-
*/
|
|
143
|
-
export const checkPermission = query({
|
|
144
|
-
args: {
|
|
145
|
-
agentId: v.string(),
|
|
146
|
-
appName: v.string(),
|
|
147
|
-
functionName: v.string(),
|
|
148
|
-
},
|
|
149
|
-
returns: permissionResultValidator,
|
|
150
|
-
handler: async (ctx, args) => {
|
|
151
|
-
const permissions = await ctx.db
|
|
152
|
-
.query("functionPermissions")
|
|
153
|
-
.withIndex("by_agent_and_app", (q) =>
|
|
154
|
-
q.eq("agentId", args.agentId).eq("appName", args.appName),
|
|
155
|
-
)
|
|
40
|
+
const existingRules = await ctx.db
|
|
41
|
+
.query("agentPermissions")
|
|
42
|
+
.withIndex("by_agentId", (q) => q.eq("agentId", args.agentId))
|
|
156
43
|
.collect();
|
|
157
44
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
.sort(
|
|
162
|
-
(a, b) =>
|
|
163
|
-
patternSpecificity(b.functionPattern) -
|
|
164
|
-
patternSpecificity(a.functionPattern),
|
|
165
|
-
);
|
|
45
|
+
for (const existingRule of existingRules) {
|
|
46
|
+
await ctx.db.delete(existingRule._id);
|
|
47
|
+
}
|
|
166
48
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
49
|
+
for (const rule of args.rules) {
|
|
50
|
+
await ctx.db.insert("agentPermissions", {
|
|
51
|
+
agentId: args.agentId,
|
|
52
|
+
functionPattern: rule.pattern,
|
|
53
|
+
permission: rule.permission,
|
|
54
|
+
rateLimitConfig: rule.rateLimitConfig,
|
|
55
|
+
updatedAt: Date.now(),
|
|
56
|
+
});
|
|
170
57
|
}
|
|
171
58
|
|
|
172
|
-
|
|
173
|
-
const best = matches[0];
|
|
174
|
-
return {
|
|
175
|
-
permission: best.permission,
|
|
176
|
-
rateLimitConfig: best.rateLimitConfig,
|
|
177
|
-
matchedPattern: best.functionPattern,
|
|
178
|
-
};
|
|
59
|
+
return args.rules.length;
|
|
179
60
|
},
|
|
180
61
|
});
|
|
181
62
|
|
|
182
|
-
|
|
183
|
-
* List all permissions for an agent on a specific app.
|
|
184
|
-
*/
|
|
185
|
-
export const listPermissions = query({
|
|
63
|
+
export const listAgentPermissions = query({
|
|
186
64
|
args: {
|
|
187
|
-
agentId: v.
|
|
188
|
-
appName: v.string(),
|
|
65
|
+
agentId: v.id("agents"),
|
|
189
66
|
},
|
|
190
67
|
returns: v.array(
|
|
191
68
|
v.object({
|
|
@@ -198,124 +75,77 @@ export const listPermissions = query({
|
|
|
198
75
|
rateLimitConfig: v.optional(
|
|
199
76
|
v.object({
|
|
200
77
|
requestsPerHour: v.number(),
|
|
201
|
-
tokenBudget: v.number(),
|
|
78
|
+
tokenBudget: v.optional(v.number()),
|
|
202
79
|
}),
|
|
203
80
|
),
|
|
204
|
-
|
|
205
|
-
createdBy: v.string(),
|
|
81
|
+
updatedAt: v.number(),
|
|
206
82
|
}),
|
|
207
83
|
),
|
|
208
84
|
handler: async (ctx, args) => {
|
|
209
|
-
const
|
|
210
|
-
.query("
|
|
211
|
-
.withIndex("
|
|
212
|
-
q.eq("agentId", args.agentId).eq("appName", args.appName),
|
|
213
|
-
)
|
|
85
|
+
const rules = await ctx.db
|
|
86
|
+
.query("agentPermissions")
|
|
87
|
+
.withIndex("by_agentId", (q) => q.eq("agentId", args.agentId))
|
|
214
88
|
.collect();
|
|
215
89
|
|
|
216
|
-
return
|
|
217
|
-
functionPattern:
|
|
218
|
-
permission:
|
|
219
|
-
rateLimitConfig:
|
|
220
|
-
|
|
221
|
-
createdBy: p.createdBy,
|
|
90
|
+
return rules.map((rule) => ({
|
|
91
|
+
functionPattern: rule.functionPattern,
|
|
92
|
+
permission: rule.permission,
|
|
93
|
+
rateLimitConfig: rule.rateLimitConfig,
|
|
94
|
+
updatedAt: rule.updatedAt,
|
|
222
95
|
}));
|
|
223
96
|
},
|
|
224
97
|
});
|
|
225
98
|
|
|
226
|
-
|
|
227
|
-
* Remove all permissions for a specific agent on a specific app.
|
|
228
|
-
*/
|
|
229
|
-
export const clearPermissions = mutation({
|
|
99
|
+
export const setFunctionOverrides = mutation({
|
|
230
100
|
args: {
|
|
231
|
-
|
|
232
|
-
|
|
101
|
+
overrides: v.array(
|
|
102
|
+
v.object({
|
|
103
|
+
key: v.string(),
|
|
104
|
+
enabled: v.boolean(),
|
|
105
|
+
globalRateLimit: v.optional(v.number()),
|
|
106
|
+
}),
|
|
107
|
+
),
|
|
108
|
+
availableFunctionKeys: v.array(v.string()),
|
|
233
109
|
},
|
|
234
110
|
returns: v.number(),
|
|
235
111
|
handler: async (ctx, args) => {
|
|
236
|
-
const
|
|
237
|
-
.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
112
|
+
for (const override of args.overrides) {
|
|
113
|
+
if (!args.availableFunctionKeys.includes(override.key)) {
|
|
114
|
+
throw new Error(`Function "${override.key}" is not exposed in config`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const existing = await ctx.db
|
|
118
|
+
.query("agentFunctions")
|
|
119
|
+
.withIndex("by_key", (q) => q.eq("key", override.key))
|
|
120
|
+
.unique();
|
|
121
|
+
if (existing) {
|
|
122
|
+
await ctx.db.patch(existing._id, {
|
|
123
|
+
enabled: override.enabled,
|
|
124
|
+
globalRateLimit: override.globalRateLimit,
|
|
125
|
+
});
|
|
126
|
+
} else {
|
|
127
|
+
await ctx.db.insert("agentFunctions", {
|
|
128
|
+
key: override.key,
|
|
129
|
+
enabled: override.enabled,
|
|
130
|
+
globalRateLimit: override.globalRateLimit,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
245
133
|
}
|
|
246
134
|
|
|
247
|
-
return
|
|
135
|
+
return args.overrides.length;
|
|
248
136
|
},
|
|
249
137
|
});
|
|
250
138
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
permissions: v.array(
|
|
263
|
-
v.object({
|
|
264
|
-
functionPattern: v.string(),
|
|
265
|
-
permission: v.union(
|
|
266
|
-
v.literal("allow"),
|
|
267
|
-
v.literal("deny"),
|
|
268
|
-
v.literal("rate_limited"),
|
|
269
|
-
),
|
|
270
|
-
specificity: v.number(),
|
|
271
|
-
}),
|
|
272
|
-
),
|
|
273
|
-
matches: v.array(
|
|
274
|
-
v.object({
|
|
275
|
-
functionPattern: v.string(),
|
|
276
|
-
permission: v.union(
|
|
277
|
-
v.literal("allow"),
|
|
278
|
-
v.literal("deny"),
|
|
279
|
-
v.literal("rate_limited"),
|
|
280
|
-
),
|
|
281
|
-
specificity: v.number(),
|
|
282
|
-
}),
|
|
283
|
-
),
|
|
284
|
-
bestMatch: v.optional(
|
|
285
|
-
v.object({
|
|
286
|
-
functionPattern: v.string(),
|
|
287
|
-
permission: v.union(
|
|
288
|
-
v.literal("allow"),
|
|
289
|
-
v.literal("deny"),
|
|
290
|
-
v.literal("rate_limited"),
|
|
291
|
-
),
|
|
292
|
-
specificity: v.number(),
|
|
293
|
-
}),
|
|
294
|
-
),
|
|
295
|
-
}),
|
|
296
|
-
handler: async (ctx, args) => {
|
|
297
|
-
const permissions = await ctx.db
|
|
298
|
-
.query("functionPermissions")
|
|
299
|
-
.withIndex("by_agent_and_app", (q) =>
|
|
300
|
-
q.eq("agentId", args.agentId).eq("appName", args.appName),
|
|
301
|
-
)
|
|
302
|
-
.collect();
|
|
303
|
-
|
|
304
|
-
const withSpecificity = permissions.map((p) => ({
|
|
305
|
-
functionPattern: p.functionPattern,
|
|
306
|
-
permission: p.permission,
|
|
307
|
-
specificity: patternSpecificity(p.functionPattern),
|
|
308
|
-
}));
|
|
309
|
-
|
|
310
|
-
const matches = withSpecificity
|
|
311
|
-
.filter((p) => matchesPattern(args.functionName, p.functionPattern))
|
|
312
|
-
.sort((a, b) => b.specificity - a.specificity);
|
|
313
|
-
|
|
314
|
-
return {
|
|
315
|
-
functionName: args.functionName,
|
|
316
|
-
permissions: withSpecificity,
|
|
317
|
-
matches,
|
|
318
|
-
bestMatch: matches[0],
|
|
319
|
-
};
|
|
139
|
+
export const listFunctionOverrides = query({
|
|
140
|
+
args: {},
|
|
141
|
+
returns: v.array(
|
|
142
|
+
v.object({
|
|
143
|
+
key: v.string(),
|
|
144
|
+
enabled: v.boolean(),
|
|
145
|
+
globalRateLimit: v.optional(v.number()),
|
|
146
|
+
}),
|
|
147
|
+
),
|
|
148
|
+
handler: async (ctx) => {
|
|
149
|
+
return await ctx.db.query("agentFunctions").collect();
|
|
320
150
|
},
|
|
321
151
|
});
|
package/src/component/schema.ts
CHANGED
|
@@ -2,66 +2,22 @@ import { defineSchema, defineTable } from "convex/server";
|
|
|
2
2
|
import { v } from "convex/values";
|
|
3
3
|
|
|
4
4
|
export default defineSchema({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
isActive: v.boolean(),
|
|
14
|
-
createdBy: v.string(), // Admin email who created the token
|
|
15
|
-
})
|
|
16
|
-
.index("by_token_hash", ["tokenHash"])
|
|
17
|
-
.index("by_email", ["employeeEmail"]),
|
|
18
|
-
|
|
19
|
-
// Registered agents (created on first provisioning)
|
|
20
|
-
registeredAgents: defineTable({
|
|
21
|
-
agentId: v.string(), // UUID generated at first provisioning
|
|
22
|
-
employeeEmail: v.string(),
|
|
23
|
-
department: v.string(),
|
|
24
|
-
firstRegisteredAt: v.number(),
|
|
25
|
-
lastSeenAt: v.number(),
|
|
26
|
-
isActive: v.boolean(),
|
|
27
|
-
revokedAt: v.optional(v.number()),
|
|
28
|
-
revokedBy: v.optional(v.string()),
|
|
29
|
-
})
|
|
30
|
-
.index("by_agent_id", ["agentId"])
|
|
31
|
-
.index("by_email", ["employeeEmail"]),
|
|
32
|
-
|
|
33
|
-
// Per-app per-agent instances (one per app per agent)
|
|
34
|
-
agentAppInstances: defineTable({
|
|
35
|
-
agentId: v.string(),
|
|
36
|
-
appName: v.string(),
|
|
37
|
-
instanceTokenHash: v.string(), // SHA-256 hash of the instance token
|
|
38
|
-
registeredAt: v.number(),
|
|
39
|
-
expiresAt: v.number(),
|
|
40
|
-
lastActivityAt: v.number(),
|
|
41
|
-
monthlyRequests: v.number(), // Request counter for this app
|
|
5
|
+
agents: defineTable({
|
|
6
|
+
name: v.string(),
|
|
7
|
+
appKey: v.optional(v.string()),
|
|
8
|
+
apiKeyHash: v.string(),
|
|
9
|
+
enabled: v.boolean(),
|
|
10
|
+
rateLimit: v.number(),
|
|
11
|
+
lastUsed: v.optional(v.number()),
|
|
12
|
+
createdAt: v.number(),
|
|
42
13
|
})
|
|
43
|
-
.index("
|
|
44
|
-
.index("
|
|
14
|
+
.index("by_apiKeyHash", ["apiKeyHash"])
|
|
15
|
+
.index("by_appKey", ["appKey"])
|
|
16
|
+
.index("by_enabled", ["enabled"]),
|
|
45
17
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
functionName: v.string(), // Alias e.g. "okr:getObjectives"
|
|
50
|
-
functionHandle: v.string(), // Function handle string from createFunctionHandle()
|
|
51
|
-
functionType: v.union(
|
|
52
|
-
v.literal("query"),
|
|
53
|
-
v.literal("mutation"),
|
|
54
|
-
v.literal("action"),
|
|
55
|
-
),
|
|
56
|
-
description: v.optional(v.string()),
|
|
57
|
-
registeredAt: v.number(),
|
|
58
|
-
}).index("by_app_and_function", ["appName", "functionName"]),
|
|
59
|
-
|
|
60
|
-
// Dynamic permissions: who can do what on which app
|
|
61
|
-
functionPermissions: defineTable({
|
|
62
|
-
agentId: v.string(),
|
|
63
|
-
appName: v.string(),
|
|
64
|
-
functionPattern: v.string(), // e.g. "okr:*", "okr:createObjective", "*"
|
|
18
|
+
agentPermissions: defineTable({
|
|
19
|
+
agentId: v.id("agents"),
|
|
20
|
+
functionPattern: v.string(),
|
|
65
21
|
permission: v.union(
|
|
66
22
|
v.literal("allow"),
|
|
67
23
|
v.literal("deny"),
|
|
@@ -70,96 +26,28 @@ export default defineSchema({
|
|
|
70
26
|
rateLimitConfig: v.optional(
|
|
71
27
|
v.object({
|
|
72
28
|
requestsPerHour: v.number(),
|
|
73
|
-
tokenBudget: v.number(),
|
|
29
|
+
tokenBudget: v.optional(v.number()),
|
|
74
30
|
}),
|
|
75
31
|
),
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
32
|
+
updatedAt: v.number(),
|
|
33
|
+
}).index("by_agentId", ["agentId"]),
|
|
34
|
+
|
|
35
|
+
agentFunctions: defineTable({
|
|
36
|
+
key: v.string(),
|
|
37
|
+
enabled: v.boolean(),
|
|
38
|
+
globalRateLimit: v.optional(v.number()),
|
|
39
|
+
}).index("by_key", ["key"]),
|
|
40
|
+
|
|
41
|
+
agentLogs: defineTable({
|
|
42
|
+
agentId: v.id("agents"),
|
|
43
|
+
functionKey: v.string(),
|
|
44
|
+
args: v.any(),
|
|
45
|
+
result: v.optional(v.any()),
|
|
46
|
+
error: v.optional(v.string()),
|
|
47
|
+
duration: v.number(),
|
|
84
48
|
timestamp: v.number(),
|
|
85
|
-
agentId: v.string(),
|
|
86
|
-
appName: v.string(),
|
|
87
|
-
functionCalled: v.string(),
|
|
88
|
-
permission: v.string(), // "allow", "deny", "rate_limited"
|
|
89
|
-
errorMessage: v.optional(v.string()),
|
|
90
|
-
durationMs: v.optional(v.number()),
|
|
91
49
|
})
|
|
92
|
-
.index("
|
|
93
|
-
.index("
|
|
94
|
-
|
|
95
|
-
// Circuit breaker counters (per agent, per app, per hour window)
|
|
96
|
-
circuitCounters: defineTable({
|
|
97
|
-
agentId: v.string(),
|
|
98
|
-
appName: v.string(),
|
|
99
|
-
windowHour: v.string(), // "2026-02-08T14" (ISO truncated to hour)
|
|
100
|
-
requestCount: v.number(),
|
|
101
|
-
tokenEstimate: v.number(),
|
|
102
|
-
isBlocked: v.boolean(),
|
|
103
|
-
blockedReason: v.optional(v.string()),
|
|
104
|
-
blockedAt: v.optional(v.number()),
|
|
105
|
-
})
|
|
106
|
-
.index("by_agentId_and_appName_and_windowHour", [
|
|
107
|
-
"agentId",
|
|
108
|
-
"appName",
|
|
109
|
-
"windowHour",
|
|
110
|
-
])
|
|
111
|
-
.index("by_isBlocked", ["isBlocked"]),
|
|
112
|
-
|
|
113
|
-
// A2A intra-app channels (thematic channels within an app)
|
|
114
|
-
appChannels: defineTable({
|
|
115
|
-
appName: v.string(),
|
|
116
|
-
channelName: v.string(),
|
|
117
|
-
description: v.optional(v.string()),
|
|
118
|
-
createdAt: v.number(),
|
|
119
|
-
isActive: v.boolean(),
|
|
120
|
-
}).index("by_appName_and_channelName", ["appName", "channelName"]),
|
|
121
|
-
|
|
122
|
-
// A2A channel messages
|
|
123
|
-
channelMessages: defineTable({
|
|
124
|
-
appName: v.string(),
|
|
125
|
-
channelName: v.string(),
|
|
126
|
-
messageId: v.string(), // UUID
|
|
127
|
-
fromAgentId: v.string(),
|
|
128
|
-
payload: v.string(), // JSON serialized
|
|
129
|
-
metadata: v.object({
|
|
130
|
-
priority: v.number(), // 1-10
|
|
131
|
-
ttl: v.number(), // TTL in ms
|
|
132
|
-
}),
|
|
133
|
-
sentAt: v.number(),
|
|
134
|
-
expiresAt: v.number(),
|
|
135
|
-
readBy: v.array(v.string()), // Array of agentIds that have read this message
|
|
136
|
-
})
|
|
137
|
-
.index("by_appName_and_channelName_and_sentAt", [
|
|
138
|
-
"appName",
|
|
139
|
-
"channelName",
|
|
140
|
-
"sentAt",
|
|
141
|
-
])
|
|
142
|
-
.index("by_expiresAt", ["expiresAt"]),
|
|
143
|
-
|
|
144
|
-
// Per-app configuration (no global singleton)
|
|
145
|
-
appConfigs: defineTable({
|
|
146
|
-
appName: v.string(),
|
|
147
|
-
defaultPermissions: v.array(
|
|
148
|
-
v.object({
|
|
149
|
-
pattern: v.string(),
|
|
150
|
-
permission: v.union(
|
|
151
|
-
v.literal("allow"),
|
|
152
|
-
v.literal("deny"),
|
|
153
|
-
v.literal("rate_limited"),
|
|
154
|
-
),
|
|
155
|
-
rateLimitConfig: v.optional(
|
|
156
|
-
v.object({
|
|
157
|
-
requestsPerHour: v.number(),
|
|
158
|
-
tokenBudget: v.number(),
|
|
159
|
-
}),
|
|
160
|
-
),
|
|
161
|
-
}),
|
|
162
|
-
),
|
|
163
|
-
configuredAt: v.number(),
|
|
164
|
-
}).index("by_app_name", ["appName"]),
|
|
50
|
+
.index("by_agentId_and_timestamp", ["agentId", "timestamp"])
|
|
51
|
+
.index("by_functionKey", ["functionKey"])
|
|
52
|
+
.index("by_timestamp", ["timestamp"]),
|
|
165
53
|
});
|
package/src/react/index.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
// React
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export { AgentBridge } from "../client/index.js";
|
|
3
|
+
// React helpers for Agent Bridge integrations.
|
|
4
|
+
export { registerRoutes, normalizeAgentBridgeConfig } from "../client/index.js";
|
|
7
5
|
export type {
|
|
8
6
|
AgentBridgeConfig,
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
AgentBridgeFunctionDefinition,
|
|
8
|
+
AgentBridgeFunctionMetadata,
|
|
9
|
+
AgentBridgeFunctionType,
|
|
11
10
|
} from "../client/index.js";
|