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
@@ -1,105 +0,0 @@
1
- interface UsageData {
2
- session_id: string
3
- include_tree: boolean
4
- input_tokens: number
5
- output_tokens: number
6
- total_tokens: number
7
- estimated_cost_usd: number
8
- calls: number
9
- by_model: Record<string, {
10
- input_tokens: number
11
- output_tokens: number
12
- estimated_cost_usd: number
13
- calls: number
14
- }>
15
- }
16
-
17
- interface UsagePanelProps {
18
- usage: UsageData
19
- onClose: () => void
20
- }
21
-
22
- function formatTokens(n: number): string {
23
- if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`
24
- if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`
25
- return n.toString()
26
- }
27
-
28
- function formatCost(usd: number): string {
29
- if (usd === 0) return '$0.00'
30
- if (usd < 0.01) return `$${usd.toFixed(4)}`
31
- return `$${usd.toFixed(2)}`
32
- }
33
-
34
- export function UsagePanel({ usage, onClose }: UsagePanelProps) {
35
- const models = Object.entries(usage.by_model)
36
-
37
- return (
38
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onClick={onClose}>
39
- <div
40
- className="bg-po-surface-2 border border-po-border rounded shadow-2xl w-[400px] max-h-[80vh] overflow-auto"
41
- onClick={(e) => e.stopPropagation()}
42
- >
43
- <div className="flex items-center justify-between px-4 py-2.5 border-b border-po-border">
44
- <h3 className="font-mono text-xs text-po-text-primary">
45
- Token Usage {usage.include_tree && <span className="text-po-text-ghost ml-1">(full tree)</span>}
46
- </h3>
47
- <button onClick={onClose} className="text-po-text-ghost hover:text-po-text-primary transition-colors duration-150">
48
- {'\u2715'}
49
- </button>
50
- </div>
51
-
52
- <div className="p-4 space-y-4">
53
- {/* Summary */}
54
- <div className="grid grid-cols-3 gap-2">
55
- <div className="bg-po-surface rounded p-2.5 text-center">
56
- <div className="text-sm font-mono text-po-accent">{formatTokens(usage.input_tokens)}</div>
57
- <div className="text-2xs text-po-text-ghost uppercase tracking-wider mt-0.5">Input</div>
58
- </div>
59
- <div className="bg-po-surface rounded p-2.5 text-center">
60
- <div className="text-sm font-mono text-po-warning">{formatTokens(usage.output_tokens)}</div>
61
- <div className="text-2xs text-po-text-ghost uppercase tracking-wider mt-0.5">Output</div>
62
- </div>
63
- <div className="bg-po-surface rounded p-2.5 text-center">
64
- <div className="text-sm font-mono text-po-text-primary">{formatCost(usage.estimated_cost_usd)}</div>
65
- <div className="text-2xs text-po-text-ghost uppercase tracking-wider mt-0.5">Est. Cost</div>
66
- </div>
67
- </div>
68
-
69
- <div className="flex justify-between text-2xs text-po-text-ghost px-1 font-mono">
70
- <span>{usage.calls} call{usage.calls !== 1 ? 's' : ''}</span>
71
- <span>{formatTokens(usage.total_tokens)} total</span>
72
- </div>
73
-
74
- {/* Per-model breakdown */}
75
- {models.length > 0 && (
76
- <div>
77
- <h4 className="text-2xs text-po-text-ghost uppercase tracking-wider mb-2">By Model</h4>
78
- <div className="space-y-1.5">
79
- {models.map(([model, data]) => (
80
- <div key={model} className="bg-po-surface rounded p-2.5">
81
- <div className="flex items-center justify-between mb-1">
82
- <span className="text-xs font-mono text-po-text-primary">{model}</span>
83
- <span className="text-2xs text-po-text-ghost">{data.calls} call{data.calls !== 1 ? 's' : ''}</span>
84
- </div>
85
- <div className="flex justify-between text-2xs text-po-text-ghost font-mono">
86
- <span>In: {formatTokens(data.input_tokens)}</span>
87
- <span>Out: {formatTokens(data.output_tokens)}</span>
88
- <span>{formatCost(data.estimated_cost_usd)}</span>
89
- </div>
90
- </div>
91
- ))}
92
- </div>
93
- </div>
94
- )}
95
-
96
- {usage.calls === 0 && (
97
- <div className="text-center text-po-text-ghost text-xs py-4 font-mono">
98
- No usage data recorded.
99
- </div>
100
- )}
101
- </div>
102
- </div>
103
- </div>
104
- )
105
- }
@@ -1,260 +0,0 @@
1
- import { useState, useRef, useEffect } from 'react'
2
- import { useStore } from '../store'
3
- import { MarkdownMessage } from './MarkdownMessage'
4
- import type { PromptObject, Message, ToolCall } from '../types'
5
-
6
- interface WorkspaceProps {
7
- po: PromptObject
8
- sendMessage: (target: string, content: string, newThread?: boolean) => void
9
- }
10
-
11
- export function Workspace({ po, sendMessage }: WorkspaceProps) {
12
- const [input, setInput] = useState('')
13
- const [continueThread, setContinueThread] = useState(false)
14
- const messagesEndRef = useRef<HTMLDivElement>(null)
15
- const { streamingContent, connected } = useStore()
16
-
17
- const messages = po.current_session?.messages || []
18
- const streaming = streamingContent[po.name]
19
- const hasMessages = messages.length > 0
20
- const isBusy = po.status !== 'idle' && connected
21
- const canSend = connected && !isBusy && !!input.trim()
22
-
23
- useEffect(() => {
24
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
25
- }, [messages, streaming])
26
-
27
- const handleSubmit = (e: React.FormEvent) => {
28
- e.preventDefault()
29
- if (!input.trim()) return
30
- const content = input.trim()
31
- const shouldCreateNewThread = !continueThread && hasMessages
32
- sendMessage(po.name, content, shouldCreateNewThread)
33
- setInput('')
34
- }
35
-
36
- const handleKeyDown = (e: React.KeyboardEvent) => {
37
- if (e.key === 'Enter' && !e.shiftKey) {
38
- e.preventDefault()
39
- if (canSend) {
40
- handleSubmit(e)
41
- }
42
- }
43
- }
44
-
45
- return (
46
- <div className="h-full flex flex-col">
47
- {/* Messages */}
48
- <div className="flex-1 overflow-auto px-4 py-2 space-y-1">
49
- {messages.length === 0 && !streaming && (
50
- <div className="h-full flex items-center justify-center">
51
- <span className="font-mono text-xs text-po-text-ghost">&gt; _</span>
52
- </div>
53
- )}
54
-
55
- {messages.map((message, index) => (
56
- <WorkspaceEntry key={index} message={message} />
57
- ))}
58
-
59
- {/* Streaming content */}
60
- {streaming && (
61
- <div className="py-1">
62
- <MarkdownMessage content={streaming} className="text-po-text-primary text-xs" />
63
- <span className="inline-block w-1.5 h-3.5 bg-po-accent animate-pulse ml-0.5 align-text-bottom" />
64
- </div>
65
- )}
66
-
67
- <div ref={messagesEndRef} />
68
- </div>
69
-
70
- {/* Input */}
71
- <div className="border-t border-po-border bg-po-surface-2 px-4 py-2">
72
- {!connected && (
73
- <div className="mb-1.5 text-2xs text-po-warning flex items-center gap-1.5 font-mono">
74
- <div className="w-1.5 h-1.5 rounded-full bg-po-warning animate-pulse" />
75
- reconnecting...
76
- </div>
77
- )}
78
-
79
- <form onSubmit={handleSubmit} className="flex items-center gap-2">
80
- <span className="text-po-text-ghost font-mono text-xs select-none">&gt;</span>
81
- <input
82
- type="text"
83
- value={input}
84
- onChange={(e) => setInput(e.target.value)}
85
- onKeyDown={handleKeyDown}
86
- placeholder={!connected ? 'disconnected' : isBusy ? `${po.status.replace('_', ' ')}...` : ''}
87
- className="flex-1 bg-transparent text-po-text-primary font-mono text-xs placeholder-po-text-ghost focus:outline-none disabled:opacity-50"
88
- disabled={isBusy}
89
- />
90
- </form>
91
-
92
- {/* Thread toggle */}
93
- {hasMessages && (
94
- <div className="flex items-center gap-2 mt-1.5 text-2xs font-mono">
95
- <button
96
- type="button"
97
- onClick={() => setContinueThread(false)}
98
- className={`px-1.5 py-0.5 rounded transition-colors duration-150 ${
99
- !continueThread
100
- ? 'bg-po-accent-wash text-po-accent'
101
- : 'text-po-text-ghost hover:text-po-text-secondary'
102
- }`}
103
- >
104
- new thread
105
- </button>
106
- <button
107
- type="button"
108
- onClick={() => setContinueThread(true)}
109
- className={`px-1.5 py-0.5 rounded transition-colors duration-150 ${
110
- continueThread
111
- ? 'bg-po-accent-wash text-po-accent'
112
- : 'text-po-text-ghost hover:text-po-text-secondary'
113
- }`}
114
- >
115
- continue
116
- </button>
117
- </div>
118
- )}
119
- </div>
120
- </div>
121
- )
122
- }
123
-
124
- function WorkspaceEntry({ message }: { message: Message }) {
125
- const isUser = message.role === 'user'
126
- const isAssistant = message.role === 'assistant'
127
- const isTool = message.role === 'tool'
128
-
129
- // Tool results
130
- if (isTool) {
131
- const results = message.results || []
132
- if (results.length === 0) return null
133
- return (
134
- <div className="space-y-1 pl-4">
135
- {results.map((result, idx) => (
136
- <ToolResultFrame key={result.tool_call_id || idx} result={result} />
137
- ))}
138
- </div>
139
- )
140
- }
141
-
142
- // User message: REPL-style "> message"
143
- if (isUser) {
144
- return (
145
- <div className="py-1">
146
- <span className="font-mono text-xs text-po-text-ghost select-none">&gt; </span>
147
- <span className="font-mono text-xs text-po-text-primary whitespace-pre-wrap">{message.content}</span>
148
- </div>
149
- )
150
- }
151
-
152
- // Assistant message: plain text with markdown
153
- if (isAssistant) {
154
- return (
155
- <div className="py-1">
156
- {message.content && (
157
- <MarkdownMessage content={message.content} className="text-po-text-primary text-xs" />
158
- )}
159
-
160
- {/* Tool calls as bordered frames */}
161
- {message.tool_calls && message.tool_calls.length > 0 && (
162
- <div className="mt-1 space-y-1">
163
- {message.tool_calls.map((tc) => (
164
- <ToolCallFrame key={tc.id} toolCall={tc} />
165
- ))}
166
- </div>
167
- )}
168
- </div>
169
- )
170
- }
171
-
172
- return null
173
- }
174
-
175
- function ToolCallFrame({ toolCall }: { toolCall: ToolCall }) {
176
- const [expanded, setExpanded] = useState(false)
177
- const { notifications } = useStore()
178
-
179
- // ask_human: amber-bordered frame
180
- if (toolCall.name === 'ask_human') {
181
- const question = toolCall.arguments.question as string
182
- const options = toolCall.arguments.options as string[] | undefined
183
- const isPending = notifications.some((n) => n.message === question)
184
-
185
- return (
186
- <div className="border-l-2 border-po-warning bg-po-accent-wash rounded-r px-3 py-2 my-1">
187
- <div className="flex items-center gap-2 mb-1">
188
- <span className="text-2xs font-mono text-po-warning">ask_human</span>
189
- {isPending ? (
190
- <span className="text-2xs bg-po-warning text-po-bg px-1.5 py-0.5 rounded font-bold animate-pulse">
191
- PENDING
192
- </span>
193
- ) : (
194
- <span className="text-2xs bg-po-success text-po-bg px-1.5 py-0.5 rounded font-bold">
195
- RESOLVED
196
- </span>
197
- )}
198
- </div>
199
- <p className="text-xs text-po-text-primary mb-1.5">{question}</p>
200
- {options && options.length > 0 && (
201
- <div className="flex flex-wrap gap-1.5">
202
- {options.map((opt, i) => (
203
- <span key={i} className="text-2xs font-mono bg-po-surface-2 px-1.5 py-0.5 rounded text-po-text-secondary">
204
- {opt}
205
- </span>
206
- ))}
207
- </div>
208
- )}
209
- </div>
210
- )
211
- }
212
-
213
- // Default tool call: bordered frame
214
- const argsStr = JSON.stringify(toolCall.arguments, null, 2)
215
-
216
- return (
217
- <div className="border-l-2 border-po-status-calling rounded-r overflow-hidden my-1">
218
- <button
219
- onClick={() => setExpanded(!expanded)}
220
- className="w-full text-left px-3 py-1 flex items-center gap-1.5 hover:bg-po-surface-2 transition-colors duration-150 bg-po-surface"
221
- >
222
- <span className="text-2xs text-po-text-ghost">{expanded ? '\u25BC' : '\u25B8'}</span>
223
- <span className="text-xs font-mono text-po-status-calling">{toolCall.name}</span>
224
- <span className="text-2xs text-po-text-ghost">
225
- ({Object.keys(toolCall.arguments).length} args)
226
- </span>
227
- </button>
228
- {expanded && (
229
- <pre className="px-3 py-1.5 bg-po-surface text-2xs text-po-text-tertiary font-mono whitespace-pre-wrap break-all">
230
- {argsStr}
231
- </pre>
232
- )}
233
- </div>
234
- )
235
- }
236
-
237
- function ToolResultFrame({ result }: { result: { tool_call_id: string; name?: string; content: string } }) {
238
- const [expanded, setExpanded] = useState(false)
239
- const content = result.content || ''
240
- const chars = content.length
241
-
242
- return (
243
- <div className="border-l-2 border-po-status-calling rounded-r overflow-hidden my-0.5">
244
- <button
245
- onClick={() => setExpanded(!expanded)}
246
- className="w-full text-left px-3 py-1 flex items-center gap-1.5 hover:bg-po-surface-2 transition-colors duration-150 bg-po-surface"
247
- >
248
- <span className="text-2xs text-po-text-ghost">{expanded ? '\u25BC' : '\u25B8'}</span>
249
- <span className="text-2xs text-po-text-tertiary">Result</span>
250
- {result.name && <span className="text-2xs text-po-status-calling font-mono">{result.name}</span>}
251
- <span className="text-2xs text-po-text-ghost">({chars} chars)</span>
252
- </button>
253
- {expanded && (
254
- <pre className="px-3 py-1.5 bg-po-surface text-2xs text-po-text-tertiary font-mono whitespace-pre-wrap break-all">
255
- {content}
256
- </pre>
257
- )}
258
- </div>
259
- )
260
- }
@@ -1,12 +0,0 @@
1
- export { SystemBar } from './SystemBar'
2
- export { ObjectList } from './ObjectList'
3
- export { Inspector } from './Inspector'
4
- export { MethodList } from './MethodList'
5
- export { SourcePane } from './SourcePane'
6
- export { Workspace } from './Workspace'
7
- export { Transcript } from './Transcript'
8
- export { NotificationPanel } from './NotificationPanel'
9
- export { MarkdownMessage } from './MarkdownMessage'
10
- export { ModelSelector } from './ModelSelector'
11
- export { ContextMenu } from './ContextMenu'
12
- export { UsagePanel } from './UsagePanel'
@@ -1,55 +0,0 @@
1
- import { useState, useCallback, useEffect, useRef } from 'react'
2
-
3
- interface UseResizeOptions {
4
- direction: 'horizontal' | 'vertical'
5
- initialSize: number
6
- minSize: number
7
- maxSize: number
8
- /** If true, dragging down/right increases size. If false (for bottom panels), dragging up increases. */
9
- inverted?: boolean
10
- }
11
-
12
- export function useResize({ direction, initialSize, minSize, maxSize, inverted = false }: UseResizeOptions) {
13
- const [size, setSize] = useState(initialSize)
14
- const dragging = useRef(false)
15
- const startPos = useRef(0)
16
- const startSize = useRef(0)
17
-
18
- const onMouseDown = useCallback((e: React.MouseEvent) => {
19
- e.preventDefault()
20
- dragging.current = true
21
- startPos.current = direction === 'horizontal' ? e.clientX : e.clientY
22
- startSize.current = size
23
- document.body.style.cursor = direction === 'horizontal' ? 'col-resize' : 'row-resize'
24
- document.body.style.userSelect = 'none'
25
- }, [direction, size])
26
-
27
- useEffect(() => {
28
- const onMouseMove = (e: MouseEvent) => {
29
- if (!dragging.current) return
30
- const currentPos = direction === 'horizontal' ? e.clientX : e.clientY
31
- const delta = currentPos - startPos.current
32
- const newSize = inverted
33
- ? startSize.current - delta
34
- : startSize.current + delta
35
- setSize(Math.min(maxSize, Math.max(minSize, newSize)))
36
- }
37
-
38
- const onMouseUp = () => {
39
- if (dragging.current) {
40
- dragging.current = false
41
- document.body.style.cursor = ''
42
- document.body.style.userSelect = ''
43
- }
44
- }
45
-
46
- document.addEventListener('mousemove', onMouseMove)
47
- document.addEventListener('mouseup', onMouseUp)
48
- return () => {
49
- document.removeEventListener('mousemove', onMouseMove)
50
- document.removeEventListener('mouseup', onMouseUp)
51
- }
52
- }, [direction, minSize, maxSize, inverted])
53
-
54
- return { size, onMouseDown }
55
- }