@memberjunction/ai-agents 6.2.0-edge.3 → 6.2.0-edge.4

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 (104) hide show
  1. package/README.md +6 -0
  2. package/dist/AgentRunner.d.ts +49 -2
  3. package/dist/AgentRunner.d.ts.map +1 -1
  4. package/dist/AgentRunner.js +114 -21
  5. package/dist/AgentRunner.js.map +1 -1
  6. package/dist/ConversationCompactionManager.d.ts +2 -0
  7. package/dist/ConversationCompactionManager.d.ts.map +1 -1
  8. package/dist/ConversationCompactionManager.js +2 -2
  9. package/dist/ConversationCompactionManager.js.map +1 -1
  10. package/dist/ConversationToolManager.d.ts +13 -2
  11. package/dist/ConversationToolManager.d.ts.map +1 -1
  12. package/dist/ConversationToolManager.js +19 -3
  13. package/dist/ConversationToolManager.js.map +1 -1
  14. package/dist/KnowledgeAgent.d.ts.map +1 -1
  15. package/dist/KnowledgeAgent.js +6 -1
  16. package/dist/KnowledgeAgent.js.map +1 -1
  17. package/dist/MJAIAgentRequestEntityServer.d.ts +6 -0
  18. package/dist/MJAIAgentRequestEntityServer.d.ts.map +1 -1
  19. package/dist/MJAIAgentRequestEntityServer.js +26 -1
  20. package/dist/MJAIAgentRequestEntityServer.js.map +1 -1
  21. package/dist/agent-run-watchdog.d.ts +65 -5
  22. package/dist/agent-run-watchdog.d.ts.map +1 -1
  23. package/dist/agent-run-watchdog.js +143 -28
  24. package/dist/agent-run-watchdog.js.map +1 -1
  25. package/dist/agent-types/loop-agent-prompt-params.d.ts +7 -0
  26. package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
  27. package/dist/agent-types/loop-agent-prompt-params.js +1 -0
  28. package/dist/agent-types/loop-agent-prompt-params.js.map +1 -1
  29. package/dist/artifact-tools/SearchResultSetToolLibrary.js +4 -4
  30. package/dist/artifact-tools/SearchResultSetToolLibrary.js.map +1 -1
  31. package/dist/base-agent.d.ts +275 -18
  32. package/dist/base-agent.d.ts.map +1 -1
  33. package/dist/base-agent.js +761 -216
  34. package/dist/base-agent.js.map +1 -1
  35. package/dist/client-tool-results.d.ts +45 -0
  36. package/dist/client-tool-results.d.ts.map +1 -0
  37. package/dist/client-tool-results.js +94 -0
  38. package/dist/client-tool-results.js.map +1 -0
  39. package/dist/index.d.ts +5 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +5 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/prior-turn-tool-result-cache.d.ts +31 -12
  44. package/dist/prior-turn-tool-result-cache.d.ts.map +1 -1
  45. package/dist/prior-turn-tool-result-cache.js +59 -16
  46. package/dist/prior-turn-tool-result-cache.js.map +1 -1
  47. package/dist/realtime/bridge-realtime-session-factory.d.ts +44 -2
  48. package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -1
  49. package/dist/realtime/bridge-realtime-session-factory.js +68 -20
  50. package/dist/realtime/bridge-realtime-session-factory.js.map +1 -1
  51. package/dist/realtime/bridge-realtime-usage-recorder.d.ts +81 -0
  52. package/dist/realtime/bridge-realtime-usage-recorder.d.ts.map +1 -0
  53. package/dist/realtime/bridge-realtime-usage-recorder.js +194 -0
  54. package/dist/realtime/bridge-realtime-usage-recorder.js.map +1 -0
  55. package/dist/realtime/client-only-channel-server.d.ts +83 -0
  56. package/dist/realtime/client-only-channel-server.d.ts.map +1 -0
  57. package/dist/realtime/client-only-channel-server.js +107 -0
  58. package/dist/realtime/client-only-channel-server.js.map +1 -0
  59. package/dist/realtime/identity-verification-channel-server.d.ts +50 -0
  60. package/dist/realtime/identity-verification-channel-server.d.ts.map +1 -0
  61. package/dist/realtime/identity-verification-channel-server.js +66 -0
  62. package/dist/realtime/identity-verification-channel-server.js.map +1 -0
  63. package/dist/realtime/interactive-component-channel-server.d.ts +39 -0
  64. package/dist/realtime/interactive-component-channel-server.d.ts.map +1 -0
  65. package/dist/realtime/interactive-component-channel-server.js +55 -0
  66. package/dist/realtime/interactive-component-channel-server.js.map +1 -0
  67. package/dist/realtime/realtime-avatar-resolution.d.ts +194 -0
  68. package/dist/realtime/realtime-avatar-resolution.d.ts.map +1 -0
  69. package/dist/realtime/realtime-avatar-resolution.js +208 -0
  70. package/dist/realtime/realtime-avatar-resolution.js.map +1 -0
  71. package/dist/realtime/realtime-channel-policy.d.ts +81 -0
  72. package/dist/realtime/realtime-channel-policy.d.ts.map +1 -0
  73. package/dist/realtime/realtime-channel-policy.js +91 -0
  74. package/dist/realtime/realtime-channel-policy.js.map +1 -0
  75. package/dist/realtime/realtime-channel-server-host.d.ts +14 -0
  76. package/dist/realtime/realtime-channel-server-host.d.ts.map +1 -1
  77. package/dist/realtime/realtime-channel-server-host.js +35 -0
  78. package/dist/realtime/realtime-channel-server-host.js.map +1 -1
  79. package/dist/realtime/realtime-client-session-service.d.ts +430 -30
  80. package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
  81. package/dist/realtime/realtime-client-session-service.js +766 -111
  82. package/dist/realtime/realtime-client-session-service.js.map +1 -1
  83. package/dist/realtime/realtime-coagent-config.d.ts +94 -15
  84. package/dist/realtime/realtime-coagent-config.d.ts.map +1 -1
  85. package/dist/realtime/realtime-coagent-config.js +109 -4
  86. package/dist/realtime/realtime-coagent-config.js.map +1 -1
  87. package/dist/realtime/realtime-recording-store.d.ts +136 -16
  88. package/dist/realtime/realtime-recording-store.d.ts.map +1 -1
  89. package/dist/realtime/realtime-recording-store.js +505 -39
  90. package/dist/realtime/realtime-recording-store.js.map +1 -1
  91. package/dist/realtime/realtime-session-runner.js +4 -4
  92. package/dist/realtime/realtime-session-runner.js.map +1 -1
  93. package/dist/realtime/realtime-vendor-resolution.d.ts +9 -0
  94. package/dist/realtime/realtime-vendor-resolution.d.ts.map +1 -1
  95. package/dist/realtime/realtime-vendor-resolution.js +16 -5
  96. package/dist/realtime/realtime-vendor-resolution.js.map +1 -1
  97. package/dist/realtime/realtime-video-output-gate.d.ts +83 -0
  98. package/dist/realtime/realtime-video-output-gate.d.ts.map +1 -0
  99. package/dist/realtime/realtime-video-output-gate.js +79 -0
  100. package/dist/realtime/realtime-video-output-gate.js.map +1 -0
  101. package/dist/tool-result-format.d.ts +14 -0
  102. package/dist/tool-result-format.d.ts.map +1 -1
  103. package/dist/tool-result-format.js.map +1 -1
  104. package/package.json +19 -19
@@ -32,11 +32,36 @@
32
32
  import { UserInfo, IMetadataProvider } from '@memberjunction/core';
33
33
  import { MJLruCache } from '@memberjunction/global';
34
34
  import { MJActionEntityExtended } from '@memberjunction/actions-base';
35
- import { BaseRealtimeModel, ChatMessage, ClientRealtimeSessionConfig, AIAPIKey, AIAPIKeyResolver, AICredentialScope, IRealtimeSession, JSONObject, RealtimeSessionParams, RealtimeToolCall, RealtimeToolDefinition } from '@memberjunction/ai';
36
- import { MJAIAgentEntityExtended, MJAIModelEntityExtended, MJAIAgentRunEntityExtended, AgentExecutionProgressCallback, ExecuteAgentResult, AppContextSnapshot } from '@memberjunction/ai-core-plus';
35
+ import { BaseRealtimeModel, ChatMessage, ClientRealtimeSessionConfig, AIAPIKey, AIAPIKeyResolver, AICredentialScope, IRealtimeSession, JSONObject, RealtimeAvatarStatus, RealtimeSessionParams, RealtimeToolCall, RealtimeToolDefinition } from '@memberjunction/ai';
36
+ import { MJAIAgentEntityExtended, MJAIModelEntityExtended, MJAIAgentRunEntityExtended, AgentExecutionProgressCallback, ExecuteAgentResult, AppContextSnapshot, type IAgentSettings, type RealtimeChannelCandidate, type RealtimeSessionClientPolicy, type RealtimeSessionClientTools } from '@memberjunction/ai-core-plus';
37
+ import { type RealtimeAvatarResolution } from './realtime-avatar-resolution.js';
37
38
  import { RealtimeToolBroker, RealtimeColleague, DelegateToTargetRequest, DelegatedResult, DelegatedRunArtifact, ToolExecutionResult } from './realtime-tool-broker.js';
38
39
  import { RealtimeAllowedAgent, RealtimeCoAgentConfig, RealtimeDirectActionsConfig } from './realtime-coagent-config.js';
39
40
  import { RealtimeVendorSelection } from './realtime-vendor-resolution.js';
41
+ import { type RealtimeUsageRecord } from '@memberjunction/ai-engine-base';
42
+ import { type RealtimeChannelRegistryRow } from './realtime-channel-policy.js';
43
+ /**
44
+ * How long closing a bridged (server-held) session waits for its model session to close before the session's runs are
45
+ * finalized anyway, in milliseconds. A model session reports its last usage while it closes (a Gemini avatar session,
46
+ * the seconds of video it has not reported yet), and the runs are priced from what was stored when they are finalized.
47
+ */
48
+ export declare const BRIDGE_SESSION_CLOSE_WAIT_MS = 5000;
49
+ /**
50
+ * Context passed to {@link PrepareClientSessionInput.ResolveHostTools} describing the
51
+ * model, vendor, and driver resolved for the realtime session.
52
+ */
53
+ export interface RealtimeHostToolsResolutionContext {
54
+ /** The resolved model entity ID. */
55
+ ModelID?: string;
56
+ /** The resolved model vendor ID, if known. */
57
+ ModelVendorID?: string;
58
+ /** The resolved realtime driver class name (e.g. 'OpenAILiveRealtime'). */
59
+ DriverClass?: string;
60
+ }
61
+ /**
62
+ * Resolver callback signature for dynamically resolving host tools prior to session start.
63
+ */
64
+ export type RealtimeHostToolsResolver = (resolved: RealtimeHostToolsResolutionContext) => RealtimeToolDefinition[] | undefined;
40
65
  /**
41
66
  * Input for {@link RealtimeClientSessionService.PrepareClientSession}.
42
67
  *
@@ -80,6 +105,15 @@ export interface PrepareClientSessionInput {
80
105
  * app layer (the cascade rests on type/co-agent/target/override only).
81
106
  */
82
107
  ApplicationID?: string;
108
+ /**
109
+ * The interactive channels the BROWSER reports it could mount in this session (key, code defaults,
110
+ * native tools, host-declared?). When present the service scopes them — registry kill switch, agent
111
+ * and app configuration (`realtime.channels`) — narrows/completes {@link ExtraTools} to match, and
112
+ * returns the resolved {@link RealtimeClientSessionPrepResult.ClientPolicy} for the browser to
113
+ * activate. Absent ⇒ no scoping (a client that predates channel scoping, or a host that mints
114
+ * through its own proxy): {@link ExtraTools} is used exactly as declared.
115
+ */
116
+ ChannelCandidates?: RealtimeChannelCandidate[];
83
117
  /**
84
118
  * Optional app-context snapshot — where the user is, what they see, and the live capability
85
119
  * manifest — injected into the companion system prompt at mint (the session-start half of the
@@ -96,6 +130,11 @@ export interface PrepareClientSessionInput {
96
130
  * local tool handler ({@link BridgeRealtimeRuntime.SetLocalToolHandler}).
97
131
  */
98
132
  HostTools?: RealtimeToolDefinition[];
133
+ /**
134
+ * Optional callback that allows the host to resolve host tools dynamically based on
135
+ * the model, vendor, and driver actually resolved for the session, before session opening.
136
+ */
137
+ ResolveHostTools?: RealtimeHostToolsResolver;
99
138
  /**
100
139
  * Host-authored instructions appended to the system prompt (e.g. "this is an audio-only phone call …",
101
140
  * the caller's number and verification status). Empty/absent adds nothing.
@@ -151,6 +190,34 @@ export interface PrepareClientSessionInput {
151
190
  * addressing GATE is the bridge's `RegexAddressedMatcher`. Ignored unless {@link DisableAutoResponse}.
152
191
  */
153
192
  SelfNames?: string[];
193
+ /**
194
+ * `'room'` for a server-side (bridged) session whose host publishes the agent's avatar into a meeting room: the
195
+ * avatar request resolved for the voiced agent carries it (`RealtimeAvatarSettings.Delivery`), so a driver may
196
+ * render it there. Absent: a server-side session asks for no video (the driver logs `bridged`), and its avatar
197
+ * status says `bridged` also when the prep asked the driver for none, or the driver reported nothing. Ignored on a
198
+ * {@link PhoneCall}.
199
+ */
200
+ AvatarDelivery?: 'room';
201
+ /**
202
+ * `true` for a server-side session (a bridged meeting or a phone call), which can show the agent's avatar only when its
203
+ * host publishes it into a room ({@link AvatarDelivery} `'room'`). Without that, the default model walk's video
204
+ * preference skips the session: no model would bring it an avatar. Absent: a browser (client-direct) session.
205
+ */
206
+ ServerSide?: boolean;
207
+ /**
208
+ * `true` when the session is a phone call: a carrier call (Twilio, Vonage, RingCentral), or a call that reaches a
209
+ * LiveKit room through SIP. The caller hears the agent and sees nothing, so the session asks the driver for no avatar,
210
+ * even in a room that could show one, and reports why (`phone`); the avatar persona's voice is kept, and the default
211
+ * model walk prefers no avatar model. Absent: not a phone call.
212
+ */
213
+ PhoneCall?: boolean;
214
+ /**
215
+ * `false` when the app showing a browser session shows no agent video: none of its channels shows it (the embeddable
216
+ * widgets and the mobile app today; the mint's `showsAgentVideo` argument). The session then asks the driver for no
217
+ * avatar and reports why (`host`), the avatar persona's voice is kept, and the default model walk prefers no avatar
218
+ * model. Absent or `true`: the app may show it, and the browser decides at connect (`host` or `browser` then).
219
+ */
220
+ ShowsAgentVideo?: boolean;
154
221
  /**
155
222
  * Optional server-authoritative hard ceiling on the session's wall-clock duration, in seconds.
156
223
  * Threaded into {@link RealtimeSessionParams.MaxSessionSeconds} so a driver can bound the
@@ -159,6 +226,11 @@ export interface PrepareClientSessionInput {
159
226
  * deployments (a public web-widget guest's `VoiceMaxSessionMinutes`); omitted otherwise.
160
227
  */
161
228
  MaxSessionSeconds?: number;
229
+ /**
230
+ * When `true`, no direct actions are projected for the session, so the model gets none and the
231
+ * session's relays run none. Set for callers that may not run actions directly.
232
+ */
233
+ ExcludeDirectActions?: boolean;
162
234
  }
163
235
  /**
164
236
  * Result of {@link RealtimeClientSessionService.PrepareClientSession}.
@@ -233,6 +305,12 @@ export interface RealtimeClientSessionPrepResult {
233
305
  * (client drivers apply provider voice settings client-side in the client-direct topology).
234
306
  */
235
307
  EffectiveConfig?: RealtimeCoAgentConfig;
308
+ /**
309
+ * The resolved channel scope and client-tool tiers for the browser to activate — present only when
310
+ * the input carried {@link PrepareClientSessionInput.ChannelCandidates}. The transport layer returns
311
+ * it in the mint result and persists the in-session channel keys on the session.
312
+ */
313
+ ClientPolicy?: RealtimeSessionClientPolicy;
236
314
  /**
237
315
  * The effective narration pace (`realtime.narration.paceMs`) — minimum gap in ms between
238
316
  * spoken progress updates. `undefined` when not configured (clients/runners use their
@@ -241,6 +319,12 @@ export interface RealtimeClientSessionPrepResult {
241
319
  * `RealtimeSessionRunnerDeps.NarrationPaceMs`.
242
320
  */
243
321
  NarrationPaceMs?: number;
322
+ /**
323
+ * The live avatar the session asked for and whether it shows: granted, or audio only and why
324
+ * ({@link ResolveRealtimeAvatarStatus}). Absent when the voiced agent asked for no avatar (its video setting is
325
+ * off). The transport layer returns it in the mint result, so the call can say why it shows no avatar.
326
+ */
327
+ AvatarStatus?: RealtimeAvatarStatus;
244
328
  }
245
329
  /**
246
330
  * The resolved co-agent system prompt text plus the id of the prompt it came from, returned by
@@ -261,9 +345,15 @@ export interface CoAgentSystemPromptResolution {
261
345
  export interface ExecuteRelayedToolInput {
262
346
  /** The shared session id grouping this voice session's runs. */
263
347
  AgentSessionID: string;
264
- /** The id of the (co-agent) run that owns this session, used as the delegated run's parent. Optional. */
348
+ /**
349
+ * The id of the (co-agent) run that owns this session, used as the delegated run's parent. Optional.
350
+ * The caller passes it only when it is a run of this session.
351
+ */
265
352
  ParentRunID?: string;
266
- /** The top-level (lead) target agent id for `invoke-target-agent` delegation. */
353
+ /**
354
+ * The top-level (lead) target agent id for `invoke-target-agent` delegation. The caller must have
355
+ * checked that the acting user may run this agent.
356
+ */
267
357
  TargetAgentID: string;
268
358
  /**
269
359
  * The session's effective allowed delegation targets (the union-accumulated set from the config
@@ -275,7 +365,8 @@ export interface ExecuteRelayedToolInput {
275
365
  /**
276
366
  * Optional direct actions configuration for this session, derived once during session prep
277
367
  * (cascade: co-agent + runtime overrides + target + app settings). When present, direct action
278
- * enforcement checks this configuration instead of recomputing from target alone.
368
+ * enforcement checks this configuration instead of recomputing from target alone. Pass it only
369
+ * from server-side state, never from a client-writable source such as a session's `Config`.
279
370
  */
280
371
  DirectActions?: RealtimeDirectActionsConfig;
281
372
  /** The tool call the browser relayed from the provider. */
@@ -296,9 +387,20 @@ export interface ExecuteRelayedToolInput {
296
387
  * Optional id of a previously-paused delegated run (Status `AwaitingFeedback`) to RESUME instead
297
388
  * of starting a fresh run. When set, {@link delegateToTarget} passes it as `lastRunId` (with
298
389
  * `autoPopulateLastRunPayload`) to {@link AgentRunner.RunAgent}, so the user's answer continues
299
- * the SAME interactive run (e.g. confirming a Query Builder task graph).
390
+ * the SAME interactive run (e.g. confirming a Query Builder task graph). The caller passes it only
391
+ * when it is a run of this session.
300
392
  */
301
393
  ResumeRunID?: string;
394
+ /**
395
+ * The browser's GraphQL session id. Lets the delegated run execute client tools the surface
396
+ * registered, because the client-tool request channel is keyed on this id.
397
+ */
398
+ BrowserSessionID?: string;
399
+ /**
400
+ * The app-context snapshot the browser sent at session start, so the delegated run's prompt sees
401
+ * surface context and tools. It does not follow later navigation in the browser.
402
+ */
403
+ AppContext?: AppContextSnapshot;
302
404
  /**
303
405
  * The id of the human this delegation is FOR, threaded into the delegated run's `userId`.
304
406
  *
@@ -354,22 +456,42 @@ export interface RealtimeSessionParamsPrep {
354
456
  EffectiveConfig?: RealtimeCoAgentConfig;
355
457
  /** The assembled session params (TARGET-identity prompt, stable tools incl. invoke-target, voice, memory). */
356
458
  SessionParams?: RealtimeSessionParams;
459
+ /** The resolved channel scope + client-tool tiers, when the input carried channel candidates. */
460
+ ClientPolicy?: RealtimeSessionClientPolicy;
461
+ /**
462
+ * The avatar the session asks for, or why there is none; empty when the voiced agent asked for none. The session
463
+ * params carry the request itself (`SessionParams.Avatar`); this keeps the reason for the call's avatar status.
464
+ */
465
+ AvatarResolution?: RealtimeAvatarResolution;
357
466
  }
358
467
  /**
359
468
  * The runtime handle returned by {@link RealtimeClientSessionService.WireBridgeRealtimeSession} — the
360
469
  * server long-lived (bridged) counterpart to what `PrepareClientSession` returns for the browser. The
361
470
  * bridge holds this for the life of the session: the observability run ids (for nesting + correlation)
362
- * and an **idempotent** {@link Finalize} the bridge MUST call on teardown so the co-agent run + prompt
363
- * run don't dangle in `Running`. Finalize also runs automatically when the session's `Close()` is invoked
364
- * or the connection drops — calling it again is a safe no-op.
471
+ * and an **idempotent** {@link Finalize} that keeps the co-agent run + prompt run from dangling in
472
+ * `Running`. It runs when the session's `Close()` is invoked, once the model session has closed, and when
473
+ * the connection drops; whichever comes first runs it, and a later call waits for that run.
365
474
  */
366
475
  export interface BridgeRealtimeRuntime {
367
476
  /** The `MJ: AI Agent Runs` row id created for this voice session (delegated runs nest under it). */
368
477
  CoAgentRunID?: string;
369
478
  /** The `MJ: AI Prompt Runs` row id for the session's system prompt. */
370
479
  PromptRunID?: string;
371
- /** Finalizes the co-agent + prompt run. Idempotent; safe to call from multiple teardown paths. */
372
- Finalize: (success: boolean) => Promise<void>;
480
+ /**
481
+ * Writes the session's last usage, then finalizes the co-agent + prompt run; usage reported afterwards is not
482
+ * stored. Closing the session runs it after the model session closed, so what the session reports while closing
483
+ * is kept; calling it before `Close()` would drop that report. Idempotent, so every teardown path may call it: it
484
+ * runs once, and every call returns the first call's promise and resolves only once the runs are finalized. The
485
+ * first call decides the outcome: its `success` and `errorMessage` stand.
486
+ *
487
+ * The session's `Close()` finalizes with `success` true, so a host whose bridge start failed calls
488
+ * `Finalize(false, error)` BEFORE it closes the session: the run, its prompt run and its step then read `Failed`
489
+ * with the start's error, and the close finalizes nothing more.
490
+ *
491
+ * @param success `true` → `Completed`, `false` → `Failed`.
492
+ * @param errorMessage Why the session failed, stamped on the failed run, prompt run and step. Ignored on success.
493
+ */
494
+ Finalize: (success: boolean, errorMessage?: string) => Promise<void>;
373
495
  /**
374
496
  * Aborts every delegated run currently in flight for this session (and drops pending narration). This is the
375
497
  * EXPLICIT cancel — on a phone it backs the `cancel_pending_work` tool — and is deliberately NOT what a
@@ -388,6 +510,12 @@ export interface BridgeRealtimeRuntime {
388
510
  * {@link BridgeLocalToolHandler.Handles} is executed by the host instead of the shared delegation path.
389
511
  */
390
512
  SetLocalToolHandler: (handler: BridgeLocalToolHandler | undefined) => void;
513
+ /**
514
+ * Whether the agent watches LiveKit meetings (`realtime.video.watchMeetings` in its effective configuration, which
515
+ * includes the voiced agent's own). The room coordinator reads it, with whether the session takes video, to decide
516
+ * whether the bot reads the cameras and screens people allow.
517
+ */
518
+ WatchesMeetingVideo: boolean;
391
519
  }
392
520
  /**
393
521
  * Executes tools the host declared through {@link PrepareClientSessionInput.HostTools}. Bound after the session
@@ -560,6 +688,11 @@ export declare class RealtimeClientSessionService {
560
688
  * @returns The prep result (Success + ClientConfig/SessionParams, or Success: false + ErrorMessage).
561
689
  */
562
690
  PrepareClientSession(input: PrepareClientSessionInput, contextUser: UserInfo, provider: IMetadataProvider): Promise<RealtimeClientSessionPrepResult>;
691
+ /**
692
+ * The call's avatar status once the driver has minted the session (see {@link ResolveRealtimeAvatarStatus}), with one
693
+ * log line saying whether the avatar shows. `undefined`, and no line, when the session asked for no avatar.
694
+ */
695
+ private resolveMintedAvatarStatus;
563
696
  /**
564
697
  * Wires a **server long-lived (bridged)** realtime session onto the SAME core machinery the
565
698
  * client-direct path uses — so a LiveKit (or future Zoom/Teams) agent does real work and is tracked
@@ -570,12 +703,22 @@ export declare class RealtimeClientSessionService {
570
703
  * under the co-agent run, supports barge-in cancel + paused-run resume — all of it, for free).
571
704
  *
572
705
  * Responsibilities, in order:
706
+ * 0. Report the avatar status the driver had nothing to say about: a prep that asked the driver for no avatar (a
707
+ * phone call, no face for the model's vendor, an unknown avatar, a Video/Output row that turns video off) leaves
708
+ * the driver nothing to report, and a driver that renders no avatar ignores a request, so the session's
709
+ * `AvatarStatus` says why instead of saying nothing ({@link ResolveBridgedAvatarStatus}).
573
710
  * 1. Create the co-agent observability run (+ prompt run + step) so the voice session shows up in the
574
711
  * agent-run timeline and delegated runs nest under it (best-effort; a failure just omits the ids).
575
- * 2. Wire `session.OnToolCall` → `ExecuteRelayedTool` → `session.SendToolResult`.
576
- * 3. Guarantee finalize-once: wrap `session.Close()` and listen for an unexpected drop (`OnClose`), both
712
+ * 2. Record the session's usage on the co-agent prompt run, as client-direct calls do: `session.OnUsage` →
713
+ * {@link BridgeRealtimeUsageRecorder} → {@link AccumulatePromptRunUsage}, every 10 s and once more at finalize.
714
+ * 3. Wire `session.OnToolCall` → `ExecuteRelayedTool` → `session.SendToolResult`.
715
+ * 4. Guarantee finalize-once: wrap `session.Close()` and listen for an unexpected drop (`OnClose`), both
577
716
  * routed through one idempotent finalizer. The bridge teardown calls `Close()`, so the run finalizes
578
- * on graceful end; a dropped socket finalizes via `OnClose`.
717
+ * on graceful end; a dropped socket finalizes via `OnClose`, and a `Close()` after it waits for that
718
+ * finalize. The wrapped `Close()` closes the model session first (waiting up to
719
+ * {@link BRIDGE_SESSION_CLOSE_WAIT_MS}), so the usage it reports while closing is recorded; the
720
+ * finalizer then writes the session's last usage before it finalizes the runs, so the prompt run is
721
+ * priced from its final counts.
579
722
  *
580
723
  * @param session The live realtime session the bridge owns (from `model.StartSession`).
581
724
  * @param input The same prep input used to build the session (carries AgentSessionID, TargetAgentID, …).
@@ -585,6 +728,47 @@ export declare class RealtimeClientSessionService {
585
728
  * @returns A {@link BridgeRealtimeRuntime} the bridge holds for the session lifetime.
586
729
  */
587
730
  WireBridgeRealtimeSession(session: IRealtimeSession, input: PrepareClientSessionInput, prep: RealtimeSessionParamsPrep, contextUser: UserInfo, provider: IMetadataProvider): Promise<BridgeRealtimeRuntime>;
731
+ /**
732
+ * Gives a bridged session the avatar status its driver had nothing to say about ({@link ResolveBridgedAvatarStatus}),
733
+ * with one log line: a prep that asked the driver for no avatar (a phone call, no face for the model's vendor, an
734
+ * unknown avatar, a Video/Output row that turns video off) leaves the driver nothing to report, and a driver that
735
+ * renders no avatar ignores a request and reports nothing. A host reads it like any driver's status (the LiveKit room
736
+ * puts it on the agent's bot, so the room shows its notice). A status the driver reported stands.
737
+ */
738
+ private reportBridgedAvatarStatus;
739
+ /**
740
+ * Records a bridged session's usage on its co-agent prompt run. The recorder is the session's only `OnUsage`
741
+ * subscriber: drivers keep one usage handler. Without a prompt run there is nowhere to record, so nothing subscribes
742
+ * and one line is logged, as the client-direct relay logs a dropped delta.
743
+ */
744
+ private wireBridgeUsage;
745
+ /**
746
+ * The bridged session's finalizer. It closes the usage recorder first (no more updates; the unwritten usage is
747
+ * written), so the prompt run's cost, computed when finalize stamps `CompletedAt`, covers the whole session. On a
748
+ * graceful close it runs after the model session closed (see `finalizeOnBridgeClose`).
749
+ *
750
+ * It runs once, and every call returns the first call's promise: whichever path calls second (a `Close()` after a
751
+ * dropped connection's `OnClose` started the finalize) resolves only once the runs are finalized and priced. The
752
+ * first call decides the outcome (see {@link BridgeRealtimeRuntime.Finalize}).
753
+ */
754
+ private createBridgeFinalizer;
755
+ /** Tool calls → the host's local handler or the shared delegation entry point, then the result back to the model. */
756
+ private wireBridgeToolCalls;
757
+ /**
758
+ * Finalizes on graceful teardown (the bridge calls `Close()`) and on an unexpected drop. Both go through the one
759
+ * finalizer, which runs once: a double fire finalizes once, and a `Close()` after a drop waits for the finalize the
760
+ * drop started, so it resolves only once the runs are finalized. Both finalize as completed: a host whose bridge
761
+ * start failed calls {@link BridgeRealtimeRuntime.Finalize} with `false` and the start's error before it closes the
762
+ * session.
763
+ *
764
+ * `Close()` closes the model session before it finalizes: a session reports its last usage while it closes (a
765
+ * Gemini avatar session, the seconds of video not reported yet), and the finalizer stores only what was reported
766
+ * before it ran. The close is waited for up to {@link BRIDGE_SESSION_CLOSE_WAIT_MS}. The runs are finalized whether
767
+ * the close finished, failed or is still running; a failed close still rejects, after the finalize.
768
+ *
769
+ * @param promptRunID The session's co-agent prompt run, which names the session in a log line.
770
+ */
771
+ private finalizeOnBridgeClose;
588
772
  /**
589
773
  * Degenerate {@link BridgeRealtimeRuntime} for the rare case wiring is attempted without a resolved
590
774
  * co-agent: answer every tool call with a clear "not available" error and a no-op finalize. Keeps the
@@ -612,6 +796,57 @@ export declare class RealtimeClientSessionService {
612
796
  * @returns The prep result: `Success` + co-agent/resolution/effective-config/session-params, or `Success: false`.
613
797
  */
614
798
  PrepareRealtimeSessionParams(input: PrepareClientSessionInput, contextUser: UserInfo, provider: IMetadataProvider): Promise<RealtimeSessionParamsPrep>;
799
+ /**
800
+ * Applies channel scoping and the client-tool tiers to a prepare input.
801
+ *
802
+ * - **App tier into the prompt.** `Application.AgentSettings.ClientTools` is resolved to metadata
803
+ * and layered, through the unified {@link ResolveClientTools}, beneath the live surface's own
804
+ * manifest in the app-context snapshot — so the co-agent is told about tools the app declares
805
+ * even when the active surface did not republish them. (Only the HOST can run them; the browser
806
+ * reports "declared but not registered" for one it has no handler for.) The agent's static
807
+ * junction tools are deliberately NOT added to the voice prompt — voice prompts are
808
+ * token-sensitive and a tool with no browser handler is noise — but they ride the returned policy
809
+ * so the browser can describe them.
810
+ * - **Channel scoping.** When the browser reported candidates, they are scoped against the
811
+ * registry and the cascade's `channels` section, and the declared tools narrowed to match
812
+ * ({@link BuildSessionChannelPolicy}).
813
+ *
814
+ * @returns The (possibly adjusted) input, and the policy to hand back when candidates were reported.
815
+ */
816
+ protected scopeSessionInput(input: PrepareClientSessionInput, effectiveConfig: RealtimeCoAgentConfig, contextUser: UserInfo, provider: IMetadataProvider, modelHasZeroDataRetention?: boolean): Promise<{
817
+ Input: PrepareClientSessionInput;
818
+ ClientPolicy?: RealtimeSessionClientPolicy;
819
+ }>;
820
+ /**
821
+ * Whether the session model's effective catalog configuration (type < model < vendor < model-vendor)
822
+ * declares `Privacy.ZeroDataRetention: true`. Fails closed: a model or vendor row that cannot be
823
+ * resolved, or a catalog lookup that throws, reads as "not declared", so an agent that REQUIRES zero
824
+ * data retention loses exposure rather than gaining it. Overridable seam.
825
+ *
826
+ * @param modelID The resolved `MJ: AI Models` id.
827
+ * @param modelVendorID The resolved model-vendor row id (the cascade's most specific layer).
828
+ */
829
+ protected modelHasZeroDataRetention(modelID: string | undefined, modelVendorID: string | undefined): boolean;
830
+ /**
831
+ * Layers the app's client tools beneath the surface's manifest in the app-context snapshot, through
832
+ * the unified resolver (`session > app`, first match by name wins). Returns the SAME snapshot object
833
+ * when nothing changes, so callers can detect "no change" by identity.
834
+ */
835
+ private withAppToolTier;
836
+ /**
837
+ * The server's view of the channel registry (`MJ: AI Agent Channels`), read from the request
838
+ * provider's cached {@link AIEngineBase} rows (already configured by the prepare). Overridable seam.
839
+ * Tolerant: an unloaded cache yields an empty registry (every candidate then reads as having no
840
+ * row), never a throw.
841
+ */
842
+ protected readChannelRegistry(provider: IMetadataProvider): RealtimeChannelRegistryRow[];
843
+ /**
844
+ * Resolves the client-tool tiers the browser is told about at mint: the APP tier
845
+ * (`Application.AgentSettings.ClientTools` resolved against the tool-definition catalog) and the
846
+ * STATIC tier (the target agent's `MJ: AI Agent Client Tools` junction). Overridable seam; tolerant —
847
+ * any failure yields empty tiers and never fails the mint.
848
+ */
849
+ protected resolveSessionClientToolTiers(applicationId: string | undefined, targetAgentId: string, contextUser: UserInfo): Promise<RealtimeSessionClientTools>;
615
850
  /**
616
851
  * Resolves the EFFECTIVE realtime configuration via the surface-agnostic precedence cascade:
617
852
  * agent-TYPE `DefaultConfiguration` (base) < **co-agent** `TypeConfiguration` < **target agent**
@@ -627,6 +862,16 @@ export declare class RealtimeClientSessionService {
627
862
  * @returns The normalized effective configuration (possibly empty, never `null`).
628
863
  */
629
864
  protected resolveEffectiveConfig(coAgent: MJAIAgentEntityExtended, overridesJson?: string, targetAgent?: MJAIAgentEntityExtended | null, appSettingsJson?: string | null): RealtimeCoAgentConfig;
865
+ /**
866
+ * Logs one line, once per co-agent and target pair per process, when the effective configuration sets
867
+ * `realtime.video.provider` or `realtime.video.providers`. Both are deprecated and nothing reads them, so an author
868
+ * who set them would otherwise get nothing and no word of it.
869
+ *
870
+ * @param config The effective configuration.
871
+ * @param coAgent The co-agent.
872
+ * @param targetAgent The voiced agent, when there is one.
873
+ */
874
+ private logDeprecatedVideoKeys;
630
875
  /**
631
876
  * Resolves the APP cascade layer JSON from `Application.AgentSettings`: the `Realtime` overrides
632
877
  * (persona/disclosure/model) plus `RelevantAgents` mapped to the union-accumulated allowed-agent
@@ -641,6 +886,14 @@ export declare class RealtimeClientSessionService {
641
886
  * @returns The canonical app-layer JSON string, or `null`.
642
887
  */
643
888
  protected resolveAppRealtimeOverrides(applicationId: string | undefined, contextUser: UserInfo, provider: IMetadataProvider): Promise<string | null>;
889
+ /**
890
+ * Reads and parses an application's `AgentSettings` (one tiny by-ID read, served from the provider's
891
+ * RunView cache on repeat). The RAW column is parsed with {@link ParseAgentSettings} rather than read
892
+ * through the CodeGen-generated `AgentSettingsObject` accessor, so a field added to the settings
893
+ * interface works the moment the code reading it ships, before CodeGen next refreshes the copy.
894
+ * Tolerant — a blank id, a failed read, a missing app, or an app with no usable settings returns `null`.
895
+ */
896
+ protected loadAppAgentSettings(applicationId: string | undefined, contextUser: UserInfo): Promise<IAgentSettings | null>;
644
897
  /**
645
898
  * Reads the co-agent's TYPE-level `DefaultConfiguration` from {@link AIEngine}'s cached agent
646
899
  * types. **Overridable seam**; tolerant — an absent type or unloaded cache returns `null`.
@@ -676,6 +929,20 @@ export declare class RealtimeClientSessionService {
676
929
  * `CompleteMessage`) when the save fails.
677
930
  */
678
931
  private createCoAgentRun;
932
+ /**
933
+ * Keeps a voice session's co-agent run alive as far as the {@link AgentRunWatchdog} is concerned. The
934
+ * run spans the whole call, but no agent loop owns it, so nothing stamped its heartbeat: the watchdog
935
+ * force-failed every call that ran past ~5 minutes ("no liveness heartbeat … owning process presumed
936
+ * dead") while the call carried on. Called when the run is created and again on each persisted
937
+ * session heartbeat (`SessionManager`), so whichever server instance the session is talking to keeps
938
+ * it fresh; the watchdog drops it once it is finalized. Only a database provider can stamp heartbeats —
939
+ * any other provider is a no-op, as for every agent run.
940
+ *
941
+ * @param coAgentRunID The session's co-agent run id (from its `Config`), or nothing.
942
+ * @param provider The request-scoped metadata provider.
943
+ * @param contextUser The user the heartbeat writes run as.
944
+ */
945
+ KeepCoAgentRunAlive(coAgentRunID: string | null | undefined, provider: IMetadataProvider, contextUser: UserInfo): void;
679
946
  /**
680
947
  * Creates the co-agent `AIPromptRun` row (Status `Running`) linked to the co-agent run via
681
948
  * `AgentRunID` AND to the co-agent itself via `AgentID` — so the run shows up both on the
@@ -705,8 +972,22 @@ export declare class RealtimeClientSessionService {
705
972
  * @param provider The request-scoped metadata provider.
706
973
  * @param success Whether the session ended successfully (controls Completed vs Failed).
707
974
  * @param coAgentRunStepID The co-agent run's single `MJ: AI Agent Run Steps` row id, or `null` to skip.
975
+ * @param errorMessage Why the session failed (for example the bridge start's error), stamped as `ErrorMessage` on each
976
+ * record it fails. Ignored when `success` is true. Without it the step gets a generic line and the runs none.
977
+ */
978
+ FinalizeCoAgentRun(coAgentRunID: string | null, promptRunID: string | null, contextUser: UserInfo, provider: IMetadataProvider, success?: boolean, coAgentRunStepID?: string | null, errorMessage?: string): Promise<void>;
979
+ /**
980
+ * Copies the co-agent prompt run's tokens and cost onto the co-agent run. The realtime model's usage
981
+ * accumulates on the prompt run ({@link AccumulatePromptRunUsage}), which prices itself; the run's
982
+ * own `TotalCost` / `Total*TokensUsed` stayed 0, so everything that sums agent runs — the realtime
983
+ * analytics dashboard's per-session cost among them — left out the voice model entirely and showed
984
+ * only the delegated runs. Mirrors how an agent loop derives its run totals from its prompt runs.
985
+ *
986
+ * Applied whatever the run's status: a run the watchdog already failed, or one a shutdown cancelled,
987
+ * still owes its cost. Runs after {@link finalizePromptRun}, which waits for in-flight usage writes,
988
+ * so the copy sees the final counts. Tolerant: logs, never throws.
708
989
  */
709
- FinalizeCoAgentRun(coAgentRunID: string | null, promptRunID: string | null, contextUser: UserInfo, provider: IMetadataProvider, success?: boolean, coAgentRunStepID?: string | null): Promise<void>;
990
+ private rollUpCoAgentRunUsage;
710
991
  /**
711
992
  * Finalizes the **co-agent observability run(s)** for an agent session that were left `Running` because
712
993
  * the session was reaped WITHOUT a live in-memory handle — a prior-boot orphan or a cross-host teardown,
@@ -735,15 +1016,22 @@ export declare class RealtimeClientSessionService {
735
1016
  * run — which is the replacement path that migration's design notes prescribe.
736
1017
  */
737
1018
  private findCoAgentChildLogIds;
738
- /** Loads + finalizes the co-agent `AIAgentRun` if still `Running`. Tolerant: logs, never throws. */
1019
+ /**
1020
+ * Loads + finalizes the co-agent `AIAgentRun` if still `Running`, with `failure` as its `ErrorMessage` when it fails.
1021
+ * Tolerant: logs, never throws.
1022
+ */
739
1023
  private finalizeAgentRun;
740
1024
  /**
741
1025
  * Loads + finalizes the co-agent run's single system-prompt `MJ: AI Agent Run Steps` row if
742
- * still `Running` (Status `Completed`/`Failed`, `CompletedAt`, `Success`). Tolerant: a
743
- * missing/already-finalized step is a no-op; a load/save failure is logged, never thrown.
1026
+ * still `Running` (Status `Completed`/`Failed`, `CompletedAt`, `Success`; a failed step's `ErrorMessage` is
1027
+ * `failure`, or a generic line without one). Tolerant: a missing/already-finalized step is a no-op; a
1028
+ * load/save failure is logged, never thrown.
744
1029
  */
745
1030
  private finalizeRunStep;
746
- /** Loads + finalizes the co-agent `AIPromptRun` if still `Running`. Tolerant: logs, never throws. */
1031
+ /**
1032
+ * Loads + finalizes the co-agent `AIPromptRun` if still `Running`, with `failure` as its `ErrorMessage` when it fails.
1033
+ * Tolerant: logs, never throws.
1034
+ */
747
1035
  private finalizePromptRun;
748
1036
  /**
749
1037
  * Appends (or replaces) one transcript turn onto the co-agent's long-lived `AIPromptRun.Messages`,
@@ -770,12 +1058,27 @@ export declare class RealtimeClientSessionService {
770
1058
  * high-frequency usage checkpoint never overwrites freshly-appended transcript turns (and vice-versa).
771
1059
  * Best-effort: load/save failures log and return `false`, never throw.
772
1060
  *
1061
+ * The per-modality details add into the usage record the run keeps in `ModelSpecificResponseDetails`
1062
+ * (`RealtimeUsage.Input` / `.Output`, which pricing reads at finalize); every other key there is kept. The
1063
+ * stored output video seconds never exceed the run's elapsed time plus 30 seconds, and the stored output video
1064
+ * tokens never exceed 6,192 a second of that: usage is client-reported, and avatar video carries a price, per
1065
+ * minute or per token.
1066
+ *
773
1067
  * @param promptRunID The co-agent observability prompt run.
774
1068
  * @param inputDelta Input-token delta to add (caller clamps to >= 0).
775
1069
  * @param outputDelta Output-token delta to add (caller clamps to >= 0).
1070
+ * @param details Per-modality usage to add (input and output blocks, avatar video seconds included).
776
1071
  * @returns `true` when the accumulated usage was persisted.
777
1072
  */
778
- AccumulatePromptRunUsage(promptRunID: string, inputDelta: number, outputDelta: number, contextUser: UserInfo, provider: IMetadataProvider): Promise<boolean>;
1073
+ AccumulatePromptRunUsage(promptRunID: string, inputDelta: number, outputDelta: number, contextUser: UserInfo, provider: IMetadataProvider, details?: RealtimeUsageRecord): Promise<boolean>;
1074
+ /**
1075
+ * Adds relayed per-modality usage into the run's usage record, with the output video seconds capped at the run's
1076
+ * elapsed time plus {@link VIDEO_SECONDS_GRACE}, and the output video tokens at that many seconds of
1077
+ * {@link VIDEO_TOKENS_PER_SECOND}. Details that are not a JSON object are left alone (logged).
1078
+ */
1079
+ private mergeUsageDetails;
1080
+ /** One log line for each output video quantity the merge capped. */
1081
+ private logClampedVideo;
779
1082
  /** Parses the prompt run's `Messages` JSON into a mutable chat-message array (tolerant: `[]` on empty/malformed). */
780
1083
  private parsePromptRunMessages;
781
1084
  /**
@@ -850,15 +1153,41 @@ export declare class RealtimeClientSessionService {
850
1153
  * {@link resolveConfiguredModelPreference}. METADATA preferences degrade gracefully — an
851
1154
  * unsatisfiable preference logs and FALLS THROUGH to the default (mirroring the co-agent
852
1155
  * resolution chain's tolerant metadata steps), it never breaks calls.
853
- * - Without either: the existing default behavior via {@link resolveRealtimeModel}
854
- * (highest-PowerRank active Realtime model), with the generic {@link noModelMessage} on failure.
1156
+ * - Without either: the default walk ({@link resolveDefaultRealtimeModel}): for a co-agent with video on, in a session
1157
+ * that could show an avatar (a browser session, or a server-side one with {@link PrepareClientSessionInput.AvatarDelivery}
1158
+ * `'room'`), the first candidate that shows one ({@link ResolveAvatarRealtimeModel}); else the existing default via
1159
+ * {@link resolveRealtimeModel} (highest-PowerRank active Realtime model), with the generic
1160
+ * {@link noModelMessage} on failure. The two explicit choices above win over the video preference.
1161
+ *
1162
+ * On every path the chosen model's vendor follows whether the session will show an avatar (the video setting is on
1163
+ * and the session could show one): among the model's keyed vendors, one that renders avatars (Vertex AI for Gemini
1164
+ * 3.8 Live) only when it will, else one that renders none; see {@link resolveVendorAndInstantiate}.
855
1165
  *
856
1166
  * @param input The prepare-session input (carries the optional preferred model id).
857
1167
  * @param coAgent The resolved co-agent (threaded to the default-resolution seam).
858
- * @param effectiveConfig The resolved effective configuration (carries `modelPreference`).
1168
+ * @param effectiveConfig The resolved effective configuration (carries `modelPreference` and the video setting).
859
1169
  * @returns The resolution outcome (resolution or failure reason).
860
1170
  */
861
1171
  protected resolveModelForSession(input: PrepareClientSessionInput, coAgent: MJAIAgentEntityExtended, effectiveConfig?: RealtimeCoAgentConfig): Promise<RealtimeModelResolutionOutcome>;
1172
+ /**
1173
+ * The default walk. With `preferAvatar` (the co-agent's video setting is on and the session could show an avatar),
1174
+ * it takes the first candidate that shows one ({@link ResolveAvatarRealtimeModel}). When none does, or without it, it
1175
+ * takes {@link resolveRealtimeModel}'s choice; when one was preferred, one log line says the call stays audio only.
1176
+ */
1177
+ private resolveDefaultRealtimeModel;
1178
+ /**
1179
+ * For a co-agent with video on: the first candidate that shows an avatar and supports client-direct sessions, in the
1180
+ * default walk's order (highest PowerRank first; a model's Active vendor rows by Priority, each with a usable key).
1181
+ * A candidate shows an avatar when its model's Video/Output row allows video or it has none, and its driver renders
1182
+ * avatars for the vendor's API name on its endpoint ({@link RealtimeModelShowsAvatar}). Every keyed vendor of a model
1183
+ * is tried, not only the first. **Overridable seam.**
1184
+ *
1185
+ * @param coAgent The co-agent (reserved for future per-agent model preference).
1186
+ * @param resolve The session's run-scoped key resolver (run keys only; see {@link resolveVendorAndInstantiate}).
1187
+ * @param credentialScope The session's credential scope; see {@link resolveVendorAndInstantiate}.
1188
+ * @returns The resolution, or `null` when no candidate shows an avatar.
1189
+ */
1190
+ protected ResolveAvatarRealtimeModel(coAgent: MJAIAgentEntityExtended, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope): RealtimeModelResolution | null;
862
1191
  /**
863
1192
  * The session's run-scoped keys as a resolver: the key for a driver class when the run carries
864
1193
  * one, else `undefined` — no platform fallback. The fallback belongs to
@@ -879,9 +1208,10 @@ export declare class RealtimeClientSessionService {
879
1208
  * @param effectiveConfig The resolved effective configuration.
880
1209
  * @param resolve The session's run-scoped key resolver (run keys only; see {@link resolveVendorAndInstantiate}).
881
1210
  * @param credentialScope The session's credential scope; see {@link resolveVendorAndInstantiate}.
1211
+ * @param showsAvatar Whether the session will show an avatar; see {@link resolveVendorAndInstantiate}.
882
1212
  * @returns The resolution, or `null` when no preference is configured or it can't be satisfied.
883
1213
  */
884
- protected resolveConfiguredModelPreference(effectiveConfig?: RealtimeCoAgentConfig, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope): RealtimeModelResolution | null;
1214
+ protected resolveConfiguredModelPreference(effectiveConfig?: RealtimeCoAgentConfig, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope, showsAvatar?: boolean): RealtimeModelResolution | null;
885
1215
  /**
886
1216
  * Looks up a model by ID (UUID-insensitive) or, failing that, by case/whitespace-insensitive
887
1217
  * Name in {@link AIEngine}'s cached models. **Overridable seam**; tolerant of an unloaded cache.
@@ -898,9 +1228,10 @@ export declare class RealtimeClientSessionService {
898
1228
  * @param preferredModelID The `MJ: AI Models.ID` the user chose.
899
1229
  * @param resolve The session's run-scoped key resolver (run keys only; see {@link resolveVendorAndInstantiate}).
900
1230
  * @param credentialScope The session's credential scope; see {@link resolveVendorAndInstantiate}.
1231
+ * @param showsAvatar Whether the session will show an avatar; see {@link resolveVendorAndInstantiate}.
901
1232
  * @returns The resolution outcome (resolution or a specific failure reason).
902
1233
  */
903
- protected resolvePreferredRealtimeModel(preferredModelID: string, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope): RealtimeModelResolutionOutcome;
1234
+ protected resolvePreferredRealtimeModel(preferredModelID: string, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope, showsAvatar?: boolean): RealtimeModelResolutionOutcome;
904
1235
  /**
905
1236
  * Looks up a model by id in {@link AIEngine}'s cached models. **Overridable seam** for tests.
906
1237
  *
@@ -922,9 +1253,10 @@ export declare class RealtimeClientSessionService {
922
1253
  * @param coAgent The co-agent being voiced (reserved for future per-agent model preference).
923
1254
  * @param resolve The session's run-scoped key resolver (run keys only; see {@link resolveVendorAndInstantiate}).
924
1255
  * @param credentialScope The session's credential scope; see {@link resolveVendorAndInstantiate}.
1256
+ * @param showsAvatar Whether the session will show an avatar; see {@link resolveVendorAndInstantiate}.
925
1257
  * @returns The resolved model + identifiers, or `null`.
926
1258
  */
927
- protected resolveRealtimeModel(coAgent: MJAIAgentEntityExtended, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope): Promise<RealtimeModelResolution | null>;
1259
+ protected resolveRealtimeModel(coAgent: MJAIAgentEntityExtended, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope, showsAvatar?: boolean): Promise<RealtimeModelResolution | null>;
928
1260
  /**
929
1261
  * Shared tail of model resolution: picks the vendor (with a usable API key) for an
930
1262
  * already-chosen model entity and instantiates its realtime driver.
@@ -940,9 +1272,23 @@ export declare class RealtimeClientSessionService {
940
1272
  * @param credentialScope A scope that rules out the `'Environment'` source (`'RuntimeOnly'`) drops the
941
1273
  * {@link getAPIKeyForDriver} seam: the run's keys are the whole chain, so a vendor they do not key
942
1274
  * is never selected on the platform's key.
1275
+ * @param showsAvatar Whether the session will show an avatar. The highest-Priority keyed vendor stands when it
1276
+ * renders avatars ({@link RealtimeModelShowsAvatar}) exactly when the session will show one; otherwise the first
1277
+ * other keyed vendor that does is taken, when there is one. So a vendor that renders avatars (Vertex AI for Gemini
1278
+ * 3.8 Live, with its own billing and limits) takes a session only when it will show an avatar, or when it is the
1279
+ * only keyed vendor; and a session that will show one goes to such a vendor whatever the Priority order.
943
1280
  * @returns The full resolution, or `null` when no vendor/key/driver can be satisfied.
944
1281
  */
945
- protected resolveVendorAndInstantiate(model: MJAIModelEntityExtended, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope): RealtimeModelResolution | null;
1282
+ protected resolveVendorAndInstantiate(model: MJAIModelEntityExtended, resolve?: AIAPIKeyResolver, credentialScope?: AICredentialScope, showsAvatar?: boolean): RealtimeModelResolution | null;
1283
+ /**
1284
+ * The session's complete key chain for vendor selection and the mint (see {@link resolveVendorAndInstantiate}): the
1285
+ * run's keys first, then this service's own seam (which subclasses and tests override), so a run-scoped credential
1286
+ * wins without taking that seam away from anyone who replaced it. A scope that rules out the environment has no second
1287
+ * step: the seam's default is the platform key.
1288
+ */
1289
+ private buildKeyChain;
1290
+ /** Instantiates a vendor's realtime driver with its key from the chain; `null` when the key or the driver is missing. */
1291
+ private instantiateRealtimeVendor;
946
1292
  /**
947
1293
  * Resolves the API key for a vendor driver class. **Overridable seam** (wraps the module-level
948
1294
  * {@link GetAIAPIKey}) so tests can simulate present/absent keys without environment setup.
@@ -965,7 +1311,9 @@ export declare class RealtimeClientSessionService {
965
1311
  protected createModelInstance(driverClass: string, apiKey: string): BaseRealtimeModel | null;
966
1312
  /**
967
1313
  * The active models of AIModelType `Realtime`, sorted highest-PowerRank first — the candidate
968
- * list {@link resolveRealtimeModel} walks until one yields a usable client-direct driver.
1314
+ * list {@link resolveRealtimeModel} walks until one yields a usable client-direct driver, and
1315
+ * {@link ResolveAvatarRealtimeModel} walks first for a co-agent with video on. Equal PowerRanks
1316
+ * keep the engine's cached order (a stable sort).
969
1317
  * Returns ALL candidates (not just the top pick) so a keyless or non-client-direct top model
970
1318
  * falls through to the next usable one instead of dead-ending the whole resolution.
971
1319
  *
@@ -1008,9 +1356,32 @@ export declare class RealtimeClientSessionService {
1008
1356
  * @param driverClass The resolved vendor's DriverClass — matches per-provider voice settings.
1009
1357
  * @param modelID The resolved `MJ: AI Models` id — keys the model-catalog `ModelConfiguration` cascade.
1010
1358
  * @param modelVendorID The resolved `MJ: AI Model Vendors` ROW id — the cascade's most-specific layer.
1359
+ * @param resolvedAvatar The session's avatar resolution, when the caller already made it; resolved here otherwise.
1011
1360
  * @returns The assembled session params.
1012
1361
  */
1013
- protected buildSessionParams(input: PrepareClientSessionInput, coAgent: MJAIAgentEntityExtended, modelApiName: string, contextUser: UserInfo, provider: IMetadataProvider, effectiveConfig?: RealtimeCoAgentConfig, driverClass?: string, modelID?: string, modelVendorID?: string): Promise<RealtimeSessionParams>;
1362
+ protected buildSessionParams(input: PrepareClientSessionInput, coAgent: MJAIAgentEntityExtended, modelApiName: string, contextUser: UserInfo, provider: IMetadataProvider, effectiveConfig?: RealtimeCoAgentConfig, driverClass?: string, modelID?: string, modelVendorID?: string, resolvedAvatar?: RealtimeAvatarResolution): Promise<RealtimeSessionParams>;
1363
+ /**
1364
+ * The live avatar this session asks for, if any: from the voiced agent's persona, or `realtime.video.avatarId`,
1365
+ * when the agent's video setting is on (see `ResolveRealtimeAvatar`). A call that picked an avatar (its runtime
1366
+ * override names `realtime.video.avatarId`) while that setting is off asks for none, with reason `video-off`. A model
1367
+ * whose `MJ: AI Model Modalities`
1368
+ * Video/Output row turns video off asks for none (reason `endpoint`, one log line); otherwise whether the session can
1369
+ * render it is the driver's call. A seam so tests can supply a resolution without the engine's persona metadata.
1370
+ *
1371
+ * @param input The prepare-session input (the voiced agent).
1372
+ * @param coAgent The co-agent.
1373
+ * @param effectiveConfig The effective configuration.
1374
+ * @param modelID The resolved model.
1375
+ * @param modelVendorID The resolved model-vendor row; its vendor scopes the persona bindings.
1376
+ */
1377
+ protected ResolveSessionAvatar(input: PrepareClientSessionInput, coAgent: MJAIAgentEntityExtended, effectiveConfig: RealtimeCoAgentConfig | undefined, modelID: string | undefined, modelVendorID: string | undefined): RealtimeAvatarResolution;
1378
+ /**
1379
+ * The config bag with the avatar persona's voice, so the face and the voice match, unless a voice was picked in this
1380
+ * call (a runtime override's `realtime.voice.default.voice`), which wins. A session nobody would see the avatar in (a
1381
+ * phone call, an app without agent video) keeps the voice without the face, so the agent sounds the same as in a call
1382
+ * that shows it.
1383
+ */
1384
+ private withAvatarVoice;
1014
1385
  /**
1015
1386
  * Builds the provider-pact `Config` bag for the session: the effective config's resolved voice
1016
1387
  * settings (per {@link GetProviderVoiceSettings} — the persona's agnostic wire-level slots
@@ -1277,11 +1648,13 @@ export declare class RealtimeClientSessionService {
1277
1648
  /**
1278
1649
  * Runs (or resumes) the target agent for a delegation. Threads the combined abort signal, parent
1279
1650
  * run linkage, session id, and the `OnProgress` callback so the resolver can stream progress.
1651
+ * The browser session id becomes the run's `sessionID` (client-tool channel) and the app-context
1652
+ * snapshot rides `data.appContext` (prompt context and surface tools); both are optional.
1280
1653
  * When {@link ExecuteRelayedToolInput.ResumeRunID} is set, resumes that paused run via
1281
1654
  * `lastRunId` + `autoPopulateLastRunPayload` (the user's answer continues the same interactive
1282
1655
  * run) instead of starting fresh.
1283
1656
  *
1284
- * @param input The relayed tool input (linkage, progress callback, optional resume id).
1657
+ * @param input The relayed tool input (linkage, progress callback, optional resume id, browser session, app context).
1285
1658
  * @param request The broker's delegation request (call id + arguments + abort signal).
1286
1659
  * @param target The resolved target agent.
1287
1660
  * @param contextUser The calling user.
@@ -1332,17 +1705,27 @@ export declare class RealtimeClientSessionService {
1332
1705
  * @returns The active action entities assigned to the agent.
1333
1706
  */
1334
1707
  protected getTargetAgentActions(targetAgentID: string): MJActionEntityExtended[];
1708
+ /**
1709
+ * The session's direct-action tools. When the input excludes direct actions, none, and the empty
1710
+ * projection is recorded so the session's relays run none.
1711
+ */
1712
+ private projectDirectActions;
1335
1713
  /**
1336
1714
  * Builds the projected direct action tool definitions for a target agent if supported by the driver.
1337
1715
  * Gated by driver capability (`SupportsDynamicToolSet`) and explicit configuration opt-in
1338
1716
  * (`Configuration.realtime.directActions.enabled = true`).
1339
1717
  *
1718
+ * With `agentSessionID`, the projection is recorded for the session, even when it is empty: relayed
1719
+ * direct-action calls for the session may run only the projected actions.
1720
+ *
1340
1721
  * @param targetAgentID The target agent ID being voiced.
1341
1722
  * @param effectiveConfig The resolved effective configuration.
1342
1723
  * @param driverClass The resolved vendor's DriverClass.
1343
1724
  * @returns The array of projected direct action tools (empty if unsupported or disabled).
1344
1725
  */
1345
1726
  BuildDirectActionTools(targetAgentID: string | undefined, effectiveConfig?: RealtimeCoAgentConfig, driverClass?: string, agentSessionID?: string): RealtimeToolDefinition[];
1727
+ /** Records that a session projected no direct actions, so its relays run none. */
1728
+ private recordEmptyProjection;
1346
1729
  /** @deprecated Use {@link BuildDirectActionTools}. */
1347
1730
  buildDirectActionTools(targetAgentID: string | undefined, effectiveConfig?: RealtimeCoAgentConfig, driverClass?: string, agentSessionID?: string): RealtimeToolDefinition[];
1348
1731
  /**
@@ -1359,12 +1742,29 @@ export declare class RealtimeClientSessionService {
1359
1742
  * configured timeout. If the tool is unrecognized, disallowed, or target resolution fails,
1360
1743
  * returns a structured "not available" result.
1361
1744
  *
1745
+ * When this service holds the session's start-time projection, only the projected actions may
1746
+ * run, whatever target the input names. When it holds none, the target agent's own metadata
1747
+ * decides: another process prepared the session, the entry was evicted or lost on a restart, or
1748
+ * the session was never started through this service (for example a row created through the
1749
+ * entity API). That fallback skips the driver-capability gate but is still limited to the
1750
+ * target's own direct-actions allowlist.
1751
+ *
1362
1752
  * @param call The non-target tool call.
1363
1753
  * @param input The optional relayed tool input context.
1364
1754
  * @param contextUser The calling user context.
1365
1755
  * @returns A {@link ToolExecutionResult} for the model's tool_response.
1366
1756
  */
1367
1757
  protected executeNonTargetTool(call: RealtimeToolCall, input?: ExecuteRelayedToolInput, contextUser?: UserInfo): Promise<ToolExecutionResult>;
1758
+ /**
1759
+ * Finds the action a relayed tool name refers to: the exact wire name first, then a
1760
+ * case-insensitive match.
1761
+ */
1762
+ private findWireAction;
1763
+ /**
1764
+ * True when the action is in the session's start-time projection, or when this service holds no
1765
+ * projection for the session (see {@link executeNonTargetTool} for when that happens).
1766
+ */
1767
+ private isInProjection;
1368
1768
  /**
1369
1769
  * Parses JSON arguments string into a key-value record of parameters.
1370
1770
  * Distinguishes "no arguments" (valid for zero-param action) from "unparseable JSON".