@lovelace_lol/polymer 0.0.6 → 0.0.8
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 +434 -12
- package/dist/index.d.ts +1945 -244
- package/dist/index.js +1686 -1017
- package/dist/vision/face-worker.js +296 -0
- package/dist/vision/face_landmarker.task +0 -0
- package/dist/vision/manifest.edn +1 -0
- package/dist/vision/vision_bundle.js +2 -0
- package/dist/vision/wasm/vision_wasm_internal.js +8841 -0
- package/dist/vision/wasm/vision_wasm_internal.wasm +0 -0
- package/dist/vision/wasm/vision_wasm_module_internal.js +8837 -0
- package/dist/vision/wasm/vision_wasm_module_internal.wasm +0 -0
- package/dist/vision/wasm/vision_wasm_nosimd_internal.js +8832 -0
- package/dist/vision/wasm/vision_wasm_nosimd_internal.wasm +0 -0
- package/dist/worker/agency-worker.js +1276 -962
- package/dist/worker/manifest.edn +1 -1
- package/package.json +33 -20
- package/dist/test.cjs +0 -1519
- package/shadow-cljs.edn +0 -173
- package/src/polymer/animation/agency.cljs +0 -84
- package/src/polymer/animation/domain.cljs +0 -110
- package/src/polymer/animation/planner.cljs +0 -88
- package/src/polymer/animation/runtime.cljs +0 -137
- package/src/polymer/animation/scheduler.cljs +0 -178
- package/src/polymer/animation/service.cljs +0 -981
- package/src/polymer/animation/state.cljs +0 -112
- package/src/polymer/blink/agency.cljs +0 -131
- package/src/polymer/blink/planner.cljs +0 -115
- package/src/polymer/blink/scheduler.cljs +0 -90
- package/src/polymer/blink/snippet.cljs +0 -50
- package/src/polymer/blink/state.cljs +0 -102
- package/src/polymer/camera_context/agency.cljs +0 -132
- package/src/polymer/camera_context/domain.cljs +0 -186
- package/src/polymer/camera_context/planner.cljs +0 -50
- package/src/polymer/camera_context/scheduler.cljs +0 -113
- package/src/polymer/camera_context/state.cljs +0 -121
- package/src/polymer/character.cljs +0 -403
- package/src/polymer/conversation/agency.cljs +0 -83
- package/src/polymer/conversation/domain.cljs +0 -35
- package/src/polymer/conversation/effector.cljs +0 -130
- package/src/polymer/conversation/planner.cljs +0 -178
- package/src/polymer/conversation/scheduler.cljs +0 -202
- package/src/polymer/conversation/service.cljs +0 -329
- package/src/polymer/conversation/state.cljs +0 -186
- package/src/polymer/core.cljs +0 -172
- package/src/polymer/eye_head/agency.cljs +0 -75
- package/src/polymer/eye_head/domain.cljs +0 -133
- package/src/polymer/eye_head/goap.cljs +0 -106
- package/src/polymer/eye_head/scheduler.cljs +0 -176
- package/src/polymer/eye_head/service.cljs +0 -259
- package/src/polymer/eye_head/snippet.cljs +0 -92
- package/src/polymer/eye_head/state.cljs +0 -167
- package/src/polymer/gaze/agency.cljs +0 -85
- package/src/polymer/gaze/domain.cljs +0 -211
- package/src/polymer/gaze/goap.cljs +0 -208
- package/src/polymer/gaze/scheduler.cljs +0 -184
- package/src/polymer/gaze/state.cljs +0 -202
- package/src/polymer/gesture/agency.cljs +0 -185
- package/src/polymer/gesture/goap.cljs +0 -461
- package/src/polymer/gesture/scheduler.cljs +0 -122
- package/src/polymer/gesture/snippet.cljs +0 -198
- package/src/polymer/gesture/state.cljs +0 -273
- package/src/polymer/lipsync/agency.cljs +0 -593
- package/src/polymer/lipsync/articulation/jaw.cljs +0 -258
- package/src/polymer/lipsync/articulation/snippet.cljs +0 -605
- package/src/polymer/lipsync/articulation/tongue.cljs +0 -418
- package/src/polymer/lipsync/articulation/visemes.cljs +0 -429
- package/src/polymer/lipsync/goap.cljs +0 -132
- package/src/polymer/lipsync/pronunciation/effector.cljs +0 -51
- package/src/polymer/lipsync/scheduler.cljs +0 -302
- package/src/polymer/lipsync/state.cljs +0 -202
- package/src/polymer/nlp/phonemes.cljs +0 -164
- package/src/polymer/prosodic/agency.cljs +0 -196
- package/src/polymer/prosodic/goap.cljs +0 -122
- package/src/polymer/prosodic/scheduler.cljs +0 -99
- package/src/polymer/prosodic/snippet.cljs +0 -106
- package/src/polymer/prosodic/state.cljs +0 -139
- package/src/polymer/runtime/embody.cljs +0 -117
- package/src/polymer/runtime/embody_wasm.cljs +0 -177
- package/src/polymer/runtime/rust_embody_host.cljs +0 -647
- package/src/polymer/society.cljs +0 -253
- package/src/polymer/stream.cljs +0 -130
- package/src/polymer/transcription/agency.cljs +0 -69
- package/src/polymer/transcription/domain.cljs +0 -68
- package/src/polymer/transcription/effector.cljs +0 -611
- package/src/polymer/transcription/planner.cljs +0 -203
- package/src/polymer/transcription/scheduler.cljs +0 -225
- package/src/polymer/transcription/service.cljs +0 -209
- package/src/polymer/transcription/state.cljs +0 -239
- package/src/polymer/tts/agency.cljs +0 -503
- package/src/polymer/tts/azure.cljs +0 -290
- package/src/polymer/tts/planner.cljs +0 -178
- package/src/polymer/tts/runtime.cljs +0 -624
- package/src/polymer/tts/scheduler.cljs +0 -162
- package/src/polymer/tts/state.cljs +0 -191
- package/src/polymer/worker.cljs +0 -81
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
(ns polymer.character
|
|
2
|
-
(:require [polymer.animation.agency :as animation]
|
|
3
|
-
[polymer.blink.agency :as blink]
|
|
4
|
-
[polymer.camera-context.agency :as camera-context]
|
|
5
|
-
[polymer.conversation.agency :as conversation]
|
|
6
|
-
[polymer.eye-head.agency :as eye-head]
|
|
7
|
-
[polymer.gaze.agency :as gaze]
|
|
8
|
-
[polymer.gesture.agency :as gesture]
|
|
9
|
-
[polymer.lipsync.agency :as lipsync]
|
|
10
|
-
[polymer.prosodic.agency :as prosodic]
|
|
11
|
-
[polymer.society :as society]
|
|
12
|
-
[polymer.stream :as stream]
|
|
13
|
-
[polymer.transcription.agency :as transcription]
|
|
14
|
-
[polymer.tts.agency :as tts]))
|
|
15
|
-
|
|
16
|
-
;; A character is a network of Polymer agencies.
|
|
17
|
-
;;
|
|
18
|
-
;; LoomLarge may still consume streams from legacy Latticework services during
|
|
19
|
-
;; the migration, but it should not consume Polymer animation events and turn
|
|
20
|
-
;; them into animation calls. Inside Polymer, Blink emits blink intent and fast
|
|
21
|
-
;; blink facts, Camera Context emits gaze facts, Transcription emits transcript
|
|
22
|
-
;; facts, Conversation emits speech requests, TTS emits speech timing facts,
|
|
23
|
-
;; LipSync emits mouth animation intent, Gesture emits arm/hand animation intent,
|
|
24
|
-
;; Prosodic emits speech/blink expression intent, and Animation talks directly
|
|
25
|
-
;; to Embody. Hair appearance and physics are Embody runtime concerns, not a
|
|
26
|
-
;; Polymer behavioral agency.
|
|
27
|
-
|
|
28
|
-
(defn- with-source-agency [event route]
|
|
29
|
-
(assoc event :sourceAgency (:from route)))
|
|
30
|
-
|
|
31
|
-
(defn- animation-command [event route]
|
|
32
|
-
(when (= "animation" (:to route))
|
|
33
|
-
(case (:type event)
|
|
34
|
-
"animation.requestScheduleSnippet"
|
|
35
|
-
{:type "scheduleSnippet"
|
|
36
|
-
:sourceAgency (:agency event)
|
|
37
|
-
:snippet (:snippet event)
|
|
38
|
-
:options (:options event)}
|
|
39
|
-
|
|
40
|
-
"animation.requestRemoveSnippet"
|
|
41
|
-
{:type "removeSnippet"
|
|
42
|
-
:sourceAgency (:agency event)
|
|
43
|
-
:name (:name event)}
|
|
44
|
-
|
|
45
|
-
"animation.requestSeekSnippet"
|
|
46
|
-
{:type "seekSnippet"
|
|
47
|
-
:sourceAgency (:agency event)
|
|
48
|
-
:name (:name event)
|
|
49
|
-
:offsetSec (:offsetSec event)}
|
|
50
|
-
|
|
51
|
-
nil)))
|
|
52
|
-
|
|
53
|
-
(defn- transcription-command [event]
|
|
54
|
-
(case (:type event)
|
|
55
|
-
"transcription.final"
|
|
56
|
-
{:type "transcript.final"
|
|
57
|
-
:text (:text event)
|
|
58
|
-
:source "transcription"
|
|
59
|
-
:confidence (:confidence event)
|
|
60
|
-
:sequence (:sequence event)
|
|
61
|
-
:sessionId (:sessionId event)
|
|
62
|
-
:at (:at event)}
|
|
63
|
-
|
|
64
|
-
"transcription.interruption"
|
|
65
|
-
{:type "interrupt"
|
|
66
|
-
:reason "transcription-interruption"
|
|
67
|
-
:text (:text event)
|
|
68
|
-
:source "transcription"}
|
|
69
|
-
|
|
70
|
-
"transcription.audioInterruption"
|
|
71
|
-
{:type "interrupt"
|
|
72
|
-
:reason "audio-interruption"
|
|
73
|
-
:event event
|
|
74
|
-
:source "transcription"}
|
|
75
|
-
|
|
76
|
-
nil))
|
|
77
|
-
|
|
78
|
-
(defn- conversation-command [event route]
|
|
79
|
-
(case (:type event)
|
|
80
|
-
"tts.requestSpeak"
|
|
81
|
-
(:command event)
|
|
82
|
-
|
|
83
|
-
"conversation.cancelRequested"
|
|
84
|
-
(if (= "tts" (:to route))
|
|
85
|
-
{:type "stop"
|
|
86
|
-
:reason (:reason event)}
|
|
87
|
-
(with-source-agency event route))
|
|
88
|
-
|
|
89
|
-
(with-source-agency event route)))
|
|
90
|
-
|
|
91
|
-
(defn- tts-command [event route]
|
|
92
|
-
(case (:type event)
|
|
93
|
-
"lipSync.command"
|
|
94
|
-
(:command event)
|
|
95
|
-
|
|
96
|
-
"ttsStatusChanged"
|
|
97
|
-
(let [status (get-in event [:state :status])]
|
|
98
|
-
(case (:to route)
|
|
99
|
-
"conversation" {:type "tts.status"
|
|
100
|
-
:status status}
|
|
101
|
-
"transcription" {:type "tts.status"
|
|
102
|
-
:status status
|
|
103
|
-
:speaking (get-in event [:state :speaking])
|
|
104
|
-
:state (:state event)}
|
|
105
|
-
nil))
|
|
106
|
-
|
|
107
|
-
"ttsSpeechStarted"
|
|
108
|
-
(case (:to route)
|
|
109
|
-
"prosodic" {:type "speechStarted"
|
|
110
|
-
:sourceAgency "tts"
|
|
111
|
-
:name (:name event)
|
|
112
|
-
:engine (:engine event)}
|
|
113
|
-
"conversation" {:type "tts.status"
|
|
114
|
-
:status "speaking"}
|
|
115
|
-
"transcription" event
|
|
116
|
-
nil)
|
|
117
|
-
|
|
118
|
-
"ttsWordBoundary"
|
|
119
|
-
(when (= "prosodic" (:to route))
|
|
120
|
-
{:type "wordBoundary"
|
|
121
|
-
:sourceAgency "tts"
|
|
122
|
-
:word (:word event)
|
|
123
|
-
:wordIndex (:wordIndex event)
|
|
124
|
-
:observedElapsedSec (:observedElapsedSec event)
|
|
125
|
-
:hostElapsedSec (:hostElapsedSec event)})
|
|
126
|
-
|
|
127
|
-
"ttsSpeechStopped"
|
|
128
|
-
(case (:to route)
|
|
129
|
-
"prosodic" {:type "speechStopped"
|
|
130
|
-
:sourceAgency "tts"
|
|
131
|
-
:reason (:reason event)}
|
|
132
|
-
"conversation" {:type "tts.status"
|
|
133
|
-
:status "idle"}
|
|
134
|
-
"transcription" event
|
|
135
|
-
nil)
|
|
136
|
-
|
|
137
|
-
"ttsSpeechEnded"
|
|
138
|
-
(case (:to route)
|
|
139
|
-
"prosodic" {:type "speechStopped"
|
|
140
|
-
:sourceAgency "tts"
|
|
141
|
-
:reason "completed"}
|
|
142
|
-
"conversation" {:type "tts.status"
|
|
143
|
-
:status "idle"}
|
|
144
|
-
"transcription" event
|
|
145
|
-
nil)
|
|
146
|
-
|
|
147
|
-
(with-source-agency event route)))
|
|
148
|
-
|
|
149
|
-
(defn- routed-command [event route]
|
|
150
|
-
(case (:type event)
|
|
151
|
-
("animation.requestScheduleSnippet"
|
|
152
|
-
"animation.requestRemoveSnippet"
|
|
153
|
-
"animation.requestSeekSnippet")
|
|
154
|
-
(animation-command event route)
|
|
155
|
-
|
|
156
|
-
"signal"
|
|
157
|
-
(if (and (= "blink" (:from route))
|
|
158
|
-
(= "prosodic" (:to route))
|
|
159
|
-
(= "blink-fast" (:signal event)))
|
|
160
|
-
{:type "blinkFast"
|
|
161
|
-
:sourceAgency "blink"
|
|
162
|
-
:plan (:plan event)}
|
|
163
|
-
(with-source-agency event route))
|
|
164
|
-
|
|
165
|
-
("eyeHeadTracking.requestGaze"
|
|
166
|
-
"eyeHeadTracking.requestReset"
|
|
167
|
-
"eyeHeadTracking.requestCancel"
|
|
168
|
-
"camera.fact"
|
|
169
|
-
"camera.stale")
|
|
170
|
-
event
|
|
171
|
-
|
|
172
|
-
("transcription.final"
|
|
173
|
-
"transcription.interruption"
|
|
174
|
-
"transcription.audioInterruption")
|
|
175
|
-
(transcription-command event)
|
|
176
|
-
|
|
177
|
-
("conversation.userUtterance"
|
|
178
|
-
"conversation.agentUtterance"
|
|
179
|
-
"conversation.requestResponse"
|
|
180
|
-
"tts.requestSpeak"
|
|
181
|
-
"conversation.cancelRequested")
|
|
182
|
-
(conversation-command event route)
|
|
183
|
-
|
|
184
|
-
("lipSync.command"
|
|
185
|
-
"ttsStatusChanged"
|
|
186
|
-
"ttsSpeechStarted"
|
|
187
|
-
"ttsWordBoundary"
|
|
188
|
-
"ttsSpeechStopped"
|
|
189
|
-
"ttsSpeechEnded")
|
|
190
|
-
(tts-command event route)
|
|
191
|
-
|
|
192
|
-
(with-source-agency event route)))
|
|
193
|
-
|
|
194
|
-
(defn canonical-agency-event
|
|
195
|
-
"Attach the source known by the agency subscription to an outgoing event.
|
|
196
|
-
|
|
197
|
-
Agency payloads are plain data and may be malformed or supplied by an
|
|
198
|
-
injected provider. The character router must not let a payload select another
|
|
199
|
-
agency's outgoing graph edges by spoofing its `agency` field."
|
|
200
|
-
[source event]
|
|
201
|
-
(assoc event :agency source))
|
|
202
|
-
|
|
203
|
-
(defn create-character-agencies [config]
|
|
204
|
-
(let [input-stream (stream/create-stream)
|
|
205
|
-
event-stream (stream/create-stream)
|
|
206
|
-
emit-input (:emit input-stream)
|
|
207
|
-
emit-event (:emit event-stream)
|
|
208
|
-
agency-society (atom (society/normalize-agency-society
|
|
209
|
-
(when config (aget config "agencySociety"))))
|
|
210
|
-
animation-agency (animation/create-animation-agency
|
|
211
|
-
(society/agency-config config @agency-society "animation"))
|
|
212
|
-
blink-agency (blink/create-blink-agency
|
|
213
|
-
(society/agency-config config @agency-society "blink"))
|
|
214
|
-
gaze-agency (gaze/create-gaze-agency
|
|
215
|
-
(society/agency-config config @agency-society "gaze"))
|
|
216
|
-
eye-head-agency (eye-head/create-eye-head-tracking-agency
|
|
217
|
-
(society/agency-config config @agency-society "eyeHeadTracking"))
|
|
218
|
-
gesture-agency (gesture/create-gesture-agency
|
|
219
|
-
(society/agency-config config @agency-society "gesture"))
|
|
220
|
-
camera-context-agency (camera-context/create-camera-context-agency
|
|
221
|
-
(society/agency-config config @agency-society "cameraContext"))
|
|
222
|
-
transcription-agency (transcription/create-transcription-agency
|
|
223
|
-
(society/agency-config config @agency-society "transcription"))
|
|
224
|
-
conversation-config (society/agency-config
|
|
225
|
-
config @agency-society "conversation")
|
|
226
|
-
;; The provider is injected once into Conversation's private effector.
|
|
227
|
-
;; The character router never invokes provider functions itself.
|
|
228
|
-
conversation-provider (when config (aget config "conversationProvider"))
|
|
229
|
-
conversation-options (if conversation-provider
|
|
230
|
-
(let [options (js/Object.assign
|
|
231
|
-
#js {}
|
|
232
|
-
(or conversation-config #js {}))]
|
|
233
|
-
(aset options "provider" conversation-provider)
|
|
234
|
-
options)
|
|
235
|
-
conversation-config)
|
|
236
|
-
conversation-agency (conversation/create-conversation-agency
|
|
237
|
-
conversation-options)
|
|
238
|
-
tts-agency (tts/create-tts-agency
|
|
239
|
-
(society/agency-config config @agency-society "tts"))
|
|
240
|
-
lipsync-runtime (when config (aget config "lipSyncRuntime"))
|
|
241
|
-
lipsync-agency (lipsync/create-lipsync-agency
|
|
242
|
-
(society/agency-config config @agency-society "lipSync")
|
|
243
|
-
lipsync-runtime)
|
|
244
|
-
prosodic-agency (prosodic/create-prosodic-agency
|
|
245
|
-
(society/agency-config config @agency-society "prosodic"))
|
|
246
|
-
unsubscribers (atom [])
|
|
247
|
-
disposed? (atom false)]
|
|
248
|
-
(letfn [(track! [unsubscribe]
|
|
249
|
-
(swap! unsubscribers conj unsubscribe))
|
|
250
|
-
|
|
251
|
-
(agency-by-name [name]
|
|
252
|
-
(case name
|
|
253
|
-
"animation" animation-agency
|
|
254
|
-
"blink" blink-agency
|
|
255
|
-
"gaze" gaze-agency
|
|
256
|
-
"eyeHeadTracking" eye-head-agency
|
|
257
|
-
"gesture" gesture-agency
|
|
258
|
-
"cameraContext" camera-context-agency
|
|
259
|
-
"transcription" transcription-agency
|
|
260
|
-
"conversation" conversation-agency
|
|
261
|
-
"tts" tts-agency
|
|
262
|
-
"lipSync" lipsync-agency
|
|
263
|
-
"prosodic" prosodic-agency
|
|
264
|
-
nil))
|
|
265
|
-
|
|
266
|
-
(dispatch-to! [name command]
|
|
267
|
-
(when-let [target (agency-by-name name)]
|
|
268
|
-
(when-let [dispatch (aget target "dispatch")]
|
|
269
|
-
(.call dispatch target (clj->js command))
|
|
270
|
-
true)))
|
|
271
|
-
|
|
272
|
-
(route-event! [source event]
|
|
273
|
-
(doseq [route (society/route-contexts @agency-society
|
|
274
|
-
source
|
|
275
|
-
event)]
|
|
276
|
-
(when-let [command (routed-command event route)]
|
|
277
|
-
(when (dispatch-to! (:to route) (assoc command :society route))
|
|
278
|
-
;; Route telemetry is emitted only after the receiving
|
|
279
|
-
;; agency accepted the command. Hosts can therefore draw
|
|
280
|
-
;; the real society traffic without reimplementing route
|
|
281
|
-
;; matching, credit admission, or required-edge rules.
|
|
282
|
-
;; Emitting directly to the character event stream also
|
|
283
|
-
;; prevents this diagnostic event from entering routing
|
|
284
|
-
;; again and recursively producing more commands.
|
|
285
|
-
(emit-event {:type "society.routeActivated"
|
|
286
|
-
:agency "character"
|
|
287
|
-
:edgeId (:edgeId route)
|
|
288
|
-
:from source
|
|
289
|
-
:to (:to route)
|
|
290
|
-
:eventType (:type event)
|
|
291
|
-
:credit (:credit route)
|
|
292
|
-
:at (.now js/Date)})))))
|
|
293
|
-
|
|
294
|
-
(emit-agency-event! [source event]
|
|
295
|
-
(let [payload (canonical-agency-event
|
|
296
|
-
source
|
|
297
|
-
(js->clj event :keywordize-keys true))]
|
|
298
|
-
(route-event! source payload)
|
|
299
|
-
(emit-event payload)))
|
|
300
|
-
|
|
301
|
-
(dispatch! [message]
|
|
302
|
-
(when-not @disposed?
|
|
303
|
-
(let [payload (js->clj message :keywordize-keys true)]
|
|
304
|
-
;; Input is still observable for tests/workers, but the write
|
|
305
|
-
;; path routes to agencies directly inside Polymer.
|
|
306
|
-
(emit-input {:type "command"
|
|
307
|
-
:agency (:agency payload)
|
|
308
|
-
:message payload})
|
|
309
|
-
(let [name (:agency payload)]
|
|
310
|
-
(cond
|
|
311
|
-
(nil? (agency-by-name name))
|
|
312
|
-
(emit-event {:type "error"
|
|
313
|
-
:agency (or name "unknown")
|
|
314
|
-
:message "Unknown Polymer agency"})
|
|
315
|
-
|
|
316
|
-
(not (society/agency-enabled? @agency-society name))
|
|
317
|
-
(emit-event {:type "agencyDisabled"
|
|
318
|
-
:agency name
|
|
319
|
-
:message "Polymer agency is disabled by agencySociety"})
|
|
320
|
-
|
|
321
|
-
:else
|
|
322
|
-
(dispatch-to! name (:command payload)))))))
|
|
323
|
-
|
|
324
|
-
(snapshot! []
|
|
325
|
-
(clj->js {:blink (js->clj (.snapshot ^js blink-agency) :keywordize-keys true)
|
|
326
|
-
:gaze (js->clj (.snapshot ^js gaze-agency) :keywordize-keys true)
|
|
327
|
-
:eyeHeadTracking (js->clj (.snapshot ^js eye-head-agency) :keywordize-keys true)
|
|
328
|
-
:gesture (js->clj (.snapshot ^js gesture-agency) :keywordize-keys true)
|
|
329
|
-
:cameraContext (js->clj (.snapshot ^js camera-context-agency) :keywordize-keys true)
|
|
330
|
-
:transcription (js->clj (.snapshot ^js transcription-agency) :keywordize-keys true)
|
|
331
|
-
:conversation (js->clj (.snapshot ^js conversation-agency) :keywordize-keys true)
|
|
332
|
-
:tts (js->clj (.snapshot ^js tts-agency) :keywordize-keys true)
|
|
333
|
-
:lipSync (js->clj (.snapshot ^js lipsync-agency) :keywordize-keys true)
|
|
334
|
-
:prosodic (js->clj (.snapshot ^js prosodic-agency) :keywordize-keys true)
|
|
335
|
-
:animation (js->clj (.snapshot ^js animation-agency) :keywordize-keys true)
|
|
336
|
-
:agencySociety @agency-society}))
|
|
337
|
-
|
|
338
|
-
(update-society-routing! [next-society]
|
|
339
|
-
(when-not @disposed?
|
|
340
|
-
(let [normalized (society/normalize-agency-society next-society)]
|
|
341
|
-
;; This live update changes route admission only. Agency-local
|
|
342
|
-
;; configure/priors still apply when the character system is
|
|
343
|
-
;; created, so a graph editor cannot bypass local planners.
|
|
344
|
-
(reset! agency-society normalized)
|
|
345
|
-
(emit-input {:type "agencySociety.update"
|
|
346
|
-
:agencySociety normalized})
|
|
347
|
-
(emit-event {:type "agencySocietyUpdated"
|
|
348
|
-
:agency "character"
|
|
349
|
-
:agencySociety normalized})
|
|
350
|
-
(clj->js normalized))))
|
|
351
|
-
|
|
352
|
-
]
|
|
353
|
-
;; Fan-in agency events to one character-level event stream for tests,
|
|
354
|
-
;; workers, and future non-React observers. LoomLarge does not need to
|
|
355
|
-
;; consume this stream for Polymer animation playback.
|
|
356
|
-
(track! (.subscribeEvents ^js animation-agency #(emit-agency-event! "animation" %)))
|
|
357
|
-
(track! (.subscribeEvents ^js blink-agency #(emit-agency-event! "blink" %)))
|
|
358
|
-
(track! (.subscribeEvents ^js gaze-agency #(emit-agency-event! "gaze" %)))
|
|
359
|
-
(track! (.subscribeEvents ^js eye-head-agency #(emit-agency-event! "eyeHeadTracking" %)))
|
|
360
|
-
(track! (.subscribeEvents ^js gesture-agency #(emit-agency-event! "gesture" %)))
|
|
361
|
-
(track! (.subscribeEvents ^js camera-context-agency #(emit-agency-event! "cameraContext" %)))
|
|
362
|
-
(track! (.subscribeEvents ^js transcription-agency #(emit-agency-event! "transcription" %)))
|
|
363
|
-
(track! (.subscribeEvents ^js conversation-agency #(emit-agency-event! "conversation" %)))
|
|
364
|
-
(track! (.subscribeEvents ^js tts-agency #(emit-agency-event! "tts" %)))
|
|
365
|
-
(track! (.subscribeEvents ^js lipsync-agency #(emit-agency-event! "lipSync" %)))
|
|
366
|
-
(track! (.subscribeEvents ^js prosodic-agency #(emit-agency-event! "prosodic" %)))
|
|
367
|
-
(let [api #js {:dispatch dispatch!
|
|
368
|
-
:input (stream/writable-port input-stream dispatch!)
|
|
369
|
-
:events (stream/readable-port event-stream)
|
|
370
|
-
:snapshot snapshot!
|
|
371
|
-
:updateSocietyRouting update-society-routing!
|
|
372
|
-
:agency (fn [name]
|
|
373
|
-
(when (society/agency-enabled? @agency-society name)
|
|
374
|
-
(agency-by-name name)))
|
|
375
|
-
:subscribeInput (fn [listener] ((:subscribe input-stream) listener))
|
|
376
|
-
:subscribeEvents (fn [listener] ((:subscribe event-stream) listener))
|
|
377
|
-
:subscribe (fn [listener] ((:subscribe event-stream) listener))
|
|
378
|
-
:subscribeStatus (fn [listener] ((:subscribe event-stream) listener))
|
|
379
|
-
:dispose (fn []
|
|
380
|
-
(when-not @disposed?
|
|
381
|
-
(reset! disposed? true)
|
|
382
|
-
(doseq [unsubscribe @unsubscribers]
|
|
383
|
-
(unsubscribe))
|
|
384
|
-
(reset! unsubscribers [])
|
|
385
|
-
(.dispose ^js blink-agency)
|
|
386
|
-
(.dispose ^js gaze-agency)
|
|
387
|
-
(.dispose ^js eye-head-agency)
|
|
388
|
-
(.dispose ^js gesture-agency)
|
|
389
|
-
(.dispose ^js camera-context-agency)
|
|
390
|
-
(.dispose ^js transcription-agency)
|
|
391
|
-
(.dispose ^js conversation-agency)
|
|
392
|
-
(.dispose ^js tts-agency)
|
|
393
|
-
(.dispose ^js lipsync-agency)
|
|
394
|
-
(.dispose ^js prosodic-agency)
|
|
395
|
-
(.dispose ^js animation-agency)
|
|
396
|
-
((:dispose input-stream))
|
|
397
|
-
((:dispose event-stream))))}]
|
|
398
|
-
(js/Object.defineProperty
|
|
399
|
-
api
|
|
400
|
-
"agencySociety"
|
|
401
|
-
#js {:enumerable true
|
|
402
|
-
:get #(clj->js @agency-society)})
|
|
403
|
-
api))))
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
(ns polymer.conversation.agency
|
|
2
|
-
(:require [polymer.conversation.domain :as domain]
|
|
3
|
-
[polymer.conversation.effector :as effector]
|
|
4
|
-
[polymer.conversation.planner :as planner]
|
|
5
|
-
[polymer.conversation.scheduler :as scheduler]
|
|
6
|
-
[polymer.conversation.state :as state]
|
|
7
|
-
[polymer.stream :as stream]))
|
|
8
|
-
|
|
9
|
-
;; Conversation is a peer agency in the Polymer character society. It accepts
|
|
10
|
-
;; transcript, response, and interruption facts as data; plans local turn-taking
|
|
11
|
-
;; work; schedules those actions; then emits requests/facts that TTS, Gaze,
|
|
12
|
-
;; Prosodic, and other agencies can decide how to handle.
|
|
13
|
-
|
|
14
|
-
(defn now-ms
|
|
15
|
-
[]
|
|
16
|
-
(.now js/Date))
|
|
17
|
-
|
|
18
|
-
(defn js-command
|
|
19
|
-
[type value]
|
|
20
|
-
#js {:type type :value value})
|
|
21
|
-
|
|
22
|
-
(defn create-conversation-agency
|
|
23
|
-
[config]
|
|
24
|
-
(let [provider (if (map? config)
|
|
25
|
-
(or (:provider config)
|
|
26
|
-
(:conversationProvider config))
|
|
27
|
-
(when config
|
|
28
|
-
(or (aget config "provider")
|
|
29
|
-
(aget config "conversationProvider"))))
|
|
30
|
-
config-map (domain/data-map config)
|
|
31
|
-
state-config (dissoc config-map :provider :conversationProvider)
|
|
32
|
-
input-stream (stream/create-stream)
|
|
33
|
-
event-stream (stream/create-stream)
|
|
34
|
-
state-atom (atom (state/config->state state-config))
|
|
35
|
-
disposed? (atom false)
|
|
36
|
-
emit-input (:emit input-stream)
|
|
37
|
-
emit-event (:emit event-stream)
|
|
38
|
-
scheduler-atom (atom nil)]
|
|
39
|
-
(letfn [(dispatch! [command]
|
|
40
|
-
(when-not @disposed?
|
|
41
|
-
(let [payload (domain/data-map command)
|
|
42
|
-
plan (planner/plan-command payload @state-atom (now-ms))]
|
|
43
|
-
;; Input is observable for workers/tests and for future
|
|
44
|
-
;; diagnostics. It is not host application state and should
|
|
45
|
-
;; not be mirrored into a UI on every agency message.
|
|
46
|
-
(emit-input {:type "command"
|
|
47
|
-
:agency "conversation"
|
|
48
|
-
:command payload})
|
|
49
|
-
(when-let [agency-scheduler @scheduler-atom]
|
|
50
|
-
((:schedule agency-scheduler) payload plan)))))
|
|
51
|
-
(dispatch-type! [type]
|
|
52
|
-
(dispatch! #js {:type type}))]
|
|
53
|
-
(let [agency-scheduler (scheduler/create-scheduler
|
|
54
|
-
{:state-atom state-atom
|
|
55
|
-
:emit-event emit-event
|
|
56
|
-
:dispatch-command dispatch!
|
|
57
|
-
:provider-effector
|
|
58
|
-
(effector/create-provider-effector provider)})]
|
|
59
|
-
(reset! scheduler-atom agency-scheduler)
|
|
60
|
-
#js {:dispatch dispatch!
|
|
61
|
-
:snapshot (fn [] (state/visible-state @state-atom))
|
|
62
|
-
:input (stream/writable-port input-stream dispatch!)
|
|
63
|
-
:events (stream/readable-port event-stream)
|
|
64
|
-
:subscribeInput (fn [listener] ((:subscribe input-stream) listener))
|
|
65
|
-
:subscribeEvents (fn [listener] ((:subscribe event-stream) listener))
|
|
66
|
-
:subscribe (fn [listener] ((:subscribe event-stream) listener))
|
|
67
|
-
:subscribeStatus (fn [listener] ((:subscribe event-stream) listener))
|
|
68
|
-
:start (fn [] (dispatch-type! "start"))
|
|
69
|
-
:stop (fn [] (dispatch-type! "stop"))
|
|
70
|
-
:reset (fn [] (dispatch-type! "reset"))
|
|
71
|
-
:interrupt (fn
|
|
72
|
-
([] (dispatch-type! "interrupt"))
|
|
73
|
-
([reason] (dispatch! #js {:type "interrupt" :reason reason})))
|
|
74
|
-
:setAutoRespond (fn [value]
|
|
75
|
-
(dispatch! #js {:type "configure"
|
|
76
|
-
:config #js {:autoRespond value}}))
|
|
77
|
-
:queue (fn [] (clj->js ((:queue agency-scheduler))))
|
|
78
|
-
:dispose (fn []
|
|
79
|
-
(when-not @disposed?
|
|
80
|
-
(reset! disposed? true)
|
|
81
|
-
((:dispose agency-scheduler))
|
|
82
|
-
((:dispose input-stream))
|
|
83
|
-
((:dispose event-stream))))}))))
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
(ns polymer.conversation.domain
|
|
2
|
-
(:require [clojure.string :as str]))
|
|
3
|
-
|
|
4
|
-
;; Pure Conversation transforms live here so command normalization is shared by
|
|
5
|
-
;; state, planner, and the JS-facing agency boundary.
|
|
6
|
-
|
|
7
|
-
(defn data-map
|
|
8
|
-
[value]
|
|
9
|
-
(cond
|
|
10
|
-
(map? value) value
|
|
11
|
-
value (js->clj value :keywordize-keys true)
|
|
12
|
-
:else {}))
|
|
13
|
-
|
|
14
|
-
(defn clean-text
|
|
15
|
-
[value]
|
|
16
|
-
(let [text (str/trim (or value ""))]
|
|
17
|
-
(when (pos? (count text))
|
|
18
|
-
text)))
|
|
19
|
-
|
|
20
|
-
(defn text-or
|
|
21
|
-
[value fallback]
|
|
22
|
-
(or (clean-text value) fallback))
|
|
23
|
-
|
|
24
|
-
(defn user-text
|
|
25
|
-
[command]
|
|
26
|
-
(clean-text (or (:text command)
|
|
27
|
-
(:transcript command)
|
|
28
|
-
(:utterance command))))
|
|
29
|
-
|
|
30
|
-
(defn agent-text
|
|
31
|
-
[command]
|
|
32
|
-
(clean-text (or (:agentText command)
|
|
33
|
-
(:responseText command)
|
|
34
|
-
(:text command)
|
|
35
|
-
(:utterance command))))
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
(ns polymer.conversation.effector
|
|
2
|
-
(:require [polymer.conversation.domain :as domain]))
|
|
3
|
-
|
|
4
|
-
;; The provider effector is the only Conversation code allowed to invoke an
|
|
5
|
-
;; external LLM/backend provider. It receives already-planned request data from
|
|
6
|
-
;; the scheduler and reports plain completion data back to the agency.
|
|
7
|
-
|
|
8
|
-
(defn provider-call
|
|
9
|
-
[provider]
|
|
10
|
-
(cond
|
|
11
|
-
(fn? provider)
|
|
12
|
-
{:target nil
|
|
13
|
-
:respond provider}
|
|
14
|
-
|
|
15
|
-
(and provider (fn? (aget provider "respond")))
|
|
16
|
-
{:target provider
|
|
17
|
-
:respond (aget provider "respond")}
|
|
18
|
-
|
|
19
|
-
:else nil))
|
|
20
|
-
|
|
21
|
-
(defn thenable?
|
|
22
|
-
[value]
|
|
23
|
-
(and value (fn? (aget value "then"))))
|
|
24
|
-
|
|
25
|
-
(defn cleanup-callback
|
|
26
|
-
[value]
|
|
27
|
-
(cond
|
|
28
|
-
(fn? value)
|
|
29
|
-
value
|
|
30
|
-
|
|
31
|
-
:else
|
|
32
|
-
(when value
|
|
33
|
-
(some (fn [method-name]
|
|
34
|
-
(when-let [method (aget value method-name)]
|
|
35
|
-
(when (fn? method)
|
|
36
|
-
#(.call method value))))
|
|
37
|
-
["cancel" "abort" "stop" "dispose"]))))
|
|
38
|
-
|
|
39
|
-
(defn response-data
|
|
40
|
-
[response]
|
|
41
|
-
(cond
|
|
42
|
-
(string? response) {:text response}
|
|
43
|
-
(map? response) response
|
|
44
|
-
response (domain/data-map response)
|
|
45
|
-
:else {}))
|
|
46
|
-
|
|
47
|
-
(defn error-message
|
|
48
|
-
[error]
|
|
49
|
-
(or (domain/clean-text (when error (aget error "message")))
|
|
50
|
-
(domain/clean-text (when (string? error) error))
|
|
51
|
-
(domain/clean-text (str error))
|
|
52
|
-
"conversation-provider-error"))
|
|
53
|
-
|
|
54
|
-
(defn create-provider-effector
|
|
55
|
-
[provider]
|
|
56
|
-
(let [call (provider-call provider)
|
|
57
|
-
active (atom {})
|
|
58
|
-
disposed? (atom false)]
|
|
59
|
-
(letfn [(active-token? [request-id token]
|
|
60
|
-
(identical? token (get-in @active [request-id :token])))
|
|
61
|
-
|
|
62
|
-
(settle! [request-id token callback value]
|
|
63
|
-
(when (and (not @disposed?)
|
|
64
|
-
(active-token? request-id token))
|
|
65
|
-
(swap! active dissoc request-id)
|
|
66
|
-
(callback value)))
|
|
67
|
-
|
|
68
|
-
(cancel-entry! [request-id]
|
|
69
|
-
(when-let [{:keys [cleanup]} (get @active request-id)]
|
|
70
|
-
(swap! active dissoc request-id)
|
|
71
|
-
(when cleanup
|
|
72
|
-
(try
|
|
73
|
-
(cleanup)
|
|
74
|
-
(catch :default _
|
|
75
|
-
nil)))))
|
|
76
|
-
|
|
77
|
-
(remember-cleanup! [request-id token cleanup]
|
|
78
|
-
(when (and cleanup (active-token? request-id token))
|
|
79
|
-
(swap! active assoc-in [request-id :cleanup] cleanup)))
|
|
80
|
-
|
|
81
|
-
(invoke! [request on-success on-error]
|
|
82
|
-
(when (and call (not @disposed?))
|
|
83
|
-
(let [request-id (:requestId request)
|
|
84
|
-
token (js-obj)
|
|
85
|
-
succeed! #(settle! request-id token on-success
|
|
86
|
-
(response-data %))
|
|
87
|
-
fail! #(settle! request-id token on-error
|
|
88
|
-
{:message (error-message %)})
|
|
89
|
-
request-js (clj->js (dissoc request
|
|
90
|
-
:type
|
|
91
|
-
:agency
|
|
92
|
-
:targetAgency))]
|
|
93
|
-
(cancel-entry! request-id)
|
|
94
|
-
(swap! active assoc request-id {:token token
|
|
95
|
-
:cleanup nil})
|
|
96
|
-
(try
|
|
97
|
-
(let [result (.call (:respond call)
|
|
98
|
-
(:target call)
|
|
99
|
-
request-js
|
|
100
|
-
succeed!
|
|
101
|
-
fail!)
|
|
102
|
-
cleanup (cleanup-callback result)]
|
|
103
|
-
(cond
|
|
104
|
-
(thenable? result)
|
|
105
|
-
(do
|
|
106
|
-
(remember-cleanup! request-id token cleanup)
|
|
107
|
-
(.then result succeed! fail!))
|
|
108
|
-
|
|
109
|
-
cleanup
|
|
110
|
-
(remember-cleanup! request-id token cleanup)
|
|
111
|
-
|
|
112
|
-
(some? result)
|
|
113
|
-
(succeed! result)
|
|
114
|
-
|
|
115
|
-
:else nil))
|
|
116
|
-
(catch :default error
|
|
117
|
-
(fail! error))))))
|
|
118
|
-
|
|
119
|
-
(cancel-all! []
|
|
120
|
-
(doseq [request-id (keys @active)]
|
|
121
|
-
(cancel-entry! request-id)))]
|
|
122
|
-
{:available? (boolean call)
|
|
123
|
-
:invoke invoke!
|
|
124
|
-
:cancel cancel-entry!
|
|
125
|
-
:cancel-all cancel-all!
|
|
126
|
-
:dispose
|
|
127
|
-
(fn []
|
|
128
|
-
(when-not @disposed?
|
|
129
|
-
(cancel-all!)
|
|
130
|
-
(reset! disposed? true)))})))
|