brainiac-discord 0.0.11 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f90a4cf177bc62d55f5773e21f3b5e05aaefbdbff94bae975fcbcb21ae3dbb64
|
|
4
|
+
data.tar.gz: a9dc84c5ab058a8173c96a6bda909a5ea8959a36fe61065d316b0b408ab2eb54
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c7df8598d6a702644e25c18c76c49aa8f406fa3c0806b2ba9a4eccf0859615fffc027e056d66d2ac42b4d737fdb7b7c00f62e2c2b629a4ee4e4e1adfa9844030
|
|
7
|
+
data.tar.gz: f7e4ddc91b9d0b819f82000e276f9490fa4fdc8454fd475ef49d09de5d58b917e988be95df2ec8577a4d55cca4ec186cc4cc1d486022912840e49767a41371ee
|
|
@@ -558,8 +558,24 @@ module Brainiac
|
|
|
558
558
|
)
|
|
559
559
|
end
|
|
560
560
|
|
|
561
|
+
# Resolve CLI overrides and work_dir BEFORE building the prompt so we can determine
|
|
562
|
+
# whether resume will actually work. This prevents sending a lean prompt when
|
|
563
|
+
# the CLI won't actually have session state.
|
|
564
|
+
work_dir = chat_mode_fallback(agent_key, agent_name, message_id, chat_mode, thread_worktree_path) ||
|
|
565
|
+
(project_config ? project_config["repo_path"] : Dir.pwd)
|
|
566
|
+
model, effort, cli_provider_override = resolve_overrides(
|
|
567
|
+
clean_content, project_config, thread_model, thread_effort, thread_cli_provider
|
|
568
|
+
)
|
|
569
|
+
resolved = resolve_project_cli_config(project_config || DEFAULT_PROJECT,
|
|
570
|
+
cli_provider_override: cli_provider_override, agent_name: agent_name)
|
|
571
|
+
|
|
572
|
+
# Convert should_resume to the actual flag/symbol. If resolve_resume returns false,
|
|
573
|
+
# we know the CLI won't actually resume, so we shouldn't send a lean prompt.
|
|
574
|
+
actual_resume = should_resume ? resolve_resume(true, resolved, work_dir) : false
|
|
575
|
+
use_lean_prompt = actual_resume && thread_worktree_path
|
|
576
|
+
|
|
561
577
|
prompt = build_prompt(
|
|
562
|
-
should_resume:
|
|
578
|
+
should_resume: use_lean_prompt, thread_worktree_path: thread_worktree_path,
|
|
563
579
|
clean_content_for_prompt: clean_content_for_prompt,
|
|
564
580
|
discord_user: discord_user, channel_name: channel_info&.dig("name") || channel_id, reply_context: reply_context,
|
|
565
581
|
channel_history: channel_history, thread_root_context: thread_root_context,
|
|
@@ -567,15 +583,9 @@ module Brainiac
|
|
|
567
583
|
brain_context: brain_context, agent_name: agent_name, supersede_key: supersede_key
|
|
568
584
|
)
|
|
569
585
|
|
|
570
|
-
work_dir = chat_mode_fallback(agent_key, agent_name, message_id, chat_mode, thread_worktree_path) ||
|
|
571
|
-
(project_config ? project_config["repo_path"] : Dir.pwd)
|
|
572
586
|
prompt_file = File.join(response_dir, "discord-prompt-#{timestamp}-#{agent_key}-#{message_id}.md")
|
|
573
587
|
File.write(prompt_file, prompt)
|
|
574
588
|
|
|
575
|
-
model, effort, cli_provider_override = resolve_overrides(
|
|
576
|
-
clean_content, project_config, thread_model, thread_effort, thread_cli_provider
|
|
577
|
-
)
|
|
578
|
-
|
|
579
589
|
persist_overrides(thread_map_key, clean_content, project_config,
|
|
580
590
|
cli_provider: cli_provider_override, model: model, effort: effort,
|
|
581
591
|
prev_cli_provider: thread_cli_provider, prev_model: thread_model, prev_effort: thread_effort)
|
|
@@ -592,8 +602,8 @@ module Brainiac
|
|
|
592
602
|
agent_key: agent_key, agent_name: agent_name, bot_token: bot_token,
|
|
593
603
|
channel_id: channel_id, message_id: message_id, discord_user: discord_user,
|
|
594
604
|
work_dir: work_dir, prompt_file: prompt_file, response_file: response_file,
|
|
595
|
-
meta_file: meta_file, model: model, effort: effort,
|
|
596
|
-
|
|
605
|
+
meta_file: meta_file, model: model, effort: effort, actual_resume: actual_resume,
|
|
606
|
+
resolved: resolved, project_config: project_config,
|
|
597
607
|
session_key: session_key, supersede_key: supersede_key,
|
|
598
608
|
attachment_paths: attachment_paths, timestamp: timestamp, response_dir: response_dir
|
|
599
609
|
)
|
|
@@ -816,6 +826,13 @@ module Brainiac
|
|
|
816
826
|
debounced_repo_fetch(repo_path)
|
|
817
827
|
worktree_path = create_or_reuse_worktree(repo_path: repo_path, branch: branch)
|
|
818
828
|
|
|
829
|
+
# Register a work item so brainiac-github can route PR comments/reviews back
|
|
830
|
+
# to the agent that actually owns this Discord thread's worktree. Without this,
|
|
831
|
+
# PRs created from a conversational session have no work item and comments
|
|
832
|
+
# fall back to the project's default agent.
|
|
833
|
+
project_key = PROJECTS.find { |_k, v| v == project_config }&.first
|
|
834
|
+
register_work_item(branch: branch, worktree: worktree_path, project: project_key, agent: agent_name)
|
|
835
|
+
|
|
819
836
|
cli, model, effort = detect_thread_overrides(
|
|
820
837
|
project_config, clean_content,
|
|
821
838
|
fallback_cli: existing&.dig("cli_provider"),
|
|
@@ -886,17 +903,15 @@ module Brainiac
|
|
|
886
903
|
|
|
887
904
|
def spawn_agent(agent_key:, agent_name:, bot_token:, channel_id:, message_id:, discord_user:,
|
|
888
905
|
work_dir:, prompt_file:, response_file:, meta_file:, model:, effort:,
|
|
889
|
-
|
|
906
|
+
actual_resume:, resolved:, project_config:,
|
|
890
907
|
session_key:, supersede_key:, attachment_paths:, timestamp:, response_dir:)
|
|
891
908
|
agent_config_name = agent_key.downcase.gsub(/[^a-z0-9-]/, "-")
|
|
892
909
|
log_file = File.join(response_dir, "discord-agent-#{timestamp}-#{agent_key}-#{message_id}.log")
|
|
893
910
|
|
|
894
|
-
resolved = resolve_project_cli_config(project_config || DEFAULT_PROJECT,
|
|
895
|
-
cli_provider_override: cli_provider_override, agent_name: agent_name)
|
|
896
911
|
cmd = build_agent_cmd(resolved, agent_config_name: agent_config_name, model: model, effort: effort,
|
|
897
|
-
prompt_file: prompt_file, resume:
|
|
912
|
+
prompt_file: prompt_file, resume: actual_resume)
|
|
898
913
|
|
|
899
|
-
resume_note =
|
|
914
|
+
resume_note = actual_resume ? ", resuming" : ""
|
|
900
915
|
if defined?(LOG)
|
|
901
916
|
LOG.info "[Discord:#{agent_name}] Dispatching for #{discord_user} " \
|
|
902
917
|
"(model: #{model || "default"}, effort: #{effort || "default"}, cli: #{resolved["agent_cli"]}#{resume_note}), tail -f #{log_file}"
|
|
@@ -910,6 +925,17 @@ module Brainiac
|
|
|
910
925
|
LOG.info "[Discord:#{agent_name}] Injecting #{agent_env.size} env var(s): #{agent_env.keys.join(", ")}" if defined?(LOG)
|
|
911
926
|
end
|
|
912
927
|
|
|
928
|
+
# Inject a GitHub App token so `gh`/`git` run as the agent's own bot
|
|
929
|
+
# identity (e.g. galen[bot]) instead of the host machine's personal
|
|
930
|
+
# `gh auth`. Without this, `gh pr create` in the prompt would open PRs
|
|
931
|
+
# under whoever is logged in on the box. No-op if the github plugin
|
|
932
|
+
# isn't loaded or the agent has no app configured.
|
|
933
|
+
gh_env = github_agent_token_env(agent_name, project_config)
|
|
934
|
+
unless gh_env.empty?
|
|
935
|
+
spawn_env.merge!(gh_env)
|
|
936
|
+
LOG.info "[Discord:#{agent_name}] Injecting GitHub App token (GH_TOKEN) for bot identity" if defined?(LOG)
|
|
937
|
+
end
|
|
938
|
+
|
|
913
939
|
head_before, status_before = capture_brainiac_state(project_config, work_dir)
|
|
914
940
|
prompt_mode = resolved["prompt_mode"] || "stdin"
|
|
915
941
|
|
|
@@ -936,6 +962,41 @@ module Brainiac
|
|
|
936
962
|
)
|
|
937
963
|
end
|
|
938
964
|
|
|
965
|
+
# Build a { "GH_TOKEN" => ... } env hash so the spawned agent's `gh`
|
|
966
|
+
# and `git` invocations authenticate as the agent's own GitHub App bot
|
|
967
|
+
# rather than the host's personal `gh auth`. This is what makes the
|
|
968
|
+
# prompt's `gh pr create` open PRs under e.g. galen[bot].
|
|
969
|
+
#
|
|
970
|
+
# Reuses the brainiac-github plugin's AppClient. The github plugin is
|
|
971
|
+
# optional, so everything is guarded: if it isn't loaded, or no app is
|
|
972
|
+
# configured for the agent (or the shared "brainiac" app), we return an
|
|
973
|
+
# empty hash and `gh` falls back to whatever's authenticated on the box.
|
|
974
|
+
def github_agent_token_env(agent_name, project_config)
|
|
975
|
+
return {} unless agent_name && project_config
|
|
976
|
+
|
|
977
|
+
repo = project_config["github_repo"]
|
|
978
|
+
return {} unless repo && !repo.to_s.empty?
|
|
979
|
+
|
|
980
|
+
return {} unless defined?(Brainiac::Plugins::Github::AppClient)
|
|
981
|
+
|
|
982
|
+
client = Brainiac::Plugins::Github::AppClient
|
|
983
|
+
effective_agent = if client.configured?(agent_name)
|
|
984
|
+
agent_name
|
|
985
|
+
elsif client.configured?("brainiac")
|
|
986
|
+
"brainiac"
|
|
987
|
+
end
|
|
988
|
+
return {} unless effective_agent
|
|
989
|
+
|
|
990
|
+
repo_owner = repo.to_s.split("/").first
|
|
991
|
+
token = client.installation_token_for(effective_agent, repo_owner: repo_owner)
|
|
992
|
+
return {} unless token && !token.empty?
|
|
993
|
+
|
|
994
|
+
{ "GH_TOKEN" => token }
|
|
995
|
+
rescue StandardError => e
|
|
996
|
+
LOG.warn "[Discord:#{agent_name}] Could not mint GitHub App token: #{e.message}" if defined?(LOG)
|
|
997
|
+
{}
|
|
998
|
+
end
|
|
999
|
+
|
|
939
1000
|
def capture_brainiac_state(project_config, work_dir)
|
|
940
1001
|
return [nil, nil] unless project_config
|
|
941
1002
|
|
|
@@ -48,8 +48,8 @@ module Brainiac
|
|
|
48
48
|
3. Make the changes, test if applicable
|
|
49
49
|
4. Commit with a clear message
|
|
50
50
|
5. Push the branch
|
|
51
|
-
6.
|
|
52
|
-
7.
|
|
51
|
+
6. Open a PR with `gh pr create --fill` (or with a descriptive body)
|
|
52
|
+
7. Summarize what you did in your response file, including a link to the PR
|
|
53
53
|
|
|
54
54
|
**When responding conversationally:**
|
|
55
55
|
- Answer questions about the codebase, architecture, conventions
|