prompt_objects 0.5.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 (292) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +142 -0
  3. data/README.md +211 -19
  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 +1350 -18
  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 +190 -432
  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 +561 -52
  65. data/lib/prompt_objects/server/app.rb +134 -1
  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 -207
  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 +774 -15
  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 +78 -0
  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 +58 -0
  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 +57 -0
  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/set_env_data.rb +101 -0
  87. data/lib/prompt_objects/version.rb +5 -0
  88. data/lib/prompt_objects.rb +36 -6
  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 +6 -2
  92. data/templates/arc-agi-1/objects/solver.md +14 -4
  93. data/templates/arc-agi-1/objects/verifier.md +6 -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 +28 -1
  230. metadata +175 -65
  231. data/CLAUDE.md +0 -176
  232. data/Gemfile +0 -10
  233. data/Gemfile.lock +0 -233
  234. data/IMPLEMENTATION_PLAN.md +0 -1073
  235. data/Rakefile +0 -27
  236. data/design-doc-v2.md +0 -1232
  237. data/frontend/.gitignore +0 -3
  238. data/frontend/index.html +0 -17
  239. data/frontend/package-lock.json +0 -4540
  240. data/frontend/package.json +0 -36
  241. data/frontend/postcss.config.js +0 -6
  242. data/frontend/src/App.tsx +0 -103
  243. data/frontend/src/canvas/CanvasView.tsx +0 -113
  244. data/frontend/src/canvas/ForceLayout.ts +0 -115
  245. data/frontend/src/canvas/SceneManager.ts +0 -587
  246. data/frontend/src/canvas/canvasStore.ts +0 -47
  247. data/frontend/src/canvas/constants.ts +0 -95
  248. data/frontend/src/canvas/controls/CameraControls.ts +0 -98
  249. data/frontend/src/canvas/edges/MessageArc.ts +0 -149
  250. data/frontend/src/canvas/inspector/InspectorPanel.tsx +0 -31
  251. data/frontend/src/canvas/inspector/POInspector.tsx +0 -262
  252. data/frontend/src/canvas/inspector/ToolCallInspector.tsx +0 -67
  253. data/frontend/src/canvas/nodes/PONode.ts +0 -249
  254. data/frontend/src/canvas/nodes/ToolCallNode.ts +0 -116
  255. data/frontend/src/canvas/types.ts +0 -24
  256. data/frontend/src/components/ContextMenu.tsx +0 -68
  257. data/frontend/src/components/Inspector.tsx +0 -232
  258. data/frontend/src/components/MarkdownMessage.tsx +0 -155
  259. data/frontend/src/components/MethodList.tsx +0 -90
  260. data/frontend/src/components/ModelSelector.tsx +0 -115
  261. data/frontend/src/components/NotificationPanel.tsx +0 -130
  262. data/frontend/src/components/ObjectList.tsx +0 -78
  263. data/frontend/src/components/PaneSlot.tsx +0 -30
  264. data/frontend/src/components/SourcePane.tsx +0 -202
  265. data/frontend/src/components/SystemBar.tsx +0 -74
  266. data/frontend/src/components/Transcript.tsx +0 -76
  267. data/frontend/src/components/UsagePanel.tsx +0 -105
  268. data/frontend/src/components/Workspace.tsx +0 -260
  269. data/frontend/src/components/index.ts +0 -12
  270. data/frontend/src/hooks/useResize.ts +0 -55
  271. data/frontend/src/hooks/useWebSocket.ts +0 -517
  272. data/frontend/src/index.css +0 -103
  273. data/frontend/src/main.tsx +0 -10
  274. data/frontend/src/store/index.ts +0 -279
  275. data/frontend/src/types/index.ts +0 -165
  276. data/frontend/tailwind.config.js +0 -44
  277. data/frontend/tsconfig.json +0 -30
  278. data/frontend/vite.config.ts +0 -29
  279. data/lib/prompt_objects/server/public/assets/index-D1myxE0l.js +0 -4345
  280. data/lib/prompt_objects/server/public/assets/index-DdCcwC-Z.css +0 -1
  281. data/lib/prompt_objects/universal/add_primitive.rb +0 -118
  282. data/lib/prompt_objects/universal/ask_human.rb +0 -109
  283. data/lib/prompt_objects/universal/create_primitive.rb +0 -174
  284. data/lib/prompt_objects/universal/list_primitives.rb +0 -145
  285. data/lib/prompt_objects/universal/think.rb +0 -41
  286. data/prompt_objects.gemspec +0 -50
  287. data/templates/basic/.gitignore +0 -2
  288. data/templates/developer/.gitignore +0 -5
  289. data/templates/empty/.gitignore +0 -5
  290. data/templates/empty/objects/.gitkeep +0 -0
  291. data/templates/minimal/.gitignore +0 -5
  292. data/templates/writer/.gitignore +0 -5
@@ -1,202 +0,0 @@
1
- import { useState, useEffect, useCallback, useRef } from 'react'
2
- import type { PromptObject, CapabilityInfo } from '../types'
3
-
4
- interface SourcePaneProps {
5
- po: PromptObject
6
- selectedCapability: CapabilityInfo | null
7
- onSave?: (prompt: string) => void
8
- }
9
-
10
- export function SourcePane({ po, selectedCapability, onSave }: SourcePaneProps) {
11
- const prompt = po.prompt || ''
12
- const config = po.config || {}
13
- const [isEditing, setIsEditing] = useState(false)
14
- const [editedPrompt, setEditedPrompt] = useState(prompt)
15
- const [saveStatus, setSaveStatus] = useState<'saved' | 'saving' | 'unsaved'>('saved')
16
- const saveTimeoutRef = useRef<number | null>(null)
17
-
18
- // Sync editedPrompt when po.prompt changes from server
19
- useEffect(() => {
20
- if (!isEditing) {
21
- setEditedPrompt(prompt)
22
- }
23
- }, [prompt, isEditing])
24
-
25
- // Debounced auto-save
26
- const debouncedSave = useCallback((newPrompt: string) => {
27
- if (saveTimeoutRef.current) {
28
- clearTimeout(saveTimeoutRef.current)
29
- }
30
-
31
- setSaveStatus('unsaved')
32
-
33
- saveTimeoutRef.current = window.setTimeout(() => {
34
- if (onSave && newPrompt !== prompt) {
35
- setSaveStatus('saving')
36
- onSave(newPrompt)
37
- setTimeout(() => setSaveStatus('saved'), 500)
38
- } else {
39
- setSaveStatus('saved')
40
- }
41
- }, 1000)
42
- }, [onSave, prompt])
43
-
44
- const handlePromptChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
45
- const newPrompt = e.target.value
46
- setEditedPrompt(newPrompt)
47
- debouncedSave(newPrompt)
48
- }
49
-
50
- const handleToggleEdit = () => {
51
- if (isEditing) {
52
- // Save on exit
53
- if (saveTimeoutRef.current) {
54
- clearTimeout(saveTimeoutRef.current)
55
- }
56
- if (editedPrompt !== prompt && onSave) {
57
- onSave(editedPrompt)
58
- }
59
- setIsEditing(false)
60
- setSaveStatus('saved')
61
- } else {
62
- setEditedPrompt(prompt)
63
- setIsEditing(true)
64
- }
65
- }
66
-
67
- // Cleanup timeout on unmount
68
- useEffect(() => {
69
- return () => {
70
- if (saveTimeoutRef.current) {
71
- clearTimeout(saveTimeoutRef.current)
72
- }
73
- }
74
- }, [])
75
-
76
- // Capability detail view
77
- if (selectedCapability) {
78
- return (
79
- <div className="flex-1 overflow-auto bg-po-bg">
80
- <div className="px-3 py-2 border-b border-po-border bg-po-surface">
81
- <span className="font-mono text-xs text-po-accent">{selectedCapability.name}</span>
82
- </div>
83
- <div className="p-3 space-y-3">
84
- <p className="text-xs text-po-text-secondary">{selectedCapability.description}</p>
85
- {selectedCapability.parameters && (
86
- <ParametersView parameters={selectedCapability.parameters} />
87
- )}
88
- </div>
89
- </div>
90
- )
91
- }
92
-
93
- // Prompt source view
94
- return (
95
- <div className="flex-1 overflow-auto bg-po-bg flex flex-col">
96
- {/* Header with edit toggle and save status */}
97
- <div className="px-3 py-1.5 border-b border-po-border bg-po-surface flex items-center gap-2 flex-shrink-0">
98
- <span className="text-2xs text-po-text-ghost uppercase tracking-wider flex-1">Source</span>
99
-
100
- {isEditing && (
101
- <span className="flex items-center gap-1">
102
- <span className={`w-1.5 h-1.5 rounded-full ${
103
- saveStatus === 'saved' ? 'bg-po-success' :
104
- saveStatus === 'saving' ? 'bg-po-accent animate-pulse' :
105
- 'bg-po-text-ghost'
106
- }`} />
107
- <span className={`text-2xs ${
108
- saveStatus === 'saved' ? 'text-po-success' :
109
- saveStatus === 'saving' ? 'text-po-accent' :
110
- 'text-po-text-ghost'
111
- }`}>
112
- {saveStatus === 'saved' ? 'saved' : saveStatus === 'saving' ? 'saving' : 'unsaved'}
113
- </span>
114
- </span>
115
- )}
116
-
117
- <button
118
- onClick={handleToggleEdit}
119
- className={`text-2xs px-1.5 py-0.5 rounded transition-colors duration-150 ${
120
- isEditing
121
- ? 'bg-po-accent text-po-bg'
122
- : 'text-po-text-tertiary hover:text-po-text-primary hover:bg-po-surface-2'
123
- }`}
124
- >
125
- {isEditing ? 'Done' : 'Edit'}
126
- </button>
127
- </div>
128
-
129
- {/* Config (collapsed) */}
130
- {Object.keys(config).length > 0 && (
131
- <details className="border-b border-po-border">
132
- <summary className="px-3 py-1 text-2xs text-po-text-ghost cursor-pointer hover:text-po-text-secondary transition-colors duration-150">
133
- Frontmatter
134
- </summary>
135
- <pre className="px-3 pb-2 text-2xs text-po-text-tertiary font-mono whitespace-pre-wrap">
136
- {JSON.stringify(config, null, 2)}
137
- </pre>
138
- </details>
139
- )}
140
-
141
- {/* Prompt content */}
142
- {isEditing ? (
143
- <textarea
144
- value={editedPrompt}
145
- onChange={handlePromptChange}
146
- className="flex-1 w-full p-3 bg-transparent text-po-text-primary font-mono text-xs resize-none focus:outline-none"
147
- placeholder="Enter prompt markdown..."
148
- spellCheck={false}
149
- />
150
- ) : (
151
- <pre className="flex-1 p-3 text-xs text-po-text-secondary font-mono whitespace-pre-wrap overflow-auto">
152
- {prompt || '(empty)'}
153
- </pre>
154
- )}
155
- </div>
156
- )
157
- }
158
-
159
- function ParametersView({ parameters }: { parameters: Record<string, unknown> }) {
160
- const properties = (parameters.properties as Record<string, unknown>) || {}
161
- const required = (parameters.required as string[]) || []
162
-
163
- const propertyNames = Object.keys(properties)
164
- if (propertyNames.length === 0) return null
165
-
166
- return (
167
- <div>
168
- <div className="text-2xs text-po-text-ghost uppercase tracking-wider mb-1.5">Parameters</div>
169
- <div className="space-y-1.5">
170
- {propertyNames.map((propName) => {
171
- const prop = properties[propName] as Record<string, unknown>
172
- const isRequired = required.includes(propName)
173
- const propType = prop.type ? String(prop.type) : null
174
- const propDescription = prop.description ? String(prop.description) : null
175
- const propEnum = prop.enum as string[] | undefined
176
-
177
- return (
178
- <div key={propName} className="bg-po-surface rounded p-2">
179
- <div className="flex items-center gap-1.5">
180
- <span className="font-mono text-2xs text-po-accent">{propName}</span>
181
- {propType && <span className="text-2xs text-po-text-ghost">({propType})</span>}
182
- {isRequired && <span className="text-2xs text-po-error">req</span>}
183
- </div>
184
- {propDescription && (
185
- <p className="text-2xs text-po-text-tertiary mt-0.5">{propDescription}</p>
186
- )}
187
- {propEnum && propEnum.length > 0 && (
188
- <div className="mt-1 flex flex-wrap gap-1">
189
- {propEnum.map((val) => (
190
- <span key={val} className="text-2xs bg-po-surface-2 px-1 py-0.5 rounded text-po-text-ghost">
191
- {val}
192
- </span>
193
- ))}
194
- </div>
195
- )}
196
- </div>
197
- )
198
- })}
199
- </div>
200
- </div>
201
- )
202
- }
@@ -1,74 +0,0 @@
1
- import { useStore, useNotificationCount } from '../store'
2
- import { ModelSelector } from './ModelSelector'
3
-
4
- interface Props {
5
- switchLLM: (provider: string, model?: string) => void
6
- }
7
-
8
- export function SystemBar({ switchLLM }: Props) {
9
- const { connected, environment, toggleBus, busOpen, currentView, setCurrentView } =
10
- useStore()
11
- const notificationCount = useNotificationCount()
12
-
13
- return (
14
- <header className="h-8 bg-po-surface-2 border-b border-po-border flex items-center px-3 gap-3 flex-shrink-0">
15
- {/* Logo / Environment */}
16
- <div className="flex items-center gap-1.5 text-xs">
17
- <span className="font-mono text-po-text-primary font-medium">PromptObjects</span>
18
- {environment && (
19
- <>
20
- <span className="text-po-text-ghost">/</span>
21
- <span className="text-po-text-secondary">{environment.name}</span>
22
- </>
23
- )}
24
- </div>
25
-
26
- <div className="flex-1" />
27
-
28
- {/* Connection dot */}
29
- <div
30
- className={`w-1.5 h-1.5 rounded-full flex-shrink-0 ${
31
- connected ? 'bg-po-success' : 'bg-po-error animate-pulse'
32
- }`}
33
- title={connected ? 'Connected' : 'Disconnected'}
34
- />
35
-
36
- {/* Model selector */}
37
- <ModelSelector switchLLM={switchLLM} />
38
-
39
- {/* Notification count */}
40
- {notificationCount > 0 && (
41
- <span
42
- className="text-2xs font-mono bg-po-warning text-po-bg px-1.5 py-0.5 rounded font-bold"
43
- title={`${notificationCount} pending requests`}
44
- >
45
- {notificationCount}
46
- </span>
47
- )}
48
-
49
- {/* Canvas toggle */}
50
- <button
51
- onClick={() => setCurrentView(currentView === 'canvas' ? 'dashboard' : 'canvas')}
52
- className={`text-xs px-2 py-0.5 rounded transition-colors duration-150 ${
53
- currentView === 'canvas'
54
- ? 'bg-po-accent text-po-bg font-medium'
55
- : 'text-po-text-secondary hover:text-po-text-primary hover:bg-po-surface-3'
56
- }`}
57
- >
58
- Canvas
59
- </button>
60
-
61
- {/* Transcript toggle */}
62
- <button
63
- onClick={toggleBus}
64
- className={`text-xs px-2 py-0.5 rounded transition-colors duration-150 ${
65
- busOpen
66
- ? 'bg-po-accent text-po-bg font-medium'
67
- : 'text-po-text-secondary hover:text-po-text-primary hover:bg-po-surface-3'
68
- }`}
69
- >
70
- Transcript
71
- </button>
72
- </header>
73
- )
74
- }
@@ -1,76 +0,0 @@
1
- import { useRef, useEffect, useState } from 'react'
2
- import { useStore } from '../store'
3
-
4
- export function Transcript() {
5
- const { busMessages, toggleBus } = useStore()
6
- const messagesEndRef = useRef<HTMLDivElement>(null)
7
-
8
- useEffect(() => {
9
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
10
- }, [busMessages])
11
-
12
- return (
13
- <div className="h-full flex flex-col border-t border-po-border">
14
- {/* Header */}
15
- <div className="h-6 bg-po-surface-2 border-b border-po-border flex items-center px-3 flex-shrink-0">
16
- <span className="text-2xs font-medium text-po-text-ghost uppercase tracking-wider flex-1">
17
- Transcript
18
- </span>
19
- <button
20
- onClick={toggleBus}
21
- className="text-2xs text-po-text-ghost hover:text-po-text-secondary transition-colors duration-150"
22
- >
23
- {'\u2715'}
24
- </button>
25
- </div>
26
-
27
- {/* Messages */}
28
- <div className="flex-1 overflow-auto px-3 py-1 font-mono">
29
- {busMessages.length === 0 ? (
30
- <div className="text-2xs text-po-text-ghost text-center py-2">
31
- No messages
32
- </div>
33
- ) : (
34
- busMessages.map((msg, index) => (
35
- <TranscriptRow key={index} msg={msg} />
36
- ))
37
- )}
38
- <div ref={messagesEndRef} />
39
- </div>
40
- </div>
41
- )
42
- }
43
-
44
- function TranscriptRow({ msg }: { msg: { from: string; to: string; content: string | Record<string, unknown>; summary?: string; timestamp: string } }) {
45
- const [expanded, setExpanded] = useState(false)
46
- const fullText = msg.summary || (typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content, null, 2))
47
- const isLong = fullText.length > 120
48
- const truncated = isLong ? fullText.slice(0, 120) + '...' : fullText
49
-
50
- return (
51
- <div>
52
- <div
53
- onClick={() => isLong && setExpanded(!expanded)}
54
- className={`text-2xs leading-relaxed flex items-baseline gap-1.5 ${isLong ? 'cursor-pointer hover:bg-po-surface-2' : ''} ${expanded ? 'bg-po-surface-2' : ''}`}
55
- >
56
- <span className="text-po-text-ghost flex-shrink-0 whitespace-nowrap">
57
- {new Date(msg.timestamp).toLocaleTimeString('en-US', { hour12: false })}
58
- </span>
59
- <span className="text-po-accent flex-shrink-0">{msg.from}</span>
60
- <span className="text-po-text-ghost">{'\u2192'}</span>
61
- <span className="text-po-status-calling flex-shrink-0">{msg.to}</span>
62
- {!expanded && (
63
- <span className="text-po-text-secondary truncate">{truncated}</span>
64
- )}
65
- {isLong && (
66
- <span className="text-po-text-ghost flex-shrink-0 ml-auto">{expanded ? '\u25BC' : '\u25B8'}</span>
67
- )}
68
- </div>
69
- {expanded && (
70
- <pre className="text-2xs text-po-text-secondary whitespace-pre-wrap break-all pl-[4.5rem] pb-1.5 bg-po-surface-2 rounded-b mb-0.5">
71
- {fullText}
72
- </pre>
73
- )}
74
- </div>
75
- )
76
- }
@@ -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
- }