@lovelace_lol/polymer 0.0.7 → 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.
Files changed (95) hide show
  1. package/README.md +434 -12
  2. package/dist/index.d.ts +1945 -244
  3. package/dist/index.js +1686 -1017
  4. package/dist/vision/face-worker.js +296 -0
  5. package/dist/vision/face_landmarker.task +0 -0
  6. package/dist/vision/manifest.edn +1 -0
  7. package/dist/vision/vision_bundle.js +2 -0
  8. package/dist/vision/wasm/vision_wasm_internal.js +8841 -0
  9. package/dist/vision/wasm/vision_wasm_internal.wasm +0 -0
  10. package/dist/vision/wasm/vision_wasm_module_internal.js +8837 -0
  11. package/dist/vision/wasm/vision_wasm_module_internal.wasm +0 -0
  12. package/dist/vision/wasm/vision_wasm_nosimd_internal.js +8832 -0
  13. package/dist/vision/wasm/vision_wasm_nosimd_internal.wasm +0 -0
  14. package/dist/worker/agency-worker.js +1276 -962
  15. package/dist/worker/manifest.edn +1 -1
  16. package/package.json +33 -20
  17. package/dist/test.cjs +0 -1519
  18. package/shadow-cljs.edn +0 -173
  19. package/src/polymer/animation/agency.cljs +0 -84
  20. package/src/polymer/animation/domain.cljs +0 -110
  21. package/src/polymer/animation/planner.cljs +0 -88
  22. package/src/polymer/animation/runtime.cljs +0 -137
  23. package/src/polymer/animation/scheduler.cljs +0 -178
  24. package/src/polymer/animation/service.cljs +0 -981
  25. package/src/polymer/animation/state.cljs +0 -112
  26. package/src/polymer/blink/agency.cljs +0 -131
  27. package/src/polymer/blink/planner.cljs +0 -115
  28. package/src/polymer/blink/scheduler.cljs +0 -90
  29. package/src/polymer/blink/snippet.cljs +0 -50
  30. package/src/polymer/blink/state.cljs +0 -102
  31. package/src/polymer/camera_context/agency.cljs +0 -132
  32. package/src/polymer/camera_context/domain.cljs +0 -186
  33. package/src/polymer/camera_context/planner.cljs +0 -50
  34. package/src/polymer/camera_context/scheduler.cljs +0 -113
  35. package/src/polymer/camera_context/state.cljs +0 -121
  36. package/src/polymer/character.cljs +0 -403
  37. package/src/polymer/conversation/agency.cljs +0 -83
  38. package/src/polymer/conversation/domain.cljs +0 -35
  39. package/src/polymer/conversation/effector.cljs +0 -130
  40. package/src/polymer/conversation/planner.cljs +0 -178
  41. package/src/polymer/conversation/scheduler.cljs +0 -202
  42. package/src/polymer/conversation/service.cljs +0 -329
  43. package/src/polymer/conversation/state.cljs +0 -186
  44. package/src/polymer/core.cljs +0 -172
  45. package/src/polymer/eye_head/agency.cljs +0 -75
  46. package/src/polymer/eye_head/domain.cljs +0 -133
  47. package/src/polymer/eye_head/goap.cljs +0 -106
  48. package/src/polymer/eye_head/scheduler.cljs +0 -176
  49. package/src/polymer/eye_head/service.cljs +0 -259
  50. package/src/polymer/eye_head/snippet.cljs +0 -92
  51. package/src/polymer/eye_head/state.cljs +0 -167
  52. package/src/polymer/gaze/agency.cljs +0 -85
  53. package/src/polymer/gaze/domain.cljs +0 -211
  54. package/src/polymer/gaze/goap.cljs +0 -208
  55. package/src/polymer/gaze/scheduler.cljs +0 -184
  56. package/src/polymer/gaze/state.cljs +0 -202
  57. package/src/polymer/gesture/agency.cljs +0 -185
  58. package/src/polymer/gesture/goap.cljs +0 -461
  59. package/src/polymer/gesture/scheduler.cljs +0 -122
  60. package/src/polymer/gesture/snippet.cljs +0 -198
  61. package/src/polymer/gesture/state.cljs +0 -273
  62. package/src/polymer/lipsync/agency.cljs +0 -593
  63. package/src/polymer/lipsync/articulation/jaw.cljs +0 -258
  64. package/src/polymer/lipsync/articulation/snippet.cljs +0 -605
  65. package/src/polymer/lipsync/articulation/tongue.cljs +0 -418
  66. package/src/polymer/lipsync/articulation/visemes.cljs +0 -429
  67. package/src/polymer/lipsync/goap.cljs +0 -132
  68. package/src/polymer/lipsync/pronunciation/effector.cljs +0 -51
  69. package/src/polymer/lipsync/scheduler.cljs +0 -302
  70. package/src/polymer/lipsync/state.cljs +0 -202
  71. package/src/polymer/nlp/phonemes.cljs +0 -164
  72. package/src/polymer/prosodic/agency.cljs +0 -196
  73. package/src/polymer/prosodic/goap.cljs +0 -122
  74. package/src/polymer/prosodic/scheduler.cljs +0 -99
  75. package/src/polymer/prosodic/snippet.cljs +0 -106
  76. package/src/polymer/prosodic/state.cljs +0 -139
  77. package/src/polymer/runtime/embody.cljs +0 -117
  78. package/src/polymer/runtime/embody_wasm.cljs +0 -177
  79. package/src/polymer/runtime/rust_embody_host.cljs +0 -647
  80. package/src/polymer/society.cljs +0 -253
  81. package/src/polymer/stream.cljs +0 -130
  82. package/src/polymer/transcription/agency.cljs +0 -69
  83. package/src/polymer/transcription/domain.cljs +0 -68
  84. package/src/polymer/transcription/effector.cljs +0 -611
  85. package/src/polymer/transcription/planner.cljs +0 -203
  86. package/src/polymer/transcription/scheduler.cljs +0 -225
  87. package/src/polymer/transcription/service.cljs +0 -209
  88. package/src/polymer/transcription/state.cljs +0 -239
  89. package/src/polymer/tts/agency.cljs +0 -503
  90. package/src/polymer/tts/azure.cljs +0 -290
  91. package/src/polymer/tts/planner.cljs +0 -178
  92. package/src/polymer/tts/runtime.cljs +0 -624
  93. package/src/polymer/tts/scheduler.cljs +0 -162
  94. package/src/polymer/tts/state.cljs +0 -191
  95. 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)))})))