@vantageos/agent-engine 0.1.0-alpha.7 → 0.3.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -50
- package/dist/component/_generated/api.d.ts +14 -27
- package/dist/component/_generated/api.js +0 -25
- package/dist/component/_generated/component.d.ts +369 -92
- package/dist/component/_generated/component.js +0 -9
- package/dist/component/_generated/dataModel.d.ts +0 -38
- package/dist/component/_generated/dataModel.js +0 -9
- package/dist/component/_generated/server.d.ts +0 -106
- package/dist/component/_generated/server.js +0 -69
- package/dist/component/convex.config.js +0 -44
- package/dist/component/engine/agents.js +0 -7
- package/dist/component/engine/awaitEventTimeout.d.ts +1 -1
- package/dist/component/engine/awaitEventTimeout.js +18 -26
- package/dist/component/engine/connections.d.ts +74 -0
- package/dist/component/engine/connections.js +254 -0
- package/dist/component/engine/delegation.d.ts +1 -1
- package/dist/component/engine/delegation.js +0 -74
- package/dist/component/engine/directory.js +0 -18
- package/dist/component/engine/durableJob.d.ts +34 -4
- package/dist/component/engine/durableJob.js +333 -86
- package/dist/component/engine/mandates.js +0 -59
- package/dist/component/engine/queue.d.ts +97 -0
- package/dist/component/engine/queue.js +201 -0
- package/dist/component/engine/resolvers.d.ts +1 -1
- package/dist/component/engine/resolvers.js +6 -18
- package/dist/component/engine/sandboxCallback.d.ts +1 -1
- package/dist/component/engine/sandboxCallback.js +2 -79
- package/dist/component/engine/sandboxConfigProvider.d.ts +9 -0
- package/dist/component/engine/sandboxConfigProvider.js +32 -0
- package/dist/component/engine/sessions.d.ts +28 -10
- package/dist/component/engine/sessions.js +153 -165
- package/dist/component/engine/streams.d.ts +47 -0
- package/dist/component/engine/streams.js +162 -0
- package/dist/component/engine/toolApprovals.d.ts +1 -1
- package/dist/component/engine/toolApprovals.js +12 -37
- package/dist/component/engine/vpConnection.js +0 -40
- package/dist/component/engine/wakeup.d.ts +5 -7
- package/dist/component/engine/wakeup.js +54 -127
- package/dist/component/engine/workflows.d.ts +42 -0
- package/dist/component/engine/workflows.js +100 -41
- package/dist/component/engine/world.d.ts +249 -0
- package/dist/component/engine/world.js +665 -0
- package/dist/component/lib/auth.js +0 -26
- package/dist/component/lib/connectionSecret.d.ts +5 -0
- package/dist/component/lib/connectionSecret.js +32 -0
- package/dist/component/schema.d.ts +227 -77
- package/dist/component/schema.js +137 -250
- package/package.json +17 -3
- package/dist/component/engine/habits.d.ts +0 -70
- package/dist/component/engine/habits.js +0 -218
- package/dist/component/testFixtures/callerSteps.d.ts +0 -20
- package/dist/component/testFixtures/callerSteps.js +0 -90
- package/dist/component/testFixtures/delegationDemoWorkflow.d.ts +0 -18
- package/dist/component/testFixtures/delegationDemoWorkflow.js +0 -75
- package/dist/component/testFixtures/sandboxDemoWorkflow.d.ts +0 -19
- package/dist/component/testFixtures/sandboxDemoWorkflow.js +0 -69
- package/dist/component/testFixtures/vpTool.d.ts +0 -4
- package/dist/component/testFixtures/vpTool.js +0 -25
- package/dist/component/testFixtures/wakeupDemoWorkflow.d.ts +0 -19
- package/dist/component/testFixtures/wakeupDemoWorkflow.js +0 -77
- package/dist/component/testFixtures/wakeupWork.d.ts +0 -8
- package/dist/component/testFixtures/wakeupWork.js +0 -21
package/dist/component/schema.js
CHANGED
|
@@ -1,27 +1,6 @@
|
|
|
1
1
|
import { defineSchema, defineTable } from "convex/server";
|
|
2
2
|
import { v } from "convex/values";
|
|
3
|
-
// @vantageos/agent-engine — COMPONENT schema (T2-QUATER).
|
|
4
|
-
//
|
|
5
|
-
// This is the schema that actually ships INSIDE the published package and
|
|
6
|
-
// is deployed under the component boundary when a consumer registers
|
|
7
|
-
// `app.use(agentEngine)` — as opposed to `convex/schema.ts` at the repo
|
|
8
|
-
// root, which only backs THIS repo's own dev/test deployment.
|
|
9
|
-
//
|
|
10
|
-
// SCOPE (T2-QUATER: durableJob only. T2-QUINQUIES, this pass: WIDENS the
|
|
11
|
-
// boundary to the SESSIONS surface a downstream conversation-thread
|
|
12
|
-
// consumer needs — session start/turn, streamed reasoning/tool-call events,
|
|
13
|
-
// toolApprovals response, replay on reconnect, dynamic resolver — see
|
|
14
|
-
// README "What's callable"). Still DELIBERATELY NARROW: `skills`,
|
|
15
|
-
// `connections`, `subagents`, `habits`, `sandboxConfig`, `modelKeys`,
|
|
16
|
-
// `mandates`, `awaitEventTimeouts`, `wakeableWork` are NOT re-hosted here —
|
|
17
|
-
// each of those needs its own component-level test harness first (Day 128:
|
|
18
|
-
// never ship unverified). `agents` is included, minimally, because a
|
|
19
|
-
// session cannot exist without an owning agent row the component itself
|
|
20
|
-
// can read (component isolation: this package cannot read a consumer app's
|
|
21
|
-
// OWN `agents` table across the component boundary).
|
|
22
3
|
export default defineSchema({
|
|
23
|
-
// durableJobs — GENERIC durable step-batch primitive. See
|
|
24
|
-
// engine/durableJob.ts for the full contract description.
|
|
25
4
|
durableJobs: defineTable({
|
|
26
5
|
orgId: v.string(),
|
|
27
6
|
kind: v.string(),
|
|
@@ -39,11 +18,6 @@ export default defineSchema({
|
|
|
39
18
|
})
|
|
40
19
|
.index("by_org", ["orgId"])
|
|
41
20
|
.index("by_org_status", ["orgId", "status"]),
|
|
42
|
-
// callerStepInvocations — TEST-ONLY fixture table, see
|
|
43
|
-
// convex/component/testFixtures/callerSteps.ts. Not part of the public
|
|
44
|
-
// contract; kept so the component-level test harness can prove the
|
|
45
|
-
// deterministic-replay / abandon-after-N properties the same way the
|
|
46
|
-
// repo-root test suite does.
|
|
47
21
|
callerStepInvocations: defineTable({
|
|
48
22
|
orgId: v.string(),
|
|
49
23
|
jobId: v.id("durableJobs"),
|
|
@@ -52,24 +26,16 @@ export default defineSchema({
|
|
|
52
26
|
})
|
|
53
27
|
.index("by_org", ["orgId"])
|
|
54
28
|
.index("by_org_job", ["orgId", "jobId"]),
|
|
55
|
-
// ---------------------------------------------------------------------
|
|
56
|
-
// T2-QUINQUIES — SESSIONS surface (EveVantage V4 conversation thread).
|
|
57
|
-
// ---------------------------------------------------------------------
|
|
58
|
-
// agents — minimal root sheet, ONLY the fields the sessions surface
|
|
59
|
-
// needs to resolve a manifest (name/instructions/model) + gate tool
|
|
60
|
-
// calls (via toolApprovals below). The full agent aggregate (skills,
|
|
61
|
-
// connections, subagents, habits, sandboxConfig, modelKeys) stays out of
|
|
62
|
-
// this component boundary for this pass — see the SCOPE note above.
|
|
63
29
|
agents: defineTable({
|
|
64
30
|
orgId: v.string(),
|
|
65
31
|
name: v.string(),
|
|
66
|
-
description: v.optional(v.string()),
|
|
32
|
+
description: v.optional(v.string()),
|
|
67
33
|
instructions: v.string(),
|
|
68
34
|
model: v.string(),
|
|
69
|
-
reasoningEffort: v.optional(v.union(v.literal("none"), v.literal("low"), v.literal("medium"), v.literal("high"))),
|
|
70
|
-
modelProvider: v.optional(v.union(v.literal("gateway"), v.literal("openrouter"))),
|
|
71
|
-
maxSubagents: v.optional(v.number()),
|
|
72
|
-
maxInputTokensPerSession: v.optional(v.union(v.number(), v.literal(false))),
|
|
35
|
+
reasoningEffort: v.optional(v.union(v.literal("none"), v.literal("low"), v.literal("medium"), v.literal("high"))),
|
|
36
|
+
modelProvider: v.optional(v.union(v.literal("gateway"), v.literal("openrouter"))),
|
|
37
|
+
maxSubagents: v.optional(v.number()),
|
|
38
|
+
maxInputTokensPerSession: v.optional(v.union(v.number(), v.literal(false))),
|
|
73
39
|
status: v.union(v.literal("draft"), v.literal("live"), v.literal("archived")),
|
|
74
40
|
createdBy: v.string(),
|
|
75
41
|
createdAt: v.number(),
|
|
@@ -77,11 +43,6 @@ export default defineSchema({
|
|
|
77
43
|
})
|
|
78
44
|
.index("by_org", ["orgId"])
|
|
79
45
|
.index("by_org_status", ["orgId", "status"]),
|
|
80
|
-
// toolApprovals — approval gate per (agent, tool), eve parity
|
|
81
|
-
// (public/definitions/tool.ts:117-125). "never" (default) means a tool
|
|
82
|
-
// call never pauses for human approval; "always"/"once" gate every /
|
|
83
|
-
// first call of a session via a `tool.approval.requested` sessionEvent
|
|
84
|
-
// that `toolApprovals.respond` resolves.
|
|
85
46
|
toolApprovals: defineTable({
|
|
86
47
|
orgId: v.string(),
|
|
87
48
|
agentId: v.id("agents"),
|
|
@@ -93,12 +54,6 @@ export default defineSchema({
|
|
|
93
54
|
.index("by_org", ["orgId"])
|
|
94
55
|
.index("by_org_agent", ["orgId", "agentId"])
|
|
95
56
|
.index("by_org_agent_tool", ["orgId", "agentId", "toolName"]),
|
|
96
|
-
// sessions — one conversation container per `sessions.start` call.
|
|
97
|
-
// "intentional divergence from Eve": a session is piloted by a VERSIONED
|
|
98
|
-
// `@convex-dev/workflow` run (engine/workflows.ts: sessionWorkflowV1), so
|
|
99
|
-
// a turn survives a deploy. `workflowId`/`workflowVersion` are optional:
|
|
100
|
-
// rows written before that workflow existed stay valid without a backfill,
|
|
101
|
-
// and a consumer driving turns itself may leave them unset.
|
|
102
57
|
sessions: defineTable({
|
|
103
58
|
orgId: v.string(),
|
|
104
59
|
agentId: v.id("agents"),
|
|
@@ -111,84 +66,28 @@ export default defineSchema({
|
|
|
111
66
|
})
|
|
112
67
|
.index("by_org", ["orgId"])
|
|
113
68
|
.index("by_org_agent", ["orgId", "agentId"]),
|
|
114
|
-
// sessionEvents — the append-only event log a client replays on
|
|
115
|
-
// reconnect (`sessions.listEvents`) and that IS the streaming transport:
|
|
116
|
-
// Convex query subscriptions push new rows to every subscriber in real
|
|
117
|
-
// time, so "streaming the reasoning and tool calls" is simply inserting
|
|
118
|
-
// rows here as they happen and letting reactivity carry them to the
|
|
119
|
-
// client — no separate transport needed. Event names mirror eve's
|
|
120
|
-
// session/turn boundaries (`session.started`, `turn.started`,
|
|
121
|
-
// dynamic-tool-definition.ts:40-46) plus the turn-body events this pass
|
|
122
|
-
// adds (reasoning chunks, tool-call lifecycle, approval lifecycle).
|
|
123
69
|
sessionEvents: defineTable({
|
|
124
70
|
orgId: v.string(),
|
|
125
71
|
sessionId: v.id("sessions"),
|
|
126
|
-
name: v.union(v.literal("session.started"), v.literal("turn.started"), v.literal("turn.reasoning"), v.literal("turn.toolCall.requested"), v.literal("turn.toolCall.completed"),
|
|
127
|
-
|
|
128
|
-
// explicit terminal state for a one-turn approval REFUSAL, distinct
|
|
129
|
-
// from "turn.toolCall.completed" (tool actually ran). Without this,
|
|
130
|
-
// a denied tool call had no event of its own -- a consumer had no
|
|
131
|
-
// way to tell "refused this turn" from "skipped, turn completed
|
|
132
|
-
// anyway", which is the wrong default a consumer had to code around.
|
|
133
|
-
v.literal("turn.toolCall.denied"), v.literal("turn.completed"), v.literal("tool.approval.requested"), v.literal("tool.approval.resolved"),
|
|
134
|
-
// Blank event auto-inserted by `engine/awaitEventTimeout.fire`
|
|
135
|
-
// (workflow#177: Convex provides no native timeout for
|
|
136
|
-
// `step.awaitEvent`). See engine/awaitEventTimeout.ts.
|
|
137
|
-
v.literal("sandbox.timeout")),
|
|
138
|
-
payload: v.optional(v.string()), // JSON-serialized, free contract per event name
|
|
72
|
+
name: v.union(v.literal("session.started"), v.literal("turn.started"), v.literal("turn.reasoning"), v.literal("turn.toolCall.requested"), v.literal("turn.toolCall.completed"), v.literal("turn.toolCall.denied"), v.literal("turn.completed"), v.literal("tool.approval.requested"), v.literal("tool.approval.resolved"), v.literal("sandbox.timeout")),
|
|
73
|
+
payload: v.optional(v.string()),
|
|
139
74
|
createdAt: v.number(),
|
|
140
75
|
})
|
|
141
76
|
.index("by_org", ["orgId"])
|
|
142
77
|
.index("by_org_session", ["orgId", "sessionId"]),
|
|
143
|
-
// ---------------------------------------------------------------------
|
|
144
|
-
// WAKE-UP WITHOUT POLLING. See engine/wakeup.ts and
|
|
145
|
-
// engine/awaitEventTimeout.ts for the mechanism itself.
|
|
146
|
-
// ---------------------------------------------------------------------
|
|
147
|
-
// wakeableWork — GENERIC wake-up primitive. `enqueue` puts caller-supplied
|
|
148
|
-
// work (an action, referenced by an opaque function-handle string) into a
|
|
149
|
-
// dedicated `@convex-dev/workpool`; that pool's `onComplete` callback
|
|
150
|
-
// calls `workflow.sendEvent(...)` against the CALLER-supplied
|
|
151
|
-
// `workflowId` the instant the work resolves — success, failure, OR
|
|
152
|
-
// cancellation alike. Zero setInterval, zero cron.
|
|
153
|
-
wakeableWork: defineTable({
|
|
154
|
-
orgId: v.string(),
|
|
155
|
-
workflowId: v.string(), // target: the workflow parked on step.awaitEvent
|
|
156
|
-
awaitedEventName: v.string(), // event name that workflow is awaiting
|
|
157
|
-
workId: v.string(), // @convex-dev/workpool WorkId, opaque string
|
|
158
|
-
status: v.union(v.literal("pending"), v.literal("completed"), // work succeeded
|
|
159
|
-
v.literal("failed"), // work threw
|
|
160
|
-
v.literal("cancelled")),
|
|
161
|
-
resultSummary: v.optional(v.string()), // error message when status=="failed"
|
|
162
|
-
createdAt: v.number(),
|
|
163
|
-
updatedAt: v.number(),
|
|
164
|
-
})
|
|
165
|
-
.index("by_org", ["orgId"])
|
|
166
|
-
.index("by_org_workflow", ["orgId", "workflowId"]),
|
|
167
|
-
// awaitEventTimeouts — self-built timeout for `step.awaitEvent`
|
|
168
|
-
// (workflow#177: "Convex does not provide a native timeout for
|
|
169
|
-
// awaitEvent"). A scheduled mutation (`ctx.scheduler.runAfter`) fires a
|
|
170
|
-
// blank `sandbox.timeout` sessionEvent if the awaited event never arrives
|
|
171
|
-
// before `deadlineAt`.
|
|
172
78
|
awaitEventTimeouts: defineTable({
|
|
173
79
|
orgId: v.string(),
|
|
174
|
-
|
|
80
|
+
runId: v.optional(v.string()),
|
|
81
|
+
sessionId: v.optional(v.id("sessions")),
|
|
175
82
|
awaitedEventName: v.string(),
|
|
176
83
|
deadlineAt: v.number(),
|
|
177
|
-
// optional: patched right after insert, once the scheduled function
|
|
178
|
-
// itself has been created (it needs this row's id as its argument).
|
|
179
84
|
scheduledFunctionId: v.optional(v.id("_scheduled_functions")),
|
|
180
85
|
firedAt: v.optional(v.number()),
|
|
181
86
|
cancelledAt: v.optional(v.number()),
|
|
182
87
|
})
|
|
183
88
|
.index("by_org", ["orgId"])
|
|
184
|
-
.index("by_org_session", ["orgId", "sessionId"])
|
|
185
|
-
|
|
186
|
-
// component/testFixtures/wakeupDemoWorkflow.ts. Not part of the public
|
|
187
|
-
// contract; a reference recipient workflow parked on `step.awaitEvent`
|
|
188
|
-
// patches `wokenAt`/`observedStatus` here ONLY after
|
|
189
|
-
// `engine/wakeup.onWorkComplete` has called `sendEvent` -- its presence
|
|
190
|
-
// is the test-observable proof that the wake mechanism (not a poll)
|
|
191
|
-
// resumed the workflow. Same discipline as `callerStepInvocations` above.
|
|
89
|
+
.index("by_org_session", ["orgId", "sessionId"])
|
|
90
|
+
.index("by_org_run", ["orgId", "runId"]),
|
|
192
91
|
wakeupDemoResults: defineTable({
|
|
193
92
|
orgId: v.string(),
|
|
194
93
|
enqueuedAt: v.number(),
|
|
@@ -196,23 +95,13 @@ export default defineSchema({
|
|
|
196
95
|
observedStatus: v.optional(v.union(v.literal("completed"), v.literal("failed"), v.literal("cancelled"))),
|
|
197
96
|
observedResultSummary: v.optional(v.string()),
|
|
198
97
|
}).index("by_org", ["orgId"]),
|
|
199
|
-
// ---------------------------------------------------------------------
|
|
200
|
-
// MANDATES — "intentional divergence from Eve": bounded authority. See
|
|
201
|
-
// engine/mandates.ts and engine/wakeup.ts, where `enqueue` funds through
|
|
202
|
-
// `mandates.spendInternal` before any work can enter the wakeup pool.
|
|
203
|
-
// ---------------------------------------------------------------------
|
|
204
|
-
// mandates — a cap is a DATA row scoped by orgId + agentId + scope,
|
|
205
|
-
// never a constant read from code. `kind`/`rate`/`period`/`capacity` are
|
|
206
|
-
// the inline contract of @convex-dev/rate-limiter ("dynamic config"): the
|
|
207
|
-
// COST (`count`) is a WEIGHTED count (tokens/euros/calls), never a plain
|
|
208
|
-
// call counter. Changing a cap is a row mutation, never a deployment.
|
|
209
98
|
mandates: defineTable({
|
|
210
99
|
orgId: v.string(),
|
|
211
100
|
agentId: v.id("agents"),
|
|
212
|
-
scope: v.string(),
|
|
101
|
+
scope: v.string(),
|
|
213
102
|
kind: v.union(v.literal("token bucket"), v.literal("fixed window")),
|
|
214
103
|
rate: v.number(),
|
|
215
|
-
period: v.number(),
|
|
104
|
+
period: v.number(),
|
|
216
105
|
capacity: v.optional(v.number()),
|
|
217
106
|
createdAt: v.number(),
|
|
218
107
|
updatedAt: v.number(),
|
|
@@ -220,9 +109,6 @@ export default defineSchema({
|
|
|
220
109
|
.index("by_org", ["orgId"])
|
|
221
110
|
.index("by_org_agent", ["orgId", "agentId"])
|
|
222
111
|
.index("by_org_agent_scope", ["orgId", "agentId", "scope"]),
|
|
223
|
-
// approvalRequests — created whenever a mandate is exceeded. NEVER a
|
|
224
|
-
// silent bypass: an overrun always becomes a persisted HUMAN approval
|
|
225
|
-
// request, never a silent refusal with no trace.
|
|
226
112
|
approvalRequests: defineTable({
|
|
227
113
|
orgId: v.string(),
|
|
228
114
|
agentId: v.id("agents"),
|
|
@@ -237,77 +123,15 @@ export default defineSchema({
|
|
|
237
123
|
.index("by_org", ["orgId"])
|
|
238
124
|
.index("by_org_agent", ["orgId", "agentId"])
|
|
239
125
|
.index("by_org_status", ["orgId", "status"]),
|
|
240
|
-
// ---------------------------------------------------------------------
|
|
241
|
-
// HABITS — "intentional divergence from Eve": a habit is a DYNAMIC cron
|
|
242
|
-
// per agent/org, which is what turns a chat into an employee. See
|
|
243
|
-
// engine/habits.ts; `crons` is a sub-component of THIS component,
|
|
244
|
-
// registered in component/convex.config.ts.
|
|
245
|
-
// ---------------------------------------------------------------------
|
|
246
|
-
// habits — a schedule is a DATA row scoped by orgId + agentId, never a
|
|
247
|
-
// constant read from a deployed `convex/crons.ts`. `cronExpression` is
|
|
248
|
-
// the DATA that drives the runtime cron registered via
|
|
249
|
-
// `@convex-dev/crons`; create/updateSchedule/enable/disable never
|
|
250
|
-
// redeploy anything.
|
|
251
|
-
habits: defineTable({
|
|
252
|
-
orgId: v.string(),
|
|
253
|
-
agentId: v.id("agents"),
|
|
254
|
-
name: v.string(),
|
|
255
|
-
cronExpression: v.string(),
|
|
256
|
-
prompt: v.string(),
|
|
257
|
-
enabled: v.boolean(),
|
|
258
|
-
// id of the runtime-registered @convex-dev/crons job, present only
|
|
259
|
-
// while `enabled` is true (cleared by `disable`, reassigned by
|
|
260
|
-
// `enable` / `updateSchedule` -- no redeploy involved in any transition).
|
|
261
|
-
cronJobId: v.optional(v.string()),
|
|
262
|
-
lastRunAt: v.optional(v.number()),
|
|
263
|
-
createdAt: v.number(),
|
|
264
|
-
updatedAt: v.number(),
|
|
265
|
-
})
|
|
266
|
-
.index("by_org", ["orgId"])
|
|
267
|
-
.index("by_org_agent", ["orgId", "agentId"]),
|
|
268
|
-
// habitRuns — proof of execution of a habit (MUST_PASS/MUST_BLOCK probe,
|
|
269
|
-
// component/habits.componentPackaging.test.ts). Every tick of the runtime
|
|
270
|
-
// cron registered via @convex-dev/crons writes a row here -- this is what
|
|
271
|
-
// makes "fires its first run without a deploy" PROVABLE rather than
|
|
272
|
-
// asserted on trust.
|
|
273
|
-
habitRuns: defineTable({
|
|
274
|
-
orgId: v.string(),
|
|
275
|
-
habitId: v.id("habits"),
|
|
276
|
-
agentId: v.id("agents"),
|
|
277
|
-
ranAt: v.number(),
|
|
278
|
-
})
|
|
279
|
-
.index("by_org", ["orgId"])
|
|
280
|
-
.index("by_org_habit", ["orgId", "habitId"]),
|
|
281
|
-
// ---------------------------------------------------------------------
|
|
282
|
-
// SANDBOX BRIDGE — the same pause/wake mechanism serves both the sandbox
|
|
283
|
-
// and agent-to-agent delegation. See engine/sandboxCallback.ts.
|
|
284
|
-
//
|
|
285
|
-
// BOUNDARY, and why it is where it is: the "use node" action
|
|
286
|
-
// that actually talks to `@vercel/sandbox` CANNOT live inside this
|
|
287
|
-
// component — the
|
|
288
|
-
// Convex CLI's own component bundler HARD-CRASHES on any "use node" file
|
|
289
|
-
// found in a child component directory ("use node directive is not
|
|
290
|
-
// supported in components", node_modules/convex/dist/cjs/cli/lib/
|
|
291
|
-
// components/definition/bundle.js). It stays app-level and calls INTO
|
|
292
|
-
// this component's public `engine.sandboxCallback.startRun` /
|
|
293
|
-
// `attachSandboxId` (and `engine.mandates.spend`) instead. Likewise, no
|
|
294
|
-
// official `@convex-dev/*` component ships an `http.ts` or reads
|
|
295
|
-
// `process.env` directly (measured: zero hits across all 7 installed
|
|
296
|
-
// `@convex-dev/*` component dist trees) — the signed callback's public
|
|
297
|
-
// HTTP route (`/sandbox/callback`) and its `SANDBOX_CALLBACK_SECRET`
|
|
298
|
-
// read + HMAC verification stay in the CONSUMER app's `convex/http.ts`,
|
|
299
|
-
// which delegates to this component's public
|
|
300
|
-
// `engine.sandboxCallback.processCallback` /
|
|
301
|
-
// `engine.sandboxCallback.deadLetterMalformed` ONLY after the signature
|
|
302
|
-
// has already checked out.
|
|
303
126
|
sandboxConfig: defineTable({
|
|
304
127
|
orgId: v.string(),
|
|
305
128
|
agentId: v.id("agents"),
|
|
306
|
-
provider: v.literal("vercel-sandbox"),
|
|
129
|
+
provider: v.union(v.literal("vercel-sandbox"), v.literal("e2b"), v.literal("daytona"), v.literal("box")),
|
|
307
130
|
image: v.optional(v.string()),
|
|
308
131
|
timeoutSeconds: v.number(),
|
|
309
132
|
egressPolicy: v.union(v.literal("allow-all"), v.literal("deny-all-allowlist")),
|
|
310
133
|
allowlistDomains: v.array(v.string()),
|
|
134
|
+
boxId: v.optional(v.string()),
|
|
311
135
|
createdAt: v.number(),
|
|
312
136
|
updatedAt: v.number(),
|
|
313
137
|
})
|
|
@@ -315,9 +139,9 @@ export default defineSchema({
|
|
|
315
139
|
.index("by_org_agent", ["orgId", "agentId"]),
|
|
316
140
|
sandboxRuns: defineTable({
|
|
317
141
|
orgId: v.string(),
|
|
318
|
-
workflowId: v.string(),
|
|
319
|
-
awaitedEventName: v.string(),
|
|
320
|
-
sandboxId: v.string(),
|
|
142
|
+
workflowId: v.string(),
|
|
143
|
+
awaitedEventName: v.string(),
|
|
144
|
+
sandboxId: v.string(),
|
|
321
145
|
status: v.union(v.literal("pending"), v.literal("completed"), v.literal("failed"), v.literal("timedOut")),
|
|
322
146
|
resultSummary: v.optional(v.string()),
|
|
323
147
|
createdAt: v.number(),
|
|
@@ -329,39 +153,24 @@ export default defineSchema({
|
|
|
329
153
|
sandboxCallbackDeliveries: defineTable({
|
|
330
154
|
orgId: v.string(),
|
|
331
155
|
sandboxRunId: v.id("sandboxRuns"),
|
|
332
|
-
deliveryId: v.string(),
|
|
333
|
-
outcome: v.union(v.literal("woke"),
|
|
334
|
-
v.literal("duplicate")),
|
|
156
|
+
deliveryId: v.string(),
|
|
157
|
+
outcome: v.union(v.literal("woke"), v.literal("duplicate")),
|
|
335
158
|
receivedAt: v.number(),
|
|
336
159
|
})
|
|
337
160
|
.index("by_org", ["orgId"])
|
|
338
161
|
.index("by_org_delivery", ["orgId", "deliveryId"])
|
|
339
162
|
.index("by_org_run", ["orgId", "sandboxRunId"]),
|
|
340
163
|
sandboxCallbackDeadLetters: defineTable({
|
|
341
|
-
orgId: v.optional(v.string()),
|
|
164
|
+
orgId: v.optional(v.string()),
|
|
342
165
|
deliveryId: v.string(),
|
|
343
166
|
reason: v.string(),
|
|
344
167
|
rawBody: v.string(),
|
|
345
168
|
createdAt: v.number(),
|
|
346
169
|
}).index("by_org", ["orgId"]),
|
|
347
|
-
// ---------------------------------------------------------------------
|
|
348
|
-
// DELEGATION — an agent delegating to another agent uses THE SAME
|
|
349
|
-
// pause/wake system as the sandbox bridge: one system to maintain, not
|
|
350
|
-
// two. See engine/delegation.ts and engine/vpConnection.ts: every
|
|
351
|
-
// delegation/clone path terminates in exactly one call to this
|
|
352
|
-
// component's own public `engine/wakeup.enqueue`, never in a second
|
|
353
|
-
// onComplete/sendEvent path.
|
|
354
|
-
// ---------------------------------------------------------------------
|
|
355
|
-
// subagents — declared subagents, RECURSIVE (the child is a full
|
|
356
|
-
// `agents` row with its own aggregate). Isolation is by construction
|
|
357
|
-
// (eve.dev/docs/subagents: "inherits nothing from the root's authored
|
|
358
|
-
// slots") -- this table ONLY declares the parent->child link and exposes
|
|
359
|
-
// it as a named tool; it never copies a single field out of the child's
|
|
360
|
-
// own skills/connections/toolApprovals onto the parent.
|
|
361
170
|
subagents: defineTable({
|
|
362
171
|
orgId: v.string(),
|
|
363
172
|
parentAgentId: v.id("agents"),
|
|
364
|
-
childAgentId: v.id("agents"),
|
|
173
|
+
childAgentId: v.id("agents"),
|
|
365
174
|
toolName: v.string(),
|
|
366
175
|
description: v.optional(v.string()),
|
|
367
176
|
enabled: v.boolean(),
|
|
@@ -370,16 +179,7 @@ export default defineSchema({
|
|
|
370
179
|
.index("by_org", ["orgId"])
|
|
371
180
|
.index("by_org_parent", ["orgId", "parentAgentId"])
|
|
372
181
|
.index("by_org_child", ["orgId", "childAgentId"])
|
|
373
|
-
// Build-time collision guard (engine/delegation.declareSubagent):
|
|
374
|
-
// exact-match lookup of an existing (parent, toolName) pair, no filter().
|
|
375
182
|
.index("by_org_parent_tool", ["orgId", "parentAgentId", "toolName"]),
|
|
376
|
-
// delegationRuns — one row per A->B delegation through a declared
|
|
377
|
-
// subagent (`subagents` table above). `workflowId`/`awaitedEventName` are
|
|
378
|
-
// the SAME two fields `engine/wakeup.enqueue` already threads through to
|
|
379
|
-
// `workflow.sendEvent` -- this table records WHICH delegation a given
|
|
380
|
-
// `wakeableWork` row belongs to; it never duplicates the wake mechanism
|
|
381
|
-
// itself (no second onComplete/sendEvent path exists anywhere in this
|
|
382
|
-
// engine).
|
|
383
183
|
delegationRuns: defineTable({
|
|
384
184
|
orgId: v.string(),
|
|
385
185
|
parentAgentId: v.id("agents"),
|
|
@@ -396,17 +196,9 @@ export default defineSchema({
|
|
|
396
196
|
.index("by_org_parent", ["orgId", "parentAgentId"])
|
|
397
197
|
.index("by_org_workflow", ["orgId", "workflowId"])
|
|
398
198
|
.index("by_org_awaitedEvent", ["orgId", "awaitedEventName"]),
|
|
399
|
-
// agentCloneRuns — the built-in `agent` tool (eve.dev/docs/subagents: "the
|
|
400
|
-
// built-in `agent` tool clones the ROOT, root-only, NOT recursive -- it
|
|
401
|
-
// cannot call itself"). `viaAgentTool` is the recursion guard: a clone
|
|
402
|
-
// invocation started BY a clone invocation (viaAgentTool: true passed in)
|
|
403
|
-
// is refused at `engine/delegation.invokeAgentClone` BEFORE any row here
|
|
404
|
-
// is written -- so every row in this table by construction has
|
|
405
|
-
// `viaAgentTool === false` on entry. Wakes through the SAME
|
|
406
|
-
// `engine/wakeup.enqueue` mechanism as `delegationRuns`.
|
|
407
199
|
agentCloneRuns: defineTable({
|
|
408
200
|
orgId: v.string(),
|
|
409
|
-
agentId: v.id("agents"),
|
|
201
|
+
agentId: v.id("agents"),
|
|
410
202
|
workflowId: v.string(),
|
|
411
203
|
awaitedEventName: v.string(),
|
|
412
204
|
status: v.union(v.literal("pending"), v.literal("completed"), v.literal("failed"), v.literal("cancelled")),
|
|
@@ -416,14 +208,6 @@ export default defineSchema({
|
|
|
416
208
|
})
|
|
417
209
|
.index("by_org", ["orgId"])
|
|
418
210
|
.index("by_org_agent", ["orgId", "agentId"]),
|
|
419
|
-
// vpConnections — teamwork. The
|
|
420
|
-
// four VantagePeers tools (memory, tasks, messages, notes) wired as a
|
|
421
|
-
// CONNECTION of the agent aggregate, an intentional divergence from Eve. 0..1 row per agent;
|
|
422
|
-
// absence means "use the defaults" (all four ON) -- see
|
|
423
|
-
// `engine/vpConnection.ts:defaultToggles`. DIRECT access: invocation
|
|
424
|
-
// goes through a caller-supplied Convex function handle
|
|
425
|
-
// (`createFunctionHandle`, same discipline as `wakeableWork.workId` /
|
|
426
|
-
// `durableJobs.stepFunctionHandle`), never a `fetch()` call.
|
|
427
211
|
vpConnections: defineTable({
|
|
428
212
|
orgId: v.string(),
|
|
429
213
|
agentId: v.id("agents"),
|
|
@@ -436,9 +220,6 @@ export default defineSchema({
|
|
|
436
220
|
})
|
|
437
221
|
.index("by_org", ["orgId"])
|
|
438
222
|
.index("by_org_agent", ["orgId", "agentId"]),
|
|
439
|
-
// vpToolInvocations — audit trail of every VantagePeers tool call an
|
|
440
|
-
// agent made, ALWAYS written by `engine/vpConnection.invokeVpTool` in the
|
|
441
|
-
// SAME transaction family as the call itself.
|
|
442
223
|
vpToolInvocations: defineTable({
|
|
443
224
|
orgId: v.string(),
|
|
444
225
|
agentId: v.id("agents"),
|
|
@@ -447,18 +228,124 @@ export default defineSchema({
|
|
|
447
228
|
})
|
|
448
229
|
.index("by_org", ["orgId"])
|
|
449
230
|
.index("by_org_agent", ["orgId", "agentId"]),
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
231
|
+
connections: defineTable({
|
|
232
|
+
orgId: v.string(),
|
|
233
|
+
agentId: v.id("agents"),
|
|
234
|
+
type: v.union(v.literal("mcp"), v.literal("openapi")),
|
|
235
|
+
name: v.string(),
|
|
236
|
+
serverConfig: v.string(),
|
|
237
|
+
authMode: v.union(v.literal("app-token"), v.literal("user-oauth"), v.literal("none"), v.literal("header")),
|
|
238
|
+
encryptedSecretCiphertext: v.optional(v.string()),
|
|
239
|
+
encryptedSecretIv: v.optional(v.string()),
|
|
240
|
+
status: v.union(v.literal("active"), v.literal("pending_authorization"), v.literal("error")),
|
|
241
|
+
createdAt: v.number(),
|
|
242
|
+
updatedAt: v.number(),
|
|
243
|
+
})
|
|
244
|
+
.index("by_org", ["orgId"])
|
|
245
|
+
.index("by_org_agent", ["orgId", "agentId"]),
|
|
246
|
+
connectionAuthorizations: defineTable({
|
|
247
|
+
orgId: v.string(),
|
|
248
|
+
connectionId: v.id("connections"),
|
|
249
|
+
workflowId: v.string(),
|
|
250
|
+
awaitedEventName: v.string(),
|
|
251
|
+
url: v.string(),
|
|
252
|
+
userCode: v.string(),
|
|
253
|
+
status: v.union(v.literal("pending"), v.literal("authorized"), v.literal("denied")),
|
|
254
|
+
resultSummary: v.optional(v.string()),
|
|
255
|
+
createdAt: v.number(),
|
|
256
|
+
updatedAt: v.number(),
|
|
257
|
+
resolvedAt: v.optional(v.number()),
|
|
258
|
+
})
|
|
259
|
+
.index("by_org", ["orgId"])
|
|
260
|
+
.index("by_org_connection", ["orgId", "connectionId"]),
|
|
458
261
|
vpTenantFixture: defineTable({
|
|
459
262
|
orgId: v.string(),
|
|
460
263
|
tool: v.union(v.literal("memory"), v.literal("tasks"), v.literal("messages"), v.literal("notes")),
|
|
461
264
|
argsJson: v.string(),
|
|
462
265
|
createdAt: v.number(),
|
|
463
266
|
}).index("by_org", ["orgId"]),
|
|
267
|
+
worldRuns: defineTable({
|
|
268
|
+
orgId: v.string(),
|
|
269
|
+
runId: v.string(),
|
|
270
|
+
status: v.union(v.literal("running"), v.literal("completed"), v.literal("failed"), v.literal("cancelled")),
|
|
271
|
+
eventCount: v.number(),
|
|
272
|
+
createdAt: v.number(),
|
|
273
|
+
updatedAt: v.number(),
|
|
274
|
+
})
|
|
275
|
+
.index("by_org", ["orgId"])
|
|
276
|
+
.index("by_org_run", ["orgId", "runId"]),
|
|
277
|
+
worldSteps: defineTable({
|
|
278
|
+
orgId: v.string(),
|
|
279
|
+
runId: v.string(),
|
|
280
|
+
stepId: v.string(),
|
|
281
|
+
status: v.union(v.literal("running"), v.literal("completed"), v.literal("failed")),
|
|
282
|
+
dataJson: v.optional(v.string()),
|
|
283
|
+
createdAt: v.number(),
|
|
284
|
+
updatedAt: v.number(),
|
|
285
|
+
})
|
|
286
|
+
.index("by_org_run", ["orgId", "runId"])
|
|
287
|
+
.index("by_org_run_step", ["orgId", "runId", "stepId"]),
|
|
288
|
+
worldHooks: defineTable({
|
|
289
|
+
orgId: v.string(),
|
|
290
|
+
runId: v.string(),
|
|
291
|
+
hookId: v.string(),
|
|
292
|
+
token: v.string(),
|
|
293
|
+
status: v.union(v.literal("pending"), v.literal("disposed")),
|
|
294
|
+
createdAt: v.number(),
|
|
295
|
+
updatedAt: v.number(),
|
|
296
|
+
})
|
|
297
|
+
.index("by_org_run", ["orgId", "runId"])
|
|
298
|
+
.index("by_org_hook", ["orgId", "hookId"])
|
|
299
|
+
.index("by_org_token", ["orgId", "token"]),
|
|
300
|
+
worldEvents: defineTable({
|
|
301
|
+
orgId: v.string(),
|
|
302
|
+
runId: v.string(),
|
|
303
|
+
seq: v.number(),
|
|
304
|
+
eventType: v.string(),
|
|
305
|
+
stepId: v.optional(v.string()),
|
|
306
|
+
hookId: v.optional(v.string()),
|
|
307
|
+
correlationId: v.optional(v.string()),
|
|
308
|
+
dataJson: v.string(),
|
|
309
|
+
createdAt: v.number(),
|
|
310
|
+
})
|
|
311
|
+
.index("by_org_run", ["orgId", "runId"])
|
|
312
|
+
.index("by_org_run_seq", ["orgId", "runId", "seq"])
|
|
313
|
+
.index("by_org_correlation", ["orgId", "correlationId"]),
|
|
314
|
+
worldQueueMessages: defineTable({
|
|
315
|
+
orgId: v.string(),
|
|
316
|
+
queueName: v.string(),
|
|
317
|
+
messageId: v.string(),
|
|
318
|
+
payloadJson: v.string(),
|
|
319
|
+
idempotencyKey: v.optional(v.string()),
|
|
320
|
+
attempt: v.number(),
|
|
321
|
+
status: v.union(v.literal("pending"), v.literal("claimed"), v.literal("delivered"), v.literal("failed")),
|
|
322
|
+
deliverAt: v.number(),
|
|
323
|
+
createdAt: v.number(),
|
|
324
|
+
updatedAt: v.number(),
|
|
325
|
+
})
|
|
326
|
+
.index("by_org", ["orgId"])
|
|
327
|
+
.index("by_org_queue", ["orgId", "queueName"])
|
|
328
|
+
.index("by_org_message", ["orgId", "messageId"])
|
|
329
|
+
.index("by_org_queue_idempotencyKey", ["orgId", "queueName", "idempotencyKey"])
|
|
330
|
+
.index("by_org_queue_status_deliverAt", ["orgId", "queueName", "status", "deliverAt"]),
|
|
331
|
+
worldStreams: defineTable({
|
|
332
|
+
orgId: v.string(),
|
|
333
|
+
runId: v.string(),
|
|
334
|
+
name: v.string(),
|
|
335
|
+
chunkCount: v.number(),
|
|
336
|
+
done: v.boolean(),
|
|
337
|
+
createdAt: v.number(),
|
|
338
|
+
updatedAt: v.number(),
|
|
339
|
+
})
|
|
340
|
+
.index("by_org", ["orgId"])
|
|
341
|
+
.index("by_org_run", ["orgId", "runId"])
|
|
342
|
+
.index("by_org_run_name", ["orgId", "runId", "name"]),
|
|
343
|
+
worldStreamChunks: defineTable({
|
|
344
|
+
orgId: v.string(),
|
|
345
|
+
runId: v.string(),
|
|
346
|
+
name: v.string(),
|
|
347
|
+
index: v.number(),
|
|
348
|
+
dataBase64: v.string(),
|
|
349
|
+
createdAt: v.number(),
|
|
350
|
+
}).index("by_org_run_name_index", ["orgId", "runId", "name", "index"]),
|
|
464
351
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vantageos/agent-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-alpha.0",
|
|
4
4
|
"description": "Reusable Convex component: durable agent engine. Agent = data aggregate (root sheet + child tables), never compiled code. Built on @convex-dev/workflow + @convex-dev/workpool (+ @convex-dev/agent). Eve parity by design.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
|
22
|
+
"!dist/component/testFixtures",
|
|
22
23
|
"README.md",
|
|
23
24
|
"LICENSE"
|
|
24
25
|
],
|
|
@@ -38,9 +39,15 @@
|
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
|
40
41
|
"dev": "convex dev",
|
|
41
|
-
"test": "vitest run",
|
|
42
|
+
"test": "npm run typecheck:build && npm run check:consumer-types && vitest run && npm run test:guard && npm run test:world-convex && npm run test:first-orchestrator",
|
|
43
|
+
"test:guard": "node --test evidence-skills/evals/guard.test.mjs",
|
|
44
|
+
"test:world-convex": "npm ci --prefix world-convex && npm test --prefix world-convex",
|
|
45
|
+
"test:first-orchestrator": "npm ci --prefix first-orchestrator && npm test --prefix first-orchestrator",
|
|
42
46
|
"test:watch": "vitest",
|
|
47
|
+
"validate:agent-standard": "vitest run convex/lib/agentStandardValidator.test.ts",
|
|
43
48
|
"typecheck": "tsc --noEmit",
|
|
49
|
+
"typecheck:build": "tsc -p tsconfig.build.json --noEmit",
|
|
50
|
+
"check:consumer-types": "node scripts/check-consumer-types.mjs",
|
|
44
51
|
"build": "tsc -p tsconfig.build.json",
|
|
45
52
|
"prepublishOnly": "npm run build && npm run check:public",
|
|
46
53
|
"check:generated": "node scripts/check-generated-freshness.mjs",
|
|
@@ -55,6 +62,7 @@
|
|
|
55
62
|
"@convex-dev/sharded-counter": "^0.2.1",
|
|
56
63
|
"@convex-dev/workflow": "0.4.4",
|
|
57
64
|
"@convex-dev/workpool": "0.4.7",
|
|
65
|
+
"@vantageos/cloud-identity": "0.21.3",
|
|
58
66
|
"@vercel/sandbox": "^2.6.1",
|
|
59
67
|
"ai": "6.0.35",
|
|
60
68
|
"convex": "1.42.1",
|
|
@@ -62,8 +70,14 @@
|
|
|
62
70
|
},
|
|
63
71
|
"devDependencies": {
|
|
64
72
|
"@edge-runtime/vm": "5.0.0",
|
|
73
|
+
"@types/node": "^26.1.2",
|
|
65
74
|
"convex-test": "0.0.54",
|
|
66
75
|
"typescript": "5.7.3",
|
|
67
|
-
"vitest": "2.
|
|
76
|
+
"vitest": "3.2.6"
|
|
77
|
+
},
|
|
78
|
+
"overrides": {
|
|
79
|
+
"nanoid": "^3.3.18",
|
|
80
|
+
"tinypool": "^2.1.2",
|
|
81
|
+
"vite": "^6.4.4"
|
|
68
82
|
}
|
|
69
83
|
}
|