@livekit/agents-plugin-anam 1.4.8 → 1.4.11
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/dist/api.cjs +16 -2
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +3 -1
- package/dist/api.d.ts +3 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +19 -3
- package/dist/api.js.map +1 -1
- package/dist/avatar.cjs +5 -6
- package/dist/avatar.cjs.map +1 -1
- package/dist/avatar.d.cts +4 -1
- package/dist/avatar.d.ts +4 -1
- package/dist/avatar.d.ts.map +1 -1
- package/dist/avatar.js +8 -7
- package/dist/avatar.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +12 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +5 -5
- package/src/api.ts +43 -7
- package/src/avatar.ts +13 -6
- package/src/types.ts +13 -0
package/dist/api.cjs
CHANGED
|
@@ -121,11 +121,14 @@ class AnamAPI {
|
|
|
121
121
|
}
|
|
122
122
|
createSessionToken(params) {
|
|
123
123
|
const pc = params.personaConfig;
|
|
124
|
-
const personaPayload = {
|
|
124
|
+
const personaPayload = pc.personaId ? { personaId: pc.personaId } : {
|
|
125
125
|
type: "ephemeral",
|
|
126
126
|
name: pc.name,
|
|
127
127
|
avatarId: pc.avatarId,
|
|
128
|
-
llmId: "CUSTOMER_CLIENT_V1"
|
|
128
|
+
llmId: "CUSTOMER_CLIENT_V1",
|
|
129
|
+
// Only forward the avatar model version when set; otherwise let Anam
|
|
130
|
+
// fall back to the avatar's default model.
|
|
131
|
+
...pc.avatarModel ? { avatarModel: pc.avatarModel } : {}
|
|
129
132
|
};
|
|
130
133
|
const payload = {
|
|
131
134
|
personaConfig: personaPayload
|
|
@@ -134,6 +137,17 @@ class AnamAPI {
|
|
|
134
137
|
livekitUrl: params.livekitUrl,
|
|
135
138
|
livekitToken: params.livekitToken
|
|
136
139
|
};
|
|
140
|
+
if (params.sessionOptions && (params.sessionOptions.videoWidth !== void 0 || params.sessionOptions.videoHeight !== void 0)) {
|
|
141
|
+
if (params.sessionOptions.videoWidth === void 0 || params.sessionOptions.videoHeight === void 0) {
|
|
142
|
+
throw new import_types.AnamException(
|
|
143
|
+
"videoWidth and videoHeight must be set together (both or neither)"
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
payload.sessionOptions = {
|
|
147
|
+
videoWidth: params.sessionOptions.videoWidth,
|
|
148
|
+
videoHeight: params.sessionOptions.videoHeight
|
|
149
|
+
};
|
|
150
|
+
}
|
|
137
151
|
return this.post(this.tokenPath, payload);
|
|
138
152
|
}
|
|
139
153
|
startEngineSession(params) {
|
package/dist/api.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log } from '@livekit/agents';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/api.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log } from '@livekit/agents';\nimport {\n type APIConnectOptions,\n AnamException,\n type PersonaConfig,\n type SessionOptions,\n} from './types.js';\n\nconst DEFAULT_API_URL = 'https://api.anam.ai';\n\n/** @public */\nexport class AnamAPI {\n constructor(\n private apiKey: string,\n private apiUrl: string = DEFAULT_API_URL,\n private conn: APIConnectOptions = { maxRetry: 3, retryInterval: 2, timeout: 10 },\n ) {}\n\n private get tokenPath(): string {\n return '/v1/auth/session-token';\n }\n\n private get startPath(): string {\n return '/v1/engine/session';\n }\n\n private async postWithHeaders<T>(\n path: string,\n body: unknown,\n headersIn: Record<string, string>,\n ): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const { maxRetry = 3, retryInterval = 2 } = this.conn;\n let lastErr: unknown;\n const logger = log().child({ module: 'AnamAPI' });\n\n for (let attempt = 0; attempt < maxRetry; attempt++) {\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headersIn,\n };\n\n const redactedHeaders: Record<string, string> = { ...headers };\n if (redactedHeaders.Authorization) {\n redactedHeaders.Authorization = 'Bearer ****';\n }\n const redactedBody = (() => {\n if (body && typeof body === 'object') {\n try {\n const clone = { ...(body as Record<string, unknown>) } as Record<string, unknown>;\n if ('livekitToken' in clone) clone.livekitToken = '****';\n if ('sessionToken' in clone) clone.sessionToken = '****' as unknown as never;\n return clone;\n } catch {\n return { note: 'unserializable body' };\n }\n }\n return body;\n })();\n\n logger.debug(\n {\n url,\n method: 'POST',\n headers: redactedHeaders,\n body: redactedBody,\n attempt: attempt + 1,\n },\n 'calling Anam API',\n );\n\n const res = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n // simple timeout: rely on AbortController in real impl\n });\n if (!res.ok) {\n const text = await res.text();\n logger.error(\n {\n url,\n method: 'POST',\n headers: redactedHeaders,\n body: redactedBody,\n status: res.status,\n response: text,\n },\n 'Anam API request failed',\n );\n throw new AnamException(`Anam ${path} failed: ${res.status} ${text}`);\n }\n const json = (await res.json()) as T;\n logger.debug({ url }, 'Anam API request succeeded');\n return json;\n } catch (e) {\n lastErr = e;\n if (attempt === maxRetry - 1) break;\n logger.warn(\n {\n url,\n method: 'POST',\n body:\n body && typeof body === 'object'\n ? { ...(body as Record<string, unknown>), livekitToken: '****' }\n : body,\n error: (e as Error)?.message,\n nextRetrySec: retryInterval,\n },\n 'Anam API error, retrying',\n );\n await new Promise((r) => setTimeout(r, retryInterval * 1000));\n }\n }\n throw lastErr instanceof Error ? lastErr : new AnamException('Anam API error');\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n return this.postWithHeaders<T>(path, body, { Authorization: `Bearer ${this.apiKey}` });\n }\n\n createSessionToken(params: {\n personaConfig: PersonaConfig;\n livekitUrl?: string;\n livekitToken?: string;\n sessionOptions?: SessionOptions;\n }) {\n const pc = params.personaConfig;\n // Anam's personaConfig is a `oneOf`: reference a previously created\n // (stateful) persona by `personaId` — the \"dev flow\" — or configure an\n // ephemeral persona inline with name/avatarId/llmId. The two are mutually\n // exclusive, so when a personaId is given we must not also send the\n // ephemeral fields.\n const personaPayload: Record<string, unknown> = pc.personaId\n ? { personaId: pc.personaId }\n : {\n type: 'ephemeral',\n name: pc.name,\n avatarId: pc.avatarId,\n llmId: 'CUSTOMER_CLIENT_V1',\n // Only forward the avatar model version when set; otherwise let Anam\n // fall back to the avatar's default model.\n ...(pc.avatarModel ? { avatarModel: pc.avatarModel } : {}),\n };\n\n const payload: Record<string, unknown> = {\n personaConfig: personaPayload,\n };\n payload.environment = {\n livekitUrl: params.livekitUrl,\n livekitToken: params.livekitToken,\n };\n\n if (\n params.sessionOptions &&\n (params.sessionOptions.videoWidth !== undefined ||\n params.sessionOptions.videoHeight !== undefined)\n ) {\n if (\n params.sessionOptions.videoWidth === undefined ||\n params.sessionOptions.videoHeight === undefined\n ) {\n throw new AnamException(\n 'videoWidth and videoHeight must be set together (both or neither)',\n );\n }\n payload.sessionOptions = {\n videoWidth: params.sessionOptions.videoWidth,\n videoHeight: params.sessionOptions.videoHeight,\n };\n }\n\n return this.post<{ sessionToken: string }>(this.tokenPath, payload);\n }\n\n startEngineSession(params: { sessionToken: string }) {\n return this.postWithHeaders<{ sessionId: string }>(\n this.startPath,\n {},\n { Authorization: `Bearer ${params.sessionToken}` },\n );\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/api.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type APIConnectOptions, type PersonaConfig } from './types.js';
|
|
1
|
+
import { type APIConnectOptions, type PersonaConfig, type SessionOptions } from './types.js';
|
|
2
|
+
/** @public */
|
|
2
3
|
export declare class AnamAPI {
|
|
3
4
|
private apiKey;
|
|
4
5
|
private apiUrl;
|
|
@@ -12,6 +13,7 @@ export declare class AnamAPI {
|
|
|
12
13
|
personaConfig: PersonaConfig;
|
|
13
14
|
livekitUrl?: string;
|
|
14
15
|
livekitToken?: string;
|
|
16
|
+
sessionOptions?: SessionOptions;
|
|
15
17
|
}): Promise<{
|
|
16
18
|
sessionToken: string;
|
|
17
19
|
}>;
|
package/dist/api.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type APIConnectOptions, type PersonaConfig } from './types.js';
|
|
1
|
+
import { type APIConnectOptions, type PersonaConfig, type SessionOptions } from './types.js';
|
|
2
|
+
/** @public */
|
|
2
3
|
export declare class AnamAPI {
|
|
3
4
|
private apiKey;
|
|
4
5
|
private apiUrl;
|
|
@@ -12,6 +13,7 @@ export declare class AnamAPI {
|
|
|
12
13
|
personaConfig: PersonaConfig;
|
|
13
14
|
livekitUrl?: string;
|
|
14
15
|
livekitToken?: string;
|
|
16
|
+
sessionOptions?: SessionOptions;
|
|
15
17
|
}): Promise<{
|
|
16
18
|
sessionToken: string;
|
|
17
19
|
}>;
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAIpB,cAAc;AACd,qBAAa,OAAO;IAEhB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;gBAFJ,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAwB,EAChC,IAAI,GAAE,iBAAkE;IAGlF,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,SAAS,GAEpB;YAEa,eAAe;YA4Ff,IAAI;IAIlB,kBAAkB,CAAC,MAAM,EAAE;QACzB,aAAa,EAAE,aAAa,CAAC;QAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,cAAc,CAAC;KACjC;sBA8CkC,MAAM;;IAGzC,kBAAkB,CAAC,MAAM,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE;mBACR,MAAM;;CAMlD"}
|
package/dist/api.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { log } from "@livekit/agents";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AnamException
|
|
4
|
+
} from "./types.js";
|
|
3
5
|
const DEFAULT_API_URL = "https://api.anam.ai";
|
|
4
6
|
class AnamAPI {
|
|
5
7
|
constructor(apiKey, apiUrl = DEFAULT_API_URL, conn = { maxRetry: 3, retryInterval: 2, timeout: 10 }) {
|
|
@@ -98,11 +100,14 @@ class AnamAPI {
|
|
|
98
100
|
}
|
|
99
101
|
createSessionToken(params) {
|
|
100
102
|
const pc = params.personaConfig;
|
|
101
|
-
const personaPayload = {
|
|
103
|
+
const personaPayload = pc.personaId ? { personaId: pc.personaId } : {
|
|
102
104
|
type: "ephemeral",
|
|
103
105
|
name: pc.name,
|
|
104
106
|
avatarId: pc.avatarId,
|
|
105
|
-
llmId: "CUSTOMER_CLIENT_V1"
|
|
107
|
+
llmId: "CUSTOMER_CLIENT_V1",
|
|
108
|
+
// Only forward the avatar model version when set; otherwise let Anam
|
|
109
|
+
// fall back to the avatar's default model.
|
|
110
|
+
...pc.avatarModel ? { avatarModel: pc.avatarModel } : {}
|
|
106
111
|
};
|
|
107
112
|
const payload = {
|
|
108
113
|
personaConfig: personaPayload
|
|
@@ -111,6 +116,17 @@ class AnamAPI {
|
|
|
111
116
|
livekitUrl: params.livekitUrl,
|
|
112
117
|
livekitToken: params.livekitToken
|
|
113
118
|
};
|
|
119
|
+
if (params.sessionOptions && (params.sessionOptions.videoWidth !== void 0 || params.sessionOptions.videoHeight !== void 0)) {
|
|
120
|
+
if (params.sessionOptions.videoWidth === void 0 || params.sessionOptions.videoHeight === void 0) {
|
|
121
|
+
throw new AnamException(
|
|
122
|
+
"videoWidth and videoHeight must be set together (both or neither)"
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
payload.sessionOptions = {
|
|
126
|
+
videoWidth: params.sessionOptions.videoWidth,
|
|
127
|
+
videoHeight: params.sessionOptions.videoHeight
|
|
128
|
+
};
|
|
129
|
+
}
|
|
114
130
|
return this.post(this.tokenPath, payload);
|
|
115
131
|
}
|
|
116
132
|
startEngineSession(params) {
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log } from '@livekit/agents';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/api.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log } from '@livekit/agents';\nimport {\n type APIConnectOptions,\n AnamException,\n type PersonaConfig,\n type SessionOptions,\n} from './types.js';\n\nconst DEFAULT_API_URL = 'https://api.anam.ai';\n\n/** @public */\nexport class AnamAPI {\n constructor(\n private apiKey: string,\n private apiUrl: string = DEFAULT_API_URL,\n private conn: APIConnectOptions = { maxRetry: 3, retryInterval: 2, timeout: 10 },\n ) {}\n\n private get tokenPath(): string {\n return '/v1/auth/session-token';\n }\n\n private get startPath(): string {\n return '/v1/engine/session';\n }\n\n private async postWithHeaders<T>(\n path: string,\n body: unknown,\n headersIn: Record<string, string>,\n ): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const { maxRetry = 3, retryInterval = 2 } = this.conn;\n let lastErr: unknown;\n const logger = log().child({ module: 'AnamAPI' });\n\n for (let attempt = 0; attempt < maxRetry; attempt++) {\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headersIn,\n };\n\n const redactedHeaders: Record<string, string> = { ...headers };\n if (redactedHeaders.Authorization) {\n redactedHeaders.Authorization = 'Bearer ****';\n }\n const redactedBody = (() => {\n if (body && typeof body === 'object') {\n try {\n const clone = { ...(body as Record<string, unknown>) } as Record<string, unknown>;\n if ('livekitToken' in clone) clone.livekitToken = '****';\n if ('sessionToken' in clone) clone.sessionToken = '****' as unknown as never;\n return clone;\n } catch {\n return { note: 'unserializable body' };\n }\n }\n return body;\n })();\n\n logger.debug(\n {\n url,\n method: 'POST',\n headers: redactedHeaders,\n body: redactedBody,\n attempt: attempt + 1,\n },\n 'calling Anam API',\n );\n\n const res = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n // simple timeout: rely on AbortController in real impl\n });\n if (!res.ok) {\n const text = await res.text();\n logger.error(\n {\n url,\n method: 'POST',\n headers: redactedHeaders,\n body: redactedBody,\n status: res.status,\n response: text,\n },\n 'Anam API request failed',\n );\n throw new AnamException(`Anam ${path} failed: ${res.status} ${text}`);\n }\n const json = (await res.json()) as T;\n logger.debug({ url }, 'Anam API request succeeded');\n return json;\n } catch (e) {\n lastErr = e;\n if (attempt === maxRetry - 1) break;\n logger.warn(\n {\n url,\n method: 'POST',\n body:\n body && typeof body === 'object'\n ? { ...(body as Record<string, unknown>), livekitToken: '****' }\n : body,\n error: (e as Error)?.message,\n nextRetrySec: retryInterval,\n },\n 'Anam API error, retrying',\n );\n await new Promise((r) => setTimeout(r, retryInterval * 1000));\n }\n }\n throw lastErr instanceof Error ? lastErr : new AnamException('Anam API error');\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n return this.postWithHeaders<T>(path, body, { Authorization: `Bearer ${this.apiKey}` });\n }\n\n createSessionToken(params: {\n personaConfig: PersonaConfig;\n livekitUrl?: string;\n livekitToken?: string;\n sessionOptions?: SessionOptions;\n }) {\n const pc = params.personaConfig;\n // Anam's personaConfig is a `oneOf`: reference a previously created\n // (stateful) persona by `personaId` — the \"dev flow\" — or configure an\n // ephemeral persona inline with name/avatarId/llmId. The two are mutually\n // exclusive, so when a personaId is given we must not also send the\n // ephemeral fields.\n const personaPayload: Record<string, unknown> = pc.personaId\n ? { personaId: pc.personaId }\n : {\n type: 'ephemeral',\n name: pc.name,\n avatarId: pc.avatarId,\n llmId: 'CUSTOMER_CLIENT_V1',\n // Only forward the avatar model version when set; otherwise let Anam\n // fall back to the avatar's default model.\n ...(pc.avatarModel ? { avatarModel: pc.avatarModel } : {}),\n };\n\n const payload: Record<string, unknown> = {\n personaConfig: personaPayload,\n };\n payload.environment = {\n livekitUrl: params.livekitUrl,\n livekitToken: params.livekitToken,\n };\n\n if (\n params.sessionOptions &&\n (params.sessionOptions.videoWidth !== undefined ||\n params.sessionOptions.videoHeight !== undefined)\n ) {\n if (\n params.sessionOptions.videoWidth === undefined ||\n params.sessionOptions.videoHeight === undefined\n ) {\n throw new AnamException(\n 'videoWidth and videoHeight must be set together (both or neither)',\n );\n }\n payload.sessionOptions = {\n videoWidth: params.sessionOptions.videoWidth,\n videoHeight: params.sessionOptions.videoHeight,\n };\n }\n\n return this.post<{ sessionToken: string }>(this.tokenPath, payload);\n }\n\n startEngineSession(params: { sessionToken: string }) {\n return this.postWithHeaders<{ sessionId: string }>(\n this.startPath,\n {},\n { Authorization: `Bearer ${params.sessionToken}` },\n );\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/avatar.cjs
CHANGED
|
@@ -59,7 +59,7 @@ class AvatarSession extends import_agents.voice.AvatarSession {
|
|
|
59
59
|
return "anam";
|
|
60
60
|
}
|
|
61
61
|
async start(agentSession, room, params) {
|
|
62
|
-
var _a, _b, _c
|
|
62
|
+
var _a, _b, _c;
|
|
63
63
|
await super.start(agentSession, room);
|
|
64
64
|
const logger = (0, import_agents.log)().child({ module: "AnamAvatar" });
|
|
65
65
|
const apiKey = this.opts.apiKey ?? process.env.ANAM_API_KEY;
|
|
@@ -76,6 +76,7 @@ class AvatarSession extends import_agents.voice.AvatarSession {
|
|
|
76
76
|
{
|
|
77
77
|
personaName: (_a = this.opts.personaConfig) == null ? void 0 : _a.name,
|
|
78
78
|
avatarId: (_b = this.opts.personaConfig) == null ? void 0 : _b.avatarId,
|
|
79
|
+
personaId: (_c = this.opts.personaConfig) == null ? void 0 : _c.personaId,
|
|
79
80
|
apiUrl: apiUrl ?? "(default https://api.anam.ai)",
|
|
80
81
|
livekitUrl,
|
|
81
82
|
avatarParticipantIdentity: this.opts.avatarParticipantIdentity ?? "anam-avatar-agent",
|
|
@@ -93,12 +94,10 @@ class AvatarSession extends import_agents.voice.AvatarSession {
|
|
|
93
94
|
const anam = new import_api.AnamAPI(apiKey, apiUrl, this.opts.connOptions);
|
|
94
95
|
logger.debug({ livekitUrl }, "requesting Anam session token");
|
|
95
96
|
const { sessionToken } = await anam.createSessionToken({
|
|
96
|
-
personaConfig:
|
|
97
|
-
name: (_c = this.opts.personaConfig) == null ? void 0 : _c.name,
|
|
98
|
-
avatarId: (_d = this.opts.personaConfig) == null ? void 0 : _d.avatarId
|
|
99
|
-
},
|
|
97
|
+
personaConfig: this.opts.personaConfig,
|
|
100
98
|
livekitUrl,
|
|
101
|
-
livekitToken: jwt
|
|
99
|
+
livekitToken: jwt,
|
|
100
|
+
sessionOptions: this.opts.sessionOptions
|
|
102
101
|
});
|
|
103
102
|
logger.debug("starting Anam engine session");
|
|
104
103
|
const started = await anam.startEngineSession({ sessionToken });
|
package/dist/avatar.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/avatar.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log, voice } from '@livekit/agents';\nimport type { Room } from '@livekit/rtc-node';\nimport { TrackKind } from '@livekit/rtc-node';\nimport { AccessToken, type VideoGrant } from 'livekit-server-sdk';\nimport { AnamAPI } from './api.js';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/avatar.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log, voice } from '@livekit/agents';\nimport type { Room } from '@livekit/rtc-node';\nimport { TrackKind } from '@livekit/rtc-node';\nimport { AccessToken, type VideoGrant } from 'livekit-server-sdk';\nimport { AnamAPI } from './api.js';\nimport {\n type APIConnectOptions,\n AnamException,\n type PersonaConfig,\n type SessionOptions,\n} from './types.js';\n\n/** @public */\nexport async function mintAvatarJoinToken({\n roomName,\n avatarIdentity,\n publishOnBehalf,\n apiKey = process.env.LIVEKIT_API_KEY!,\n apiSecret = process.env.LIVEKIT_API_SECRET!,\n ttl = '60s',\n}: {\n roomName: string;\n avatarIdentity: string;\n publishOnBehalf: string;\n apiKey?: string;\n apiSecret?: string;\n ttl?: string | number;\n}): Promise<string> {\n const at = new AccessToken(apiKey, apiSecret);\n at.identity = avatarIdentity;\n at.name = 'Anam Avatar';\n at.kind = 'agent';\n at.ttl = ttl;\n at.attributes = { 'lk.publish_on_behalf': publishOnBehalf };\n\n at.addGrant({ roomJoin: true, room: roomName } as VideoGrant);\n return at.toJwt();\n}\n\nconst AVATAR_IDENTITY = 'anam-avatar-agent';\nconst _AVATAR_NAME = 'anam-avatar-agent';\n\n/** @public */\nexport class AvatarSession extends voice.AvatarSession {\n private sessionId?: string;\n\n constructor(\n private opts: {\n personaConfig: PersonaConfig;\n sessionOptions?: SessionOptions;\n apiUrl?: string;\n apiKey?: string;\n avatarParticipantIdentity?: string;\n avatarParticipantName?: string;\n connOptions?: APIConnectOptions;\n },\n ) {\n super();\n }\n\n override get avatarIdentity(): string {\n return this.opts.avatarParticipantIdentity ?? AVATAR_IDENTITY;\n }\n\n override get provider(): string {\n return 'anam';\n }\n\n async start(\n agentSession: voice.AgentSession,\n room: Room,\n params?: {\n livekitUrl?: string;\n livekitApiKey?: string;\n livekitApiSecret?: string;\n },\n ) {\n await super.start(agentSession, room);\n\n const logger = log().child({ module: 'AnamAvatar' });\n const apiKey = this.opts.apiKey ?? process.env.ANAM_API_KEY;\n if (!apiKey) throw new AnamException('ANAM_API_KEY is required');\n\n const apiUrl = this.opts.apiUrl ?? process.env.ANAM_API_URL;\n const livekitUrl = params?.livekitUrl ?? process.env.LIVEKIT_URL;\n const lkKey = params?.livekitApiKey ?? process.env.LIVEKIT_API_KEY;\n const lkSecret = params?.livekitApiSecret ?? process.env.LIVEKIT_API_SECRET;\n\n if (!livekitUrl || !lkKey || !lkSecret) {\n throw new AnamException('LIVEKIT_URL/API_KEY/API_SECRET must be set');\n }\n\n const localIdentity = (room.localParticipant && room.localParticipant.identity) || 'agent';\n\n logger.debug(\n {\n personaName: this.opts.personaConfig?.name,\n avatarId: this.opts.personaConfig?.avatarId,\n personaId: this.opts.personaConfig?.personaId,\n apiUrl: apiUrl ?? '(default https://api.anam.ai)',\n livekitUrl,\n avatarParticipantIdentity: this.opts.avatarParticipantIdentity ?? 'anam-avatar-agent',\n publishOnBehalf: localIdentity,\n },\n 'starting Anam avatar session',\n );\n\n const jwt = await mintAvatarJoinToken({\n roomName: room.name!,\n avatarIdentity: this.avatarIdentity,\n publishOnBehalf: localIdentity,\n apiKey: lkKey,\n apiSecret: lkSecret,\n });\n\n const anam = new AnamAPI(apiKey, apiUrl, this.opts.connOptions);\n logger.debug({ livekitUrl }, 'requesting Anam session token');\n\n const { sessionToken } = await anam.createSessionToken({\n personaConfig: this.opts.personaConfig,\n livekitUrl,\n livekitToken: jwt,\n sessionOptions: this.opts.sessionOptions,\n });\n logger.debug('starting Anam engine session');\n const started = await anam.startEngineSession({ sessionToken });\n this.sessionId = started.sessionId;\n\n agentSession.output.audio = new voice.DataStreamAudioOutput({\n room,\n destinationIdentity: this.avatarIdentity,\n waitRemoteTrack: TrackKind.KIND_VIDEO,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,oBAA2B;AAE3B,sBAA0B;AAC1B,gCAA6C;AAC7C,iBAAwB;AACxB,mBAKO;AAGP,eAAsB,oBAAoB;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,QAAQ,IAAI;AAAA,EACrB,YAAY,QAAQ,IAAI;AAAA,EACxB,MAAM;AACR,GAOoB;AAClB,QAAM,KAAK,IAAI,sCAAY,QAAQ,SAAS;AAC5C,KAAG,WAAW;AACd,KAAG,OAAO;AACV,KAAG,OAAO;AACV,KAAG,MAAM;AACT,KAAG,aAAa,EAAE,wBAAwB,gBAAgB;AAE1D,KAAG,SAAS,EAAE,UAAU,MAAM,MAAM,SAAS,CAAe;AAC5D,SAAO,GAAG,MAAM;AAClB;AAEA,MAAM,kBAAkB;AACxB,MAAM,eAAe;AAGd,MAAM,sBAAsB,oBAAM,cAAc;AAAA,EAGrD,YACU,MASR;AACA,UAAM;AAVE;AAAA,EAWV;AAAA,EAdQ;AAAA,EAgBR,IAAa,iBAAyB;AACpC,WAAO,KAAK,KAAK,6BAA6B;AAAA,EAChD;AAAA,EAEA,IAAa,WAAmB;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MACJ,cACA,MACA,QAKA;AA/EJ;AAgFI,UAAM,MAAM,MAAM,cAAc,IAAI;AAEpC,UAAM,aAAS,mBAAI,EAAE,MAAM,EAAE,QAAQ,aAAa,CAAC;AACnD,UAAM,SAAS,KAAK,KAAK,UAAU,QAAQ,IAAI;AAC/C,QAAI,CAAC,OAAQ,OAAM,IAAI,2BAAc,0BAA0B;AAE/D,UAAM,SAAS,KAAK,KAAK,UAAU,QAAQ,IAAI;AAC/C,UAAM,cAAa,iCAAQ,eAAc,QAAQ,IAAI;AACrD,UAAM,SAAQ,iCAAQ,kBAAiB,QAAQ,IAAI;AACnD,UAAM,YAAW,iCAAQ,qBAAoB,QAAQ,IAAI;AAEzD,QAAI,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU;AACtC,YAAM,IAAI,2BAAc,4CAA4C;AAAA,IACtE;AAEA,UAAM,gBAAiB,KAAK,oBAAoB,KAAK,iBAAiB,YAAa;AAEnF,WAAO;AAAA,MACL;AAAA,QACE,cAAa,UAAK,KAAK,kBAAV,mBAAyB;AAAA,QACtC,WAAU,UAAK,KAAK,kBAAV,mBAAyB;AAAA,QACnC,YAAW,UAAK,KAAK,kBAAV,mBAAyB;AAAA,QACpC,QAAQ,UAAU;AAAA,QAClB;AAAA,QACA,2BAA2B,KAAK,KAAK,6BAA6B;AAAA,QAClE,iBAAiB;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AAEA,UAAM,MAAM,MAAM,oBAAoB;AAAA,MACpC,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,iBAAiB;AAAA,MACjB,QAAQ;AAAA,MACR,WAAW;AAAA,IACb,CAAC;AAED,UAAM,OAAO,IAAI,mBAAQ,QAAQ,QAAQ,KAAK,KAAK,WAAW;AAC9D,WAAO,MAAM,EAAE,WAAW,GAAG,+BAA+B;AAE5D,UAAM,EAAE,aAAa,IAAI,MAAM,KAAK,mBAAmB;AAAA,MACrD,eAAe,KAAK,KAAK;AAAA,MACzB;AAAA,MACA,cAAc;AAAA,MACd,gBAAgB,KAAK,KAAK;AAAA,IAC5B,CAAC;AACD,WAAO,MAAM,8BAA8B;AAC3C,UAAM,UAAU,MAAM,KAAK,mBAAmB,EAAE,aAAa,CAAC;AAC9D,SAAK,YAAY,QAAQ;AAEzB,iBAAa,OAAO,QAAQ,IAAI,oBAAM,sBAAsB;AAAA,MAC1D;AAAA,MACA,qBAAqB,KAAK;AAAA,MAC1B,iBAAiB,0BAAU;AAAA,IAC7B,CAAC;AAAA,EACH;AACF;","names":[]}
|
package/dist/avatar.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { voice } from '@livekit/agents';
|
|
2
2
|
import type { Room } from '@livekit/rtc-node';
|
|
3
|
-
import { type APIConnectOptions, type PersonaConfig } from './types.js';
|
|
3
|
+
import { type APIConnectOptions, type PersonaConfig, type SessionOptions } from './types.js';
|
|
4
|
+
/** @public */
|
|
4
5
|
export declare function mintAvatarJoinToken({ roomName, avatarIdentity, publishOnBehalf, apiKey, apiSecret, ttl, }: {
|
|
5
6
|
roomName: string;
|
|
6
7
|
avatarIdentity: string;
|
|
@@ -9,11 +10,13 @@ export declare function mintAvatarJoinToken({ roomName, avatarIdentity, publishO
|
|
|
9
10
|
apiSecret?: string;
|
|
10
11
|
ttl?: string | number;
|
|
11
12
|
}): Promise<string>;
|
|
13
|
+
/** @public */
|
|
12
14
|
export declare class AvatarSession extends voice.AvatarSession {
|
|
13
15
|
private opts;
|
|
14
16
|
private sessionId?;
|
|
15
17
|
constructor(opts: {
|
|
16
18
|
personaConfig: PersonaConfig;
|
|
19
|
+
sessionOptions?: SessionOptions;
|
|
17
20
|
apiUrl?: string;
|
|
18
21
|
apiKey?: string;
|
|
19
22
|
avatarParticipantIdentity?: string;
|
package/dist/avatar.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { voice } from '@livekit/agents';
|
|
2
2
|
import type { Room } from '@livekit/rtc-node';
|
|
3
|
-
import { type APIConnectOptions, type PersonaConfig } from './types.js';
|
|
3
|
+
import { type APIConnectOptions, type PersonaConfig, type SessionOptions } from './types.js';
|
|
4
|
+
/** @public */
|
|
4
5
|
export declare function mintAvatarJoinToken({ roomName, avatarIdentity, publishOnBehalf, apiKey, apiSecret, ttl, }: {
|
|
5
6
|
roomName: string;
|
|
6
7
|
avatarIdentity: string;
|
|
@@ -9,11 +10,13 @@ export declare function mintAvatarJoinToken({ roomName, avatarIdentity, publishO
|
|
|
9
10
|
apiSecret?: string;
|
|
10
11
|
ttl?: string | number;
|
|
11
12
|
}): Promise<string>;
|
|
13
|
+
/** @public */
|
|
12
14
|
export declare class AvatarSession extends voice.AvatarSession {
|
|
13
15
|
private opts;
|
|
14
16
|
private sessionId?;
|
|
15
17
|
constructor(opts: {
|
|
16
18
|
personaConfig: PersonaConfig;
|
|
19
|
+
sessionOptions?: SessionOptions;
|
|
17
20
|
apiUrl?: string;
|
|
18
21
|
apiKey?: string;
|
|
19
22
|
avatarParticipantIdentity?: string;
|
package/dist/avatar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../src/avatar.ts"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAI9C,OAAO,
|
|
1
|
+
{"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../src/avatar.ts"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAI9C,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAEpB,cAAc;AACd,wBAAsB,mBAAmB,CAAC,EACxC,QAAQ,EACR,cAAc,EACd,eAAe,EACf,MAAqC,EACrC,SAA2C,EAC3C,GAAW,GACZ,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,CAAC,CAUlB;AAKD,cAAc;AACd,qBAAa,aAAc,SAAQ,KAAK,CAAC,aAAa;IAIlD,OAAO,CAAC,IAAI;IAHd,OAAO,CAAC,SAAS,CAAC,CAAS;gBAGjB,IAAI,EAAE;QACZ,aAAa,EAAE,aAAa,CAAC;QAC7B,cAAc,CAAC,EAAE,cAAc,CAAC;QAChC,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,WAAW,CAAC,EAAE,iBAAiB,CAAC;KACjC;IAKH,IAAa,cAAc,IAAI,MAAM,CAEpC;IAED,IAAa,QAAQ,IAAI,MAAM,CAE9B;IAEK,KAAK,CACT,YAAY,EAAE,KAAK,CAAC,YAAY,EAChC,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B;CA2DJ"}
|
package/dist/avatar.js
CHANGED
|
@@ -2,7 +2,9 @@ import { log, voice } from "@livekit/agents";
|
|
|
2
2
|
import { TrackKind } from "@livekit/rtc-node";
|
|
3
3
|
import { AccessToken } from "livekit-server-sdk";
|
|
4
4
|
import { AnamAPI } from "./api.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
AnamException
|
|
7
|
+
} from "./types.js";
|
|
6
8
|
async function mintAvatarJoinToken({
|
|
7
9
|
roomName,
|
|
8
10
|
avatarIdentity,
|
|
@@ -35,7 +37,7 @@ class AvatarSession extends voice.AvatarSession {
|
|
|
35
37
|
return "anam";
|
|
36
38
|
}
|
|
37
39
|
async start(agentSession, room, params) {
|
|
38
|
-
var _a, _b, _c
|
|
40
|
+
var _a, _b, _c;
|
|
39
41
|
await super.start(agentSession, room);
|
|
40
42
|
const logger = log().child({ module: "AnamAvatar" });
|
|
41
43
|
const apiKey = this.opts.apiKey ?? process.env.ANAM_API_KEY;
|
|
@@ -52,6 +54,7 @@ class AvatarSession extends voice.AvatarSession {
|
|
|
52
54
|
{
|
|
53
55
|
personaName: (_a = this.opts.personaConfig) == null ? void 0 : _a.name,
|
|
54
56
|
avatarId: (_b = this.opts.personaConfig) == null ? void 0 : _b.avatarId,
|
|
57
|
+
personaId: (_c = this.opts.personaConfig) == null ? void 0 : _c.personaId,
|
|
55
58
|
apiUrl: apiUrl ?? "(default https://api.anam.ai)",
|
|
56
59
|
livekitUrl,
|
|
57
60
|
avatarParticipantIdentity: this.opts.avatarParticipantIdentity ?? "anam-avatar-agent",
|
|
@@ -69,12 +72,10 @@ class AvatarSession extends voice.AvatarSession {
|
|
|
69
72
|
const anam = new AnamAPI(apiKey, apiUrl, this.opts.connOptions);
|
|
70
73
|
logger.debug({ livekitUrl }, "requesting Anam session token");
|
|
71
74
|
const { sessionToken } = await anam.createSessionToken({
|
|
72
|
-
personaConfig:
|
|
73
|
-
name: (_c = this.opts.personaConfig) == null ? void 0 : _c.name,
|
|
74
|
-
avatarId: (_d = this.opts.personaConfig) == null ? void 0 : _d.avatarId
|
|
75
|
-
},
|
|
75
|
+
personaConfig: this.opts.personaConfig,
|
|
76
76
|
livekitUrl,
|
|
77
|
-
livekitToken: jwt
|
|
77
|
+
livekitToken: jwt,
|
|
78
|
+
sessionOptions: this.opts.sessionOptions
|
|
78
79
|
});
|
|
79
80
|
logger.debug("starting Anam engine session");
|
|
80
81
|
const started = await anam.startEngineSession({ sessionToken });
|
package/dist/avatar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/avatar.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log, voice } from '@livekit/agents';\nimport type { Room } from '@livekit/rtc-node';\nimport { TrackKind } from '@livekit/rtc-node';\nimport { AccessToken, type VideoGrant } from 'livekit-server-sdk';\nimport { AnamAPI } from './api.js';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/avatar.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { log, voice } from '@livekit/agents';\nimport type { Room } from '@livekit/rtc-node';\nimport { TrackKind } from '@livekit/rtc-node';\nimport { AccessToken, type VideoGrant } from 'livekit-server-sdk';\nimport { AnamAPI } from './api.js';\nimport {\n type APIConnectOptions,\n AnamException,\n type PersonaConfig,\n type SessionOptions,\n} from './types.js';\n\n/** @public */\nexport async function mintAvatarJoinToken({\n roomName,\n avatarIdentity,\n publishOnBehalf,\n apiKey = process.env.LIVEKIT_API_KEY!,\n apiSecret = process.env.LIVEKIT_API_SECRET!,\n ttl = '60s',\n}: {\n roomName: string;\n avatarIdentity: string;\n publishOnBehalf: string;\n apiKey?: string;\n apiSecret?: string;\n ttl?: string | number;\n}): Promise<string> {\n const at = new AccessToken(apiKey, apiSecret);\n at.identity = avatarIdentity;\n at.name = 'Anam Avatar';\n at.kind = 'agent';\n at.ttl = ttl;\n at.attributes = { 'lk.publish_on_behalf': publishOnBehalf };\n\n at.addGrant({ roomJoin: true, room: roomName } as VideoGrant);\n return at.toJwt();\n}\n\nconst AVATAR_IDENTITY = 'anam-avatar-agent';\nconst _AVATAR_NAME = 'anam-avatar-agent';\n\n/** @public */\nexport class AvatarSession extends voice.AvatarSession {\n private sessionId?: string;\n\n constructor(\n private opts: {\n personaConfig: PersonaConfig;\n sessionOptions?: SessionOptions;\n apiUrl?: string;\n apiKey?: string;\n avatarParticipantIdentity?: string;\n avatarParticipantName?: string;\n connOptions?: APIConnectOptions;\n },\n ) {\n super();\n }\n\n override get avatarIdentity(): string {\n return this.opts.avatarParticipantIdentity ?? AVATAR_IDENTITY;\n }\n\n override get provider(): string {\n return 'anam';\n }\n\n async start(\n agentSession: voice.AgentSession,\n room: Room,\n params?: {\n livekitUrl?: string;\n livekitApiKey?: string;\n livekitApiSecret?: string;\n },\n ) {\n await super.start(agentSession, room);\n\n const logger = log().child({ module: 'AnamAvatar' });\n const apiKey = this.opts.apiKey ?? process.env.ANAM_API_KEY;\n if (!apiKey) throw new AnamException('ANAM_API_KEY is required');\n\n const apiUrl = this.opts.apiUrl ?? process.env.ANAM_API_URL;\n const livekitUrl = params?.livekitUrl ?? process.env.LIVEKIT_URL;\n const lkKey = params?.livekitApiKey ?? process.env.LIVEKIT_API_KEY;\n const lkSecret = params?.livekitApiSecret ?? process.env.LIVEKIT_API_SECRET;\n\n if (!livekitUrl || !lkKey || !lkSecret) {\n throw new AnamException('LIVEKIT_URL/API_KEY/API_SECRET must be set');\n }\n\n const localIdentity = (room.localParticipant && room.localParticipant.identity) || 'agent';\n\n logger.debug(\n {\n personaName: this.opts.personaConfig?.name,\n avatarId: this.opts.personaConfig?.avatarId,\n personaId: this.opts.personaConfig?.personaId,\n apiUrl: apiUrl ?? '(default https://api.anam.ai)',\n livekitUrl,\n avatarParticipantIdentity: this.opts.avatarParticipantIdentity ?? 'anam-avatar-agent',\n publishOnBehalf: localIdentity,\n },\n 'starting Anam avatar session',\n );\n\n const jwt = await mintAvatarJoinToken({\n roomName: room.name!,\n avatarIdentity: this.avatarIdentity,\n publishOnBehalf: localIdentity,\n apiKey: lkKey,\n apiSecret: lkSecret,\n });\n\n const anam = new AnamAPI(apiKey, apiUrl, this.opts.connOptions);\n logger.debug({ livekitUrl }, 'requesting Anam session token');\n\n const { sessionToken } = await anam.createSessionToken({\n personaConfig: this.opts.personaConfig,\n livekitUrl,\n livekitToken: jwt,\n sessionOptions: this.opts.sessionOptions,\n });\n logger.debug('starting Anam engine session');\n const started = await anam.startEngineSession({ sessionToken });\n this.sessionId = started.sessionId;\n\n agentSession.output.audio = new voice.DataStreamAudioOutput({\n room,\n destinationIdentity: this.avatarIdentity,\n waitRemoteTrack: TrackKind.KIND_VIDEO,\n });\n }\n}\n"],"mappings":"AAGA,SAAS,KAAK,aAAa;AAE3B,SAAS,iBAAiB;AAC1B,SAAS,mBAAoC;AAC7C,SAAS,eAAe;AACxB;AAAA,EAEE;AAAA,OAGK;AAGP,eAAsB,oBAAoB;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,QAAQ,IAAI;AAAA,EACrB,YAAY,QAAQ,IAAI;AAAA,EACxB,MAAM;AACR,GAOoB;AAClB,QAAM,KAAK,IAAI,YAAY,QAAQ,SAAS;AAC5C,KAAG,WAAW;AACd,KAAG,OAAO;AACV,KAAG,OAAO;AACV,KAAG,MAAM;AACT,KAAG,aAAa,EAAE,wBAAwB,gBAAgB;AAE1D,KAAG,SAAS,EAAE,UAAU,MAAM,MAAM,SAAS,CAAe;AAC5D,SAAO,GAAG,MAAM;AAClB;AAEA,MAAM,kBAAkB;AACxB,MAAM,eAAe;AAGd,MAAM,sBAAsB,MAAM,cAAc;AAAA,EAGrD,YACU,MASR;AACA,UAAM;AAVE;AAAA,EAWV;AAAA,EAdQ;AAAA,EAgBR,IAAa,iBAAyB;AACpC,WAAO,KAAK,KAAK,6BAA6B;AAAA,EAChD;AAAA,EAEA,IAAa,WAAmB;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MACJ,cACA,MACA,QAKA;AA/EJ;AAgFI,UAAM,MAAM,MAAM,cAAc,IAAI;AAEpC,UAAM,SAAS,IAAI,EAAE,MAAM,EAAE,QAAQ,aAAa,CAAC;AACnD,UAAM,SAAS,KAAK,KAAK,UAAU,QAAQ,IAAI;AAC/C,QAAI,CAAC,OAAQ,OAAM,IAAI,cAAc,0BAA0B;AAE/D,UAAM,SAAS,KAAK,KAAK,UAAU,QAAQ,IAAI;AAC/C,UAAM,cAAa,iCAAQ,eAAc,QAAQ,IAAI;AACrD,UAAM,SAAQ,iCAAQ,kBAAiB,QAAQ,IAAI;AACnD,UAAM,YAAW,iCAAQ,qBAAoB,QAAQ,IAAI;AAEzD,QAAI,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU;AACtC,YAAM,IAAI,cAAc,4CAA4C;AAAA,IACtE;AAEA,UAAM,gBAAiB,KAAK,oBAAoB,KAAK,iBAAiB,YAAa;AAEnF,WAAO;AAAA,MACL;AAAA,QACE,cAAa,UAAK,KAAK,kBAAV,mBAAyB;AAAA,QACtC,WAAU,UAAK,KAAK,kBAAV,mBAAyB;AAAA,QACnC,YAAW,UAAK,KAAK,kBAAV,mBAAyB;AAAA,QACpC,QAAQ,UAAU;AAAA,QAClB;AAAA,QACA,2BAA2B,KAAK,KAAK,6BAA6B;AAAA,QAClE,iBAAiB;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AAEA,UAAM,MAAM,MAAM,oBAAoB;AAAA,MACpC,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,iBAAiB;AAAA,MACjB,QAAQ;AAAA,MACR,WAAW;AAAA,IACb,CAAC;AAED,UAAM,OAAO,IAAI,QAAQ,QAAQ,QAAQ,KAAK,KAAK,WAAW;AAC9D,WAAO,MAAM,EAAE,WAAW,GAAG,+BAA+B;AAE5D,UAAM,EAAE,aAAa,IAAI,MAAM,KAAK,mBAAmB;AAAA,MACrD,eAAe,KAAK,KAAK;AAAA,MACzB;AAAA,MACA,cAAc;AAAA,MACd,gBAAgB,KAAK,KAAK;AAAA,IAC5B,CAAC;AACD,WAAO,MAAM,8BAA8B;AAC3C,UAAM,UAAU,MAAM,KAAK,mBAAmB,EAAE,aAAa,CAAC;AAC9D,SAAK,YAAY,QAAQ;AAEzB,iBAAa,OAAO,QAAQ,IAAI,MAAM,sBAAsB;AAAA,MAC1D;AAAA,MACA,qBAAqB,KAAK;AAAA,MAC1B,iBAAiB,UAAU;AAAA,IAC7B,CAAC;AAAA,EACH;AACF;","names":[]}
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
package/dist/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport type PersonaConfig = {\n /** Optional display name (prod flow) */\n name?: string;\n /** Optional avatar asset id (prod flow) */\n avatarId?: string;\n /** Optional persona id (dev flow) */\n personaId?: string;\n};\n\nexport type APIConnectOptions = {\n maxRetry?: number;\n retryInterval?: number; // seconds\n timeout?: number; // seconds\n};\n\nexport class AnamException extends Error {}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n/** @public */\nexport type PersonaConfig = {\n /** Optional display name (prod flow) */\n name?: string;\n /** Optional avatar asset id (prod flow) */\n avatarId?: string;\n /** Optional avatar model version, e.g. \"cara-3\" or \"cara-4-latest\" (prod flow) */\n avatarModel?: string;\n /** Optional persona id (dev flow) */\n personaId?: string;\n};\n\n/** @public */\nexport type SessionOptions = {\n /** Output video frame width in pixels. Provide together with videoHeight. */\n videoWidth?: number;\n /** Output video frame height in pixels. Provide together with videoWidth. */\n videoHeight?: number;\n};\n\n/** @public */\nexport type APIConnectOptions = {\n maxRetry?: number;\n retryInterval?: number; // seconds\n timeout?: number; // seconds\n};\n\n/** @public */\nexport class AnamException extends Error {}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BO,MAAM,sBAAsB,MAAM;AAAC;","names":[]}
|
package/dist/types.d.cts
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
|
+
/** @public */
|
|
1
2
|
export type PersonaConfig = {
|
|
2
3
|
/** Optional display name (prod flow) */
|
|
3
4
|
name?: string;
|
|
4
5
|
/** Optional avatar asset id (prod flow) */
|
|
5
6
|
avatarId?: string;
|
|
7
|
+
/** Optional avatar model version, e.g. "cara-3" or "cara-4-latest" (prod flow) */
|
|
8
|
+
avatarModel?: string;
|
|
6
9
|
/** Optional persona id (dev flow) */
|
|
7
10
|
personaId?: string;
|
|
8
11
|
};
|
|
12
|
+
/** @public */
|
|
13
|
+
export type SessionOptions = {
|
|
14
|
+
/** Output video frame width in pixels. Provide together with videoHeight. */
|
|
15
|
+
videoWidth?: number;
|
|
16
|
+
/** Output video frame height in pixels. Provide together with videoWidth. */
|
|
17
|
+
videoHeight?: number;
|
|
18
|
+
};
|
|
19
|
+
/** @public */
|
|
9
20
|
export type APIConnectOptions = {
|
|
10
21
|
maxRetry?: number;
|
|
11
22
|
retryInterval?: number;
|
|
12
23
|
timeout?: number;
|
|
13
24
|
};
|
|
25
|
+
/** @public */
|
|
14
26
|
export declare class AnamException extends Error {
|
|
15
27
|
}
|
|
16
28
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
|
+
/** @public */
|
|
1
2
|
export type PersonaConfig = {
|
|
2
3
|
/** Optional display name (prod flow) */
|
|
3
4
|
name?: string;
|
|
4
5
|
/** Optional avatar asset id (prod flow) */
|
|
5
6
|
avatarId?: string;
|
|
7
|
+
/** Optional avatar model version, e.g. "cara-3" or "cara-4-latest" (prod flow) */
|
|
8
|
+
avatarModel?: string;
|
|
6
9
|
/** Optional persona id (dev flow) */
|
|
7
10
|
personaId?: string;
|
|
8
11
|
};
|
|
12
|
+
/** @public */
|
|
13
|
+
export type SessionOptions = {
|
|
14
|
+
/** Output video frame width in pixels. Provide together with videoHeight. */
|
|
15
|
+
videoWidth?: number;
|
|
16
|
+
/** Output video frame height in pixels. Provide together with videoWidth. */
|
|
17
|
+
videoHeight?: number;
|
|
18
|
+
};
|
|
19
|
+
/** @public */
|
|
9
20
|
export type APIConnectOptions = {
|
|
10
21
|
maxRetry?: number;
|
|
11
22
|
retryInterval?: number;
|
|
12
23
|
timeout?: number;
|
|
13
24
|
};
|
|
25
|
+
/** @public */
|
|
14
26
|
export declare class AnamException extends Error {
|
|
15
27
|
}
|
|
16
28
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG;IAC1B,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,aAAc,SAAQ,KAAK;CAAG"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,cAAc;AACd,MAAM,MAAM,aAAa,GAAG;IAC1B,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,cAAc;AACd,MAAM,MAAM,cAAc,GAAG;IAC3B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,cAAc;AACd,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,cAAc;AACd,qBAAa,aAAc,SAAQ,KAAK;CAAG"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport type PersonaConfig = {\n /** Optional display name (prod flow) */\n name?: string;\n /** Optional avatar asset id (prod flow) */\n avatarId?: string;\n /** Optional persona id (dev flow) */\n personaId?: string;\n};\n\nexport type APIConnectOptions = {\n maxRetry?: number;\n retryInterval?: number; // seconds\n timeout?: number; // seconds\n};\n\nexport class AnamException extends Error {}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n/** @public */\nexport type PersonaConfig = {\n /** Optional display name (prod flow) */\n name?: string;\n /** Optional avatar asset id (prod flow) */\n avatarId?: string;\n /** Optional avatar model version, e.g. \"cara-3\" or \"cara-4-latest\" (prod flow) */\n avatarModel?: string;\n /** Optional persona id (dev flow) */\n personaId?: string;\n};\n\n/** @public */\nexport type SessionOptions = {\n /** Output video frame width in pixels. Provide together with videoHeight. */\n videoWidth?: number;\n /** Output video frame height in pixels. Provide together with videoWidth. */\n videoHeight?: number;\n};\n\n/** @public */\nexport type APIConnectOptions = {\n maxRetry?: number;\n retryInterval?: number; // seconds\n timeout?: number; // seconds\n};\n\n/** @public */\nexport class AnamException extends Error {}\n"],"mappings":"AA+BO,MAAM,sBAAsB,MAAM;AAAC;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/agents-plugin-anam",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.11",
|
|
4
4
|
"description": "Anam plugin for LiveKit Node Agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"require": "dist/index.cjs",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"@types/ws": "^8.5.10",
|
|
31
31
|
"tsup": "^8.3.5",
|
|
32
32
|
"typescript": "^5.0.0",
|
|
33
|
-
"@livekit/agents": "1.4.
|
|
34
|
-
"@livekit/agents-plugin-openai": "1.4.
|
|
35
|
-
"@livekit/agents-plugins-test": "1.4.
|
|
33
|
+
"@livekit/agents": "1.4.11",
|
|
34
|
+
"@livekit/agents-plugin-openai": "1.4.11",
|
|
35
|
+
"@livekit/agents-plugins-test": "1.4.11"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"livekit-server-sdk": "^2.9.2",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@livekit/rtc-node": "^0.13.29",
|
|
43
|
-
"@livekit/agents": "1.4.
|
|
43
|
+
"@livekit/agents": "1.4.11"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsup --onSuccess \"pnpm build:types\"",
|
package/src/api.ts
CHANGED
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { log } from '@livekit/agents';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
type APIConnectOptions,
|
|
7
|
+
AnamException,
|
|
8
|
+
type PersonaConfig,
|
|
9
|
+
type SessionOptions,
|
|
10
|
+
} from './types.js';
|
|
6
11
|
|
|
7
12
|
const DEFAULT_API_URL = 'https://api.anam.ai';
|
|
8
13
|
|
|
14
|
+
/** @public */
|
|
9
15
|
export class AnamAPI {
|
|
10
16
|
constructor(
|
|
11
17
|
private apiKey: string,
|
|
@@ -121,14 +127,25 @@ export class AnamAPI {
|
|
|
121
127
|
personaConfig: PersonaConfig;
|
|
122
128
|
livekitUrl?: string;
|
|
123
129
|
livekitToken?: string;
|
|
130
|
+
sessionOptions?: SessionOptions;
|
|
124
131
|
}) {
|
|
125
132
|
const pc = params.personaConfig;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
// Anam's personaConfig is a `oneOf`: reference a previously created
|
|
134
|
+
// (stateful) persona by `personaId` — the "dev flow" — or configure an
|
|
135
|
+
// ephemeral persona inline with name/avatarId/llmId. The two are mutually
|
|
136
|
+
// exclusive, so when a personaId is given we must not also send the
|
|
137
|
+
// ephemeral fields.
|
|
138
|
+
const personaPayload: Record<string, unknown> = pc.personaId
|
|
139
|
+
? { personaId: pc.personaId }
|
|
140
|
+
: {
|
|
141
|
+
type: 'ephemeral',
|
|
142
|
+
name: pc.name,
|
|
143
|
+
avatarId: pc.avatarId,
|
|
144
|
+
llmId: 'CUSTOMER_CLIENT_V1',
|
|
145
|
+
// Only forward the avatar model version when set; otherwise let Anam
|
|
146
|
+
// fall back to the avatar's default model.
|
|
147
|
+
...(pc.avatarModel ? { avatarModel: pc.avatarModel } : {}),
|
|
148
|
+
};
|
|
132
149
|
|
|
133
150
|
const payload: Record<string, unknown> = {
|
|
134
151
|
personaConfig: personaPayload,
|
|
@@ -138,6 +155,25 @@ export class AnamAPI {
|
|
|
138
155
|
livekitToken: params.livekitToken,
|
|
139
156
|
};
|
|
140
157
|
|
|
158
|
+
if (
|
|
159
|
+
params.sessionOptions &&
|
|
160
|
+
(params.sessionOptions.videoWidth !== undefined ||
|
|
161
|
+
params.sessionOptions.videoHeight !== undefined)
|
|
162
|
+
) {
|
|
163
|
+
if (
|
|
164
|
+
params.sessionOptions.videoWidth === undefined ||
|
|
165
|
+
params.sessionOptions.videoHeight === undefined
|
|
166
|
+
) {
|
|
167
|
+
throw new AnamException(
|
|
168
|
+
'videoWidth and videoHeight must be set together (both or neither)',
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
payload.sessionOptions = {
|
|
172
|
+
videoWidth: params.sessionOptions.videoWidth,
|
|
173
|
+
videoHeight: params.sessionOptions.videoHeight,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
141
177
|
return this.post<{ sessionToken: string }>(this.tokenPath, payload);
|
|
142
178
|
}
|
|
143
179
|
|
package/src/avatar.ts
CHANGED
|
@@ -6,8 +6,14 @@ import type { Room } from '@livekit/rtc-node';
|
|
|
6
6
|
import { TrackKind } from '@livekit/rtc-node';
|
|
7
7
|
import { AccessToken, type VideoGrant } from 'livekit-server-sdk';
|
|
8
8
|
import { AnamAPI } from './api.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import {
|
|
10
|
+
type APIConnectOptions,
|
|
11
|
+
AnamException,
|
|
12
|
+
type PersonaConfig,
|
|
13
|
+
type SessionOptions,
|
|
14
|
+
} from './types.js';
|
|
15
|
+
|
|
16
|
+
/** @public */
|
|
11
17
|
export async function mintAvatarJoinToken({
|
|
12
18
|
roomName,
|
|
13
19
|
avatarIdentity,
|
|
@@ -37,12 +43,14 @@ export async function mintAvatarJoinToken({
|
|
|
37
43
|
const AVATAR_IDENTITY = 'anam-avatar-agent';
|
|
38
44
|
const _AVATAR_NAME = 'anam-avatar-agent';
|
|
39
45
|
|
|
46
|
+
/** @public */
|
|
40
47
|
export class AvatarSession extends voice.AvatarSession {
|
|
41
48
|
private sessionId?: string;
|
|
42
49
|
|
|
43
50
|
constructor(
|
|
44
51
|
private opts: {
|
|
45
52
|
personaConfig: PersonaConfig;
|
|
53
|
+
sessionOptions?: SessionOptions;
|
|
46
54
|
apiUrl?: string;
|
|
47
55
|
apiKey?: string;
|
|
48
56
|
avatarParticipantIdentity?: string;
|
|
@@ -91,6 +99,7 @@ export class AvatarSession extends voice.AvatarSession {
|
|
|
91
99
|
{
|
|
92
100
|
personaName: this.opts.personaConfig?.name,
|
|
93
101
|
avatarId: this.opts.personaConfig?.avatarId,
|
|
102
|
+
personaId: this.opts.personaConfig?.personaId,
|
|
94
103
|
apiUrl: apiUrl ?? '(default https://api.anam.ai)',
|
|
95
104
|
livekitUrl,
|
|
96
105
|
avatarParticipantIdentity: this.opts.avatarParticipantIdentity ?? 'anam-avatar-agent',
|
|
@@ -111,12 +120,10 @@ export class AvatarSession extends voice.AvatarSession {
|
|
|
111
120
|
logger.debug({ livekitUrl }, 'requesting Anam session token');
|
|
112
121
|
|
|
113
122
|
const { sessionToken } = await anam.createSessionToken({
|
|
114
|
-
personaConfig:
|
|
115
|
-
name: this.opts.personaConfig?.name,
|
|
116
|
-
avatarId: this.opts.personaConfig?.avatarId,
|
|
117
|
-
},
|
|
123
|
+
personaConfig: this.opts.personaConfig,
|
|
118
124
|
livekitUrl,
|
|
119
125
|
livekitToken: jwt,
|
|
126
|
+
sessionOptions: this.opts.sessionOptions,
|
|
120
127
|
});
|
|
121
128
|
logger.debug('starting Anam engine session');
|
|
122
129
|
const started = await anam.startEngineSession({ sessionToken });
|
package/src/types.ts
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2025 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
/** @public */
|
|
4
5
|
export type PersonaConfig = {
|
|
5
6
|
/** Optional display name (prod flow) */
|
|
6
7
|
name?: string;
|
|
7
8
|
/** Optional avatar asset id (prod flow) */
|
|
8
9
|
avatarId?: string;
|
|
10
|
+
/** Optional avatar model version, e.g. "cara-3" or "cara-4-latest" (prod flow) */
|
|
11
|
+
avatarModel?: string;
|
|
9
12
|
/** Optional persona id (dev flow) */
|
|
10
13
|
personaId?: string;
|
|
11
14
|
};
|
|
12
15
|
|
|
16
|
+
/** @public */
|
|
17
|
+
export type SessionOptions = {
|
|
18
|
+
/** Output video frame width in pixels. Provide together with videoHeight. */
|
|
19
|
+
videoWidth?: number;
|
|
20
|
+
/** Output video frame height in pixels. Provide together with videoWidth. */
|
|
21
|
+
videoHeight?: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** @public */
|
|
13
25
|
export type APIConnectOptions = {
|
|
14
26
|
maxRetry?: number;
|
|
15
27
|
retryInterval?: number; // seconds
|
|
16
28
|
timeout?: number; // seconds
|
|
17
29
|
};
|
|
18
30
|
|
|
31
|
+
/** @public */
|
|
19
32
|
export class AnamException extends Error {}
|