@vantageos/agent-engine 0.1.0-alpha.4 → 0.1.0-alpha.6

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.
Files changed (41) hide show
  1. package/README.md +285 -46
  2. package/dist/component/_generated/api.d.ts +31 -0
  3. package/dist/component/_generated/component.d.ts +365 -3
  4. package/dist/component/convex.config.js +19 -0
  5. package/dist/component/engine/agents.d.ts +10 -0
  6. package/dist/component/engine/agents.js +21 -0
  7. package/dist/component/engine/awaitEventTimeout.d.ts +13 -0
  8. package/dist/component/engine/awaitEventTimeout.js +82 -0
  9. package/dist/component/engine/delegation.d.ts +75 -0
  10. package/dist/component/engine/delegation.js +329 -0
  11. package/dist/component/engine/directory.d.ts +9 -0
  12. package/dist/component/engine/directory.js +45 -0
  13. package/dist/component/engine/habits.d.ts +70 -0
  14. package/dist/component/engine/habits.js +219 -0
  15. package/dist/component/engine/mandates.d.ts +74 -0
  16. package/dist/component/engine/mandates.js +272 -0
  17. package/dist/component/engine/sandboxCallback.d.ts +36 -0
  18. package/dist/component/engine/sandboxCallback.js +262 -0
  19. package/dist/component/engine/sessions.d.ts +7 -2
  20. package/dist/component/engine/sessions.js +75 -15
  21. package/dist/component/engine/toolApprovals.d.ts +2 -1
  22. package/dist/component/engine/toolApprovals.js +64 -26
  23. package/dist/component/engine/vpConnection.d.ts +69 -0
  24. package/dist/component/engine/vpConnection.js +221 -0
  25. package/dist/component/engine/wakeup.d.ts +33 -0
  26. package/dist/component/engine/wakeup.js +230 -0
  27. package/dist/component/engine/workflows.d.ts +11 -0
  28. package/dist/component/engine/workflows.js +87 -0
  29. package/dist/component/schema.d.ts +365 -4
  30. package/dist/component/schema.js +360 -1
  31. package/dist/component/testFixtures/delegationDemoWorkflow.d.ts +18 -0
  32. package/dist/component/testFixtures/delegationDemoWorkflow.js +76 -0
  33. package/dist/component/testFixtures/sandboxDemoWorkflow.d.ts +19 -0
  34. package/dist/component/testFixtures/sandboxDemoWorkflow.js +69 -0
  35. package/dist/component/testFixtures/vpTool.d.ts +4 -0
  36. package/dist/component/testFixtures/vpTool.js +25 -0
  37. package/dist/component/testFixtures/wakeupDemoWorkflow.d.ts +19 -0
  38. package/dist/component/testFixtures/wakeupDemoWorkflow.js +77 -0
  39. package/dist/component/testFixtures/wakeupWork.d.ts +8 -0
  40. package/dist/component/testFixtures/wakeupWork.js +21 -0
  41. package/package.json +2 -1
@@ -22,31 +22,115 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
22
22
  engine: {
23
23
  agents: {
24
24
  create: FunctionReference<"mutation", "internal", {
25
+ createdBy: string;
26
+ description?: string;
25
27
  instructions: string;
28
+ maxInputTokensPerSession?: number | false;
29
+ maxSubagents?: number;
26
30
  model: string;
31
+ modelProvider?: "gateway" | "openrouter";
27
32
  name: string;
33
+ orgId: string;
34
+ reasoningEffort?: "none" | "low" | "medium" | "high";
28
35
  }, string, Name>;
29
36
  get: FunctionReference<"query", "internal", {
30
37
  agentId: string;
38
+ orgId: string;
31
39
  }, {
32
40
  _creationTime: number;
33
41
  _id: string;
34
42
  createdAt: number;
35
43
  createdBy: string;
44
+ description?: string;
36
45
  instructions: string;
46
+ maxInputTokensPerSession?: number | false;
47
+ maxSubagents?: number;
37
48
  model: string;
49
+ modelProvider?: "gateway" | "openrouter";
38
50
  name: string;
39
51
  orgId: string;
52
+ reasoningEffort?: "none" | "low" | "medium" | "high";
40
53
  status: "draft" | "live" | "archived";
41
54
  updatedAt: number;
42
55
  } | null, Name>;
43
56
  };
57
+ awaitEventTimeout: {
58
+ cancel: FunctionReference<"mutation", "internal", {
59
+ orgId: string;
60
+ timeoutRowId: string;
61
+ }, null, Name>;
62
+ schedule: FunctionReference<"mutation", "internal", {
63
+ awaitedEventName: string;
64
+ orgId: string;
65
+ sessionId: string;
66
+ timeoutMs: number;
67
+ }, string, Name>;
68
+ };
69
+ delegation: {
70
+ declareSubagent: FunctionReference<"mutation", "internal", {
71
+ childAgentId: string;
72
+ description?: string;
73
+ orgId: string;
74
+ parentAgentId: string;
75
+ toolName: string;
76
+ }, string, Name>;
77
+ delegateToSubagent: FunctionReference<"action", "internal", {
78
+ awaitedEventName: string;
79
+ cost: number;
80
+ orgId: string;
81
+ payload?: string;
82
+ reason: string;
83
+ scope: string;
84
+ subagentId: string;
85
+ workFunctionHandle: string;
86
+ workflowId: string;
87
+ }, string, Name>;
88
+ invokeAgentClone: FunctionReference<"action", "internal", {
89
+ agentId: string;
90
+ awaitedEventName: string;
91
+ cost: number;
92
+ orgId: string;
93
+ payload?: string;
94
+ reason: string;
95
+ scope: string;
96
+ viaAgentTool: boolean;
97
+ workFunctionHandle: string;
98
+ workflowId: string;
99
+ }, string, Name>;
100
+ listSubagents: FunctionReference<"query", "internal", {
101
+ orgId: string;
102
+ parentAgentId: string;
103
+ }, Array<{
104
+ _creationTime: number;
105
+ _id: string;
106
+ childAgentId: string;
107
+ createdAt: number;
108
+ description?: string;
109
+ enabled: boolean;
110
+ orgId: string;
111
+ parentAgentId: string;
112
+ toolName: string;
113
+ }>, Name>;
114
+ };
115
+ directory: {
116
+ listByOrg: FunctionReference<"query", "internal", {
117
+ orgId: string;
118
+ }, Array<{
119
+ _id: string;
120
+ createdAt: number;
121
+ model: string;
122
+ name: string;
123
+ status: "draft" | "live" | "archived";
124
+ }>, Name>;
125
+ };
44
126
  durableJob: {
45
127
  cancel: FunctionReference<"mutation", "internal", {
46
128
  jobId: string;
129
+ orgId: string;
47
130
  }, null, Name>;
48
131
  getStatus: FunctionReference<"query", "internal", {
49
132
  jobId: string;
133
+ orgId: string;
50
134
  }, {
51
135
  abandonedAtStep?: number;
52
136
  cursor: number;
@@ -57,12 +141,148 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
57
141
  start: FunctionReference<"mutation", "internal", {
58
142
  kind: string;
59
143
  maxAttemptsPerStep: number;
144
+ orgId: string;
60
145
  stepFunctionHandle: string;
61
146
  totalSteps: number;
62
147
  }, string, Name>;
63
148
  };
149
+ habits: {
150
+ create: FunctionReference<"mutation", "internal", {
151
+ agentId: string;
152
+ cronExpression: string;
153
+ name: string;
154
+ orgId: string;
155
+ prompt: string;
156
+ }, string, Name>;
157
+ disable: FunctionReference<"mutation", "internal", {
158
+ habitId: string;
159
+ orgId: string;
160
+ }, null, Name>;
161
+ enable: FunctionReference<"mutation", "internal", {
162
+ habitId: string;
163
+ orgId: string;
164
+ }, null, Name>;
165
+ get: FunctionReference<"query", "internal", {
166
+ habitId: string;
167
+ orgId: string;
168
+ }, {
169
+ _creationTime: number;
170
+ _id: string;
171
+ agentId: string;
172
+ createdAt: number;
173
+ cronExpression: string;
174
+ cronJobId?: string;
175
+ enabled: boolean;
176
+ lastRunAt?: number;
177
+ name: string;
178
+ orgId: string;
179
+ prompt: string;
180
+ updatedAt: number;
181
+ } | null, Name>;
182
+ listForAgent: FunctionReference<"query", "internal", {
183
+ agentId: string;
184
+ orgId: string;
185
+ }, Array<{
186
+ _creationTime: number;
187
+ _id: string;
188
+ agentId: string;
189
+ createdAt: number;
190
+ cronExpression: string;
191
+ cronJobId?: string;
192
+ enabled: boolean;
193
+ lastRunAt?: number;
194
+ name: string;
195
+ orgId: string;
196
+ prompt: string;
197
+ updatedAt: number;
198
+ }>, Name>;
199
+ listRuns: FunctionReference<"query", "internal", {
200
+ habitId: string;
201
+ orgId: string;
202
+ }, Array<{
203
+ _creationTime: number;
204
+ _id: string;
205
+ agentId: string;
206
+ habitId: string;
207
+ orgId: string;
208
+ ranAt: number;
209
+ }>, Name>;
210
+ updateSchedule: FunctionReference<"mutation", "internal", {
211
+ cronExpression?: string;
212
+ habitId: string;
213
+ name?: string;
214
+ orgId: string;
215
+ prompt?: string;
216
+ }, null, Name>;
217
+ };
218
+ mandates: {
219
+ get: FunctionReference<"query", "internal", {
220
+ agentId: string;
221
+ orgId: string;
222
+ scope: string;
223
+ }, {
224
+ _creationTime: number;
225
+ _id: string;
226
+ agentId: string;
227
+ capacity?: number;
228
+ createdAt: number;
229
+ kind: "token bucket" | "fixed window";
230
+ orgId: string;
231
+ period: number;
232
+ rate: number;
233
+ scope: string;
234
+ updatedAt: number;
235
+ } | null, Name>;
236
+ listApprovals: FunctionReference<"query", "internal", {
237
+ agentId?: string;
238
+ orgId: string;
239
+ }, Array<{
240
+ _creationTime: number;
241
+ _id: string;
242
+ agentId: string;
243
+ createdAt: number;
244
+ orgId: string;
245
+ reason: string;
246
+ requestedCost: number;
247
+ resolvedAt?: number;
248
+ resolvedBy?: string;
249
+ scope: string;
250
+ status: "pending" | "approved" | "denied";
251
+ }>, Name>;
252
+ resolveApproval: FunctionReference<"mutation", "internal", {
253
+ approvalId: string;
254
+ decision: "approved" | "denied";
255
+ orgId: string;
256
+ resolvedBy: string;
257
+ }, null, Name>;
258
+ set: FunctionReference<"mutation", "internal", {
259
+ agentId: string;
260
+ capacity?: number;
261
+ kind: "token bucket" | "fixed window";
262
+ orgId: string;
263
+ period: number;
264
+ rate: number;
265
+ scope: string;
266
+ }, string, Name>;
267
+ spend: FunctionReference<"mutation", "internal", {
268
+ agentId: string;
269
+ cost: number;
270
+ orgId: string;
271
+ reason: string;
272
+ scope: string;
273
+ }, {
274
+ approvalId?: string;
275
+ ok: boolean;
276
+ }, Name>;
277
+ usageCount: FunctionReference<"query", "internal", {
278
+ agentId: string;
279
+ orgId: string;
280
+ scope: string;
281
+ }, number, Name>;
282
+ };
64
283
  resolvers: {
65
284
  resolveManifest: FunctionReference<"query", "internal", {
285
+ orgId: string;
66
286
  sessionId: string;
67
287
  }, {
68
288
  agentId: string;
@@ -75,50 +295,192 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
75
295
  }>;
76
296
  }, Name>;
77
297
  };
298
+ sandboxCallback: {
299
+ attachSandboxId: FunctionReference<"mutation", "internal", {
300
+ orgId: string;
301
+ sandboxId: string;
302
+ sandboxRunId: string;
303
+ }, null, Name>;
304
+ deadLetterMalformed: FunctionReference<"mutation", "internal", {
305
+ deliveryId: string;
306
+ orgId?: string;
307
+ rawBody: string;
308
+ reason: string;
309
+ }, null, Name>;
310
+ getStatus: FunctionReference<"query", "internal", {
311
+ orgId: string;
312
+ sandboxRunId: string;
313
+ }, {
314
+ resultSummary?: string;
315
+ status: "pending" | "completed" | "failed" | "timedOut";
316
+ }, Name>;
317
+ processCallback: FunctionReference<"mutation", "internal", {
318
+ deliveryId: string;
319
+ orgId: string;
320
+ resultSummary?: string;
321
+ sandboxRunId: string;
322
+ status: "completed" | "failed";
323
+ }, {
324
+ outcome: "woke" | "duplicate" | "dead-lettered";
325
+ }, Name>;
326
+ startRun: FunctionReference<"mutation", "internal", {
327
+ awaitedEventName: string;
328
+ orgId: string;
329
+ timeoutMs: number;
330
+ workflowId: string;
331
+ }, string, Name>;
332
+ };
78
333
  sessions: {
79
334
  appendReasoning: FunctionReference<"mutation", "internal", {
80
335
  chunk: string;
336
+ orgId: string;
81
337
  sessionId: string;
82
338
  }, null, Name>;
83
339
  completeToolCall: FunctionReference<"mutation", "internal", {
340
+ orgId: string;
84
341
  resultJson: string;
85
342
  sessionId: string;
86
343
  toolName: string;
87
344
  }, null, Name>;
88
345
  completeTurn: FunctionReference<"mutation", "internal", {
346
+ orgId: string;
89
347
  sessionId: string;
90
348
  }, null, Name>;
91
349
  listEvents: FunctionReference<"query", "internal", {
350
+ orgId: string;
92
351
  sessionId: string;
93
352
  }, Array<{
94
353
  _creationTime: number;
95
354
  _id: string;
96
355
  createdAt: number;
97
- name: "session.started" | "turn.started" | "turn.reasoning" | "turn.toolCall.requested" | "turn.toolCall.completed" | "turn.completed" | "tool.approval.requested" | "tool.approval.resolved";
356
+ name: "session.started" | "turn.started" | "turn.reasoning" | "turn.toolCall.requested" | "turn.toolCall.completed" | "turn.toolCall.denied" | "turn.completed" | "tool.approval.requested" | "tool.approval.resolved" | "sandbox.timeout";
98
357
  payload?: string;
99
358
  }>, Name>;
100
359
  requestToolCall: FunctionReference<"mutation", "internal", {
101
360
  argsJson: string;
361
+ orgId: string;
102
362
  sessionId: string;
103
363
  toolName: string;
104
364
  }, {
105
365
  approvalPending: boolean;
106
366
  authorized: boolean;
367
+ denied: boolean;
107
368
  }, Name>;
108
369
  sendTurn: FunctionReference<"mutation", "internal", {
109
370
  input: string;
371
+ orgId: string;
110
372
  sessionId: string;
111
373
  }, null, Name>;
112
374
  start: FunctionReference<"mutation", "internal", {
113
375
  agentId: string;
114
- }, string, Name>;
376
+ createdBy: string;
377
+ orgId: string;
378
+ }, {
379
+ sessionId: string;
380
+ workflowId: string;
381
+ }, Name>;
115
382
  };
116
383
  toolApprovals: {
117
384
  respond: FunctionReference<"mutation", "internal", {
118
- approval: "always" | "once" | "never";
385
+ decision: "approved" | "denied";
386
+ orgId: string;
119
387
  sessionId: string;
120
388
  toolName: string;
389
+ updatePolicy?: "always" | "once" | "never";
121
390
  }, null, Name>;
122
391
  };
392
+ vpConnection: {
393
+ get: FunctionReference<"query", "internal", {
394
+ agentId: string;
395
+ orgId: string;
396
+ }, {
397
+ _creationTime: number;
398
+ _id: string;
399
+ agentId: string;
400
+ createdAt: number;
401
+ memoryEnabled: boolean;
402
+ messagesEnabled: boolean;
403
+ notesEnabled: boolean;
404
+ orgId: string;
405
+ tasksEnabled: boolean;
406
+ updatedAt: number;
407
+ } | null, Name>;
408
+ getToggles: FunctionReference<"query", "internal", {
409
+ agentId: string;
410
+ orgId: string;
411
+ }, {
412
+ memoryEnabled: boolean;
413
+ messagesEnabled: boolean;
414
+ notesEnabled: boolean;
415
+ tasksEnabled: boolean;
416
+ }, Name>;
417
+ invokeVpTool: FunctionReference<"action", "internal", {
418
+ agentId: string;
419
+ argsJson: string;
420
+ orgId: string;
421
+ tool: "memory" | "tasks" | "messages" | "notes";
422
+ vpFunctionHandle: string;
423
+ }, null, Name>;
424
+ setToggles: FunctionReference<"mutation", "internal", {
425
+ agentId: string;
426
+ memoryEnabled?: boolean;
427
+ messagesEnabled?: boolean;
428
+ notesEnabled?: boolean;
429
+ orgId: string;
430
+ tasksEnabled?: boolean;
431
+ }, string, Name>;
432
+ };
433
+ wakeup: {
434
+ cancel: FunctionReference<"mutation", "internal", {
435
+ orgId: string;
436
+ wakeableWorkId: string;
437
+ }, null, Name>;
438
+ enqueue: FunctionReference<"action", "internal", {
439
+ agentId: string;
440
+ awaitedEventName: string;
441
+ cost: number;
442
+ orgId: string;
443
+ payload?: string;
444
+ reason: string;
445
+ scope: string;
446
+ workFunctionHandle: string;
447
+ workflowId: string;
448
+ }, string, Name>;
449
+ getStatus: FunctionReference<"query", "internal", {
450
+ orgId: string;
451
+ wakeableWorkId: string;
452
+ }, {
453
+ resultSummary?: string;
454
+ status: "pending" | "completed" | "failed" | "cancelled";
455
+ }, Name>;
456
+ };
457
+ };
458
+ testFixtures: {
459
+ delegationDemoWorkflow: {
460
+ start: FunctionReference<"mutation", "internal", {
461
+ awaitedEventName: string;
462
+ orgId: string;
463
+ }, {
464
+ workflowId: string;
465
+ }, Name>;
466
+ };
467
+ sandboxDemoWorkflow: {
468
+ start: FunctionReference<"mutation", "internal", {
469
+ awaitedEventName: string;
470
+ orgId: string;
471
+ }, {
472
+ resultId: string;
473
+ workflowId: string;
474
+ }, Name>;
475
+ };
476
+ wakeupDemoWorkflow: {
477
+ start: FunctionReference<"mutation", "internal", {
478
+ awaitedEventName: string;
479
+ orgId: string;
480
+ }, {
481
+ resultId: string;
482
+ workflowId: string;
483
+ }, Name>;
484
+ };
123
485
  };
124
486
  };
@@ -2,6 +2,9 @@ import { defineComponent } from "convex/server";
2
2
  import workflow from "@convex-dev/workflow/convex.config";
3
3
  import workpool from "@convex-dev/workpool/convex.config";
4
4
  import agent from "@convex-dev/agent/convex.config";
5
+ import rateLimiter from "@convex-dev/rate-limiter/convex.config";
6
+ import shardedCounter from "@convex-dev/sharded-counter/convex.config";
7
+ import crons from "@convex-dev/crons/convex.config";
5
8
  // @vantageos/agent-engine — Convex COMPONENT definition (pattern
6
9
  // `@convex-dev/*`, verified against the published shape of
7
10
  // `@convex-dev/workflow` — `defineComponent(name)` + a `convex.config.ts`
@@ -32,9 +35,25 @@ import agent from "@convex-dev/agent/convex.config";
32
35
  // awaitEventTimeouts, wakeableWork) is deliberately NOT yet re-hosted
33
36
  // here — porting those without a working component-level test harness
34
37
  // behind each of them would violate Day 128 (never ship unverified).
38
+ // C3 (this pass): mandates ("notre ligne", autorité bornée) are now hosted
39
+ // under this component boundary, following the exact same trio the
40
+ // repo-root prototype used (I0 §3, `convex/convex.config.ts`) -- official
41
+ // `@convex-dev/*` libraries only, NO canary/alpha dependency for a
42
+ // guardrail: `rate-limiter` for the fails-closed spend gate itself,
43
+ // `sharded-counter` for the usage rollup. See component/engine/mandates.ts.
44
+ // C4 (this pass): habits ("notre ligne", un cron DYNAMIQUE par agent/org)
45
+ // are now hosted under this component boundary, ported byte-identical from
46
+ // the repo-root prototype (convex/habits.ts). `crons` is a sub-component of
47
+ // THIS component -- create/updateSchedule/enable/disable register or tear
48
+ // down a runtime cron job via `@convex-dev/crons` inside the SAME Convex
49
+ // mutation transaction that writes the `habits` row, so no habit schedule
50
+ // change ever requires a redeploy. See component/engine/habits.ts.
35
51
  const component = defineComponent("agentEngine");
36
52
  component.use(workflow);
37
53
  component.use(workpool, { name: "agentTurnPool" });
38
54
  component.use(workpool, { name: "wakeupPool" });
39
55
  component.use(agent);
56
+ component.use(rateLimiter);
57
+ component.use(shardedCounter);
58
+ component.use(crons);
40
59
  export default component;
@@ -1,4 +1,9 @@
1
1
  export declare const create: import("convex/server").RegisteredMutation<"public", {
2
+ description?: string | undefined;
3
+ reasoningEffort?: "none" | "low" | "medium" | "high" | undefined;
4
+ modelProvider?: "gateway" | "openrouter" | undefined;
5
+ maxSubagents?: number | undefined;
6
+ maxInputTokensPerSession?: number | false | undefined;
2
7
  name: string;
3
8
  orgId: string;
4
9
  instructions: string;
@@ -11,6 +16,11 @@ export declare const get: import("convex/server").RegisteredQuery<"public", {
11
16
  }, Promise<{
12
17
  _id: import("convex/values").GenericId<"agents">;
13
18
  _creationTime: number;
19
+ description?: string | undefined;
20
+ reasoningEffort?: "none" | "low" | "medium" | "high" | undefined;
21
+ modelProvider?: "gateway" | "openrouter" | undefined;
22
+ maxSubagents?: number | undefined;
23
+ maxInputTokensPerSession?: number | false | undefined;
14
24
  name: string;
15
25
  orgId: string;
16
26
  status: "draft" | "live" | "archived";
@@ -8,13 +8,21 @@ import { requireOrgId } from "../lib/auth.js";
8
8
  // `create`/`get`, no `update`/`list`/skills/connections — the full agent
9
9
  // aggregate CRUD stays out of this component boundary for this pass (see
10
10
  // component/schema.ts SCOPE note).
11
+ const reasoningEffort = v.union(v.literal("none"), v.literal("low"), v.literal("medium"), v.literal("high"));
12
+ const modelProvider = v.union(v.literal("gateway"), v.literal("openrouter"));
13
+ const maxInputTokensPerSession = v.union(v.number(), v.literal(false));
11
14
  const agentDoc = v.object({
12
15
  _id: v.id("agents"),
13
16
  _creationTime: v.number(),
14
17
  orgId: v.string(),
15
18
  name: v.string(),
19
+ description: v.optional(v.string()),
16
20
  instructions: v.string(),
17
21
  model: v.string(),
22
+ reasoningEffort: v.optional(reasoningEffort),
23
+ modelProvider: v.optional(modelProvider),
24
+ maxSubagents: v.optional(v.number()),
25
+ maxInputTokensPerSession: v.optional(maxInputTokensPerSession),
18
26
  status: v.union(v.literal("draft"), v.literal("live"), v.literal("archived")),
19
27
  createdBy: v.string(),
20
28
  createdAt: v.number(),
@@ -25,8 +33,13 @@ export const create = mutation({
25
33
  orgId: v.string(),
26
34
  createdBy: v.string(),
27
35
  name: v.string(),
36
+ description: v.optional(v.string()),
28
37
  instructions: v.string(),
29
38
  model: v.string(),
39
+ reasoningEffort: v.optional(reasoningEffort),
40
+ modelProvider: v.optional(modelProvider),
41
+ maxSubagents: v.optional(v.number()),
42
+ maxInputTokensPerSession: v.optional(maxInputTokensPerSession),
30
43
  },
31
44
  returns: v.id("agents"),
32
45
  handler: async (ctx, args) => {
@@ -43,12 +56,20 @@ export const create = mutation({
43
56
  if (args.model.trim().length === 0) {
44
57
  throw new Error("Validation: model must not be empty");
45
58
  }
59
+ if (args.maxSubagents !== undefined && args.maxSubagents < 0) {
60
+ throw new Error("Validation: maxSubagents must not be negative");
61
+ }
46
62
  const now = Date.now();
47
63
  return await ctx.db.insert("agents", {
48
64
  orgId,
49
65
  name: args.name,
66
+ description: args.description,
50
67
  instructions: args.instructions,
51
68
  model: args.model,
69
+ reasoningEffort: args.reasoningEffort,
70
+ modelProvider: args.modelProvider,
71
+ maxSubagents: args.maxSubagents,
72
+ maxInputTokensPerSession: args.maxInputTokensPerSession,
52
73
  status: "live",
53
74
  createdBy: args.createdBy,
54
75
  createdAt: now,
@@ -0,0 +1,13 @@
1
+ export declare const schedule: import("convex/server").RegisteredMutation<"public", {
2
+ orgId: string;
3
+ sessionId: import("convex/values").GenericId<"sessions">;
4
+ awaitedEventName: string;
5
+ timeoutMs: number;
6
+ }, Promise<import("convex/values").GenericId<"awaitEventTimeouts">>>;
7
+ export declare const cancel: import("convex/server").RegisteredMutation<"public", {
8
+ orgId: string;
9
+ timeoutRowId: import("convex/values").GenericId<"awaitEventTimeouts">;
10
+ }, Promise<null>>;
11
+ export declare const fire: import("convex/server").RegisteredMutation<"internal", {
12
+ timeoutRowId: import("convex/values").GenericId<"awaitEventTimeouts">;
13
+ }, Promise<null>>;
@@ -0,0 +1,82 @@
1
+ import { v } from "convex/values";
2
+ import { internal } from "../_generated/api.js";
3
+ import { internalMutation, mutation } from "../_generated/server.js";
4
+ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
5
+ // engine/awaitEventTimeout — self-built timeout for step.awaitEvent
6
+ // (workflow#177: "Convex does not provide a native timeout for
7
+ // awaitEvent"). PORTED from convex/engine/awaitEventTimeout.ts (repo-root
8
+ // prototype) into the component boundary (C2). We schedule a mutation that
9
+ // fires a "blank" `sandbox.timeout` sessionEvent at the deadline; the
10
+ // workflow's `awaitEvent` call is written to also accept this event name so
11
+ // it wakes up even if the awaited event never arrives. Pattern:
12
+ // maintainer's posted code in workflow#177, adapted to our sessionEvents
13
+ // table.
14
+ //
15
+ // C2 MIGRATION NOTE ("notre ligne"): orgId is an EXPLICIT ARGUMENT on
16
+ // every public function, never derived from `ctx.auth` -- auth does NOT
17
+ // propagate across a component boundary (component/lib/auth.ts). Also:
18
+ // `sessionEvents.name`'s union in component/schema.ts did not previously
19
+ // include `sandbox.timeout` -- it has been added there (and mirrored in
20
+ // `engine/sessions.listEvents`'s return validator) as part of this
21
+ // migration, otherwise `fire`'s insert below would not compile under the
22
+ // strict build.
23
+ export const schedule = mutation({
24
+ args: {
25
+ orgId: v.string(),
26
+ sessionId: v.id("sessions"),
27
+ awaitedEventName: v.string(),
28
+ timeoutMs: v.number(),
29
+ },
30
+ returns: v.id("awaitEventTimeouts"),
31
+ handler: async (ctx, args) => {
32
+ const orgId = requireOrgId(args.orgId);
33
+ const session = await ctx.db.get(args.sessionId);
34
+ assertSameOrg(orgId, session, "Session not found");
35
+ if (args.timeoutMs <= 0) {
36
+ throw new Error("Validation: timeoutMs must be > 0");
37
+ }
38
+ const timeoutRowId = await ctx.db.insert("awaitEventTimeouts", {
39
+ orgId,
40
+ sessionId: args.sessionId,
41
+ awaitedEventName: args.awaitedEventName,
42
+ deadlineAt: Date.now() + args.timeoutMs,
43
+ });
44
+ const scheduledFunctionId = await ctx.scheduler.runAfter(args.timeoutMs, internal.engine.awaitEventTimeout.fire, { timeoutRowId });
45
+ await ctx.db.patch(timeoutRowId, { scheduledFunctionId });
46
+ return timeoutRowId;
47
+ },
48
+ });
49
+ export const cancel = mutation({
50
+ args: { orgId: v.string(), timeoutRowId: v.id("awaitEventTimeouts") },
51
+ returns: v.null(),
52
+ handler: async (ctx, args) => {
53
+ const orgId = requireOrgId(args.orgId);
54
+ const row = await ctx.db.get(args.timeoutRowId);
55
+ assertSameOrg(orgId, row, "Timeout not found");
56
+ if (!row.firedAt && !row.cancelledAt && row.scheduledFunctionId) {
57
+ await ctx.scheduler.cancel(row.scheduledFunctionId);
58
+ await ctx.db.patch(args.timeoutRowId, { cancelledAt: Date.now() });
59
+ }
60
+ return null;
61
+ },
62
+ });
63
+ // internal — invoked only by the scheduler, never by a client.
64
+ export const fire = internalMutation({
65
+ args: { timeoutRowId: v.id("awaitEventTimeouts") },
66
+ returns: v.null(),
67
+ handler: async (ctx, args) => {
68
+ const row = await ctx.db.get(args.timeoutRowId);
69
+ if (!row || row.firedAt || row.cancelledAt) {
70
+ return null; // already resolved by the real event or by a prior fire
71
+ }
72
+ await ctx.db.patch(args.timeoutRowId, { firedAt: Date.now() });
73
+ await ctx.db.insert("sessionEvents", {
74
+ orgId: row.orgId,
75
+ sessionId: row.sessionId,
76
+ name: "sandbox.timeout",
77
+ payload: JSON.stringify({ awaitedEventName: row.awaitedEventName }),
78
+ createdAt: Date.now(),
79
+ });
80
+ return null;
81
+ },
82
+ });