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

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.
@@ -35,15 +35,14 @@ import crons from "@convex-dev/crons/convex.config";
35
35
  // awaitEventTimeouts, wakeableWork) is deliberately NOT yet re-hosted
36
36
  // here — porting those without a working component-level test harness
37
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
38
+ // Mandates (bounded, weighted spending authority per agent/org/scope) are
39
+ // hosted under this component boundary, using official `@convex-dev/*`
40
+ // libraries only -- no canary/alpha dependency for a guardrail:
41
+ // `rate-limiter` for the fails-closed spend gate itself, `sharded-counter`
42
+ // for the usage rollup. See component/engine/mandates.ts.
43
+ // Habits (a dynamic, per-agent/org cron schedule editable at runtime) are
44
+ // also hosted under this component boundary, ported byte-identical from the
45
+ // repo-root prototype (convex/habits.ts). `crons` is a sub-component of
47
46
  // THIS component -- create/updateSchedule/enable/disable register or tear
48
47
  // down a runtime cron job via `@convex-dev/crons` inside the SAME Convex
49
48
  // mutation transaction that writes the `habits` row, so no habit schedule
@@ -4,15 +4,14 @@ import { internalMutation, mutation } from "../_generated/server.js";
4
4
  import { assertSameOrg, requireOrgId } from "../lib/auth.js";
5
5
  // engine/awaitEventTimeout — self-built timeout for step.awaitEvent
6
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
7
+ // awaitEvent"). We schedule a mutation that
9
8
  // fires a "blank" `sandbox.timeout` sessionEvent at the deadline; the
10
9
  // workflow's `awaitEvent` call is written to also accept this event name so
11
10
  // it wakes up even if the awaited event never arrives. Pattern:
12
11
  // maintainer's posted code in workflow#177, adapted to our sessionEvents
13
12
  // table.
14
13
  //
15
- // C2 MIGRATION NOTE ("notre ligne"): orgId is an EXPLICIT ARGUMENT on
14
+ // NOTE ("intentional divergence from Eve"): orgId is an EXPLICIT ARGUMENT on
16
15
  // every public function, never derived from `ctx.auth` -- auth does NOT
17
16
  // propagate across a component boundary (component/lib/auth.ts). Also:
18
17
  // `sessionEvents.name`'s union in component/schema.ts did not previously
@@ -2,25 +2,23 @@ import { v } from "convex/values";
2
2
  import { api, internal } from "../_generated/api.js";
3
3
  import { action, internalMutation, internalQuery, mutation, query, } from "../_generated/server.js";
4
4
  import { assertSameOrg, requireOrgId } from "../lib/auth.js";
5
- // engine/delegation — C6 (SYNTHESE.md §4.d): "un agent qui délègue à un
6
- // autre agent = LE MÊME système pause/réveil (awaitEvent/sendEvent) que le
7
- // pont sandbox -- un seul système à écrire, pas deux". Ported from
8
- // convex/engine/delegation.ts (repo-root prototype, I6) into the component
9
- // boundary (C6). Every delegation path below (declared subagent AND the
10
- // built-in `agent` clone tool) terminates in exactly ONE call to
11
- // `engine.wakeup.enqueue` -- the SAME public action C2/C3 already ships,
12
- // imported here and never reimplemented.
5
+ // engine/delegation — an agent delegating to another agent uses THE SAME
6
+ // pause/wake system (awaitEvent/sendEvent) as the sandbox bridge: one
7
+ // system to maintain, not two. Every delegation path below (declared
8
+ // subagent AND the built-in `agent` clone tool) terminates in exactly ONE
9
+ // call to `engine.wakeup.enqueue` -- the same public action this component
10
+ // already ships, imported here and never reimplemented.
13
11
  // grep proof: this file makes zero calls to `wakeupPool.*` / `workflow.*`
14
12
  // directly; the only wake-capable call in this module is
15
13
  // `api.engine.wakeup.enqueue` at the bottom of `delegateToSubagent` and
16
14
  // `invokeAgentClone`.
17
15
  //
18
- // C6 orgId discipline (component/lib/auth.ts): every PUBLIC function takes
16
+ // orgId discipline (component/lib/auth.ts): every PUBLIC function takes
19
17
  // `orgId` as an explicit ARGUMENT (auth does not propagate across a
20
- // component boundary), same as engine/mandates.ts (C3) / engine/wakeup.ts
21
- // (C2). `delegateToSubagent`/`invokeAgentClone` are `action`s because they
22
- // each call `api.engine.wakeup.enqueue` (itself an action, C3's two-
23
- // transaction funding protocol) -- `orgId` is threaded explicitly through
18
+ // component boundary), same as engine/mandates.ts / engine/wakeup.ts.
19
+ // `delegateToSubagent`/`invokeAgentClone` are `action`s because they each
20
+ // call `api.engine.wakeup.enqueue` (itself an action: the two-transaction
21
+ // funding protocol) -- `orgId` is threaded explicitly through
24
22
  // every hop, never relying on any identity propagation across the boundary.
25
23
  // Reserved tool name for the built-in, root-only, non-recursive clone tool
26
24
  // (eve.dev/docs/subagents). A declared subagent may never claim this name --
@@ -125,10 +123,10 @@ export const listSubagents = query({
125
123
  // (a.2) DELEGATION -- reuses `engine.wakeup.enqueue` end to end
126
124
  // ---------------------------------------------------------------------
127
125
  // delegateToSubagent — A delegates to a declared subagent B by the SAME
128
- // pause/réveil mechanism the sandbox bridge (C5) uses: it enqueues the
126
+ // pause/wake mechanism the sandbox bridge uses: it enqueues the
129
127
  // caller-supplied `workFunctionHandle` (an action that performs B's turn)
130
128
  // through `api.engine.wakeup.enqueue`. That enqueue funds through
131
- // `mandates.spendInternal` (C3's own choke point, untouched), puts the work
129
+ // `mandates.spendInternal` (the funding choke point, untouched), puts the work
132
130
  // into `wakeupPool`, and when it resolves, `engine.wakeup.onWorkComplete`
133
131
  // calls `workflow.sendEvent` (workflowId, awaitedEventName, ...) -- waking
134
132
  // whatever workflow step A's own session parked on `step.awaitEvent`. There
@@ -167,7 +165,7 @@ export const delegateToSubagent = action({
167
165
  awaitedEventName: args.awaitedEventName,
168
166
  });
169
167
  // THE reuse point: no bespoke pause/wake code below this line -- this
170
- // is a direct call into C2/C3's own PUBLIC `engine.wakeup.enqueue`
168
+ // is a direct call into this component's own PUBLIC `engine.wakeup.enqueue`
171
169
  // action. `orgId` is threaded explicitly (no identity propagation
172
170
  // across the component boundary).
173
171
  await ctx.runAction(api.engine.wakeup.enqueue, {
@@ -2,7 +2,7 @@ import { v } from "convex/values";
2
2
  import { query } from "../_generated/server.js";
3
3
  import { requireOrgId } from "../lib/auth.js";
4
4
  // engine/directory — component-boundary port of the app-level
5
- // `convex/directory.ts:listByOrg` (M-COMPLETION C1, VP k1717xyrn25n99h6j10m48f1jx8akg6v).
5
+ // `convex/directory.ts:listByOrg`.
6
6
  //
7
7
  // Trust-boundary divergence from the app-level prototype (see
8
8
  // component/lib/auth.ts): auth does NOT propagate across a component
@@ -3,9 +3,9 @@ import { WorkflowManager } from "@convex-dev/workflow";
3
3
  import { components, internal } from "../_generated/api.js";
4
4
  import { internalMutation, internalQuery, mutation, query, } from "../_generated/server.js";
5
5
  import { assertSameOrg, requireOrgId } from "../lib/auth.js";
6
- // durableJobs — THE SURVIVAL CONTRACT (I1, SYNTHESE.md §5/§7): "mise en
7
- // pause à la frontière d'étape, rejeu déterministe, reprise, abandon après
8
- // N échecs." This ENVELOPS `@convex-dev/workflow` -- it does not reimplement
6
+ // durableJobs — THE SURVIVAL CONTRACT: pause at the step boundary,
7
+ // deterministic replay, resume, and abandon after N failures. This ENVELOPS
8
+ // `@convex-dev/workflow` -- it does not reimplement
9
9
  // durable execution. Every real unit of work (the caller-supplied
10
10
  // `stepFunctionHandle`) runs inside its own bounded mutation call; the
11
11
  // workflow persists `cursor` (steps [0, cursor) done) between calls, so a
@@ -13,8 +13,8 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
13
13
  // still completes -- no single call has to survive past the ceiling, only
14
14
  // the aggregate progress does.
15
15
  //
16
- // Contract surface (this is what a consumer -- VantagePeers/Sigma first --
17
- // calls; see examples/vantage-peers-long-task for a worked integration):
16
+ // Contract surface (this is what a consumer calls; see
17
+ // examples/vantage-peers-long-task for a worked integration):
18
18
  // 1. `start` -- enqueue a job of N steps, driven by a step function
19
19
  // the CALLER owns (created via `createFunctionHandle`
20
20
  // in the caller's own app). We never read the
@@ -40,7 +40,7 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
40
40
  // which the workflow handler catches and turns into
41
41
  // `status: "abandoned"` with `abandonedAtStep` + `lastError`.
42
42
  //
43
- // Versioned workflow discipline (workflow#35, I0 §7.1) -- same as
43
+ // Versioned workflow discipline (workflow#35) -- same as
44
44
  // `engine/workflows.ts:sessionWorkflowV1`: never edit `durableJobWorkflowV1`
45
45
  // in place once jobs reference it; ship `...V2` and drain v1 first.
46
46
  const CURRENT_WORKFLOW_VERSION = "v1";
@@ -3,17 +3,16 @@ import { Crons } from "@convex-dev/crons";
3
3
  import { internal, components } from "../_generated/api.js";
4
4
  import { internalMutation, mutation, query } from "../_generated/server.js";
5
5
  import { assertSameOrg, requireOrgId } from "../lib/auth.js";
6
- // engine/habits — NOTRE LIGNE (SYNTHESE §2/§4.e-ter: "ce qui transforme un
7
- // chat en employé"). Une habitude = un cron DYNAMIQUE par agent/org,
8
- // enregistré à l'exécution via @convex-dev/crons — jamais un
9
- // `convex/crons.ts` statique. Créer / exécuter / modifier / désactiver ne
10
- // redéploient jamais rien : le `cronExpression` est une DONNÉE portée par
11
- // la ligne `habits`, le cron runtime en est un simple reflet. Ported from
12
- // convex/habits.ts (repo-root prototype) into the component boundary (C4).
6
+ // engine/habits — "intentional divergence from Eve": a habit is what turns
7
+ // a chat into an employee. A habit is a DYNAMIC cron per agent/org,
8
+ // registered at runtime via @convex-dev/crons — never a static
9
+ // `convex/crons.ts`. Creating, running, editing or disabling one deploys
10
+ // nothing: the `cronExpression` is DATA carried by the `habits` row, and
11
+ // the runtime cron is merely a reflection of it.
13
12
  //
14
- // C4 orgId discipline (component/lib/auth.ts): every PUBLIC function takes
13
+ // orgId discipline (component/lib/auth.ts): every PUBLIC function takes
15
14
  // `orgId` as an explicit ARGUMENT (auth does not propagate across a
16
- // component boundary), same as engine/mandates.ts (C3). The cron runtime
15
+ // component boundary), same as engine/mandates.ts. The cron runtime
17
16
  // target is `internal.engine.habits.run` -- the component-boundary path
18
17
  // for this module, mirroring `internal.habits.run` at the app level.
19
18
  const crons = new Crons(components.crons);
@@ -4,9 +4,8 @@ import { ShardedCounter } from "@convex-dev/sharded-counter";
4
4
  import { internalMutation, mutation, query } from "../_generated/server.js";
5
5
  import { components } from "../_generated/api.js";
6
6
  import { assertSameOrg, requireOrgId } from "../lib/auth.js";
7
- // engine/mandates — NOTRE LIGNE (SYNTHESE §2 / §4.e-ter) : « autorité
8
- // bornée ». Ported from convex/mandates.ts (repo-root prototype) into the
9
- // component boundary (C3). A mandate is a LINE OF DATA scoped
7
+ // engine/mandates — "intentional divergence from Eve": BOUNDED AUTHORITY.
8
+ // A mandate is a LINE OF DATA scoped
10
9
  // orgId+agentId+scope, never a constant read from code (litmus test: a
11
10
  // client changes their mind => zero deployment). The rate-limiter has NO
12
11
  // static named config in this module -- every call to `spend` builds its
@@ -15,7 +14,7 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
15
14
  // dynamically"). Fails-closed: no mandate row => refusal, never a silent
16
15
  // bypass.
17
16
  //
18
- // C3 orgId discipline (component/lib/auth.ts): every PUBLIC function takes
17
+ // orgId discipline (component/lib/auth.ts): every PUBLIC function takes
19
18
  // `orgId` as an explicit ARGUMENT (auth does not propagate across a
20
19
  // component boundary), same as the rest of this component (agents,
21
20
  // wakeup, sessions). `spendInternal` also takes `orgId` as an argument, but
@@ -24,7 +23,7 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
24
23
  // caller-supplied `orgId` argument through after validating it.
25
24
  const rateLimiter = new RateLimiter(components.rateLimiter);
26
25
  // Usage rollup, keyed identically to the rate-limiter key (org+agent+scope).
27
- // I0 §7.4: counters via sharded-counter, never a canary/alpha dependency.
26
+ // internal research notes: counters via sharded-counter, never a canary/alpha dependency.
28
27
  const usageCounter = new ShardedCounter(components.shardedCounter);
29
28
  const mandateDoc = v.object({
30
29
  _id: v.id("mandates"),
@@ -143,7 +142,7 @@ export const spend = mutation({
143
142
  // spendInternal — SAME choke point as `spend`, INTERNAL ONLY (unreachable
144
143
  // from any client). This is the ONE function `engine/wakeup.enqueue` (an
145
144
  // `action`) calls, in its OWN transaction, before it may ever call
146
- // `enqueueInternal` to put work in the pool -- see the C3 wiring note in
145
+ // `enqueueInternal` to put work in the pool -- see the wiring note in
147
146
  // component/engine/wakeup.ts. Trusting an `orgId` argument here is exactly
148
147
  // as safe as `engine/wakeup.enqueueInternal` trusting one: the only code
149
148
  // that can reach an `internal.*` function is other server code, never a
@@ -205,7 +204,7 @@ async function spendCore(ctx, orgId, args) {
205
204
  });
206
205
  return { ok: false, approvalId };
207
206
  }
208
- // Rollup via sharded-counter (I0 §7.4: no canary dependency for a
207
+ // Rollup via sharded-counter (internal research notes: no canary dependency for a
209
208
  // guardrail). One shard bucket per org+agent+scope key.
210
209
  await usageCounter.add(ctx, key, args.cost);
211
210
  return { ok: true };
@@ -3,12 +3,10 @@ import { v } from "convex/values";
3
3
  import { components, internal } from "../_generated/api.js";
4
4
  import { internalMutation, mutation, query } from "../_generated/server.js";
5
5
  import { assertSameOrg, requireOrgId } from "../lib/auth.js";
6
- // engine/sandboxCallback — C5: THE SIGNED CALLBACK GATE'S DB-SIDE LOGIC,
7
- // PORTED from convex/engine/sandboxCallback.ts (repo-root prototype, I5,
8
- // SYNTHESE.md §4.c-d, i0-research §8/§5) into the component boundary.
6
+ // engine/sandboxCallback — THE SIGNED CALLBACK GATE'S DB-SIDE LOGIC.
9
7
  //
10
- // NOTRE LIGNE (C5 recherche-d'abord, see component/schema.ts's C5 header
11
- // comment for the measured verdict + citations):
8
+ // BOUNDARY (see the sandbox-bridge header in component/schema.ts for the
9
+ // measured verdict behind each of these):
12
10
  // - The public HTTP route (`/sandbox/callback`) that verifies the
13
11
  // `SANDBOX_CALLBACK_SECRET` HMAC signature over the raw body CANNOT
14
12
  // live in this component (no official `@convex-dev/*` component ships
@@ -20,12 +18,11 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
20
18
  // (`Sandbox.create()` / `sandbox.runCommand()`) CANNOT live in this
21
19
  // component either (Convex's own bundler hard-crashes on any "use
22
20
  // node" file inside a child component). It stays app-level
23
- // (convex/engine/sandboxBridgeActions.ts) and calls INTO `startRun` /
24
- // `attachSandboxId` below (both PUBLIC `mutation`s, not
25
- // `internalMutation`s, precisely so a cross-component caller can reach
26
- // them — a component's `internal*` functions are unreachable from
27
- // outside the component, see component/engine/mandates.ts's
28
- // `spendInternal` for the same convention already established in C3).
21
+ // and calls INTO `startRun` / `attachSandboxId` below (both PUBLIC
22
+ // `mutation`s, not `internalMutation`s, precisely so a cross-component
23
+ // caller can reach them — a component's `internal*` functions are
24
+ // unreachable from outside the component; engine/mandates.ts's
25
+ // `spendInternal` follows the same convention).
29
26
  //
30
27
  // Everything below assumes the signature already checked out (verified by
31
28
  // the caller, upstream of this module) — this module's job is dedup-by-
@@ -29,12 +29,11 @@ const CURRENT_SESSION_WORKFLOW_VERSION = "v1";
29
29
  // manifest immediately so a caller can act on it before the first turn,
30
30
  // then STARTS the durable, versioned session workflow
31
31
  // (engine/workflows.ts:sessionWorkflowV1) that pilots this session from
32
- // here on (C1.5 -- retires the T2-QUINQUIES "sessions are just an event
33
- // table" divergence).
32
+ // here on.
34
33
  //
35
- // RETURN CONTRACT ("notre ligne", C1.5): `start` now returns
34
+ // RETURN CONTRACT ("intentional divergence from Eve"): `start` returns
36
35
  // `{ sessionId, workflowId }` instead of a bare `sessionId`. A bare ID
37
- // return was the pre-C1.5 shape when no workflow existed to reference;
36
+ // would be the shape for a session with no workflow to reference;
38
37
  // once a session IS piloted by a real, durable workflow run, silently
39
38
  // dropping that run's id would make it unobservable/uncancellable to
40
39
  // every caller except one that re-reads the session row. Returning both
@@ -45,7 +44,7 @@ const CURRENT_SESSION_WORKFLOW_VERSION = "v1";
45
44
  export const start = mutation({
46
45
  args: { orgId: v.string(), agentId: v.id("agents"), createdBy: v.string() },
47
46
  returns: v.object({ sessionId: v.id("sessions"), workflowId: v.string() }),
48
- // EXPLICIT return-type annotation ("notre ligne" -- Convex pattern for
47
+ // EXPLICIT return-type annotation ("intentional divergence from Eve" -- Convex pattern for
49
48
  // any handler that references `components`/a WorkflowManager built on
50
49
  // `components.workflow`): `workflow.start` closes over `components`,
51
50
  // which closes back over this component's own generated `api` --
@@ -55,7 +54,7 @@ export const start = mutation({
55
54
  // `.d.ts` EMISSION (declaration:true, tsconfig.build.json) fails --
56
55
  // TS2502/TS2615/TS7022 -- even though `tsc --noEmit` at the repo root
57
56
  // stays green (noEmit skips the exact codepath that breaks). Measured
58
- // on PR #13 (Eta gate): `npm run build` is the build that SHIPS; a
57
+ // on PR #13 (build gate review): `npm run build` is the build that SHIPS; a
59
58
  // green `tsc --noEmit` is not sufficient proof by itself.
60
59
  handler: async (ctx, args) => {
61
60
  const orgId = requireOrgId(args.orgId);
@@ -188,8 +187,8 @@ export const requestToolCall = mutation({
188
187
  // approval === "once": gate unless this tool's approval was already
189
188
  // resolved with `decision: "approved"` in this session. A prior
190
189
  // `decision: "denied"` resolution must NOT be treated as
191
- // authorization (that was the pre-alpha.5 bug -- "outil sauté, tour
192
- // complété quand même") -- it is reported back as a terminal refusal
190
+ // authorization (the tool would be skipped while the turn still
191
+ // completed) -- it is reported back as a terminal refusal
193
192
  // instead, and the caller re-requests (a fresh human decision) rather
194
193
  // than silently proceeding.
195
194
  const events = await ctx.db
@@ -272,7 +271,7 @@ export const listEvents = query({
272
271
  _id: v.id("sessionEvents"),
273
272
  _creationTime: v.number(),
274
273
  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"),
275
- // C2 — blank event auto-inserted by
274
+ // Blank event auto-inserted by
276
275
  // `engine/awaitEventTimeout.fire` (workflow#177).
277
276
  v.literal("sandbox.timeout")),
278
277
  payload: v.optional(v.string()),
@@ -10,7 +10,7 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
10
10
  // 1. `decision` -- the RESPONSE to THIS ONE pending approval request,
11
11
  // for THIS turn only. Vocabulary aligned with Eve's `ApprovalStatus`
12
12
  // (packages/eve/src/public/definitions/approval.ts: "approved" |
13
- // "denied" | ...) -- eve parity, cited verbatim, not "notre ligne".
13
+ // "denied" | ...) -- eve parity, cited verbatim, not "intentional divergence from Eve".
14
14
  // `"denied"` means: this turn's tool call is refused, full stop. It
15
15
  // does NOT change the agent's standing policy for the tool, and it
16
16
  // must NOT be interpreted as "tool skipped, turn completed anyway" --
@@ -2,22 +2,19 @@ import { v } from "convex/values";
2
2
  import { action, internalMutation, internalQuery, mutation, query, } from "../_generated/server.js";
3
3
  import { assertSameOrg, requireOrgId } from "../lib/auth.js";
4
4
  import { internal } from "../_generated/api.js";
5
- // engine/vpConnection — C6 (I6.b), mvp-evevantage.md §2.2 "Travail
6
- // d'équipe". Ported from convex/engine/vpConnection.ts (repo-root
7
- // prototype) into the component boundary (C6). The four VantagePeers tools
5
+ // engine/vpConnection — teamwork. The four VantagePeers tools
8
6
  // (memory, tasks, messages, notes) are wired as a CONNECTION of the agent
9
- // aggregate -- notre ligne, same slot family as `connections` (MCP/OpenAPI).
7
+ // aggregate -- intentional divergence from Eve, same slot family as `connections` (MCP/OpenAPI).
10
8
  // Four toggles, ON by default.
11
9
  //
12
10
  // DIRECT ACCESS, NO NETWORK IN THE HOT PATH: `invokeVpTool` dispatches via a
13
11
  // caller-supplied Convex function handle (`createFunctionHandle`), the same
14
12
  // discipline `engine/wakeup.ts` and `engine/durableJob.ts` already use for
15
13
  // `workFunctionHandle` / `stepFunctionHandle` -- an in-process function
16
- // reference resolved by `ctx.runMutation`, never an HTTP request. grep proof
17
- // (cited in the PR/README): this file contains zero occurrences of the
18
- // literal fetch call.
14
+ // reference resolved by `ctx.runMutation`, never an HTTP request: this file
15
+ // contains zero occurrences of the literal fetch call.
19
16
  //
20
- // C6 orgId discipline (component/lib/auth.ts): every PUBLIC function takes
17
+ // orgId discipline (component/lib/auth.ts): every PUBLIC function takes
21
18
  // `orgId` as an explicit ARGUMENT (auth does not propagate across a
22
19
  // component boundary). `orgId` is passed EXPLICITLY to the target function
23
20
  // handle (never trusting the target's own `ctx.auth`) -- this is the
@@ -25,7 +22,7 @@ import { internal } from "../_generated/api.js";
25
22
  // is expected to write scoped to the `orgId` it was HANDED, not to derive
26
23
  // one itself.
27
24
  const vpTool = v.union(v.literal("memory"), v.literal("tasks"), v.literal("messages"), v.literal("notes"));
28
- // defaultToggles — mvp §2.2: "quatre interrupteurs cochés par défaut". A
25
+ // defaultToggles — four switches, all ticked by default. A
29
26
  // missing `vpConnections` row means "use these defaults", so every agent
30
27
  // starts with all four VP tools available with zero extra setup.
31
28
  export const defaultToggles = {
@@ -4,17 +4,16 @@ import { WorkflowManager } from "@convex-dev/workflow";
4
4
  import { components, internal } from "../_generated/api.js";
5
5
  import { action, internalMutation, mutation, query } from "../_generated/server.js";
6
6
  import { assertSameOrg, requireOrgId } from "../lib/auth.js";
7
- // engine/wakeup — THE GENERIC WAKE-UP PRIMITIVE (I2, SYNTHESE.md §5: "Adam
8
- // ne demande pas toutes les minutes s'il y a du travail -- il est réveillé
9
- // quand du travail arrive"). PORTED from convex/engine/wakeup.ts (repo-root
10
- // prototype) into the component boundary (C2). Mechanism: `enqueue` puts
11
- // caller-supplied work (an action, referenced by an opaque handle string
7
+ // engine/wakeup — THE GENERIC WAKE-UP PRIMITIVE. An agent does not ask every
8
+ // minute whether work has arrived: it is woken the instant the work resolves.
9
+ // Mechanism: `enqueue` puts caller-supplied work (an action, referenced by
10
+ // an opaque handle string
12
11
  // from `createFunctionHandle` in the CALLER's own app, same
13
12
  // component-isolation discipline as `durableJob.stepFunctionHandle`) into a
14
13
  // dedicated `@convex-dev/workpool` (`components.wakeupPool`, declared in
15
14
  // component/convex.config.ts). That pool's `onComplete` callback -- which
16
- // fires in its OWN transaction once the work resolves (I0 §2: "onComplete
17
- // en transaction séparée, pas de pause native", workpool issue #133) --
15
+ // fires in its OWN transaction once the work resolves (workpool issue #133:
16
+ // onComplete runs in a separate transaction; there is no native pause) --
18
17
  // calls `workflow.sendEvent(...)` against the CALLER-supplied
19
18
  // `workflowId`. Any workflow step parked on
20
19
  // `step.awaitEvent({ name: awaitedEventName })` resumes the INSTANT that
@@ -28,7 +27,7 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
28
27
  // of those tables.
29
28
  //
30
29
  // ---------------------------------------------------------------------
31
- // C2 MIGRATION NOTES ("notre ligne")
30
+ // "intentional divergence from Eve"
32
31
  // ---------------------------------------------------------------------
33
32
  //
34
33
  // (A) orgId is an EXPLICIT ARGUMENT on every public function, never derived
@@ -36,7 +35,7 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
36
35
  // (see component/lib/auth.ts). The consumer app has already authenticated
37
36
  // its caller and resolved orgId on its OWN side before calling in.
38
37
  //
39
- // (B) C3: MANDATE FUNDING CHOKE-POINT IS NOW WIRED. `enqueue` is an
38
+ // (B) MANDATE FUNDING CHOKE-POINT. `enqueue` is an
40
39
  // `action` because funding-then-starting is a TWO-TRANSACTION protocol a
41
40
  // single mutation cannot express: `mandates.spendInternal` must be able to
42
41
  // COMMIT an `approvalRequests` row on an overrun WITHOUT that commit being
@@ -54,13 +53,12 @@ import { assertSameOrg, requireOrgId } from "../lib/auth.js";
54
53
  // 4. only on `result.ok === true` does it call `enqueueInternal` in a
55
54
  // SECOND transaction to actually put the work in the pool.
56
55
  // There is no code path from "client wants work started" to "work enters
57
- // the pool" that does not pass through step 2 -- this is the "argument you
58
- // cannot fabricate" form (Pi/Sigma, T4 lesson): the only way to make
56
+ // the pool" that does not pass through step 2 -- this is an "argument you
57
+ // cannot fabricate" pattern: the only way to make
59
58
  // `enqueueInternal` run at all is to be `enqueue` itself, and `enqueue`
60
- // always calls `mandates.spendInternal` first. Mirrors the app-level
61
- // pre-C2 prototype (`convex/engine/wakeup.ts`) exactly, adapted to the
62
- // orgId-argument discipline of this component boundary (`spendInternal`
63
- // takes `orgId` as an argument rather than deriving it from `ctx.auth`).
59
+ // always calls `mandates.spendInternal` first. `spendInternal` takes
60
+ // `orgId` as an argument rather than deriving it from `ctx.auth`, per the
61
+ // boundary discipline in note A.
64
62
  export const wakeupPool = new Workpool(components.wakeupPool, {
65
63
  maxParallelism: 10,
66
64
  });
@@ -72,8 +70,8 @@ const workflow = new WorkflowManager(components.workflow);
72
70
  // ---------------------------------------------------------------------
73
71
  // PUBLIC CONTRACT
74
72
  // ---------------------------------------------------------------------
75
- // enqueue — the ONLY client-facing entry point (C3: now an `action`, see
76
- // note B above). Funds the work through `mandates.spendInternal` in its
73
+ // enqueue — the ONLY client-facing entry point (an `action`, see note B
74
+ // above). Funds the work through `mandates.spendInternal` in its
77
75
  // own transaction FIRST; only calls `enqueueInternal` (a second,
78
76
  // independent transaction) once that funding succeeded.
79
77
  export const enqueue = action({
@@ -119,9 +117,9 @@ export const enqueue = action({
119
117
  });
120
118
  },
121
119
  });
122
- // enqueueInternal -- INTERNAL ONLY variant, kept for the C3 two-transaction
123
- // protocol (a future funding `action` calls this in its SECOND transaction
124
- // once `mandates.spend` returned `{ ok: true }`, same split as the
120
+ // enqueueInternal -- INTERNAL ONLY variant, kept for the two-transaction
121
+ // funding protocol (`enqueue` calls this in its SECOND transaction
122
+ // once `mandates.spendInternal` returned `{ ok: true }`, same split as the
125
123
  // app-level prototype). Unreachable from any client: Convex excludes
126
124
  // `internal.*` functions from the API surface shipped to clients.
127
125
  export const enqueueInternal = internalMutation({
@@ -2,12 +2,9 @@ import { WorkflowManager } from "@convex-dev/workflow";
2
2
  import { v } from "convex/values";
3
3
  import { components, internal } from "../_generated/api.js";
4
4
  import { internalMutation, internalQuery } from "../_generated/server.js";
5
- // C1.5 — porting the durable, VERSIONED session workflow into the
6
- // component boundary (ported from the repo-root prototype,
7
- // convex/engine/workflows.ts). This is what makes `sessions.start` open a
8
- // session PILOTED by `@convex-dev/workflow` instead of the T2-QUINQUIES
9
- // "sessions are just an event table" divergence (component/schema.ts,
10
- // sessions table comment retired alongside this file).
5
+ // The durable, VERSIONED session workflow. This is what makes
6
+ // `sessions.start` open a session PILOTED by `@convex-dev/workflow` rather
7
+ // than a bare event table.
11
8
  //
12
9
  // Trust model at this boundary: the workflow engine runs with NO end-user
13
10
  // identity and NO client-supplied orgId (component isolation, same
@@ -53,7 +50,7 @@ export const recordTurnStartedInternal = internalMutation({
53
50
  return null;
54
51
  },
55
52
  });
56
- // Versioned workflow discipline (workflow#35, I0 §7.1): "if you change much
53
+ // Versioned workflow discipline (workflow#35): "if you change much
57
54
  // of anything in a workflow while there are ongoing workflows, they'll
58
55
  // fail." We never edit a workflow function in place once sessions
59
56
  // reference it -- a breaking change ships as `sessionWorkflowV2`, and the