turnkit 0.2.8 → 0.2.10
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 +12 -5
- data/README.md +165 -26
- data/UPGRADE.md +35 -68
- data/lib/turnkit/adapters/codex.rb +160 -0
- data/lib/turnkit/agent.rb +70 -4
- data/lib/turnkit/budget.rb +23 -8
- data/lib/turnkit/compaction.rb +15 -4
- data/lib/turnkit/conversation.rb +4 -3
- data/lib/turnkit/error.rb +1 -0
- data/lib/turnkit/output_audit.rb +92 -0
- data/lib/turnkit/output_policy.rb +121 -0
- data/lib/turnkit/run.rb +2 -0
- data/lib/turnkit/tool_runner.rb +11 -4
- data/lib/turnkit/turn.rb +96 -12
- data/lib/turnkit/version.rb +1 -1
- data/lib/turnkit/{fleet.rb → workflow.rb} +40 -13
- data/lib/turnkit.rb +14 -5
- metadata +10 -6
data/lib/turnkit/turn.rb
CHANGED
|
@@ -6,7 +6,7 @@ module TurnKit
|
|
|
6
6
|
|
|
7
7
|
attr_reader :agent, :conversation, :store, :budget, :depth
|
|
8
8
|
attr_reader :id, :conversation_id, :agent_name, :parent_turn_id, :parent_tool_execution_id
|
|
9
|
-
attr_reader :root_turn_id, :context_message_sequence, :model, :thinking, :compact, :output_schema
|
|
9
|
+
attr_reader :root_turn_id, :context_message_sequence, :model, :thinking, :compact, :output_schema, :prompt_mode
|
|
10
10
|
attr_reader :started_at
|
|
11
11
|
|
|
12
12
|
def initialize(agent:, conversation:, record:, store:, budget: nil, depth: 0, on_event: nil)
|
|
@@ -25,6 +25,7 @@ module TurnKit
|
|
|
25
25
|
@thinking = thinking_from_options
|
|
26
26
|
@compact = compact_from_options
|
|
27
27
|
@output_schema = output_schema_from_options
|
|
28
|
+
@prompt_mode = prompt_mode_from_options
|
|
28
29
|
@started_at = @record["started_at"]
|
|
29
30
|
@budget = budget || agent.build_budget
|
|
30
31
|
@depth = depth
|
|
@@ -44,13 +45,13 @@ module TurnKit
|
|
|
44
45
|
TurnKit::Compaction.maybe_compact!(self)
|
|
45
46
|
|
|
46
47
|
request = model_request
|
|
47
|
-
|
|
48
|
+
emit_model_requested("model.requested", request)
|
|
48
49
|
result = call_client(request)
|
|
49
|
-
emit("model.completed", model: result.model || model, tool_call_count: result.tool_calls.length)
|
|
50
50
|
result_cost = Cost.from_usage(result.usage, model: result.model || model)
|
|
51
51
|
|
|
52
|
-
budget.add_cost!(result_cost.total)
|
|
53
52
|
add_usage!(result.usage, cost: result_cost)
|
|
53
|
+
emit_model_completed("model.completed", result, result_cost, model: model)
|
|
54
|
+
budget.add_cost!(result_cost.total)
|
|
54
55
|
persist_assistant_message(result)
|
|
55
56
|
|
|
56
57
|
if result.tool_calls?
|
|
@@ -61,8 +62,7 @@ module TurnKit
|
|
|
61
62
|
break
|
|
62
63
|
end
|
|
63
64
|
else
|
|
64
|
-
|
|
65
|
-
emit("turn.completed", status: status, output_text: result.text)
|
|
65
|
+
complete_with_output(result.text, output_data: result.output_data)
|
|
66
66
|
break
|
|
67
67
|
end
|
|
68
68
|
end
|
|
@@ -95,6 +95,10 @@ module TurnKit
|
|
|
95
95
|
@record["output_data"]
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
def output_audit
|
|
99
|
+
(@record["options"] || {})["output_audit"]
|
|
100
|
+
end
|
|
101
|
+
|
|
98
102
|
def usage
|
|
99
103
|
Usage.from_h(@record["usage"] || {})
|
|
100
104
|
end
|
|
@@ -112,6 +116,7 @@ module TurnKit
|
|
|
112
116
|
@thinking = thinking_from_options
|
|
113
117
|
@compact = compact_from_options
|
|
114
118
|
@output_schema = output_schema_from_options
|
|
119
|
+
@prompt_mode = prompt_mode_from_options
|
|
115
120
|
self
|
|
116
121
|
end
|
|
117
122
|
|
|
@@ -123,9 +128,31 @@ module TurnKit
|
|
|
123
128
|
emit_event(Event.new(type: type, turn_id: id, conversation_id: conversation.id, payload: payload))
|
|
124
129
|
end
|
|
125
130
|
|
|
131
|
+
def internal_model_call(model:, messages:, instructions:, tools: [], thinking: nil, output_schema: nil, metadata: {}, purpose:, client: nil)
|
|
132
|
+
request = ModelRequest.new(
|
|
133
|
+
model: model,
|
|
134
|
+
messages: messages,
|
|
135
|
+
tools: tools,
|
|
136
|
+
instructions: instructions,
|
|
137
|
+
thinking: thinking,
|
|
138
|
+
output_schema: output_schema,
|
|
139
|
+
metadata: { purpose: purpose.to_s, turn_id: id, conversation_id: conversation.id }.merge(metadata || {})
|
|
140
|
+
)
|
|
141
|
+
model_client = client || agent.effective_client
|
|
142
|
+
model_client.validate!(model: request.model)
|
|
143
|
+
|
|
144
|
+
emit_model_requested("#{purpose}.model.requested", request)
|
|
145
|
+
result = call_client(request, client: model_client)
|
|
146
|
+
result_cost = Cost.from_usage(result.usage, model: result.model || request.model)
|
|
147
|
+
add_usage!(result.usage, cost: result_cost)
|
|
148
|
+
emit_model_completed("#{purpose}.model.completed", result, result_cost, model: request.model)
|
|
149
|
+
budget.add_cost!(result_cost.total)
|
|
150
|
+
result
|
|
151
|
+
end
|
|
152
|
+
|
|
126
153
|
private
|
|
127
154
|
def model_request
|
|
128
|
-
prompt = SystemPrompt.new(agent: agent, turn: self, conversation: conversation, mode: agent.effective_prompt_mode(turn: self))
|
|
155
|
+
prompt = SystemPrompt.new(agent: agent, turn: self, conversation: conversation, mode: prompt_mode || agent.effective_prompt_mode(turn: self))
|
|
129
156
|
instructions = case agent.system_prompt
|
|
130
157
|
when nil
|
|
131
158
|
prompt.to_s
|
|
@@ -146,7 +173,7 @@ module TurnKit
|
|
|
146
173
|
)
|
|
147
174
|
end
|
|
148
175
|
|
|
149
|
-
def call_client(request)
|
|
176
|
+
def call_client(request, client: agent.effective_client)
|
|
150
177
|
kwargs = {
|
|
151
178
|
model: request.model,
|
|
152
179
|
messages: request.messages,
|
|
@@ -157,9 +184,9 @@ module TurnKit
|
|
|
157
184
|
metadata: request.metadata,
|
|
158
185
|
on_event: ->(event) { emit_event(event) }
|
|
159
186
|
}
|
|
160
|
-
accepted = chat_keyword_names(
|
|
187
|
+
accepted = chat_keyword_names(client)
|
|
161
188
|
kwargs = kwargs.slice(*accepted) unless accepted.include?(:keyrest)
|
|
162
|
-
|
|
189
|
+
client.chat(**kwargs)
|
|
163
190
|
end
|
|
164
191
|
|
|
165
192
|
def chat_keyword_names(client)
|
|
@@ -174,6 +201,26 @@ module TurnKit
|
|
|
174
201
|
MessageProjection.for(TurnKit::Compaction.project(conversation.messages_for_turn(self)))
|
|
175
202
|
end
|
|
176
203
|
|
|
204
|
+
def emit_model_requested(type, request)
|
|
205
|
+
emit(
|
|
206
|
+
type,
|
|
207
|
+
model: request.model,
|
|
208
|
+
tool_names: request.tool_names,
|
|
209
|
+
message_count: request.messages.length,
|
|
210
|
+
prompt: request.report
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def emit_model_completed(type, result, cost, model: self.model)
|
|
215
|
+
emit(
|
|
216
|
+
type,
|
|
217
|
+
model: result.model || model,
|
|
218
|
+
tool_call_count: result.tool_calls.length,
|
|
219
|
+
usage: result.usage.to_h,
|
|
220
|
+
cost: cost.to_h
|
|
221
|
+
)
|
|
222
|
+
end
|
|
223
|
+
|
|
177
224
|
def thinking_from_options
|
|
178
225
|
options = (@record["options"] || {}).transform_keys(&:to_s)
|
|
179
226
|
return Agent.normalize_thinking(options["thinking"]) if options.key?("thinking")
|
|
@@ -191,6 +238,11 @@ module TurnKit
|
|
|
191
238
|
options["output_schema"] if options.key?("output_schema")
|
|
192
239
|
end
|
|
193
240
|
|
|
241
|
+
def prompt_mode_from_options
|
|
242
|
+
options = (@record["options"] || {}).transform_keys(&:to_s)
|
|
243
|
+
options["prompt_mode"]&.to_sym if options.key?("prompt_mode")
|
|
244
|
+
end
|
|
245
|
+
|
|
194
246
|
def persist_assistant_message(result)
|
|
195
247
|
if result.tool_calls?
|
|
196
248
|
message = conversation.append_message(
|
|
@@ -212,8 +264,40 @@ module TurnKit
|
|
|
212
264
|
message = runner.completion_message(execution)
|
|
213
265
|
assistant = conversation.append_message(role: "assistant", kind: "text", text: message, turn_id: id)
|
|
214
266
|
emit("message.created", message_id: assistant.id, role: assistant.role, kind: assistant.kind)
|
|
215
|
-
|
|
216
|
-
|
|
267
|
+
complete_with_output(message)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def complete_with_output(text, output_data: nil)
|
|
271
|
+
audit = audit_output(text, output_data: output_data)
|
|
272
|
+
attrs = { output_text: text, output_data: output_data, completed_at: Clock.now }
|
|
273
|
+
if audit && !audit.clean? && agent.output_audit_mode == :fail
|
|
274
|
+
attrs[:status] = "failed"
|
|
275
|
+
attrs[:error] = { "class" => "TurnKit::OutputAudit", "message" => audit.messages.join("; "), "output_audit" => audit.to_h }
|
|
276
|
+
else
|
|
277
|
+
attrs[:status] = "completed"
|
|
278
|
+
end
|
|
279
|
+
update!(attrs)
|
|
280
|
+
persist_output_audit(audit) if audit
|
|
281
|
+
|
|
282
|
+
if failed?
|
|
283
|
+
emit("turn.failed", error: @record["error"])
|
|
284
|
+
else
|
|
285
|
+
emit("turn.completed", status: status, output_text: text)
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def audit_output(text, output_data: nil)
|
|
290
|
+
constraints = agent.effective_output_audit
|
|
291
|
+
return nil if constraints.empty?
|
|
292
|
+
|
|
293
|
+
output = output_data.nil? ? text : output_data
|
|
294
|
+
TurnKit.audit_output(output, constraints: constraints, context: { turn: self, output_text: text, output_data: output_data })
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def persist_output_audit(audit)
|
|
298
|
+
options = (@record["options"] || {}).merge("output_audit" => audit.to_h)
|
|
299
|
+
update!(options: options)
|
|
300
|
+
emit("output_audit.completed", clean: audit.clean?, violation_count: audit.violations.length)
|
|
217
301
|
end
|
|
218
302
|
|
|
219
303
|
def add_usage!(usage, cost: nil)
|
data/lib/turnkit/version.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "agent"
|
|
4
|
+
|
|
3
5
|
module TurnKit
|
|
4
|
-
class
|
|
6
|
+
class Workflow
|
|
5
7
|
attr_reader :name, :description, :instructions, :tools, :skills, :available_skills
|
|
6
8
|
attr_reader :model, :client, :store, :prompt_mode, :thinking, :compaction, :output_schema
|
|
7
|
-
attr_reader :
|
|
9
|
+
attr_reader :on_event
|
|
10
|
+
attr_reader :max_iterations, :timeout, :cost_limit, :max_depth, :max_tool_executions, :max_tool_executions_by_name
|
|
11
|
+
attr_reader :output_audit, :output_audit_mode, :output_policy, :output_policy_mode, :output_policy_model, :output_policy_thinking
|
|
8
12
|
|
|
9
13
|
DEFAULT_INSTRUCTIONS = <<~TEXT.strip
|
|
10
14
|
You are an autonomous task orchestrator. Navigate from the application
|
|
@@ -15,17 +19,22 @@ module TurnKit
|
|
|
15
19
|
patterns. Iterate when work needs missing context, critique, revision, or
|
|
16
20
|
verification.
|
|
17
21
|
|
|
22
|
+
When multiple independent items need the same kind of fetch or read, and
|
|
23
|
+
an available batch tool can handle them in one call, prefer the batch tool
|
|
24
|
+
over repeated one-item tool calls.
|
|
25
|
+
|
|
18
26
|
Stop when the task is complete, when the available context and tools are
|
|
19
27
|
sufficient for the best possible answer, or when further iteration would
|
|
20
28
|
not materially improve the result. Respect runtime, cost, and iteration
|
|
21
29
|
limits.
|
|
22
30
|
TEXT
|
|
23
31
|
|
|
24
|
-
def initialize(name: "
|
|
32
|
+
def initialize(name: "workflow", description: "", instructions: nil,
|
|
25
33
|
tools: [], skills: [], available_skills: [], model: nil, client: nil,
|
|
26
|
-
store: nil, prompt_mode: :task, thinking: nil, compaction: nil,
|
|
34
|
+
store: nil, prompt_mode: :task, thinking: nil, compaction: nil, on_event: nil,
|
|
27
35
|
output_schema: nil, max_iterations: nil, timeout: nil, max_spend: nil,
|
|
28
|
-
cost_limit: nil, max_depth: nil, max_tool_executions: nil
|
|
36
|
+
cost_limit: nil, max_depth: nil, max_tool_executions: nil, max_tool_executions_by_name: nil,
|
|
37
|
+
output_audit: nil, output_audit_mode: nil, output_policy: nil, output_policy_mode: nil, output_policy_model: nil, output_policy_thinking: nil)
|
|
29
38
|
|
|
30
39
|
@name = name.to_s
|
|
31
40
|
@description = description.to_s
|
|
@@ -39,14 +48,22 @@ module TurnKit
|
|
|
39
48
|
@prompt_mode = prompt_mode
|
|
40
49
|
@thinking = thinking
|
|
41
50
|
@compaction = compaction
|
|
51
|
+
@on_event = on_event
|
|
42
52
|
@output_schema = output_schema
|
|
43
53
|
@max_iterations = max_iterations
|
|
44
54
|
@timeout = timeout
|
|
45
55
|
@cost_limit = cost_limit || max_spend
|
|
46
56
|
@max_depth = max_depth
|
|
47
57
|
@max_tool_executions = max_tool_executions
|
|
58
|
+
@max_tool_executions_by_name = max_tool_executions_by_name
|
|
59
|
+
@output_audit = output_audit
|
|
60
|
+
@output_audit_mode = output_audit_mode
|
|
61
|
+
@output_policy = output_policy
|
|
62
|
+
@output_policy_mode = output_policy_mode
|
|
63
|
+
@output_policy_model = output_policy_model
|
|
64
|
+
@output_policy_thinking = output_policy_thinking
|
|
48
65
|
raise ArgumentError, "name is required" if @name.empty?
|
|
49
|
-
build_agent
|
|
66
|
+
@agent = build_agent
|
|
50
67
|
end
|
|
51
68
|
|
|
52
69
|
def run(prompt = nil, task: nil, input: nil, async: false, subject: nil, metadata: {},
|
|
@@ -55,7 +72,13 @@ module TurnKit
|
|
|
55
72
|
task = task || prompt
|
|
56
73
|
raise ArgumentError, "task is required" if task.to_s.empty?
|
|
57
74
|
|
|
58
|
-
|
|
75
|
+
runtime_agent = if options.empty? && cost_limit.nil? && max_spend.nil?
|
|
76
|
+
@agent
|
|
77
|
+
else
|
|
78
|
+
build_agent(cost_limit: cost_limit || max_spend, **options)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
runtime_agent.run(
|
|
59
82
|
task,
|
|
60
83
|
input: input,
|
|
61
84
|
async: async,
|
|
@@ -64,11 +87,8 @@ module TurnKit
|
|
|
64
87
|
)
|
|
65
88
|
end
|
|
66
89
|
|
|
67
|
-
alias_method :auto_run, :run
|
|
68
|
-
alias_method :autorun, :run
|
|
69
|
-
|
|
70
90
|
def agent(**options)
|
|
71
|
-
build_agent(**options)
|
|
91
|
+
options.empty? ? @agent : build_agent(**options)
|
|
72
92
|
end
|
|
73
93
|
|
|
74
94
|
def max_spend
|
|
@@ -90,16 +110,23 @@ module TurnKit
|
|
|
90
110
|
prompt_mode: prompt_mode,
|
|
91
111
|
thinking: thinking,
|
|
92
112
|
compaction: compaction,
|
|
113
|
+
on_event: on_event,
|
|
93
114
|
output_schema: output_schema,
|
|
94
115
|
max_iterations: max_iterations,
|
|
95
116
|
timeout: timeout,
|
|
96
117
|
cost_limit: cost_limit,
|
|
97
118
|
max_depth: max_depth,
|
|
98
|
-
max_tool_executions: max_tool_executions
|
|
119
|
+
max_tool_executions: max_tool_executions,
|
|
120
|
+
max_tool_executions_by_name: max_tool_executions_by_name,
|
|
121
|
+
output_audit: output_audit,
|
|
122
|
+
output_audit_mode: output_audit_mode,
|
|
123
|
+
output_policy: output_policy,
|
|
124
|
+
output_policy_mode: output_policy_mode,
|
|
125
|
+
output_policy_model: output_policy_model,
|
|
126
|
+
output_policy_thinking: output_policy_thinking
|
|
99
127
|
}
|
|
100
128
|
attrs.merge!(overrides.compact)
|
|
101
129
|
Agent.new(**attrs)
|
|
102
130
|
end
|
|
103
131
|
end
|
|
104
|
-
|
|
105
132
|
end
|
data/lib/turnkit.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "digest"
|
|
|
5
5
|
require "securerandom"
|
|
6
6
|
require "time"
|
|
7
7
|
require "date"
|
|
8
|
+
require "pathname"
|
|
8
9
|
|
|
9
10
|
require_relative "turnkit/version"
|
|
10
11
|
require_relative "turnkit/error"
|
|
@@ -15,13 +16,15 @@ require_relative "turnkit/budget"
|
|
|
15
16
|
require_relative "turnkit/event"
|
|
16
17
|
require_relative "turnkit/model_request"
|
|
17
18
|
require_relative "turnkit/agent"
|
|
18
|
-
require_relative "turnkit/
|
|
19
|
+
require_relative "turnkit/workflow"
|
|
19
20
|
require_relative "turnkit/client"
|
|
20
21
|
require_relative "turnkit/conversation"
|
|
21
22
|
require_relative "turnkit/message"
|
|
22
23
|
require_relative "turnkit/record"
|
|
23
24
|
require_relative "turnkit/result"
|
|
24
25
|
require_relative "turnkit/skill"
|
|
26
|
+
require_relative "turnkit/output_audit"
|
|
27
|
+
require_relative "turnkit/output_policy"
|
|
25
28
|
require_relative "turnkit/prompt_data"
|
|
26
29
|
require_relative "turnkit/prompt_context"
|
|
27
30
|
require_relative "turnkit/prompt_contribution"
|
|
@@ -38,6 +41,7 @@ require_relative "turnkit/tool_runner"
|
|
|
38
41
|
require_relative "turnkit/turn"
|
|
39
42
|
require_relative "turnkit/usage"
|
|
40
43
|
require_relative "turnkit/run"
|
|
44
|
+
require_relative "turnkit/adapters/codex"
|
|
41
45
|
require_relative "turnkit/adapters/ruby_llm"
|
|
42
46
|
require_relative "turnkit/stores/active_record_store"
|
|
43
47
|
|
|
@@ -47,8 +51,10 @@ module TurnKit
|
|
|
47
51
|
class << self
|
|
48
52
|
attr_accessor :default_model, :client, :store, :logger
|
|
49
53
|
attr_accessor :max_iterations, :timeout, :max_depth, :max_tool_executions
|
|
54
|
+
attr_accessor :max_tool_executions_by_name
|
|
50
55
|
attr_accessor :cost_limit, :prompt_cache
|
|
51
56
|
attr_accessor :compaction
|
|
57
|
+
attr_accessor :output_policy_model, :output_policy_thinking
|
|
52
58
|
attr_accessor :cost_rates, :cost_calculator
|
|
53
59
|
attr_accessor :prompt_sections, :prompt_behavior, :available_skills
|
|
54
60
|
attr_accessor :prompt_data_max_chars, :context_contributors
|
|
@@ -65,6 +71,7 @@ module TurnKit
|
|
|
65
71
|
self.timeout = 300
|
|
66
72
|
self.max_depth = 3
|
|
67
73
|
self.max_tool_executions = 100
|
|
74
|
+
self.max_tool_executions_by_name = {}
|
|
68
75
|
self.prompt_cache = :auto
|
|
69
76
|
self.compaction = true
|
|
70
77
|
self.cost_rates = {}
|
|
@@ -75,6 +82,8 @@ module TurnKit
|
|
|
75
82
|
self.system_prompt_contributors = []
|
|
76
83
|
self.model_prompt_contributors = {}
|
|
77
84
|
self.on_event = nil
|
|
85
|
+
self.output_policy_model = nil
|
|
86
|
+
self.output_policy_thinking = { effort: :low }
|
|
78
87
|
|
|
79
88
|
def self.configure
|
|
80
89
|
yield self
|
|
@@ -96,13 +105,13 @@ module TurnKit
|
|
|
96
105
|
self.cost_limit = value
|
|
97
106
|
end
|
|
98
107
|
|
|
99
|
-
def self.fleet(name = "orchestrator", **options)
|
|
100
|
-
Fleet.new(name: name, **options)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
108
|
def self.reconcile_stale!(before: Clock.now - (timeout || 300))
|
|
104
109
|
store.find_stale_turns(before: before).each do |turn|
|
|
105
110
|
store.update_turn(turn.fetch("id"), "status" => "stale", "completed_at" => Clock.now)
|
|
106
111
|
end
|
|
107
112
|
end
|
|
113
|
+
|
|
114
|
+
def self.audit_output(output, constraints: [], context: {})
|
|
115
|
+
OutputAudit.check(output, constraints: constraints, context: context)
|
|
116
|
+
end
|
|
108
117
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: turnkit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sam Couch
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ruby_llm
|
|
@@ -24,8 +24,9 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.14'
|
|
27
|
-
description: TurnKit is a Ruby/Rails agent runtime for durable AI conversations,
|
|
28
|
-
calling, skills, sub-agents, context compaction,
|
|
27
|
+
description: TurnKit is a Ruby/Rails agent runtime for durable AI conversations, application
|
|
28
|
+
runs, reusable workflows, tool calling, skills, sub-agents, context compaction,
|
|
29
|
+
and persistence.
|
|
29
30
|
email:
|
|
30
31
|
- sam@samcouch.com
|
|
31
32
|
executables: []
|
|
@@ -37,6 +38,7 @@ files:
|
|
|
37
38
|
- README.md
|
|
38
39
|
- UPGRADE.md
|
|
39
40
|
- lib/turnkit.rb
|
|
41
|
+
- lib/turnkit/adapters/codex.rb
|
|
40
42
|
- lib/turnkit/adapters/ruby_llm.rb
|
|
41
43
|
- lib/turnkit/agent.rb
|
|
42
44
|
- lib/turnkit/budget.rb
|
|
@@ -47,7 +49,6 @@ files:
|
|
|
47
49
|
- lib/turnkit/cost.rb
|
|
48
50
|
- lib/turnkit/error.rb
|
|
49
51
|
- lib/turnkit/event.rb
|
|
50
|
-
- lib/turnkit/fleet.rb
|
|
51
52
|
- lib/turnkit/generators/turnkit/install/templates/conversation.rb
|
|
52
53
|
- lib/turnkit/generators/turnkit/install/templates/create_turnkit_tables.rb
|
|
53
54
|
- lib/turnkit/generators/turnkit/install/templates/initializer.rb
|
|
@@ -60,6 +61,8 @@ files:
|
|
|
60
61
|
- lib/turnkit/message.rb
|
|
61
62
|
- lib/turnkit/message_projection.rb
|
|
62
63
|
- lib/turnkit/model_request.rb
|
|
64
|
+
- lib/turnkit/output_audit.rb
|
|
65
|
+
- lib/turnkit/output_policy.rb
|
|
63
66
|
- lib/turnkit/prompt_context.rb
|
|
64
67
|
- lib/turnkit/prompt_contribution.rb
|
|
65
68
|
- lib/turnkit/prompt_data.rb
|
|
@@ -79,6 +82,7 @@ files:
|
|
|
79
82
|
- lib/turnkit/turn.rb
|
|
80
83
|
- lib/turnkit/usage.rb
|
|
81
84
|
- lib/turnkit/version.rb
|
|
85
|
+
- lib/turnkit/workflow.rb
|
|
82
86
|
homepage: https://github.com/samuelcouch/turnkit
|
|
83
87
|
licenses:
|
|
84
88
|
- MIT
|
|
@@ -106,5 +110,5 @@ requirements: []
|
|
|
106
110
|
rubygems_version: 3.5.22
|
|
107
111
|
signing_key:
|
|
108
112
|
specification_version: 4
|
|
109
|
-
summary: Ruby/Rails agent runtime for durable AI conversations.
|
|
113
|
+
summary: Ruby/Rails agent runtime for durable AI conversations, runs, and workflows.
|
|
110
114
|
test_files: []
|