little_ghost 0.7.0 → 0.9.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/README.md +34 -6
- data/docs/guides/assemblies.md +21 -9
- data/docs/guides/code_mode.md +2 -2
- data/docs/guides/getting_started.md +27 -2
- data/docs/guides/integrations.md +20 -161
- data/docs/guides/mcp.md +288 -0
- data/docs/guides/models_and_providers.md +21 -54
- data/docs/guides/production.md +14 -5
- data/docs/guides/prompt_views.md +234 -27
- data/docs/guides/providers.md +275 -0
- data/docs/guides/sandboxing.md +42 -7
- data/docs/guides/skills.md +1 -3
- data/docs/guides/tools.md +2 -0
- data/exe/little_ghost +12 -0
- data/lib/little_ghost/agent/context_management.rb +2 -13
- data/lib/little_ghost/agent/delegation.rb +7 -4
- data/lib/little_ghost/agent/skills.rb +8 -6
- data/lib/little_ghost/agent/tool_loop.rb +4 -4
- data/lib/little_ghost/agent.rb +230 -70
- data/lib/little_ghost/agent_builder.rb +16 -4
- data/lib/little_ghost/artifacts/workspace_store.rb +16 -14
- data/lib/little_ghost/assembly.rb +48 -7
- data/lib/little_ghost/assembly_builder.rb +3 -3
- data/lib/little_ghost/cli.rb +429 -0
- data/lib/little_ghost/code_mode/broker.rb +11 -3
- data/lib/little_ghost/code_mode/javascript/client.rb +58 -11
- data/lib/little_ghost/code_mode/javascript/host.rb +37 -13
- data/lib/little_ghost/code_mode/javascript/session.rb +21 -9
- data/lib/little_ghost/code_mode/javascript_engine.rb +21 -42
- data/lib/little_ghost/code_mode/ruby/host.rb +8 -4
- data/lib/little_ghost/code_mode/ruby/session.rb +41 -14
- data/lib/little_ghost/code_mode/ruby_engine.rb +6 -36
- data/lib/little_ghost/code_mode/runtime.rb +57 -24
- data/lib/little_ghost/console.rb +17 -0
- data/lib/little_ghost/errors.rb +20 -2
- data/lib/little_ghost/framework_prompts.rb +376 -0
- data/lib/little_ghost/generators/application_generator.rb +179 -0
- data/lib/little_ghost/generators/templates/application/Gemfile.tt +3 -0
- data/lib/little_ghost/generators/templates/application/README.md.tt +29 -0
- data/lib/little_ghost/generators/templates/application/app/agents/application_agent.rb.tt +5 -0
- data/lib/little_ghost/generators/templates/application/app/prompts/application/system_prompt.erb.tt +1 -0
- data/lib/little_ghost/generators/templates/application/bin/application.tt +10 -0
- data/lib/little_ghost/generators/templates/application/config/little_ghost.rb.tt +5 -0
- data/lib/little_ghost/generators/templates/application/gitignore.tt +2 -0
- data/lib/little_ghost/generators/templates/application/keep.tt +0 -0
- data/lib/little_ghost/graph.rb +24 -5
- data/lib/little_ghost/mcp/client.rb +307 -610
- data/lib/little_ghost/mcp/toolset.rb +133 -95
- data/lib/little_ghost/mcp.rb +21 -3
- data/lib/little_ghost/model_operations.rb +103 -36
- data/lib/little_ghost/model_resolver.rb +2 -0
- data/lib/little_ghost/models/catalog/models_dev_source.rb +4 -1
- data/lib/little_ghost/prompt_resolver.rb +61 -27
- data/lib/little_ghost/prompts/little_ghost/agent/interjections/instructions.erb +12 -0
- data/lib/little_ghost/prompts/little_ghost/agent/system/default.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/batch/feedback/batch_too_large.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/batch/feedback/batch_too_many.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/batch/feedback/item_too_large.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/errors/preparation_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/errors/resolver_invalid.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/errors/value_unstorable.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/format/reference.erb +13 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/format/references.erb +12 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/format/workspace_references.erb +12 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/notices/full_result.erb +14 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/presentation/notices/storage_failed.erb +13 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/destination_unsafe.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/secure_unavailable.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/workspace_changed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/workspace_unavailable.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/errors/workspace_unsafe.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/feedback/count_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/feedback/destination_exists.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/feedback/too_large.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/artifacts/storage/feedback/total_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/assembly/feedback/transition_only.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/assembly/tools/fallback/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/artifacts/format/references.erb +12 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/errors/brokered_close.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/errors/cleanup_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/errors/execution_failed.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/arguments_object.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/closed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/control_active.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/limit_exceeded.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/not_active.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/program_active.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/program_timed_out.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/unavailable_tool.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/feedback/unknown_program.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/active_programs_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/cleanup_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/execution_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/invalid_request.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/memory_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/pending_calls_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/source_size_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/errors/tools_array.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/javascript/instructions.erb +35 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/ruby/feedback/parallel_callables.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/ruby/instructions.erb +40 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/tools/exec/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/tools/stop/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/tools/stop/inputs/max_output_tokens/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/tools/wait/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/code_mode/tools/wait/inputs/max_output_tokens/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/context_management/summary/request.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/context_management/summary/system_instruction.erb +16 -0
- data/lib/little_ghost/prompts/little_ghost/graph/context/format/failed_input.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/graph/context/format/previous_input.erb +13 -0
- data/lib/little_ghost/prompts/little_ghost/graph/context/headings/original_task.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/graph/context/headings/previous_inputs.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/mcp/errors/request_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/mcp/errors/transformation_unserializable.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/mcp/tools/fallback/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/output/truncation/marker.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/errors/mount_changed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/errors/secure_traversal_unavailable.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/errors/workspace_root_changed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/directory_listing_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/entry_required.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/file_read_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/invalid_utf8.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/mount_escape.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/mount_missing.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/multiply_linked.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/not_directory.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/not_file.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/null_byte.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/outside_scope.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/parent_escape.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/path_missing.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/path_traverses_symlink.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/read_only.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/replace_empty.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/symlink_path.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/text_multiple.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/text_not_found.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/write_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/write_parent_missing.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/filesystem/feedback/write_target_symlink.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/policy/feedback/feature_denied.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/process/errors/program_supervisor_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/command_timed_out.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/executable_required.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/program_memory_exceeded.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/program_output_exceeded.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/sandbox/process/feedback/program_timed_out.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/skills/discovery/instructions.erb +18 -0
- data/lib/little_ghost/prompts/little_ghost/skills/feedback/unknown.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/skills/resources/notices/truncated.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/skills/tools/activate/content.erb +28 -0
- data/lib/little_ghost/prompts/little_ghost/skills/tools/activate/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/skills/tools/activate/inputs/name/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/persistence/format/redaction.erb +12 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/repair/feedback/invalid_result.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/repair/feedback/schema_errors.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/repair/request.erb +14 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/tools/result/description.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/invalid_json.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/missing_tool.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/multiple_tools.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/too_complex.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/too_deep.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/too_large.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/structured_output/validation/feedback/tool_not_exclusive.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/errors/create_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/errors/previous_turn_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/errors/restore_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/errors/turn_failed.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/duplicate_ids.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/duplicate_path.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/identity_capacity.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/inactive.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/interjection_chars_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/interjection_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/interjection_unsupported.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/invalid_cursor.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/invalid_mode.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/list_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/message_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/message_type.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/not_running.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/queue_capacity.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/task_name_invalid.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/task_name_limit.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/terminal_identity.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/turn_capacity.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/unknown_id.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/feedback/unknown_kind.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/notices/turn_cancelled.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/interject/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/interject/inputs/active_id/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/interject/inputs/message/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/list/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/send/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/send/inputs/id/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/send/inputs/message/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/send/inputs/send_mode/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/inputs/kind/description.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/inputs/spawn_mode/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/inputs/task/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/spawn/inputs/task_name/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/wait/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/subagents/tools/wait/inputs/ids/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/swarm/handoff/notice.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/swarm/handoff/request.erb +16 -0
- data/lib/little_ghost/prompts/little_ghost/swarm/tools/handoff/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/built_in/list_files/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/built_in/read_file/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/built_in/replace_in_file/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/built_in/shell/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/built_in/write_file/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/built_in/write_todos/description.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/built_in/write_todos/feedback/single_progress.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/built_in/write_todos/feedback/unique_ids.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/errors/unexpected_failure.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/errors/unserializable_result.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/feedback/invalid_input.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/feedback/unknown.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/loop/notices/final_warning.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/loop/notices/termination.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/loop/notices/warning.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/additional_property.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/enum.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/invalid_format.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/invalid_pattern.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/max_items.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/max_length.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/maximum.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/min_items.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/min_length.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/minimum.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/required.erb +10 -0
- data/lib/little_ghost/prompts/little_ghost/tools/validation/schema/type.erb +11 -0
- data/lib/little_ghost/prompts/little_ghost/workspace/feedback/path_changed.erb +10 -0
- data/lib/little_ghost/provider_registry.rb +1 -0
- data/lib/little_ghost/providers/lm_studio/catalog_source.rb +201 -0
- data/lib/little_ghost/providers/lm_studio.rb +52 -0
- data/lib/little_ghost/providers/openai.rb +3 -75
- data/lib/little_ghost/providers/openai_compatible.rb +78 -1
- data/lib/little_ghost/runtime/hooks/artifacts.rb +58 -22
- data/lib/little_ghost/runtime.rb +8 -3
- data/lib/little_ghost/sandbox/environment_policy.rb +29 -4
- data/lib/little_ghost/sandbox/filesystem.rb +51 -33
- data/lib/little_ghost/sandbox/policy.rb +28 -6
- data/lib/little_ghost/sandbox/process_runner.rb +6 -2
- data/lib/little_ghost/sandbox/process_session.rb +8 -4
- data/lib/little_ghost/sandbox/scope.rb +4 -1
- data/lib/little_ghost/sandboxes/seatbelt.rb +3 -1
- data/lib/little_ghost/sandboxes/unrestricted.rb +17 -9
- data/lib/little_ghost/skills/catalog.rb +41 -36
- data/lib/little_ghost/structured_output.rb +6 -6
- data/lib/little_ghost/subagents/control_tool.rb +58 -0
- data/lib/little_ghost/subagents/manager.rb +99 -74
- data/lib/little_ghost/support/output_truncation.rb +28 -4
- data/lib/little_ghost/swarm.rb +20 -7
- data/lib/little_ghost/tool.rb +47 -20
- data/lib/little_ghost/tool_registry.rb +2 -2
- data/lib/little_ghost/tools/filesystem.rb +12 -4
- data/lib/little_ghost/tools/shell.rb +5 -1
- data/lib/little_ghost/tools/write_todos.rb +9 -9
- data/lib/little_ghost/version.rb +1 -1
- data/lib/little_ghost/workflow.rb +199 -27
- data/lib/little_ghost/workspace.rb +2 -2
- data/lib/little_ghost.rb +6 -2
- metadata +222 -7
- data/lib/little_ghost/mcp/types.rb +0 -216
data/docs/guides/prompt_views.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Prompts as Views
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Keep growing Agent instructions readable by moving them into a **prompt view**:
|
|
4
|
+
an ERB file that LittleGhost finds and renders for the Agent. The Agent prepares
|
|
5
|
+
any application values the prompt needs, while the view holds the instructions
|
|
6
|
+
sent to the model.
|
|
6
7
|
|
|
7
8
|
## Start with the inline prompt
|
|
8
9
|
|
|
@@ -28,7 +29,7 @@ class CustomerSupportAgent < LittleGhost::Agent
|
|
|
28
29
|
end
|
|
29
30
|
```
|
|
30
31
|
|
|
31
|
-
Then create `app/prompts/customer_support/
|
|
32
|
+
Then create `app/prompts/customer_support/system_prompt.erb`:
|
|
32
33
|
|
|
33
34
|
```erb
|
|
34
35
|
You help customers understand their orders and account.
|
|
@@ -38,57 +39,115 @@ Never invent company guidance. Check the help center when policy matters.
|
|
|
38
39
|
Use the order status tool before making a claim about a private order.
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
That is enough. `CustomerSupportAgent`
|
|
42
|
+
That is enough. LittleGhost turns `CustomerSupportAgent` into the logical path
|
|
43
|
+
`customer_support` and looks for
|
|
44
|
+
`app/prompts/customer_support/system_prompt.erb`.
|
|
42
45
|
|
|
43
|
-
The prompt is still a system instruction sent to the selected model provider.
|
|
46
|
+
The prompt is still a system instruction sent to the selected model provider.
|
|
47
|
+
Keeping it in a view improves organization; it does not keep the content inside
|
|
48
|
+
your process.
|
|
44
49
|
|
|
45
|
-
##
|
|
50
|
+
## Prepare application values with Ruby
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
Define `system_prompt` as an instance method when the view needs values from
|
|
53
|
+
your application. Assign those values to instance variables:
|
|
48
54
|
|
|
49
55
|
```ruby
|
|
50
56
|
class CustomerSupportAgent < LittleGhost::Agent
|
|
51
|
-
|
|
57
|
+
def system_prompt
|
|
58
|
+
@company_name = "Northstar"
|
|
59
|
+
@policy_version = SupportPolicy.current_version
|
|
60
|
+
end
|
|
52
61
|
end
|
|
53
62
|
```
|
|
54
63
|
|
|
55
|
-
|
|
64
|
+
LittleGhost calls the method before it renders the view. The instance variables
|
|
65
|
+
are available there by the same names:
|
|
56
66
|
|
|
57
67
|
```erb
|
|
58
|
-
You are a customer support agent for <%= company_name %>.
|
|
68
|
+
You are a customer support agent for <%= @company_name %>.
|
|
69
|
+
Follow support policy <%= @policy_version %>.
|
|
59
70
|
Answer clearly and concisely.
|
|
60
71
|
```
|
|
61
72
|
|
|
62
|
-
|
|
73
|
+
If you know Rails controllers, the pairing is familiar: the method prepares
|
|
74
|
+
values, and the ERB file presents them. The method's return value is ignored. If
|
|
75
|
+
it raises an exception, the Run fails in the usual way.
|
|
76
|
+
|
|
77
|
+
An inline `system_prompt` declaration still takes precedence over a view. Remove
|
|
78
|
+
the inline declaration when you want LittleGhost to call the instance method and
|
|
79
|
+
render `system_prompt.erb`.
|
|
80
|
+
|
|
81
|
+
Subclass actions can call `super` before adding their own values:
|
|
63
82
|
|
|
64
83
|
```ruby
|
|
65
|
-
class
|
|
66
|
-
|
|
84
|
+
class BillingSupportAgent < CustomerSupportAgent
|
|
85
|
+
def system_prompt
|
|
86
|
+
super
|
|
87
|
+
@billing_region = "US"
|
|
88
|
+
end
|
|
67
89
|
end
|
|
68
90
|
```
|
|
69
91
|
|
|
70
|
-
Prompt views also receive
|
|
92
|
+
Prompt views also receive three built-in local variables: `invocation` for the
|
|
93
|
+
current request, `run` for its lifecycle, and `agent` for the run-scoped Agent.
|
|
94
|
+
Use them when an instruction genuinely depends on the current request. Keep the
|
|
95
|
+
customer's wording in the caller message unless it belongs in the system
|
|
96
|
+
instruction.
|
|
71
97
|
|
|
72
|
-
Every rendered value may be sent to the model provider.
|
|
98
|
+
Every rendered value may be sent to the model provider. Put only data that
|
|
99
|
+
belongs in the prompt into the view.
|
|
73
100
|
|
|
74
101
|
## Share a small partial
|
|
75
102
|
|
|
76
103
|
Partials keep repeated instructions in one place. Create `app/prompts/shared/_voice.erb`:
|
|
77
104
|
|
|
78
105
|
```erb
|
|
79
|
-
Use a warm, direct voice for <%= company_name %>.
|
|
106
|
+
Use a warm, direct voice for <%= @company_name %>.
|
|
80
107
|
Prefer one clear next step over a long list of possibilities.
|
|
81
108
|
```
|
|
82
109
|
|
|
83
110
|
Render it from the Agent's system view:
|
|
84
111
|
|
|
85
112
|
```erb
|
|
86
|
-
You are a customer support agent for <%= company_name %>.
|
|
113
|
+
You are a customer support agent for <%= @company_name %>.
|
|
114
|
+
|
|
115
|
+
<%= partial "shared/voice" %>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The underscore marks a partial. Partials share the Agent's instance variables,
|
|
119
|
+
so `@company_name` remains available without extra wiring.
|
|
120
|
+
|
|
121
|
+
Use an explicit local for a value that belongs only to one partial. For example,
|
|
122
|
+
create `app/prompts/shared/_closing.erb`:
|
|
123
|
+
|
|
124
|
+
```erb
|
|
125
|
+
Offer one clear next step for <%= audience %>.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Then pass `audience` when you render it:
|
|
87
129
|
|
|
88
|
-
|
|
130
|
+
```erb
|
|
131
|
+
<%= partial "shared/closing", locals: {audience: "account owners"} %>
|
|
89
132
|
```
|
|
90
133
|
|
|
91
|
-
|
|
134
|
+
Locals do not flow into nested partials unless you pass them again.
|
|
135
|
+
|
|
136
|
+
## Keep repeated renders predictable
|
|
137
|
+
|
|
138
|
+
LittleGhost calls `system_prompt` once for each file-backed prompt render. Each
|
|
139
|
+
call starts with the instance variables captured after LittleGhost's
|
|
140
|
+
`after_initialize` callbacks finish. Values left behind by a later callback,
|
|
141
|
+
Tool, or earlier render do not become prompt assigns by accident.
|
|
142
|
+
|
|
143
|
+
After preparing the view, LittleGhost restores the Agent's live instance
|
|
144
|
+
variables. The objects assigned to the view are still ordinary Ruby objects,
|
|
145
|
+
though, so the view sees the same mutable objects. Treat them as read-only, or
|
|
146
|
+
duplicate a value before assigning it when the template needs an isolated copy.
|
|
147
|
+
|
|
148
|
+
For state that should change across invocations, read from `run`, a session, or
|
|
149
|
+
an application object in `system_prompt` instead of relying on an earlier
|
|
150
|
+
prompt render.
|
|
92
151
|
|
|
93
152
|
## Choose a different template path
|
|
94
153
|
|
|
@@ -104,10 +163,154 @@ LittleGhost chooses one prompt source in this order:
|
|
|
104
163
|
|
|
105
164
|
1. An inline `system_prompt`
|
|
106
165
|
2. An explicit `system_template`
|
|
107
|
-
3. The Agent's conventional `
|
|
166
|
+
3. The Agent's conventional `system_prompt.erb` view
|
|
108
167
|
|
|
109
168
|
Applications can add prompt lookup roots through `Configuration#prompt_paths`.
|
|
110
|
-
Earlier roots win,
|
|
169
|
+
Earlier roots win, so an application can override a view from a shared prompt
|
|
170
|
+
package.
|
|
171
|
+
|
|
172
|
+
## Customize LittleGhost's framework prompts
|
|
173
|
+
|
|
174
|
+
You can change LittleGhost's own model-facing language without replacing its
|
|
175
|
+
Ruby behavior. Tool descriptions, structured-result repair requests, context
|
|
176
|
+
summaries, code-mode instructions, and other framework messages all come from
|
|
177
|
+
bundled prompt views under the `little_ghost/` namespace.
|
|
178
|
+
|
|
179
|
+
### Decide when to customize
|
|
180
|
+
|
|
181
|
+
Models can respond differently to the same instruction, even when the Tool,
|
|
182
|
+
schema, and task stay the same. Wording that works well with one model may lead
|
|
183
|
+
another model to miss a Tool constraint, mishandle a repair request, or recover
|
|
184
|
+
less reliably from a failed call. Adjusting the relevant framework prompt gives
|
|
185
|
+
you a direct way to improve that interaction without forking LittleGhost.
|
|
186
|
+
|
|
187
|
+
An override can also align framework language with your application's
|
|
188
|
+
terminology and voice. Start with the narrowest template that covers the
|
|
189
|
+
behavior you want to change, and evaluate it with the models your application
|
|
190
|
+
uses. Keep protocol checks, authorization, and execution limits in Ruby;
|
|
191
|
+
prompt wording guides the model but does not enforce those boundaries.
|
|
192
|
+
|
|
193
|
+
### Find the prompt you want to change
|
|
194
|
+
|
|
195
|
+
Browse the catalog from your application:
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
$ little_ghost prompts list
|
|
199
|
+
$ little_ghost prompts list structured_output
|
|
200
|
+
$ little_ghost prompts list structured_output/repair
|
|
201
|
+
$ little_ghost prompts show structured_output/repair/request
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The bare `list` command shows top-level features with template counts. Pass a
|
|
205
|
+
feature or component path to browse its immediate children, or use `list --all`
|
|
206
|
+
to print every template key. Keys follow `feature/component/purpose`. For
|
|
207
|
+
example, built-in Tool descriptions live under `tools/built_in`, while JSON
|
|
208
|
+
Schema feedback lives under `tools/validation/schema`. Directories named
|
|
209
|
+
`feedback` contain conditions the model can correct. Directories named `errors`
|
|
210
|
+
contain operational failures.
|
|
211
|
+
|
|
212
|
+
`show` prints the bundled ERB source. Every bundled template starts with a
|
|
213
|
+
structured ERB comment that explains where LittleGhost renders it, its locals,
|
|
214
|
+
and any formatting constraints. These headers use `<%# ... -%>`, so neither the
|
|
215
|
+
comment nor its trailing newline enters the rendered prompt. Each interior line
|
|
216
|
+
also starts with `#` so Ruby-aware editors recognize the whole header as a
|
|
217
|
+
comment. A `#` line outside `<%# ... -%>` and an HTML comment are output text and
|
|
218
|
+
would be sent to the model.
|
|
219
|
+
|
|
220
|
+
Bundled prompts use plain text and Markdown. When a prompt needs headings or
|
|
221
|
+
structured sections, the default template uses Markdown headings and lists
|
|
222
|
+
rather than XML-like wrapper tags.
|
|
223
|
+
|
|
224
|
+
### Copy an override into your application
|
|
225
|
+
|
|
226
|
+
Copy one template into the default application prompt root before editing it:
|
|
227
|
+
|
|
228
|
+
```sh
|
|
229
|
+
$ little_ghost prompts copy structured_output/repair/request
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
That creates
|
|
233
|
+
`app/prompts/little_ghost/structured_output/repair/request.erb`. Use `--root` when the
|
|
234
|
+
application configures a different prompt root:
|
|
235
|
+
|
|
236
|
+
```sh
|
|
237
|
+
$ little_ghost prompts copy structured_output/repair/request --root config/prompts
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Use `--agent` when one Agent needs different wording from the rest of the
|
|
241
|
+
application. Pass the Agent's logical path, which is its underscored class name
|
|
242
|
+
without the `Agent` suffix:
|
|
243
|
+
|
|
244
|
+
```sh
|
|
245
|
+
$ little_ghost prompts copy structured_output/repair/request --agent customer_support
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
That creates
|
|
249
|
+
`app/prompts/customer_support/little_ghost/structured_output/repair/request.erb`.
|
|
250
|
+
Namespaced classes use a namespaced logical path, such as
|
|
251
|
+
`Admin::CustomerSupportAgent` becoming `admin/customer_support`.
|
|
252
|
+
|
|
253
|
+
Copy the complete catalog when an application deliberately wants to own every
|
|
254
|
+
piece of framework wording:
|
|
255
|
+
|
|
256
|
+
```sh
|
|
257
|
+
$ little_ghost prompts copy --all
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Copy commands refuse to overwrite any existing destination. With `--all`, the
|
|
261
|
+
command checks every destination before it starts writing. Copied templates
|
|
262
|
+
retain their invisible documentation headers so the override remains
|
|
263
|
+
self-explanatory in the application.
|
|
264
|
+
|
|
265
|
+
### Choose the override scope
|
|
266
|
+
|
|
267
|
+
For every framework prompt that applies to an Agent invocation, LittleGhost
|
|
268
|
+
uses the first matching template in this order:
|
|
269
|
+
|
|
270
|
+
1. An invocation-specific `TrustedPath` root
|
|
271
|
+
2. The Agent-scoped directory inside a configured prompt root
|
|
272
|
+
3. The runtime-wide directory inside a configured prompt root
|
|
273
|
+
4. The template bundled with LittleGhost
|
|
274
|
+
|
|
275
|
+
Each root keeps the same `little_ghost/<key>.erb` namespace. Agent scope inserts
|
|
276
|
+
the logical path before that namespace.
|
|
277
|
+
|
|
278
|
+
Runtime-wide overrides normally live in the default `app/prompts` root. Add or
|
|
279
|
+
replace configured roots when the application uses another location:
|
|
280
|
+
|
|
281
|
+
```ruby
|
|
282
|
+
LittleGhost.configure do |config|
|
|
283
|
+
config.prompt_paths = ["config/prompts", "app/prompts"]
|
|
284
|
+
end
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
The uncommon invocation-specific layer is explicit because it can change model
|
|
288
|
+
instructions for only one call. From `config/little_ghost.rb`:
|
|
289
|
+
|
|
290
|
+
```ruby
|
|
291
|
+
campaign_prompts = LittleGhost::TrustedPath.new(
|
|
292
|
+
path: File.expand_path("campaign_prompts", __dir__)
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
CustomerSupportAgent.ask(
|
|
296
|
+
"Where is my order?",
|
|
297
|
+
template_paths: [campaign_prompts]
|
|
298
|
+
)
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The invocation root contains
|
|
302
|
+
`little_ghost/structured_output/repair/request.erb`, as a runtime root does.
|
|
303
|
+
Direct `LittleGhost.generate` calls accept the same `template_paths:` option.
|
|
304
|
+
|
|
305
|
+
### Know what an override can change
|
|
306
|
+
|
|
307
|
+
Framework templates control model-facing language, not protocol roles, Tool
|
|
308
|
+
names, schemas, validation behavior, security checks, or execution limits. A
|
|
309
|
+
required template cannot render as blank.
|
|
310
|
+
|
|
311
|
+
LittleGhost is pre-1.0. Template keys and their documented locals are maintained
|
|
312
|
+
on a best-effort basis until 1.0, so review release notes and copied overrides
|
|
313
|
+
when upgrading.
|
|
111
314
|
|
|
112
315
|
## Treat views as application code
|
|
113
316
|
|
|
@@ -115,13 +318,16 @@ Prompt views run as ERB inside the Ruby process and can call Ruby. Keep prompt
|
|
|
115
318
|
directories with the rest of your application code rather than letting a
|
|
116
319
|
request choose one.
|
|
117
320
|
|
|
118
|
-
`TrustedPath`
|
|
119
|
-
|
|
120
|
-
|
|
321
|
+
Use `TrustedPath` only when application code needs to select a request-specific
|
|
322
|
+
root. Do not derive its path from a request parameter, model output, or Tool
|
|
323
|
+
argument. The wrapper confirms that the directory exists and resolves symbolic
|
|
324
|
+
links. It does not inspect who can edit the directory or restrict what its ERB
|
|
325
|
+
can execute.
|
|
121
326
|
|
|
122
327
|
## Build request-specific input in a Workflow
|
|
123
328
|
|
|
124
|
-
A prompt view defines reusable instructions for one Agent. A Workflow may still
|
|
329
|
+
A prompt view defines reusable instructions for one Agent. A Workflow may still
|
|
330
|
+
build request-specific input for that Agent:
|
|
125
331
|
|
|
126
332
|
```ruby
|
|
127
333
|
invoke CustomerSupportAgent, input: <<~MESSAGE
|
|
@@ -132,7 +338,8 @@ invoke CustomerSupportAgent, input: <<~MESSAGE
|
|
|
132
338
|
MESSAGE
|
|
133
339
|
```
|
|
134
340
|
|
|
135
|
-
The Workflow is composing this request. `CustomerSupportAgent` still receives
|
|
341
|
+
The Workflow is composing this request. `CustomerSupportAgent` still receives
|
|
342
|
+
its own system prompt view when it runs.
|
|
136
343
|
|
|
137
344
|
Continue with [Tools](tools.md) to give those Agents application capabilities
|
|
138
345
|
while keeping model input, trusted context, and delegated sandbox operations
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Provider Support
|
|
2
|
+
|
|
3
|
+
Use this page to connect a hosted provider or local model server. If you are
|
|
4
|
+
still deciding how Agents should choose models, start with [Models and
|
|
5
|
+
Providers](models_and_providers.md).
|
|
6
|
+
|
|
7
|
+
## Compare provider support
|
|
8
|
+
|
|
9
|
+
Every connection uses the same configuration shape:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
LittleGhost.configure do |config|
|
|
13
|
+
config.providers = {
|
|
14
|
+
primary: {
|
|
15
|
+
adapter: :openrouter,
|
|
16
|
+
api_key: ENV.fetch("OPENROUTER_API_KEY")
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`primary` is a name chosen by the application, and `adapter` selects the wire
|
|
23
|
+
protocol. An Agent can now use a target such as
|
|
24
|
+
`primary:openai/gpt-5.6-luna`.
|
|
25
|
+
|
|
26
|
+
| Provider or endpoint | Adapter | Generation | Embeddings |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| OpenRouter | `:openrouter` | Chat Completions | When the model supports it |
|
|
29
|
+
| OpenAI | `:openai` | Responses or Chat Completions | Yes |
|
|
30
|
+
| Compatible API | `:openai_compatible` | Responses or Chat Completions | When the endpoint implements it |
|
|
31
|
+
| Ollama | `:openai_compatible` | Responses or Chat Completions | When the model supports it |
|
|
32
|
+
| Anthropic | `:anthropic` | Messages | No |
|
|
33
|
+
| Gemini | `:gemini` | Gemini API | No |
|
|
34
|
+
| Vertex AI | `:vertex_ai` | Gemini on Vertex AI | No |
|
|
35
|
+
| Bedrock | `:bedrock` | Converse | Titan Text Embeddings V2 |
|
|
36
|
+
| LM Studio | `:lm_studio` | Responses or Chat Completions | Yes |
|
|
37
|
+
|
|
38
|
+
Capabilities can vary by model, account, and server version. Handle provider
|
|
39
|
+
failures even when a model is expected to support a feature.
|
|
40
|
+
|
|
41
|
+
## Hosted providers
|
|
42
|
+
|
|
43
|
+
### OpenRouter
|
|
44
|
+
|
|
45
|
+
OpenRouter gives one connection access to models from several providers:
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
config.providers = {
|
|
49
|
+
openrouter: {
|
|
50
|
+
adapter: :openrouter,
|
|
51
|
+
api_key: ENV.fetch("OPENROUTER_API_KEY"),
|
|
52
|
+
app_name: "Support Console",
|
|
53
|
+
site_url: "https://support.example.com"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Use OpenRouter's `publisher/model` form, such as
|
|
59
|
+
`openrouter:anthropic/claude-sonnet-4`. `app_name` and `site_url` are optional.
|
|
60
|
+
The selected model must support embeddings before you call
|
|
61
|
+
`LittleGhost.embed`.
|
|
62
|
+
|
|
63
|
+
### OpenAI
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
config.providers = {
|
|
67
|
+
openai: {
|
|
68
|
+
adapter: :openai,
|
|
69
|
+
api_key: ENV.fetch("OPENAI_API_KEY")
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Generation uses the Responses API by default. Use `openai:gpt-5.6-luna` for
|
|
75
|
+
generation or `openai:text-embedding-3-small` for embeddings. Set
|
|
76
|
+
`api: :chat_completions` only when required.
|
|
77
|
+
|
|
78
|
+
### Anthropic
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
config.providers = {
|
|
82
|
+
anthropic: {
|
|
83
|
+
adapter: :anthropic,
|
|
84
|
+
api_key: ENV.fetch("ANTHROPIC_API_KEY")
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Use a target such as `anthropic:claude-sonnet-4-6`. The adapter uses the
|
|
90
|
+
Messages API. LittleGhost does not provide Anthropic embeddings.
|
|
91
|
+
|
|
92
|
+
### Gemini
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
config.providers = {
|
|
96
|
+
gemini: {
|
|
97
|
+
adapter: :gemini,
|
|
98
|
+
api_key: ENV.fetch("GEMINI_API_KEY")
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Use `gemini:gemini-2.5-flash`, for example. LittleGhost does not provide Gemini
|
|
104
|
+
embeddings.
|
|
105
|
+
|
|
106
|
+
### Vertex AI
|
|
107
|
+
|
|
108
|
+
Vertex AI uses Gemini's request format with a Google Cloud project and
|
|
109
|
+
location:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
config.providers = {
|
|
113
|
+
vertex: {
|
|
114
|
+
adapter: :vertex_ai,
|
|
115
|
+
project: ENV.fetch("GOOGLE_CLOUD_PROJECT"),
|
|
116
|
+
location: "global"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Use a target such as `vertex:gemini-2.5-flash`. The credential resolver can
|
|
122
|
+
obtain Google credentials, or startup can supply an access token. LittleGhost
|
|
123
|
+
does not provide Vertex AI embeddings.
|
|
124
|
+
|
|
125
|
+
### Amazon Bedrock
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
config.providers = {
|
|
129
|
+
bedrock: {
|
|
130
|
+
adapter: :bedrock,
|
|
131
|
+
region: ENV.fetch("AWS_REGION")
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Use a model available in the region, such as
|
|
137
|
+
`bedrock:us.anthropic.claude-sonnet-4-6-v1:0`. The adapter resolves AWS
|
|
138
|
+
credentials and signs requests without an AWS SDK.
|
|
139
|
+
|
|
140
|
+
Bedrock embeddings support `amazon.titan-embed-text-v2:0`. Its `dimensions`
|
|
141
|
+
setting accepts 256, 512, or 1024, and `normalize` defaults to `true`.
|
|
142
|
+
|
|
143
|
+
## Compatible APIs and local servers
|
|
144
|
+
|
|
145
|
+
### Another OpenAI-compatible API
|
|
146
|
+
|
|
147
|
+
Use `:openai_compatible` for a hosted service, gateway, or local server that
|
|
148
|
+
implements OpenAI-style endpoints:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
config.providers = {
|
|
152
|
+
models: {
|
|
153
|
+
adapter: :openai_compatible,
|
|
154
|
+
base_url: "https://models.example.com/v1/",
|
|
155
|
+
api_key: ENV.fetch("MODEL_API_KEY"),
|
|
156
|
+
api: :responses
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Use the model identifier expected by the endpoint, such as
|
|
162
|
+
`models:example-model`. Choose `api: :responses` or
|
|
163
|
+
`api: :chat_completions` to match the server. `LittleGhost.embed` uses the
|
|
164
|
+
connection's `embeddings` endpoint and supports `dimensions` when the server
|
|
165
|
+
and model accept it.
|
|
166
|
+
|
|
167
|
+
Tool calls, structured results, reasoning, attachments, and embeddings depend
|
|
168
|
+
on the compatible server and model.
|
|
169
|
+
|
|
170
|
+
Ollama and LM Studio normally listen on loopback HTTP. LittleGhost requires
|
|
171
|
+
`allow_insecure_http: true` as an explicit opt-in because HTTP does not protect
|
|
172
|
+
prompts, output, or credentials in transit. Use this setting only for a local
|
|
173
|
+
or otherwise trusted endpoint; use HTTPS for a remote server.
|
|
174
|
+
|
|
175
|
+
### Ollama
|
|
176
|
+
|
|
177
|
+
Pull a model, start Ollama, and use the existing OpenAI-compatible adapter:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
$ ollama pull qwen3
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
config.providers = {
|
|
185
|
+
ollama: {
|
|
186
|
+
adapter: :openai_compatible,
|
|
187
|
+
base_url: "http://localhost:11434/v1/",
|
|
188
|
+
api_key: "ollama",
|
|
189
|
+
api: :responses,
|
|
190
|
+
allow_insecure_http: true
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Use the pulled model name in the target, such as `ollama:qwen3`. The `api_key`
|
|
196
|
+
is a placeholder for a local server without authentication.
|
|
197
|
+
|
|
198
|
+
Ollama added its Responses endpoint in version 0.13.3. Set
|
|
199
|
+
`api: :chat_completions` for an earlier release or when the selected model does
|
|
200
|
+
not support the Responses features you need. See Ollama's [OpenAI compatibility
|
|
201
|
+
reference](https://docs.ollama.com/api/openai-compatibility) for release-specific
|
|
202
|
+
fields.
|
|
203
|
+
|
|
204
|
+
For embeddings, pull an embedding model and pass its target to
|
|
205
|
+
`LittleGhost.embed`. LittleGhost does not list, pull, or delete Ollama models.
|
|
206
|
+
|
|
207
|
+
### LM Studio
|
|
208
|
+
|
|
209
|
+
Start LM Studio's local server after downloading or loading the model you want
|
|
210
|
+
to use. The dedicated adapter supplies the usual local endpoint and a
|
|
211
|
+
placeholder credential:
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
config.providers = {
|
|
215
|
+
lm_studio: {
|
|
216
|
+
adapter: :lm_studio,
|
|
217
|
+
allow_insecure_http: true
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Use the model key shown by LM Studio, for example
|
|
223
|
+
`lm_studio:google/gemma-3-4b`. Generation uses the Responses API by default.
|
|
224
|
+
|
|
225
|
+
Set `api: :chat_completions` with LM Studio releases earlier than 0.3.29, or
|
|
226
|
+
when required by the selected model. `LittleGhost.embed` uses the same
|
|
227
|
+
connection with an embedding model. See LM Studio's [compatibility
|
|
228
|
+
reference](https://lmstudio.ai/docs/developer/openai-compat) for its current
|
|
229
|
+
generation and embedding endpoints.
|
|
230
|
+
|
|
231
|
+
When LM Studio authentication is enabled, add
|
|
232
|
+
`api_key: ENV.fetch("LM_STUDIO_API_TOKEN")` to the connection.
|
|
233
|
+
|
|
234
|
+
The native model list and API-token authentication require LM Studio 0.4.0 or
|
|
235
|
+
newer. LittleGhost reads the list; it does not load, unload, or download models.
|
|
236
|
+
|
|
237
|
+
## Discover current model details
|
|
238
|
+
|
|
239
|
+
Call `refresh!` when you need current availability, loaded state, or
|
|
240
|
+
capabilities. Ordinary model requests do not make discovery calls.
|
|
241
|
+
|
|
242
|
+
```ruby
|
|
243
|
+
resolver = LittleGhost.model_resolver
|
|
244
|
+
result = resolver.refresh!(target: "lm_studio:google/gemma-3-4b")
|
|
245
|
+
result[:errors]
|
|
246
|
+
|
|
247
|
+
details = resolver.details("lm_studio:google/gemma-3-4b")
|
|
248
|
+
details[:loaded]
|
|
249
|
+
details.context_window
|
|
250
|
+
details.input_modalities
|
|
251
|
+
details.supported_parameters
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Pass `target:` for one model, or omit it for every configured source. On
|
|
255
|
+
failure, `result[:errors]` describes the problem and previous details remain.
|
|
256
|
+
|
|
257
|
+
Hosted adapters can combine models.dev data with their provider's model API.
|
|
258
|
+
LM Studio reads its native model list. The generic compatible adapter and
|
|
259
|
+
Ollama do not have built-in model discovery.
|
|
260
|
+
|
|
261
|
+
LM Studio details can include downloaded and loaded state, active context
|
|
262
|
+
length, input types, tools, and reasoning. An unloaded model has no active
|
|
263
|
+
context length. See `LittleGhost::Models::Details` for every field.
|
|
264
|
+
|
|
265
|
+
## Keep connection settings in application code
|
|
266
|
+
|
|
267
|
+
Choose keys, tokens, headers, base URLs, model identifiers, and API variants at
|
|
268
|
+
startup. Read secrets from deployment configuration or a secret manager. Do
|
|
269
|
+
not copy public request parameters into provider settings.
|
|
270
|
+
|
|
271
|
+
The selected provider may receive prompts, conversation history, Tool results,
|
|
272
|
+
schemas, and attachments. Choose one appropriate for that data.
|
|
273
|
+
|
|
274
|
+
Continue with [Running in Production](production.md) to place connections,
|
|
275
|
+
roles, sessions, and observability into a long-running application.
|
data/docs/guides/sandboxing.md
CHANGED
|
@@ -23,10 +23,7 @@ LittleGhost.configure do |config|
|
|
|
23
23
|
|
|
24
24
|
config.sandbox = {
|
|
25
25
|
provider: :native,
|
|
26
|
-
files: {root: :read_write}
|
|
27
|
-
root_filesystem: :isolated,
|
|
28
|
-
environment: {inherit: false, set: {"LANG" => "C.UTF-8"}},
|
|
29
|
-
network: :none
|
|
26
|
+
files: {root: :read_write}
|
|
30
27
|
}
|
|
31
28
|
end
|
|
32
29
|
```
|
|
@@ -34,7 +31,9 @@ end
|
|
|
34
31
|
This example gives each Run a temporary writable root and removes it during
|
|
35
32
|
teardown. The `:native` Sandbox backend selects Seatbelt on macOS or Bubblewrap on
|
|
36
33
|
Linux. It raises instead of running without isolation when the native backend
|
|
37
|
-
is unavailable.
|
|
34
|
+
is unavailable. Unless you configure otherwise, it isolates the host root,
|
|
35
|
+
removes child-process network access, and starts child processes without
|
|
36
|
+
inheriting the host environment.
|
|
38
37
|
|
|
39
38
|
`LittleGhost::Tools::Filesystem` and `LittleGhost::Tools::Shell` use the Sandbox
|
|
40
39
|
assigned to the current Run. Code-mode interpreters also run inside their own
|
|
@@ -148,8 +147,7 @@ config.sandbox = {
|
|
|
148
147
|
},
|
|
149
148
|
runtime_paths: {
|
|
150
149
|
home: :read_write
|
|
151
|
-
}
|
|
152
|
-
network: :none
|
|
150
|
+
}
|
|
153
151
|
}
|
|
154
152
|
```
|
|
155
153
|
|
|
@@ -200,6 +198,39 @@ Workspace paths:
|
|
|
200
198
|
On Seatbelt, host-visible modes permit subprocesses because development tools
|
|
201
199
|
often need them. A Scope can remove `process_spawn` for a command that does not.
|
|
202
200
|
|
|
201
|
+
## Start child processes with only the values they need
|
|
202
|
+
|
|
203
|
+
When `environment` is omitted, sandboxed processes do not inherit the host
|
|
204
|
+
environment. LittleGhost starts with `LANG`, `LC_ALL`, and `PATH`, then adds
|
|
205
|
+
`LITTLE_GHOST_WORKSPACE_*` variables so the child can locate its Workspace.
|
|
206
|
+
Locale values come from the host when present and otherwise use `C.UTF-8`.
|
|
207
|
+
`PATH` keeps the host's absolute entries, removes empty, relative, and duplicate
|
|
208
|
+
entries, and falls back to `/usr/local/bin:/usr/bin:/bin` when nothing remains.
|
|
209
|
+
Credentials, provider keys, package-manager settings, and home-directory
|
|
210
|
+
variables are not copied into the child.
|
|
211
|
+
|
|
212
|
+
> **Safety note:** An absolute directory is not necessarily a trusted one. A
|
|
213
|
+
> host `PATH` may include project directories, temporary directories, or
|
|
214
|
+
> user-managed shims. Configure a fixed `PATH` when a model can invoke commands
|
|
215
|
+
> by name and you do not trust every host entry.
|
|
216
|
+
|
|
217
|
+
Declaring `environment` replaces the locale and path baseline instead of
|
|
218
|
+
merging with it. Use an empty Hash to omit all configurable values, or set
|
|
219
|
+
exactly what the process needs. Workspace routing variables remain available:
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
config.sandbox = {
|
|
223
|
+
provider: :native,
|
|
224
|
+
environment: {
|
|
225
|
+
inherit: false,
|
|
226
|
+
set: {"LANG" => "C.UTF-8", "PATH" => "/opt/my-tool/bin:/usr/bin"}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Host inheritance requires both `inherit: true` in the Sandbox policy and an
|
|
232
|
+
individual process call that opts into inheritance.
|
|
233
|
+
|
|
203
234
|
## Choose an enforcement backend
|
|
204
235
|
|
|
205
236
|
| Sandbox backend | Host | What it enforces |
|
|
@@ -260,6 +291,10 @@ Sandbox networking has three modes:
|
|
|
260
291
|
- `:allowlist` requires an enforcing gateway: a supervised proxy that permits
|
|
261
292
|
only configured destinations.
|
|
262
293
|
|
|
294
|
+
Seatbelt, Bubblewrap, and `:native` default to `:none`; declare a network mode
|
|
295
|
+
only when the child needs a different policy. The unrestricted backend uses
|
|
296
|
+
`:inherit` because it is not a security boundary.
|
|
297
|
+
|
|
263
298
|
Proxy environment variables alone are not an allowlist. An external gateway
|
|
264
299
|
uses named, process-only Workspace paths and verifies that they still point to
|
|
265
300
|
the configured directories; it does not create a virtual path mapping.
|