envoy_ai 0.0.2 → 0.0.4
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/app/assets/stylesheets/envoy/chat.css +27 -0
- data/app/models/envoy/conversation.rb +33 -0
- data/lib/envoy/runner.rb +5 -0
- data/lib/envoy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 78234041fb1cc9c8df4b16e0125c24069f29c224bbb4fbaf601ecd72e831715f
|
|
4
|
+
data.tar.gz: 040c720efeaa6677fc1ceb05b3d1f8dec26b0cdcc110d2c0567ee3e536785829
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b76061cf8adc16a4cc216e05568a3e918508b0cf7fc81afe349325fcf1281349272738a24b2c3855cec9a8d4af9527b0442d367a73436060b9e84b063b92fb7e
|
|
7
|
+
data.tar.gz: 5abcc9d99056f8ed6835e457270df6e0f6ff75cf70da8b22642136112799ab3163bbc80665acb58ed6d036a69ad0835600ecdd3043456f8a980a1c893b39bdd7
|
|
@@ -7,10 +7,17 @@
|
|
|
7
7
|
--envoy-ink, --envoy-subtle, --envoy-line, --envoy-accent,
|
|
8
8
|
--envoy-accent-ink, --envoy-warn, --envoy-radius. */
|
|
9
9
|
|
|
10
|
+
/* Fills a flex-column container (an embedded, fixed-height panel) so the log
|
|
11
|
+
below can scroll internally. Inert when the parent isn't a flex container —
|
|
12
|
+
e.g. the full-page console, which keeps its natural height and page-scrolls —
|
|
13
|
+
because flex item properties only apply inside a flex parent. The embedding
|
|
14
|
+
host is responsible for giving this element a bounded height (a flex column
|
|
15
|
+
with a definite height); the transcript then fills it and scrolls its log. */
|
|
10
16
|
.envoy-chat {
|
|
11
17
|
display: flex;
|
|
12
18
|
flex-direction: column;
|
|
13
19
|
min-height: 0;
|
|
20
|
+
flex: 1 1 auto;
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
.envoy-chat__log {
|
|
@@ -18,6 +25,26 @@
|
|
|
18
25
|
min-height: 0;
|
|
19
26
|
overflow-y: auto;
|
|
20
27
|
overscroll-behavior: contain;
|
|
28
|
+
scrollbar-width: thin;
|
|
29
|
+
scrollbar-color: var(--envoy-subtle, #6b7280) transparent;
|
|
30
|
+
}
|
|
31
|
+
.envoy-chat__log::-webkit-scrollbar { width: 8px; }
|
|
32
|
+
.envoy-chat__log::-webkit-scrollbar-track { background: transparent; }
|
|
33
|
+
.envoy-chat__log::-webkit-scrollbar-thumb {
|
|
34
|
+
background: var(--envoy-subtle, #6b7280);
|
|
35
|
+
border-radius: 9999px;
|
|
36
|
+
}
|
|
37
|
+
.envoy-chat__log::-webkit-scrollbar-thumb:hover {
|
|
38
|
+
background: var(--envoy-ink, #111827);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Separate the transcript from the composer: in the flex column the log sits
|
|
42
|
+
flush against the input form, so the last message and the textarea run
|
|
43
|
+
together without a divider. */
|
|
44
|
+
.envoy-chat > form {
|
|
45
|
+
margin-top: 0.75rem;
|
|
46
|
+
padding-top: 0.75rem;
|
|
47
|
+
border-top: 1px solid var(--envoy-line, #e5e7eb);
|
|
21
48
|
}
|
|
22
49
|
|
|
23
50
|
/* ---------------------------------------------------------------------- */
|
|
@@ -37,8 +37,41 @@ module Envoy
|
|
|
37
37
|
system_prompt.presence
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
# Truncate an interrupted tail so the next turn starts from a valid state.
|
|
41
|
+
#
|
|
42
|
+
# acts_as_chat replays the whole message log to the provider every turn. If a
|
|
43
|
+
# turn died without a RubyLLM::Error (a deploy restart mid-turn, an OOM, a
|
|
44
|
+
# network kill), RubyLLM's own cleanup never ran and the log can end with a
|
|
45
|
+
# blank assistant row or an assistant tool_use that has no result — both of
|
|
46
|
+
# which the provider rejects, bricking every future turn. Drop everything
|
|
47
|
+
# after the last *completed* assistant turn (non-blank content, every tool_use
|
|
48
|
+
# answered); if there is no such checkpoint yet, drop everything but a leading
|
|
49
|
+
# system prefix. Returns the number of messages removed. A steady conversation
|
|
50
|
+
# already ending on a completed turn is a no-op.
|
|
51
|
+
#
|
|
52
|
+
# Safe because a completed assistant turn could only have been produced if the
|
|
53
|
+
# log before it already replayed cleanly — so nothing before the checkpoint
|
|
54
|
+
# can be malformed.
|
|
55
|
+
def heal_interrupted_tail!
|
|
56
|
+
ordered = messages.order(:id).to_a
|
|
57
|
+
checkpoint = ordered.rindex { |m| completed_assistant_turn?(m) }
|
|
58
|
+
stale = checkpoint ? ordered[(checkpoint + 1)..] : ordered.reject { |m| m.role == "system" }
|
|
59
|
+
return 0 if stale.empty?
|
|
60
|
+
|
|
61
|
+
# Newest first so a tool-result message is removed before the tool_call it
|
|
62
|
+
# points at (destroyed via the assistant's dependent: :destroy).
|
|
63
|
+
stale.reverse_each(&:destroy!)
|
|
64
|
+
stale.size
|
|
65
|
+
end
|
|
66
|
+
|
|
40
67
|
private
|
|
41
68
|
|
|
69
|
+
def completed_assistant_turn?(message)
|
|
70
|
+
return false unless message.role == "assistant"
|
|
71
|
+
return false if message.content.blank?
|
|
72
|
+
message.tool_calls.all? { |tc| Envoy::Message.exists?(tool_call_id: tc.id) }
|
|
73
|
+
end
|
|
74
|
+
|
|
42
75
|
def toolset_or_surface_present
|
|
43
76
|
return if toolset_key.present? || surface_key.present?
|
|
44
77
|
errors.add(:base, "toolset_key or surface_key must be present")
|
data/lib/envoy/runner.rb
CHANGED
|
@@ -12,6 +12,11 @@ module Envoy
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def call(content:, &on_event)
|
|
15
|
+
# Repair an interrupted tail before replaying: a prior turn killed mid-flight
|
|
16
|
+
# (deploy restart, OOM, timeout) can leave a blank assistant or dangling
|
|
17
|
+
# tool_use that the provider rejects on every subsequent turn. Heal first so
|
|
18
|
+
# one bad turn can't permanently brick the conversation.
|
|
19
|
+
@conversation.heal_interrupted_tail!
|
|
15
20
|
tools = compiled_tools
|
|
16
21
|
Envoy.llm(conversation: @conversation)
|
|
17
22
|
.run(content: content, tools: tools, instructions: instructions, &on_event)
|
data/lib/envoy/version.rb
CHANGED