little_ghost 0.7.0 → 0.8.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 +33 -5
- data/docs/guides/code_mode.md +2 -2
- data/docs/guides/getting_started.md +26 -1
- 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/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/assembly.rb +11 -3
- data/lib/little_ghost/assembly_builder.rb +2 -2
- data/lib/little_ghost/cli.rb +138 -0
- data/lib/little_ghost/console.rb +17 -0
- data/lib/little_ghost/errors.rb +1 -1
- 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.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/mcp/client.rb +295 -606
- data/lib/little_ghost/mcp/toolset.rb +133 -95
- data/lib/little_ghost/mcp.rb +21 -3
- 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/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/sandbox/environment_policy.rb +29 -4
- data/lib/little_ghost/sandbox/policy.rb +28 -6
- data/lib/little_ghost/sandboxes/unrestricted.rb +7 -3
- data/lib/little_ghost/skills/catalog.rb +13 -3
- data/lib/little_ghost/tool.rb +6 -1
- data/lib/little_ghost/version.rb +1 -1
- data/lib/little_ghost.rb +1 -0
- metadata +37 -7
- data/lib/little_ghost/mcp/types.rb +0 -216
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LittleGhost
|
|
4
|
-
module MCP
|
|
5
|
-
module ImmutableValue # :nodoc:
|
|
6
|
-
module_function
|
|
7
|
-
|
|
8
|
-
def mapping(value, field:)
|
|
9
|
-
raise ProtocolError, "MCP #{field} must be an object" unless value.is_a?(Hash)
|
|
10
|
-
|
|
11
|
-
freeze_value(DataMap.new(value))
|
|
12
|
-
rescue ArgumentError => error
|
|
13
|
-
raise ProtocolError, "MCP #{field} is invalid: #{error.message}"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def optional_mapping(value, field:)
|
|
17
|
-
return if value.nil?
|
|
18
|
-
|
|
19
|
-
mapping(value, field:)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def array(value, field:)
|
|
23
|
-
raise ProtocolError, "MCP #{field} must be an array" unless value.is_a?(Array)
|
|
24
|
-
|
|
25
|
-
freeze_value(DataMap.new("items" => value).fetch("items"))
|
|
26
|
-
rescue ArgumentError => error
|
|
27
|
-
raise ProtocolError, "MCP #{field} is invalid: #{error.message}"
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def freeze_value(value)
|
|
31
|
-
pending = [value]
|
|
32
|
-
until pending.empty?
|
|
33
|
-
current = pending.pop
|
|
34
|
-
case current
|
|
35
|
-
when Hash
|
|
36
|
-
current.each do |key, child|
|
|
37
|
-
key.freeze
|
|
38
|
-
pending << child
|
|
39
|
-
end
|
|
40
|
-
when Array
|
|
41
|
-
current.each { |child| pending << child }
|
|
42
|
-
end
|
|
43
|
-
current.freeze
|
|
44
|
-
end
|
|
45
|
-
value
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
Definition = Data.define( # :nodoc:
|
|
50
|
-
:source_name,
|
|
51
|
-
:name,
|
|
52
|
-
:description,
|
|
53
|
-
:input_schema,
|
|
54
|
-
:output_schema,
|
|
55
|
-
:annotations,
|
|
56
|
-
:title,
|
|
57
|
-
:metadata,
|
|
58
|
-
:raw
|
|
59
|
-
) do
|
|
60
|
-
def initialize(source_name:, name:, description:, input_schema:, raw:, output_schema: nil,
|
|
61
|
-
annotations: {}, title: nil, metadata: {})
|
|
62
|
-
source_name = String(source_name)
|
|
63
|
-
name = String(name)
|
|
64
|
-
raise ProtocolError, "MCP tool definition must include a name" if source_name.empty?
|
|
65
|
-
raise ConfigurationError, "MCP tool name cannot be empty" if name.empty?
|
|
66
|
-
|
|
67
|
-
super(
|
|
68
|
-
source_name: source_name.freeze,
|
|
69
|
-
name: name.freeze,
|
|
70
|
-
description: String(description).freeze,
|
|
71
|
-
input_schema: ImmutableValue.mapping(input_schema, field: "tool inputSchema"),
|
|
72
|
-
output_schema: ImmutableValue.optional_mapping(output_schema, field: "tool outputSchema"),
|
|
73
|
-
annotations: ImmutableValue.mapping(annotations, field: "tool annotations"),
|
|
74
|
-
title: title.nil? ? nil : String(title).freeze,
|
|
75
|
-
metadata: ImmutableValue.mapping(metadata, field: "tool _meta"),
|
|
76
|
-
raw: ImmutableValue.mapping(raw, field: "tool definition")
|
|
77
|
-
)
|
|
78
|
-
rescue TypeError
|
|
79
|
-
raise ProtocolError, "MCP tool definition is invalid"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def [](key) = raw[key]
|
|
83
|
-
def fetch(...) = raw.fetch(...)
|
|
84
|
-
def dig(...) = raw.dig(...)
|
|
85
|
-
def key?(key) = raw.key?(key)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Immutable server-advertised Tool metadata. +source_name+ is always the
|
|
89
|
-
# name sent back to the server; +name+ is the initially generated
|
|
90
|
-
# model-facing name and may later be customized on the generated Tool class.
|
|
91
|
-
class Definition < Data # :doc:
|
|
92
|
-
##
|
|
93
|
-
# :attr_reader: source_name
|
|
94
|
-
# The unmodified server-advertised name used for dispatch.
|
|
95
|
-
|
|
96
|
-
##
|
|
97
|
-
# :attr_reader: name
|
|
98
|
-
# The normalized, optionally prefixed initial model-facing name.
|
|
99
|
-
|
|
100
|
-
##
|
|
101
|
-
# :attr_reader: description
|
|
102
|
-
# The model-facing description, including LittleGhost's fallback when the
|
|
103
|
-
# server omitted one.
|
|
104
|
-
|
|
105
|
-
##
|
|
106
|
-
# :attr_reader: input_schema
|
|
107
|
-
# The deeply frozen MCP input schema.
|
|
108
|
-
|
|
109
|
-
##
|
|
110
|
-
# :attr_reader: output_schema
|
|
111
|
-
# The optional deeply frozen MCP output schema.
|
|
112
|
-
|
|
113
|
-
##
|
|
114
|
-
# :attr_reader: annotations
|
|
115
|
-
# Deeply frozen MCP tool annotations.
|
|
116
|
-
|
|
117
|
-
##
|
|
118
|
-
# :attr_reader: title
|
|
119
|
-
# The optional human-readable MCP title.
|
|
120
|
-
|
|
121
|
-
##
|
|
122
|
-
# :attr_reader: metadata
|
|
123
|
-
# Deeply frozen MCP <tt>_meta</tt> object.
|
|
124
|
-
|
|
125
|
-
##
|
|
126
|
-
# :attr_reader: raw
|
|
127
|
-
# A deeply frozen, indifferent-access copy of the complete server
|
|
128
|
-
# definition object.
|
|
129
|
-
# Definition also delegates +[]+, +fetch+, +dig+, and +key?+ to this map.
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
Call = Data.define(:definition, :arguments, :context, :binding) do # :nodoc:
|
|
133
|
-
def initialize(definition:, arguments:, context: nil, binding: Tool::Binding.new)
|
|
134
|
-
raise ArgumentError, "definition must be a LittleGhost::MCP::Definition" unless definition.is_a?(Definition)
|
|
135
|
-
|
|
136
|
-
super(
|
|
137
|
-
definition:,
|
|
138
|
-
arguments: ImmutableValue.mapping(arguments, field: "tool call arguments"),
|
|
139
|
-
context:,
|
|
140
|
-
binding:
|
|
141
|
-
)
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# Describes one MCP Tool invocation. It combines the server's Definition,
|
|
146
|
-
# the copied arguments, and the Tool::Binding used to execute the generated
|
|
147
|
-
# Tool.
|
|
148
|
-
class Call < Data # :doc:
|
|
149
|
-
##
|
|
150
|
-
# :attr_reader: definition
|
|
151
|
-
# The Definition whose +source_name+ is sent to the server.
|
|
152
|
-
|
|
153
|
-
##
|
|
154
|
-
# :attr_reader: arguments
|
|
155
|
-
# Deeply frozen, indifferent-access arguments.
|
|
156
|
-
|
|
157
|
-
##
|
|
158
|
-
# :attr_reader: context
|
|
159
|
-
# The RunContext controlling cancellation, deadlines, and working state.
|
|
160
|
-
|
|
161
|
-
##
|
|
162
|
-
# :attr_reader: binding
|
|
163
|
-
# The Tool::Binding for the generated Tool instance.
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
Result = Data.define(:content, :structured_content, :error, :metadata, :raw) do # :nodoc:
|
|
167
|
-
def initialize(content:, raw:, structured_content: nil, error: false, metadata: {})
|
|
168
|
-
unless error.nil? || error == true || error == false
|
|
169
|
-
raise ProtocolError, "MCP tool result isError must be boolean"
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
super(
|
|
173
|
-
content: ImmutableValue.array(content, field: "tool result content"),
|
|
174
|
-
structured_content: ImmutableValue.optional_mapping(
|
|
175
|
-
structured_content,
|
|
176
|
-
field: "structuredContent"
|
|
177
|
-
),
|
|
178
|
-
error: !!error,
|
|
179
|
-
metadata: ImmutableValue.mapping(metadata, field: "tool result _meta"),
|
|
180
|
-
raw: ImmutableValue.mapping(raw, field: "tool result")
|
|
181
|
-
)
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def error? = error
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
# Represents one MCP Tool result without discarding server fields. Mapping
|
|
188
|
-
# callbacks can inspect normalized content, structured content, metadata, or
|
|
189
|
-
# the complete protocol value.
|
|
190
|
-
class Result < Data # :doc:
|
|
191
|
-
##
|
|
192
|
-
# :attr_reader: content
|
|
193
|
-
# Deeply frozen MCP content blocks.
|
|
194
|
-
|
|
195
|
-
##
|
|
196
|
-
# :attr_reader: structured_content
|
|
197
|
-
# The optional deeply frozen structured result object.
|
|
198
|
-
|
|
199
|
-
##
|
|
200
|
-
# :attr_reader: error
|
|
201
|
-
# Whether the server marked the result with <tt>isError</tt>.
|
|
202
|
-
|
|
203
|
-
##
|
|
204
|
-
# :attr_reader: metadata
|
|
205
|
-
# Deeply frozen MCP result <tt>_meta</tt>.
|
|
206
|
-
|
|
207
|
-
##
|
|
208
|
-
# :attr_reader: raw
|
|
209
|
-
# A deeply frozen copy of the complete server result object.
|
|
210
|
-
|
|
211
|
-
##
|
|
212
|
-
# :method: error?
|
|
213
|
-
# Whether the server marked the result as an error.
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
end
|