envoy_ai 0.0.1
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 +7 -0
- data/MIT-LICENSE +22 -0
- data/README.md +399 -0
- data/app/assets/stylesheets/envoy/console.css +371 -0
- data/app/controllers/envoy/application_controller.rb +18 -0
- data/app/controllers/envoy/conversations_controller.rb +36 -0
- data/app/controllers/envoy/messages_controller.rb +14 -0
- data/app/controllers/envoy/system_prompts_controller.rb +52 -0
- data/app/javascript/envoy/controllers/autoscroll_controller.js +46 -0
- data/app/javascript/envoy/controllers/composer_controller.js +30 -0
- data/app/jobs/envoy/application_job.rb +4 -0
- data/app/jobs/envoy/run_job.rb +65 -0
- data/app/models/envoy/application_record.rb +5 -0
- data/app/models/envoy/conversation.rb +20 -0
- data/app/models/envoy/message.rb +8 -0
- data/app/models/envoy/system_prompt.rb +24 -0
- data/app/models/envoy/system_prompt_version.rb +14 -0
- data/app/models/envoy/tool_call.rb +28 -0
- data/app/views/envoy/conversations/_composer_input.html.erb +4 -0
- data/app/views/envoy/conversations/index.html.erb +15 -0
- data/app/views/envoy/conversations/new.html.erb +19 -0
- data/app/views/envoy/conversations/show.html.erb +18 -0
- data/app/views/envoy/messages/_message.html.erb +7 -0
- data/app/views/envoy/messages/_streaming.html.erb +6 -0
- data/app/views/envoy/messages/_tool_call.html.erb +8 -0
- data/app/views/envoy/messages/create.turbo_stream.erb +25 -0
- data/app/views/envoy/system_prompts/_form.html.erb +14 -0
- data/app/views/envoy/system_prompts/edit.html.erb +2 -0
- data/app/views/envoy/system_prompts/index.html.erb +14 -0
- data/app/views/envoy/system_prompts/new.html.erb +2 -0
- data/app/views/envoy/system_prompts/show.html.erb +15 -0
- data/app/views/layouts/envoy/application.html.erb +20 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20260710000001_create_envoy_conversations.rb +14 -0
- data/db/migrate/20260710000002_create_envoy_messages.rb +14 -0
- data/db/migrate/20260710000003_create_envoy_tool_calls.rb +14 -0
- data/db/migrate/20260711000001_create_envoy_system_prompts.rb +10 -0
- data/db/migrate/20260711000002_create_envoy_system_prompt_versions.rb +13 -0
- data/db/migrate/20260711000003_add_system_prompt_version_to_envoy_conversations.rb +6 -0
- data/lib/envoy/badges.rb +22 -0
- data/lib/envoy/compiled_tool.rb +43 -0
- data/lib/envoy/configuration.rb +21 -0
- data/lib/envoy/engine.rb +19 -0
- data/lib/envoy/errors.rb +6 -0
- data/lib/envoy/guard.rb +28 -0
- data/lib/envoy/llm.rb +24 -0
- data/lib/envoy/markdown.rb +16 -0
- data/lib/envoy/runner.rb +44 -0
- data/lib/envoy/testing/fake_llm.rb +41 -0
- data/lib/envoy/tool_definition.rb +38 -0
- data/lib/envoy/toolset.rb +72 -0
- data/lib/envoy/version.rb +3 -0
- data/lib/envoy.rb +45 -0
- data/lib/envoy_ai.rb +3 -0
- metadata +138 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Envoy
|
|
2
|
+
class ToolDefinition
|
|
3
|
+
attr_reader :name, :params, :perform_block
|
|
4
|
+
attr_accessor :tool_class
|
|
5
|
+
|
|
6
|
+
def initialize(name)
|
|
7
|
+
@name = name.to_s
|
|
8
|
+
@description = ""
|
|
9
|
+
@access = :read
|
|
10
|
+
@params = []
|
|
11
|
+
@perform_block = ->(**) { }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# --- DSL ---
|
|
15
|
+
def description(text = nil)
|
|
16
|
+
return @description if text.nil?
|
|
17
|
+
@description = text
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def access(level = nil)
|
|
21
|
+
return @access if level.nil?
|
|
22
|
+
raise Envoy::Error, "access must be :read or :write" unless %i[read write].include?(level)
|
|
23
|
+
@access = level
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def param(name, desc, type: :string, required: true)
|
|
27
|
+
@params << { name: name.to_sym, desc: desc, type: type, required: required }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def perform(&block)
|
|
31
|
+
@perform_block = block
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# --- introspection ---
|
|
35
|
+
def read? = @access == :read
|
|
36
|
+
def write? = @access == :write
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module Envoy
|
|
2
|
+
class Toolset
|
|
3
|
+
attr_reader :key, :tools
|
|
4
|
+
|
|
5
|
+
def initialize(key)
|
|
6
|
+
@key = key.to_s
|
|
7
|
+
@description = ""
|
|
8
|
+
@tools = {}
|
|
9
|
+
@composed_keys = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Reader returns this toolset's own description followed by each composed
|
|
13
|
+
# toolset's (so the model understands every tool group); setter records it.
|
|
14
|
+
def description(text = nil)
|
|
15
|
+
return @description = text unless text.nil?
|
|
16
|
+
collect_descriptions.compact_blank.join("\n\n")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def tool(name, &block)
|
|
20
|
+
definition = ToolDefinition.new(name)
|
|
21
|
+
definition.instance_eval(&block)
|
|
22
|
+
@tools[definition.name] = definition
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Compose other toolsets into this one. Keys are resolved lazily (at
|
|
26
|
+
# tools_for / description time via Envoy.toolset), so the load order of
|
|
27
|
+
# toolset definitions does not matter.
|
|
28
|
+
def use(*keys)
|
|
29
|
+
@composed_keys.concat(keys.map(&:to_s))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# This toolset's own tools plus every composed toolset's, de-duplicated by
|
|
33
|
+
# name (own tools win, then composed in `use` order). read_only strips write
|
|
34
|
+
# tools across the merged set (governance lever for embeds).
|
|
35
|
+
def tools_for(read_only: false)
|
|
36
|
+
list = collect_tools.values
|
|
37
|
+
read_only ? list.select(&:read?) : list
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
protected
|
|
41
|
+
|
|
42
|
+
# seen threads the ancestry so a toolset that composes itself (directly or
|
|
43
|
+
# transitively) raises instead of looping forever.
|
|
44
|
+
def collect_tools(seen = [])
|
|
45
|
+
guard_cycle!(seen)
|
|
46
|
+
merged = {}
|
|
47
|
+
@tools.each { |name, definition| merged[name] = definition } # own first, own wins
|
|
48
|
+
@composed_keys.each do |composed_key|
|
|
49
|
+
Envoy.toolset(composed_key).collect_tools(seen + [ key ]).each do |name, definition|
|
|
50
|
+
merged[name] ||= definition # earlier composed wins over later
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
merged
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def collect_descriptions(seen = [])
|
|
57
|
+
guard_cycle!(seen)
|
|
58
|
+
descriptions = [ @description ]
|
|
59
|
+
@composed_keys.each do |composed_key|
|
|
60
|
+
descriptions.concat(Envoy.toolset(composed_key).collect_descriptions(seen + [ key ]))
|
|
61
|
+
end
|
|
62
|
+
descriptions
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def guard_cycle!(seen)
|
|
68
|
+
return unless seen.include?(key)
|
|
69
|
+
raise Envoy::ToolsetCycle, "toolset composition cycle: #{(seen + [ key ]).join(' -> ')}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/envoy.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require "ruby_llm"
|
|
2
|
+
require "commonmarker"
|
|
3
|
+
require "envoy/version"
|
|
4
|
+
require "envoy/configuration"
|
|
5
|
+
require "envoy/markdown"
|
|
6
|
+
require "envoy/badges"
|
|
7
|
+
require "envoy/engine"
|
|
8
|
+
require "envoy/errors"
|
|
9
|
+
require "envoy/tool_definition"
|
|
10
|
+
require "envoy/toolset"
|
|
11
|
+
require "envoy/guard"
|
|
12
|
+
require "envoy/compiled_tool"
|
|
13
|
+
require "envoy/llm"
|
|
14
|
+
require "envoy/runner"
|
|
15
|
+
|
|
16
|
+
module Envoy
|
|
17
|
+
class << self
|
|
18
|
+
def config
|
|
19
|
+
@config ||= Configuration.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def configure
|
|
23
|
+
yield config
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Build an LLM runner for a turn.
|
|
27
|
+
def llm(**opts)
|
|
28
|
+
config.llm.call(**opts)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def toolsets
|
|
32
|
+
@toolsets ||= {}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def define_toolset(key, &block)
|
|
36
|
+
toolset = Toolset.new(key)
|
|
37
|
+
toolset.instance_eval(&block)
|
|
38
|
+
toolsets[toolset.key] = toolset
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def toolset(key)
|
|
42
|
+
toolsets.fetch(key.to_s) { raise UnknownToolset, "no toolset #{key.inspect}" }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/envoy_ai.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: envoy_ai
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Travis Petticrew
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '8.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '8.1'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: ruby_llm
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.16'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.16'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: commonmarker
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '2.6'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.6'
|
|
54
|
+
description: 'Envoy is a mountable Rails engine for governed, tool-calling agent chat:
|
|
55
|
+
a DSL for host-owned toolsets, guard hooks for authorizing every tool call, persisted
|
|
56
|
+
conversations, and a debug console.'
|
|
57
|
+
email:
|
|
58
|
+
- travis@launchsupply.com
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- MIT-LICENSE
|
|
64
|
+
- README.md
|
|
65
|
+
- app/assets/stylesheets/envoy/console.css
|
|
66
|
+
- app/controllers/envoy/application_controller.rb
|
|
67
|
+
- app/controllers/envoy/conversations_controller.rb
|
|
68
|
+
- app/controllers/envoy/messages_controller.rb
|
|
69
|
+
- app/controllers/envoy/system_prompts_controller.rb
|
|
70
|
+
- app/javascript/envoy/controllers/autoscroll_controller.js
|
|
71
|
+
- app/javascript/envoy/controllers/composer_controller.js
|
|
72
|
+
- app/jobs/envoy/application_job.rb
|
|
73
|
+
- app/jobs/envoy/run_job.rb
|
|
74
|
+
- app/models/envoy/application_record.rb
|
|
75
|
+
- app/models/envoy/conversation.rb
|
|
76
|
+
- app/models/envoy/message.rb
|
|
77
|
+
- app/models/envoy/system_prompt.rb
|
|
78
|
+
- app/models/envoy/system_prompt_version.rb
|
|
79
|
+
- app/models/envoy/tool_call.rb
|
|
80
|
+
- app/views/envoy/conversations/_composer_input.html.erb
|
|
81
|
+
- app/views/envoy/conversations/index.html.erb
|
|
82
|
+
- app/views/envoy/conversations/new.html.erb
|
|
83
|
+
- app/views/envoy/conversations/show.html.erb
|
|
84
|
+
- app/views/envoy/messages/_message.html.erb
|
|
85
|
+
- app/views/envoy/messages/_streaming.html.erb
|
|
86
|
+
- app/views/envoy/messages/_tool_call.html.erb
|
|
87
|
+
- app/views/envoy/messages/create.turbo_stream.erb
|
|
88
|
+
- app/views/envoy/system_prompts/_form.html.erb
|
|
89
|
+
- app/views/envoy/system_prompts/edit.html.erb
|
|
90
|
+
- app/views/envoy/system_prompts/index.html.erb
|
|
91
|
+
- app/views/envoy/system_prompts/new.html.erb
|
|
92
|
+
- app/views/envoy/system_prompts/show.html.erb
|
|
93
|
+
- app/views/layouts/envoy/application.html.erb
|
|
94
|
+
- config/routes.rb
|
|
95
|
+
- db/migrate/20260710000001_create_envoy_conversations.rb
|
|
96
|
+
- db/migrate/20260710000002_create_envoy_messages.rb
|
|
97
|
+
- db/migrate/20260710000003_create_envoy_tool_calls.rb
|
|
98
|
+
- db/migrate/20260711000001_create_envoy_system_prompts.rb
|
|
99
|
+
- db/migrate/20260711000002_create_envoy_system_prompt_versions.rb
|
|
100
|
+
- db/migrate/20260711000003_add_system_prompt_version_to_envoy_conversations.rb
|
|
101
|
+
- lib/envoy.rb
|
|
102
|
+
- lib/envoy/badges.rb
|
|
103
|
+
- lib/envoy/compiled_tool.rb
|
|
104
|
+
- lib/envoy/configuration.rb
|
|
105
|
+
- lib/envoy/engine.rb
|
|
106
|
+
- lib/envoy/errors.rb
|
|
107
|
+
- lib/envoy/guard.rb
|
|
108
|
+
- lib/envoy/llm.rb
|
|
109
|
+
- lib/envoy/markdown.rb
|
|
110
|
+
- lib/envoy/runner.rb
|
|
111
|
+
- lib/envoy/testing/fake_llm.rb
|
|
112
|
+
- lib/envoy/tool_definition.rb
|
|
113
|
+
- lib/envoy/toolset.rb
|
|
114
|
+
- lib/envoy/version.rb
|
|
115
|
+
- lib/envoy_ai.rb
|
|
116
|
+
homepage: https://www.launchsupply.com/
|
|
117
|
+
licenses:
|
|
118
|
+
- MIT
|
|
119
|
+
metadata:
|
|
120
|
+
homepage_uri: https://www.launchsupply.com/
|
|
121
|
+
rdoc_options: []
|
|
122
|
+
require_paths:
|
|
123
|
+
- lib
|
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
|
+
requirements:
|
|
126
|
+
- - ">="
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: '3.2'
|
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
|
+
requirements:
|
|
131
|
+
- - ">="
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: '0'
|
|
134
|
+
requirements: []
|
|
135
|
+
rubygems_version: 4.0.6
|
|
136
|
+
specification_version: 4
|
|
137
|
+
summary: Governed, tool-calling agent chat as a mountable Rails engine.
|
|
138
|
+
test_files: []
|