134 lines
4.0 KiB
Ruby
134 lines
4.0 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe DiscourseAi::Personas::Tools::ReadArtifact do
|
|
fab!(:llm_model)
|
|
let(:bot_user) { DiscourseAi::AiBot::EntryPoint.find_user_from_model(llm_model.name) }
|
|
fab!(:post)
|
|
fab!(:post2) { Fabricate(:post, user: post.user) }
|
|
fab!(:artifact) do
|
|
AiArtifact.create!(
|
|
user: post.user,
|
|
post: post,
|
|
name: "Test Artifact",
|
|
html: "<div>Test Content</div>",
|
|
css: ".test { color: blue; }",
|
|
js: "console.log('test');",
|
|
)
|
|
end
|
|
|
|
before { SiteSetting.ai_bot_enabled = true }
|
|
|
|
describe "#invoke" do
|
|
it "successfully reads a local artifact" do
|
|
tool =
|
|
described_class.new(
|
|
{ url: "#{Discourse.base_url}/discourse-ai/ai-bot/artifacts/#{artifact.id}" },
|
|
bot_user: bot_user,
|
|
llm: llm_model.to_llm,
|
|
context: DiscourseAi::Personas::BotContext.new(post: post),
|
|
)
|
|
|
|
result = tool.invoke {}
|
|
expect(result[:status]).to eq("success")
|
|
|
|
new_artifact = AiArtifact.last
|
|
expect(new_artifact.html).to eq(artifact.html)
|
|
expect(new_artifact.css).to eq(artifact.css)
|
|
expect(new_artifact.js).to eq(artifact.js)
|
|
expect(new_artifact.metadata["cloned_from"]).to eq(artifact.id)
|
|
end
|
|
|
|
it "handles invalid URLs" do
|
|
tool =
|
|
described_class.new(
|
|
{ url: "invalid-url" },
|
|
bot_user: bot_user,
|
|
llm: llm_model.to_llm,
|
|
context: DiscourseAi::Personas::BotContext.new(post: post),
|
|
)
|
|
|
|
result = tool.invoke {}
|
|
expect(result[:status]).to eq("error")
|
|
expect(result[:error]).to eq("Invalid URL")
|
|
end
|
|
|
|
it "handles non-existent artifacts" do
|
|
tool =
|
|
described_class.new(
|
|
{ url: "#{Discourse.base_url}/discourse-ai/ai-bot/artifacts/99999" },
|
|
bot_user: bot_user,
|
|
llm: llm_model.to_llm,
|
|
context: DiscourseAi::Personas::BotContext.new(post: post),
|
|
)
|
|
|
|
result = tool.invoke {}
|
|
expect(result[:status]).to eq("error")
|
|
expect(result[:error]).to eq("Artifact not found")
|
|
end
|
|
|
|
it "handles external web pages" do
|
|
stub_request(:get, "https://example.com").to_return(status: 200, body: <<~HTML)
|
|
<html>
|
|
<head>
|
|
<link rel="stylesheet" href="/style.css">
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<div>External Content</div>
|
|
</main>
|
|
<script>console.log('test');</script>
|
|
</body>
|
|
</html>
|
|
HTML
|
|
|
|
stub_request(:get, "https://example.com/style.css").to_return(
|
|
status: 200,
|
|
body: ".external { color: red; }",
|
|
)
|
|
|
|
tool =
|
|
described_class.new(
|
|
{ url: "https://example.com" },
|
|
bot_user: bot_user,
|
|
llm: llm_model.to_llm,
|
|
context: DiscourseAi::Personas::BotContext.new(post: post),
|
|
)
|
|
|
|
result = tool.invoke {}
|
|
expect(result[:status]).to eq("success")
|
|
|
|
new_artifact = AiArtifact.last
|
|
expect(new_artifact.html).to include("<div>External Content</div>")
|
|
expect(new_artifact.css).to include(".external { color: red; }")
|
|
expect(new_artifact.js).to include("console.log('test');")
|
|
expect(new_artifact.metadata["imported_from"]).to eq("https://example.com")
|
|
end
|
|
|
|
it "respects MAX_HTML_SIZE limit" do
|
|
large_content = "x" * (described_class::MAX_HTML_SIZE + 1000)
|
|
|
|
stub_request(:get, "https://example.com").to_return(status: 200, body: <<~HTML)
|
|
<html>
|
|
<body>
|
|
<main>#{large_content}</main>
|
|
</body>
|
|
</html>
|
|
HTML
|
|
|
|
tool =
|
|
described_class.new(
|
|
{ url: "https://example.com" },
|
|
bot_user: bot_user,
|
|
llm: llm_model.to_llm,
|
|
context: DiscourseAi::Personas::BotContext.new(post: post),
|
|
)
|
|
|
|
result = tool.invoke {}
|
|
expect(result[:status]).to eq("success")
|
|
|
|
new_artifact = AiArtifact.last
|
|
expect(new_artifact.html.length).to be <= described_class::MAX_HTML_SIZE
|
|
end
|
|
end
|
|
end
|