Skip to content
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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
GEMINI_API_KEY=

# Hosted defuddle worker (content extraction). URL defaults to the production worker.
DEFUDDLE_API_KEY=
DEFUDDLE_API_URL=https://deffudler.svc.canadasbuilding.com
3 changes: 3 additions & 0 deletions app/controllers/api/agent/commitment_matches_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ def create
matchable_id: params.require(:matchable_id),
)

# A match created by the agent has, by definition, already been reviewed.
match.assign_attributes(
relevance_score: params.require(:relevance_score),
relevance_reasoning: params[:relevance_reasoning],
matched_at: Time.current,
assessed: true,
assessed_at: Time.current,
)

match.save!
Expand Down
23 changes: 15 additions & 8 deletions app/controllers/api/agent/pages_controller.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
module Api
module Agent
class PagesController < BaseController
ALLOWED_SUFFIXES = %w[.canada.ca .gc.ca].freeze
ALLOWED_SUFFIXES = %w[.canada.ca .gc.ca .parl.ca].freeze

def fetch
url = params.require(:url)
government_id = params.require(:government_id)

unless government_url?(url)
render json: { error: "URL must be on a *.canada.ca or *.gc.ca domain" }, status: :unprocessable_entity
render json: { error: "URL must be on a *.canada.ca, *.gc.ca, or *.parl.ca domain" }, status: :unprocessable_entity
return
end

# Fetch and parse the page
response = HTTP.timeout(connect: 5, read: 20)
.headers("User-Agent" => "BuildCanada-Tracker/1.0")
.follow(max_hops: 3)
.get(url)
begin
response = PageFetcher.get(url)
rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, SocketError => e
render json: { error: "Failed to fetch: #{e.class.name.demodulize} (#{e.message})" }, status: :bad_gateway
return
end

unless response.status.success?
render json: { error: "Failed to fetch: HTTP #{response.status}" }, status: :bad_gateway
Expand All @@ -31,8 +33,13 @@ def fetch
end

# Parse HTML to markdown
prepared_html = Defuddle.prepare_html(response.body.to_s)
parsed_markdown, _parsed_html = Defuddle.defuddle(prepared_html)
begin
prepared_html = Defuddle.prepare_html(response.body.to_s)
parsed_markdown, _parsed_html = Defuddle.defuddle(prepared_html, url: final_url)
rescue Defuddle::ParseError => e
render json: { error: "Failed to parse page: #{e.message}" }, status: :bad_gateway
return
end

# Extract title and date from meta tags
doc = Nokogiri::HTML(response.body.to_s)
Expand Down
9 changes: 7 additions & 2 deletions app/controllers/statcan_datasets_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
class StatcanDatasetsController < ApplicationController
def show
dataset = StatcanDataset.find_by(name: params[:id])
render json: dataset
dataset = StatcanDataset.find_by(name: params[:id]) || StatcanDataset.find_by(id: params[:id])

if dataset
render json: dataset
else
render json: { error: "Dataset not found" }, status: :not_found
end
end
end
4 changes: 2 additions & 2 deletions app/jobs/agent_evaluate_commitment_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def build_cmd(prompt, hook_script:)
"--system-prompt", system_prompt,
"--allowedTools", allowed_tools.join(","),
"--permission-mode", "bypassPermissions",
"--model", ENV.fetch("AGENT_MODEL", "claude-sonnet-4-6"),
"--model", ENV.fetch("AGENT_MODEL", "claude-sonnet-5"),
"--output-format", "text",
"--settings", hook_settings
]
Expand Down Expand Up @@ -91,7 +91,7 @@ def agent_env(commitment_id: nil, entry_id: nil)
"CLAUDE_CODE_OAUTH_TOKEN" => ENV["CLAUDE_CODE_OAUTH_TOKEN"],
"RAILS_API_URL" => ENV.fetch("RAILS_API_URL", "http://localhost:3000"),
"RAILS_API_KEY" => Rails.application.credentials.dig(:agent, :api_key) || ENV["AGENT_API_KEY"],
"AGENT_MODEL" => ENV.fetch("AGENT_MODEL", "claude-sonnet-4-6"),
"AGENT_MODEL" => ENV.fetch("AGENT_MODEL", "claude-sonnet-5"),
"COMMITMENT_ID" => commitment_id&.to_s,
"ENTRY_ID" => entry_id&.to_s,
# Explicitly unset — subprocess must not access Rails credentials
Expand Down
4 changes: 2 additions & 2 deletions app/jobs/agent_process_entry_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def build_cmd(prompt, hook_script:)
"--system-prompt", system_prompt,
"--allowedTools", allowed_tools.join(","),
"--permission-mode", "bypassPermissions",
"--model", ENV.fetch("AGENT_MODEL", "claude-opus-4-6"),
"--model", ENV.fetch("AGENT_MODEL", "claude-sonnet-5"),
"--output-format", "text",
"--settings", hook_settings
]
Expand Down Expand Up @@ -79,7 +79,7 @@ def agent_env(commitment_id: nil, entry_id: nil)
"CLAUDE_CODE_OAUTH_TOKEN" => ENV["CLAUDE_CODE_OAUTH_TOKEN"],
"RAILS_API_URL" => ENV.fetch("RAILS_API_URL", "http://localhost:3000"),
"RAILS_API_KEY" => Rails.application.credentials.dig(:agent, :api_key) || ENV["AGENT_API_KEY"],
"AGENT_MODEL" => ENV.fetch("AGENT_MODEL", "claude-opus-4-6"),
"AGENT_MODEL" => ENV.fetch("AGENT_MODEL", "claude-sonnet-5"),
"COMMITMENT_ID" => commitment_id&.to_s,
"ENTRY_ID" => entry_id&.to_s,
# Explicitly unset — subprocess must not access Rails credentials
Expand Down
12 changes: 0 additions & 12 deletions app/jobs/commitment_assessment_cron_job.rb

This file was deleted.

103 changes: 0 additions & 103 deletions app/jobs/commitment_assessment_job.rb

This file was deleted.

10 changes: 10 additions & 0 deletions app/models/chat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ class Chat < ApplicationRecord

belongs_to :record, polymorphic: true, optional: true

class << self
# Rows from retired pipelines (CriterionAssessor, CommitmentStatusDeriver) remain as an
# audit log after their classes were removed. Load them as plain Chats instead of raising.
def find_sti_class(type_name)
super
rescue ActiveRecord::SubclassNotFound
self
end
end

def system_prompt
end

Expand Down
120 changes: 0 additions & 120 deletions app/models/commitment_status_deriver.rb

This file was deleted.

Loading
Loading