prompt_objects 0.1.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 (117) hide show
  1. checksums.yaml +7 -0
  2. data/CLAUDE.md +108 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +231 -0
  5. data/IMPLEMENTATION_PLAN.md +1073 -0
  6. data/LICENSE +21 -0
  7. data/README.md +73 -0
  8. data/Rakefile +27 -0
  9. data/design-doc-v2.md +1232 -0
  10. data/exe/prompt_objects +572 -0
  11. data/exe/prompt_objects_mcp +34 -0
  12. data/frontend/.gitignore +3 -0
  13. data/frontend/index.html +13 -0
  14. data/frontend/package-lock.json +4417 -0
  15. data/frontend/package.json +32 -0
  16. data/frontend/postcss.config.js +6 -0
  17. data/frontend/src/App.tsx +95 -0
  18. data/frontend/src/components/CapabilitiesPanel.tsx +44 -0
  19. data/frontend/src/components/ChatPanel.tsx +251 -0
  20. data/frontend/src/components/Dashboard.tsx +83 -0
  21. data/frontend/src/components/Header.tsx +141 -0
  22. data/frontend/src/components/MarkdownMessage.tsx +153 -0
  23. data/frontend/src/components/MessageBus.tsx +55 -0
  24. data/frontend/src/components/ModelSelector.tsx +112 -0
  25. data/frontend/src/components/NotificationPanel.tsx +134 -0
  26. data/frontend/src/components/POCard.tsx +56 -0
  27. data/frontend/src/components/PODetail.tsx +117 -0
  28. data/frontend/src/components/PromptPanel.tsx +51 -0
  29. data/frontend/src/components/SessionsPanel.tsx +174 -0
  30. data/frontend/src/components/ThreadsSidebar.tsx +119 -0
  31. data/frontend/src/components/index.ts +11 -0
  32. data/frontend/src/hooks/useWebSocket.ts +363 -0
  33. data/frontend/src/index.css +37 -0
  34. data/frontend/src/main.tsx +10 -0
  35. data/frontend/src/store/index.ts +246 -0
  36. data/frontend/src/types/index.ts +146 -0
  37. data/frontend/tailwind.config.js +25 -0
  38. data/frontend/tsconfig.json +30 -0
  39. data/frontend/vite.config.ts +29 -0
  40. data/lib/prompt_objects/capability.rb +46 -0
  41. data/lib/prompt_objects/cli.rb +431 -0
  42. data/lib/prompt_objects/connectors/base.rb +73 -0
  43. data/lib/prompt_objects/connectors/mcp.rb +524 -0
  44. data/lib/prompt_objects/environment/exporter.rb +83 -0
  45. data/lib/prompt_objects/environment/git.rb +118 -0
  46. data/lib/prompt_objects/environment/importer.rb +159 -0
  47. data/lib/prompt_objects/environment/manager.rb +401 -0
  48. data/lib/prompt_objects/environment/manifest.rb +218 -0
  49. data/lib/prompt_objects/environment.rb +283 -0
  50. data/lib/prompt_objects/human_queue.rb +144 -0
  51. data/lib/prompt_objects/llm/anthropic_adapter.rb +137 -0
  52. data/lib/prompt_objects/llm/factory.rb +84 -0
  53. data/lib/prompt_objects/llm/gemini_adapter.rb +209 -0
  54. data/lib/prompt_objects/llm/openai_adapter.rb +104 -0
  55. data/lib/prompt_objects/llm/response.rb +61 -0
  56. data/lib/prompt_objects/loader.rb +32 -0
  57. data/lib/prompt_objects/mcp/server.rb +167 -0
  58. data/lib/prompt_objects/mcp/tools/get_conversation.rb +60 -0
  59. data/lib/prompt_objects/mcp/tools/get_pending_requests.rb +54 -0
  60. data/lib/prompt_objects/mcp/tools/inspect_po.rb +73 -0
  61. data/lib/prompt_objects/mcp/tools/list_prompt_objects.rb +37 -0
  62. data/lib/prompt_objects/mcp/tools/respond_to_request.rb +68 -0
  63. data/lib/prompt_objects/mcp/tools/send_message.rb +71 -0
  64. data/lib/prompt_objects/message_bus.rb +97 -0
  65. data/lib/prompt_objects/primitive.rb +13 -0
  66. data/lib/prompt_objects/primitives/http_get.rb +72 -0
  67. data/lib/prompt_objects/primitives/list_files.rb +95 -0
  68. data/lib/prompt_objects/primitives/read_file.rb +81 -0
  69. data/lib/prompt_objects/primitives/write_file.rb +73 -0
  70. data/lib/prompt_objects/prompt_object.rb +415 -0
  71. data/lib/prompt_objects/registry.rb +88 -0
  72. data/lib/prompt_objects/server/api/routes.rb +297 -0
  73. data/lib/prompt_objects/server/app.rb +174 -0
  74. data/lib/prompt_objects/server/file_watcher.rb +113 -0
  75. data/lib/prompt_objects/server/public/assets/index-2acS2FYZ.js +77 -0
  76. data/lib/prompt_objects/server/public/assets/index-DXU5uRXQ.css +1 -0
  77. data/lib/prompt_objects/server/public/index.html +14 -0
  78. data/lib/prompt_objects/server/websocket_handler.rb +619 -0
  79. data/lib/prompt_objects/server.rb +166 -0
  80. data/lib/prompt_objects/session/store.rb +826 -0
  81. data/lib/prompt_objects/universal/add_capability.rb +74 -0
  82. data/lib/prompt_objects/universal/add_primitive.rb +113 -0
  83. data/lib/prompt_objects/universal/ask_human.rb +109 -0
  84. data/lib/prompt_objects/universal/create_capability.rb +219 -0
  85. data/lib/prompt_objects/universal/create_primitive.rb +170 -0
  86. data/lib/prompt_objects/universal/list_capabilities.rb +55 -0
  87. data/lib/prompt_objects/universal/list_primitives.rb +145 -0
  88. data/lib/prompt_objects/universal/modify_primitive.rb +180 -0
  89. data/lib/prompt_objects/universal/request_primitive.rb +287 -0
  90. data/lib/prompt_objects/universal/think.rb +41 -0
  91. data/lib/prompt_objects/universal/verify_primitive.rb +173 -0
  92. data/lib/prompt_objects.rb +62 -0
  93. data/objects/coordinator.md +48 -0
  94. data/objects/greeter.md +30 -0
  95. data/objects/reader.md +33 -0
  96. data/prompt_objects.gemspec +50 -0
  97. data/templates/basic/.gitignore +2 -0
  98. data/templates/basic/manifest.yml +7 -0
  99. data/templates/basic/objects/basic.md +32 -0
  100. data/templates/developer/.gitignore +5 -0
  101. data/templates/developer/manifest.yml +17 -0
  102. data/templates/developer/objects/code_reviewer.md +33 -0
  103. data/templates/developer/objects/coordinator.md +39 -0
  104. data/templates/developer/objects/debugger.md +35 -0
  105. data/templates/empty/.gitignore +5 -0
  106. data/templates/empty/manifest.yml +14 -0
  107. data/templates/empty/objects/.gitkeep +0 -0
  108. data/templates/empty/objects/assistant.md +41 -0
  109. data/templates/minimal/.gitignore +5 -0
  110. data/templates/minimal/manifest.yml +7 -0
  111. data/templates/minimal/objects/assistant.md +41 -0
  112. data/templates/writer/.gitignore +5 -0
  113. data/templates/writer/manifest.yml +17 -0
  114. data/templates/writer/objects/coordinator.md +33 -0
  115. data/templates/writer/objects/editor.md +33 -0
  116. data/templates/writer/objects/researcher.md +34 -0
  117. metadata +343 -0
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "server/api/routes"
4
+ require_relative "server/websocket_handler"
5
+ require_relative "server/file_watcher"
6
+ require_relative "server/app"
7
+
8
+ module PromptObjects
9
+ module Server
10
+ # Start the server for a given runtime.
11
+ # @param runtime [Runtime] The runtime/environment to serve
12
+ # @param host [String] Host to bind to
13
+ # @param port [Integer] Port to listen on
14
+ # @param env_path [String] Path to the environment directory
15
+ def self.start(runtime:, host: "localhost", port: 3000, env_path: nil)
16
+ require "async"
17
+ require "async/http/endpoint"
18
+ require "falcon"
19
+
20
+ app = App.new(runtime)
21
+ url = "http://#{host}:#{port}"
22
+
23
+ puts "PromptObjects Server"
24
+ puts "===================="
25
+ puts "Environment: #{runtime.name}"
26
+ puts "URL: #{url}"
27
+ puts ""
28
+ puts "Prompt Objects:"
29
+ runtime.registry.prompt_objects.each do |po|
30
+ puts " - #{po.name}: #{po.description}"
31
+ end
32
+ puts ""
33
+ puts "Press Ctrl+C to stop"
34
+ puts ""
35
+
36
+ # Register callback for immediate PO registration notifications
37
+ # This fires when create_capability creates a new PO programmatically
38
+ runtime.on_po_registered = ->(po) {
39
+ app.broadcast(
40
+ type: "po_added",
41
+ payload: {
42
+ name: po.name,
43
+ state: po_state_hash(po)
44
+ }
45
+ )
46
+ puts "Broadcast: PO registered - #{po.name}"
47
+ }
48
+
49
+ # Start file watcher for live updates (manual file edits)
50
+ file_watcher = nil
51
+ if env_path
52
+ file_watcher = FileWatcher.new(runtime: runtime, env_path: env_path)
53
+ file_watcher.subscribe do |event, data|
54
+ handle_file_event(app, event, data)
55
+ end
56
+ file_watcher.start
57
+ end
58
+
59
+ Async do |task|
60
+ endpoint = Async::HTTP::Endpoint.parse(url)
61
+
62
+ server = Falcon::Server.new(
63
+ Falcon::Server.middleware(app),
64
+ endpoint
65
+ )
66
+
67
+ task.async do
68
+ server.run
69
+ end
70
+ ensure
71
+ file_watcher&.stop
72
+ end
73
+ end
74
+
75
+ # Handle file change events and broadcast to connected clients.
76
+ def self.handle_file_event(app, event, data)
77
+ case event
78
+ when :po_added
79
+ po = data
80
+ app.broadcast(
81
+ type: "po_added",
82
+ payload: {
83
+ name: po.name,
84
+ state: po_state_hash(po)
85
+ }
86
+ )
87
+ puts "Broadcast: PO added - #{po.name}"
88
+
89
+ when :po_modified
90
+ po = data
91
+ app.broadcast(
92
+ type: "po_modified",
93
+ payload: {
94
+ name: po.name,
95
+ state: po_state_hash(po)
96
+ }
97
+ )
98
+ puts "Broadcast: PO modified - #{po.name}"
99
+
100
+ when :po_removed
101
+ app.broadcast(
102
+ type: "po_removed",
103
+ payload: { name: data[:name] }
104
+ )
105
+ puts "Broadcast: PO removed - #{data[:name]}"
106
+ end
107
+ end
108
+
109
+ # Helper to convert PO to state hash for broadcasting.
110
+ def self.po_state_hash(po)
111
+ {
112
+ status: po.instance_variable_get(:@state) || "idle",
113
+ description: po.description,
114
+ capabilities: po.config["capabilities"] || [],
115
+ current_session: current_session_hash(po),
116
+ sessions: po.list_sessions.map do |s|
117
+ {
118
+ id: s[:id],
119
+ name: s[:name],
120
+ message_count: s[:message_count] || 0,
121
+ updated_at: s[:updated_at]&.iso8601,
122
+ # Thread fields
123
+ parent_session_id: s[:parent_session_id],
124
+ parent_po: s[:parent_po],
125
+ thread_type: s[:thread_type] || "root"
126
+ }
127
+ end,
128
+ prompt: po.body,
129
+ config: po.config
130
+ }
131
+ end
132
+
133
+ # Helper to get current session data for a PO.
134
+ def self.current_session_hash(po)
135
+ return nil unless po.session_id
136
+
137
+ {
138
+ id: po.session_id,
139
+ messages: po.history.map { |m| message_to_hash(m) }
140
+ }
141
+ end
142
+
143
+ # Helper to convert a message to JSON-serializable hash.
144
+ def self.message_to_hash(msg)
145
+ case msg[:role]
146
+ when :user
147
+ { role: "user", content: msg[:content], from: msg[:from] }
148
+ when :assistant
149
+ hash = { role: "assistant", content: msg[:content] }
150
+ if msg[:tool_calls]
151
+ hash[:tool_calls] = msg[:tool_calls].map do |tc|
152
+ tc_id = tc.respond_to?(:id) ? tc.id : (tc[:id] || tc["id"])
153
+ tc_name = tc.respond_to?(:name) ? tc.name : (tc[:name] || tc["name"])
154
+ tc_args = tc.respond_to?(:arguments) ? tc.arguments : (tc[:arguments] || tc["arguments"] || {})
155
+ { id: tc_id, name: tc_name, arguments: tc_args }
156
+ end
157
+ end
158
+ hash
159
+ when :tool
160
+ { role: "tool", results: msg[:results] }
161
+ else
162
+ { role: msg[:role].to_s, content: msg[:content] }
163
+ end
164
+ end
165
+ end
166
+ end