@lovelace_lol/polymer 0.0.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.
Files changed (85) hide show
  1. package/README.md +226 -0
  2. package/dist/index.d.ts +2603 -0
  3. package/dist/index.js +1031 -0
  4. package/dist/test.cjs +1519 -0
  5. package/dist/worker/agency-worker.js +972 -0
  6. package/dist/worker/manifest.edn +1 -0
  7. package/package.json +57 -0
  8. package/shadow-cljs.edn +173 -0
  9. package/src/polymer/animation/agency.cljs +84 -0
  10. package/src/polymer/animation/domain.cljs +110 -0
  11. package/src/polymer/animation/planner.cljs +88 -0
  12. package/src/polymer/animation/runtime.cljs +137 -0
  13. package/src/polymer/animation/scheduler.cljs +178 -0
  14. package/src/polymer/animation/service.cljs +981 -0
  15. package/src/polymer/animation/state.cljs +112 -0
  16. package/src/polymer/blink/agency.cljs +131 -0
  17. package/src/polymer/blink/planner.cljs +115 -0
  18. package/src/polymer/blink/scheduler.cljs +90 -0
  19. package/src/polymer/blink/snippet.cljs +50 -0
  20. package/src/polymer/blink/state.cljs +102 -0
  21. package/src/polymer/camera_context/agency.cljs +132 -0
  22. package/src/polymer/camera_context/domain.cljs +186 -0
  23. package/src/polymer/camera_context/planner.cljs +50 -0
  24. package/src/polymer/camera_context/scheduler.cljs +113 -0
  25. package/src/polymer/camera_context/state.cljs +121 -0
  26. package/src/polymer/character.cljs +471 -0
  27. package/src/polymer/conversation/agency.cljs +83 -0
  28. package/src/polymer/conversation/domain.cljs +35 -0
  29. package/src/polymer/conversation/effector.cljs +130 -0
  30. package/src/polymer/conversation/planner.cljs +178 -0
  31. package/src/polymer/conversation/scheduler.cljs +202 -0
  32. package/src/polymer/conversation/service.cljs +329 -0
  33. package/src/polymer/conversation/state.cljs +186 -0
  34. package/src/polymer/core.cljs +172 -0
  35. package/src/polymer/eye_head/agency.cljs +75 -0
  36. package/src/polymer/eye_head/domain.cljs +133 -0
  37. package/src/polymer/eye_head/goap.cljs +106 -0
  38. package/src/polymer/eye_head/scheduler.cljs +176 -0
  39. package/src/polymer/eye_head/service.cljs +259 -0
  40. package/src/polymer/eye_head/snippet.cljs +92 -0
  41. package/src/polymer/eye_head/state.cljs +167 -0
  42. package/src/polymer/gaze/agency.cljs +85 -0
  43. package/src/polymer/gaze/domain.cljs +211 -0
  44. package/src/polymer/gaze/goap.cljs +208 -0
  45. package/src/polymer/gaze/scheduler.cljs +184 -0
  46. package/src/polymer/gaze/state.cljs +202 -0
  47. package/src/polymer/gesture/agency.cljs +185 -0
  48. package/src/polymer/gesture/goap.cljs +461 -0
  49. package/src/polymer/gesture/scheduler.cljs +122 -0
  50. package/src/polymer/gesture/snippet.cljs +198 -0
  51. package/src/polymer/gesture/state.cljs +273 -0
  52. package/src/polymer/lipsync/agency.cljs +593 -0
  53. package/src/polymer/lipsync/articulation/jaw.cljs +258 -0
  54. package/src/polymer/lipsync/articulation/snippet.cljs +605 -0
  55. package/src/polymer/lipsync/articulation/tongue.cljs +418 -0
  56. package/src/polymer/lipsync/articulation/visemes.cljs +429 -0
  57. package/src/polymer/lipsync/goap.cljs +132 -0
  58. package/src/polymer/lipsync/pronunciation/effector.cljs +51 -0
  59. package/src/polymer/lipsync/scheduler.cljs +302 -0
  60. package/src/polymer/lipsync/state.cljs +202 -0
  61. package/src/polymer/nlp/phonemes.cljs +164 -0
  62. package/src/polymer/prosodic/agency.cljs +196 -0
  63. package/src/polymer/prosodic/goap.cljs +122 -0
  64. package/src/polymer/prosodic/scheduler.cljs +99 -0
  65. package/src/polymer/prosodic/snippet.cljs +106 -0
  66. package/src/polymer/prosodic/state.cljs +139 -0
  67. package/src/polymer/runtime/embody.cljs +117 -0
  68. package/src/polymer/runtime/embody_wasm.cljs +177 -0
  69. package/src/polymer/runtime/rust_embody_host.cljs +645 -0
  70. package/src/polymer/society.cljs +239 -0
  71. package/src/polymer/stream.cljs +130 -0
  72. package/src/polymer/transcription/agency.cljs +69 -0
  73. package/src/polymer/transcription/domain.cljs +68 -0
  74. package/src/polymer/transcription/effector.cljs +611 -0
  75. package/src/polymer/transcription/planner.cljs +203 -0
  76. package/src/polymer/transcription/scheduler.cljs +225 -0
  77. package/src/polymer/transcription/service.cljs +209 -0
  78. package/src/polymer/transcription/state.cljs +239 -0
  79. package/src/polymer/tts/agency.cljs +503 -0
  80. package/src/polymer/tts/azure.cljs +290 -0
  81. package/src/polymer/tts/planner.cljs +178 -0
  82. package/src/polymer/tts/runtime.cljs +624 -0
  83. package/src/polymer/tts/scheduler.cljs +162 -0
  84. package/src/polymer/tts/state.cljs +191 -0
  85. package/src/polymer/worker.cljs +70 -0
@@ -0,0 +1,130 @@
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)))})))
@@ -0,0 +1,178 @@
1
+ (ns polymer.conversation.planner
2
+ (:require [polymer.conversation.domain :as domain]))
3
+
4
+ ;; Conversation planning stays agency-local. It decides what this agency wants
5
+ ;; to do with a transcript, provider result, or interruption, then hands ordered
6
+ ;; action data to the scheduler. It never calls a backend, TTS provider, or peer
7
+ ;; agency function directly.
8
+
9
+ (def supported-command-types
10
+ #{"configure"
11
+ "start"
12
+ "stop"
13
+ "reset"
14
+ "cancel"
15
+ "interrupt"
16
+ "transcript.final"
17
+ "transcriptFinal"
18
+ "userUtterance"
19
+ "agentUtterance"
20
+ "responseReady"
21
+ "providerError"
22
+ "tts.status"})
23
+
24
+ (defn command-type
25
+ [command]
26
+ (:type command))
27
+
28
+ (defn request-id
29
+ [prefix now-ms]
30
+ (str prefix ":" now-ms ":" (rand-int 1000000)))
31
+
32
+ (defn stale-response?
33
+ [command state]
34
+ (or (:interrupted state)
35
+ (nil? (:pendingResponse state))
36
+ (and (:turnId command)
37
+ (not= (:turnId command) (:turnId state)))
38
+ (and (:requestId command)
39
+ (not= (:requestId command)
40
+ (:requestId (:pendingResponse state))))))
41
+
42
+ (defn failure-step
43
+ [command]
44
+ (cond
45
+ (not (contains? supported-command-types (command-type command)))
46
+ {:op "fail"
47
+ :reason "unsupported-command"
48
+ :commandType (command-type command)}
49
+
50
+ (and (#{"transcript.final" "transcriptFinal" "userUtterance"} (command-type command))
51
+ (not (domain/user-text command)))
52
+ {:op "fail"
53
+ :reason "missing-user-text"
54
+ :commandType (command-type command)}
55
+
56
+ (and (#{"agentUtterance" "responseReady"} (command-type command))
57
+ (not (domain/agent-text command)))
58
+ {:op "fail"
59
+ :reason "missing-agent-text"
60
+ :commandType (command-type command)}))
61
+
62
+ (defn transcript-steps
63
+ [command state now-ms]
64
+ (let [text (domain/user-text command)
65
+ source (or (:source command) "transcription")
66
+ pending-request-id (get-in state [:pendingResponse :requestId])
67
+ response-text (domain/clean-text (or (:responseText command) (:agentText command)))
68
+ response-request {:requestId (request-id "conversation:response" now-ms)
69
+ :text text
70
+ :source source
71
+ :turnId (:turnId state)
72
+ :history (:history state)
73
+ :requestedAt now-ms}]
74
+ (cond-> [{:op "record-user-utterance"
75
+ :text text
76
+ :source source}
77
+ {:op "emit-user-utterance"
78
+ :text text
79
+ :source source}]
80
+ (and (get-in state [:config :autoRespond])
81
+ pending-request-id)
82
+ (conj {:op "cancel-provider"
83
+ :requestId pending-request-id
84
+ :reason "superseded"})
85
+
86
+ (get-in state [:config :autoRespond])
87
+ (conj {:op "request-response"
88
+ :request response-request}
89
+ {:op "invoke-provider"
90
+ :request response-request})
91
+
92
+ response-text
93
+ (conj {:op "record-agent-utterance"
94
+ :text response-text
95
+ :source "response"}
96
+ {:op "request-tts"
97
+ :text response-text
98
+ :source "response"
99
+ :requestId (request-id "conversation:tts" now-ms)}))))
100
+
101
+ (defn agent-utterance-steps
102
+ [command state now-ms]
103
+ (let [text (domain/agent-text command)]
104
+ (if (and (= "responseReady" (:type command))
105
+ (stale-response? command state))
106
+ [{:op "ignore-stale-response"
107
+ :reason "stale-response"
108
+ :requestId (:requestId command)
109
+ :turnId (:turnId command)}]
110
+ [{:op "record-agent-utterance"
111
+ :text text
112
+ :source (or (:source command) "conversation")}
113
+ {:op "request-tts"
114
+ :text text
115
+ :source (or (:source command) "conversation")
116
+ :requestId (request-id "conversation:tts" now-ms)}])))
117
+
118
+ (defn provider-error-steps
119
+ [command state]
120
+ (if (stale-response? command state)
121
+ [{:op "ignore-stale-response"
122
+ :reason "stale-provider-error"
123
+ :requestId (:requestId command)
124
+ :turnId (:turnId command)}]
125
+ [{:op "record-provider-error"
126
+ :requestId (:requestId command)
127
+ :turnId (:turnId command)
128
+ :message (or (:message command) "conversation-provider-error")}
129
+ {:op "publish-provider-error"
130
+ :requestId (:requestId command)
131
+ :turnId (:turnId command)
132
+ :message (or (:message command) "conversation-provider-error")}]))
133
+
134
+ (defn command-steps
135
+ [command state now-ms]
136
+ (if-let [failure (failure-step command)]
137
+ [failure]
138
+ (case (command-type command)
139
+ "configure" [{:op "apply-config"}
140
+ {:op "publish-status" :status (:status state)}]
141
+ "start" [{:op "start-session"}
142
+ {:op "publish-status" :status "listening"}]
143
+ "stop" [{:op "cancel-provider"
144
+ :requestId (get-in state [:pendingResponse :requestId])
145
+ :reason (or (:reason command) "stopped")}
146
+ {:op "stop-session" :reason (or (:reason command) "stopped")}
147
+ {:op "publish-status" :status "idle"}]
148
+ "reset" [{:op "cancel-provider"
149
+ :requestId (get-in state [:pendingResponse :requestId])
150
+ :reason "reset"}
151
+ {:op "reset-state"}
152
+ {:op "publish-status" :status "idle"}]
153
+ ("cancel" "interrupt") [{:op "cancel-provider"
154
+ :requestId (get-in state [:pendingResponse :requestId])
155
+ :reason (or (:reason command) (command-type command))}
156
+ {:op "cancel-turn"
157
+ :reason (or (:reason command) (command-type command))}
158
+ {:op "publish-cancel"
159
+ :reason (or (:reason command) (command-type command))}
160
+ {:op "publish-status" :status "interrupted"}]
161
+ ("transcript.final" "transcriptFinal" "userUtterance")
162
+ (transcript-steps command state now-ms)
163
+ ("agentUtterance" "responseReady")
164
+ (agent-utterance-steps command state now-ms)
165
+ "providerError"
166
+ (provider-error-steps command state)
167
+ "tts.status" [{:op "record-tts-status"
168
+ :status (:status command)}
169
+ {:op "publish-status" :status (:status command)}])))
170
+
171
+ (defn plan-command
172
+ [command state now-ms]
173
+ (let [steps (command-steps command state now-ms)]
174
+ {:agency "conversation"
175
+ :commandType (command-type command)
176
+ :createdAt now-ms
177
+ :ok (not= "fail" (:op (first steps)))
178
+ :steps steps}))
@@ -0,0 +1,202 @@
1
+ (ns polymer.conversation.scheduler
2
+ (:require [polymer.conversation.state :as state]))
3
+
4
+ ;; The Conversation scheduler is the ordered work boundary for the agency. This
5
+ ;; first slice executes immediately, but it still records every planned step in
6
+ ;; a queue so future backend/provider sequencing, retries, and cancellation can
7
+ ;; extend the same architecture without moving logic into host UI code.
8
+
9
+ (defn now-ms
10
+ []
11
+ (.now js/Date))
12
+
13
+ (defn queue-entry
14
+ [step index plan]
15
+ (assoc step
16
+ :agency "conversation"
17
+ :queueIndex index
18
+ :commandType (:commandType plan)
19
+ :queuedAt (now-ms)))
20
+
21
+ (defn emit-status!
22
+ [emit-event state-atom status reason]
23
+ (emit-event (cond-> {:type "conversation.status"
24
+ :agency "conversation"
25
+ :status status
26
+ :turnId (:turnId @state-atom)
27
+ :at (now-ms)}
28
+ reason (assoc :reason reason))))
29
+
30
+ (defn create-scheduler
31
+ [{:keys [state-atom emit-event dispatch-command provider-effector]}]
32
+ (let [queue (atom [])
33
+ disposed? (atom false)]
34
+ (letfn [(enqueue! [step plan]
35
+ (let [entry (queue-entry step (count @queue) plan)]
36
+ (swap! queue conj entry)
37
+ entry))
38
+
39
+ (request-tts! [step requested-at]
40
+ (let [request {:type "tts.requestSpeak"
41
+ :agency "conversation"
42
+ :targetAgency (get-in @state-atom [:config :ttsAgency])
43
+ :requestId (:requestId step)
44
+ :text (:text step)
45
+ :source (:source step)
46
+ :turnId (:turnId @state-atom)
47
+ :requestedAt requested-at
48
+ :command {:type "speak"
49
+ :text (:text step)
50
+ :source "conversation"}}]
51
+ (swap! state-atom state/record-tts-request request)
52
+ (emit-event request)))
53
+
54
+ (invoke-provider! [request]
55
+ (when (:available? provider-effector)
56
+ ((:invoke provider-effector)
57
+ request
58
+ (fn [response]
59
+ (dispatch-command
60
+ {:type "responseReady"
61
+ :requestId (:requestId request)
62
+ :turnId (:turnId request)
63
+ :text (or (:text response)
64
+ (:responseText response)
65
+ (:agentText response))
66
+ :source (or (:source response)
67
+ (get-in @state-atom [:config :responseSource]))}))
68
+ (fn [error]
69
+ (dispatch-command
70
+ {:type "providerError"
71
+ :requestId (:requestId request)
72
+ :turnId (:turnId request)
73
+ :message (:message error)})))))
74
+
75
+ (execute-step! [step command plan]
76
+ (let [now (now-ms)]
77
+ (enqueue! step plan)
78
+ (case (:op step)
79
+ "apply-config"
80
+ (do
81
+ (swap! state-atom state/configure (:config command))
82
+ (emit-status! emit-event state-atom (:status @state-atom) "configured"))
83
+
84
+ "start-session"
85
+ (do
86
+ (swap! state-atom state/mark-started now)
87
+ (emit-status! emit-event state-atom "listening" nil))
88
+
89
+ "stop-session"
90
+ (do
91
+ (swap! state-atom state/mark-stopped now (:reason step))
92
+ (emit-status! emit-event state-atom "idle" (:reason step)))
93
+
94
+ "reset-state"
95
+ (do
96
+ (swap! state-atom state/reset-state)
97
+ (emit-status! emit-event state-atom "idle" "reset"))
98
+
99
+ "record-user-utterance"
100
+ (swap! state-atom state/record-user-utterance (:text step) now (:source step))
101
+
102
+ "emit-user-utterance"
103
+ (emit-event {:type "conversation.userUtterance"
104
+ :agency "conversation"
105
+ :text (:text step)
106
+ :source (:source step)
107
+ :turnId (:turnId @state-atom)
108
+ :at now})
109
+
110
+ "request-response"
111
+ (let [request (:request step)]
112
+ (swap! state-atom state/record-response-request request)
113
+ (emit-event (assoc request
114
+ :type "conversation.requestResponse"
115
+ :agency "conversation"
116
+ :targetAgency "conversation-provider")))
117
+
118
+ "invoke-provider"
119
+ (invoke-provider! (:request step))
120
+
121
+ "cancel-provider"
122
+ (when-let [request-id (:requestId step)]
123
+ ((:cancel provider-effector) request-id))
124
+
125
+ "record-agent-utterance"
126
+ (do
127
+ (swap! state-atom state/record-agent-utterance (:text step) now (:source step))
128
+ (emit-event {:type "conversation.agentUtterance"
129
+ :agency "conversation"
130
+ :text (:text step)
131
+ :source (:source step)
132
+ :turnId (:turnId @state-atom)
133
+ :at now}))
134
+
135
+ "request-tts"
136
+ (request-tts! step now)
137
+
138
+ "record-provider-error"
139
+ (swap! state-atom state/record-provider-error
140
+ (:requestId step)
141
+ (:message step)
142
+ now)
143
+
144
+ "publish-provider-error"
145
+ (emit-event {:type "conversation.providerError"
146
+ :agency "conversation"
147
+ :requestId (:requestId step)
148
+ :turnId (:turnId step)
149
+ :message (:message step)
150
+ :at now})
151
+
152
+ "cancel-turn"
153
+ (swap! state-atom state/record-cancel now (:reason step))
154
+
155
+ "publish-cancel"
156
+ (emit-event {:type "conversation.cancelRequested"
157
+ :agency "conversation"
158
+ :targetAgency (get-in @state-atom [:config :ttsAgency])
159
+ :reason (:reason step)
160
+ :turnId (:turnId @state-atom)
161
+ :at now})
162
+
163
+ "ignore-stale-response"
164
+ (emit-event {:type "conversation.ignored"
165
+ :agency "conversation"
166
+ :reason (:reason step)
167
+ :requestId (:requestId step)
168
+ :turnId (:turnId step)
169
+ :at now})
170
+
171
+ "record-tts-status"
172
+ (swap! state-atom assoc
173
+ :status (or (:status step) (:status @state-atom))
174
+ :lastEvent {:type "conversation.ttsStatus"
175
+ :status (:status step)
176
+ :at now})
177
+
178
+ "publish-status"
179
+ (emit-status! emit-event state-atom (:status step) (:reason step))
180
+
181
+ "fail"
182
+ (emit-event {:type "error"
183
+ :agency "conversation"
184
+ :message (:reason step)
185
+ :commandType (:commandType step)})
186
+
187
+ nil)))]
188
+ {:schedule
189
+ (fn [command plan]
190
+ (when-not @disposed?
191
+ (doseq [step (:steps plan)]
192
+ (execute-step! step command plan))))
193
+
194
+ :queue
195
+ (fn []
196
+ @queue)
197
+
198
+ :dispose
199
+ (fn []
200
+ (reset! disposed? true)
201
+ ((:dispose provider-effector))
202
+ (reset! queue []))})))