1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# frozen_string_literal: true
require 'babosa'
require 'fileutils'
require_relative '../logic/helpers/hash'
require_relative '../components/storage'
module NanoBot
module Controllers
STREAM_TIMEOUT_IN_SECONDS = 5
class Session
attr_accessor :stream
def initialize(provider:, cartridge:, state: nil, stream: $stdout)
@stream = stream
@provider = provider
@cartridge = cartridge
@stateless = state.nil? || state.strip == '-' || state.strip.empty?
if @stateless
@state = { history: [] }
else
@state_path = Components::Storage.build_path_and_ensure_state_file!(
state.strip, @cartridge
)
@state = load_state
end
end
def debug
pp({
state: {
path: @state_path,
content: @state
}
})
end
def load_state
@state = Logic::Helpers::Hash.symbolize_keys(JSON.parse(File.read(@state_path)))
end
def store_state!
File.write(@state_path, JSON.generate(@state))
end
def boot(mode:)
return unless Logic::Helpers::Hash.fetch(@cartridge, %i[behaviors boot instruction])
behavior = Logic::Helpers::Hash.fetch(@cartridge, %i[behaviors boot]) || {}
input = { behavior:, history: [] }
process(input, mode:)
end
def evaluate_and_print(message, mode:)
behavior = Logic::Helpers::Hash.fetch(@cartridge, %i[behaviors interaction]) || {}
@state[:history] << ({ who: 'user', message: })
input = { behavior:, history: @state[:history] }
process(input, mode:)
end
def streaming(interface)
provider = @provider.settings.key?(:stream) ? @provider.settings[:stream] : true
interface = interface.key?(:stream) ? interface[:stream] : true
provider && interface
end
def process(input, mode:)
interface = Logic::Helpers::Hash.fetch(@cartridge, [:interfaces, mode.to_sym]) || {}
streaming = streaming(interface)
input[:interface] = interface
updated_at = Time.now
ready = false
@provider.evaluate(input) do |output, finished|
updated_at = Time.now
if finished
@state[:history] << output
self.print(output[:message]) unless streaming
ready = true
flush
elsif streaming
self.print(output[:message])
end
end
until ready
seconds = (Time.now - updated_at).to_i
raise StandardError, 'The stream has become unresponsive.' if seconds >= STREAM_TIMEOUT_IN_SECONDS
end
store_state! unless @stateless
end
def flush
@stream.flush
end
def print(content)
@stream.write(content)
end
end
end
end
|