@opengeni/core 1.2.1-canary.37222965366001 → 1.4.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.
Files changed (35) hide show
  1. package/dist/canonical-human-identities.js +1 -1
  2. package/dist/{chunk-MM6N7CTO.js → chunk-672TAJCH.js} +45 -5
  3. package/dist/chunk-672TAJCH.js.map +1 -0
  4. package/dist/domain/connector-tool-permissions.d.ts +3 -1
  5. package/dist/domain/knowledge-messages.d.ts +4 -4
  6. package/dist/domain/realtime-voice-billing.d.ts +81 -0
  7. package/dist/domain/scheduled-task-access.d.ts +2 -2
  8. package/dist/domain/scheduled-tasks.d.ts +2 -2
  9. package/dist/domain/session-connection-accounts.d.ts +1 -1
  10. package/dist/domain/session-tool-policy.d.ts +4 -4
  11. package/dist/domain/voice-input-billing.d.ts +76 -0
  12. package/dist/domain/web-search-billing.d.ts +45 -0
  13. package/dist/goal-admission.d.ts +24 -0
  14. package/dist/index.d.ts +4 -1
  15. package/dist/index.js +963 -211
  16. package/dist/index.js.map +1 -1
  17. package/dist/managed-session.d.ts +4 -1
  18. package/dist/transcription.d.ts +119 -2
  19. package/package.json +12 -12
  20. package/src/application/api-integration-servers.ts +9 -0
  21. package/src/domain/connector-tool-permissions.ts +199 -73
  22. package/src/domain/realtime-voice-billing.ts +330 -0
  23. package/src/domain/scheduled-task-access.ts +2 -1
  24. package/src/domain/scheduled-tasks.ts +3 -2
  25. package/src/domain/session-connection-accounts.ts +7 -3
  26. package/src/domain/session-tool-policy.ts +14 -2
  27. package/src/domain/sessions.ts +17 -4
  28. package/src/domain/slack-bot.ts +15 -3
  29. package/src/domain/voice-input-billing.ts +310 -0
  30. package/src/domain/web-search-billing.ts +154 -0
  31. package/src/index.ts +5 -0
  32. package/src/managed-session.ts +59 -5
  33. package/src/sandbox/routing.ts +59 -25
  34. package/src/transcription.ts +122 -3
  35. package/dist/chunk-MM6N7CTO.js.map +0 -1
@@ -3,7 +3,7 @@ import {
3
3
  getManagedAuthRequestActorLeaseStamp,
4
4
  getManagedSession,
5
5
  markManagedAuthRequestActorTransitionApplied
6
- } from "./chunk-MM6N7CTO.js";
6
+ } from "./chunk-672TAJCH.js";
7
7
  import "./chunk-QO5GVFFO.js";
8
8
 
9
9
  // src/canonical-human-identities.ts
@@ -7,7 +7,13 @@ import {
7
7
  } from "./chunk-QO5GVFFO.js";
8
8
 
9
9
  // src/managed-session.ts
10
+ import { AsyncLocalStorage } from "async_hooks";
10
11
  import { managedUserEmailAllowed } from "@opengeni/config";
12
+ import {
13
+ DatabaseUnavailableError,
14
+ isDatabaseConnectionLoss,
15
+ isRetryableDatabaseTransportFailure
16
+ } from "@opengeni/db";
11
17
  import {
12
18
  acquireManagedAuthActorMutationLease,
13
19
  getManagedAuthAdoptedSessionSnapshot,
@@ -19,6 +25,36 @@ import {
19
25
  } from "@opengeni/db/managed-auth-session-sets";
20
26
  import { validateCanonicalHumanSession } from "@opengeni/db/canonical-human-identities";
21
27
  import { HTTPException } from "hono/http-exception";
28
+ var managedAuthLookupFailures = new AsyncLocalStorage();
29
+ var MANAGED_AUTH_LOOKUP_FAILURE_LIMIT = 8;
30
+ function recordManagedAuthLoggedFailure(args) {
31
+ const store = managedAuthLookupFailures.getStore();
32
+ if (!store) return;
33
+ for (const value of args) {
34
+ if (store.errors.length >= MANAGED_AUTH_LOOKUP_FAILURE_LIMIT) return;
35
+ if (value && typeof value === "object") store.errors.push(value);
36
+ }
37
+ }
38
+ function isBetterAuthInternalServerError(error) {
39
+ if (!error || typeof error !== "object") return false;
40
+ const candidate = error;
41
+ return candidate.status === "INTERNAL_SERVER_ERROR" || candidate.statusCode === 500;
42
+ }
43
+ async function withManagedAuthSessionLookup(lookup) {
44
+ const store = { errors: [] };
45
+ try {
46
+ return await managedAuthLookupFailures.run(store, lookup);
47
+ } catch (error) {
48
+ if (isBetterAuthInternalServerError(error) && store.errors.some(
49
+ (logged) => isDatabaseConnectionLoss(logged) || isRetryableDatabaseTransportFailure(logged)
50
+ )) {
51
+ throw new DatabaseUnavailableError("managed auth session store unavailable", {
52
+ cause: error
53
+ });
54
+ }
55
+ throw error;
56
+ }
57
+ }
22
58
  var ACTOR_MUTATION_LEASE_SECONDS = 15 * 60;
23
59
  var ACTOR_MUTATION_LEASE_REFRESH_MS = 5 * 60 * 1e3;
24
60
  var ACTOR_MUTATION_HANDLER_DEADLINE_MS = 10 * 60 * 1e3;
@@ -165,10 +201,12 @@ async function resolveManagedSession(c, auth, options) {
165
201
  throw error;
166
202
  }
167
203
  }
168
- const result = await auth.api.getSession({
169
- headers: c.req.raw.headers,
170
- returnHeaders: true
171
- });
204
+ const result = await withManagedAuthSessionLookup(
205
+ () => auth.api.getSession({
206
+ headers: c.req.raw.headers,
207
+ returnHeaders: true
208
+ })
209
+ );
172
210
  for (const cookie of setCookieHeaders(result.headers)) {
173
211
  c.header("set-cookie", cookie, { append: true });
174
212
  }
@@ -372,6 +410,8 @@ function setCookieHeaders(headers) {
372
410
  }
373
411
 
374
412
  export {
413
+ recordManagedAuthLoggedFailure,
414
+ withManagedAuthSessionLookup,
375
415
  configureManagedUserAdmission,
376
416
  getManagedSession,
377
417
  assertManagedUserAdmission,
@@ -384,4 +424,4 @@ export {
384
424
  getManagedAuthRequestActorAdmissionStamp,
385
425
  getManagedAuthRequestActorLeaseStamp
386
426
  };
387
- //# sourceMappingURL=chunk-MM6N7CTO.js.map
427
+ //# sourceMappingURL=chunk-672TAJCH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/managed-session.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { managedUserEmailAllowed } from \"@opengeni/config\";\nimport type { Context } from \"hono\";\nimport type { ManagedAuth } from \"./managed-auth-type\";\nimport {\n DatabaseUnavailableError,\n isDatabaseConnectionLoss,\n isRetryableDatabaseTransportFailure,\n type Database,\n} from \"@opengeni/db\";\nimport {\n acquireManagedAuthActorMutationLease,\n getManagedAuthAdoptedSessionSnapshot,\n getManagedAuthSessionSetSnapshot,\n ManagedAuthSessionSetAuthorityError,\n ManagedAuthSessionSetGenerationConflictError,\n releaseManagedAuthActorMutationLease,\n validateManagedAuthActorMutationLease,\n} from \"@opengeni/db/managed-auth-session-sets\";\nimport { validateCanonicalHumanSession } from \"@opengeni/db/canonical-human-identities\";\nimport type { ManagedAuthSessionSetMode } from \"@opengeni/contracts/managed-auth-session-sets\";\nimport { HTTPException } from \"hono/http-exception\";\nimport {\n MANAGED_AUTH_ACTOR_EPOCH_HEADER,\n MANAGED_AUTH_SESSION_SET_COOKIE,\n ManagedAuthActorChangeError,\n managedAuthSha256,\n resolveManagedAuthSelectedSession,\n type ManagedAuthSessionAdapter,\n} from \"./managed-auth-session-sets\";\n\n/**\n * Better Auth's session endpoint replaces every non-API failure with a generic\n * INTERNAL_SERVER_ERROR and passes the original only to its logger. A lookup run\n * through `withManagedAuthSessionLookup` collects what the logger saw, so a lost\n * database connection is reported as a retryable outage instead of an opaque 500.\n */\nconst managedAuthLookupFailures = new AsyncLocalStorage<{ errors: unknown[] }>();\nconst MANAGED_AUTH_LOOKUP_FAILURE_LIMIT = 8;\n\n/** Better Auth `logger.log` sink; a no-op outside a managed-auth session lookup. */\nexport function recordManagedAuthLoggedFailure(args: readonly unknown[]): void {\n const store = managedAuthLookupFailures.getStore();\n if (!store) return;\n for (const value of args) {\n if (store.errors.length >= MANAGED_AUTH_LOOKUP_FAILURE_LIMIT) return;\n if (value && typeof value === \"object\") store.errors.push(value);\n }\n}\n\nfunction isBetterAuthInternalServerError(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const candidate = error as { status?: unknown; statusCode?: unknown };\n return candidate.status === \"INTERNAL_SERVER_ERROR\" || candidate.statusCode === 500;\n}\n\nexport async function withManagedAuthSessionLookup<T>(lookup: () => Promise<T>): Promise<T> {\n const store = { errors: [] as unknown[] };\n try {\n return await managedAuthLookupFailures.run(store, lookup);\n } catch (error) {\n // Better Auth's session endpoint only reads its database adapter, so a\n // socket failure it logged is that adapter's connection, not another service.\n if (\n isBetterAuthInternalServerError(error) &&\n store.errors.some(\n (logged) => isDatabaseConnectionLoss(logged) || isRetryableDatabaseTransportFailure(logged),\n )\n ) {\n throw new DatabaseUnavailableError(\"managed auth session store unavailable\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nconst ACTOR_MUTATION_LEASE_SECONDS = 15 * 60;\nconst ACTOR_MUTATION_LEASE_REFRESH_MS = 5 * 60 * 1_000;\nconst ACTOR_MUTATION_HANDLER_DEADLINE_MS = 10 * 60 * 1_000;\nconst ACTOR_MUTATION_FATAL_SAFETY_MS = 5_000;\ntype ActorMutationLeaseRuntime = {\n monotonicNow: () => number;\n schedule: (callback: () => void, delayMs: number) => ReturnType<typeof setTimeout>;\n cancel: (timer: ReturnType<typeof setTimeout>) => void;\n terminate: () => void;\n};\nconst productionActorMutationLeaseRuntime: ActorMutationLeaseRuntime = {\n monotonicNow: () => performance.now(),\n schedule: (callback, delayMs) => unrefTimer(setTimeout(callback, delayMs)),\n cancel: (timer) => clearTimeout(timer),\n terminate: () => {\n process.stderr.write(\"fatal: managed actor mutation outlived its durable lease\\n\");\n process.exit(1);\n },\n};\nlet actorMutationLeaseRuntime = productionActorMutationLeaseRuntime;\ntype ActorMutationLease = {\n db: Database;\n authorityHash: string;\n actorEpoch: string;\n requestId: string;\n refreshTimer: ReturnType<typeof setTimeout> | null;\n deadlineTimer: ReturnType<typeof setTimeout> | null;\n fatalTimer: ReturnType<typeof setTimeout> | null;\n expiresAt: Date;\n localFatalDeadlineMonotonicMs: number;\n runtime: ActorMutationLeaseRuntime;\n abortController: AbortController;\n poisoned: unknown | null;\n actorTransitionApplied: boolean;\n};\nconst actorMutationLeaseByRequest = new WeakMap<Request, ActorMutationLease>();\nconst managedActorEpochByRequest = new WeakMap<Request, string>();\nconst managedActorAdmissionByRequest = new WeakMap<Request, ManagedAuthActorAdmissionStamp>();\n\n/**\n * Read a Better Auth session without bypassing its sliding-cookie renewal.\n *\n * Better Auth can refresh the durable session while resolving `getSession`.\n * Programmatic callers must explicitly request and forward the returned cookie\n * headers; the HTTP handler does this automatically, but direct API calls do not.\n */\nconst managedUserAllowlists = new WeakMap<ManagedAuth, readonly string[]>();\n\n/** Bind admission to this auth instance, including all session-set modes. */\nexport function configureManagedUserAdmission(\n auth: ManagedAuth,\n emails: readonly string[] | undefined,\n): void {\n if (emails === undefined) managedUserAllowlists.delete(auth);\n else managedUserAllowlists.set(auth, [...emails]);\n}\n\nexport async function getManagedSession(...args: Parameters<typeof resolveManagedSession>) {\n const session = await resolveManagedSession(...args);\n assertManagedUserAdmission(args[1], session?.user);\n return session;\n}\n\nexport function assertManagedUserAdmission(\n auth: ManagedAuth,\n user: { email: string; emailVerified: boolean } | null | undefined,\n): void {\n const emails = managedUserAllowlists.get(auth);\n if (\n user &&\n emails !== undefined &&\n (!user.emailVerified || !managedUserEmailAllowed(emails, user.email))\n )\n throw new HTTPException(403, { message: \"Account is not permitted on this deployment\" });\n}\n\nasync function resolveManagedSession(\n c: Context,\n auth: ManagedAuth,\n options?: {\n db?: Database | undefined;\n allowIdentityRecovery?: boolean | undefined;\n sessionSetMode?: ManagedAuthSessionSetMode | undefined;\n sessionAdapter?: ManagedAuthSessionAdapter | null | undefined;\n },\n) {\n const sessionSetMode = options?.sessionSetMode ?? \"legacy\";\n if (sessionSetMode !== \"legacy\" && options?.db && options.sessionAdapter) {\n const authority = requestCookie(c.req.raw, MANAGED_AUTH_SESSION_SET_COOKIE);\n if (authority) {\n try {\n // A long-lived response reuses this exact Request for periodic\n // authorization. Once admitted, the server-owned stamp is the actor\n // fence: a client may omit the header on its initial GET, but a later\n // reauthorization must not follow a newly selected actor.\n const admittedActorEpoch = managedActorEpochByRequest.get(c.req.raw) ?? null;\n const expectedActorEpoch =\n admittedActorEpoch ?? c.req.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER) ?? null;\n const legacyAmbient =\n sessionSetMode === \"dual\" && expectedActorEpoch === null\n ? await options.sessionAdapter.resolveAmbientSession(c.req.raw.headers)\n : null;\n const selected = await resolveManagedAuthSelectedSession({\n db: options.db,\n adapter: options.sessionAdapter,\n authority,\n mode: sessionSetMode,\n expectedActorEpoch,\n legacyAmbientSessionId:\n typeof legacyAmbient?.session?.id === \"string\" ? legacyAmbient.session.id : null,\n allowRecovery: options.allowIdentityRecovery ?? false,\n });\n if (selected) {\n // The actor epoch is both an admission fence and response provenance.\n // A browser must ignore a late finite response after another tab has\n // advanced selection, even when the request itself was read-only.\n if (admittedActorEpoch === null) {\n c.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER, selected.projection.actorEpoch);\n managedActorEpochByRequest.set(c.req.raw, selected.projection.actorEpoch);\n }\n managedActorAdmissionByRequest.set(c.req.raw, {\n authorityHash: managedAuthSha256(authority),\n actorEpoch: selected.projection.actorEpoch,\n });\n }\n if (selected && !selected.session) return null;\n if (selected?.session) {\n let resolvedSession = selected.session;\n if (requestNeedsActorMutationLease(c.req.method)) {\n await ensureActorMutationLease(\n c.req.raw,\n options.db,\n authority,\n selected.projection.actorEpoch,\n );\n const selectedSlot = await selectedSlotForAuthority(\n options.db,\n authority,\n sessionSetMode,\n options.allowIdentityRecovery ?? false,\n );\n if (!selectedSlot) throw new ManagedAuthActorChangeError();\n const refreshed = await options.sessionAdapter.refreshSelectedSession(selectedSlot);\n if (\n !refreshed ||\n refreshed.session.id !== selectedSlot.authSessionId ||\n refreshed.user.id !== selectedSlot.authUserId\n ) {\n throw new ManagedAuthActorChangeError();\n }\n resolvedSession = refreshed;\n }\n return resolvedSession;\n }\n // Once a browser presents a session-set authority it is authoritative.\n // An absent/expired/rekeyed authority must never fall through to an\n // ambient Better Auth cookie in dual mode: that would bypass the actor\n // epoch and mutation-lease fences after another tab transitions.\n return null;\n } catch (error) {\n if (error instanceof ManagedAuthActorChangeError) {\n // Response headers are immutable after an SSE body starts. The\n // original response already carries its actor epoch; reauthorization\n // closes that stream through the thrown conflict instead.\n if (!managedActorEpochByRequest.has(c.req.raw)) {\n c.header(\"x-opengeni-actor-state\", \"changed\");\n }\n throw new HTTPException(409, { message: error.code, cause: error });\n }\n throw error;\n }\n }\n if (sessionSetMode === \"broker\") return null;\n const ambient = await options.sessionAdapter.resolveAmbientSession(c.req.raw.headers);\n if (ambient?.session?.id)\n try {\n const adopted = await getManagedAuthAdoptedSessionSnapshot(options.db, ambient.session.id);\n if (adopted) {\n const admittedActorEpoch = managedActorEpochByRequest.get(c.req.raw) ?? null;\n if (\n adopted.actorEpoch !== \"1\" ||\n (admittedActorEpoch !== null && adopted.actorEpoch !== admittedActorEpoch) ||\n !adopted.selected ||\n adopted.selected.authSessionId !== ambient.session.id ||\n adopted.selected.authUserId !== ambient.user.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n if (admittedActorEpoch === null) {\n c.header(MANAGED_AUTH_ACTOR_EPOCH_HEADER, adopted.actorEpoch);\n managedActorEpochByRequest.set(c.req.raw, adopted.actorEpoch);\n }\n managedActorAdmissionByRequest.set(c.req.raw, {\n authorityHash: adopted.authorityHash,\n actorEpoch: adopted.actorEpoch,\n });\n if (requestNeedsActorMutationLease(c.req.method)) {\n await ensureActorMutationLeaseForHash(\n c.req.raw,\n options.db,\n adopted.authorityHash,\n adopted.actorEpoch,\n );\n const current = await getManagedAuthAdoptedSessionSnapshot(\n options.db,\n ambient.session.id,\n );\n if (\n current?.authorityHash !== adopted.authorityHash ||\n current.actorEpoch !== adopted.actorEpoch ||\n !current.selected ||\n current.selected.authSessionId !== ambient.session.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n const refreshed = await options.sessionAdapter.refreshSelectedSession(current.selected);\n if (\n !refreshed ||\n refreshed.session.id !== ambient.session.id ||\n refreshed.user.id !== ambient.user.id\n ) {\n throw new ManagedAuthActorChangeError();\n }\n return refreshed;\n }\n return ambient;\n }\n } catch (error) {\n if (error instanceof ManagedAuthActorChangeError) {\n if (!managedActorEpochByRequest.has(c.req.raw)) {\n c.header(\"x-opengeni-actor-state\", \"changed\");\n }\n throw new HTTPException(409, { message: error.code, cause: error });\n }\n throw error;\n }\n }\n const result = await withManagedAuthSessionLookup(() =>\n auth.api.getSession({\n headers: c.req.raw.headers,\n returnHeaders: true,\n }),\n );\n\n for (const cookie of setCookieHeaders(result.headers)) {\n c.header(\"set-cookie\", cookie, { append: true });\n }\n\n const session = result.response;\n if (!session?.user || !options?.db) return session;\n const authSessionId = session.session?.id;\n if (typeof authSessionId !== \"string\") return null;\n const valid = await validateCanonicalHumanSession(options.db, {\n authSessionId,\n authUserId: session.user.id,\n ...(options.allowIdentityRecovery === undefined\n ? {}\n : { allowRecovery: options.allowIdentityRecovery }),\n });\n return valid ? session : null;\n}\n\n/** Safe response provenance for a request authenticated through session-set authority. */\nexport function getManagedAuthRequestActorEpoch(request: Request): string | null {\n return managedActorEpochByRequest.get(request) ?? null;\n}\n\nfunction selectedSlotForAuthority(\n db: Database,\n authority: string,\n mode: ManagedAuthSessionSetMode,\n allowRecovery: boolean,\n) {\n return getManagedAuthSessionSetSnapshot(db, {\n authorityHash: managedAuthSha256(authority),\n mode,\n includeInternal: true,\n allowRecovery,\n readOnly: true,\n }).then((snapshot) => snapshot?.selected ?? null);\n}\n\n/** Release the multi-replica actor fence after the outer HTTP handler settles. */\nexport async function releaseManagedAuthRequestActorLease(request: Request): Promise<void> {\n const lease = actorMutationLeaseByRequest.get(request);\n if (!lease) return;\n actorMutationLeaseByRequest.delete(request);\n if (lease.refreshTimer) lease.runtime.cancel(lease.refreshTimer);\n if (lease.deadlineTimer) lease.runtime.cancel(lease.deadlineTimer);\n if (lease.fatalTimer) lease.runtime.cancel(lease.fatalTimer);\n await releaseManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n requestId: lease.requestId,\n });\n}\n\n/** Cooperative cancellation signal for actor-scoped provider/external I/O. */\nexport function getManagedAuthRequestActorAbortSignal(request: Request): AbortSignal | null {\n return actorMutationLeaseByRequest.get(request)?.abortController.signal ?? null;\n}\n\n/** @internal Deterministic lease-clock seam used only by direct lifecycle tests. */\nexport function installManagedAuthActorLeaseRuntimeForTest(\n overrides: Partial<ActorMutationLeaseRuntime>,\n): () => void {\n const previous = actorMutationLeaseRuntime;\n actorMutationLeaseRuntime = {\n ...productionActorMutationLeaseRuntime,\n ...overrides,\n };\n return () => {\n actorMutationLeaseRuntime = previous;\n };\n}\n\n/**\n * Exact post-handler fence. A finite unsafe response is not released unless\n * its request-owned lease is still live at the same actor epoch.\n */\nexport async function validateManagedAuthRequestActorLease(request: Request): Promise<void> {\n const lease = actorMutationLeaseByRequest.get(request);\n if (!lease) return;\n if (lease.actorTransitionApplied) return;\n if (lease.poisoned !== null) {\n throw new ManagedAuthActorLeaseOutcomeUnknownError({\n cause: lease.poisoned,\n });\n }\n const valid = await validateManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n });\n if (!valid) throw new ManagedAuthActorChangeError();\n}\n\nexport class ManagedAuthActorLeaseOutcomeUnknownError extends Error {\n readonly name = \"ManagedAuthActorLeaseOutcomeUnknownError\";\n readonly code = \"operation_outcome_unknown\";\n constructor(options?: ErrorOptions) {\n super(\"The actor-scoped request outcome is unknown after its durable lease was lost\", options);\n }\n}\n\n/** A known-applied same-request canonical transition intentionally consumes its lease. */\nexport function markManagedAuthRequestActorTransitionApplied(request: Request): void {\n const lease = actorMutationLeaseByRequest.get(request);\n if (lease) lease.actorTransitionApplied = true;\n}\n\nexport type ManagedAuthActorMutationLeaseStamp = {\n authorityHash: string;\n actorEpoch: string;\n requestId: string;\n};\n\nexport type ManagedAuthActorAdmissionStamp = {\n authorityHash: string;\n actorEpoch: string;\n};\n\n/** Verified server-owned actor evidence available to both reads and mutations. */\nexport function getManagedAuthRequestActorAdmissionStamp(\n request: Request,\n): ManagedAuthActorAdmissionStamp | null {\n return managedActorAdmissionByRequest.get(request) ?? null;\n}\n\n/** Exact request-owned fence passed into a same-transaction actor transition. */\nexport function getManagedAuthRequestActorLeaseStamp(\n request: Request,\n): ManagedAuthActorMutationLeaseStamp | null {\n const lease = actorMutationLeaseByRequest.get(request);\n return lease\n ? {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n }\n : null;\n}\n\nfunction requestNeedsActorMutationLease(method: string): boolean {\n return method !== \"GET\" && method !== \"HEAD\" && method !== \"OPTIONS\";\n}\n\nasync function ensureActorMutationLease(\n request: Request,\n db: Database,\n authority: string,\n actorEpoch: string,\n): Promise<void> {\n const authorityHash = managedAuthSha256(authority);\n await ensureActorMutationLeaseForHash(request, db, authorityHash, actorEpoch);\n}\n\nasync function ensureActorMutationLeaseForHash(\n request: Request,\n db: Database,\n authorityHash: string,\n actorEpoch: string,\n): Promise<void> {\n const existing = actorMutationLeaseByRequest.get(request);\n if (existing) {\n if (existing.authorityHash !== authorityHash || existing.actorEpoch !== actorEpoch) {\n throw new ManagedAuthActorChangeError();\n }\n return;\n }\n const lease: ActorMutationLease = {\n db,\n authorityHash,\n actorEpoch,\n requestId: crypto.randomUUID(),\n refreshTimer: null,\n deadlineTimer: null,\n fatalTimer: null,\n expiresAt: new Date(0),\n localFatalDeadlineMonotonicMs: 0,\n runtime: actorMutationLeaseRuntime,\n abortController: new AbortController(),\n poisoned: null,\n actorTransitionApplied: false,\n };\n const acquireStartedAtMonotonicMs = lease.runtime.monotonicNow();\n try {\n lease.expiresAt = await acquireManagedAuthActorMutationLease(db, {\n authorityHash,\n actorEpoch,\n requestId: lease.requestId,\n leaseSeconds: ACTOR_MUTATION_LEASE_SECONDS,\n });\n } catch (error) {\n if (\n error instanceof ManagedAuthSessionSetGenerationConflictError ||\n error instanceof ManagedAuthSessionSetAuthorityError\n ) {\n throw new ManagedAuthActorChangeError();\n }\n throw error;\n }\n lease.localFatalDeadlineMonotonicMs =\n acquireStartedAtMonotonicMs +\n ACTOR_MUTATION_LEASE_SECONDS * 1_000 -\n ACTOR_MUTATION_FATAL_SAFETY_MS;\n actorMutationLeaseByRequest.set(request, lease);\n scheduleActorMutationLeaseRefresh(request, lease);\n lease.deadlineTimer = lease.runtime.schedule(() => {\n poisonActorMutationLease(\n request,\n lease,\n new Error(\"managed actor mutation handler exceeded its bounded lifetime\"),\n );\n }, ACTOR_MUTATION_HANDLER_DEADLINE_MS);\n}\n\nfunction scheduleActorMutationLeaseRefresh(request: Request, lease: ActorMutationLease): void {\n const timer = lease.runtime.schedule(() => {\n if (actorMutationLeaseByRequest.get(request) !== lease) return;\n const refreshStartedAtMonotonicMs = lease.runtime.monotonicNow();\n void acquireManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n actorEpoch: lease.actorEpoch,\n requestId: lease.requestId,\n leaseSeconds: ACTOR_MUTATION_LEASE_SECONDS,\n })\n .then(async (expiresAt) => {\n if (actorMutationLeaseByRequest.get(request) !== lease) {\n // Release may have won while this pooled acquire statement was in\n // flight. Converge the just-renewed row immediately; never resurrect\n // a request-owned fence after the outer handler has settled.\n await releaseManagedAuthActorMutationLease(lease.db, {\n authorityHash: lease.authorityHash,\n requestId: lease.requestId,\n });\n return;\n }\n lease.expiresAt = expiresAt;\n lease.localFatalDeadlineMonotonicMs =\n refreshStartedAtMonotonicMs +\n ACTOR_MUTATION_LEASE_SECONDS * 1_000 -\n ACTOR_MUTATION_FATAL_SAFETY_MS;\n scheduleActorMutationLeaseRefresh(request, lease);\n })\n .catch((error) => poisonActorMutationLease(request, lease, error));\n }, ACTOR_MUTATION_LEASE_REFRESH_MS);\n lease.refreshTimer = timer;\n}\n\nfunction poisonActorMutationLease(\n request: Request,\n lease: ActorMutationLease,\n error: unknown,\n): void {\n if (actorMutationLeaseByRequest.get(request) !== lease || lease.poisoned !== null) return;\n lease.poisoned = error;\n if (lease.refreshTimer) lease.runtime.cancel(lease.refreshTimer);\n lease.refreshTimer = null;\n lease.abortController.abort(error);\n const fatalAfterMs = Math.max(\n 0,\n lease.localFatalDeadlineMonotonicMs - lease.runtime.monotonicNow(),\n );\n lease.fatalTimer = lease.runtime.schedule(() => {\n if (actorMutationLeaseByRequest.get(request) !== lease) return;\n // A handler that ignored cooperative cancellation must not outlive the\n // durable fence and resume under a later actor. Terminate this API\n // instance before PostgreSQL can expire the lease; process death is the\n // final multi-replica-safe cancellation boundary.\n lease.runtime.terminate();\n }, fatalAfterMs);\n}\n\nfunction unrefTimer<T extends ReturnType<typeof setTimeout>>(timer: T): T {\n (timer as T & { unref?: () => void }).unref?.();\n return timer;\n}\n\nfunction requestCookie(request: Request, name: string): string | null {\n const header = request.headers.get(\"cookie\");\n if (!header) return null;\n for (const part of header.split(\";\")) {\n const separator = part.indexOf(\"=\");\n if (separator < 0 || part.slice(0, separator).trim() !== name) continue;\n const value = part.slice(separator + 1).trim();\n if (!value || value.length > 512) return null;\n try {\n return decodeURIComponent(value);\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction setCookieHeaders(headers: Headers): string[] {\n const getSetCookie = (\n headers as Headers & {\n getSetCookie?: () => string[];\n }\n ).getSetCookie;\n if (getSetCookie) {\n return getSetCookie.call(headers);\n }\n\n const cookie = headers.get(\"set-cookie\");\n return cookie ? [cookie] : [];\n}\n"],"mappings":"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","names":[]}
@@ -9,6 +9,8 @@ type Input = {
9
9
  grant: AccessGrant;
10
10
  capabilityId: string;
11
11
  personalOwnerVerified: boolean;
12
+ connectionId?: string;
13
+ instanceKey?: string;
12
14
  };
13
15
  type ListedTool = {
14
16
  name: string;
@@ -26,7 +28,7 @@ export declare function connectorToolGroup(tool: ListedTool): "read" | "write" |
26
28
  export declare function unpinnedConnectorToolPermissionAccount<T extends ConnectionMetadata>(ref: McpServerConnectionRef, visible: T[], subjectId: string): T | null;
27
29
  export declare function connectorToolPermissionReference(ref: McpServerConnectionRef, connectionId: string): McpServerConnectionRef;
28
30
  /** Use the same adapter-owned identities as execution for reviewed local catalogs. */
29
- export declare function reviewedConnectorToolCatalog(server: Pick<Settings["mcpServers"][number], "url" | "connectionRef" | "allowedTools">, grantedScopes: readonly string[]): ListedTool[] | null;
31
+ export declare function reviewedConnectorToolCatalog(server: Pick<Settings["mcpServers"][number], "url" | "connectionRef" | "allowedTools">, grantedScopes: readonly string[], deployment: Pick<Settings, "gmailWatchTopicName">): ListedTool[] | null;
30
32
  /** Collect discovery pages without changing the caller's connection or authority. */
31
33
  export declare function collectConnectorToolPages(client: Pick<Client, "listTools">, deadline: AbortSignal): Promise<ListedTool[]>;
32
34
  export declare function getConnectorToolPermissions(input: Input): Promise<ConnectorToolPermissionsResponse>;
@@ -1,23 +1,23 @@
1
1
  import { type Database, type KnowledgeContext } from "@opengeni/db";
2
2
  /** Retain actual message bytes, never a model-authored reconstruction of a confirmation. */
3
3
  export declare function retainKnowledgeMessage(db: Database, context: KnowledgeContext, messageId?: string): Promise<{
4
- revisionId?: never;
5
4
  retained: boolean;
6
5
  reason: string;
7
6
  entryId?: never;
7
+ revisionId?: never;
8
8
  outcome?: never;
9
9
  messageId?: never;
10
10
  reused?: never;
11
11
  } | {
12
- revisionId?: never;
13
12
  retained: boolean;
14
13
  reason: string;
15
14
  entryId: string;
15
+ revisionId?: never;
16
16
  outcome?: never;
17
17
  messageId?: never;
18
18
  reused?: never;
19
19
  } | {
20
- reason?: never;
20
+ readonly reason?: never;
21
21
  retained: boolean;
22
22
  entryId: string;
23
23
  revisionId: string;
@@ -32,7 +32,7 @@ export declare function retainKnowledgeMessage(db: Database, context: KnowledgeC
32
32
  outcome: "archived" | "pending" | "published" | "rejected";
33
33
  reviewBatchId: string | null;
34
34
  replayed: boolean;
35
- reason?: never;
35
+ readonly reason?: never;
36
36
  reused?: never;
37
37
  retained: boolean;
38
38
  messageId: string;
@@ -0,0 +1,81 @@
1
+ import { type RealtimeVoicePricing, type Settings } from "@opengeni/config";
2
+ import type { SessionRealtimeModel } from "@opengeni/contracts";
3
+ import { type CreditDebitAttribution, type Database } from "@opengeni/db";
4
+ import { TranscriptionBillingRefusedError } from "../transcription.js";
5
+ /** Credit debit type and usage source for deployment-funded live voice. */
6
+ export declare const REALTIME_VOICE_DEBIT_TYPE = "voice_realtime_debit";
7
+ export declare const REALTIME_VOICE_SOURCE_TYPE = "voice_realtime";
8
+ export type DeploymentRealtimeVoice = {
9
+ provider: "azure-live" | "ai-gateway";
10
+ /** Credentials exist and this deployment offers the model. */
11
+ configured: boolean;
12
+ pricing: RealtimeVoicePricing | null;
13
+ };
14
+ /**
15
+ * Live-voice models the deployment pays the provider for. Connected Codex,
16
+ * SuperGrok, and a workspace's own Gateway key are paid by the workspace and
17
+ * return null. (The catalog lists hosted GPT Live instead of the managed
18
+ * Gateway choices when both are configured; both remain priced and gated.)
19
+ */
20
+ export declare function deploymentRealtimeVoice(settings: Settings, model: SessionRealtimeModel | string): DeploymentRealtimeVoice | null;
21
+ export type RealtimeVoiceUnavailableCode = "not_configured" | "pricing_unconfigured";
22
+ /** The deployment cannot offer this live-voice model at all (not a credit refusal). */
23
+ export declare class RealtimeVoiceUnavailableError extends Error {
24
+ readonly code: RealtimeVoiceUnavailableCode;
25
+ readonly name = "RealtimeVoiceUnavailableError";
26
+ constructor(code: RealtimeVoiceUnavailableCode, message: string);
27
+ }
28
+ /** Static offer check: configured, and priced whenever credits are enforced. */
29
+ export declare function realtimeVoiceOfferProblem(settings: Settings, voice: DeploymentRealtimeVoice): RealtimeVoiceUnavailableError | null;
30
+ export declare const REALTIME_VOICE_INSUFFICIENT_CREDITS_MESSAGE = "Live voice needs Opengeni credits. Add credits to continue.";
31
+ export type RealtimeVoiceSettlement = {
32
+ /** Credits debited by this settlement call (0 on replay). */
33
+ debitedMicros: number;
34
+ /** Why the live call must stop now, when it must. */
35
+ stop: TranscriptionBillingRefusedError | RealtimeVoiceUnavailableError | null;
36
+ };
37
+ /**
38
+ * Credit admission and time metering for deployment-funded live voice.
39
+ *
40
+ * Admission mirrors voice-input admission (same refusal codes and HTTP
41
+ * shape): spendable general credits must be positive, the workspace/member
42
+ * allowance must not be exhausted, and the static monthly cost cap applies.
43
+ * Metering bills every started minute of each issued provider connection,
44
+ * measured only from server-observed facts (connection claim time, owner
45
+ * heartbeats, owner-proven end). Each (connection, minute) is one idempotent
46
+ * usage receipt plus one post-use debit.
47
+ */
48
+ export declare function createRealtimeVoiceBilling(deps: {
49
+ db: Database;
50
+ settings: Settings;
51
+ }): {
52
+ /**
53
+ * Throws RealtimeVoiceUnavailableError when the deployment cannot offer
54
+ * the model and TranscriptionBillingRefusedError for a credit refusal.
55
+ * Workspace-funded models are always admitted here.
56
+ */
57
+ admit(input: {
58
+ accountId: string;
59
+ workspaceId: string;
60
+ model: SessionRealtimeModel;
61
+ attribution: CreditDebitAttribution;
62
+ now?: Date;
63
+ }): Promise<void>;
64
+ /** Spendable credits are positive (always true when credits are not enforced). */
65
+ hasSpendableCredits(accountId: string): Promise<boolean>;
66
+ /**
67
+ * Settle every started minute observed so far for one live-voice mode and
68
+ * report whether the call must stop. Safe to call repeatedly and
69
+ * concurrently: receipts and debits are idempotent per (connection, minute).
70
+ */
71
+ settle(input: {
72
+ workspaceId: string;
73
+ sessionId: string;
74
+ realtimeId: string;
75
+ /** Authenticated caller; its attribution applies only when it owns the call. */
76
+ callerSubjectId: string;
77
+ attribution: CreditDebitAttribution;
78
+ now?: Date;
79
+ }): Promise<RealtimeVoiceSettlement>;
80
+ };
81
+ export type RealtimeVoiceBilling = ReturnType<typeof createRealtimeVoiceBilling>;
@@ -10,7 +10,7 @@
10
10
  * ordinary owner update path, so a refresh never widens beyond what the calling
11
11
  * person could grant with an edit. See docs/scheduled-task-access.md.
12
12
  */
13
- import { type Settings } from "@opengeni/config";
13
+ import { type Settings, type FirstPartyMcpToolPolicySettings } from "@opengeni/config";
14
14
  import { type AccessGrant, type ConnectionMetadata, type FirstPartyMcpToolName, type McpConnectionAccountSelection, type Permission, type RefreshScheduledTaskAccessRequest, type ScheduledTask, type ScheduledTaskAccessAttention, type ScheduledTaskAccessConnector, type ScheduledTaskPolicyDrift, type ScheduledTaskRun, type ScheduledTaskRunAccessFailure, type SessionAuthorizationPort, type SessionAuthorizationSurface, type ToolRef } from "@opengeni/contracts";
15
15
  import { type Database, type ScheduledTaskCreatorPolicy } from "@opengeni/db";
16
16
  import { type AccessGrantAuthorization } from "../access/index.js";
@@ -88,7 +88,7 @@ export type FirstPartyToolPermissionRequirements = (tools: readonly FirstPartyMc
88
88
  */
89
89
  export declare function planScheduledTaskOpenGeniTools(input: {
90
90
  creatorPolicy: Pick<ScheduledTaskCreatorPolicy, "firstPartyMcpTools" | "firstPartyMcpPermissions"> | null;
91
- settings: Pick<Settings, "defaultFirstPartyMcpTools" | "allowedFirstPartyMcpTools">;
91
+ settings: FirstPartyMcpToolPolicySettings;
92
92
  grantPermissions: readonly Permission[];
93
93
  grantPermissionMode?: AccessGrant["permissionMode"];
94
94
  permissionsRequiredByTools: FirstPartyToolPermissionRequirements;
@@ -1,4 +1,4 @@
1
- import { type Settings } from "@opengeni/config";
1
+ import { type FirstPartyMcpToolPolicySettings, type Settings } from "@opengeni/config";
2
2
  import type { AccessGrant, ScheduledTask, ScheduledTaskAgentConfig, Session, ToolRef, SessionAuthorizationPort, SessionAuthorizationSurface, CreateScheduledTaskRequest as CreateScheduledTaskPayload, UpdateScheduledTaskRequest as UpdateScheduledTaskPayload } from "@opengeni/contracts";
3
3
  import { type KnowledgeContext, type Database, type ScheduledTaskCreatorPolicy, type SessionCommandActor, type TemporalScheduleCleanupClaim, type UpdateScheduledTaskInput } from "@opengeni/db";
4
4
  import { type AccessGrantAuthorization } from "../access/index.js";
@@ -195,4 +195,4 @@ export declare function manualScheduledTaskTriggerUsageKey(workspaceId: string,
195
195
  * provider, or treats ambient worker credentials as responder capability.
196
196
  * Mutable rig/variable-set metadata is revalidated again at dispatch.
197
197
  */
198
- export declare function validateIncidentTelemetryPreflightSelection(settings: Pick<Settings, "allowedFirstPartyMcpTools" | "defaultFirstPartyMcpTools">, agentConfig: ScheduledTaskAgentConfig): void;
198
+ export declare function validateIncidentTelemetryPreflightSelection(settings: FirstPartyMcpToolPolicySettings, agentConfig: ScheduledTaskAgentConfig): void;
@@ -1,5 +1,5 @@
1
1
  import type { AccessGrant } from "@opengeni/contracts";
2
- import type { Settings } from "@opengeni/config";
2
+ import { type Settings } from "@opengeni/config";
3
3
  import { type Database } from "@opengeni/db";
4
4
  /** Freeze the authenticated request's eligible accounts before starting voice.
5
5
  * The resulting lease snapshot, not a later participant or ambient connection,
@@ -106,10 +106,10 @@ export declare function sessionEffectiveToolProjectionInput(session: Session & {
106
106
  mcpServerIds: string[];
107
107
  productServerIds: ReadonlySet<string>;
108
108
  environment: AgentToolEnvironment;
109
- runtimeToolNames: ("apply_patch" | "code_search" | "exec_command" | "generate_image" | "generate_video" | "get_video_generation_capabilities" | "image_generation" | "knowledge_source_fetch" | "knowledge_source_read" | "list_models" | "operation_read" | "refresh_credentials" | "repository_skill_read" | "request_human_input" | "skill_checkout" | "skill_install" | "skill_publish" | "skill_read" | "skill_remove" | "skill_save" | "skill_search" | "tool_invoke" | "tool_list" | "tool_search" | "view_image" | "web_search" | "write_stdin" | "x_search")[];
110
- hostedToolNames: ("apply_patch" | "code_search" | "exec_command" | "generate_image" | "generate_video" | "get_video_generation_capabilities" | "image_generation" | "knowledge_source_fetch" | "knowledge_source_read" | "list_models" | "operation_read" | "refresh_credentials" | "repository_skill_read" | "request_human_input" | "skill_checkout" | "skill_install" | "skill_publish" | "skill_read" | "skill_remove" | "skill_save" | "skill_search" | "tool_invoke" | "tool_list" | "tool_search" | "view_image" | "web_search" | "write_stdin" | "x_search")[];
111
- sandboxToolNames: ("apply_patch" | "code_search" | "exec_command" | "generate_image" | "generate_video" | "get_video_generation_capabilities" | "image_generation" | "knowledge_source_fetch" | "knowledge_source_read" | "list_models" | "operation_read" | "refresh_credentials" | "repository_skill_read" | "request_human_input" | "skill_checkout" | "skill_install" | "skill_publish" | "skill_read" | "skill_remove" | "skill_save" | "skill_search" | "tool_invoke" | "tool_list" | "tool_search" | "view_image" | "web_search" | "write_stdin" | "x_search")[];
112
- routerToolNames: ("apply_patch" | "code_search" | "exec_command" | "generate_image" | "generate_video" | "get_video_generation_capabilities" | "image_generation" | "knowledge_source_fetch" | "knowledge_source_read" | "list_models" | "operation_read" | "refresh_credentials" | "repository_skill_read" | "request_human_input" | "skill_checkout" | "skill_install" | "skill_publish" | "skill_read" | "skill_remove" | "skill_save" | "skill_search" | "tool_invoke" | "tool_list" | "tool_search" | "view_image" | "web_search" | "write_stdin" | "x_search")[];
109
+ runtimeToolNames: ("apply_patch" | "code_search" | "exec_command" | "generate_image" | "generate_video" | "get_video_generation_capabilities" | "image_generation" | "knowledge_source_fetch" | "knowledge_source_read" | "list_models" | "operation_read" | "refresh_credentials" | "repository_skill_read" | "request_human_input" | "skill_checkout" | "skill_install" | "skill_publish" | "skill_read" | "skill_remove" | "skill_save" | "skill_search" | "tool_invoke" | "tool_list" | "tool_search" | "view_image" | "web_fetch" | "web_search" | "write_stdin" | "x_search")[];
110
+ hostedToolNames: ("apply_patch" | "code_search" | "exec_command" | "generate_image" | "generate_video" | "get_video_generation_capabilities" | "image_generation" | "knowledge_source_fetch" | "knowledge_source_read" | "list_models" | "operation_read" | "refresh_credentials" | "repository_skill_read" | "request_human_input" | "skill_checkout" | "skill_install" | "skill_publish" | "skill_read" | "skill_remove" | "skill_save" | "skill_search" | "tool_invoke" | "tool_list" | "tool_search" | "view_image" | "web_fetch" | "web_search" | "write_stdin" | "x_search")[];
111
+ sandboxToolNames: ("apply_patch" | "code_search" | "exec_command" | "generate_image" | "generate_video" | "get_video_generation_capabilities" | "image_generation" | "knowledge_source_fetch" | "knowledge_source_read" | "list_models" | "operation_read" | "refresh_credentials" | "repository_skill_read" | "request_human_input" | "skill_checkout" | "skill_install" | "skill_publish" | "skill_read" | "skill_remove" | "skill_save" | "skill_search" | "tool_invoke" | "tool_list" | "tool_search" | "view_image" | "web_fetch" | "web_search" | "write_stdin" | "x_search")[];
112
+ routerToolNames: ("apply_patch" | "code_search" | "exec_command" | "generate_image" | "generate_video" | "get_video_generation_capabilities" | "image_generation" | "knowledge_source_fetch" | "knowledge_source_read" | "list_models" | "operation_read" | "refresh_credentials" | "repository_skill_read" | "request_human_input" | "skill_checkout" | "skill_install" | "skill_publish" | "skill_read" | "skill_remove" | "skill_save" | "skill_search" | "tool_invoke" | "tool_list" | "tool_search" | "view_image" | "web_fetch" | "web_search" | "write_stdin" | "x_search")[];
113
113
  upfrontToolNames: Set<string>;
114
114
  mediaAttachment: AgentMediaAttachment | {
115
115
  readonly image: null;
@@ -0,0 +1,76 @@
1
+ import { type Settings, type VoiceInputPricing, type VoiceInputUsage } from "@opengeni/config";
2
+ import { type Database } from "@opengeni/db";
3
+ import { type TranscriptionBilling, type TranscriptionBillingContext } from "../transcription.js";
4
+ /** Credit debit type and usage source for deployment-funded voice input. */
5
+ export declare const VOICE_INPUT_DEBIT_TYPE = "voice_transcription_debit";
6
+ export declare const VOICE_INPUT_SOURCE_TYPE = "voice_transcription";
7
+ /** How the billed quantity was measured; recorded on the ledger entry. */
8
+ export type VoiceInputBillingBasis = "provider_tokens" | "provider_duration" | "server_duration" | "reconciled_receipt";
9
+ /**
10
+ * Pick the billed measurement. Provider usage wins when this deployment can
11
+ * price it (token usage with token rates, or a reported duration). Otherwise
12
+ * the duration the server measured from WAV bytes it produced bills. Every
13
+ * deployment-funded call carries that server duration, so an unpriced usage
14
+ * shape never leaves a call unbillable. A client-reported duration is never a
15
+ * billing input.
16
+ */
17
+ export declare function voiceInputBillableUsage(input: {
18
+ pricing: VoiceInputPricing;
19
+ usage: VoiceInputUsage | null;
20
+ trustedDurationSeconds?: number | undefined;
21
+ }): {
22
+ usage: VoiceInputUsage;
23
+ basis: VoiceInputBillingBasis;
24
+ };
25
+ /**
26
+ * Same admission shape as knowledge-search and session admission: general
27
+ * (not model-promotional) credits must be positive, the workspace/member
28
+ * allowance must not be exhausted, and a static monthly cost cap applies.
29
+ * Admission is a read, not a reservation; settlement is post-use and may take
30
+ * an account below zero by at most the concurrent in-flight calls.
31
+ */
32
+ export declare function createVoiceInputBilling(deps: {
33
+ db: Database;
34
+ settings: Settings;
35
+ /** Reconciliation is best-effort at admission; failures are reported here. */
36
+ onReconcileError?: (error: unknown, scope: {
37
+ accountId: string;
38
+ workspaceId: string;
39
+ }) => void;
40
+ /** Minimum spacing of admission-time reconciliation per workspace (default 5 min). */
41
+ reconcileIntervalMilliseconds?: number;
42
+ }): TranscriptionBilling;
43
+ /**
44
+ * Two commits, in order: the `model.cost` usage receipt (Insights spend,
45
+ * monthly cost cap, member-allowance attribution), then the post-use credit
46
+ * debit. The receipt is the first-writer authority for the amount and the
47
+ * durable record of the charge: if the debit commit fails, the receipt stays
48
+ * and {@link reconcileUnsettledVoiceInputCharges} applies the same debit (same
49
+ * idempotency key) on the workspace's next admission. A retried unit settles
50
+ * exactly once at the originally recorded price.
51
+ */
52
+ export declare function settleVoiceInputUsage(db: Database, input: {
53
+ accountId: string;
54
+ workspaceId: string;
55
+ providerId: string;
56
+ model: string;
57
+ billing: TranscriptionBillingContext;
58
+ usage: VoiceInputUsage;
59
+ basis: VoiceInputBillingBasis;
60
+ providerCostMicros: number;
61
+ creditCostMicros: number;
62
+ }): Promise<{
63
+ creditCostMicros: number;
64
+ }>;
65
+ /**
66
+ * Apply the debit for every voice usage receipt in this workspace whose debit
67
+ * never committed. Idempotent with the inline settlement (same key), bounded
68
+ * per call, and safe to run concurrently.
69
+ */
70
+ export declare function reconcileUnsettledVoiceInputCharges(db: Database, input: {
71
+ accountId: string;
72
+ workspaceId: string;
73
+ minAgeMilliseconds?: number;
74
+ }): Promise<{
75
+ reconciled: number;
76
+ }>;
@@ -0,0 +1,45 @@
1
+ import type { Settings } from "@opengeni/config";
2
+ import { type Database } from "@opengeni/db";
3
+ /** Credit ledger type and usage source for deployment-funded web search calls. */
4
+ export declare const WEB_SEARCH_DEBIT_TYPE = "web_search_debit";
5
+ export declare const WEB_SEARCH_SOURCE_TYPE = "web_search";
6
+ /** Same rule as other deployment-funded resources: Stripe or managed limits. */
7
+ export declare function webSearchCreditBillingActive(settings: Pick<Settings, "billingMode" | "usageLimitsMode">): boolean;
8
+ /** Exact attempt that called the tool. Every charge is attributed to its turn. */
9
+ export type WebSearchCallScope = {
10
+ accountId: string;
11
+ workspaceId: string;
12
+ sessionId: string;
13
+ turnId: string;
14
+ attemptId: string;
15
+ };
16
+ export type WebSearchCallCost = {
17
+ /** Model tool-call or Codemode operation identity, unique within the attempt. */
18
+ operationId: string;
19
+ operation: "search" | "fetch";
20
+ provider: string;
21
+ providerMicros: number;
22
+ creditMicros: number;
23
+ marginBps: number;
24
+ basis: "provider_reported" | "configured_price" | "list_price";
25
+ };
26
+ export declare class WebSearchBillingRefusedError extends Error {
27
+ readonly code: "insufficient_credits" | "allowance_exhausted";
28
+ constructor(code: "insufficient_credits" | "allowance_exhausted", message: string);
29
+ }
30
+ /**
31
+ * Admission and post-use settlement for paid web search, matching paid
32
+ * Knowledge queries and voice input: admission reads general credits and the
33
+ * workspace/member allowance (a read, not a reservation); settlement records a
34
+ * durable usage receipt and the idempotent debit in one transaction. Calls
35
+ * that cost nothing (free providers, or billing inactive) are never refused.
36
+ */
37
+ export declare function createWebSearchBilling(deps: {
38
+ db: Database;
39
+ settings: Settings;
40
+ }): {
41
+ active: boolean;
42
+ admit(scope: WebSearchCallScope, expectedProviderMicros: number): Promise<void>;
43
+ settle(scope: WebSearchCallScope, cost: WebSearchCallCost): Promise<void>;
44
+ };
45
+ export type WebSearchBilling = ReturnType<typeof createWebSearchBilling>;
@@ -102,6 +102,7 @@ export declare function resolveGoalModelAdmission(db: Database, settings: Settin
102
102
  delegationSecret?: string | undefined;
103
103
  defaultFirstPartyMcpTools?: ("artifacts_archive" | "artifacts_create" | "artifacts_get_source" | "artifacts_list" | "artifacts_prepare_upload" | "artifacts_publish" | "artifacts_restore" | "artifacts_rollback" | "atlassian_get" | "atlassian_search" | "atlassian_sources_list" | "browser_act" | "browser_auth" | "browser_clipboard" | "browser_debug" | "browser_download_save" | "browser_downloads" | "browser_identity" | "browser_lifecycle" | "browser_observe" | "browser_open" | "browser_publish" | "browser_read" | "browser_screenshot" | "browser_tabs" | "capability_authorization_request" | "capability_catalog_search" | "command_read" | "command_wait" | "company_profile_confirm" | "company_profile_propose" | "computer_act" | "computer_clipboard" | "computer_lifecycle" | "computer_observe" | "computer_open" | "computer_targets" | "connected_machine_enroll_token" | "connected_machine_remove" | "custom_mcp_setup_request" | "editable_artifact_apply" | "editable_artifact_create" | "editable_artifact_export" | "editable_artifact_export_status" | "editable_artifact_get" | "editable_artifact_import" | "editable_artifact_inspect" | "editable_artifact_list" | "environment_list" | "environment_set_variable" | "fiken_bank_accounts_list" | "fiken_companies_list" | "fiken_contact_create" | "fiken_contacts_list" | "fiken_invoice_draft_create" | "fiken_invoice_get" | "fiken_invoices_list" | "fiken_products_list" | "fiken_purchases_list" | "fiken_sales_list" | "github_connect_link" | "github_repositories_list" | "goal_complete" | "goal_pause" | "goal_progress" | "goal_resume" | "goal_set" | "goal_update" | "instruction_policy_get" | "instruction_policy_propose" | "instruction_policy_save" | "interaction_discover" | "interaction_request_human" | "knowledge_archive" | "knowledge_browse" | "knowledge_correct" | "knowledge_get" | "knowledge_prepare_save" | "knowledge_propose" | "knowledge_retain_file" | "knowledge_retain_message" | "knowledge_save" | "knowledge_search" | "memory_correct" | "memory_save" | "memory_search" | "preference_propose" | "preference_registry_get" | "preference_registry_summary" | "project_create" | "project_delete" | "project_get" | "project_list" | "project_reorder" | "project_update" | "reddit_accounts_list" | "reddit_mentions_live" | "reddit_post_reply" | "reddit_posts_sync" | "reddit_search_live" | "reddit_thread_fetch" | "remember" | "remember_confirm" | "rig_get" | "rig_list" | "rig_promote" | "rig_propose_change" | "rig_verify" | "run_on" | "sandbox_attach" | "sandbox_file_publish" | "sandbox_provision" | "sandbox_swap" | "sandboxes_list" | "scheduled_task_runs_list" | "scheduled_tasks_create" | "scheduled_tasks_delete" | "scheduled_tasks_get" | "scheduled_tasks_list" | "scheduled_tasks_pause" | "scheduled_tasks_resume" | "scheduled_tasks_trigger" | "scheduled_tasks_update" | "session_create" | "session_events" | "session_get" | "session_human_input_respond" | "session_pause" | "session_resume" | "session_send_message" | "session_set_model" | "session_set_project" | "session_steer" | "session_wait" | "sessions_list" | "set_other_session_title" | "set_session_title" | "slack_bot_channel_history" | "slack_bot_delete_message" | "slack_bot_file_content" | "slack_bot_file_info" | "slack_bot_list_channels" | "slack_bot_list_files" | "slack_bot_list_users" | "slack_bot_post_message" | "slack_bot_prepare_message" | "slack_bot_search" | "slack_bot_send_prepared_message" | "slack_bot_thread_replies" | "slack_bot_upload_file" | "social_connections_list" | "social_daily_analysis_context" | "social_mentions_live" | "social_post_reply" | "social_posts_recent" | "social_posts_sync" | "social_search_live" | "social_thread_fetch" | "task_note_archive" | "task_note_promote_instruction_policy" | "task_note_promote_knowledge" | "task_note_promote_preference" | "task_note_replace" | "task_note_save" | "task_notes_list" | "variable_set_get_variable" | "variable_set_list" | "variable_set_set_variable" | "wait_for_input" | "work_claim_release" | "work_claim_upsert" | "x_accounts_list" | "x_mentions_live" | "x_post_reply" | "x_posts_sync" | "x_search_live" | "x_thread_fetch")[] | undefined;
104
104
  allowedFirstPartyMcpTools?: ("artifacts_archive" | "artifacts_create" | "artifacts_get_source" | "artifacts_list" | "artifacts_prepare_upload" | "artifacts_publish" | "artifacts_restore" | "artifacts_rollback" | "atlassian_get" | "atlassian_search" | "atlassian_sources_list" | "browser_act" | "browser_auth" | "browser_clipboard" | "browser_debug" | "browser_download_save" | "browser_downloads" | "browser_identity" | "browser_lifecycle" | "browser_observe" | "browser_open" | "browser_publish" | "browser_read" | "browser_screenshot" | "browser_tabs" | "capability_authorization_request" | "capability_catalog_search" | "command_read" | "command_wait" | "company_profile_confirm" | "company_profile_propose" | "computer_act" | "computer_clipboard" | "computer_lifecycle" | "computer_observe" | "computer_open" | "computer_targets" | "connected_machine_enroll_token" | "connected_machine_remove" | "custom_mcp_setup_request" | "editable_artifact_apply" | "editable_artifact_create" | "editable_artifact_export" | "editable_artifact_export_status" | "editable_artifact_get" | "editable_artifact_import" | "editable_artifact_inspect" | "editable_artifact_list" | "environment_list" | "environment_set_variable" | "fiken_bank_accounts_list" | "fiken_companies_list" | "fiken_contact_create" | "fiken_contacts_list" | "fiken_invoice_draft_create" | "fiken_invoice_get" | "fiken_invoices_list" | "fiken_products_list" | "fiken_purchases_list" | "fiken_sales_list" | "github_connect_link" | "github_repositories_list" | "goal_complete" | "goal_pause" | "goal_progress" | "goal_resume" | "goal_set" | "goal_update" | "instruction_policy_get" | "instruction_policy_propose" | "instruction_policy_save" | "interaction_discover" | "interaction_request_human" | "knowledge_archive" | "knowledge_browse" | "knowledge_correct" | "knowledge_get" | "knowledge_prepare_save" | "knowledge_propose" | "knowledge_retain_file" | "knowledge_retain_message" | "knowledge_save" | "knowledge_search" | "memory_correct" | "memory_save" | "memory_search" | "preference_propose" | "preference_registry_get" | "preference_registry_summary" | "project_create" | "project_delete" | "project_get" | "project_list" | "project_reorder" | "project_update" | "reddit_accounts_list" | "reddit_mentions_live" | "reddit_post_reply" | "reddit_posts_sync" | "reddit_search_live" | "reddit_thread_fetch" | "remember" | "remember_confirm" | "rig_get" | "rig_list" | "rig_promote" | "rig_propose_change" | "rig_verify" | "run_on" | "sandbox_attach" | "sandbox_file_publish" | "sandbox_provision" | "sandbox_swap" | "sandboxes_list" | "scheduled_task_runs_list" | "scheduled_tasks_create" | "scheduled_tasks_delete" | "scheduled_tasks_get" | "scheduled_tasks_list" | "scheduled_tasks_pause" | "scheduled_tasks_resume" | "scheduled_tasks_trigger" | "scheduled_tasks_update" | "session_create" | "session_events" | "session_get" | "session_human_input_respond" | "session_pause" | "session_resume" | "session_send_message" | "session_set_model" | "session_set_project" | "session_steer" | "session_wait" | "sessions_list" | "set_other_session_title" | "set_session_title" | "slack_bot_channel_history" | "slack_bot_delete_message" | "slack_bot_file_content" | "slack_bot_file_info" | "slack_bot_list_channels" | "slack_bot_list_files" | "slack_bot_list_users" | "slack_bot_post_message" | "slack_bot_prepare_message" | "slack_bot_search" | "slack_bot_send_prepared_message" | "slack_bot_thread_replies" | "slack_bot_upload_file" | "social_connections_list" | "social_daily_analysis_context" | "social_mentions_live" | "social_post_reply" | "social_posts_recent" | "social_posts_sync" | "social_search_live" | "social_thread_fetch" | "task_note_archive" | "task_note_promote_instruction_policy" | "task_note_promote_knowledge" | "task_note_promote_preference" | "task_note_replace" | "task_note_save" | "task_notes_list" | "variable_set_get_variable" | "variable_set_list" | "variable_set_set_variable" | "wait_for_input" | "work_claim_release" | "work_claim_upsert" | "x_accounts_list" | "x_mentions_live" | "x_post_reply" | "x_posts_sync" | "x_search_live" | "x_thread_fetch")[] | undefined;
105
+ artifactMaterializerDeployed: boolean;
105
106
  streamTokenSecret?: string | undefined;
106
107
  streamControlEnabled: boolean;
107
108
  workDiscoveryEnabled: boolean;
@@ -201,6 +202,20 @@ export declare function resolveGoalModelAdmission(db: Database, settings: Settin
201
202
  voiceInputAzureApiVersion?: string | undefined;
202
203
  voiceInputAzureApiKey?: string | undefined;
203
204
  voiceInputAzureAdToken?: string | undefined;
205
+ azureLiveEndpoint?: string | undefined;
206
+ azureLiveApiKey?: string | undefined;
207
+ azureLiveDeployment: string;
208
+ azureLiveVoice: string;
209
+ azureLivePricingJson?: string | undefined;
210
+ aiGatewayRealtimePricingJson?: string | undefined;
211
+ voiceInputMaiEndpoint?: string | undefined;
212
+ voiceInputMaiApiKey?: string | undefined;
213
+ voiceInputMaiApiVersion: string;
214
+ voiceInputMaiPricingJson?: string | undefined;
215
+ voiceInputMaiModel: string;
216
+ voiceInputAzureModel?: string | undefined;
217
+ voiceInputOpenaiPricingJson?: string | undefined;
218
+ voiceInputAzurePricingJson?: string | undefined;
204
219
  voiceInputCodexExperimentalEnabled: boolean;
205
220
  modelPricingJson: string;
206
221
  modelCatalogSource: "code" | "database";
@@ -231,6 +246,15 @@ export declare function resolveGoalModelAdmission(db: Database, settings: Settin
231
246
  openaiReasoningEncryptedContent: boolean;
232
247
  openaiMaxRetries: number;
233
248
  webSearchEnabled: boolean;
249
+ webSearchProvider?: string | undefined;
250
+ webSearchApiKey?: string | undefined;
251
+ webSearchBaseUrl?: string | undefined;
252
+ webFetchProvider?: string | undefined;
253
+ webFetchApiKey?: string | undefined;
254
+ webFetchBaseUrl?: string | undefined;
255
+ webSearchProviderMode?: string | undefined;
256
+ webSearchPricingJson?: string | undefined;
257
+ webSearchRequestTimeoutMs: number;
234
258
  jevApiKey?: string | undefined;
235
259
  jevBaseUrl: string;
236
260
  jevModel: string;
package/dist/index.d.ts CHANGED
@@ -7,13 +7,16 @@ export * from "./domain/session-connection-accounts.js";
7
7
  export * from "./domain/organization-integration-catalog.js";
8
8
  export * from "./domain/knowledge.js";
9
9
  export * from "./domain/knowledge-search.js";
10
+ export * from "./domain/voice-input-billing.js";
11
+ export * from "./domain/web-search-billing.js";
12
+ export * from "./domain/realtime-voice-billing.js";
10
13
  export * from "./dependencies.js";
11
14
  export * from "./workflow-wake-contract.js";
12
15
  export * from "./user-presence.js";
13
16
  export * from "./product-usage-metrics.js";
14
17
  export * from "./sandbox-types.js";
15
18
  export * from "./managed-auth-type.js";
16
- export { getManagedAuthRequestActorAbortSignal, getManagedAuthRequestActorAdmissionStamp, getManagedAuthRequestActorEpoch, getManagedAuthRequestActorLeaseStamp, getManagedSession, configureManagedUserAdmission, assertManagedUserAdmission, ManagedAuthActorLeaseOutcomeUnknownError, markManagedAuthRequestActorTransitionApplied, releaseManagedAuthRequestActorLease, validateManagedAuthRequestActorLease, type ManagedAuthActorAdmissionStamp, type ManagedAuthActorMutationLeaseStamp, } from "./managed-session.js";
19
+ export { getManagedAuthRequestActorAbortSignal, getManagedAuthRequestActorAdmissionStamp, getManagedAuthRequestActorEpoch, getManagedAuthRequestActorLeaseStamp, getManagedSession, recordManagedAuthLoggedFailure, withManagedAuthSessionLookup, configureManagedUserAdmission, assertManagedUserAdmission, ManagedAuthActorLeaseOutcomeUnknownError, markManagedAuthRequestActorTransitionApplied, releaseManagedAuthRequestActorLease, validateManagedAuthRequestActorLease, type ManagedAuthActorAdmissionStamp, type ManagedAuthActorMutationLeaseStamp, } from "./managed-session.js";
17
20
  export * from "./transcription.js";
18
21
  export * from "./model-catalog.js";
19
22
  export * from "./goal-admission.js";