prompt_objects 0.6.0 → 0.7.0

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 (291) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +126 -0
  3. data/README.md +93 -22
  4. data/exe/poop +5 -0
  5. data/exe/prompt_objects +1 -1108
  6. data/exe/prompt_objects_mcp +5 -3
  7. data/lib/prompt_objects/capability.rb +33 -0
  8. data/lib/prompt_objects/cli/diagnostics_command.rb +69 -0
  9. data/lib/prompt_objects/cli/env_command.rb +435 -0
  10. data/lib/prompt_objects/cli/events_command.rb +145 -0
  11. data/lib/prompt_objects/cli/explore_command.rb +155 -0
  12. data/lib/prompt_objects/cli/helpers.rb +91 -0
  13. data/lib/prompt_objects/cli/message_command.rb +216 -0
  14. data/lib/prompt_objects/cli/repl_command.rb +366 -0
  15. data/lib/prompt_objects/cli/serve_command.rb +162 -0
  16. data/lib/prompt_objects/cli.rb +64 -422
  17. data/lib/prompt_objects/connectors/base.rb +16 -29
  18. data/lib/prompt_objects/connectors/mcp.rb +82 -98
  19. data/lib/prompt_objects/domain/records.rb +45 -0
  20. data/lib/prompt_objects/environment/exporter.rb +5 -4
  21. data/lib/prompt_objects/environment/git.rb +21 -1
  22. data/lib/prompt_objects/environment/importer.rb +5 -4
  23. data/lib/prompt_objects/environment/manager.rb +44 -6
  24. data/lib/prompt_objects/environment/manifest.rb +26 -4
  25. data/lib/prompt_objects/environment.rb +1337 -20
  26. data/lib/prompt_objects/execution/blocking_executor.rb +88 -0
  27. data/lib/prompt_objects/execution/context.rb +137 -0
  28. data/lib/prompt_objects/execution/contracts.rb +59 -0
  29. data/lib/prompt_objects/execution/permit_pool.rb +49 -0
  30. data/lib/prompt_objects/execution/policy.rb +47 -0
  31. data/lib/prompt_objects/execution/resource_lock_manager.rb +63 -0
  32. data/lib/prompt_objects/execution/runner.rb +498 -0
  33. data/lib/prompt_objects/execution/scheduler.rb +325 -0
  34. data/lib/prompt_objects/llm/factory.rb +4 -4
  35. data/lib/prompt_objects/llm/gemini_adapter.rb +25 -8
  36. data/lib/prompt_objects/llm/openai_adapter.rb +9 -1
  37. data/lib/prompt_objects/llm/pricing.rb +9 -2
  38. data/lib/prompt_objects/llm/response.rb +9 -4
  39. data/lib/prompt_objects/loader.rb +28 -1
  40. data/lib/prompt_objects/mcp/server.rb +6 -3
  41. data/lib/prompt_objects/mcp/tools/get_conversation.rb +15 -11
  42. data/lib/prompt_objects/mcp/tools/get_pending_requests.rb +2 -2
  43. data/lib/prompt_objects/mcp/tools/respond_to_request.rb +3 -3
  44. data/lib/prompt_objects/mcp/tools/send_message.rb +42 -32
  45. data/lib/prompt_objects/operations/diagnostics.rb +115 -0
  46. data/lib/prompt_objects/operations/retention.rb +75 -0
  47. data/lib/prompt_objects/operations/run_trace_builder.rb +152 -0
  48. data/lib/prompt_objects/primitives/http_get.rb +2 -0
  49. data/lib/prompt_objects/primitives/list_files.rb +2 -0
  50. data/lib/prompt_objects/primitives/read_file.rb +2 -0
  51. data/lib/prompt_objects/primitives/think.rb +36 -0
  52. data/lib/prompt_objects/primitives/write_file.rb +9 -0
  53. data/lib/prompt_objects/prompt_object.rb +171 -519
  54. data/lib/prompt_objects/repositories/artifact_repository.rb +109 -0
  55. data/lib/prompt_objects/repositories/base_repository.rb +37 -0
  56. data/lib/prompt_objects/repositories/definition_repository.rb +36 -0
  57. data/lib/prompt_objects/repositories/env_data_repository.rb +103 -0
  58. data/lib/prompt_objects/repositories/event_repository.rb +105 -0
  59. data/lib/prompt_objects/repositories/message_repository.rb +73 -0
  60. data/lib/prompt_objects/repositories/run_repository.rb +254 -0
  61. data/lib/prompt_objects/repositories/thread_repository.rb +87 -0
  62. data/lib/prompt_objects/repositories/tool_execution_repository.rb +88 -0
  63. data/lib/prompt_objects/repositories/workspace_session_repository.rb +61 -0
  64. data/lib/prompt_objects/server/api/routes.rb +549 -53
  65. data/lib/prompt_objects/server/app.rb +133 -14
  66. data/lib/prompt_objects/server/file_watcher.rb +9 -0
  67. data/lib/prompt_objects/server/public/assets/index-BjKlODDD.js +90 -0
  68. data/lib/prompt_objects/server/public/assets/index-w3fpIb5c.css +1 -0
  69. data/lib/prompt_objects/server/public/index.html +2 -2
  70. data/lib/prompt_objects/server/websocket_handler.rb +202 -227
  71. data/lib/prompt_objects/server.rb +170 -1
  72. data/lib/prompt_objects/service.rb +129 -0
  73. data/lib/prompt_objects/session/store.rb +600 -13
  74. data/lib/prompt_objects/universal/add_capability.rb +1 -1
  75. data/lib/prompt_objects/universal/create_capability.rb +4 -2
  76. data/lib/prompt_objects/universal/delete_env_data.rb +23 -15
  77. data/lib/prompt_objects/universal/delete_primitive.rb +1 -1
  78. data/lib/prompt_objects/universal/dispatch_po.rb +54 -0
  79. data/lib/prompt_objects/universal/get_env_data.rb +8 -14
  80. data/lib/prompt_objects/universal/get_run_status.rb +30 -0
  81. data/lib/prompt_objects/universal/join_runs.rb +35 -0
  82. data/lib/prompt_objects/universal/list_env_data.rb +10 -14
  83. data/lib/prompt_objects/universal/modify_primitive.rb +1 -1
  84. data/lib/prompt_objects/universal/render_artifact.rb +91 -0
  85. data/lib/prompt_objects/universal/request_primitive.rb +1 -1
  86. data/lib/prompt_objects/universal/{store_env_data.rb → set_env_data.rb} +34 -20
  87. data/lib/prompt_objects/version.rb +5 -0
  88. data/lib/prompt_objects.rb +33 -8
  89. data/objects/coordinator.md +8 -4
  90. data/templates/arc-agi-1/objects/data_manager.md +2 -2
  91. data/templates/arc-agi-1/objects/observer.md +2 -2
  92. data/templates/arc-agi-1/objects/solver.md +6 -5
  93. data/templates/arc-agi-1/objects/verifier.md +2 -2
  94. data/templates/arc-agi-3/manifest.yml +19 -0
  95. data/templates/arc-agi-3/objects/analyst.md +79 -0
  96. data/templates/arc-agi-3/objects/player.md +76 -0
  97. data/templates/arc-agi-3/objects/strategist.md +97 -0
  98. data/templates/arc-agi-3/primitives/action_log.rb +133 -0
  99. data/templates/arc-agi-3/primitives/arc3_api.rb +223 -0
  100. data/templates/arc-agi-3/primitives/arc3_scorecard.rb +131 -0
  101. data/templates/arc-agi-3/primitives/frame_diff.rb +143 -0
  102. data/templates/arc-agi-3/primitives/frame_info.rb +96 -0
  103. data/templates/arc-agi-3/primitives/render_frame.rb +140 -0
  104. data/templates/basic/objects/basic.md +11 -3
  105. data/templates/chiptune/extras/sonic_pi_boot.rb +220 -0
  106. data/templates/chiptune/manifest.yml +20 -0
  107. data/templates/chiptune/objects/conductor.md +184 -0
  108. data/templates/chiptune/objects/sonic_pi.md +65 -0
  109. data/templates/chiptune/objects/voice_bass.md +44 -0
  110. data/templates/chiptune/objects/voice_lead.md +44 -0
  111. data/templates/chiptune/objects/voice_pad.md +43 -0
  112. data/templates/chiptune/objects/voice_perc.md +45 -0
  113. data/templates/chiptune/primitives/play_note.rb +59 -0
  114. data/templates/chiptune/primitives/play_sequence.rb +55 -0
  115. data/templates/chiptune/primitives/query_sonic_pi.rb +141 -0
  116. data/templates/chiptune/primitives/set_synth.rb +57 -0
  117. data/templates/chiptune/primitives/set_tempo.rb +45 -0
  118. data/templates/chiptune/primitives/stop_voice.rb +46 -0
  119. data/templates/chiptune/primitives/support/osc_bridge.rb +33 -0
  120. data/templates/chiptune/vendor/osc-ruby-1.1.5/LICENSE +19 -0
  121. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
  122. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
  123. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
  124. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
  125. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
  126. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
  127. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
  128. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
  129. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
  130. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
  131. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
  132. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
  133. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
  134. data/templates/developer/objects/code_reviewer.md +1 -1
  135. data/templates/developer/objects/coordinator.md +16 -3
  136. data/templates/developer/objects/debugger.md +3 -3
  137. data/templates/empty/objects/assistant.md +10 -5
  138. data/templates/minimal/objects/assistant.md +10 -5
  139. data/templates/music/extras/sonic_pi_boot.rb +220 -0
  140. data/templates/music/manifest.yml +16 -0
  141. data/templates/music/objects/conductor.md +154 -0
  142. data/templates/music/objects/sonic_pi.md +65 -0
  143. data/templates/music/primitives/play_note.rb +55 -0
  144. data/templates/music/primitives/play_sequence.rb +51 -0
  145. data/templates/music/primitives/query_sonic_pi.rb +139 -0
  146. data/templates/music/primitives/set_synth.rb +53 -0
  147. data/templates/music/primitives/set_tempo.rb +43 -0
  148. data/templates/music/primitives/stop_voice.rb +44 -0
  149. data/templates/music/primitives/support/osc_bridge.rb +33 -0
  150. data/templates/music/vendor/osc-ruby-1.1.5/LICENSE +19 -0
  151. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
  152. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
  153. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
  154. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
  155. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
  156. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
  157. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
  158. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
  159. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
  160. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
  161. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
  162. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
  163. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
  164. data/templates/music-beginner/README.md +100 -0
  165. data/templates/music-beginner/extras/README.md +27 -0
  166. data/templates/music-beginner/extras/sonic_pi_boot.rb +297 -0
  167. data/templates/music-beginner/manifest.yml +25 -0
  168. data/templates/music-beginner/objects/conductor.md +222 -0
  169. data/templates/music-beginner/objects/engine_setup.md +54 -0
  170. data/templates/music-beginner/objects/voice_bass.md +43 -0
  171. data/templates/music-beginner/objects/voice_keys.md +48 -0
  172. data/templates/music-beginner/objects/voice_pad.md +46 -0
  173. data/templates/music-beginner/objects/voice_percussion.md +45 -0
  174. data/templates/music-beginner/objects/voice_texture.md +37 -0
  175. data/templates/music-beginner/primitives/play_pattern.rb +118 -0
  176. data/templates/music-beginner/primitives/query_music_engine.rb +94 -0
  177. data/templates/music-beginner/primitives/set_instrument.rb +47 -0
  178. data/templates/music-beginner/primitives/set_tempo.rb +43 -0
  179. data/templates/music-beginner/primitives/set_voice_level.rb +46 -0
  180. data/templates/music-beginner/primitives/stop_voice.rb +37 -0
  181. data/templates/music-beginner/primitives/support/osc_bridge.rb +25 -0
  182. data/templates/music-beginner/vendor/osc-ruby-1.1.5/LICENSE +19 -0
  183. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
  184. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
  185. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
  186. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
  187. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
  188. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
  189. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
  190. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
  191. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
  192. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
  193. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
  194. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
  195. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
  196. data/templates/music-pro/extras/AUDITION.md +100 -0
  197. data/templates/music-pro/extras/sonic_pi_boot.rb +546 -0
  198. data/templates/music-pro/manifest.yml +19 -0
  199. data/templates/music-pro/objects/conductor.md +126 -0
  200. data/templates/music-pro/objects/sonic_pi.md +35 -0
  201. data/templates/music-pro/objects/voice_harmony.md +48 -0
  202. data/templates/music-pro/objects/voice_rhythm.md +43 -0
  203. data/templates/music-pro/objects/voice_texture.md +42 -0
  204. data/templates/music-pro/primitives/define_patch.rb +46 -0
  205. data/templates/music-pro/primitives/query_music_engine.rb +69 -0
  206. data/templates/music-pro/primitives/set_live_pattern.rb +70 -0
  207. data/templates/music-pro/primitives/set_tempo.rb +31 -0
  208. data/templates/music-pro/primitives/stop_voice.rb +31 -0
  209. data/templates/music-pro/primitives/support/music_protocol.rb +136 -0
  210. data/templates/music-pro/primitives/support/osc_bridge.rb +33 -0
  211. data/templates/music-pro/primitives/trigger_event.rb +44 -0
  212. data/templates/music-pro/vendor/osc-ruby-1.1.5/LICENSE +19 -0
  213. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
  214. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
  215. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
  216. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
  217. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
  218. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
  219. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
  220. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
  221. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
  222. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
  223. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
  224. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
  225. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
  226. data/templates/writer/objects/coordinator.md +14 -3
  227. data/templates/writer/objects/editor.md +1 -1
  228. data/templates/writer/objects/researcher.md +2 -2
  229. data/tools/thread-explorer.html +1 -1
  230. metadata +172 -65
  231. data/CLAUDE.md +0 -177
  232. data/Gemfile +0 -10
  233. data/Rakefile +0 -27
  234. data/frontend/.gitignore +0 -3
  235. data/frontend/index.html +0 -17
  236. data/frontend/package-lock.json +0 -4540
  237. data/frontend/package.json +0 -36
  238. data/frontend/postcss.config.js +0 -6
  239. data/frontend/src/App.tsx +0 -104
  240. data/frontend/src/canvas/CanvasView.tsx +0 -113
  241. data/frontend/src/canvas/ForceLayout.ts +0 -115
  242. data/frontend/src/canvas/SceneManager.ts +0 -587
  243. data/frontend/src/canvas/canvasStore.ts +0 -47
  244. data/frontend/src/canvas/constants.ts +0 -95
  245. data/frontend/src/canvas/controls/CameraControls.ts +0 -98
  246. data/frontend/src/canvas/edges/MessageArc.ts +0 -149
  247. data/frontend/src/canvas/inspector/InspectorPanel.tsx +0 -31
  248. data/frontend/src/canvas/inspector/POInspector.tsx +0 -262
  249. data/frontend/src/canvas/inspector/ToolCallInspector.tsx +0 -67
  250. data/frontend/src/canvas/nodes/PONode.ts +0 -249
  251. data/frontend/src/canvas/nodes/ToolCallNode.ts +0 -116
  252. data/frontend/src/canvas/types.ts +0 -24
  253. data/frontend/src/components/ContextMenu.tsx +0 -68
  254. data/frontend/src/components/EnvDataPane.tsx +0 -69
  255. data/frontend/src/components/Inspector.tsx +0 -263
  256. data/frontend/src/components/MarkdownMessage.tsx +0 -155
  257. data/frontend/src/components/MethodList.tsx +0 -90
  258. data/frontend/src/components/ModelSelector.tsx +0 -115
  259. data/frontend/src/components/NotificationPanel.tsx +0 -130
  260. data/frontend/src/components/ObjectList.tsx +0 -78
  261. data/frontend/src/components/PaneSlot.tsx +0 -30
  262. data/frontend/src/components/SourcePane.tsx +0 -202
  263. data/frontend/src/components/SystemBar.tsx +0 -74
  264. data/frontend/src/components/Transcript.tsx +0 -76
  265. data/frontend/src/components/UsagePanel.tsx +0 -105
  266. data/frontend/src/components/Workspace.tsx +0 -260
  267. data/frontend/src/components/index.ts +0 -12
  268. data/frontend/src/hooks/useResize.ts +0 -55
  269. data/frontend/src/hooks/useWebSocket.ts +0 -559
  270. data/frontend/src/index.css +0 -102
  271. data/frontend/src/main.tsx +0 -10
  272. data/frontend/src/store/index.ts +0 -311
  273. data/frontend/src/types/index.ts +0 -176
  274. data/frontend/tailwind.config.js +0 -44
  275. data/frontend/tsconfig.json +0 -30
  276. data/frontend/vite.config.ts +0 -29
  277. data/lib/prompt_objects/server/public/assets/index-DEPawnfZ.js +0 -4345
  278. data/lib/prompt_objects/server/public/assets/index-oMrRce1m.css +0 -1
  279. data/lib/prompt_objects/universal/add_primitive.rb +0 -118
  280. data/lib/prompt_objects/universal/ask_human.rb +0 -109
  281. data/lib/prompt_objects/universal/create_primitive.rb +0 -174
  282. data/lib/prompt_objects/universal/list_primitives.rb +0 -145
  283. data/lib/prompt_objects/universal/think.rb +0 -41
  284. data/lib/prompt_objects/universal/update_env_data.rb +0 -88
  285. data/prompt_objects.gemspec +0 -50
  286. data/templates/basic/.gitignore +0 -2
  287. data/templates/developer/.gitignore +0 -5
  288. data/templates/empty/.gitignore +0 -5
  289. data/templates/empty/objects/.gitkeep +0 -0
  290. data/templates/minimal/.gitignore +0 -5
  291. data/templates/writer/.gitignore +0 -5
@@ -0,0 +1,46 @@
1
+ module OSC
2
+ class Bundle
3
+ attr_accessor :timetag
4
+
5
+ def initialize(timetag=nil, *args)
6
+ @timetag = timetag
7
+ @args = args
8
+ end
9
+
10
+ def encode()
11
+ s = OSCString.new('#bundle').encode
12
+ s << encode_timetag(@timetag)
13
+ s << @args.collect do |x|
14
+ x2 = x.encode; [x2.size].pack('N') + x2
15
+ end.join
16
+ end
17
+
18
+ def to_a
19
+ @args.collect{|x| x.to_a}
20
+ end
21
+
22
+ private
23
+
24
+ def encode_timetag(t)
25
+ case t
26
+ when nil # immediately
27
+ t1 = 0
28
+ t2 = 1
29
+ when Numeric
30
+ t1, t2 = construct_timetag(t)
31
+ when Time
32
+ t1, t2 = construct_timetag(t.to_ntp)
33
+ else
34
+ raise(ArgumentError, 'invalid time')
35
+ end
36
+ [t1, t2].pack('N2')
37
+ end
38
+
39
+ def construct_timetag(time)
40
+ t1, fr = time.divmod(1)
41
+ t2 = (fr * (2**32)).to_i
42
+
43
+ [t1, t2]
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ module OSC
2
+ class Client
3
+
4
+ def initialize(host, port)
5
+ @so = UDPSocket.new
6
+ @so.connect(host, port)
7
+ end
8
+
9
+ def send(mesg)
10
+ @so.send(mesg.encode, 0)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ class Time
2
+
3
+ def to_ntp
4
+ self.to_f + 2208988800
5
+ end
6
+ end
@@ -0,0 +1,63 @@
1
+ require 'eventmachine'
2
+
3
+ module OSC
4
+ Channel = EM::Channel.new
5
+
6
+ class Connection < EventMachine::Connection
7
+ def receive_data(data)
8
+ ip_info = get_peername[2,6].unpack("nC4")
9
+ Channel << OSC::OSCPacket.messages_from_network(data, ip_info)
10
+ end
11
+ end
12
+
13
+ class EMServer
14
+
15
+ def initialize(port = 3333)
16
+ @port = port
17
+ setup_dispatcher
18
+ @tuples = []
19
+ end
20
+
21
+ def run
22
+ EM.error_handler{ |e|
23
+ Thread.main.raise e
24
+ }
25
+
26
+ EM.run do
27
+ EM::open_datagram_socket "0.0.0.0", @port, Connection
28
+ end
29
+ end
30
+
31
+ def add_method(address_pattern, &proc)
32
+ matcher = AddressPattern.new(address_pattern)
33
+
34
+ @tuples << [matcher, proc]
35
+ end
36
+
37
+ private
38
+ def setup_dispatcher
39
+ Channel.subscribe do |messages|
40
+ messages.each do |message|
41
+ diff = (message.time || 0) - Time.now.to_ntp
42
+
43
+ if diff <= 0
44
+ sendmesg(message)
45
+ else
46
+ EM.defer do
47
+ sleep(diff)
48
+ sendmesg(message)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def sendmesg(mesg)
56
+ @tuples.each do |matcher, obj|
57
+ if matcher.match?(mesg.address)
58
+ obj.call(mesg)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,46 @@
1
+ module OSC
2
+ class Message
3
+ attr_accessor :address
4
+ attr_accessor :time
5
+ attr_accessor :ip_address
6
+ attr_accessor :ip_port
7
+
8
+ def self.new_with_time(address, time, tags=nil, *args)
9
+ message = new(address, tags, *args)
10
+ message.time = time
11
+ message
12
+ end
13
+
14
+ def initialize(address, *args)
15
+ @address = address
16
+ @args = []
17
+
18
+ args.each do |arg|
19
+ case arg
20
+ when Integer; @args << OSCInt32.new(arg)
21
+ when Float; @args << OSCFloat32.new(arg)
22
+ when String; @args << OSCString.new(arg)
23
+ when OSCArgument; @args << arg
24
+ end
25
+ end
26
+ end
27
+
28
+ def tags
29
+ @args.collect{|x| x.tag}.join
30
+ end
31
+
32
+ def encode
33
+ s = OSCString.new(@address).encode
34
+ s << OSCString.new(',' + tags).encode
35
+ s << @args.collect{|x| x.encode}.join
36
+ end
37
+
38
+ def to_a
39
+ @args.collect{|x| x.val}
40
+ end
41
+
42
+ def ==(other)
43
+ @address == other.address && to_a == other.to_a
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,42 @@
1
+ module OSC
2
+ class NetworkPacket
3
+ def initialize(str)
4
+ @str = str.force_encoding("BINARY")
5
+ @index = 0
6
+ end
7
+
8
+ def to_s
9
+ @str
10
+ end
11
+
12
+ def rem
13
+ @str.length - @index
14
+ end
15
+
16
+ def eof?
17
+ rem <= 0
18
+ end
19
+
20
+ def skip(n)
21
+ @index += n
22
+ end
23
+
24
+ def skip_padding
25
+ skip((4 - (@index % 4)) % 4)
26
+ end
27
+
28
+ def getn(n)
29
+ raise(EOFError) if rem < n
30
+ s = @str[@index, n]
31
+ skip(n)
32
+ s
33
+ end
34
+
35
+ def getc
36
+ raise(EOFError) if rem < 1
37
+ c = @str[@index]
38
+ skip(1)
39
+ c
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ module OSC
2
+ class OSCArgument
3
+ def initialize(val)
4
+ @val = val
5
+ end
6
+
7
+ attr_accessor :val
8
+
9
+ def to_i()
10
+ @val.to_i
11
+ end
12
+
13
+ def to_f()
14
+ @val.to_f
15
+ end
16
+
17
+ def to_s()
18
+ @val.to_s
19
+ end
20
+
21
+ private
22
+ def padding(s)
23
+ s + ("\000" * ((4 - (s.size % 4)) % 4))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,140 @@
1
+ require File.join(File.dirname( __FILE__ ), 'network_packet')
2
+ require 'ostruct'
3
+
4
+ module OSC
5
+ class UnknownType < StandardError; end
6
+
7
+ class OSCPacket
8
+ def self.messages_from_network(string, ip_info=nil)
9
+ messages = []
10
+ osc = new(string)
11
+
12
+ if osc.bundle?
13
+ osc.get_string
14
+ time = osc.get_timestamp
15
+
16
+ osc.get_bundle_messages.each do |message|
17
+ msg = decode_simple_message(time, OSCPacket.new(message))
18
+ if ip_info
19
+ # Append info for the ip address
20
+ msg.ip_port = ip_info.shift
21
+ msg.ip_address = ip_info.join(".")
22
+ end
23
+ messages << msg
24
+ end
25
+
26
+ else
27
+ msg = decode_simple_message(time, osc)
28
+ if ip_info
29
+ # Append info for the ip address
30
+ msg.ip_port = ip_info.shift
31
+ msg.ip_address = ip_info.join(".")
32
+ end
33
+ messages << msg
34
+ end
35
+
36
+ return messages
37
+ end
38
+
39
+ def self.decode_simple_message(time, osc_packet)
40
+ address = osc_packet.get_string
41
+ args = osc_packet.get_arguments
42
+
43
+ Message.new_with_time(address, time, nil, *args)
44
+ end
45
+
46
+ def initialize(string)
47
+ @packet = NetworkPacket.new(string)
48
+
49
+ @types = {
50
+ "i" => lambda{OSCInt32.new(get_int32)},
51
+ "f" => lambda{ OSCFloat32.new(get_float32)},
52
+ "d" => lambda{ OSCDouble64.new(get_double64)},
53
+ "s" => lambda{ OSCString.new(get_string)},
54
+ "b" => lambda{ OSCBlob.new(get_blob)}
55
+ }
56
+ end
57
+
58
+ def get_bundle_messages
59
+ bundle_messages = []
60
+
61
+ until @packet.eof?
62
+ l = @packet.getn(4).unpack('N')[0]
63
+ bundle_messages << @packet.getn(l)
64
+ end
65
+ bundle_messages
66
+ end
67
+
68
+ def get_string
69
+ result = ''
70
+ until ((c = @packet.getc) == string_delemeter)
71
+ result << c
72
+ end
73
+ @packet.skip_padding
74
+ result
75
+ end
76
+
77
+ def get_timestamp
78
+ #TODO: refactor this so a mortal can figure it out
79
+ t1 = @packet.getn(4).unpack('N')[0]
80
+ t2 = @packet.getn(4).unpack('N')[0]
81
+ @packet.skip_padding
82
+
83
+ if t1 == 0 && t2 == 1
84
+ time = nil
85
+ else
86
+ time = t1 + t2.to_f / (2**32)
87
+ end
88
+
89
+ time
90
+ end
91
+
92
+ def get_arguments
93
+ if (@packet.getc == ?,)
94
+ tags = get_string
95
+ args = []
96
+
97
+ tags.scan(/./) do |tag|
98
+ type_handler = @types[tag]
99
+ raise(UnknownType, "Unknown OSC type: #{tag}") unless type_handler
100
+ args << type_handler.call
101
+ end
102
+ args
103
+ end
104
+ end
105
+
106
+ def get_int32
107
+ i = @packet.getn(4).unpack('N')[0]
108
+ i -= 2**32 if i > (2**31-1)
109
+ @packet.skip_padding
110
+ i
111
+ end
112
+
113
+ def get_float32
114
+ f = @packet.getn(4).unpack('g')[0]
115
+ @packet.skip_padding
116
+ f
117
+ end
118
+
119
+ def get_double64
120
+ f = @packet.getn(8).unpack('G')[0]
121
+ @packet.skip_padding
122
+ f
123
+ end
124
+
125
+ def get_blob
126
+ l = @packet.getn(4).unpack('N')[0]
127
+ b = @packet.getn(l)
128
+ @packet.skip_padding
129
+ b
130
+ end
131
+
132
+ def bundle?
133
+ !(@packet.to_s =~ /\A\#bundle/).nil?
134
+ end
135
+
136
+ def string_delemeter
137
+ "\x00"
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,53 @@
1
+ require File.join(File.dirname(__FILE__), "osc_argument")
2
+
3
+ module OSC
4
+ class OSCInt32 < OSCArgument
5
+ def tag
6
+ 'i'
7
+ end
8
+
9
+ def encode
10
+ [@val].pack('N').force_encoding("BINARY")
11
+ end
12
+ end
13
+
14
+ class OSCFloat32 < OSCArgument
15
+ def tag
16
+ 'f'
17
+ end
18
+
19
+ def encode
20
+ [@val].pack('g').force_encoding("BINARY")
21
+ end
22
+ end
23
+
24
+ class OSCDouble64 < OSCArgument
25
+ def tag
26
+ 'd'
27
+ end
28
+
29
+ def encode
30
+ [@val].pack('G').force_encoding("BINARY")
31
+ end
32
+ end
33
+
34
+ class OSCString < OSCArgument
35
+ def tag
36
+ 's'
37
+ end
38
+
39
+ def encode
40
+ padding(@val.sub(/\000.*\z/, '') + "\000").force_encoding("BINARY")
41
+ end
42
+ end
43
+
44
+ class OSCBlob < OSCArgument
45
+ def tag
46
+ 'b'
47
+ end
48
+
49
+ def encode
50
+ padding([@val.size].pack('N') + @val).force_encoding("BINARY")
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,91 @@
1
+ module OSC
2
+ class Server
3
+ def initialize(port)
4
+ @socket = UDPSocket.new
5
+ @socket.bind('', port)
6
+ @matchers = []
7
+ @queue = Queue.new
8
+ end
9
+
10
+ def run
11
+ start_dispatcher
12
+
13
+ start_detector
14
+ end
15
+
16
+ def stop
17
+ @socket.close
18
+ end
19
+
20
+ def add_method(address_pattern, &proc)
21
+ matcher = AddressPattern.new(address_pattern)
22
+
23
+ @matchers << [matcher, proc]
24
+ end
25
+
26
+ private
27
+
28
+ def start_detector
29
+ begin
30
+ detector
31
+ rescue
32
+ Thread.main.raise($!)
33
+ end
34
+ end
35
+
36
+ def start_dispatcher
37
+ Thread.fork do
38
+ begin
39
+ dispatcher
40
+ rescue
41
+ Thread.main.raise($!)
42
+ end
43
+ end
44
+ end
45
+
46
+ def dispatcher
47
+ loop do
48
+ mesg = @queue.pop
49
+ dispatch_message(mesg)
50
+ end
51
+ end
52
+
53
+ def dispatch_message(message)
54
+ diff = (message.time || 0) - Time.now.to_ntp
55
+
56
+ if diff <= 0
57
+ sendmesg(message)
58
+ else # spawn a thread to wait until it's time
59
+ Thread.fork do
60
+ sleep(diff)
61
+ sendmesg(message)
62
+ Thread.exit
63
+ end
64
+ end
65
+ end
66
+
67
+ def sendmesg(mesg)
68
+ @matchers.each do |matcher, proc|
69
+ if matcher.match?(mesg.address)
70
+ proc.call(mesg)
71
+ end
72
+ end
73
+ end
74
+
75
+ def detector
76
+ loop do
77
+ osc_data, network = @socket.recvfrom(16384)
78
+ begin
79
+ ip_info = Array.new
80
+ ip_info << network[1]
81
+ ip_info.concat(network[2].split('.'))
82
+ OSCPacket.messages_from_network( osc_data, ip_info ).each do |message|
83
+ @queue.push(message)
84
+ end
85
+
86
+ rescue(EOFError)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,18 @@
1
+ require 'socket'
2
+ require 'thread'
3
+
4
+ # core extensions
5
+ require 'osc-ruby/core_ext/time'
6
+
7
+ # jus the basics
8
+ require 'osc-ruby/osc_types'
9
+ require 'osc-ruby/osc_packet'
10
+
11
+ require 'osc-ruby/message'
12
+ require 'osc-ruby/bundle'
13
+ require 'osc-ruby/address_pattern'
14
+
15
+ # now we gettin fancy
16
+ require 'osc-ruby/server'
17
+ require 'osc-ruby/client'
18
+ require 'osc-ruby/broadcast_client'
@@ -0,0 +1,100 @@
1
+ # Auditioning Music Pro
2
+
3
+ ## Start it
4
+
5
+ 1. Create a new environment from the `music-pro` template and open it.
6
+ 2. Open Sonic Pi. In Settings, allow incoming OSC if needed.
7
+ 3. In a Sonic Pi buffer, run one line with the environment's absolute path:
8
+
9
+ ```ruby
10
+ run_file "/Users/you/.prompt_objects/environments/my-music/extras/sonic_pi_boot.rb"
11
+ ```
12
+
13
+ 4. Ask the `conductor` to check Sonic Pi, then ask it to begin a flowing,
14
+ talk-safe composition. Add one musician at a time while listening, but keep
15
+ one sustained, phrase-based, or rhythmic layer connecting the ensemble.
16
+
17
+ The autonomous timer stays dormant until the conductor receives a new human
18
+ message after the server starts. Its first evolution turn happens 24 seconds
19
+ later and uses the short evolution instruction in the conductor's frontmatter,
20
+ not the human's initialization prompt.
21
+
22
+ The Log should say `Prompt Objects Music Pro loaded`. The connection query reports engine `music-pro/1`.
23
+
24
+ `connected: true` confirms only that the engine is reachable. The conductor
25
+ must require each musician to call `set_live_pattern` and then verify an active
26
+ voice in live engine state. A connected engine with an empty `voices` object is
27
+ silent; prose proposals and defined-but-unused patches do not produce sound.
28
+
29
+ ## Pattern notation
30
+
31
+ | Notation | Meaning |
32
+ | --- | --- |
33
+ | `C4/1` | C4 for one beat |
34
+ | `(C4,E4,G4)/2` | chord for two beats |
35
+ | `~/1` or `-/1` | one-beat rest |
36
+ | `@bd_haus/0.5` | built-in Sonic Pi sample |
37
+ | `[C4/1 E4/1 G4/1]/1` | subdivide/compress the sequence into one beat |
38
+ | `<C4 E4 G4>/1` | choose the next alternative on each cycle |
39
+ | `C4/0.5*4` | repeat an event four times |
40
+ | `C4/1{amp=0.4,pan=-0.2}` | per-event raw controls |
41
+ | `C4/1{gate=0.8}` | one-beat step with a shorter 0.8-beat synth envelope |
42
+
43
+ Patterns are whitespace-separated. Durations are Sonic Pi beats and determine
44
+ the distance to the next onset. Synth envelopes default to roughly 95% of that
45
+ duration so sustained parts connect; an explicit `gate` may shorten the sound or
46
+ overlap the next onset without changing the rhythm. Explicit patch `sustain`
47
+ still takes precedence. Updates take effect at the next bar. A pattern is padded
48
+ to the next bar boundary after completing, so every voice re-locks safely; this
49
+ prototype does not yet preserve free-running polymetric phase across rewrites.
50
+
51
+ Available cycle transforms are `transpose`, `stretch`, `rotate`, `reverse`, `probability`, deterministic `seed`, and `every`, for example:
52
+
53
+ ```json
54
+ {
55
+ "rotate": 1,
56
+ "seed": 42,
57
+ "every": { "cycles": 4, "transform": "reverse" }
58
+ }
59
+ ```
60
+
61
+ ## Raw patches
62
+
63
+ The bundled quiet patches are only starting points. A voice can define any installed Sonic Pi synth or built-in sample and up to three effects:
64
+
65
+ ```json
66
+ {
67
+ "name": "moving_blade",
68
+ "patch": {
69
+ "kind": "synth",
70
+ "synth": "blade",
71
+ "params": { "amp": 0.12, "attack": 0.4, "release": 2.5, "cutoff": 76 },
72
+ "effects": [
73
+ { "name": "reverb", "params": { "mix": 0.25, "room": 0.8 } },
74
+ { "name": "lpf", "params": { "cutoff": 90 } }
75
+ ]
76
+ }
77
+ }
78
+ ```
79
+
80
+ Unknown synth, sample, effect, or parameter names are reported in Sonic Pi's Log without taking down other voice loops.
81
+
82
+ ## Listening comparison
83
+
84
+ To judge the system rather than one lucky pattern, try three five-minute runs from fresh environments. Give each the same high-level request and note:
85
+
86
+ - whether a recognizable idea survives multiple autonomous changes;
87
+ - whether musicians leave room and respond to one another;
88
+ - harshness, muddiness, clipping, and distracting transients;
89
+ - how often a change feels motivated rather than random;
90
+ - whether human feedback produces an audible correction within one rewrite.
91
+
92
+ Agents can query structure but cannot hear audio. Specific human feedback is part of the perception loop.
93
+
94
+ For a stage rehearsal, begin with the venue output muted, start one voice at a time, set the computer/PA gain conservatively, and keep `stop_voice(voice: "all")` ready. The engine clamps generated event gain but cannot control the operating-system or venue mixer.
95
+
96
+ ## Prototype compatibility and limits
97
+
98
+ This prototype targets Sonic Pi 4.6.0, the version used while checking the bundled synth/effect names and Ruby syntax. It uses Sonic Pi's Ruby `json` standard library and its `with_fx`/`play_chord` APIs. Verify it against the exact Sonic Pi build used for a performance.
99
+
100
+ The notation is inspired by live-pattern languages but is not Strudel syntax. It intentionally does not evaluate arbitrary Ruby. Runtime patches may select any installed synth, built-in sample, and up to three effects; arbitrary sample file paths are not accepted in this first protocol. Chords are simultaneous, while the events within one voice otherwise run sequentially. Free-running polymeter, hot control of already-ringing synth nodes, audio analysis, and agent listening are future work.