@securecoms/agent-bridge 0.25.2 → 0.25.3
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/bin.js +36 -7
- package/dist/bridge-agent.d.ts +14 -0
- package/dist/index.js +36 -7
- package/dist/version.d.ts +1 -1
- package/dist/voice/fast-prompt.d.ts +3 -0
- package/dist/voice/persona.d.ts +7 -1
- package/dist/voice/prompt-compiler.d.ts +8 -1
- package/dist/voice/settings.d.ts +6 -0
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -7436,10 +7436,10 @@ var HANDOFF = {
|
|
|
7436
7436
|
balanced: "If the message needs files, tools, memory lookups, current data, or any work you cannot do instantly, say in one sentence that you are checking and end your reply with the exact token [[DEFER]] so the full agent answers next. For greetings, small talk, and anything you can answer completely yourself, answer completely and do NOT add the token.",
|
|
7437
7437
|
self: "Answer yourself whenever you reasonably can. Only when the message clearly needs files, tools, or current data you cannot see, say in one sentence that you are checking and end your reply with the exact token [[DEFER]]."
|
|
7438
7438
|
};
|
|
7439
|
-
function compileVoicePrompt(s) {
|
|
7439
|
+
function compileVoicePrompt(s, agentName) {
|
|
7440
7440
|
const parts = [];
|
|
7441
7441
|
const persona = s.persona.trim();
|
|
7442
|
-
const displayName =
|
|
7442
|
+
const displayName = (agentName ?? "").trim();
|
|
7443
7443
|
if (displayName && !persona.toLowerCase().includes(displayName.toLowerCase())) {
|
|
7444
7444
|
parts.push(`You are ${displayName}.`);
|
|
7445
7445
|
}
|
|
@@ -7491,6 +7491,9 @@ var Row = z.object({
|
|
|
7491
7491
|
voice_id: z.string().nullable().optional(),
|
|
7492
7492
|
pace: z.enum(PACES).default("normal"),
|
|
7493
7493
|
display_name: z.string().max(40).default(""),
|
|
7494
|
+
// Owner decision 2026-10-01 ("one name"). Lenient: a bad value is dropped
|
|
7495
|
+
// (see identityName below), never a reason to reject the whole row.
|
|
7496
|
+
identity_display_name: z.unknown().optional(),
|
|
7494
7497
|
persona: z.string().max(600).default(""),
|
|
7495
7498
|
warmth: z.enum(WARMTHS).default("friendly"),
|
|
7496
7499
|
formality: z.enum(FORMALITIES).default("neutral"),
|
|
@@ -7501,8 +7504,14 @@ var Row = z.object({
|
|
|
7501
7504
|
avoid_topics: z.array(z.string().max(80)).max(10).default([]),
|
|
7502
7505
|
handoff: z.enum(HANDOFFS).default("balanced")
|
|
7503
7506
|
}).passthrough();
|
|
7507
|
+
function identityName(v) {
|
|
7508
|
+
if (typeof v !== "string") return void 0;
|
|
7509
|
+
const name = v.trim();
|
|
7510
|
+
return name && name.length <= 200 ? name : void 0;
|
|
7511
|
+
}
|
|
7504
7512
|
function parseVoiceSettings(raw) {
|
|
7505
7513
|
const r = Row.parse(raw);
|
|
7514
|
+
const identityDisplayName = identityName(r.identity_display_name);
|
|
7506
7515
|
return {
|
|
7507
7516
|
version: r.version,
|
|
7508
7517
|
voiceId: r.voice_id ?? null,
|
|
@@ -7516,7 +7525,8 @@ function parseVoiceSettings(raw) {
|
|
|
7516
7525
|
quirks: r.quirks,
|
|
7517
7526
|
greetingStyle: r.greeting_style,
|
|
7518
7527
|
avoidTopics: r.avoid_topics,
|
|
7519
|
-
handoff: r.handoff
|
|
7528
|
+
handoff: r.handoff,
|
|
7529
|
+
...identityDisplayName ? { identityDisplayName } : {}
|
|
7520
7530
|
};
|
|
7521
7531
|
}
|
|
7522
7532
|
function settingsToVoiceConfig(s, proxy) {
|
|
@@ -7577,10 +7587,11 @@ function parseVoiceConfig(raw, env) {
|
|
|
7577
7587
|
}
|
|
7578
7588
|
};
|
|
7579
7589
|
}
|
|
7580
|
-
function systemPrompt(p, settings) {
|
|
7590
|
+
function systemPrompt(p, settings, agentName) {
|
|
7581
7591
|
const core = p.persona.trim().endsWith(CONTINUITY_CLAUSE) ? p.persona.trim().slice(0, -CONTINUITY_CLAUSE.length).trim() : p.persona.trim();
|
|
7582
7592
|
return compileVoicePrompt(
|
|
7583
|
-
settings ?? { ...DEFAULT_VOICE_SETTINGS,
|
|
7593
|
+
settings ?? { ...DEFAULT_VOICE_SETTINGS, persona: core, quirks: p.quirks },
|
|
7594
|
+
agentName
|
|
7584
7595
|
);
|
|
7585
7596
|
}
|
|
7586
7597
|
|
|
@@ -28350,7 +28361,7 @@ function clampContent(content, max = MAX_MESSAGE_CHARS) {
|
|
|
28350
28361
|
}
|
|
28351
28362
|
function buildFastMessages(args2) {
|
|
28352
28363
|
const cap = args2.charCap ?? 4e3;
|
|
28353
|
-
const sp = systemPrompt(args2.persona, args2.settings);
|
|
28364
|
+
const sp = systemPrompt(args2.persona, args2.settings, args2.agentName);
|
|
28354
28365
|
const head = sp.slice(0, sp.length - CONTINUITY_CLAUSE.length).trimEnd();
|
|
28355
28366
|
const system = `${head} ${args2.guidance.trim()} ${CONTINUITY_CLAUSE}`;
|
|
28356
28367
|
const recent = args2.memory.recent.map((t) => ({
|
|
@@ -29250,6 +29261,12 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
29250
29261
|
* `roomDisplayName`. Kept across a later failed refresh, so a transient
|
|
29251
29262
|
* members-fetch error does not make the agent deaf to its own name; a
|
|
29252
29263
|
* successful refresh after a rename replaces it.
|
|
29264
|
+
*
|
|
29265
|
+
* 2026-10-01 ("one name"): also the name the voice fast path speaks as
|
|
29266
|
+
* ("You are <name>."). A voice settings fetch that carries
|
|
29267
|
+
* `identity_display_name` writes it too (the backend pings
|
|
29268
|
+
* `voice_settings_changed` on a rename), so the latest observation from
|
|
29269
|
+
* either source wins; both read the same identity column.
|
|
29253
29270
|
*/
|
|
29254
29271
|
lastOwnDisplayName;
|
|
29255
29272
|
/**
|
|
@@ -29653,6 +29670,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
29653
29670
|
const res = await this.fetchBounded("voice_settings", "read", url, { headers: { authorization: `Bearer ${this.cfg.apiKey}` } });
|
|
29654
29671
|
if (!res.ok) throw new Error(`voice-settings ${res.status}`);
|
|
29655
29672
|
const s = parseVoiceSettings(await res.json());
|
|
29673
|
+
if (s.identityDisplayName) this.lastOwnDisplayName = s.identityDisplayName;
|
|
29656
29674
|
const proxy = settingsToVoiceConfig(s, { baseUrl: this.cfg.apiBase, apiKey: this.cfg.apiKey });
|
|
29657
29675
|
if (s.version === 0 && this.fileVoiceConfig) {
|
|
29658
29676
|
const merged = {
|
|
@@ -31550,7 +31568,8 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
31550
31568
|
memory,
|
|
31551
31569
|
speaker,
|
|
31552
31570
|
text,
|
|
31553
|
-
settings: this.voiceSettings ?? void 0
|
|
31571
|
+
settings: this.voiceSettings ?? void 0,
|
|
31572
|
+
agentName: this.voiceAgentName()
|
|
31554
31573
|
});
|
|
31555
31574
|
const maxSentences = this.voiceSettings?.brevity === "one" ? 1 : 2;
|
|
31556
31575
|
const { reply, defer } = splitFastReply(await this.fastLlm.complete(messages), 200, maxSentences);
|
|
@@ -32857,6 +32876,16 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
32857
32876
|
ownRoomDisplayName() {
|
|
32858
32877
|
return this.lastOwnDisplayName;
|
|
32859
32878
|
}
|
|
32879
|
+
/**
|
|
32880
|
+
* 2026-10-01 (owner decision, "one name"): the name the voice prompt uses.
|
|
32881
|
+
* The agent's CURRENT identity display name (roster or voice settings
|
|
32882
|
+
* fetch, whichever saw it last); before either has, the credential's
|
|
32883
|
+
* agent_name (the same identity name as of credential issue). Never the
|
|
32884
|
+
* legacy voice settings `display_name` or the file `voice.persona.display_name`.
|
|
32885
|
+
*/
|
|
32886
|
+
voiceAgentName() {
|
|
32887
|
+
return this.lastOwnDisplayName ?? this.cfg.agentName;
|
|
32888
|
+
}
|
|
32860
32889
|
/** Phase 3 F3: the loop guard's view of the sender — server roster first. */
|
|
32861
32890
|
loopSenderIsAgent(channelId, senderId, envelopeSaysAgent, relayedHumanTurn) {
|
|
32862
32891
|
if (relayedHumanTurn) return false;
|
package/dist/bridge-agent.d.ts
CHANGED
|
@@ -567,6 +567,12 @@ export declare class BridgeAgent {
|
|
|
567
567
|
* `roomDisplayName`. Kept across a later failed refresh, so a transient
|
|
568
568
|
* members-fetch error does not make the agent deaf to its own name; a
|
|
569
569
|
* successful refresh after a rename replaces it.
|
|
570
|
+
*
|
|
571
|
+
* 2026-10-01 ("one name"): also the name the voice fast path speaks as
|
|
572
|
+
* ("You are <name>."). A voice settings fetch that carries
|
|
573
|
+
* `identity_display_name` writes it too (the backend pings
|
|
574
|
+
* `voice_settings_changed` on a rename), so the latest observation from
|
|
575
|
+
* either source wins; both read the same identity column.
|
|
570
576
|
*/
|
|
571
577
|
private lastOwnDisplayName;
|
|
572
578
|
/**
|
|
@@ -2001,6 +2007,14 @@ export declare class BridgeAgent {
|
|
|
2001
2007
|
* the identity id.
|
|
2002
2008
|
*/
|
|
2003
2009
|
private ownRoomDisplayName;
|
|
2010
|
+
/**
|
|
2011
|
+
* 2026-10-01 (owner decision, "one name"): the name the voice prompt uses.
|
|
2012
|
+
* The agent's CURRENT identity display name (roster or voice settings
|
|
2013
|
+
* fetch, whichever saw it last); before either has, the credential's
|
|
2014
|
+
* agent_name (the same identity name as of credential issue). Never the
|
|
2015
|
+
* legacy voice settings `display_name` or the file `voice.persona.display_name`.
|
|
2016
|
+
*/
|
|
2017
|
+
private voiceAgentName;
|
|
2004
2018
|
/** Phase 3 F3: the loop guard's view of the sender — server roster first. */
|
|
2005
2019
|
private loopSenderIsAgent;
|
|
2006
2020
|
private noteAgentTurnSuppressed;
|
package/dist/index.js
CHANGED
|
@@ -28041,10 +28041,10 @@ var HANDOFF = {
|
|
|
28041
28041
|
balanced: "If the message needs files, tools, memory lookups, current data, or any work you cannot do instantly, say in one sentence that you are checking and end your reply with the exact token [[DEFER]] so the full agent answers next. For greetings, small talk, and anything you can answer completely yourself, answer completely and do NOT add the token.",
|
|
28042
28042
|
self: "Answer yourself whenever you reasonably can. Only when the message clearly needs files, tools, or current data you cannot see, say in one sentence that you are checking and end your reply with the exact token [[DEFER]]."
|
|
28043
28043
|
};
|
|
28044
|
-
function compileVoicePrompt(s) {
|
|
28044
|
+
function compileVoicePrompt(s, agentName) {
|
|
28045
28045
|
const parts = [];
|
|
28046
28046
|
const persona = s.persona.trim();
|
|
28047
|
-
const displayName =
|
|
28047
|
+
const displayName = (agentName ?? "").trim();
|
|
28048
28048
|
if (displayName && !persona.toLowerCase().includes(displayName.toLowerCase())) {
|
|
28049
28049
|
parts.push(`You are ${displayName}.`);
|
|
28050
28050
|
}
|
|
@@ -28096,6 +28096,9 @@ var Row = z.object({
|
|
|
28096
28096
|
voice_id: z.string().nullable().optional(),
|
|
28097
28097
|
pace: z.enum(PACES).default("normal"),
|
|
28098
28098
|
display_name: z.string().max(40).default(""),
|
|
28099
|
+
// Owner decision 2026-10-01 ("one name"). Lenient: a bad value is dropped
|
|
28100
|
+
// (see identityName below), never a reason to reject the whole row.
|
|
28101
|
+
identity_display_name: z.unknown().optional(),
|
|
28099
28102
|
persona: z.string().max(600).default(""),
|
|
28100
28103
|
warmth: z.enum(WARMTHS).default("friendly"),
|
|
28101
28104
|
formality: z.enum(FORMALITIES).default("neutral"),
|
|
@@ -28106,8 +28109,14 @@ var Row = z.object({
|
|
|
28106
28109
|
avoid_topics: z.array(z.string().max(80)).max(10).default([]),
|
|
28107
28110
|
handoff: z.enum(HANDOFFS).default("balanced")
|
|
28108
28111
|
}).passthrough();
|
|
28112
|
+
function identityName(v) {
|
|
28113
|
+
if (typeof v !== "string") return void 0;
|
|
28114
|
+
const name = v.trim();
|
|
28115
|
+
return name && name.length <= 200 ? name : void 0;
|
|
28116
|
+
}
|
|
28109
28117
|
function parseVoiceSettings(raw) {
|
|
28110
28118
|
const r = Row.parse(raw);
|
|
28119
|
+
const identityDisplayName = identityName(r.identity_display_name);
|
|
28111
28120
|
return {
|
|
28112
28121
|
version: r.version,
|
|
28113
28122
|
voiceId: r.voice_id ?? null,
|
|
@@ -28121,7 +28130,8 @@ function parseVoiceSettings(raw) {
|
|
|
28121
28130
|
quirks: r.quirks,
|
|
28122
28131
|
greetingStyle: r.greeting_style,
|
|
28123
28132
|
avoidTopics: r.avoid_topics,
|
|
28124
|
-
handoff: r.handoff
|
|
28133
|
+
handoff: r.handoff,
|
|
28134
|
+
...identityDisplayName ? { identityDisplayName } : {}
|
|
28125
28135
|
};
|
|
28126
28136
|
}
|
|
28127
28137
|
function settingsToVoiceConfig(s, proxy) {
|
|
@@ -28182,10 +28192,11 @@ function parseVoiceConfig(raw, env) {
|
|
|
28182
28192
|
}
|
|
28183
28193
|
};
|
|
28184
28194
|
}
|
|
28185
|
-
function systemPrompt(p, settings) {
|
|
28195
|
+
function systemPrompt(p, settings, agentName) {
|
|
28186
28196
|
const core = p.persona.trim().endsWith(CONTINUITY_CLAUSE) ? p.persona.trim().slice(0, -CONTINUITY_CLAUSE.length).trim() : p.persona.trim();
|
|
28187
28197
|
return compileVoicePrompt(
|
|
28188
|
-
settings ?? { ...DEFAULT_VOICE_SETTINGS,
|
|
28198
|
+
settings ?? { ...DEFAULT_VOICE_SETTINGS, persona: core, quirks: p.quirks },
|
|
28199
|
+
agentName
|
|
28189
28200
|
);
|
|
28190
28201
|
}
|
|
28191
28202
|
|
|
@@ -28199,7 +28210,7 @@ function clampContent(content, max = MAX_MESSAGE_CHARS) {
|
|
|
28199
28210
|
}
|
|
28200
28211
|
function buildFastMessages(args2) {
|
|
28201
28212
|
const cap = args2.charCap ?? 4e3;
|
|
28202
|
-
const sp = systemPrompt(args2.persona, args2.settings);
|
|
28213
|
+
const sp = systemPrompt(args2.persona, args2.settings, args2.agentName);
|
|
28203
28214
|
const head = sp.slice(0, sp.length - CONTINUITY_CLAUSE.length).trimEnd();
|
|
28204
28215
|
const system = `${head} ${args2.guidance.trim()} ${CONTINUITY_CLAUSE}`;
|
|
28205
28216
|
const recent = args2.memory.recent.map((t) => ({
|
|
@@ -29099,6 +29110,12 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
29099
29110
|
* `roomDisplayName`. Kept across a later failed refresh, so a transient
|
|
29100
29111
|
* members-fetch error does not make the agent deaf to its own name; a
|
|
29101
29112
|
* successful refresh after a rename replaces it.
|
|
29113
|
+
*
|
|
29114
|
+
* 2026-10-01 ("one name"): also the name the voice fast path speaks as
|
|
29115
|
+
* ("You are <name>."). A voice settings fetch that carries
|
|
29116
|
+
* `identity_display_name` writes it too (the backend pings
|
|
29117
|
+
* `voice_settings_changed` on a rename), so the latest observation from
|
|
29118
|
+
* either source wins; both read the same identity column.
|
|
29102
29119
|
*/
|
|
29103
29120
|
lastOwnDisplayName;
|
|
29104
29121
|
/**
|
|
@@ -29502,6 +29519,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
29502
29519
|
const res = await this.fetchBounded("voice_settings", "read", url, { headers: { authorization: `Bearer ${this.cfg.apiKey}` } });
|
|
29503
29520
|
if (!res.ok) throw new Error(`voice-settings ${res.status}`);
|
|
29504
29521
|
const s = parseVoiceSettings(await res.json());
|
|
29522
|
+
if (s.identityDisplayName) this.lastOwnDisplayName = s.identityDisplayName;
|
|
29505
29523
|
const proxy = settingsToVoiceConfig(s, { baseUrl: this.cfg.apiBase, apiKey: this.cfg.apiKey });
|
|
29506
29524
|
if (s.version === 0 && this.fileVoiceConfig) {
|
|
29507
29525
|
const merged = {
|
|
@@ -31399,7 +31417,8 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
31399
31417
|
memory,
|
|
31400
31418
|
speaker,
|
|
31401
31419
|
text,
|
|
31402
|
-
settings: this.voiceSettings ?? void 0
|
|
31420
|
+
settings: this.voiceSettings ?? void 0,
|
|
31421
|
+
agentName: this.voiceAgentName()
|
|
31403
31422
|
});
|
|
31404
31423
|
const maxSentences = this.voiceSettings?.brevity === "one" ? 1 : 2;
|
|
31405
31424
|
const { reply, defer } = splitFastReply(await this.fastLlm.complete(messages), 200, maxSentences);
|
|
@@ -32706,6 +32725,16 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
32706
32725
|
ownRoomDisplayName() {
|
|
32707
32726
|
return this.lastOwnDisplayName;
|
|
32708
32727
|
}
|
|
32728
|
+
/**
|
|
32729
|
+
* 2026-10-01 (owner decision, "one name"): the name the voice prompt uses.
|
|
32730
|
+
* The agent's CURRENT identity display name (roster or voice settings
|
|
32731
|
+
* fetch, whichever saw it last); before either has, the credential's
|
|
32732
|
+
* agent_name (the same identity name as of credential issue). Never the
|
|
32733
|
+
* legacy voice settings `display_name` or the file `voice.persona.display_name`.
|
|
32734
|
+
*/
|
|
32735
|
+
voiceAgentName() {
|
|
32736
|
+
return this.lastOwnDisplayName ?? this.cfg.agentName;
|
|
32737
|
+
}
|
|
32709
32738
|
/** Phase 3 F3: the loop guard's view of the sender — server roster first. */
|
|
32710
32739
|
loopSenderIsAgent(channelId, senderId, envelopeSaysAgent, relayedHumanTurn) {
|
|
32711
32740
|
if (relayedHumanTurn) return false;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const BRIDGE_VERSION = "0.25.
|
|
1
|
+
export declare const BRIDGE_VERSION = "0.25.3";
|
|
@@ -35,6 +35,9 @@ export declare function buildFastMessages(args: {
|
|
|
35
35
|
* from these backend-loaded dials (compileVoicePrompt) instead of the
|
|
36
36
|
* credential file's persona block. */
|
|
37
37
|
settings?: VoiceSettings;
|
|
38
|
+
/** The agent's identity display name ("one name", 2026-10-01): the only
|
|
39
|
+
* source of the prompt's "You are <name>." line. */
|
|
40
|
+
agentName?: string;
|
|
38
41
|
}): ChatMessage[];
|
|
39
42
|
/** The fast model appends this when the full agent must answer next. */
|
|
40
43
|
export declare const DEFER_TOKEN = "[[DEFER]]";
|
package/dist/voice/persona.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { type VoiceSettings } from "./settings.js";
|
|
2
2
|
export declare const CONTINUITY_CLAUSE: string;
|
|
3
|
+
/**
|
|
4
|
+
* `displayName` is legacy (the credential file's `voice.persona.display_name`,
|
|
5
|
+
* or the backend's voice settings `display_name`). It is still parsed so old
|
|
6
|
+
* credentials and payloads load, but the prompt never reads it: the agent's
|
|
7
|
+
* name comes from its identity display name (owner decision 2026-10-01, "one name").
|
|
8
|
+
*/
|
|
3
9
|
export interface VoicePersona {
|
|
4
10
|
displayName?: string;
|
|
5
11
|
persona: string;
|
|
@@ -20,4 +26,4 @@ export interface VoiceConfig {
|
|
|
20
26
|
settings?: VoiceSettings;
|
|
21
27
|
}
|
|
22
28
|
export declare function parseVoiceConfig(raw: unknown, env: Record<string, string | undefined>): VoiceConfig | undefined;
|
|
23
|
-
export declare function systemPrompt(p: VoicePersona, settings?: VoiceSettings): string;
|
|
29
|
+
export declare function systemPrompt(p: VoicePersona, settings?: VoiceSettings, agentName?: string): string;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { VoiceSettings } from "./settings.js";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* `agentName` is the agent's identity display name (`ConnectIdentity.display_name`,
|
|
4
|
+
* the one name shown in rosters and the Directory). Owner decision 2026-10-01
|
|
5
|
+
* ("one name"): the voice settings `display_name` (`s.displayName`) is a legacy
|
|
6
|
+
* field that is still parsed for compatibility but never read here, so a
|
|
7
|
+
* rename reaches calls too.
|
|
8
|
+
*/
|
|
9
|
+
export declare function compileVoicePrompt(s: VoiceSettings, agentName?: string): string;
|
|
3
10
|
export declare const VOICE_CALL_START_MARKER = "[voice call started]";
|
|
4
11
|
export declare function greetingTurnFor(s: VoiceSettings, callerName?: string): string;
|
package/dist/voice/settings.d.ts
CHANGED
|
@@ -10,7 +10,13 @@ export interface VoiceSettings {
|
|
|
10
10
|
version: number;
|
|
11
11
|
voiceId: string | null;
|
|
12
12
|
pace: (typeof PACES)[number];
|
|
13
|
+
/** Legacy voice-only name (backend `display_name`). Parsed for compatibility
|
|
14
|
+
* with older backends/web clients, never used for the prompt ("one name",
|
|
15
|
+
* 2026-10-01). */
|
|
13
16
|
displayName: string;
|
|
17
|
+
/** The agent's identity display name at fetch time (backend
|
|
18
|
+
* `identity_display_name`), when the backend sends it. */
|
|
19
|
+
identityDisplayName?: string;
|
|
14
20
|
persona: string;
|
|
15
21
|
warmth: (typeof WARMTHS)[number];
|
|
16
22
|
formality: (typeof FORMALITIES)[number];
|