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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +142 -0
- data/README.md +211 -19
- data/exe/poop +5 -0
- data/exe/prompt_objects +1 -1108
- data/exe/prompt_objects_mcp +5 -3
- data/lib/prompt_objects/capability.rb +33 -0
- data/lib/prompt_objects/cli/diagnostics_command.rb +69 -0
- data/lib/prompt_objects/cli/env_command.rb +435 -0
- data/lib/prompt_objects/cli/events_command.rb +145 -0
- data/lib/prompt_objects/cli/explore_command.rb +155 -0
- data/lib/prompt_objects/cli/helpers.rb +91 -0
- data/lib/prompt_objects/cli/message_command.rb +216 -0
- data/lib/prompt_objects/cli/repl_command.rb +366 -0
- data/lib/prompt_objects/cli/serve_command.rb +162 -0
- data/lib/prompt_objects/cli.rb +64 -422
- data/lib/prompt_objects/connectors/base.rb +16 -29
- data/lib/prompt_objects/connectors/mcp.rb +82 -98
- data/lib/prompt_objects/domain/records.rb +45 -0
- data/lib/prompt_objects/environment/exporter.rb +5 -4
- data/lib/prompt_objects/environment/git.rb +21 -1
- data/lib/prompt_objects/environment/importer.rb +5 -4
- data/lib/prompt_objects/environment/manager.rb +44 -6
- data/lib/prompt_objects/environment/manifest.rb +26 -4
- data/lib/prompt_objects/environment.rb +1350 -18
- data/lib/prompt_objects/execution/blocking_executor.rb +88 -0
- data/lib/prompt_objects/execution/context.rb +137 -0
- data/lib/prompt_objects/execution/contracts.rb +59 -0
- data/lib/prompt_objects/execution/permit_pool.rb +49 -0
- data/lib/prompt_objects/execution/policy.rb +47 -0
- data/lib/prompt_objects/execution/resource_lock_manager.rb +63 -0
- data/lib/prompt_objects/execution/runner.rb +498 -0
- data/lib/prompt_objects/execution/scheduler.rb +325 -0
- data/lib/prompt_objects/llm/factory.rb +4 -4
- data/lib/prompt_objects/llm/gemini_adapter.rb +25 -8
- data/lib/prompt_objects/llm/openai_adapter.rb +9 -1
- data/lib/prompt_objects/llm/pricing.rb +9 -2
- data/lib/prompt_objects/llm/response.rb +9 -4
- data/lib/prompt_objects/loader.rb +28 -1
- data/lib/prompt_objects/mcp/server.rb +6 -3
- data/lib/prompt_objects/mcp/tools/get_conversation.rb +15 -11
- data/lib/prompt_objects/mcp/tools/get_pending_requests.rb +2 -2
- data/lib/prompt_objects/mcp/tools/respond_to_request.rb +3 -3
- data/lib/prompt_objects/mcp/tools/send_message.rb +42 -32
- data/lib/prompt_objects/operations/diagnostics.rb +115 -0
- data/lib/prompt_objects/operations/retention.rb +75 -0
- data/lib/prompt_objects/operations/run_trace_builder.rb +152 -0
- data/lib/prompt_objects/primitives/http_get.rb +2 -0
- data/lib/prompt_objects/primitives/list_files.rb +2 -0
- data/lib/prompt_objects/primitives/read_file.rb +2 -0
- data/lib/prompt_objects/primitives/think.rb +36 -0
- data/lib/prompt_objects/primitives/write_file.rb +9 -0
- data/lib/prompt_objects/prompt_object.rb +190 -432
- data/lib/prompt_objects/repositories/artifact_repository.rb +109 -0
- data/lib/prompt_objects/repositories/base_repository.rb +37 -0
- data/lib/prompt_objects/repositories/definition_repository.rb +36 -0
- data/lib/prompt_objects/repositories/env_data_repository.rb +103 -0
- data/lib/prompt_objects/repositories/event_repository.rb +105 -0
- data/lib/prompt_objects/repositories/message_repository.rb +73 -0
- data/lib/prompt_objects/repositories/run_repository.rb +254 -0
- data/lib/prompt_objects/repositories/thread_repository.rb +87 -0
- data/lib/prompt_objects/repositories/tool_execution_repository.rb +88 -0
- data/lib/prompt_objects/repositories/workspace_session_repository.rb +61 -0
- data/lib/prompt_objects/server/api/routes.rb +561 -52
- data/lib/prompt_objects/server/app.rb +134 -1
- data/lib/prompt_objects/server/file_watcher.rb +9 -0
- data/lib/prompt_objects/server/public/assets/index-BjKlODDD.js +90 -0
- data/lib/prompt_objects/server/public/assets/index-w3fpIb5c.css +1 -0
- data/lib/prompt_objects/server/public/index.html +2 -2
- data/lib/prompt_objects/server/websocket_handler.rb +202 -207
- data/lib/prompt_objects/server.rb +170 -1
- data/lib/prompt_objects/service.rb +129 -0
- data/lib/prompt_objects/session/store.rb +774 -15
- data/lib/prompt_objects/universal/add_capability.rb +1 -1
- data/lib/prompt_objects/universal/create_capability.rb +4 -2
- data/lib/prompt_objects/universal/delete_env_data.rb +78 -0
- data/lib/prompt_objects/universal/delete_primitive.rb +1 -1
- data/lib/prompt_objects/universal/dispatch_po.rb +54 -0
- data/lib/prompt_objects/universal/get_env_data.rb +58 -0
- data/lib/prompt_objects/universal/get_run_status.rb +30 -0
- data/lib/prompt_objects/universal/join_runs.rb +35 -0
- data/lib/prompt_objects/universal/list_env_data.rb +57 -0
- data/lib/prompt_objects/universal/modify_primitive.rb +1 -1
- data/lib/prompt_objects/universal/render_artifact.rb +91 -0
- data/lib/prompt_objects/universal/request_primitive.rb +1 -1
- data/lib/prompt_objects/universal/set_env_data.rb +101 -0
- data/lib/prompt_objects/version.rb +5 -0
- data/lib/prompt_objects.rb +36 -6
- data/objects/coordinator.md +8 -4
- data/templates/arc-agi-1/objects/data_manager.md +2 -2
- data/templates/arc-agi-1/objects/observer.md +6 -2
- data/templates/arc-agi-1/objects/solver.md +14 -4
- data/templates/arc-agi-1/objects/verifier.md +6 -2
- data/templates/arc-agi-3/manifest.yml +19 -0
- data/templates/arc-agi-3/objects/analyst.md +79 -0
- data/templates/arc-agi-3/objects/player.md +76 -0
- data/templates/arc-agi-3/objects/strategist.md +97 -0
- data/templates/arc-agi-3/primitives/action_log.rb +133 -0
- data/templates/arc-agi-3/primitives/arc3_api.rb +223 -0
- data/templates/arc-agi-3/primitives/arc3_scorecard.rb +131 -0
- data/templates/arc-agi-3/primitives/frame_diff.rb +143 -0
- data/templates/arc-agi-3/primitives/frame_info.rb +96 -0
- data/templates/arc-agi-3/primitives/render_frame.rb +140 -0
- data/templates/basic/objects/basic.md +11 -3
- data/templates/chiptune/extras/sonic_pi_boot.rb +220 -0
- data/templates/chiptune/manifest.yml +20 -0
- data/templates/chiptune/objects/conductor.md +184 -0
- data/templates/chiptune/objects/sonic_pi.md +65 -0
- data/templates/chiptune/objects/voice_bass.md +44 -0
- data/templates/chiptune/objects/voice_lead.md +44 -0
- data/templates/chiptune/objects/voice_pad.md +43 -0
- data/templates/chiptune/objects/voice_perc.md +45 -0
- data/templates/chiptune/primitives/play_note.rb +59 -0
- data/templates/chiptune/primitives/play_sequence.rb +55 -0
- data/templates/chiptune/primitives/query_sonic_pi.rb +141 -0
- data/templates/chiptune/primitives/set_synth.rb +57 -0
- data/templates/chiptune/primitives/set_tempo.rb +45 -0
- data/templates/chiptune/primitives/stop_voice.rb +46 -0
- data/templates/chiptune/primitives/support/osc_bridge.rb +33 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/LICENSE +19 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
- data/templates/developer/objects/code_reviewer.md +1 -1
- data/templates/developer/objects/coordinator.md +16 -3
- data/templates/developer/objects/debugger.md +3 -3
- data/templates/empty/objects/assistant.md +10 -5
- data/templates/minimal/objects/assistant.md +10 -5
- data/templates/music/extras/sonic_pi_boot.rb +220 -0
- data/templates/music/manifest.yml +16 -0
- data/templates/music/objects/conductor.md +154 -0
- data/templates/music/objects/sonic_pi.md +65 -0
- data/templates/music/primitives/play_note.rb +55 -0
- data/templates/music/primitives/play_sequence.rb +51 -0
- data/templates/music/primitives/query_sonic_pi.rb +139 -0
- data/templates/music/primitives/set_synth.rb +53 -0
- data/templates/music/primitives/set_tempo.rb +43 -0
- data/templates/music/primitives/stop_voice.rb +44 -0
- data/templates/music/primitives/support/osc_bridge.rb +33 -0
- data/templates/music/vendor/osc-ruby-1.1.5/LICENSE +19 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
- data/templates/music-beginner/README.md +100 -0
- data/templates/music-beginner/extras/README.md +27 -0
- data/templates/music-beginner/extras/sonic_pi_boot.rb +297 -0
- data/templates/music-beginner/manifest.yml +25 -0
- data/templates/music-beginner/objects/conductor.md +222 -0
- data/templates/music-beginner/objects/engine_setup.md +54 -0
- data/templates/music-beginner/objects/voice_bass.md +43 -0
- data/templates/music-beginner/objects/voice_keys.md +48 -0
- data/templates/music-beginner/objects/voice_pad.md +46 -0
- data/templates/music-beginner/objects/voice_percussion.md +45 -0
- data/templates/music-beginner/objects/voice_texture.md +37 -0
- data/templates/music-beginner/primitives/play_pattern.rb +118 -0
- data/templates/music-beginner/primitives/query_music_engine.rb +94 -0
- data/templates/music-beginner/primitives/set_instrument.rb +47 -0
- data/templates/music-beginner/primitives/set_tempo.rb +43 -0
- data/templates/music-beginner/primitives/set_voice_level.rb +46 -0
- data/templates/music-beginner/primitives/stop_voice.rb +37 -0
- data/templates/music-beginner/primitives/support/osc_bridge.rb +25 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/LICENSE +19 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
- data/templates/music-pro/extras/AUDITION.md +100 -0
- data/templates/music-pro/extras/sonic_pi_boot.rb +546 -0
- data/templates/music-pro/manifest.yml +19 -0
- data/templates/music-pro/objects/conductor.md +126 -0
- data/templates/music-pro/objects/sonic_pi.md +35 -0
- data/templates/music-pro/objects/voice_harmony.md +48 -0
- data/templates/music-pro/objects/voice_rhythm.md +43 -0
- data/templates/music-pro/objects/voice_texture.md +42 -0
- data/templates/music-pro/primitives/define_patch.rb +46 -0
- data/templates/music-pro/primitives/query_music_engine.rb +69 -0
- data/templates/music-pro/primitives/set_live_pattern.rb +70 -0
- data/templates/music-pro/primitives/set_tempo.rb +31 -0
- data/templates/music-pro/primitives/stop_voice.rb +31 -0
- data/templates/music-pro/primitives/support/music_protocol.rb +136 -0
- data/templates/music-pro/primitives/support/osc_bridge.rb +33 -0
- data/templates/music-pro/primitives/trigger_event.rb +44 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/LICENSE +19 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
- data/templates/writer/objects/coordinator.md +14 -3
- data/templates/writer/objects/editor.md +1 -1
- data/templates/writer/objects/researcher.md +2 -2
- data/tools/thread-explorer.html +28 -1
- metadata +175 -65
- data/CLAUDE.md +0 -176
- data/Gemfile +0 -10
- data/Gemfile.lock +0 -233
- data/IMPLEMENTATION_PLAN.md +0 -1073
- data/Rakefile +0 -27
- data/design-doc-v2.md +0 -1232
- data/frontend/.gitignore +0 -3
- data/frontend/index.html +0 -17
- data/frontend/package-lock.json +0 -4540
- data/frontend/package.json +0 -36
- data/frontend/postcss.config.js +0 -6
- data/frontend/src/App.tsx +0 -103
- data/frontend/src/canvas/CanvasView.tsx +0 -113
- data/frontend/src/canvas/ForceLayout.ts +0 -115
- data/frontend/src/canvas/SceneManager.ts +0 -587
- data/frontend/src/canvas/canvasStore.ts +0 -47
- data/frontend/src/canvas/constants.ts +0 -95
- data/frontend/src/canvas/controls/CameraControls.ts +0 -98
- data/frontend/src/canvas/edges/MessageArc.ts +0 -149
- data/frontend/src/canvas/inspector/InspectorPanel.tsx +0 -31
- data/frontend/src/canvas/inspector/POInspector.tsx +0 -262
- data/frontend/src/canvas/inspector/ToolCallInspector.tsx +0 -67
- data/frontend/src/canvas/nodes/PONode.ts +0 -249
- data/frontend/src/canvas/nodes/ToolCallNode.ts +0 -116
- data/frontend/src/canvas/types.ts +0 -24
- data/frontend/src/components/ContextMenu.tsx +0 -68
- data/frontend/src/components/Inspector.tsx +0 -232
- data/frontend/src/components/MarkdownMessage.tsx +0 -155
- data/frontend/src/components/MethodList.tsx +0 -90
- data/frontend/src/components/ModelSelector.tsx +0 -115
- data/frontend/src/components/NotificationPanel.tsx +0 -130
- data/frontend/src/components/ObjectList.tsx +0 -78
- data/frontend/src/components/PaneSlot.tsx +0 -30
- data/frontend/src/components/SourcePane.tsx +0 -202
- data/frontend/src/components/SystemBar.tsx +0 -74
- data/frontend/src/components/Transcript.tsx +0 -76
- data/frontend/src/components/UsagePanel.tsx +0 -105
- data/frontend/src/components/Workspace.tsx +0 -260
- data/frontend/src/components/index.ts +0 -12
- data/frontend/src/hooks/useResize.ts +0 -55
- data/frontend/src/hooks/useWebSocket.ts +0 -517
- data/frontend/src/index.css +0 -103
- data/frontend/src/main.tsx +0 -10
- data/frontend/src/store/index.ts +0 -279
- data/frontend/src/types/index.ts +0 -165
- data/frontend/tailwind.config.js +0 -44
- data/frontend/tsconfig.json +0 -30
- data/frontend/vite.config.ts +0 -29
- data/lib/prompt_objects/server/public/assets/index-D1myxE0l.js +0 -4345
- data/lib/prompt_objects/server/public/assets/index-DdCcwC-Z.css +0 -1
- data/lib/prompt_objects/universal/add_primitive.rb +0 -118
- data/lib/prompt_objects/universal/ask_human.rb +0 -109
- data/lib/prompt_objects/universal/create_primitive.rb +0 -174
- data/lib/prompt_objects/universal/list_primitives.rb +0 -145
- data/lib/prompt_objects/universal/think.rb +0 -41
- data/prompt_objects.gemspec +0 -50
- data/templates/basic/.gitignore +0 -2
- data/templates/developer/.gitignore +0 -5
- data/templates/empty/.gitignore +0 -5
- data/templates/empty/objects/.gitkeep +0 -0
- data/templates/minimal/.gitignore +0 -5
- data/templates/writer/.gitignore +0 -5
|
@@ -18,15 +18,30 @@ module PromptObjects
|
|
|
18
18
|
message: {
|
|
19
19
|
type: "string",
|
|
20
20
|
description: "The message to send"
|
|
21
|
+
},
|
|
22
|
+
thread_id: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "Optional runtime thread ID"
|
|
25
|
+
},
|
|
26
|
+
workspace_session_id: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Optional workspace session ID"
|
|
29
|
+
},
|
|
30
|
+
client_request_id: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "Optional idempotency key"
|
|
33
|
+
},
|
|
34
|
+
deadline: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Optional ISO 8601 deadline for queued and running work"
|
|
21
37
|
}
|
|
22
38
|
},
|
|
23
39
|
required: %w[po_name message]
|
|
24
40
|
)
|
|
25
41
|
|
|
26
|
-
def self.call(po_name:, message:,
|
|
42
|
+
def self.call(po_name:, message:, thread_id: nil, workspace_session_id: nil,
|
|
43
|
+
client_request_id: nil, deadline: nil, server_context:)
|
|
27
44
|
env = server_context[:env]
|
|
28
|
-
context = server_context[:context]
|
|
29
|
-
|
|
30
45
|
po = env.registry.get(po_name)
|
|
31
46
|
unless po.is_a?(PromptObjects::PromptObject)
|
|
32
47
|
return ::MCP::Tool::Response.new([{
|
|
@@ -35,35 +50,30 @@ module PromptObjects
|
|
|
35
50
|
}])
|
|
36
51
|
end
|
|
37
52
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
::MCP::Tool::Response.new([{
|
|
63
|
-
type: "text",
|
|
64
|
-
text: JSON.generate({ error: e.message, backtrace: e.backtrace.first(5) })
|
|
65
|
-
}])
|
|
66
|
-
end
|
|
53
|
+
run, response = env.execute_message_run(
|
|
54
|
+
target_po: po_name,
|
|
55
|
+
content: message,
|
|
56
|
+
from_source: "service:mcp",
|
|
57
|
+
workspace_session_id: workspace_session_id,
|
|
58
|
+
thread_id: thread_id,
|
|
59
|
+
client_request_id: client_request_id,
|
|
60
|
+
deadline: deadline,
|
|
61
|
+
tui_mode: true
|
|
62
|
+
)
|
|
63
|
+
history_length = Repositories::MessageRepository.new(env.session_store)
|
|
64
|
+
.list(thread_id: run.thread_id, limit: 10_000).length
|
|
65
|
+
::MCP::Tool::Response.new([{
|
|
66
|
+
type: "text",
|
|
67
|
+
text: JSON.generate({
|
|
68
|
+
po_name: po_name,
|
|
69
|
+
response: response,
|
|
70
|
+
workspace_session_id: run.workspace_session_id,
|
|
71
|
+
thread_id: run.thread_id,
|
|
72
|
+
run_id: run.id,
|
|
73
|
+
status: run.status,
|
|
74
|
+
history_length: history_length
|
|
75
|
+
})
|
|
76
|
+
}])
|
|
67
77
|
end
|
|
68
78
|
end
|
|
69
79
|
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Operations
|
|
5
|
+
# Content-free operational snapshot for health checks and support bundles.
|
|
6
|
+
class Diagnostics
|
|
7
|
+
TABLES = %w[
|
|
8
|
+
workspace_sessions sessions runs messages run_events workspace_events
|
|
9
|
+
tool_executions artifacts env_data
|
|
10
|
+
].freeze
|
|
11
|
+
|
|
12
|
+
def initialize(store)
|
|
13
|
+
@store = store
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def snapshot(scheduler: {}, limits: {})
|
|
17
|
+
data = @store.with_connection do |db|
|
|
18
|
+
runs = db.execute(<<~SQL)
|
|
19
|
+
SELECT status, provider, model, enqueued_at, started_at, finished_at, usage
|
|
20
|
+
FROM runs
|
|
21
|
+
SQL
|
|
22
|
+
tools = db.execute("SELECT status, started_at, finished_at FROM tool_executions")
|
|
23
|
+
{
|
|
24
|
+
schema_version: db.get_first_value("PRAGMA user_version").to_i,
|
|
25
|
+
database: database_stats(db),
|
|
26
|
+
counts: TABLES.to_h { |table| [table.to_sym, db.get_first_value("SELECT COUNT(*) FROM #{table}").to_i] },
|
|
27
|
+
runs: run_stats(runs),
|
|
28
|
+
tools: tool_stats(tools)
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
data.merge(
|
|
32
|
+
generated_at: Time.now.utc.iso8601,
|
|
33
|
+
scheduler: scheduler,
|
|
34
|
+
limits: limits
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def database_stats(db)
|
|
41
|
+
path = db.execute("PRAGMA database_list").find { |row| row["name"] == "main" }&.dig("file")
|
|
42
|
+
files = [path, "#{path}-wal", "#{path}-shm"].compact
|
|
43
|
+
{
|
|
44
|
+
filename: path && File.basename(path),
|
|
45
|
+
bytes: files.sum { |file| File.file?(file) ? File.size(file) : 0 },
|
|
46
|
+
journal_mode: db.get_first_value("PRAGMA journal_mode"),
|
|
47
|
+
integrity: db.get_first_value("PRAGMA quick_check")
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def run_stats(rows)
|
|
52
|
+
status_counts = rows.group_by { |row| row["status"] }.transform_values(&:length)
|
|
53
|
+
terminal = rows.count { |row| %w[completed failed cancelled skipped interrupted].include?(row["status"]) }
|
|
54
|
+
failures = rows.count { |row| %w[failed interrupted].include?(row["status"]) }
|
|
55
|
+
{
|
|
56
|
+
by_status: status_counts,
|
|
57
|
+
active: rows.count { |row| %w[queued running waiting].include?(row["status"]) },
|
|
58
|
+
failure_rate: terminal.zero? ? 0.0 : (failures.to_f / terminal).round(4),
|
|
59
|
+
queue_wait_ms: duration_stats(rows, "enqueued_at", "started_at"),
|
|
60
|
+
duration_ms: duration_stats(rows, "started_at", "finished_at"),
|
|
61
|
+
provider_usage: provider_usage(rows)
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def tool_stats(rows)
|
|
66
|
+
{
|
|
67
|
+
by_status: rows.group_by { |row| row["status"] }.transform_values(&:length),
|
|
68
|
+
duration_ms: duration_stats(rows, "started_at", "finished_at")
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def duration_stats(rows, start_key, finish_key)
|
|
73
|
+
values = rows.filter_map do |row|
|
|
74
|
+
next unless row[start_key] && row[finish_key]
|
|
75
|
+
|
|
76
|
+
((Time.parse(row[finish_key]) - Time.parse(row[start_key])) * 1000).round(2)
|
|
77
|
+
end.sort
|
|
78
|
+
return { count: 0, average: 0.0, p95: 0.0, maximum: 0.0 } if values.empty?
|
|
79
|
+
|
|
80
|
+
{
|
|
81
|
+
count: values.length,
|
|
82
|
+
average: (values.sum / values.length.to_f).round(2),
|
|
83
|
+
p95: values[[(values.length * 0.95).ceil - 1, 0].max],
|
|
84
|
+
maximum: values.last
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def provider_usage(rows)
|
|
89
|
+
rows.group_by { |row| [row["provider"] || "unknown", row["model"] || "unknown"] }
|
|
90
|
+
.to_h do |(provider, model), provider_rows|
|
|
91
|
+
usage = provider_rows.filter_map { |row| parse_json(row["usage"]) }
|
|
92
|
+
[[provider, model].join("/"), {
|
|
93
|
+
runs: provider_rows.length,
|
|
94
|
+
input_tokens: usage.sum { |value| token_value(value, :input_tokens, :prompt_tokens) },
|
|
95
|
+
output_tokens: usage.sum { |value| token_value(value, :output_tokens, :completion_tokens) }
|
|
96
|
+
}]
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def parse_json(value)
|
|
101
|
+
value && JSON.parse(value, symbolize_names: true)
|
|
102
|
+
rescue JSON::ParserError
|
|
103
|
+
nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def token_value(usage, *keys)
|
|
107
|
+
keys.each do |key|
|
|
108
|
+
value = usage[key]
|
|
109
|
+
return value.to_i if value
|
|
110
|
+
end
|
|
111
|
+
0
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Operations
|
|
5
|
+
# Bounds replay logs while preserving current snapshots and durable domain
|
|
6
|
+
# rows. Pruned clients recover from workspace/thread snapshots.
|
|
7
|
+
class Retention
|
|
8
|
+
DEFAULT_RUN_EVENT_LIMIT = 500
|
|
9
|
+
DEFAULT_WORKSPACE_EVENT_LIMIT = 5_000
|
|
10
|
+
|
|
11
|
+
def initialize(store)
|
|
12
|
+
@store = store
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def prune_events!(run_event_limit: DEFAULT_RUN_EVENT_LIMIT,
|
|
16
|
+
workspace_event_limit: DEFAULT_WORKSPACE_EVENT_LIMIT)
|
|
17
|
+
raise ArgumentError, "run_event_limit must be positive" unless run_event_limit.positive?
|
|
18
|
+
raise ArgumentError, "workspace_event_limit must be positive" unless workspace_event_limit.positive?
|
|
19
|
+
|
|
20
|
+
@store.transaction do |db|
|
|
21
|
+
run_event_ids = db.execute(<<~SQL, [run_event_limit]).map { |row| row["id"] }
|
|
22
|
+
SELECT id FROM (
|
|
23
|
+
SELECT id, ROW_NUMBER() OVER (PARTITION BY run_id ORDER BY sequence DESC) AS position
|
|
24
|
+
FROM run_events
|
|
25
|
+
) WHERE position > ?
|
|
26
|
+
SQL
|
|
27
|
+
workspace_cursors = run_event_ids.empty? ? [] : db.execute(
|
|
28
|
+
"SELECT workspace_cursor FROM run_events WHERE id IN (#{placeholders(run_event_ids)})",
|
|
29
|
+
run_event_ids
|
|
30
|
+
).map { |row| row["workspace_cursor"] }
|
|
31
|
+
delete_ids(db, "run_events", run_event_ids)
|
|
32
|
+
delete_ids(db, "workspace_events", workspace_cursors)
|
|
33
|
+
|
|
34
|
+
workspace_event_ids = db.execute(<<~SQL, [workspace_event_limit]).map { |row| row["id"] }
|
|
35
|
+
SELECT id FROM (
|
|
36
|
+
SELECT id, ROW_NUMBER() OVER (
|
|
37
|
+
PARTITION BY workspace_session_id ORDER BY id DESC
|
|
38
|
+
) AS position
|
|
39
|
+
FROM workspace_events
|
|
40
|
+
) WHERE position > ?
|
|
41
|
+
SQL
|
|
42
|
+
workspace_event_ids.reject! do |id|
|
|
43
|
+
db.get_first_value("SELECT 1 FROM run_events WHERE workspace_cursor = ?", [id])
|
|
44
|
+
end
|
|
45
|
+
delete_ids(db, "workspace_events", workspace_event_ids)
|
|
46
|
+
|
|
47
|
+
{
|
|
48
|
+
run_events_deleted: run_event_ids.length,
|
|
49
|
+
workspace_events_deleted: (workspace_cursors + workspace_event_ids).uniq.length
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def compact!
|
|
55
|
+
@store.with_connection do |db|
|
|
56
|
+
db.execute("PRAGMA wal_checkpoint(TRUNCATE)")
|
|
57
|
+
db.execute("VACUUM")
|
|
58
|
+
end
|
|
59
|
+
true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def delete_ids(db, table, ids)
|
|
65
|
+
return if ids.empty?
|
|
66
|
+
|
|
67
|
+
db.execute("DELETE FROM #{table} WHERE id IN (#{placeholders(ids)})", ids)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def placeholders(values)
|
|
71
|
+
Array.new(values.length, "?").join(", ")
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Operations
|
|
5
|
+
# Projects the durable runtime records for one execution tree into a
|
|
6
|
+
# debugger-friendly read model. The projection deliberately labels model
|
|
7
|
+
# context as reconstructed until exact provider exchanges are persisted.
|
|
8
|
+
class RunTraceBuilder
|
|
9
|
+
CATEGORY_BY_KIND = {
|
|
10
|
+
"model_started" => "model",
|
|
11
|
+
"model_completed" => "model",
|
|
12
|
+
"tool_batch_started" => "tool_batch",
|
|
13
|
+
"tool_started" => "tool",
|
|
14
|
+
"tool_completed" => "tool",
|
|
15
|
+
"tool_failed" => "tool",
|
|
16
|
+
"tool_cancelled" => "tool",
|
|
17
|
+
"delegation_started" => "delegation",
|
|
18
|
+
"delegation_completed" => "delegation",
|
|
19
|
+
"artifact_upserted" => "state",
|
|
20
|
+
"env_data_changed" => "state"
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
23
|
+
def initialize(store)
|
|
24
|
+
@runs = Repositories::RunRepository.new(store)
|
|
25
|
+
@definitions = Repositories::DefinitionRepository.new(store)
|
|
26
|
+
@messages = Repositories::MessageRepository.new(store)
|
|
27
|
+
@events = Repositories::EventRepository.new(store)
|
|
28
|
+
@tools = Repositories::ToolExecutionRepository.new(store)
|
|
29
|
+
@artifacts = Repositories::ArtifactRepository.new(store)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def build(run_id)
|
|
33
|
+
requested = @runs.get(run_id)
|
|
34
|
+
raise ArgumentError, "unknown run: #{run_id}" unless requested
|
|
35
|
+
|
|
36
|
+
root_run_id = requested.root_run_id || requested.id
|
|
37
|
+
related_runs = @runs.tree(root_run_id: root_run_id)
|
|
38
|
+
workspace_artifacts = @artifacts.list(workspace_session_id: requested.workspace_session_id)
|
|
39
|
+
|
|
40
|
+
{
|
|
41
|
+
requested_run_id: requested.id,
|
|
42
|
+
root_run_id: root_run_id,
|
|
43
|
+
workspace_session_id: requested.workspace_session_id,
|
|
44
|
+
completeness: {
|
|
45
|
+
run_records: "exact",
|
|
46
|
+
definitions: "exact_when_available",
|
|
47
|
+
messages: "exact",
|
|
48
|
+
tools: "exact",
|
|
49
|
+
model_context: "reconstructed",
|
|
50
|
+
state_history: "current_revision_only"
|
|
51
|
+
},
|
|
52
|
+
runs: related_runs.map { |run| build_run(run, related_runs, workspace_artifacts) }
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def build_run(run, related_runs, workspace_artifacts)
|
|
59
|
+
events = @events.run_events(run_id: run.id)
|
|
60
|
+
tools = @tools.list(run_id: run.id)
|
|
61
|
+
definition = @definitions.get(run.id)
|
|
62
|
+
context_messages = @messages.list(
|
|
63
|
+
thread_id: run.thread_id,
|
|
64
|
+
through_turn: run.turn_ordinal,
|
|
65
|
+
limit: 10_000
|
|
66
|
+
)
|
|
67
|
+
run_messages = context_messages.select { |message| message[:run_id] == run.id }
|
|
68
|
+
produced_artifacts = workspace_artifacts.select { |artifact| artifact.producing_run_id == run.id }
|
|
69
|
+
|
|
70
|
+
{
|
|
71
|
+
run: run.to_h,
|
|
72
|
+
definition: definition&.to_h,
|
|
73
|
+
completeness: {
|
|
74
|
+
definition: definition ? "exact" : "unavailable",
|
|
75
|
+
model_context: "reconstructed",
|
|
76
|
+
state_history: produced_artifacts.empty? ? "unavailable" : "current_revision_only"
|
|
77
|
+
},
|
|
78
|
+
context_messages: context_messages,
|
|
79
|
+
messages: run_messages,
|
|
80
|
+
tool_executions: tools.map(&:to_h),
|
|
81
|
+
artifacts: produced_artifacts.map(&:to_h),
|
|
82
|
+
nodes: events.map do |event|
|
|
83
|
+
build_node(event, tools, related_runs, produced_artifacts)
|
|
84
|
+
end
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def build_node(event, tools, related_runs, artifacts)
|
|
89
|
+
tool = tool_for(event, tools)
|
|
90
|
+
child = child_for(event, related_runs)
|
|
91
|
+
artifact = artifact_for(event, artifacts)
|
|
92
|
+
{
|
|
93
|
+
id: "#{event.run_id}:#{event.sequence}",
|
|
94
|
+
run_id: event.run_id,
|
|
95
|
+
sequence: event.sequence,
|
|
96
|
+
workspace_cursor: event.workspace_cursor,
|
|
97
|
+
kind: event.kind,
|
|
98
|
+
category: category_for(event.kind),
|
|
99
|
+
title: title_for(event, tool, child, artifact),
|
|
100
|
+
status: status_for(event.kind),
|
|
101
|
+
timestamp: event.timestamp,
|
|
102
|
+
data: event.data,
|
|
103
|
+
tool_execution: tool&.to_h,
|
|
104
|
+
child_run: child&.to_h,
|
|
105
|
+
artifact: artifact&.to_h
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def tool_for(event, tools)
|
|
110
|
+
execution_id = event.data[:tool_execution_id] || event.data["tool_execution_id"]
|
|
111
|
+
tools.find { |tool| tool.id == execution_id }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def child_for(event, related_runs)
|
|
115
|
+
child_run_id = event.data[:child_run_id] || event.data["child_run_id"]
|
|
116
|
+
related_runs.find { |run| run.id == child_run_id }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def artifact_for(event, artifacts)
|
|
120
|
+
artifact_id = event.data[:artifact_id] || event.data["artifact_id"]
|
|
121
|
+
artifacts.find { |artifact| artifact.id == artifact_id }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def category_for(kind)
|
|
125
|
+
CATEGORY_BY_KIND.fetch(kind, "lifecycle")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def status_for(kind)
|
|
129
|
+
return "failed" if kind.end_with?("_failed")
|
|
130
|
+
return "cancelled" if kind.end_with?("_cancelled") || kind.end_with?("_interrupted")
|
|
131
|
+
return "completed" if kind.end_with?("_completed") || kind == "artifact_upserted"
|
|
132
|
+
return "active" if kind.end_with?("_started") || kind.end_with?("_waiting")
|
|
133
|
+
|
|
134
|
+
"info"
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def title_for(event, tool, child, artifact)
|
|
138
|
+
case event.kind
|
|
139
|
+
when "tool_started", "tool_completed", "tool_failed", "tool_cancelled"
|
|
140
|
+
[event.kind.tr("_", " "), tool&.capability_name || event.data[:name]].compact.join(" · ")
|
|
141
|
+
when "delegation_started", "delegation_completed"
|
|
142
|
+
target = child&.po_name || event.data[:target_po] || event.data["target_po"]
|
|
143
|
+
[event.kind.tr("_", " "), target].compact.join(" · ")
|
|
144
|
+
when "artifact_upserted"
|
|
145
|
+
["artifact upserted", artifact&.title || event.data[:title] || event.data["title"]].compact.join(" · ")
|
|
146
|
+
else
|
|
147
|
+
event.kind.tr("_", " ")
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Primitives
|
|
5
|
+
# Optional standard-library capability for visible reasoning notes.
|
|
6
|
+
# Prompt Objects must declare this tool explicitly when its trace is useful.
|
|
7
|
+
class Think < Primitive
|
|
8
|
+
execution_policy parallel_safe: true, side_effect: :read
|
|
9
|
+
|
|
10
|
+
def name
|
|
11
|
+
"think"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def description
|
|
15
|
+
"Record a visible reasoning note before acting. Use only when an explicit thinking trace helps the human follow the work."
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def parameters
|
|
19
|
+
{
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
thought: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "Reasoning to show in the conversation"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
required: ["thought"]
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def receive(message, context:)
|
|
32
|
+
"Thought recorded."
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -4,6 +4,15 @@ module PromptObjects
|
|
|
4
4
|
module Primitives
|
|
5
5
|
# Primitive capability to write content to a file.
|
|
6
6
|
class WriteFile < Primitive
|
|
7
|
+
execution_policy(
|
|
8
|
+
parallel_safe: true,
|
|
9
|
+
side_effect: :write,
|
|
10
|
+
resource_keys: ->(arguments, _context, _capability) {
|
|
11
|
+
path = arguments[:path] || arguments["path"]
|
|
12
|
+
path ? ["file:#{File.expand_path(path)}"] : []
|
|
13
|
+
}
|
|
14
|
+
)
|
|
15
|
+
|
|
7
16
|
def name
|
|
8
17
|
"write_file"
|
|
9
18
|
end
|