Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit 646fae4

Browse files
committed
improve progress story for artifact rendering
1 parent 869e1ca commit 646fae4

File tree

6 files changed

+145
-57
lines changed

6 files changed

+145
-57
lines changed

lib/ai_bot/artifact_update_strategies/base.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,20 @@ def initialize(llm:, post:, user:, artifact:, artifact_version:, instructions:)
1616
@instructions = instructions
1717
end
1818

19-
def apply
20-
changes = generate_changes
19+
def apply(&progress)
20+
changes = generate_changes(&progress)
2121
parsed_changes = parse_changes(changes)
2222
apply_changes(parsed_changes)
2323
end
2424

2525
private
2626

27-
def generate_changes
27+
def generate_changes(&progress)
2828
response = +""
29-
llm.generate(build_prompt, user: user) { |partial| response << partial }
29+
llm.generate(build_prompt, user: user) do |partial|
30+
progress.call(partial) if progress
31+
response << partial
32+
end
3033
response
3134
end
3235

lib/ai_bot/bot.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,11 @@ def invoke_tool(tool, llm, cancel, context, &update_blk)
220220
update_blk.call("", cancel, build_placeholder(tool.summary, "")) if show_placeholder
221221

222222
result =
223-
tool.invoke do |progress|
224-
if show_placeholder
223+
tool.invoke do |progress, render_raw|
224+
if render_raw
225+
update_blk.call("", cancel, tool.custom_raw, :partial_invoke)
226+
show_placeholder = false
227+
elsif show_placeholder
225228
placeholder = build_placeholder(tool.summary, progress)
226229
update_blk.call("", cancel, placeholder)
227230
end

lib/ai_bot/playground.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,9 @@ def reply_to(post, custom_instructions: nil, &blk)
479479
raw = reply.dup
480480
raw << "\n\n" << placeholder if placeholder.present?
481481

482-
blk.call(partial) if blk && type != :tool_details && type != :partial_tool
482+
if blk && type != :tool_details && type != :partial_tool && type != :partial_invoke
483+
blk.call(partial)
484+
end
483485

484486
if stream_reply && !Discourse.redis.get(redis_stream_key)
485487
cancel&.call

lib/ai_bot/tools/create_artifact.rb

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def self.specification_description
4242
- List any specific libraries or frameworks to use/avoid
4343
- Describe error states and edge cases
4444
- Include accessibility requirements
45+
- Include code snippets to help ground the specification
4546
DESC
4647
end
4748

@@ -66,54 +67,56 @@ def self.signature
6667
}
6768
end
6869

69-
def self.inject_prompt(prompt:, context:, persona:)
70-
return if persona.options["echo_artifact"] != "true"
71-
# we inject the current artifact content into the last user message
72-
if topic_id = context[:topic_id]
73-
posts = Post.where(topic_id: topic_id)
74-
artifact = AiArtifact.order("id desc").where(post: posts).first
75-
if artifact
76-
latest_version = artifact.versions.order(version_number: :desc).first
77-
current = latest_version || artifact
78-
79-
artifact_source = <<~MSG
80-
Current Artifact:
81-
82-
### HTML
83-
```html
84-
#{current.html}
85-
```
86-
87-
### CSS
88-
```css
89-
#{current.css}
90-
```
91-
92-
### JavaScript
93-
```javascript
94-
#{current.js}
95-
```
96-
97-
MSG
98-
99-
last_message = prompt.messages.last
100-
last_message[:content] = "#{artifact_source}\n\n#{last_message[:content]}"
101-
end
70+
def self.accepted_options
71+
[option(:creator_llm, type: :llm)]
72+
end
73+
74+
def self.allow_partial_tool_calls?
75+
true
76+
end
77+
78+
def partial_invoke
79+
if parameters[:specification].present?
80+
in_progress(specification: parameters[:specification])
10281
end
10382
end
10483

105-
def self.accepted_options
106-
[option(:creator_llm, type: :llm), option(:echo_artifact, type: :boolean)]
84+
def in_progress(specification:, source: nil)
85+
source = (<<~HTML) if source.present?
86+
### Source
87+
88+
````
89+
#{source}
90+
````
91+
HTML
92+
93+
self.custom_raw = <<~HTML
94+
<details>
95+
<summary>Thinking...</summary>
96+
97+
98+
### Specification
99+
````
100+
#{specification}
101+
````
102+
103+
#{source}
104+
105+
</details>
106+
HTML
107107
end
108108

109109
def invoke
110-
name = parameters[:name] || "New Artifact"
111-
yield "#{name}\n\n" + parameters[:specification].to_s
112-
113110
post = Post.find_by(id: context[:post_id])
114111
return error_response("No post context found") unless post
115112

116-
artifact_code = generate_artifact_code(post: post, user: post.user)
113+
partial_response = +""
114+
artifact_code =
115+
generate_artifact_code(post: post, user: post.user) do |partial|
116+
partial_response << partial
117+
in_progress(specification: parameters[:specification], source: partial_response)
118+
yield nil, true
119+
end
117120
return error_response(artifact_code[:error]) if artifact_code[:error]
118121

119122
artifact = create_artifact(post, artifact_code)
@@ -122,6 +125,7 @@ def invoke
122125
update_custom_html(artifact)
123126
success_response(artifact)
124127
else
128+
self.custom_raw = self.custom_raw + "\n\n###Error creating artifact..."
125129
error_response(artifact.errors.full_messages.join(", "))
126130
end
127131
end
@@ -148,6 +152,7 @@ def generate_artifact_code(post:, user:)
148152

149153
llm.generate(prompt, user: user, feature_name: "create_artifact") do |partial_response|
150154
response << partial_response
155+
yield partial_response
151156
end
152157

153158
sections = parse_sections(response)

lib/ai_bot/tools/update_artifact.rb

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,83 @@ def self.signature
3737
}
3838
end
3939

40+
def self.inject_prompt(prompt:, context:, persona:)
41+
return if persona.options["echo_artifact"].to_s == "false"
42+
# we inject the current artifact content into the last user message
43+
if topic_id = context[:topic_id]
44+
posts = Post.where(topic_id: topic_id)
45+
artifact = AiArtifact.order("id desc").where(post: posts).first
46+
if artifact
47+
latest_version = artifact.versions.order(version_number: :desc).first
48+
current = latest_version || artifact
49+
50+
artifact_source = <<~MSG
51+
Current Artifact:
52+
53+
### HTML
54+
```html
55+
#{current.html}
56+
```
57+
58+
### CSS
59+
```css
60+
#{current.css}
61+
```
62+
63+
### JavaScript
64+
```javascript
65+
#{current.js}
66+
```
67+
68+
MSG
69+
70+
last_message = prompt.messages.last
71+
last_message[:content] = "#{artifact_source}\n\n#{last_message[:content]}"
72+
end
73+
end
74+
end
75+
4076
def self.accepted_options
4177
[
4278
option(:editor_llm, type: :llm),
4379
option(:update_algorithm, type: :enum, values: %w[full diff], default: "full"),
80+
option(:echo_artifact, type: :boolean, default: true),
4481
]
4582
end
4683

47-
def invoke
48-
yield "Updating Artifact\n#{parameters[:instructions]}\n\n"
84+
def self.allow_partial_tool_calls?
85+
true
86+
end
87+
88+
def partial_invoke
89+
in_progress(instructions: parameters[:instructions]) if parameters[:instructions].present?
90+
end
91+
92+
def in_progress(instructions:, source: nil)
93+
source = (<<~HTML) if source.present?
94+
### Source
95+
96+
````
97+
#{source}
98+
````
99+
HTML
100+
101+
self.custom_raw = <<~HTML
102+
<details>
103+
<summary>Thinking...</summary>
49104
105+
### Instructions
106+
````
107+
#{instructions}
108+
````
109+
110+
#{source}
111+
112+
</details>
113+
HTML
114+
end
115+
116+
def invoke
50117
post = Post.find_by(id: context[:post_id])
51118
return error_response("No post context found") unless post
52119

@@ -81,15 +148,23 @@ def invoke
81148
)
82149

83150
begin
151+
partial_response = +""
84152
new_version =
85-
strategy.new(
86-
llm: llm,
87-
post: post,
88-
user: post.user,
89-
artifact: artifact,
90-
artifact_version: artifact_version,
91-
instructions: parameters[:instructions],
92-
).apply
153+
strategy
154+
.new(
155+
llm: llm,
156+
post: post,
157+
user: post.user,
158+
artifact: artifact,
159+
artifact_version: artifact_version,
160+
instructions: parameters[:instructions],
161+
)
162+
.apply do |progress|
163+
partial_response << progress
164+
in_progress(instructions: parameters[:instructions], source: partial_response)
165+
# force in progress to render
166+
yield nil, true
167+
end
93168

94169
update_custom_html(
95170
artifact: artifact,

lib/completions/endpoints/open_ai.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def decode_chunk(chunk)
123123
end
124124

125125
def decode_chunk_finish
126-
@processor.finish
126+
processor.finish
127127
end
128128

129129
def xml_tools_enabled?

0 commit comments

Comments
 (0)