@voicethere/agent 0.9.0 → 0.9.1
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 +36 -21
- package/dist/agent.js +26 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.ts +10 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/runtime.d.ts +26 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +45 -2
- package/dist/runtime.js.map +1 -1
- package/dist/templates/echo/agent.js +20 -0
- package/dist/templates/echo-dc/agent.js +20 -0
- package/dist/templates/game-sync/agent.js +20 -0
- package/dist/templates/language-switch/agent.js +73 -11
- package/dist/templates/positional-tts/agent.js +20 -0
- package/dist/templates/recording-consent/agent.js +20 -0
- package/dist/templates/spatial-showcase/agent.js +20 -0
- package/dist/templates/voice-showcase/agent.js +20 -0
- package/dist/templates/voice-starter/agent.js +20 -0
- package/dist/templates/webhooks/agent.js +20 -0
- package/dist/templates/webhooks-redis/agent.js +20 -0
- package/dist/templates/world-sync/agent.js +20 -0
- package/dist/templates/world-sync-binary/agent.js +20 -0
- package/package.json +1 -1
- package/templates/README.md +30 -30
- package/templates/language-switch/README.md +11 -1
- package/templates/language-switch/agent.ts +68 -15
package/templates/README.md
CHANGED
|
@@ -17,10 +17,10 @@ import {
|
|
|
17
17
|
|
|
18
18
|
## Product vs e2e
|
|
19
19
|
|
|
20
|
-
| Kind | Dashboard create
|
|
21
|
-
| ----------- |
|
|
20
|
+
| Kind | Dashboard create | Prebuilt seed bundle | Typical consumer |
|
|
21
|
+
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | ----------------------- |
|
|
22
22
|
| **product** | Yes (`echo`, `echo-dc`, `voice-starter`, `language-switch`, `world-sync`, `world-sync-binary`, `game-sync`, `voice-showcase`, `recording-consent`, `positional-tts`, `spatial-showcase`, `webhooks`, `webhooks-redis`) | Yes — `dist/templates/<id>/agent.js` | Platform project create |
|
|
23
|
-
| **e2e** | No
|
|
23
|
+
| **e2e** | No | No — build from sources at test time | `voicethere/e2e` smokes |
|
|
24
24
|
|
|
25
25
|
Product templates always set `seedOnCreate: true`. CI fails if a product template is missing its prebuilt bundle after `npm run build`.
|
|
26
26
|
|
|
@@ -47,11 +47,11 @@ npm run build:templates
|
|
|
47
47
|
|
|
48
48
|
Three product templates cover positional / world sync, from JSON to Redis:
|
|
49
49
|
|
|
50
|
-
| Id
|
|
51
|
-
|
|
|
52
|
-
| `world-sync`
|
|
53
|
-
| `world-sync-binary`
|
|
54
|
-
| `game-sync`
|
|
50
|
+
| Id | Channel | State |
|
|
51
|
+
| ------------------- | ------------------------------------------------------------------ | ----------------------------------- |
|
|
52
|
+
| `world-sync` | `onDataChannelMessage` (JSON) | One agent, in-memory, no Redis |
|
|
53
|
+
| `world-sync-binary` | `onDataChannelBinary` + `broadCastBinaryToClients` (`ArrayBuffer`) | One agent, in-memory, no Redis |
|
|
54
|
+
| `game-sync` | JSON control + binary world snapshots | Redis when `AGENT_REDIS_URL` is set |
|
|
55
55
|
|
|
56
56
|
See each folder README for the wire format.
|
|
57
57
|
|
|
@@ -59,33 +59,33 @@ See each folder README for the wire format.
|
|
|
59
59
|
|
|
60
60
|
Each folder has its own README. Summary:
|
|
61
61
|
|
|
62
|
-
| Id
|
|
63
|
-
|
|
|
64
|
-
| `echo`
|
|
65
|
-
| `echo-dc`
|
|
66
|
-
| `voice-starter`
|
|
67
|
-
| `language-switch`
|
|
68
|
-
| `world-sync`
|
|
69
|
-
| `world-sync-binary` | `world-sync-binary/` | Binary pose `ArrayBuffer`
|
|
70
|
-
| `game-sync`
|
|
71
|
-
| `voice-showcase`
|
|
72
|
-
| `recording-consent` | `recording-consent/` | Recording consent flow
|
|
73
|
-
| `positional-tts`
|
|
74
|
-
| `spatial-showcase`
|
|
75
|
-
| `webhooks`
|
|
76
|
-
| `webhooks-redis`
|
|
62
|
+
| Id | Folder | Summary |
|
|
63
|
+
| ------------------- | -------------------- | ----------------------------------------------------------------- |
|
|
64
|
+
| `echo` | `echo/` | Voice + chat echo |
|
|
65
|
+
| `echo-dc` | `echo-dc/` | Data-channel echo, no TTS |
|
|
66
|
+
| `voice-starter` | `voice-starter/` | Every speech event |
|
|
67
|
+
| `language-switch` | `language-switch/` | Manual `setVoiceLanguage` or runner auto-switch + prompt handlers |
|
|
68
|
+
| `world-sync` | `world-sync/` | JSON pose broadcast |
|
|
69
|
+
| `world-sync-binary` | `world-sync-binary/` | Binary pose `ArrayBuffer` |
|
|
70
|
+
| `game-sync` | `game-sync/` | Authoritative sim, Redis + binary snapshots |
|
|
71
|
+
| `voice-showcase` | `voice-showcase/` | Conversational landing demo |
|
|
72
|
+
| `recording-consent` | `recording-consent/` | Recording consent flow |
|
|
73
|
+
| `positional-tts` | `positional-tts/` | Orbiting TTS |
|
|
74
|
+
| `spatial-showcase` | `spatial-showcase/` | Orbit / soundboard / proximity |
|
|
75
|
+
| `webhooks` | `webhooks/` | Inbound HMAC webhooks |
|
|
76
|
+
| `webhooks-redis` | `webhooks-redis/` | Webhooks plus Redis counter |
|
|
77
77
|
|
|
78
78
|
## E2e templates
|
|
79
79
|
|
|
80
80
|
These mirror former `e2e/fixtures/*` sources. E2E resolves entries from the package, builds into ephemeral workdirs, and uploads `dist/agent.js`.
|
|
81
81
|
|
|
82
|
-
| Id | Source
|
|
83
|
-
| ----------------- |
|
|
84
|
-
| `echo-smoke` | `echo-smoke/agent.ts`
|
|
85
|
-
| `crash` | `crash/agent.ts`
|
|
86
|
-
| `game-sync-smoke` | `game-sync-smoke/agent.ts`
|
|
87
|
-
| `redis-sync` | `redis-sync/agent.ts` + `world-layout.ts`
|
|
88
|
-
| `mix-smoke` | `mix-smoke/agent.ts`
|
|
82
|
+
| Id | Source | Purpose |
|
|
83
|
+
| ----------------- | ----------------------------------------- | ------------------------------------------------------ |
|
|
84
|
+
| `echo-smoke` | `echo-smoke/agent.ts` | voice-smoke, agent-smoke, cli-smoke |
|
|
85
|
+
| `crash` | `crash/agent.ts` | session-errors-smoke, crash-policy smokes |
|
|
86
|
+
| `game-sync-smoke` | `game-sync-smoke/agent.ts` | deploy-smoke, shared-child, idle smokes |
|
|
87
|
+
| `redis-sync` | `redis-sync/agent.ts` + `world-layout.ts` | redis-sync-smoke (binary positions + Redis world blob) |
|
|
88
|
+
| `mix-smoke` | `mix-smoke/agent.ts` | voice-data-mix-smoke |
|
|
89
89
|
|
|
90
90
|
**Note:** Product `echo` is not the same as e2e `echo-smoke` — keep both ids.
|
|
91
91
|
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
# language-switch
|
|
2
2
|
|
|
3
|
-
Spoken-language detection tells the agent which ISO 639-1 code it heard. It does **not** change the TTS voice or the STT model. This template
|
|
3
|
+
Spoken-language detection tells the agent which ISO 639-1 code it heard. It does **not** change the TTS voice or the STT model by itself. This template shows how to react in two ways:
|
|
4
|
+
|
|
5
|
+
## Mode A — Manual switch (default)
|
|
6
|
+
|
|
7
|
+
Leave the project **spoken-language auto-switch** setting off. When `onUserLanguage` fires, this agent calls `setVoiceLanguage` separately for each side:
|
|
4
8
|
|
|
5
9
|
- `scope: "tts"` switches only the speaking voice
|
|
6
10
|
- `scope: "stt"` switches only the listening model
|
|
7
11
|
|
|
8
12
|
A Sherpa language with no STT id (`it`, `pt`, `nl`, `pl`, `hi`) fails the STT call and still switches TTS.
|
|
9
13
|
|
|
14
|
+
## Mode B — Runner auto-switch
|
|
15
|
+
|
|
16
|
+
Enable auto-switch in the project voice settings (runner applies STT/TTS when LID detects a new language). When `session_start.env` includes a truthy `SHERPA_LID_AUTO_SWITCH`, this template **does not** call `setVoiceLanguage` from `onUserLanguage` — it logs that the runner owns the switch and updates prompts only. Use `onVoiceLanguageChanged` when you need the committed language after the runner applies the change.
|
|
17
|
+
|
|
18
|
+
Detection and chat commands are unchanged: `/tts` and `/stt` still call `setVoiceLanguage` for one vendor at a time.
|
|
19
|
+
|
|
10
20
|
Chat commands change one vendor while the session stays connected. API keys are project secrets on the running deploy, not arguments:
|
|
11
21
|
|
|
12
22
|
- `/tts sherpa de` — Sherpa TTS only
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Change STT and TTS separately, including the vendor, while the call stays up.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Two deployment modes (see README):
|
|
5
|
+
*
|
|
6
|
+
* (A) Project auto-switch off — this agent calls `setVoiceLanguage` from
|
|
7
|
+
* `onUserLanguage` when LID detects a new language.
|
|
8
|
+
* (B) Project enables runner auto-switch — STT/TTS are runner-owned; use
|
|
9
|
+
* `onUserLanguage` / `onVoiceLanguageChanged` for prompts only.
|
|
10
|
+
*
|
|
11
|
+
* Chat commands change a single vendor mid-conversation:
|
|
8
12
|
*
|
|
9
13
|
* - `/tts sherpa de` — Sherpa TTS only
|
|
10
14
|
* - `/stt sherpa de` — Sherpa STT only
|
|
@@ -17,6 +21,7 @@
|
|
|
17
21
|
import {
|
|
18
22
|
agentLog,
|
|
19
23
|
defineAgent,
|
|
24
|
+
isRunnerLidAutoSwitchEnabled,
|
|
20
25
|
parseChatText,
|
|
21
26
|
setVoiceLanguage,
|
|
22
27
|
speak,
|
|
@@ -39,17 +44,22 @@ const REPLIES: Record<string, string> = {
|
|
|
39
44
|
|
|
40
45
|
type SessionLanguage = {
|
|
41
46
|
language: string;
|
|
47
|
+
runnerAutoSwitch: boolean;
|
|
42
48
|
echoTimer: ReturnType<typeof setTimeout> | undefined;
|
|
43
49
|
suppressNextFinal: boolean;
|
|
44
50
|
};
|
|
45
51
|
|
|
46
52
|
const sessions = new Map<string, SessionLanguage>();
|
|
47
53
|
|
|
48
|
-
function stateFor(
|
|
54
|
+
function stateFor(
|
|
55
|
+
sessionId: string,
|
|
56
|
+
env?: Record<string, string>,
|
|
57
|
+
): SessionLanguage {
|
|
49
58
|
const existing = sessions.get(sessionId);
|
|
50
59
|
if (existing) return existing;
|
|
51
60
|
const created: SessionLanguage = {
|
|
52
61
|
language: "en",
|
|
62
|
+
runnerAutoSwitch: env ? isRunnerLidAutoSwitchEnabled(env) : false,
|
|
53
63
|
echoTimer: undefined,
|
|
54
64
|
suppressNextFinal: false,
|
|
55
65
|
};
|
|
@@ -61,9 +71,16 @@ function replyFor(language: string): string {
|
|
|
61
71
|
return REPLIES[language] ?? `Continuing in ${language}.`;
|
|
62
72
|
}
|
|
63
73
|
|
|
64
|
-
function logSwitch(
|
|
74
|
+
function logSwitch(
|
|
75
|
+
sessionId: string,
|
|
76
|
+
side: string,
|
|
77
|
+
result: VoiceLanguageResult,
|
|
78
|
+
): void {
|
|
65
79
|
if (!result.ok) {
|
|
66
|
-
agentLog(
|
|
80
|
+
agentLog(
|
|
81
|
+
"warn",
|
|
82
|
+
`setVoiceLanguage ${side} failed: ${result.reason ?? "unknown"}`,
|
|
83
|
+
);
|
|
67
84
|
return;
|
|
68
85
|
}
|
|
69
86
|
const provider = side === "tts" ? result.ttsProvider : result.sttProvider;
|
|
@@ -74,21 +91,45 @@ function logSwitch(sessionId: string, side: string, result: VoiceLanguageResult)
|
|
|
74
91
|
);
|
|
75
92
|
}
|
|
76
93
|
|
|
94
|
+
function prepareLanguageTransition(state: SessionLanguage): void {
|
|
95
|
+
if (state.echoTimer) {
|
|
96
|
+
clearTimeout(state.echoTimer);
|
|
97
|
+
state.echoTimer = undefined;
|
|
98
|
+
} else {
|
|
99
|
+
state.suppressNextFinal = true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
77
103
|
defineAgent({
|
|
78
|
-
onSessionStart({ sessionId }) {
|
|
79
|
-
stateFor(sessionId);
|
|
80
|
-
|
|
104
|
+
onSessionStart({ sessionId, env }) {
|
|
105
|
+
const state = stateFor(sessionId, env);
|
|
106
|
+
if (state.runnerAutoSwitch) {
|
|
107
|
+
agentLog(
|
|
108
|
+
"info",
|
|
109
|
+
`language-switch session_start ${sessionId} runner LID auto-switch owns STT/TTS`,
|
|
110
|
+
);
|
|
111
|
+
} else {
|
|
112
|
+
agentLog(
|
|
113
|
+
"info",
|
|
114
|
+
`language-switch session_start ${sessionId} manual setVoiceLanguage`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
81
117
|
},
|
|
82
118
|
|
|
83
119
|
async onUserLanguage({ sessionId, language }) {
|
|
84
120
|
const state = stateFor(sessionId);
|
|
85
121
|
if (!language || language === state.language) return;
|
|
86
122
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
123
|
+
prepareLanguageTransition(state);
|
|
124
|
+
|
|
125
|
+
if (state.runnerAutoSwitch) {
|
|
126
|
+
agentLog(
|
|
127
|
+
"info",
|
|
128
|
+
`LID detected ${language}; runner auto-switch applies STT/TTS — agent updates prompts only`,
|
|
129
|
+
);
|
|
130
|
+
state.language = language;
|
|
131
|
+
speak(sessionId, replyFor(language));
|
|
132
|
+
return;
|
|
92
133
|
}
|
|
93
134
|
|
|
94
135
|
const tts = await setVoiceLanguage(sessionId, {
|
|
@@ -114,6 +155,18 @@ defineAgent({
|
|
|
114
155
|
speak(sessionId, replyFor(language));
|
|
115
156
|
},
|
|
116
157
|
|
|
158
|
+
async onVoiceLanguageChanged({ sessionId, language }) {
|
|
159
|
+
const state = stateFor(sessionId);
|
|
160
|
+
if (!state.runnerAutoSwitch || !language || language === state.language) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
agentLog(
|
|
164
|
+
"info",
|
|
165
|
+
`runner committed voice language ${language} for ${sessionId}`,
|
|
166
|
+
);
|
|
167
|
+
state.language = language;
|
|
168
|
+
},
|
|
169
|
+
|
|
117
170
|
async onDataChannelMessage(ctx) {
|
|
118
171
|
const text = parseChatText(ctx.message);
|
|
119
172
|
if (!text) return;
|