@memberjunction/ai-agents 6.2.0-edge.2 → 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.
- package/README.md +6 -0
- package/dist/AgentDecisionService.d.ts +8 -1
- package/dist/AgentDecisionService.d.ts.map +1 -1
- package/dist/AgentDecisionService.js +4 -0
- package/dist/AgentDecisionService.js.map +1 -1
- package/dist/AgentRunner.d.ts +51 -2
- package/dist/AgentRunner.d.ts.map +1 -1
- package/dist/AgentRunner.js +121 -23
- package/dist/AgentRunner.js.map +1 -1
- package/dist/ConversationCompactionManager.d.ts +9 -1
- package/dist/ConversationCompactionManager.d.ts.map +1 -1
- package/dist/ConversationCompactionManager.js +6 -3
- package/dist/ConversationCompactionManager.js.map +1 -1
- package/dist/ConversationToolManager.d.ts +13 -2
- package/dist/ConversationToolManager.d.ts.map +1 -1
- package/dist/ConversationToolManager.js +19 -3
- package/dist/ConversationToolManager.js.map +1 -1
- package/dist/KnowledgeAgent.d.ts.map +1 -1
- package/dist/KnowledgeAgent.js +6 -1
- package/dist/KnowledgeAgent.js.map +1 -1
- package/dist/MJAIAgentRequestEntityServer.d.ts +6 -0
- package/dist/MJAIAgentRequestEntityServer.d.ts.map +1 -1
- package/dist/MJAIAgentRequestEntityServer.js +26 -1
- package/dist/MJAIAgentRequestEntityServer.js.map +1 -1
- package/dist/PayloadFeedbackManager.d.ts +3 -0
- package/dist/PayloadFeedbackManager.d.ts.map +1 -1
- package/dist/PayloadFeedbackManager.js +2 -1
- package/dist/PayloadFeedbackManager.js.map +1 -1
- package/dist/agent-run-watchdog.d.ts +65 -5
- package/dist/agent-run-watchdog.d.ts.map +1 -1
- package/dist/agent-run-watchdog.js +143 -28
- package/dist/agent-run-watchdog.js.map +1 -1
- package/dist/agent-types/loop-agent-prompt-params.d.ts +7 -0
- package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-prompt-params.js +1 -0
- package/dist/agent-types/loop-agent-prompt-params.js.map +1 -1
- package/dist/agent-types/loop-agent-type.d.ts +20 -0
- package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-type.js +73 -2
- package/dist/agent-types/loop-agent-type.js.map +1 -1
- package/dist/artifact-tools/SearchResultSetToolLibrary.js +4 -4
- package/dist/artifact-tools/SearchResultSetToolLibrary.js.map +1 -1
- package/dist/base-agent.d.ts +310 -26
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +867 -244
- package/dist/base-agent.js.map +1 -1
- package/dist/client-tool-results.d.ts +45 -0
- package/dist/client-tool-results.d.ts.map +1 -0
- package/dist/client-tool-results.js +94 -0
- package/dist/client-tool-results.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/native-tools/action-tool-builder.d.ts +14 -0
- package/dist/native-tools/action-tool-builder.d.ts.map +1 -1
- package/dist/native-tools/action-tool-builder.js +62 -7
- package/dist/native-tools/action-tool-builder.js.map +1 -1
- package/dist/native-tools/control-tools.d.ts +17 -1
- package/dist/native-tools/control-tools.d.ts.map +1 -1
- package/dist/native-tools/control-tools.js +40 -3
- package/dist/native-tools/control-tools.js.map +1 -1
- package/dist/prior-turn-tool-result-cache.d.ts +31 -12
- package/dist/prior-turn-tool-result-cache.d.ts.map +1 -1
- package/dist/prior-turn-tool-result-cache.js +59 -16
- package/dist/prior-turn-tool-result-cache.js.map +1 -1
- package/dist/realtime/bridge-host-params.d.ts +22 -0
- package/dist/realtime/bridge-host-params.d.ts.map +1 -0
- package/dist/realtime/bridge-host-params.js +53 -0
- package/dist/realtime/bridge-host-params.js.map +1 -0
- package/dist/realtime/bridge-realtime-session-factory.d.ts +63 -3
- package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -1
- package/dist/realtime/bridge-realtime-session-factory.js +83 -22
- package/dist/realtime/bridge-realtime-session-factory.js.map +1 -1
- package/dist/realtime/bridge-realtime-usage-recorder.d.ts +81 -0
- package/dist/realtime/bridge-realtime-usage-recorder.d.ts.map +1 -0
- package/dist/realtime/bridge-realtime-usage-recorder.js +194 -0
- package/dist/realtime/bridge-realtime-usage-recorder.js.map +1 -0
- package/dist/realtime/bridge-session-transcript-sink.d.ts +37 -0
- package/dist/realtime/bridge-session-transcript-sink.d.ts.map +1 -0
- package/dist/realtime/bridge-session-transcript-sink.js +58 -0
- package/dist/realtime/bridge-session-transcript-sink.js.map +1 -0
- package/dist/realtime/client-only-channel-server.d.ts +83 -0
- package/dist/realtime/client-only-channel-server.d.ts.map +1 -0
- package/dist/realtime/client-only-channel-server.js +107 -0
- package/dist/realtime/client-only-channel-server.js.map +1 -0
- package/dist/realtime/identity-verification-channel-server.d.ts +50 -0
- package/dist/realtime/identity-verification-channel-server.d.ts.map +1 -0
- package/dist/realtime/identity-verification-channel-server.js +66 -0
- package/dist/realtime/identity-verification-channel-server.js.map +1 -0
- package/dist/realtime/interactive-component-channel-server.d.ts +39 -0
- package/dist/realtime/interactive-component-channel-server.d.ts.map +1 -0
- package/dist/realtime/interactive-component-channel-server.js +55 -0
- package/dist/realtime/interactive-component-channel-server.js.map +1 -0
- package/dist/realtime/realtime-avatar-resolution.d.ts +194 -0
- package/dist/realtime/realtime-avatar-resolution.d.ts.map +1 -0
- package/dist/realtime/realtime-avatar-resolution.js +208 -0
- package/dist/realtime/realtime-avatar-resolution.js.map +1 -0
- package/dist/realtime/realtime-channel-policy.d.ts +81 -0
- package/dist/realtime/realtime-channel-policy.d.ts.map +1 -0
- package/dist/realtime/realtime-channel-policy.js +91 -0
- package/dist/realtime/realtime-channel-policy.js.map +1 -0
- package/dist/realtime/realtime-channel-server-host.d.ts +14 -0
- package/dist/realtime/realtime-channel-server-host.d.ts.map +1 -1
- package/dist/realtime/realtime-channel-server-host.js +35 -0
- package/dist/realtime/realtime-channel-server-host.js.map +1 -1
- package/dist/realtime/realtime-client-session-service.d.ts +493 -30
- package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
- package/dist/realtime/realtime-client-session-service.js +825 -98
- package/dist/realtime/realtime-client-session-service.js.map +1 -1
- package/dist/realtime/realtime-coagent-config.d.ts +94 -15
- package/dist/realtime/realtime-coagent-config.d.ts.map +1 -1
- package/dist/realtime/realtime-coagent-config.js +109 -4
- package/dist/realtime/realtime-coagent-config.js.map +1 -1
- package/dist/realtime/realtime-coagent-resolution.d.ts +90 -0
- package/dist/realtime/realtime-coagent-resolution.d.ts.map +1 -0
- package/dist/realtime/realtime-coagent-resolution.js +186 -0
- package/dist/realtime/realtime-coagent-resolution.js.map +1 -0
- package/dist/realtime/realtime-delegation-narrator.d.ts +97 -0
- package/dist/realtime/realtime-delegation-narrator.d.ts.map +1 -0
- package/dist/realtime/realtime-delegation-narrator.js +162 -0
- package/dist/realtime/realtime-delegation-narrator.js.map +1 -0
- package/dist/realtime/realtime-recording-store.d.ts +136 -16
- package/dist/realtime/realtime-recording-store.d.ts.map +1 -1
- package/dist/realtime/realtime-recording-store.js +505 -39
- package/dist/realtime/realtime-recording-store.js.map +1 -1
- package/dist/realtime/realtime-session-runner.d.ts +2 -82
- package/dist/realtime/realtime-session-runner.d.ts.map +1 -1
- package/dist/realtime/realtime-session-runner.js +16 -191
- package/dist/realtime/realtime-session-runner.js.map +1 -1
- package/dist/realtime/realtime-vendor-resolution.d.ts +9 -0
- package/dist/realtime/realtime-vendor-resolution.d.ts.map +1 -1
- package/dist/realtime/realtime-vendor-resolution.js +16 -5
- package/dist/realtime/realtime-vendor-resolution.js.map +1 -1
- package/dist/realtime/realtime-video-output-gate.d.ts +83 -0
- package/dist/realtime/realtime-video-output-gate.d.ts.map +1 -0
- package/dist/realtime/realtime-video-output-gate.js +79 -0
- package/dist/realtime/realtime-video-output-gate.js.map +1 -0
- package/dist/rubric-evaluation-agent-runner.js +17 -8
- package/dist/rubric-evaluation-agent-runner.js.map +1 -1
- package/dist/self-check.d.ts +6 -3
- package/dist/self-check.d.ts.map +1 -1
- package/dist/self-check.js +3 -3
- package/dist/self-check.js.map +1 -1
- package/dist/tool-result-format.d.ts +14 -0
- package/dist/tool-result-format.d.ts.map +1 -1
- package/dist/tool-result-format.js.map +1 -1
- package/package.json +19 -19
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-verification-channel-server.d.ts","sourceRoot":"","sources":["../../src/realtime/identity-verification-channel-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,EAAE,uBAAuB,EAA+B,MAAM,8BAA8B,CAAC;AAEpG,gFAAgF;AAChF,eAAO,MAAM,kCAAkC,yBAAyB,CAAC;AAEzE;;;;;;;;;GASG;AACH,qBACa,iCAAkC,SAAQ,uBAAuB;IAC1E,+DAA+D;IAC/D,IAAoB,WAAW,IAAI,MAAM,CAExC;CACJ;AAED;;;GAGG;AACH,wBAAgB,qCAAqC,IAAI,IAAI,CAE5D"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server-side channel plugin for the **Identity Verification** channel — the generic,
|
|
3
|
+
* opt-in channel through which a realtime agent helps a person (often an anonymous widget guest) prove
|
|
4
|
+
* they control an email address without leaving the call.
|
|
5
|
+
*
|
|
6
|
+
* Paired with the browser's `IdentityVerificationChannel` client plugin through the seeded
|
|
7
|
+
* `MJ: AI Agent Channels` row (`Name: 'IdentityVerification'`,
|
|
8
|
+
* `ServerPluginClass: 'IdentityVerificationChannelServer'`, `ClientPluginClass: 'IdentityVerificationChannel'`).
|
|
9
|
+
*
|
|
10
|
+
* **Why the server half is intentionally thin, and validates nothing beyond scope.** The channel's verbs
|
|
11
|
+
* are executed in the browser, which then calls the verification operations
|
|
12
|
+
* (`RequestRealtimeSessionVerification`, `SubmitRealtimeSessionVerificationCode`) on the session's own
|
|
13
|
+
* principal. Those operations — not this plugin — are the security boundary: domain policy, rate limits,
|
|
14
|
+
* code hashing, expiry and deadline extension all live in the verification service, and the server never
|
|
15
|
+
* trusts anything the client says about verification state. A server tool here would only be a second,
|
|
16
|
+
* weaker door to the same room, and a state of record would put an email address (PII) onto the session's
|
|
17
|
+
* channel row for no benefit — the session's verification state is already stored, hashed where it must
|
|
18
|
+
* be, on the session itself. So the plugin completes the registry pairing (so the channel is discoverable
|
|
19
|
+
* and scoped like every other) and contributes no server tools and no persisted state.
|
|
20
|
+
*
|
|
21
|
+
* "Scope" is the only thing that applies server-side: whether the channel is in a session at all is decided
|
|
22
|
+
* by the channel-scoping cascade (`channels.config.IdentityVerification`, opt-in by default) and the
|
|
23
|
+
* registry's kill switch, both resolved before this plugin is ever created.
|
|
24
|
+
*
|
|
25
|
+
* @module @memberjunction/ai-agents
|
|
26
|
+
* @author MemberJunction.com
|
|
27
|
+
*/
|
|
28
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
29
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
30
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
31
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
32
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
33
|
+
};
|
|
34
|
+
import { BaseRealtimeChannelServer } from '@memberjunction/ai';
|
|
35
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
36
|
+
import { ClientOnlyChannelServer, LoadClientOnlyChannelServer } from './client-only-channel-server.js';
|
|
37
|
+
/** The stable channel name, matching the seeded `MJ: AI Agent Channels` row. */
|
|
38
|
+
export const IDENTITY_VERIFICATION_CHANNEL_NAME = 'IdentityVerification';
|
|
39
|
+
/**
|
|
40
|
+
* Server half of the Identity Verification channel. One instance per realtime session (created by
|
|
41
|
+
* `RealtimeChannelServerHost` from the channel registry; never construct directly).
|
|
42
|
+
*
|
|
43
|
+
* A {@link ClientOnlyChannelServer} that pins the channel's name under its own, already-seeded registry key
|
|
44
|
+
* (`IdentityVerificationChannelServer`), so the existing row keeps resolving. It contributes no server tools and does not
|
|
45
|
+
* rewrite saves. The channel's state is a name and an email in a form: the client plugin has no state of record (it never
|
|
46
|
+
* requests a save), so no email address reaches the channel row. A server plugin cannot refuse a save, so that guarantee
|
|
47
|
+
* rests on the client plugin continuing not to request one.
|
|
48
|
+
*/
|
|
49
|
+
let IdentityVerificationChannelServer = class IdentityVerificationChannelServer extends ClientOnlyChannelServer {
|
|
50
|
+
/** Matches the seeded `MJ: AI Agent Channels` row's `Name`. */
|
|
51
|
+
get ChannelName() {
|
|
52
|
+
return IDENTITY_VERIFICATION_CHANNEL_NAME;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
IdentityVerificationChannelServer = __decorate([
|
|
56
|
+
RegisterClass(BaseRealtimeChannelServer, 'IdentityVerificationChannelServer')
|
|
57
|
+
], IdentityVerificationChannelServer);
|
|
58
|
+
export { IdentityVerificationChannelServer };
|
|
59
|
+
/**
|
|
60
|
+
* Tree-shaking prevention for {@link IdentityVerificationChannelServer}'s `@RegisterClass` registration.
|
|
61
|
+
* Called from a static code path in the server host so the registration always executes.
|
|
62
|
+
*/
|
|
63
|
+
export function LoadIdentityVerificationChannelServer() {
|
|
64
|
+
LoadClientOnlyChannelServer();
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=identity-verification-channel-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-verification-channel-server.js","sourceRoot":"","sources":["../../src/realtime/identity-verification-channel-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;;;;;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAEpG,gFAAgF;AAChF,MAAM,CAAC,MAAM,kCAAkC,GAAG,sBAAsB,CAAC;AAEzE;;;;;;;;;GASG;AAEI,IAAM,iCAAiC,GAAvC,MAAM,iCAAkC,SAAQ,uBAAuB;IAC1E,+DAA+D;IAC/D,IAAoB,WAAW;QAC3B,OAAO,kCAAkC,CAAC;IAC9C,CAAC;CACJ,CAAA;AALY,iCAAiC;IAD7C,aAAa,CAAC,yBAAyB,EAAE,mCAAmC,CAAC;GACjE,iCAAiC,CAK7C;;AAED;;;GAGG;AACH,MAAM,UAAU,qCAAqC;IACjD,2BAA2B,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server-side channel plugin for the **Interactive Component** channel, the one that shows the user
|
|
3
|
+
* any component artifact next to the call and lets the agent operate it.
|
|
4
|
+
*
|
|
5
|
+
* Paired with the browser's `RealtimeInteractiveComponentChannel` client plugin through the
|
|
6
|
+
* `MJ: AI Agent Channels` row `Name: 'InteractiveComponent'`
|
|
7
|
+
* (`ServerPluginClass: 'InteractiveComponentChannelServer'`, `ClientPluginClass: 'RealtimeInteractiveComponentChannel'`).
|
|
8
|
+
*
|
|
9
|
+
* **Why the server half is intentionally thin.** The channel's work happens where the component runs, in the
|
|
10
|
+
* browser: the client plugin loads the artifact through the signed-in user's own session, renders it, derives the
|
|
11
|
+
* agent's actions from the component's spec and drives it. Its contract is not known until a component is open,
|
|
12
|
+
* so there is nothing to declare to the model as a native server tool; every action reaches the browser through
|
|
13
|
+
* the stable `ContextTool` proxy. The server half exists to complete the channel registry pairing (so the channel
|
|
14
|
+
* is discoverable and loadable like every other) and to say, explicitly, that it holds nothing: no server tools and
|
|
15
|
+
* no state of record. Open components are live-only and are not restored when a session resumes.
|
|
16
|
+
*
|
|
17
|
+
* @module @memberjunction/ai-agents
|
|
18
|
+
*/
|
|
19
|
+
import { ClientOnlyChannelServer } from './client-only-channel-server.js';
|
|
20
|
+
/** The stable channel name, matching the `MJ: AI Agent Channels` row. */
|
|
21
|
+
export declare const INTERACTIVE_COMPONENT_CHANNEL_NAME = "InteractiveComponent";
|
|
22
|
+
/**
|
|
23
|
+
* Server half of the Interactive Component channel. One instance per realtime session (created by
|
|
24
|
+
* `RealtimeChannelServerHost` from the channel registry; never construct directly).
|
|
25
|
+
*
|
|
26
|
+
* A {@link ClientOnlyChannelServer} that pins the channel's name under its own, already-seeded registry key
|
|
27
|
+
* (`InteractiveComponentChannelServer`), so the existing row keeps resolving. It contributes no server tools and does not
|
|
28
|
+
* rewrite saves; the client plugin is live-only (`SerializeState()` returns `null`), so nothing is ever persisted.
|
|
29
|
+
*/
|
|
30
|
+
export declare class InteractiveComponentChannelServer extends ClientOnlyChannelServer {
|
|
31
|
+
/** Matches the `MJ: AI Agent Channels` row's `Name`. */
|
|
32
|
+
get ChannelName(): string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Tree-shaking prevention for {@link InteractiveComponentChannelServer}'s `@RegisterClass` registration. Called from a
|
|
36
|
+
* static code path in the server host so the registration always executes.
|
|
37
|
+
*/
|
|
38
|
+
export declare function LoadInteractiveComponentChannelServer(): void;
|
|
39
|
+
//# sourceMappingURL=interactive-component-channel-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-component-channel-server.d.ts","sourceRoot":"","sources":["../../src/realtime/interactive-component-channel-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAE,uBAAuB,EAA+B,MAAM,8BAA8B,CAAC;AAEpG,yEAAyE;AACzE,eAAO,MAAM,kCAAkC,yBAAyB,CAAC;AAEzE;;;;;;;GAOG;AACH,qBACa,iCAAkC,SAAQ,uBAAuB;IAC1E,wDAAwD;IACxD,IAAoB,WAAW,IAAI,MAAM,CAExC;CACJ;AAED;;;GAGG;AACH,wBAAgB,qCAAqC,IAAI,IAAI,CAE5D"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Server-side channel plugin for the **Interactive Component** channel, the one that shows the user
|
|
3
|
+
* any component artifact next to the call and lets the agent operate it.
|
|
4
|
+
*
|
|
5
|
+
* Paired with the browser's `RealtimeInteractiveComponentChannel` client plugin through the
|
|
6
|
+
* `MJ: AI Agent Channels` row `Name: 'InteractiveComponent'`
|
|
7
|
+
* (`ServerPluginClass: 'InteractiveComponentChannelServer'`, `ClientPluginClass: 'RealtimeInteractiveComponentChannel'`).
|
|
8
|
+
*
|
|
9
|
+
* **Why the server half is intentionally thin.** The channel's work happens where the component runs, in the
|
|
10
|
+
* browser: the client plugin loads the artifact through the signed-in user's own session, renders it, derives the
|
|
11
|
+
* agent's actions from the component's spec and drives it. Its contract is not known until a component is open,
|
|
12
|
+
* so there is nothing to declare to the model as a native server tool; every action reaches the browser through
|
|
13
|
+
* the stable `ContextTool` proxy. The server half exists to complete the channel registry pairing (so the channel
|
|
14
|
+
* is discoverable and loadable like every other) and to say, explicitly, that it holds nothing: no server tools and
|
|
15
|
+
* no state of record. Open components are live-only and are not restored when a session resumes.
|
|
16
|
+
*
|
|
17
|
+
* @module @memberjunction/ai-agents
|
|
18
|
+
*/
|
|
19
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
20
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
22
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
23
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
24
|
+
};
|
|
25
|
+
import { BaseRealtimeChannelServer } from '@memberjunction/ai';
|
|
26
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
27
|
+
import { ClientOnlyChannelServer, LoadClientOnlyChannelServer } from './client-only-channel-server.js';
|
|
28
|
+
/** The stable channel name, matching the `MJ: AI Agent Channels` row. */
|
|
29
|
+
export const INTERACTIVE_COMPONENT_CHANNEL_NAME = 'InteractiveComponent';
|
|
30
|
+
/**
|
|
31
|
+
* Server half of the Interactive Component channel. One instance per realtime session (created by
|
|
32
|
+
* `RealtimeChannelServerHost` from the channel registry; never construct directly).
|
|
33
|
+
*
|
|
34
|
+
* A {@link ClientOnlyChannelServer} that pins the channel's name under its own, already-seeded registry key
|
|
35
|
+
* (`InteractiveComponentChannelServer`), so the existing row keeps resolving. It contributes no server tools and does not
|
|
36
|
+
* rewrite saves; the client plugin is live-only (`SerializeState()` returns `null`), so nothing is ever persisted.
|
|
37
|
+
*/
|
|
38
|
+
let InteractiveComponentChannelServer = class InteractiveComponentChannelServer extends ClientOnlyChannelServer {
|
|
39
|
+
/** Matches the `MJ: AI Agent Channels` row's `Name`. */
|
|
40
|
+
get ChannelName() {
|
|
41
|
+
return INTERACTIVE_COMPONENT_CHANNEL_NAME;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
InteractiveComponentChannelServer = __decorate([
|
|
45
|
+
RegisterClass(BaseRealtimeChannelServer, 'InteractiveComponentChannelServer')
|
|
46
|
+
], InteractiveComponentChannelServer);
|
|
47
|
+
export { InteractiveComponentChannelServer };
|
|
48
|
+
/**
|
|
49
|
+
* Tree-shaking prevention for {@link InteractiveComponentChannelServer}'s `@RegisterClass` registration. Called from a
|
|
50
|
+
* static code path in the server host so the registration always executes.
|
|
51
|
+
*/
|
|
52
|
+
export function LoadInteractiveComponentChannelServer() {
|
|
53
|
+
LoadClientOnlyChannelServer();
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=interactive-component-channel-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-component-channel-server.js","sourceRoot":"","sources":["../../src/realtime/interactive-component-channel-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;;;;;;;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAEpG,yEAAyE;AACzE,MAAM,CAAC,MAAM,kCAAkC,GAAG,sBAAsB,CAAC;AAEzE;;;;;;;GAOG;AAEI,IAAM,iCAAiC,GAAvC,MAAM,iCAAkC,SAAQ,uBAAuB;IAC1E,wDAAwD;IACxD,IAAoB,WAAW;QAC3B,OAAO,kCAAkC,CAAC;IAC9C,CAAC;CACJ,CAAA;AALY,iCAAiC;IAD7C,aAAa,CAAC,yBAAyB,EAAE,mCAAmC,CAAC;GACjE,iCAAiC,CAK7C;;AAED;;;GAGG;AACH,MAAM,UAAU,qCAAqC;IACjD,2BAA2B,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Which live avatar, if any, a realtime session asks for, and the voice that goes with it.
|
|
3
|
+
*
|
|
4
|
+
* A persona is a voice and a face: its Audio binding on a vendor is a voice, its Video binding an avatar. A session asks
|
|
5
|
+
* for an avatar when the voiced agent's video setting is on (`realtime.video.enabled`), the model's Video/Output row
|
|
6
|
+
* doesn't turn video off (`IsSupported` false: reason `endpoint`), and a face resolves:
|
|
7
|
+
* 1. `realtime.video.avatarId`, accepted only when it names an Active Video binding the model supports on the vendor;
|
|
8
|
+
* 2. else the voiced (target) agent's personas, default first, the first with a face;
|
|
9
|
+
* 3. else the co-agent's personas, the same way;
|
|
10
|
+
* 4. else none. The model's own first persona is never used: an agent with no persona gets no face.
|
|
11
|
+
*
|
|
12
|
+
* A call's avatar pick (the runtime override's `realtime.video.avatarId`) can't turn the video setting on: with the
|
|
13
|
+
* setting off the session asks for none, and says why (reason `video-off`), since the pick asked for one.
|
|
14
|
+
*
|
|
15
|
+
* Where the session runs can rule the avatar out before any of that: nobody sees an avatar on a phone call (reason
|
|
16
|
+
* `phone`), or in an app that shows no agent video (reason `host`: the app said so at mint), so such a session asks for
|
|
17
|
+
* none ({@link WithoutUnseenAvatar}) and keeps only the persona's voice.
|
|
18
|
+
*
|
|
19
|
+
* Whether the session can render the avatar is otherwise the driver's call (its endpoint profile); this only decides
|
|
20
|
+
* which one to ask for. Once the driver has minted the session, {@link ResolveRealtimeAvatarStatus} merges the two into
|
|
21
|
+
* the status the call gets, so a call that shows no avatar can say why. A server-side session gets its status from
|
|
22
|
+
* {@link ResolveBridgedAvatarStatus}, so a meeting can say why too, including when the prep asked its driver for none
|
|
23
|
+
* and when its driver renders no avatar and ignored the request.
|
|
24
|
+
*
|
|
25
|
+
* @module @memberjunction/ai-agents
|
|
26
|
+
*/
|
|
27
|
+
import type { RealtimeAvatarSettings, RealtimeAvatarStatus, RealtimeAvatarUnavailableReason } from '@memberjunction/ai';
|
|
28
|
+
import type { ResolvedAgentPersona, ResolvedModelPersona } from '@memberjunction/ai-engine-base';
|
|
29
|
+
import type { RealtimeCoAgentConfig } from './realtime-coagent-config.js';
|
|
30
|
+
import type { RealtimeVideoOutputRow } from './realtime-video-output-gate.js';
|
|
31
|
+
/** The persona lookups the resolution needs: `AIEngine` provides them; tests pass a fake. */
|
|
32
|
+
export interface RealtimeAvatarPersonaSource {
|
|
33
|
+
GetModelPersonas(modelId: string, modalityName?: string, vendorId?: string): ResolvedModelPersona[];
|
|
34
|
+
GetAgentPersonas(agentId: string): ResolvedAgentPersona[];
|
|
35
|
+
}
|
|
36
|
+
/** What the session needs to know to resolve its avatar. */
|
|
37
|
+
export interface RealtimeAvatarResolutionInput {
|
|
38
|
+
/** The session's effective realtime configuration. */
|
|
39
|
+
EffectiveConfig: RealtimeCoAgentConfig | null | undefined;
|
|
40
|
+
/** The voiced (target) agent, when there is one. */
|
|
41
|
+
TargetAgentID?: string | null;
|
|
42
|
+
/** The co-agent voicing it. */
|
|
43
|
+
CoAgentID: string;
|
|
44
|
+
/** The resolved realtime model. */
|
|
45
|
+
ModelID: string;
|
|
46
|
+
/** The AI vendor serving it. Bindings on other vendors don't count. */
|
|
47
|
+
VendorID?: string | null;
|
|
48
|
+
/**
|
|
49
|
+
* The model's Video/Output row (`ReadRealtimeVideoOutputRow`). `'unsupported'` turns video off: no avatar, reason
|
|
50
|
+
* `endpoint`. `'supported'`, `'unstated'` or absent leave it to the driver's endpoint profile at the mint.
|
|
51
|
+
*/
|
|
52
|
+
VideoOutputRow?: RealtimeVideoOutputRow;
|
|
53
|
+
/**
|
|
54
|
+
* Whether the call picked an avatar (its runtime override names `realtime.video.avatarId`). With the agent's video
|
|
55
|
+
* setting off, the pick is dropped with reason `video-off`; absent or `false`, the session asks for nothing then.
|
|
56
|
+
*/
|
|
57
|
+
AvatarPicked?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Why nobody would see an avatar in a session, whatever its model renders: `'phone'`, a phone call; `'host'`, an app that
|
|
61
|
+
* shows no agent video. Such a session asks the model for none.
|
|
62
|
+
*/
|
|
63
|
+
export type RealtimeAvatarUnseenReason = Extract<RealtimeAvatarUnavailableReason, 'phone' | 'host'>;
|
|
64
|
+
/** Which avatar to ask for, and its persona's voice; or why there is none. */
|
|
65
|
+
export interface RealtimeAvatarResolution {
|
|
66
|
+
/**
|
|
67
|
+
* The avatar to ask for. Absent when the video setting is off, the model's row turns video off, no face resolves, or
|
|
68
|
+
* nobody in the session would see it.
|
|
69
|
+
*/
|
|
70
|
+
Avatar?: RealtimeAvatarSettings;
|
|
71
|
+
/**
|
|
72
|
+
* The avatar persona's voice on the same vendor, when it has one. Kept when nobody would see the avatar, so the agent
|
|
73
|
+
* sounds the same on a phone call, or in an app without agent video, as in a call that shows its face.
|
|
74
|
+
*/
|
|
75
|
+
Voice?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Why there is no avatar although the video setting is on or the call picked one: nobody in the session would see it
|
|
78
|
+
* (`phone`, `host`), the call picked one and the agent's video setting is off (`video-off`), the model's Video/Output
|
|
79
|
+
* row turns video off (`endpoint`), the requested avatar is not a face the model has on the vendor (`unknown-avatar`),
|
|
80
|
+
* or no persona has one (`no-binding`).
|
|
81
|
+
*/
|
|
82
|
+
Reason?: RealtimeAvatarUnseenReason | Extract<RealtimeAvatarUnavailableReason, 'video-off' | 'endpoint' | 'unknown-avatar' | 'no-binding'>;
|
|
83
|
+
}
|
|
84
|
+
/** What says, before any model is asked, whether anyone in a session could see an avatar. */
|
|
85
|
+
export interface RealtimeAvatarViewers {
|
|
86
|
+
/** `true` when the session is a phone call: the caller hears the agent and sees no video. */
|
|
87
|
+
PhoneCall?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* `false` when the app showing the call shows no agent video (none of its channels shows it). Absent or `true`: it
|
|
90
|
+
* may show it.
|
|
91
|
+
*/
|
|
92
|
+
ShowsAgentVideo?: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Why nobody would see an avatar in a session, whatever its model renders, or `undefined` when someone could. A phone
|
|
96
|
+
* call says `phone` whatever app relays it.
|
|
97
|
+
*
|
|
98
|
+
* @param viewers What the session says about who is on the other end.
|
|
99
|
+
*/
|
|
100
|
+
export declare function ResolveAvatarUnseenReason(viewers: RealtimeAvatarViewers): RealtimeAvatarUnseenReason | undefined;
|
|
101
|
+
/** What says whether a session could show an avatar at all: who is on the other end, and where the session runs. */
|
|
102
|
+
export interface RealtimeAvatarSessionShape extends RealtimeAvatarViewers {
|
|
103
|
+
/** `true` for a server-side (bridged or agent-run) session; absent for a browser session. */
|
|
104
|
+
ServerSide?: boolean;
|
|
105
|
+
/** `'room'` when the session's host publishes the avatar into a room. */
|
|
106
|
+
AvatarDelivery?: 'room';
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Whether a session could show an avatar at all: a browser session whose app may show agent video, or a server-side
|
|
110
|
+
* one whose host publishes the avatar into a room. A phone call or an app without agent video
|
|
111
|
+
* ({@link ResolveAvatarUnseenReason}), or a server-side session whose host can't publish video, can't.
|
|
112
|
+
*
|
|
113
|
+
* @param session What the session says about its viewers and where it runs.
|
|
114
|
+
*/
|
|
115
|
+
export declare function RealtimeSessionCanShowAvatar(session: RealtimeAvatarSessionShape): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* A resolution without its avatar request when nobody in the session would see the avatar
|
|
118
|
+
* ({@link ResolveAvatarUnseenReason}), so the driver is never asked to render video that nobody sees. The reason replaces
|
|
119
|
+
* any other, since no model or face could change it; the persona's voice stays. A resolution that asked for nothing
|
|
120
|
+
* (the video setting is off) stays as it is, so the call gets no notice.
|
|
121
|
+
*
|
|
122
|
+
* @param resolution The session's avatar resolution.
|
|
123
|
+
* @param viewers What the session says about who is on the other end.
|
|
124
|
+
*/
|
|
125
|
+
export declare function WithoutUnseenAvatar(resolution: RealtimeAvatarResolution, viewers: RealtimeAvatarViewers): RealtimeAvatarResolution;
|
|
126
|
+
/** What a server-side (bridged) session's avatar status is made from, once its driver has opened it. */
|
|
127
|
+
export interface RealtimeBridgedAvatarStatusInput {
|
|
128
|
+
/** The session's avatar resolution (`RealtimeSessionParamsPrep.AvatarResolution`); absent when the prep made none. */
|
|
129
|
+
Resolution: RealtimeAvatarResolution | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Whether the session's host publishes the avatar into a room (`PrepareClientSessionInput.AvatarDelivery` `'room'`).
|
|
132
|
+
* Without it nothing on the server shows an avatar.
|
|
133
|
+
*/
|
|
134
|
+
RoomDelivery: boolean;
|
|
135
|
+
/**
|
|
136
|
+
* Whether the session's model shows avatars (`RealtimeModelShowsAvatar`: its Video/Output row and its driver's
|
|
137
|
+
* endpoint). Asked only in a session whose host publishes the avatar, when the driver had nothing to report: the prep
|
|
138
|
+
* asked it for no avatar for a reason other than who would see it, or asked it for one and it reported nothing.
|
|
139
|
+
*/
|
|
140
|
+
ModelShowsAvatar: () => boolean;
|
|
141
|
+
/** What the driver reported when it opened the session (`IRealtimeSession.AvatarStatus`). */
|
|
142
|
+
DriverStatus: RealtimeAvatarStatus | undefined;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The avatar status a server-side (bridged) session reports, which its host shows (the LiveKit room puts it on the
|
|
146
|
+
* agent's bot as `mj.agentAvatar`). A status the driver reported about the avatar it was asked for stands: the driver
|
|
147
|
+
* decided. A session whose prep asked for none because the video setting is off keeps the driver's status (none).
|
|
148
|
+
* Otherwise the driver had nothing to report, because the prep asked it for no avatar for a reason, or because it renders
|
|
149
|
+
* no avatar and ignored the request, so the status says why, asked for and not granted:
|
|
150
|
+
* 1. `phone` (or `host`): nobody would see the avatar, whatever renders it; or `video-off`: the agent's video setting
|
|
151
|
+
* dropped the call's pick;
|
|
152
|
+
* 2. `bridged` when the host publishes no avatar into a room, which is what a driver asked there says (the LiveKit room
|
|
153
|
+
* then names its own reason, such as `decoder-missing`);
|
|
154
|
+
* 3. `endpoint` when the model shows no avatar, as a browser call says ({@link ResolveRealtimeAvatarStatus});
|
|
155
|
+
* 4. else the prep's reason: `endpoint` (the model's Video/Output row), `unknown-avatar` or `no-binding`. A driver that
|
|
156
|
+
* was asked for the avatar on a model that shows avatars and reported nothing gives no reason, so there is no status.
|
|
157
|
+
*
|
|
158
|
+
* @param input The resolution, whether the host publishes the avatar, the model's capability and the driver's status.
|
|
159
|
+
* @returns The status for the session; `undefined` when the session asked for no avatar, or its driver reported nothing
|
|
160
|
+
* about one on a model that shows avatars.
|
|
161
|
+
*/
|
|
162
|
+
export declare function ResolveBridgedAvatarStatus(input: RealtimeBridgedAvatarStatusInput): RealtimeAvatarStatus | undefined;
|
|
163
|
+
/**
|
|
164
|
+
* Resolves the avatar a session asks for (see the file header for the order).
|
|
165
|
+
*
|
|
166
|
+
* @param input The session's configuration, agents, model and vendor.
|
|
167
|
+
* @param personas The persona lookups (`AIEngine.Instance`).
|
|
168
|
+
*/
|
|
169
|
+
export declare function ResolveRealtimeAvatar(input: RealtimeAvatarResolutionInput, personas: RealtimeAvatarPersonaSource): RealtimeAvatarResolution;
|
|
170
|
+
/** What a session's avatar status is made from, once the driver has minted it. */
|
|
171
|
+
export interface RealtimeAvatarStatusInput {
|
|
172
|
+
/** The session's avatar resolution: an avatar, a reason there is none, or neither when the agent asked for none. */
|
|
173
|
+
Resolution: RealtimeAvatarResolution;
|
|
174
|
+
/**
|
|
175
|
+
* Whether the resolved model shows avatars (`RealtimeModelShowsAvatar`): its Video/Output row allows video or it has
|
|
176
|
+
* none, and its driver renders avatars on its endpoint (`BaseRealtimeModel.SupportsAvatarOutput`).
|
|
177
|
+
*/
|
|
178
|
+
ModelSupportsAvatarOutput: boolean;
|
|
179
|
+
/** The driver's decision at mint (`ClientRealtimeSessionConfig.AvatarStatus`), when it reported one. */
|
|
180
|
+
DriverStatus?: RealtimeAvatarStatus;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The status a call gets about the avatar its agent asked for. Nothing when the agent asked for none (its video
|
|
184
|
+
* setting is off, and the call picked none). Otherwise audio only when nobody in the session would see it
|
|
185
|
+
* ({@link RealtimeAvatarUnseenReason}) or the agent's video setting dropped the call's pick (`video-off`), whatever the
|
|
186
|
+
* model renders; then `endpoint` when the model shows no avatar (its Video/Output row turns video off, or it
|
|
187
|
+
* renders none on its endpoint), whatever driver serves it; then the resolution's reason (`unknown-avatar`,
|
|
188
|
+
* `no-binding`); else the driver's own decision (granted, or `custom-disabled` and the like).
|
|
189
|
+
*
|
|
190
|
+
* @param input The resolution, the model's capability and the driver's decision.
|
|
191
|
+
* @returns The status for the call, or `undefined` when the session asked for no avatar or the driver reported none.
|
|
192
|
+
*/
|
|
193
|
+
export declare function ResolveRealtimeAvatarStatus(input: RealtimeAvatarStatusInput): RealtimeAvatarStatus | undefined;
|
|
194
|
+
//# sourceMappingURL=realtime-avatar-resolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-avatar-resolution.d.ts","sourceRoot":"","sources":["../../src/realtime/realtime-avatar-resolution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Which live avatar, if any, a realtime session asks for, and the voice that goes with it.
|
|
3
|
+
*
|
|
4
|
+
* A persona is a voice and a face: its Audio binding on a vendor is a voice, its Video binding an avatar. A session asks
|
|
5
|
+
* for an avatar when the voiced agent's video setting is on (`realtime.video.enabled`), the model's Video/Output row
|
|
6
|
+
* doesn't turn video off (`IsSupported` false: reason `endpoint`), and a face resolves:
|
|
7
|
+
* 1. `realtime.video.avatarId`, accepted only when it names an Active Video binding the model supports on the vendor;
|
|
8
|
+
* 2. else the voiced (target) agent's personas, default first, the first with a face;
|
|
9
|
+
* 3. else the co-agent's personas, the same way;
|
|
10
|
+
* 4. else none. The model's own first persona is never used: an agent with no persona gets no face.
|
|
11
|
+
*
|
|
12
|
+
* A call's avatar pick (the runtime override's `realtime.video.avatarId`) can't turn the video setting on: with the
|
|
13
|
+
* setting off the session asks for none, and says why (reason `video-off`), since the pick asked for one.
|
|
14
|
+
*
|
|
15
|
+
* Where the session runs can rule the avatar out before any of that: nobody sees an avatar on a phone call (reason
|
|
16
|
+
* `phone`), or in an app that shows no agent video (reason `host`: the app said so at mint), so such a session asks for
|
|
17
|
+
* none ({@link WithoutUnseenAvatar}) and keeps only the persona's voice.
|
|
18
|
+
*
|
|
19
|
+
* Whether the session can render the avatar is otherwise the driver's call (its endpoint profile); this only decides
|
|
20
|
+
* which one to ask for. Once the driver has minted the session, {@link ResolveRealtimeAvatarStatus} merges the two into
|
|
21
|
+
* the status the call gets, so a call that shows no avatar can say why. A server-side session gets its status from
|
|
22
|
+
* {@link ResolveBridgedAvatarStatus}, so a meeting can say why too, including when the prep asked its driver for none
|
|
23
|
+
* and when its driver renders no avatar and ignored the request.
|
|
24
|
+
*
|
|
25
|
+
* @module @memberjunction/ai-agents
|
|
26
|
+
*/
|
|
27
|
+
import { IndexByUUID, UUIDsEqual } from '@memberjunction/global';
|
|
28
|
+
/**
|
|
29
|
+
* Why nobody would see an avatar in a session, whatever its model renders, or `undefined` when someone could. A phone
|
|
30
|
+
* call says `phone` whatever app relays it.
|
|
31
|
+
*
|
|
32
|
+
* @param viewers What the session says about who is on the other end.
|
|
33
|
+
*/
|
|
34
|
+
export function ResolveAvatarUnseenReason(viewers) {
|
|
35
|
+
if (viewers.PhoneCall === true) {
|
|
36
|
+
return 'phone';
|
|
37
|
+
}
|
|
38
|
+
return viewers.ShowsAgentVideo === false ? 'host' : undefined;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether a session could show an avatar at all: a browser session whose app may show agent video, or a server-side
|
|
42
|
+
* one whose host publishes the avatar into a room. A phone call or an app without agent video
|
|
43
|
+
* ({@link ResolveAvatarUnseenReason}), or a server-side session whose host can't publish video, can't.
|
|
44
|
+
*
|
|
45
|
+
* @param session What the session says about its viewers and where it runs.
|
|
46
|
+
*/
|
|
47
|
+
export function RealtimeSessionCanShowAvatar(session) {
|
|
48
|
+
if (ResolveAvatarUnseenReason(session)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return session.ServerSide !== true || session.AvatarDelivery === 'room';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A resolution without its avatar request when nobody in the session would see the avatar
|
|
55
|
+
* ({@link ResolveAvatarUnseenReason}), so the driver is never asked to render video that nobody sees. The reason replaces
|
|
56
|
+
* any other, since no model or face could change it; the persona's voice stays. A resolution that asked for nothing
|
|
57
|
+
* (the video setting is off) stays as it is, so the call gets no notice.
|
|
58
|
+
*
|
|
59
|
+
* @param resolution The session's avatar resolution.
|
|
60
|
+
* @param viewers What the session says about who is on the other end.
|
|
61
|
+
*/
|
|
62
|
+
export function WithoutUnseenAvatar(resolution, viewers) {
|
|
63
|
+
const unseen = ResolveAvatarUnseenReason(viewers);
|
|
64
|
+
if (!unseen || (!resolution.Avatar && !resolution.Reason)) {
|
|
65
|
+
return resolution;
|
|
66
|
+
}
|
|
67
|
+
return resolution.Voice ? { Voice: resolution.Voice, Reason: unseen } : { Reason: unseen };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The avatar status a server-side (bridged) session reports, which its host shows (the LiveKit room puts it on the
|
|
71
|
+
* agent's bot as `mj.agentAvatar`). A status the driver reported about the avatar it was asked for stands: the driver
|
|
72
|
+
* decided. A session whose prep asked for none because the video setting is off keeps the driver's status (none).
|
|
73
|
+
* Otherwise the driver had nothing to report, because the prep asked it for no avatar for a reason, or because it renders
|
|
74
|
+
* no avatar and ignored the request, so the status says why, asked for and not granted:
|
|
75
|
+
* 1. `phone` (or `host`): nobody would see the avatar, whatever renders it; or `video-off`: the agent's video setting
|
|
76
|
+
* dropped the call's pick;
|
|
77
|
+
* 2. `bridged` when the host publishes no avatar into a room, which is what a driver asked there says (the LiveKit room
|
|
78
|
+
* then names its own reason, such as `decoder-missing`);
|
|
79
|
+
* 3. `endpoint` when the model shows no avatar, as a browser call says ({@link ResolveRealtimeAvatarStatus});
|
|
80
|
+
* 4. else the prep's reason: `endpoint` (the model's Video/Output row), `unknown-avatar` or `no-binding`. A driver that
|
|
81
|
+
* was asked for the avatar on a model that shows avatars and reported nothing gives no reason, so there is no status.
|
|
82
|
+
*
|
|
83
|
+
* @param input The resolution, whether the host publishes the avatar, the model's capability and the driver's status.
|
|
84
|
+
* @returns The status for the session; `undefined` when the session asked for no avatar, or its driver reported nothing
|
|
85
|
+
* about one on a model that shows avatars.
|
|
86
|
+
*/
|
|
87
|
+
export function ResolveBridgedAvatarStatus(input) {
|
|
88
|
+
const prepReason = input.Resolution?.Reason;
|
|
89
|
+
const unreported = input.Resolution?.Avatar !== undefined && !input.DriverStatus;
|
|
90
|
+
if (!prepReason && !unreported) {
|
|
91
|
+
return input.DriverStatus;
|
|
92
|
+
}
|
|
93
|
+
const reason = bridgedAudioOnlyReason(prepReason, input);
|
|
94
|
+
return reason ? { Requested: true, Granted: false, Reason: reason } : undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Why a bridged session whose driver had nothing to report is audio only, in {@link ResolveBridgedAvatarStatus}'s order.
|
|
98
|
+
* `prepReason` is why the prep asked the driver for no avatar; it is absent when the prep asked for one and the driver
|
|
99
|
+
* reported nothing, which names no reason (`undefined`) on a model that shows avatars.
|
|
100
|
+
*/
|
|
101
|
+
function bridgedAudioOnlyReason(prepReason, input) {
|
|
102
|
+
if (prepReason && standsWhateverModel(prepReason)) {
|
|
103
|
+
return prepReason;
|
|
104
|
+
}
|
|
105
|
+
if (!input.RoomDelivery) {
|
|
106
|
+
return 'bridged';
|
|
107
|
+
}
|
|
108
|
+
return input.ModelShowsAvatar() ? prepReason : 'endpoint';
|
|
109
|
+
}
|
|
110
|
+
/** Whether a resolution's reason says nobody in the session would see the avatar. */
|
|
111
|
+
function isUnseenReason(reason) {
|
|
112
|
+
return reason === 'phone' || reason === 'host';
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Whether a resolution's reason stands whatever model or host serves the session: nobody would see the avatar, or the
|
|
116
|
+
* agent's video setting dropped the call's pick (`video-off`).
|
|
117
|
+
*/
|
|
118
|
+
function standsWhateverModel(reason) {
|
|
119
|
+
return isUnseenReason(reason) || reason === 'video-off';
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Resolves the avatar a session asks for (see the file header for the order).
|
|
123
|
+
*
|
|
124
|
+
* @param input The session's configuration, agents, model and vendor.
|
|
125
|
+
* @param personas The persona lookups (`AIEngine.Instance`).
|
|
126
|
+
*/
|
|
127
|
+
export function ResolveRealtimeAvatar(input, personas) {
|
|
128
|
+
const video = input.EffectiveConfig?.realtime?.video;
|
|
129
|
+
if (video?.enabled !== true) {
|
|
130
|
+
return input.AvatarPicked ? { Reason: 'video-off' } : {};
|
|
131
|
+
}
|
|
132
|
+
if (input.VideoOutputRow === 'unsupported') {
|
|
133
|
+
return { Reason: 'endpoint' };
|
|
134
|
+
}
|
|
135
|
+
const vendorId = input.VendorID ?? undefined;
|
|
136
|
+
const faces = personas.GetModelPersonas(input.ModelID, 'Video', vendorId);
|
|
137
|
+
const requested = video.avatarId?.trim();
|
|
138
|
+
if (requested) {
|
|
139
|
+
const face = faces.find((f) => f.PersonaVendor.APIName.trim().toLowerCase() === requested.toLowerCase());
|
|
140
|
+
return face ? withVoice(face, 'override', input, personas) : { Reason: 'unknown-avatar' };
|
|
141
|
+
}
|
|
142
|
+
for (const agentId of [input.TargetAgentID, input.CoAgentID]) {
|
|
143
|
+
const face = agentId ? firstFaceOf(agentId, faces, personas) : undefined;
|
|
144
|
+
if (face) {
|
|
145
|
+
return withVoice(face, 'persona', input, personas);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { Reason: 'no-binding' };
|
|
149
|
+
}
|
|
150
|
+
/** The agent's first persona (the default first, then by sequence) that has a face. */
|
|
151
|
+
function firstFaceOf(agentId, faces, personas) {
|
|
152
|
+
const agentPersonas = personas.GetAgentPersonas(agentId);
|
|
153
|
+
const ordered = [...agentPersonas.filter((p) => p.AgentPersona.IsDefault), ...agentPersonas.filter((p) => !p.AgentPersona.IsDefault)];
|
|
154
|
+
// First face per persona wins, as faces.find() would.
|
|
155
|
+
const facesByPersona = IndexByUUID(faces, (f) => f.Persona.ID);
|
|
156
|
+
for (const agentPersona of ordered) {
|
|
157
|
+
const face = facesByPersona.Get(agentPersona.Persona.ID);
|
|
158
|
+
if (face) {
|
|
159
|
+
return face;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* The status a call gets about the avatar its agent asked for. Nothing when the agent asked for none (its video
|
|
166
|
+
* setting is off, and the call picked none). Otherwise audio only when nobody in the session would see it
|
|
167
|
+
* ({@link RealtimeAvatarUnseenReason}) or the agent's video setting dropped the call's pick (`video-off`), whatever the
|
|
168
|
+
* model renders; then `endpoint` when the model shows no avatar (its Video/Output row turns video off, or it
|
|
169
|
+
* renders none on its endpoint), whatever driver serves it; then the resolution's reason (`unknown-avatar`,
|
|
170
|
+
* `no-binding`); else the driver's own decision (granted, or `custom-disabled` and the like).
|
|
171
|
+
*
|
|
172
|
+
* @param input The resolution, the model's capability and the driver's decision.
|
|
173
|
+
* @returns The status for the call, or `undefined` when the session asked for no avatar or the driver reported none.
|
|
174
|
+
*/
|
|
175
|
+
export function ResolveRealtimeAvatarStatus(input) {
|
|
176
|
+
const { Avatar: avatar, Reason: reason } = input.Resolution;
|
|
177
|
+
if (!avatar && !reason) {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
if (reason && standsWhateverModel(reason)) {
|
|
181
|
+
return { Requested: true, Granted: false, Reason: reason };
|
|
182
|
+
}
|
|
183
|
+
if (!input.ModelSupportsAvatarOutput) {
|
|
184
|
+
return { Requested: true, Granted: false, Reason: 'endpoint' };
|
|
185
|
+
}
|
|
186
|
+
if (reason) {
|
|
187
|
+
return { Requested: true, Granted: false, Reason: reason };
|
|
188
|
+
}
|
|
189
|
+
return input.DriverStatus;
|
|
190
|
+
}
|
|
191
|
+
/** The avatar request for a face, and the same persona's voice on the vendor. */
|
|
192
|
+
function withVoice(face, source, input, personas) {
|
|
193
|
+
const settings = face.PersonaVendor.VendorSettingsObject?.Avatar;
|
|
194
|
+
const avatar = {
|
|
195
|
+
AvatarID: face.PersonaVendor.APIName.trim(),
|
|
196
|
+
PersonaName: face.Persona.Name,
|
|
197
|
+
Source: source,
|
|
198
|
+
...(settings?.Kind ? { Kind: settings.Kind } : {}),
|
|
199
|
+
...(settings?.ReferenceImageFileID ? { ReferenceImageFileID: settings.ReferenceImageFileID } : {}),
|
|
200
|
+
...(settings?.Resolution ? { Resolution: settings.Resolution } : {}),
|
|
201
|
+
...(settings?.Background ? { Background: settings.Background } : {}),
|
|
202
|
+
};
|
|
203
|
+
const voice = personas
|
|
204
|
+
.GetModelPersonas(input.ModelID, 'Audio', input.VendorID ?? undefined)
|
|
205
|
+
.find((p) => UUIDsEqual(p.Persona.ID, face.Persona.ID))?.PersonaVendor.APIName;
|
|
206
|
+
return voice ? { Avatar: avatar, Voice: voice } : { Avatar: avatar };
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=realtime-avatar-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-avatar-resolution.js","sourceRoot":"","sources":["../../src/realtime/realtime-avatar-resolution.ts"],"names":[],"mappings":"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"}
|