Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/models/ai_tool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ def self.preamble
* base_64_content (string): Base64 encoded content of the file.
* Returns: { id: number, url: string, short_url: string } - Details of the created upload record.
*
* upload.getUrl(shortUrl): Given a short URL, eg upload://12345, returns the full CDN friendly URL of the upload.
* 5. chain
* Controls the execution flow.
*
Expand Down
19 changes: 19 additions & 0 deletions lib/personas/tool_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def framework_script

const upload = {
create: _upload_create,
getUrl: _upload_get_url,
}

const chain = {
Expand Down Expand Up @@ -570,6 +571,24 @@ def attach_discourse(mini_racer_context)
end

def attach_upload(mini_racer_context)
mini_racer_context.attach(
"_upload_get_url",
->(short_url) do
in_attached_function do
return nil if short_url.blank?

sha1 = Upload.sha1_from_short_url(short_url)
return nil if sha1.blank?

upload = Upload.find_by(sha1: sha1)
return nil if upload.nil?
# TODO we may need to introduce an API to unsecure, secure uploads
return nil if upload.secure?

GlobalPath.full_cdn_url(upload.url)
end
end,
)
mini_racer_context.attach(
"_upload_create",
->(filename, base_64_content) do
Expand Down
60 changes: 60 additions & 0 deletions spec/models/ai_tool_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -675,4 +675,64 @@ def stub_embeddings
expect(ai_persona.temperature).to eq(0.5)
end
end

describe "upload URL resolution" do
it "can resolve upload short URLs to public URLs" do
upload =
Fabricate(
:upload,
sha1: "abcdef1234567890abcdef1234567890abcdef12",
url: "/uploads/default/original/1X/test.jpg",
original_filename: "test.jpg",
)

script = <<~JS
function invoke(params) {
return upload.getUrl(params.short_url);
}
JS

tool = create_tool(script: script)
runner = tool.runner({ "short_url" => upload.short_url }, llm: nil, bot_user: nil)

result = runner.invoke

expect(result).to eq(GlobalPath.full_cdn_url(upload.url))
end

it "returns null for invalid upload short URLs" do
script = <<~JS
function invoke(params) {
return upload.getUrl(params.short_url);
}
JS

tool = create_tool(script: script)
runner = tool.runner({ "short_url" => "upload://invalid" }, llm: nil, bot_user: nil)

result = runner.invoke

expect(result).to be_nil
end

it "returns null for non-existent uploads" do
script = <<~JS
function invoke(params) {
return upload.getUrl(params.short_url);
}
JS

tool = create_tool(script: script)
runner =
tool.runner(
{ "short_url" => "upload://hwmUkTAL9mwhQuRMLsXw6tvDi5C.jpeg" },
llm: nil,
bot_user: nil,
)

result = runner.invoke

expect(result).to be_nil
end
end
end
Loading