turnkit 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +112 -6
- data/UPGRADE.md +37 -299
- data/lib/turnkit/adapters/ruby_llm.rb +29 -0
- data/lib/turnkit/agent.rb +61 -7
- data/lib/turnkit/budget.rb +44 -10
- data/lib/turnkit/compaction.rb +16 -4
- data/lib/turnkit/error.rb +2 -0
- data/lib/turnkit/generators/turnkit/install/templates/create_turnkit_tables.rb +0 -1
- data/lib/turnkit/load_skill_tool.rb +29 -0
- data/lib/turnkit/memory_store.rb +11 -0
- data/lib/turnkit/message.rb +14 -7
- data/lib/turnkit/message_projection.rb +17 -2
- data/lib/turnkit/output_audit.rb +92 -0
- data/lib/turnkit/output_policy.rb +127 -0
- data/lib/turnkit/result.rb +29 -4
- data/lib/turnkit/run.rb +4 -3
- data/lib/turnkit/schema_check.rb +68 -0
- data/lib/turnkit/skill.rb +16 -2
- data/lib/turnkit/store.rb +6 -0
- data/lib/turnkit/stores/active_record_store.rb +10 -2
- data/lib/turnkit/sub_agent_tool.rb +2 -1
- data/lib/turnkit/system_prompt.rb +1 -1
- data/lib/turnkit/tool.rb +2 -21
- data/lib/turnkit/tool_call.rb +3 -3
- data/lib/turnkit/tool_runner.rb +40 -11
- data/lib/turnkit/turn.rb +162 -18
- data/lib/turnkit/version.rb +1 -1
- data/lib/turnkit/workflow.rb +24 -69
- data/lib/turnkit.rb +16 -9
- metadata +6 -2
data/lib/turnkit/version.rb
CHANGED
data/lib/turnkit/workflow.rb
CHANGED
|
@@ -4,11 +4,7 @@ require_relative "agent"
|
|
|
4
4
|
|
|
5
5
|
module TurnKit
|
|
6
6
|
class Workflow
|
|
7
|
-
|
|
8
|
-
attr_reader :model, :client, :store, :prompt_mode, :thinking, :compaction, :output_schema
|
|
9
|
-
attr_reader :max_iterations, :timeout, :cost_limit, :max_depth, :max_tool_executions
|
|
10
|
-
|
|
11
|
-
DEFAULT_INSTRUCTIONS = <<~TEXT.strip
|
|
7
|
+
ORCHESTRATOR_PREAMBLE = <<~TEXT.strip
|
|
12
8
|
You are an autonomous task orchestrator. Navigate from the application
|
|
13
9
|
request to a final output without asking the user follow-up questions.
|
|
14
10
|
|
|
@@ -17,87 +13,46 @@ module TurnKit
|
|
|
17
13
|
patterns. Iterate when work needs missing context, critique, revision, or
|
|
18
14
|
verification.
|
|
19
15
|
|
|
16
|
+
When multiple independent items need the same kind of fetch or read, and
|
|
17
|
+
an available batch tool can handle them in one call, prefer the batch tool
|
|
18
|
+
over repeated one-item tool calls.
|
|
19
|
+
|
|
20
20
|
Stop when the task is complete, when the available context and tools are
|
|
21
21
|
sufficient for the best possible answer, or when further iteration would
|
|
22
22
|
not materially improve the result. Respect runtime, cost, and iteration
|
|
23
23
|
limits.
|
|
24
24
|
TEXT
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
output_schema: nil, max_iterations: nil, timeout: nil, max_spend: nil,
|
|
30
|
-
cost_limit: nil, max_depth: nil, max_tool_executions: nil)
|
|
26
|
+
DEFAULT_INSTRUCTIONS = ORCHESTRATOR_PREAMBLE
|
|
27
|
+
|
|
28
|
+
attr_reader :name, :options
|
|
31
29
|
|
|
30
|
+
def initialize(name: "workflow", instructions: nil, preamble: true, **options)
|
|
32
31
|
@name = name.to_s
|
|
33
|
-
@description = description.to_s
|
|
34
|
-
@instructions = instructions || DEFAULT_INSTRUCTIONS
|
|
35
|
-
@tools = Array(tools)
|
|
36
|
-
@skills = Array(skills)
|
|
37
|
-
@available_skills = Array(available_skills)
|
|
38
|
-
@model = model
|
|
39
|
-
@client = client
|
|
40
|
-
@store = store
|
|
41
|
-
@prompt_mode = prompt_mode
|
|
42
|
-
@thinking = thinking
|
|
43
|
-
@compaction = compaction
|
|
44
|
-
@output_schema = output_schema
|
|
45
|
-
@max_iterations = max_iterations
|
|
46
|
-
@timeout = timeout
|
|
47
|
-
@cost_limit = cost_limit || max_spend
|
|
48
|
-
@max_depth = max_depth
|
|
49
|
-
@max_tool_executions = max_tool_executions
|
|
50
32
|
raise ArgumentError, "name is required" if @name.empty?
|
|
51
|
-
build_agent
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def run(prompt = nil, task: nil, input: nil, async: false, subject: nil, metadata: {},
|
|
55
|
-
max_spend: nil, cost_limit: nil, **options)
|
|
56
|
-
|
|
57
|
-
task = task || prompt
|
|
58
|
-
raise ArgumentError, "task is required" if task.to_s.empty?
|
|
59
33
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
34
|
+
@options = options.merge(
|
|
35
|
+
name: @name,
|
|
36
|
+
prompt_mode: options.fetch(:prompt_mode, :task),
|
|
37
|
+
instructions: compose_instructions(instructions, preamble: preamble)
|
|
38
|
+
).freeze
|
|
39
|
+
@agent = Agent.new(**@options)
|
|
67
40
|
end
|
|
68
41
|
|
|
69
|
-
def
|
|
70
|
-
|
|
42
|
+
def run(prompt = nil, task: nil, input: nil, async: false, subject: nil, metadata: {}, **overrides)
|
|
43
|
+
agent(**overrides).run(task || prompt, input: input, async: async, subject: subject, metadata: metadata)
|
|
71
44
|
end
|
|
72
45
|
|
|
73
|
-
def
|
|
74
|
-
|
|
46
|
+
def agent(**overrides)
|
|
47
|
+
overrides.empty? ? @agent : Agent.new(**@options.merge(overrides.compact))
|
|
75
48
|
end
|
|
76
49
|
|
|
77
50
|
private
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
tools: tools,
|
|
84
|
-
skills: skills,
|
|
85
|
-
available_skills: available_skills,
|
|
86
|
-
model: model,
|
|
87
|
-
client: client,
|
|
88
|
-
store: store,
|
|
89
|
-
prompt_mode: prompt_mode,
|
|
90
|
-
thinking: thinking,
|
|
91
|
-
compaction: compaction,
|
|
92
|
-
output_schema: output_schema,
|
|
93
|
-
max_iterations: max_iterations,
|
|
94
|
-
timeout: timeout,
|
|
95
|
-
cost_limit: cost_limit,
|
|
96
|
-
max_depth: max_depth,
|
|
97
|
-
max_tool_executions: max_tool_executions
|
|
98
|
-
}
|
|
99
|
-
attrs.merge!(overrides.compact)
|
|
100
|
-
Agent.new(**attrs)
|
|
51
|
+
def compose_instructions(instructions, preamble:)
|
|
52
|
+
parts = []
|
|
53
|
+
parts << ORCHESTRATOR_PREAMBLE if preamble
|
|
54
|
+
parts << instructions.to_s.strip unless instructions.to_s.strip.empty?
|
|
55
|
+
parts.join("\n\n")
|
|
101
56
|
end
|
|
102
57
|
end
|
|
103
58
|
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"
|
|
@@ -14,6 +15,7 @@ require_relative "turnkit/cost"
|
|
|
14
15
|
require_relative "turnkit/budget"
|
|
15
16
|
require_relative "turnkit/event"
|
|
16
17
|
require_relative "turnkit/model_request"
|
|
18
|
+
require_relative "turnkit/schema_check"
|
|
17
19
|
require_relative "turnkit/agent"
|
|
18
20
|
require_relative "turnkit/workflow"
|
|
19
21
|
require_relative "turnkit/client"
|
|
@@ -22,6 +24,8 @@ require_relative "turnkit/message"
|
|
|
22
24
|
require_relative "turnkit/record"
|
|
23
25
|
require_relative "turnkit/result"
|
|
24
26
|
require_relative "turnkit/skill"
|
|
27
|
+
require_relative "turnkit/output_audit"
|
|
28
|
+
require_relative "turnkit/output_policy"
|
|
25
29
|
require_relative "turnkit/prompt_data"
|
|
26
30
|
require_relative "turnkit/prompt_context"
|
|
27
31
|
require_relative "turnkit/prompt_contribution"
|
|
@@ -33,6 +37,7 @@ require_relative "turnkit/tool"
|
|
|
33
37
|
require_relative "turnkit/tool_call"
|
|
34
38
|
require_relative "turnkit/tool_execution"
|
|
35
39
|
require_relative "turnkit/sub_agent_tool"
|
|
40
|
+
require_relative "turnkit/load_skill_tool"
|
|
36
41
|
require_relative "turnkit/message_projection"
|
|
37
42
|
require_relative "turnkit/tool_runner"
|
|
38
43
|
require_relative "turnkit/turn"
|
|
@@ -48,8 +53,10 @@ module TurnKit
|
|
|
48
53
|
class << self
|
|
49
54
|
attr_accessor :default_model, :client, :store, :logger
|
|
50
55
|
attr_accessor :max_iterations, :timeout, :max_depth, :max_tool_executions
|
|
51
|
-
attr_accessor :
|
|
56
|
+
attr_accessor :max_tool_executions_by_name
|
|
57
|
+
attr_accessor :max_spend, :prompt_cache
|
|
52
58
|
attr_accessor :compaction
|
|
59
|
+
attr_accessor :output_policy_model, :output_policy_thinking
|
|
53
60
|
attr_accessor :cost_rates, :cost_calculator
|
|
54
61
|
attr_accessor :prompt_sections, :prompt_behavior, :available_skills
|
|
55
62
|
attr_accessor :prompt_data_max_chars, :context_contributors
|
|
@@ -66,6 +73,8 @@ module TurnKit
|
|
|
66
73
|
self.timeout = 300
|
|
67
74
|
self.max_depth = 3
|
|
68
75
|
self.max_tool_executions = 100
|
|
76
|
+
self.max_tool_executions_by_name = {}
|
|
77
|
+
self.max_spend = nil
|
|
69
78
|
self.prompt_cache = :auto
|
|
70
79
|
self.compaction = true
|
|
71
80
|
self.cost_rates = {}
|
|
@@ -76,6 +85,8 @@ module TurnKit
|
|
|
76
85
|
self.system_prompt_contributors = []
|
|
77
86
|
self.model_prompt_contributors = {}
|
|
78
87
|
self.on_event = nil
|
|
88
|
+
self.output_policy_model = nil
|
|
89
|
+
self.output_policy_thinking = { effort: :low }
|
|
79
90
|
|
|
80
91
|
def self.configure
|
|
81
92
|
yield self
|
|
@@ -89,17 +100,13 @@ module TurnKit
|
|
|
89
100
|
self.default_model = value
|
|
90
101
|
end
|
|
91
102
|
|
|
92
|
-
def self.max_spend
|
|
93
|
-
cost_limit
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def self.max_spend=(value)
|
|
97
|
-
self.cost_limit = value
|
|
98
|
-
end
|
|
99
|
-
|
|
100
103
|
def self.reconcile_stale!(before: Clock.now - (timeout || 300))
|
|
101
104
|
store.find_stale_turns(before: before).each do |turn|
|
|
102
105
|
store.update_turn(turn.fetch("id"), "status" => "stale", "completed_at" => Clock.now)
|
|
103
106
|
end
|
|
104
107
|
end
|
|
108
|
+
|
|
109
|
+
def self.check_output_policy(output, constraints: [], context: {})
|
|
110
|
+
OutputAudit.check(output, constraints: constraints, context: context)
|
|
111
|
+
end
|
|
105
112
|
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.
|
|
4
|
+
version: 0.3.0
|
|
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
|
|
@@ -57,10 +57,13 @@ files:
|
|
|
57
57
|
- lib/turnkit/generators/turnkit/install/templates/turn.rb
|
|
58
58
|
- lib/turnkit/generators/turnkit/install_generator.rb
|
|
59
59
|
- lib/turnkit/id.rb
|
|
60
|
+
- lib/turnkit/load_skill_tool.rb
|
|
60
61
|
- lib/turnkit/memory_store.rb
|
|
61
62
|
- lib/turnkit/message.rb
|
|
62
63
|
- lib/turnkit/message_projection.rb
|
|
63
64
|
- lib/turnkit/model_request.rb
|
|
65
|
+
- lib/turnkit/output_audit.rb
|
|
66
|
+
- lib/turnkit/output_policy.rb
|
|
64
67
|
- lib/turnkit/prompt_context.rb
|
|
65
68
|
- lib/turnkit/prompt_contribution.rb
|
|
66
69
|
- lib/turnkit/prompt_data.rb
|
|
@@ -68,6 +71,7 @@ files:
|
|
|
68
71
|
- lib/turnkit/record.rb
|
|
69
72
|
- lib/turnkit/result.rb
|
|
70
73
|
- lib/turnkit/run.rb
|
|
74
|
+
- lib/turnkit/schema_check.rb
|
|
71
75
|
- lib/turnkit/skill.rb
|
|
72
76
|
- lib/turnkit/store.rb
|
|
73
77
|
- lib/turnkit/stores/active_record_store.rb
|