From a9e4e90bc3b9000db654442dfaa04e42400bfd50 Mon Sep 17 00:00:00 2001 From: nshkrdotcom <127063941+nshkrdotcom@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:08:29 -1000 Subject: [PATCH 1/4] chore(deps): use local jido deps --- mix.exs | 8 ++++---- mix.lock | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mix.exs b/mix.exs index 724f1a4..212f680 100644 --- a/mix.exs +++ b/mix.exs @@ -105,10 +105,10 @@ defmodule AgentJido.MixProject do {:dns_cluster, "~> 0.2.0"}, # Jido AI framework - {:jido, "~> 2.0.0-rc"}, - {:jido_action, "~> 2.0.0-rc", override: true}, - {:jido_signal, "~> 2.0.0-rc"}, - {:jido_ai, github: "agentjido/jido_ai", branch: "main"}, + {:jido, path: "../jido", override: true}, + {:jido_action, path: "../jido_action", override: true}, + {:jido_signal, path: "../jido_signal", override: true}, + {:jido_ai, path: "../jido_ai"}, {:req_llm, "~> 1.4", override: true}, {:timex, "~> 3.7", override: true}, {:gettext, "~> 0.26", override: true}, diff --git a/mix.lock b/mix.lock index 3f2590d..e36f624 100644 --- a/mix.lock +++ b/mix.lock @@ -74,7 +74,6 @@ "jido": {:hex, :jido, "2.0.0-rc.2", "cd8b2db9efb9e791d914f7779b05120a3b12d458fb07e72b1b3277cb21f95972", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:igniter, "~> 0.7", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:jido_action, "~> 2.0.0-rc.2", [hex: :jido_action, repo: "hexpm", optional: false]}, {:jido_signal, "~> 2.0.0-rc.2", [hex: :jido_signal, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:ok, "~> 2.3", [hex: :ok, repo: "hexpm", optional: false]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:sched_ex, "~> 1.1", [hex: :sched_ex, repo: "hexpm", optional: false]}, {:splode, "~> 0.3.0", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.3", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.1", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:uniq, "~> 0.6.1", [hex: :uniq, repo: "hexpm", optional: false]}], "hexpm", "1c9de2a9af8c9f953ce58efcfe1b01beb67b34587edb2e899144427ca3d6ccb7"}, "jido_action": {:hex, :jido_action, "2.0.0-rc.2", "c6e9e0604812f5d39d7fb16ced05123efbf012a8e35b2b40fc22de7b4d6a02f8", [:mix], [{:abacus, "~> 2.1", [hex: :abacus, repo: "hexpm", optional: false]}, {:igniter, "~> 0.7", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:libgraph, "~> 0.16.0", [hex: :libgraph, repo: "hexpm", optional: false]}, {:lua, "~> 0.3", [hex: :lua, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:private, "~> 0.1.2", [hex: :private, repo: "hexpm", optional: false]}, {:req, "~> 0.5.10", [hex: :req, repo: "hexpm", optional: false]}, {:splode, "~> 0.3.0", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.3", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.1", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:tentacat, "~> 2.5", [hex: :tentacat, repo: "hexpm", optional: false]}, {:uniq, "~> 0.6.1", [hex: :uniq, repo: "hexpm", optional: false]}, {:weather, "~> 0.4.0", [hex: :weather, repo: "hexpm", optional: false]}, {:zoi, "~> 0.16", [hex: :zoi, repo: "hexpm", optional: false]}], "hexpm", "28cd235a159dc2d1ceb82cc3d1ef1b84d4bff6fa4ae8a076079b13cbc2a8bb93"}, "jido_ai": {:git, "https://github.com/agentjido/jido_ai.git", "59c2775cdb4adfe43801c9e69b6cca8772d3d9a2", [branch: "main"]}, - "jido_browser": {:git, "https://github.com/agentjido/jido_browser.git", "ece3bb70d0abb6c148680f59c313029a7ed6dac0", [branch: "main"]}, "jido_signal": {:hex, :jido_signal, "2.0.0-rc.2", "f1afc591a6ca92d7ac69168762d0c48f4e581abb9c5d30622c85ab9ecad58cec", [:mix], [{:fuse, "~> 2.5", [hex: :fuse, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:memento, "~> 0.5.0", [hex: :memento, repo: "hexpm", optional: false]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:private, "~> 0.1.2", [hex: :private, repo: "hexpm", optional: false]}, {:splode, "~> 0.3.0", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.3", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.1", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:uniq, "~> 0.6.1", [hex: :uniq, repo: "hexpm", optional: false]}, {:zoi, "~> 0.16", [hex: :zoi, repo: "hexpm", optional: false]}], "hexpm", "80ee1af67fc8154ce686001571fd5aff00312d6ca4674f9133453ed82ea589d8"}, "joken": {:hex, :joken, "2.6.2", "5daaf82259ca603af4f0b065475099ada1b2b849ff140ccd37f4b6828ca6892a", [:mix], [{:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5134b5b0a6e37494e46dbf9e4dad53808e5e787904b7c73972651b51cce3d72b"}, "jose": {:hex, :jose, "1.11.12", "06e62b467b61d3726cbc19e9b5489f7549c37993de846dfb3ee8259f9ed208b3", [:mix, :rebar3], [], "hexpm", "31e92b653e9210b696765cdd885437457de1add2a9011d92f8cf63e4641bab7b"}, From 9a46f4181c7340059e69f226f07f0ffb68a71d51 Mon Sep 17 00:00:00 2001 From: nshkrdotcom <127063941+nshkrdotcom@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:10:33 -1000 Subject: [PATCH 2/4] fix(ui): handle terminal exec results --- .../issue_run/actions/pull_request_result_action.ex | 4 +--- .../issue_run/actions/research_result_action.ex | 4 +--- .../issue_run/actions/triage_result_action.ex | 4 +--- .../pull_request/workers/actions/pr_submit_action.ex | 6 +++++- lib/agent_jido_web/components/blockquote.ex | 3 ++- lib/agent_jido_web/live/forge/show_live.ex | 3 ++- .../pull_request/pull_request_coordinator_test.exs | 1 + test/agent_jido_web/controllers/page_controller_test.exs | 2 +- test/agent_jido_web/live/demos/chat_live_test.exs | 4 +--- 9 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/agent_jido/github_issue_bot/issue_run/actions/pull_request_result_action.ex b/lib/agent_jido/github_issue_bot/issue_run/actions/pull_request_result_action.ex index 45719f8..97934af 100644 --- a/lib/agent_jido/github_issue_bot/issue_run/actions/pull_request_result_action.ex +++ b/lib/agent_jido/github_issue_bot/issue_run/actions/pull_request_result_action.ex @@ -31,9 +31,7 @@ defmodule AgentJido.GithubIssueBot.IssueRun.Actions.PullRequestResultAction do cond do current_run_id != run_id -> - Logger.warning( - "Received pull_request result for wrong run: #{run_id} (expected #{current_run_id})" - ) + Logger.warning("Received pull_request result for wrong run: #{run_id} (expected #{current_run_id})") {:ok, %{}} diff --git a/lib/agent_jido/github_issue_bot/issue_run/actions/research_result_action.ex b/lib/agent_jido/github_issue_bot/issue_run/actions/research_result_action.ex index e566711..94bd94b 100644 --- a/lib/agent_jido/github_issue_bot/issue_run/actions/research_result_action.ex +++ b/lib/agent_jido/github_issue_bot/issue_run/actions/research_result_action.ex @@ -30,9 +30,7 @@ defmodule AgentJido.GithubIssueBot.IssueRun.Actions.ResearchResultAction do cond do current_run_id != run_id -> - Logger.warning( - "Received research result for wrong run: #{run_id} (expected #{current_run_id})" - ) + Logger.warning("Received research result for wrong run: #{run_id} (expected #{current_run_id})") {:ok, %{}} diff --git a/lib/agent_jido/github_issue_bot/issue_run/actions/triage_result_action.ex b/lib/agent_jido/github_issue_bot/issue_run/actions/triage_result_action.ex index fc44c38..0d743fe 100644 --- a/lib/agent_jido/github_issue_bot/issue_run/actions/triage_result_action.ex +++ b/lib/agent_jido/github_issue_bot/issue_run/actions/triage_result_action.ex @@ -34,9 +34,7 @@ defmodule AgentJido.GithubIssueBot.IssueRun.Actions.TriageResultAction do cond do current_run_id != run_id -> - Logger.warning( - "Received triage result for wrong run: #{run_id} (expected #{current_run_id})" - ) + Logger.warning("Received triage result for wrong run: #{run_id} (expected #{current_run_id})") {:ok, %{}} diff --git a/lib/agent_jido/github_issue_bot/pull_request/workers/actions/pr_submit_action.ex b/lib/agent_jido/github_issue_bot/pull_request/workers/actions/pr_submit_action.ex index e3476b0..d90c0a0 100644 --- a/lib/agent_jido/github_issue_bot/pull_request/workers/actions/pr_submit_action.ex +++ b/lib/agent_jido/github_issue_bot/pull_request/workers/actions/pr_submit_action.ex @@ -60,6 +60,7 @@ defmodule AgentJido.GithubIssueBot.PullRequest.Workers.Actions.PRSubmitAction do # Stub: Generate mock PR data # TODO: Replace with actual GitHub API calls pr_number = generate_pr_number() + result = %{ pr_number: pr_number, pr_url: "https://github.com/#{repo}/pull/#{pr_number}", @@ -118,7 +119,10 @@ defmodule AgentJido.GithubIssueBot.PullRequest.Workers.Actions.PRSubmitAction do classification = Map.get(triage, :classification, :unknown) root_cause = get_in(research, [:root_cause, :hypothesis]) || "See research findings" - attempt_note = if attempt > 1, do: "\n\n> **Note**: This fix required #{attempt} iterations to pass all quality checks.", else: "" + attempt_note = + if attempt > 1, + do: "\n\n> **Note**: This fix required #{attempt} iterations to pass all quality checks.", + else: "" """ ## Summary diff --git a/lib/agent_jido_web/components/blockquote.ex b/lib/agent_jido_web/components/blockquote.ex index 66ed5ed..ec3c962 100644 --- a/lib/agent_jido_web/components/blockquote.ex +++ b/lib/agent_jido_web/components/blockquote.ex @@ -228,7 +228,8 @@ defmodule AgentJidoWeb.Components.Blockquote do defp space_class(params) when is_binary(params), do: params defp border_class(_, _, variant) - when variant in ["default", "shadow", "transparent", "gradient"], do: nil + when variant in ["default", "shadow", "transparent", "gradient"], + do: nil defp border_class(_, "none", _), do: nil diff --git a/lib/agent_jido_web/live/forge/show_live.ex b/lib/agent_jido_web/live/forge/show_live.ex index b59d325..75445b1 100644 --- a/lib/agent_jido_web/live/forge/show_live.ex +++ b/lib/agent_jido_web/live/forge/show_live.ex @@ -101,7 +101,8 @@ defmodule AgentJidoWeb.Forge.ShowLive do end end - def handle_info({:terminal_exec_result, {output, exit_code}}, socket) do + def handle_info({:terminal_exec_result, {output, exit_code}}, socket) + when is_binary(output) and is_integer(exit_code) do socket = output |> String.split("\n", trim: true) diff --git a/test/agent_jido/github_issue_bot/pull_request/pull_request_coordinator_test.exs b/test/agent_jido/github_issue_bot/pull_request/pull_request_coordinator_test.exs index e9b53f5..524ec8a 100644 --- a/test/agent_jido/github_issue_bot/pull_request/pull_request_coordinator_test.exs +++ b/test/agent_jido/github_issue_bot/pull_request/pull_request_coordinator_test.exs @@ -256,6 +256,7 @@ defmodule AgentJido.GithubIssueBotTest.PullRequest.PullRequestCoordinatorTest do # Should have 3 failed attempts in history assert length(pr.attempt_history) == 3 + Enum.each(pr.attempt_history, fn entry -> assert entry.outcome == :failed end) diff --git a/test/agent_jido_web/controllers/page_controller_test.exs b/test/agent_jido_web/controllers/page_controller_test.exs index 9589c9c..d6f2a29 100644 --- a/test/agent_jido_web/controllers/page_controller_test.exs +++ b/test/agent_jido_web/controllers/page_controller_test.exs @@ -3,6 +3,6 @@ defmodule AgentJidoWeb.PageControllerTest do test "GET /", %{conn: conn} do conn = get(conn, ~p"/") - assert html_response(conn, 200) =~ "Peace of mind from prototype to production" + assert html_response(conn, 200) =~ "Agent Jido" end end diff --git a/test/agent_jido_web/live/demos/chat_live_test.exs b/test/agent_jido_web/live/demos/chat_live_test.exs index 3eaf58b..e10f2ee 100644 --- a/test/agent_jido_web/live/demos/chat_live_test.exs +++ b/test/agent_jido_web/live/demos/chat_live_test.exs @@ -1,11 +1,9 @@ defmodule AgentJidoWeb.Demos.ChatLiveTest do use AgentJidoWeb.ConnCase, async: false - import Phoenix.LiveViewTest - describe "ChatLive" do @tag :skip - test "renders chat interface when authenticated", %{conn: conn} do + test "renders chat interface when authenticated", %{conn: _conn} do # This test requires authentication - skip for now until auth helpers are set up # When auth is available: # conn = log_in_user(conn, user) From f8148ed01c08adac53a3570cdf8192c3aa1a166d Mon Sep 17 00:00:00 2001 From: nshkrdotcom <127063941+nshkrdotcom@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:40:55 -1000 Subject: [PATCH 3/4] fix(compat): Elixir 1.18 compatibility and code quality improvements - Add @moduledoc false to internal modules to suppress missing doc warnings - Alphabetize alias statements to satisfy Elixir 1.18 compiler checks - Refactor nested conditionals into extracted helper functions for clarity - Replace Enum.map + Enum.join with Enum.map_join for idiomatic Elixir - Use pattern matching on boolean guards instead of if/else branches - Fix TypeScript ash_rpc nullable union type inference with NonNullable wrappers - Export internal TypeScript types for external consumption - Update README with Node.js 18+ requirement and npm install instructions - Bump ash, ash_postgres, ash_sql, ash_typescript, llm_db, and req_llm deps --- README.md | 6 +- assets/js/ash_rpc.ts | 88 ++++--- lib/agent_jido/accounts.ex | 1 + lib/agent_jido/accounts/api_key.ex | 1 + lib/agent_jido/accounts/token.ex | 1 + lib/agent_jido/accounts/user.ex | 1 + lib/agent_jido/folio.ex | 1 + lib/agent_jido/forge.ex | 21 +- lib/agent_jido/forge/domain.ex | 1 + lib/agent_jido/forge/manager.ex | 91 ++++--- lib/agent_jido/forge/operations.ex | 2 +- lib/agent_jido/forge/persistence.ex | 26 +- lib/agent_jido/forge/resources/checkpoint.ex | 1 + lib/agent_jido/forge/resources/event.ex | 1 + .../forge/resources/exec_session.ex | 1 + lib/agent_jido/forge/resources/session.ex | 1 + lib/agent_jido/forge/resources/sprite_spec.ex | 1 + lib/agent_jido/forge/resources/workflow.ex | 1 + lib/agent_jido/forge/runners/claude_code.ex | 45 ++-- lib/agent_jido/forge/sprite_client/fake.ex | 24 +- lib/agent_jido/forge/sprite_client/live.ex | 4 +- .../workers/streaming_exec_session_worker.ex | 2 +- lib/agent_jido/github.ex | 1 + lib/agent_jido/github/issue_analysis.ex | 1 + lib/agent_jido/github/webhook_delivery.ex | 1 + lib/agent_jido/github_issue_bot/cli/run.ex | 8 +- .../actions/research_result_action.ex | 2 +- .../issue_run/actions/start_run_action.ex | 2 +- .../issue_run/actions/triage_result_action.ex | 2 +- .../issue_run/coordinator_agent.ex | 6 +- .../actions/patch_result_action.ex | 2 +- .../actions/start_pull_request_action.ex | 2 +- .../pull_request/pull_request_coordinator.ex | 6 +- .../research/actions/start_research_action.ex | 8 +- .../research/actions/worker_result_action.ex | 4 +- .../research/research_coordinator.ex | 4 +- .../workers/actions/root_cause_action.ex | 36 +-- .../triage/actions/triage_action.ex | 31 ++- lib/agent_jido/secrets.ex | 1 + lib/agent_jido_web.ex | 2 +- lib/agent_jido_web/ash_json_api_router.ex | 1 + lib/agent_jido_web/auth_overrides.ex | 1 + lib/agent_jido_web/components/accordion.ex | 4 +- lib/agent_jido_web/components/breadcrumb.ex | 2 +- lib/agent_jido_web/components/button.ex | 10 +- .../components/checkbox_field.ex | 4 +- .../components/core_components.ex | 11 +- lib/agent_jido_web/components/input_field.ex | 3 +- lib/agent_jido_web/components/mega_menu.ex | 2 +- .../components/mishka_components.ex | 1 + lib/agent_jido_web/components/pagination.ex | 2 +- lib/agent_jido_web/components/speed_dial.ex | 2 +- lib/agent_jido_web/components/stepper.ex | 2 +- lib/agent_jido_web/components/toggle_field.ex | 2 +- lib/agent_jido_web/live/demos/chat_live.ex | 227 ++++++++++-------- lib/agent_jido_web/live/folio_live.ex | 221 +++++++++-------- lib/agent_jido_web/live/forge/show_live.ex | 66 ++--- lib/agent_jido_web/live_user_auth.ex | 4 +- mix.lock | 18 +- .../issue_run/coordinator_test.exs | 2 +- .../pull_request_coordinator_test.exs | 4 +- .../research/research_coordinator_test.exs | 4 +- test/support/data_case.ex | 6 +- 63 files changed, 537 insertions(+), 502 deletions(-) diff --git a/README.md b/README.md index 10f0dfc..a89d6b6 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ AgentJido is a Phoenix 1.8 application for the Jido AI agent ecosystem. - Elixir 1.18+ - PostgreSQL 14+ +- Node.js 18+ (for asset compilation) ### Setup @@ -26,7 +27,10 @@ AgentJido is a Phoenix 1.8 application for the Jido AI agent ecosystem. git clone https://github.com/agentjido/agent_jido.git cd agent_jido -# Install dependencies and setup database +# Install JavaScript dependencies +cd assets && npm install && cd .. + +# Install Elixir dependencies and setup database mix setup # Start the Phoenix server diff --git a/assets/js/ash_rpc.ts b/assets/js/ash_rpc.ts index 5b55d24..317a581 100644 --- a/assets/js/ash_rpc.ts +++ b/assets/js/ash_rpc.ts @@ -16,20 +16,20 @@ // Utility Types // Resource schema constraint -type TypedSchema = { +export type TypedSchema = { __type: "Resource" | "TypedMap" | "Union"; __primitiveFields: string; }; // Utility type to convert union to intersection -type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( +export type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( k: infer I, ) => void ? I : never; // Helper type to infer union field values, avoiding duplication between array and non-array unions -type InferUnionFieldValue< +export type InferUnionFieldValue< UnionSchema extends { __type: "Union"; __primitiveFields: any }, FieldSelection extends any[], > = UnionToIntersection< @@ -41,34 +41,34 @@ type InferUnionFieldValue< : FieldSelection[FieldIndex] extends Record ? { [UnionKey in keyof FieldSelection[FieldIndex]]: UnionKey extends keyof UnionSchema - ? UnionSchema[UnionKey] extends { __array: true; __type: "TypedMap"; __primitiveFields: infer TypedMapFields } + ? NonNullable extends { __array: true; __type: "TypedMap"; __primitiveFields: infer TypedMapFields } ? FieldSelection[FieldIndex][UnionKey] extends any[] ? Array< UnionToIntersection< { [FieldIdx in keyof FieldSelection[FieldIndex][UnionKey]]: FieldSelection[FieldIndex][UnionKey][FieldIdx] extends TypedMapFields - ? FieldSelection[FieldIndex][UnionKey][FieldIdx] extends keyof UnionSchema[UnionKey] - ? { [P in FieldSelection[FieldIndex][UnionKey][FieldIdx]]: UnionSchema[UnionKey][P] } + ? FieldSelection[FieldIndex][UnionKey][FieldIdx] extends keyof NonNullable + ? { [P in FieldSelection[FieldIndex][UnionKey][FieldIdx]]: NonNullable[P] } : never : never; }[number] > > | null : never - : UnionSchema[UnionKey] extends { __type: "TypedMap"; __primitiveFields: infer TypedMapFields } + : NonNullable extends { __type: "TypedMap"; __primitiveFields: infer TypedMapFields } ? FieldSelection[FieldIndex][UnionKey] extends any[] ? UnionToIntersection< { [FieldIdx in keyof FieldSelection[FieldIndex][UnionKey]]: FieldSelection[FieldIndex][UnionKey][FieldIdx] extends TypedMapFields - ? FieldSelection[FieldIndex][UnionKey][FieldIdx] extends keyof UnionSchema[UnionKey] - ? { [P in FieldSelection[FieldIndex][UnionKey][FieldIdx]]: UnionSchema[UnionKey][P] } + ? FieldSelection[FieldIndex][UnionKey][FieldIdx] extends keyof NonNullable + ? { [P in FieldSelection[FieldIndex][UnionKey][FieldIdx]]: NonNullable[P] } : never : never; }[number] > | null : never - : UnionSchema[UnionKey] extends TypedSchema - ? InferResult + : NonNullable extends TypedSchema + ? InferResult, FieldSelection[FieldIndex][UnionKey]> : never : never; } @@ -76,21 +76,21 @@ type InferUnionFieldValue< }[number] >; -type HasComplexFields = keyof Omit< +export type HasComplexFields = keyof Omit< T, "__primitiveFields" | "__type" | T["__primitiveFields"] > extends never ? false : true; -type ComplexFieldKeys = keyof Omit< +export type ComplexFieldKeys = keyof Omit< T, "__primitiveFields" | "__type" | T["__primitiveFields"] >; -type LeafFieldSelection = T["__primitiveFields"]; +export type LeafFieldSelection = T["__primitiveFields"]; -type ComplexFieldSelection = { +export type ComplexFieldSelection = { [K in ComplexFieldKeys]?: T[K] extends { __type: "Relationship"; __resource: infer Resource; @@ -119,17 +119,17 @@ type ComplexFieldSelection = { : T[K] extends { __type: "Union"; __primitiveFields: infer PrimitiveFields } ? T[K] extends { __array: true } ? (PrimitiveFields | { - [UnionKey in keyof Omit]?: T[K][UnionKey] extends { __type: "TypedMap"; __primitiveFields: any } - ? T[K][UnionKey]["__primitiveFields"][] - : T[K][UnionKey] extends TypedSchema - ? UnifiedFieldSelection[] + [UnionKey in keyof Omit]?: NonNullable extends { __type: "TypedMap"; __primitiveFields: any } + ? NonNullable["__primitiveFields"][] + : NonNullable extends TypedSchema + ? UnifiedFieldSelection>[] : never; })[] : (PrimitiveFields | { - [UnionKey in keyof Omit]?: T[K][UnionKey] extends { __type: "TypedMap"; __primitiveFields: any } - ? T[K][UnionKey]["__primitiveFields"][] - : T[K][UnionKey] extends TypedSchema - ? UnifiedFieldSelection[] + [UnionKey in keyof Omit]?: NonNullable extends { __type: "TypedMap"; __primitiveFields: any } + ? NonNullable["__primitiveFields"][] + : NonNullable extends TypedSchema + ? UnifiedFieldSelection>[] : never; })[] : NonNullable extends TypedSchema @@ -138,12 +138,12 @@ type ComplexFieldSelection = { }; // Main type: Use explicit base case detection to prevent infinite recursion -type UnifiedFieldSelection = +export type UnifiedFieldSelection = HasComplexFields extends false ? LeafFieldSelection // Base case: only primitives, no recursion : LeafFieldSelection | ComplexFieldSelection; // Recursive case -type InferFieldValue< +export type InferFieldValue< T extends TypedSchema, Field, > = Field extends T["__primitiveFields"] @@ -279,20 +279,16 @@ type InferFieldValue< : never : T[K] extends { __type: "Union"; __primitiveFields: any } ? T[K] extends { __array: true } - ? { - [CurrentK in K]: T[CurrentK] extends { __type: "Union"; __primitiveFields: any } - ? Field[CurrentK] extends any[] - ? Array> | null - : never - : never - } - : { - [CurrentK in K]: T[CurrentK] extends { __type: "Union"; __primitiveFields: any } - ? Field[CurrentK] extends any[] - ? InferUnionFieldValue | null - : never - : never - } + ? Field[K] extends any[] + ? null extends T[K] + ? Array> | null + : Array> + : never + : Field[K] extends any[] + ? null extends T[K] + ? InferUnionFieldValue | null + : InferUnionFieldValue + : never : NonNullable extends TypedSchema ? null extends T[K] ? InferResult, Field[K]> | null @@ -302,7 +298,7 @@ type InferFieldValue< } : never; -type InferResult< +export type InferResult< T extends TypedSchema, SelectedFields extends UnifiedFieldSelection[] | undefined, > = SelectedFields extends undefined @@ -319,14 +315,14 @@ type InferResult< // Pagination conditional types // Checks if a page configuration object has any pagination parameters -type HasPaginationParams = +export type HasPaginationParams = Page extends { offset: any } ? true : Page extends { after: any } ? true : Page extends { before: any } ? true : false; // Infer which pagination type is being used from the page config -type InferPaginationType = +export type InferPaginationType = Page extends { offset: any } ? "offset" : Page extends { after: any } | { before: any } ? "keyset" : never; @@ -335,7 +331,7 @@ type InferPaginationType = // For single pagination type support (offset-only or keyset-only) // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unused-vars -type ConditionalPaginatedResult< +export type ConditionalPaginatedResult< Page, RecordType, PaginatedType @@ -347,7 +343,7 @@ type ConditionalPaginatedResult< // For actions supporting both offset and keyset pagination // Infers the specific pagination type based on which params were passed -type ConditionalPaginatedResultMixed< +export type ConditionalPaginatedResultMixed< Page, RecordType, OffsetType, @@ -533,7 +529,7 @@ export function buildCSRFHeaders(headers: Record = {}): Record( +export async function executeActionRpcRequest( payload: Record, config: ActionConfig ): Promise { @@ -584,7 +580,7 @@ async function executeActionRpcRequest( * Handles hooks, request configuration, fetch execution, and error handling * @param config Configuration matching ValidationConfig */ -async function executeValidationRpcRequest( +export async function executeValidationRpcRequest( payload: Record, config: ValidationConfig ): Promise { diff --git a/lib/agent_jido/accounts.ex b/lib/agent_jido/accounts.ex index a219ecc..69b3b62 100644 --- a/lib/agent_jido/accounts.ex +++ b/lib/agent_jido/accounts.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Accounts do + @moduledoc false use Ash.Domain, otp_app: :agent_jido, extensions: [AshAdmin.Domain] admin do diff --git a/lib/agent_jido/accounts/api_key.ex b/lib/agent_jido/accounts/api_key.ex index a0d25ef..0822664 100644 --- a/lib/agent_jido/accounts/api_key.ex +++ b/lib/agent_jido/accounts/api_key.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Accounts.ApiKey do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Accounts, diff --git a/lib/agent_jido/accounts/token.ex b/lib/agent_jido/accounts/token.ex index 3213ef7..7667174 100644 --- a/lib/agent_jido/accounts/token.ex +++ b/lib/agent_jido/accounts/token.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Accounts.Token do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Accounts, diff --git a/lib/agent_jido/accounts/user.ex b/lib/agent_jido/accounts/user.ex index 388084f..c23de5f 100644 --- a/lib/agent_jido/accounts/user.ex +++ b/lib/agent_jido/accounts/user.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Accounts.User do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Accounts, diff --git a/lib/agent_jido/folio.ex b/lib/agent_jido/folio.ex index c91b8fb..608a3ee 100644 --- a/lib/agent_jido/folio.ex +++ b/lib/agent_jido/folio.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Folio do + @moduledoc false use Ash.Domain resources do diff --git a/lib/agent_jido/forge.ex b/lib/agent_jido/forge.ex index c8dd6c9..5d504e4 100644 --- a/lib/agent_jido/forge.ex +++ b/lib/agent_jido/forge.ex @@ -157,26 +157,16 @@ defmodule AgentJido.Forge do defp do_run_loop(session_id, opts, max_iterations, iteration, return_error_result?) do case run_iteration(session_id, opts) do - {:ok, %{status: :done} = result} -> - {:ok, result} - - {:ok, %{status: :needs_input} = result} -> - {:ok, result} - - {:ok, %{status: :blocked} = result} -> + {:ok, %{status: status} = result} when status in [:done, :needs_input, :blocked] -> {:ok, result} {:ok, %{status: :error} = result} -> - if return_error_result? do - {:ok, result} - else - {:error, {:iteration_error, result}} - end + handle_error_result(result, return_error_result?) - {:ok, %{continue: true} = _result} -> + {:ok, %{continue: true}} -> do_run_loop(session_id, opts, max_iterations, iteration + 1, return_error_result?) - {:ok, %{status: :continue} = _result} -> + {:ok, %{status: :continue}} -> do_run_loop(session_id, opts, max_iterations, iteration + 1, return_error_result?) {:ok, result} -> @@ -187,6 +177,9 @@ defmodule AgentJido.Forge do end end + defp handle_error_result(result, true = _return_error_result?), do: {:ok, result} + defp handle_error_result(result, false = _return_error_result?), do: {:error, {:iteration_error, result}} + # Session lifecycle operations @doc """ diff --git a/lib/agent_jido/forge/domain.ex b/lib/agent_jido/forge/domain.ex index c7b6c5d..55acf80 100644 --- a/lib/agent_jido/forge/domain.ex +++ b/lib/agent_jido/forge/domain.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Forge.Domain do + @moduledoc false use Ash.Domain, otp_app: :agent_jido, extensions: [AshAdmin.Domain] admin do diff --git a/lib/agent_jido/forge/manager.ex b/lib/agent_jido/forge/manager.ex index a4ca404..6c388fa 100644 --- a/lib/agent_jido/forge/manager.ex +++ b/lib/agent_jido/forge/manager.ex @@ -90,46 +90,11 @@ defmodule AgentJido.Forge.Manager do def handle_call({:start_session, session_id, spec}, _from, state) do runner_type = Map.get(spec, :runner) || Map.get(spec, :runner_type) || Map.get(spec, "runner_type") || :shell - cond do - MapSet.size(state.sessions) >= state.max_sessions -> - {:reply, {:error, :max_sessions_reached}, state} - - Map.get(state.runner_counts, runner_type, 0) >= - Map.get(state.max_per_runner, runner_type, 100) -> - {:reply, {:error, {:runner_limit_reached, runner_type}}, state} - - true -> - case Registry.lookup(@registry, session_id) do - [{pid, _}] -> - {:reply, {:error, {:already_started, pid}}, state} - - [] -> - Persistence.record_session_started(session_id, spec) - - child_spec = {SpriteSession, {session_id, spec, []}} - - case DynamicSupervisor.start_child(@supervisor, child_spec) do - {:ok, pid} -> - Process.monitor(pid) - new_sessions = MapSet.put(state.sessions, session_id) - new_session_runners = Map.put(state.session_runners, session_id, runner_type) - new_runner_counts = Map.update(state.runner_counts, runner_type, 1, &(&1 + 1)) - - Logger.debug("Started session #{session_id} with pid #{inspect(pid)}") - ForgePubSub.broadcast_sessions({:session_started, session_id}) - - {:reply, {:ok, pid}, - %{ - state - | sessions: new_sessions, - session_runners: new_session_runners, - runner_counts: new_runner_counts - }} - - {:error, reason} -> - {:reply, {:error, reason}, state} - end - end + with :ok <- check_session_limits(state, runner_type), + :ok <- check_session_not_running(session_id) do + do_start_session(session_id, spec, runner_type, state) + else + {:error, reason} -> {:reply, {:error, reason}, state} end end @@ -168,6 +133,52 @@ defmodule AgentJido.Forge.Manager do {:noreply, new_state} end + defp check_session_limits(state, runner_type) do + cond do + MapSet.size(state.sessions) >= state.max_sessions -> + {:error, :max_sessions_reached} + + Map.get(state.runner_counts, runner_type, 0) >= Map.get(state.max_per_runner, runner_type, 100) -> + {:error, {:runner_limit_reached, runner_type}} + + true -> + :ok + end + end + + defp check_session_not_running(session_id) do + case Registry.lookup(@registry, session_id) do + [{pid, _}] -> {:error, {:already_started, pid}} + [] -> :ok + end + end + + defp do_start_session(session_id, spec, runner_type, state) do + Persistence.record_session_started(session_id, spec) + child_spec = {SpriteSession, {session_id, spec, []}} + + case DynamicSupervisor.start_child(@supervisor, child_spec) do + {:ok, pid} -> + Process.monitor(pid) + new_state = update_state_for_started_session(state, session_id, runner_type) + Logger.debug("Started session #{session_id} with pid #{inspect(pid)}") + ForgePubSub.broadcast_sessions({:session_started, session_id}) + {:reply, {:ok, pid}, new_state} + + {:error, reason} -> + {:reply, {:error, reason}, state} + end + end + + defp update_state_for_started_session(state, session_id, runner_type) do + %{ + state + | sessions: MapSet.put(state.sessions, session_id), + session_runners: Map.put(state.session_runners, session_id, runner_type), + runner_counts: Map.update(state.runner_counts, runner_type, 1, &(&1 + 1)) + } + end + defp decrement_session(state, session_id) do runner_type = Map.get(state.session_runners, session_id) diff --git a/lib/agent_jido/forge/operations.ex b/lib/agent_jido/forge/operations.ex index ccefe55..dba6dc8 100644 --- a/lib/agent_jido/forge/operations.ex +++ b/lib/agent_jido/forge/operations.ex @@ -10,7 +10,7 @@ defmodule AgentJido.Forge.Operations do require Logger alias AgentJido.Forge.{Manager, PubSub} - alias AgentJido.Forge.Resources.{Session, Event, Checkpoint} + alias AgentJido.Forge.Resources.{Checkpoint, Event, Session} @doc """ Resume a session from its last checkpoint. diff --git a/lib/agent_jido/forge/persistence.ex b/lib/agent_jido/forge/persistence.ex index e3a7ed4..9856a59 100644 --- a/lib/agent_jido/forge/persistence.ex +++ b/lib/agent_jido/forge/persistence.ex @@ -21,7 +21,7 @@ defmodule AgentJido.Forge.Persistence do require Logger - alias AgentJido.Forge.Resources.{Session, Event, ExecSession} + alias AgentJido.Forge.Resources.{Event, ExecSession, Session} @doc """ Check if persistence is enabled. @@ -187,22 +187,24 @@ defmodule AgentJido.Forge.Persistence do @spec log_event(String.t(), String.t(), map()) :: :ok def log_event(session_id, event_type, data \\ %{}) do if enabled?() do - Task.start(fn -> - with {:ok, session} <- find_session(session_id) do - Event - |> Ash.Changeset.for_create(:log, %{ - session_id: session.id, - event_type: event_type, - data: data - }) - |> Ash.create() - end - end) + Task.start(fn -> do_log_event(session_id, event_type, data) end) end :ok end + defp do_log_event(session_id, event_type, data) do + with {:ok, session} <- find_session(session_id) do + Event + |> Ash.Changeset.for_create(:log, %{ + session_id: session.id, + event_type: event_type, + data: data + }) + |> Ash.create() + end + end + # Private helpers defp find_session(session_id) when is_binary(session_id) do diff --git a/lib/agent_jido/forge/resources/checkpoint.ex b/lib/agent_jido/forge/resources/checkpoint.ex index be6c33d..3761dc6 100644 --- a/lib/agent_jido/forge/resources/checkpoint.ex +++ b/lib/agent_jido/forge/resources/checkpoint.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Forge.Resources.Checkpoint do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Forge.Domain, diff --git a/lib/agent_jido/forge/resources/event.ex b/lib/agent_jido/forge/resources/event.ex index 2228586..158de94 100644 --- a/lib/agent_jido/forge/resources/event.ex +++ b/lib/agent_jido/forge/resources/event.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Forge.Resources.Event do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Forge.Domain, diff --git a/lib/agent_jido/forge/resources/exec_session.ex b/lib/agent_jido/forge/resources/exec_session.ex index f68cb49..815b2a9 100644 --- a/lib/agent_jido/forge/resources/exec_session.ex +++ b/lib/agent_jido/forge/resources/exec_session.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Forge.Resources.ExecSession do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Forge.Domain, diff --git a/lib/agent_jido/forge/resources/session.ex b/lib/agent_jido/forge/resources/session.ex index eeef6f0..2efedf1 100644 --- a/lib/agent_jido/forge/resources/session.ex +++ b/lib/agent_jido/forge/resources/session.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Forge.Resources.Session do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Forge.Domain, diff --git a/lib/agent_jido/forge/resources/sprite_spec.ex b/lib/agent_jido/forge/resources/sprite_spec.ex index cd65da9..40298f3 100644 --- a/lib/agent_jido/forge/resources/sprite_spec.ex +++ b/lib/agent_jido/forge/resources/sprite_spec.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Forge.Resources.SpriteSpec do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Forge.Domain, diff --git a/lib/agent_jido/forge/resources/workflow.ex b/lib/agent_jido/forge/resources/workflow.ex index d9bcbc5..8a448e2 100644 --- a/lib/agent_jido/forge/resources/workflow.ex +++ b/lib/agent_jido/forge/resources/workflow.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Forge.Resources.Workflow do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.Forge.Domain, diff --git a/lib/agent_jido/forge/runners/claude_code.ex b/lib/agent_jido/forge/runners/claude_code.ex index cda86ce..3773775 100644 --- a/lib/agent_jido/forge/runners/claude_code.ex +++ b/lib/agent_jido/forge/runners/claude_code.ex @@ -33,35 +33,39 @@ defmodule AgentJido.Forge.Runners.ClaudeCode do @impl true def init(client, config) do with :ok <- setup_directories(client), - :ok <- setup_claude_settings(client, config), - :ok <- setup_templates(client, config) do - :ok + :ok <- setup_claude_settings(client, config) do + setup_templates(client, config) end end @impl true def run_iteration(client, state, opts) do + {model, max_turns, max_budget, prompt} = resolve_run_options(state, opts) + cmd = build_claude_command(model, max_turns, max_budget, prompt) + + client + |> SpriteClient.exec(cmd, timeout: :infinity) + |> handle_exec_result() + end + + defp resolve_run_options(state, opts) do model = opts[:model] || state[:model] || "claude-sonnet-4-20250514" max_turns = opts[:max_turns] || state[:max_turns] || 200 max_budget = opts[:max_budget] || state[:max_budget] || 10.0 prompt = opts[:prompt] || state[:prompt] + {model, max_turns, max_budget, prompt} + end - cmd = build_claude_command(model, max_turns, max_budget, prompt) + defp handle_exec_result({output, 0}), do: {:ok, parse_claude_output(output)} - case SpriteClient.exec(client, cmd, timeout: :infinity) do - {output, 0} -> - result = parse_claude_output(output) - {:ok, result} - - {output, code} -> - {:ok, - %{ - status: :error, - output: output, - error: "Claude exited with code #{code}", - metadata: %{exit_code: code} - }} - end + defp handle_exec_result({output, code}) do + {:ok, + %{ + status: :error, + output: output, + error: "Claude exited with code #{code}", + metadata: %{exit_code: code} + }} end @impl true @@ -115,9 +119,8 @@ defmodule AgentJido.Forge.Runners.ClaudeCode do end defp setup_templates(client, config) do - with :ok <- maybe_write_template(client, config, :prompt_template, "iterate.md"), - :ok <- maybe_write_template(client, config, :context_template, "context.md") do - :ok + with :ok <- maybe_write_template(client, config, :prompt_template, "iterate.md") do + maybe_write_template(client, config, :context_template, "context.md") end end diff --git a/lib/agent_jido/forge/sprite_client/fake.ex b/lib/agent_jido/forge/sprite_client/fake.ex index ce1a579..d0434a7 100644 --- a/lib/agent_jido/forge/sprite_client/fake.ex +++ b/lib/agent_jido/forge/sprite_client/fake.ex @@ -173,18 +173,7 @@ defmodule AgentJido.Forge.SpriteClient.Fake do case Map.keys(sprites) do [sprite_id | _] -> - Agent.update(agent_pid, fn sprites -> - update_in(sprites, [sprite_id, :env], fn existing_env -> - # Normalize all env values to strings (binaries) - normalized_map = - env_map - |> Enum.map(fn {k, v} -> {to_binary_string(k), to_binary_string(v)} end) - |> Map.new() - - Map.merge(existing_env || %{}, normalized_map) - end) - end) - + Agent.update(agent_pid, &merge_env_into_sprite(&1, sprite_id, env_map)) :ok [] -> @@ -192,6 +181,17 @@ defmodule AgentJido.Forge.SpriteClient.Fake do end end + defp merge_env_into_sprite(sprites, sprite_id, env_map) do + normalized_map = normalize_env_map(env_map) + update_in(sprites, [sprite_id, :env], &Map.merge(&1 || %{}, normalized_map)) + end + + defp normalize_env_map(env_map) do + env_map + |> Enum.map(fn {k, v} -> {to_binary_string(k), to_binary_string(v)} end) + |> Map.new() + end + @impl true def destroy(%__MODULE__{agent_pid: agent_pid} = _client, sprite_id) do ensure_agent_started(agent_pid) diff --git a/lib/agent_jido/forge/sprite_client/live.ex b/lib/agent_jido/forge/sprite_client/live.ex index f3c0ab5..b5163cd 100644 --- a/lib/agent_jido/forge/sprite_client/live.ex +++ b/lib/agent_jido/forge/sprite_client/live.ex @@ -131,9 +131,7 @@ defmodule AgentJido.Forge.SpriteClient.Live do def inject_env(%__MODULE__{sprite: sprite} = _client, env_map) do env_lines = - env_map - |> Enum.map(fn {k, v} -> "export #{k}=\"#{escape_value(v)}\"" end) - |> Enum.join("\n") + Enum.map_join(env_map, "\n", fn {k, v} -> "export #{k}=\"#{escape_value(v)}\"" end) encoded = Base.encode64(env_lines <> "\n") diff --git a/lib/agent_jido/forge/workers/streaming_exec_session_worker.ex b/lib/agent_jido/forge/workers/streaming_exec_session_worker.ex index 46242da..6cbddb5 100644 --- a/lib/agent_jido/forge/workers/streaming_exec_session_worker.ex +++ b/lib/agent_jido/forge/workers/streaming_exec_session_worker.ex @@ -11,7 +11,7 @@ defmodule AgentJido.Forge.Workers.StreamingExecSessionWorker do require Logger alias AgentJido.Forge.PubSub, as: ForgePubSub - alias AgentJido.Forge.Resources.{ExecSession, Event} + alias AgentJido.Forge.Resources.{Event, ExecSession} @chunk_coalesce_ms 50 @max_buffer_size 64 * 1024 diff --git a/lib/agent_jido/github.ex b/lib/agent_jido/github.ex index d28ddb2..5d0b96b 100644 --- a/lib/agent_jido/github.ex +++ b/lib/agent_jido/github.ex @@ -1,4 +1,5 @@ defmodule AgentJido.GitHub do + @moduledoc false use Ash.Domain, otp_app: :agent_jido, extensions: [AshAdmin.Domain] admin do diff --git a/lib/agent_jido/github/issue_analysis.ex b/lib/agent_jido/github/issue_analysis.ex index 1732006..a9f8089 100644 --- a/lib/agent_jido/github/issue_analysis.ex +++ b/lib/agent_jido/github/issue_analysis.ex @@ -1,4 +1,5 @@ defmodule AgentJido.GitHub.IssueAnalysis do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.GitHub, diff --git a/lib/agent_jido/github/webhook_delivery.ex b/lib/agent_jido/github/webhook_delivery.ex index 4365c1d..94a22f3 100644 --- a/lib/agent_jido/github/webhook_delivery.ex +++ b/lib/agent_jido/github/webhook_delivery.ex @@ -1,4 +1,5 @@ defmodule AgentJido.GitHub.WebhookDelivery do + @moduledoc false use Ash.Resource, otp_app: :agent_jido, domain: AgentJido.GitHub, diff --git a/lib/agent_jido/github_issue_bot/cli/run.ex b/lib/agent_jido/github_issue_bot/cli/run.ex index 9f8a706..1f24156 100644 --- a/lib/agent_jido/github_issue_bot/cli/run.ex +++ b/lib/agent_jido/github_issue_bot/cli/run.ex @@ -10,9 +10,9 @@ defmodule AgentJido.GithubIssueBot.CLI.Run do mix run -e "AgentJido.GithubIssueBot.CLI.Run.run(run_id: \\"test-run\\")" """ + alias AgentJido.GithubIssueBot.IssueRun.CoordinatorAgent alias Jido.AgentServer alias Jido.Signal - alias AgentJido.GithubIssueBot.IssueRun.CoordinatorAgent require Logger @@ -119,7 +119,7 @@ defmodule AgentJido.GithubIssueBot.CLI.Run do Enum.each(artifacts, fn {name, artifact} -> IO.puts("\n--- #{name} ---") - IO.inspect(artifact, pretty: true, limit: :infinity) + IO.puts(inspect(artifact, pretty: true, limit: :infinity)) end) end @@ -132,9 +132,9 @@ defmodule AgentJido.GithubIssueBot.CLI.Run do print_artifacts(state.artifacts) end - if length(state.errors) > 0 do + if state.errors != [] do IO.puts("\n--- Errors ---") - Enum.each(state.errors, &IO.inspect/1) + Enum.each(state.errors, fn error -> IO.puts(inspect(error)) end) end end end diff --git a/lib/agent_jido/github_issue_bot/issue_run/actions/research_result_action.ex b/lib/agent_jido/github_issue_bot/issue_run/actions/research_result_action.ex index 94bd94b..14ef900 100644 --- a/lib/agent_jido/github_issue_bot/issue_run/actions/research_result_action.ex +++ b/lib/agent_jido/github_issue_bot/issue_run/actions/research_result_action.ex @@ -18,8 +18,8 @@ defmodule AgentJido.GithubIssueBot.IssueRun.Actions.ResearchResultAction do summary: [type: :string, default: ""] ] - alias Jido.Agent.Directive alias AgentJido.GithubIssueBot.PullRequest.PullRequestCoordinator + alias Jido.Agent.Directive require Logger diff --git a/lib/agent_jido/github_issue_bot/issue_run/actions/start_run_action.ex b/lib/agent_jido/github_issue_bot/issue_run/actions/start_run_action.ex index 769f2c0..ef3b15b 100644 --- a/lib/agent_jido/github_issue_bot/issue_run/actions/start_run_action.ex +++ b/lib/agent_jido/github_issue_bot/issue_run/actions/start_run_action.ex @@ -11,8 +11,8 @@ defmodule AgentJido.GithubIssueBot.IssueRun.Actions.StartRunAction do issue: [type: :map, required: true] ] - alias Jido.Agent.Directive alias AgentJido.GithubIssueBot.Triage.TriageAgent + alias Jido.Agent.Directive require Logger diff --git a/lib/agent_jido/github_issue_bot/issue_run/actions/triage_result_action.ex b/lib/agent_jido/github_issue_bot/issue_run/actions/triage_result_action.ex index 0d743fe..4ac2530 100644 --- a/lib/agent_jido/github_issue_bot/issue_run/actions/triage_result_action.ex +++ b/lib/agent_jido/github_issue_bot/issue_run/actions/triage_result_action.ex @@ -14,8 +14,8 @@ defmodule AgentJido.GithubIssueBot.IssueRun.Actions.TriageResultAction do summary: [type: :string, default: ""] ] - alias Jido.Agent.Directive alias AgentJido.GithubIssueBot.Research.ResearchCoordinator + alias Jido.Agent.Directive require Logger diff --git a/lib/agent_jido/github_issue_bot/issue_run/coordinator_agent.ex b/lib/agent_jido/github_issue_bot/issue_run/coordinator_agent.ex index d9f6e46..e05157e 100644 --- a/lib/agent_jido/github_issue_bot/issue_run/coordinator_agent.ex +++ b/lib/agent_jido/github_issue_bot/issue_run/coordinator_agent.ex @@ -40,11 +40,11 @@ defmodule AgentJido.GithubIssueBot.IssueRun.CoordinatorAgent do ] alias AgentJido.GithubIssueBot.IssueRun.Actions.{ - StartRunAction, ChildStartedAction, - TriageResultAction, + PullRequestResultAction, ResearchResultAction, - PullRequestResultAction + StartRunAction, + TriageResultAction } def signal_routes do diff --git a/lib/agent_jido/github_issue_bot/pull_request/actions/patch_result_action.ex b/lib/agent_jido/github_issue_bot/pull_request/actions/patch_result_action.ex index efdf034..0a1dc05 100644 --- a/lib/agent_jido/github_issue_bot/pull_request/actions/patch_result_action.ex +++ b/lib/agent_jido/github_issue_bot/pull_request/actions/patch_result_action.ex @@ -12,8 +12,8 @@ defmodule AgentJido.GithubIssueBot.PullRequest.Actions.PatchResultAction do result: [type: :map, required: true] ] - alias Jido.Agent.Directive alias AgentJido.GithubIssueBot.PullRequest.Workers.QualityAgent + alias Jido.Agent.Directive require Logger diff --git a/lib/agent_jido/github_issue_bot/pull_request/actions/start_pull_request_action.ex b/lib/agent_jido/github_issue_bot/pull_request/actions/start_pull_request_action.ex index 6613999..8f70dd2 100644 --- a/lib/agent_jido/github_issue_bot/pull_request/actions/start_pull_request_action.ex +++ b/lib/agent_jido/github_issue_bot/pull_request/actions/start_pull_request_action.ex @@ -23,8 +23,8 @@ defmodule AgentJido.GithubIssueBot.PullRequest.Actions.StartPullRequestAction do research: [type: :map, required: true] ] - alias Jido.Agent.Directive alias AgentJido.GithubIssueBot.PullRequest.Workers.PatchAgent + alias Jido.Agent.Directive require Logger diff --git a/lib/agent_jido/github_issue_bot/pull_request/pull_request_coordinator.ex b/lib/agent_jido/github_issue_bot/pull_request/pull_request_coordinator.ex index 4729d13..886789e 100644 --- a/lib/agent_jido/github_issue_bot/pull_request/pull_request_coordinator.ex +++ b/lib/agent_jido/github_issue_bot/pull_request/pull_request_coordinator.ex @@ -64,11 +64,11 @@ defmodule AgentJido.GithubIssueBot.PullRequest.PullRequestCoordinator do ] alias AgentJido.GithubIssueBot.PullRequest.Actions.{ - StartPullRequestAction, - WorkerStartedAction, PatchResultAction, + PRSubmitResultAction, QualityResultAction, - PRSubmitResultAction + StartPullRequestAction, + WorkerStartedAction } def signal_routes do diff --git a/lib/agent_jido/github_issue_bot/research/actions/start_research_action.ex b/lib/agent_jido/github_issue_bot/research/actions/start_research_action.ex index a01370f..915b8a2 100644 --- a/lib/agent_jido/github_issue_bot/research/actions/start_research_action.ex +++ b/lib/agent_jido/github_issue_bot/research/actions/start_research_action.ex @@ -18,15 +18,15 @@ defmodule AgentJido.GithubIssueBot.Research.Actions.StartResearchAction do triage: [type: :map, required: true] ] - alias Jido.Agent.Directive - alias AgentJido.GithubIssueBot.Research.Workers.{ CodeSearchAgent, + PRSearchAgent, ReproductionAgent, - RootCauseAgent, - PRSearchAgent + RootCauseAgent } + alias Jido.Agent.Directive + require Logger # Workers to spawn - each gets a tag for identification diff --git a/lib/agent_jido/github_issue_bot/research/actions/worker_result_action.ex b/lib/agent_jido/github_issue_bot/research/actions/worker_result_action.ex index c4018d1..525df80 100644 --- a/lib/agent_jido/github_issue_bot/research/actions/worker_result_action.ex +++ b/lib/agent_jido/github_issue_bot/research/actions/worker_result_action.ex @@ -109,12 +109,10 @@ defmodule AgentJido.GithubIssueBot.Research.Actions.WorkerResultAction do # TODO: Could use LLM to synthesize a coherent narrative defp synthesize_summary(worker_results) do parts = - worker_results - |> Enum.map(fn {worker, result} -> + Enum.map_join(worker_results, "; ", fn {worker, result} -> summary = Map.get(result, :summary, "No summary") "#{worker}: #{summary}" end) - |> Enum.join("; ") "Research complete. #{parts}" end diff --git a/lib/agent_jido/github_issue_bot/research/research_coordinator.ex b/lib/agent_jido/github_issue_bot/research/research_coordinator.ex index a787e4f..5a1c6d2 100644 --- a/lib/agent_jido/github_issue_bot/research/research_coordinator.ex +++ b/lib/agent_jido/github_issue_bot/research/research_coordinator.ex @@ -45,8 +45,8 @@ defmodule AgentJido.GithubIssueBot.Research.ResearchCoordinator do alias AgentJido.GithubIssueBot.Research.Actions.{ StartResearchAction, - WorkerStartedAction, - WorkerResultAction + WorkerResultAction, + WorkerStartedAction } def signal_routes do diff --git a/lib/agent_jido/github_issue_bot/research/workers/actions/root_cause_action.ex b/lib/agent_jido/github_issue_bot/research/workers/actions/root_cause_action.ex index 5db542c..010ee37 100644 --- a/lib/agent_jido/github_issue_bot/research/workers/actions/root_cause_action.ex +++ b/lib/agent_jido/github_issue_bot/research/workers/actions/root_cause_action.ex @@ -80,33 +80,21 @@ defmodule AgentJido.GithubIssueBot.Research.Workers.Actions.RootCauseAction do # Generate hypothesis based on keywords and classification defp hypothesize(title, body, classification) do cond do - # State-related issues - String.contains?(body, "state") and String.contains?(body, "persist") -> - {"State serialization/deserialization issue", :medium, "lib/core/state.ex"} - - String.contains?(body, "state") and String.contains?(body, "lost") -> - {"State not being saved properly", :medium, "lib/core/agent.ex"} - - # Concurrency issues - String.contains?(body, "race") or String.contains?(body, "concurrent") -> - {"Race condition in concurrent operations", :low, "lib/core/"} - - # Error handling - String.contains?(title, "error") or String.contains?(body, "exception") -> - {"Unhandled error case", :medium, "lib/"} - - # Classification-based fallbacks - classification == :bug -> - {"Logic error in core functionality", :low, "lib/"} - - classification == :feature -> - {"Missing feature implementation", :high, "lib/"} - - true -> - {"Unable to determine root cause", :low, nil} + state_persist_issue?(body) -> {"State serialization/deserialization issue", :medium, "lib/core/state.ex"} + state_lost_issue?(body) -> {"State not being saved properly", :medium, "lib/core/agent.ex"} + concurrency_issue?(body) -> {"Race condition in concurrent operations", :low, "lib/core/"} + error_handling_issue?(title, body) -> {"Unhandled error case", :medium, "lib/"} + classification == :bug -> {"Logic error in core functionality", :low, "lib/"} + classification == :feature -> {"Missing feature implementation", :high, "lib/"} + true -> {"Unable to determine root cause", :low, nil} end end + defp state_persist_issue?(body), do: String.contains?(body, "state") and String.contains?(body, "persist") + defp state_lost_issue?(body), do: String.contains?(body, "state") and String.contains?(body, "lost") + defp concurrency_issue?(body), do: String.contains?(body, "race") or String.contains?(body, "concurrent") + defp error_handling_issue?(title, body), do: String.contains?(title, "error") or String.contains?(body, "exception") + # Extract evidence from issue body defp extract_evidence(body) do evidence = [] diff --git a/lib/agent_jido/github_issue_bot/triage/actions/triage_action.ex b/lib/agent_jido/github_issue_bot/triage/actions/triage_action.ex index 6c8a5de..5a4a5be 100644 --- a/lib/agent_jido/github_issue_bot/triage/actions/triage_action.ex +++ b/lib/agent_jido/github_issue_bot/triage/actions/triage_action.ex @@ -55,22 +55,29 @@ defmodule AgentJido.GithubIssueBot.Triage.Actions.TriageAction do defp classify(title, _body, labels) do cond do - "bug" in labels or String.contains?(title, "bug") or String.contains?(title, "error") -> - :bug + bug?(title, labels) -> :bug + feature?(title, labels) -> :feature + question?(title, labels) -> :question + documentation?(title, labels) -> :documentation + true -> :unknown + end + end - "feature" in labels or "enhancement" in labels or - String.contains?(title, "feature") or String.contains?(title, "add") -> - :feature + defp bug?(title, labels) do + "bug" in labels or String.contains?(title, "bug") or String.contains?(title, "error") + end - "question" in labels or String.contains?(title, "?") -> - :question + defp feature?(title, labels) do + "feature" in labels or "enhancement" in labels or + String.contains?(title, "feature") or String.contains?(title, "add") + end - "documentation" in labels or String.contains?(title, "docs") -> - :documentation + defp question?(title, labels) do + "question" in labels or String.contains?(title, "?") + end - true -> - :unknown - end + defp documentation?(title, labels) do + "documentation" in labels or String.contains?(title, "docs") end defp needs_more_info?(body) do diff --git a/lib/agent_jido/secrets.ex b/lib/agent_jido/secrets.ex index 6c42606..84e8d68 100644 --- a/lib/agent_jido/secrets.ex +++ b/lib/agent_jido/secrets.ex @@ -1,4 +1,5 @@ defmodule AgentJido.Secrets do + @moduledoc false use AshAuthentication.Secret def secret_for( diff --git a/lib/agent_jido_web.ex b/lib/agent_jido_web.ex index 6d4adea..212b0d0 100644 --- a/lib/agent_jido_web.ex +++ b/lib/agent_jido_web.ex @@ -88,8 +88,8 @@ defmodule AgentJidoWeb do use AgentJidoWeb.Components.MishkaComponents # Common modules used in templates - alias Phoenix.LiveView.JS alias AgentJidoWeb.Layouts + alias Phoenix.LiveView.JS # Routes generation with the ~p sigil unquote(verified_routes()) diff --git a/lib/agent_jido_web/ash_json_api_router.ex b/lib/agent_jido_web/ash_json_api_router.ex index 3b64b48..165d4d6 100644 --- a/lib/agent_jido_web/ash_json_api_router.ex +++ b/lib/agent_jido_web/ash_json_api_router.ex @@ -1,4 +1,5 @@ defmodule AgentJidoWeb.AshJsonApiRouter do + @moduledoc false use AshJsonApi.Router, domains: [], open_api: "/open_api" diff --git a/lib/agent_jido_web/auth_overrides.ex b/lib/agent_jido_web/auth_overrides.ex index 5b388ab..28fc9ab 100644 --- a/lib/agent_jido_web/auth_overrides.ex +++ b/lib/agent_jido_web/auth_overrides.ex @@ -1,4 +1,5 @@ defmodule AgentJidoWeb.AuthOverrides do + @moduledoc false use AshAuthentication.Phoenix.Overrides # configure your UI overrides here diff --git a/lib/agent_jido_web/components/accordion.ex b/lib/agent_jido_web/components/accordion.ex index 792acd4..67776b5 100644 --- a/lib/agent_jido_web/components/accordion.ex +++ b/lib/agent_jido_web/components/accordion.ex @@ -150,8 +150,8 @@ defmodule AgentJidoWeb.Components.Accordion do |> Enum.map(& &1.id) cond do - length(initial_open) > 0 -> Enum.join(initial_open, ",") - length(slot_open_items) > 0 -> Enum.join(slot_open_items, ",") + initial_open != [] -> Enum.join(initial_open, ",") + slot_open_items != [] -> Enum.join(slot_open_items, ",") true -> "" end end diff --git a/lib/agent_jido_web/components/breadcrumb.ex b/lib/agent_jido_web/components/breadcrumb.ex index 19609cb..e476b4b 100644 --- a/lib/agent_jido_web/components/breadcrumb.ex +++ b/lib/agent_jido_web/components/breadcrumb.ex @@ -249,7 +249,7 @@ defmodule AgentJidoWeb.Components.Breadcrumb do defp size_class(params) when is_binary(params), do: params - defp default_classes() do + defp default_classes do [ "flex items-center transition-all ease-in-out duration-100 group" ] diff --git a/lib/agent_jido_web/components/button.ex b/lib/agent_jido_web/components/button.ex index e9bac8b..b8ac11a 100644 --- a/lib/agent_jido_web/components/button.ex +++ b/lib/agent_jido_web/components/button.ex @@ -191,7 +191,7 @@ defmodule AgentJidoWeb.Components.Button do end def button(assigns) do - assigns = assign_new(assigns, :indicator, fn -> is_indicators?(assigns[:rest]) end) + assigns = assign_new(assigns, :indicator, fn -> has_indicators?(assigns[:rest]) end) ~H"""