brainiac 0.1.9 → 0.1.10

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: cedcfe4e4dfa26034cf0ded9746d8ff5bade886ec3d83774580d8334777d4d3c
4
- data.tar.gz: 96d1702d994f06f0a4f41870de6652258fc700a9f9df1b6193c347b2cce3b365
3
+ metadata.gz: e63254b890e44045e1c05872417234f86e34fdcd36a737c7565c4ee7efc74426
4
+ data.tar.gz: 630399ccb91dc4ef99b6f14619710c5893b6194354dc3a89f3d491cc4b226bdb
5
5
  SHA512:
6
- metadata.gz: 16a5c9937e67afe78bcba468dea8a4b75c73864c4a320b8d2da930a966bd618797b6285f765f772a99394d8925ba9438fe2b9012ccb94730908e97642148cdbb
7
- data.tar.gz: 95cd9275779731da352b0356e1da275f12511b960037512e829614a6b5e2a4a97e3b00ba0ceeefbdbcc8eff71a3f0717b9cc43fb3ee4d21b2b706361e4dfccc0
6
+ metadata.gz: d0a1f9cc0ca39aa87aec48c3b45132b7777e6dc6ca7f71006a78e6ebe00879c188d8cea9104822d2e32a3d1b65970d09d5271c558d5af10faa8d29a24bd182a5
7
+ data.tar.gz: '02884d9354a9b5946a28f58f0e0c70d4f98893554b773f1738aa6e2a9383850d4f7577c8d691c9ef11867f71a81c5327a5ac28922fc7b90a95311bb1ceb536c4'
@@ -704,9 +704,11 @@ def prior_session_exists?(chdir, agent_cli, session_dir: nil)
704
704
  return true if File.directory?(session_dir_local)
705
705
 
706
706
  # Fallback: look for recent session logs in tmp/ that suggest this CLI ran here before.
707
- # This covers CLIs that don't leave a dotdir but do leave logs via brainiac.
707
+ # This covers CLIs that don't leave a dotdir but do leave logs via brainiac. The logs
708
+ # don't say which CLI wrote them, so only trust them when the last-CLI marker says it was this one.
708
709
  tmp_dir = File.join(chdir, "tmp")
709
710
  return false unless File.directory?(tmp_dir)
711
+ return false unless last_cli_for(chdir) == cli_name
710
712
 
711
713
  Dir.glob(File.join(tmp_dir, "agent-*.log")).any? do |log|
712
714
  # Only count logs from the last 24 hours as valid "resumable" sessions
@@ -716,6 +718,40 @@ rescue StandardError
716
718
  false
717
719
  end
718
720
 
721
+ # Marker recording which CLI binary last ran in a directory (written by run_agent).
722
+ def last_cli_marker_path(chdir)
723
+ File.join(chdir, "tmp", ".brainiac-last-cli")
724
+ end
725
+
726
+ def last_cli_for(chdir)
727
+ return nil unless chdir
728
+
729
+ name = File.read(last_cli_marker_path(chdir)).strip
730
+ name.empty? ? nil : name
731
+ rescue StandardError
732
+ nil
733
+ end
734
+
735
+ def record_last_cli(chdir, agent_cli)
736
+ key = cli_session_key(agent_cli)
737
+ return unless chdir && key
738
+
739
+ FileUtils.mkdir_p(File.join(chdir, "tmp"))
740
+ File.write(last_cli_marker_path(chdir), key)
741
+ rescue StandardError => e
742
+ LOG.warn "[Dispatch] Could not record last CLI for #{chdir}: #{e.message}"
743
+ end
744
+
745
+ # True when a different CLI ran in this directory more recently than agent_cli.
746
+ # A switched-to CLI never saw the other provider's turns, so resuming its own (older)
747
+ # session would hand it a lean prompt with a stale or empty history. Start fresh instead
748
+ # and let the full prompt (memory file + source context) carry the conversation.
749
+ def cli_switched_since_last_run?(chdir, agent_cli)
750
+ last = last_cli_for(chdir)
751
+ key = cli_session_key(agent_cli)
752
+ !last.nil? && !key.nil? && last != key
753
+ end
754
+
719
755
  # Check if a centralized session directory has sessions matching the given cwd.
720
756
  # Supports CLIs that store sessions as .jsonl files in date-partitioned directories (YYYY/MM/DD/)
721
757
  # with a first-line JSON metadata object containing a "payload.cwd" field.
@@ -777,6 +813,7 @@ end
777
813
  def resume_viable?(project_config:, cli_provider: nil, agent_name: nil, chdir: nil)
778
814
  resolved = resolve_project_cli_config(project_config, cli_provider_override: cli_provider, agent_name: agent_name)
779
815
  chdir ||= resolved["repo_path"]
816
+ return false if cli_switched_since_last_run?(chdir, resolved["agent_cli"])
780
817
  return stored_cli_session_viable?(resolved, chdir) if resolved["resume_id_flag"]
781
818
  return false unless resolved["resume_flag"] || resolved["resume_args"]
782
819
 
@@ -805,6 +842,11 @@ end
805
842
  def resolve_resume(resume, resolved, chdir, session_id: nil)
806
843
  return false unless resume
807
844
 
845
+ if cli_switched_since_last_run?(chdir, resolved["agent_cli"])
846
+ LOG.info "[Dispatch] CLI switched from #{last_cli_for(chdir)} to #{resolved["agent_cli"]} in #{chdir} — starting fresh session"
847
+ return false
848
+ end
849
+
808
850
  if resolved["resume_id_flag"]
809
851
  id = session_id.to_s.empty? ? cli_session_id_for(agent_cli: resolved["agent_cli"], worktree: chdir) : session_id
810
852
  if id.to_s.empty?
@@ -824,16 +866,27 @@ def resolve_resume(resume, resolved, chdir, session_id: nil)
824
866
  false
825
867
  end
826
868
 
827
- # Some CLIs (e.g. grok --session-id) let the caller name a new session up front.
828
- # Mint a UUID only on the first run, when we are not resuming an existing id.
829
- def mint_cli_session_id(resolved, stored_session:, resuming:)
869
+ # Some CLIs (e.g. claude/grok --session-id) let the caller name a new session up front.
870
+ # Mint a UUID whenever we start fresh — including after a provider switch, when an older
871
+ # stored id exists — so the stored id always points at the latest session for this CLI.
872
+ def mint_cli_session_id(resolved, resuming:)
830
873
  return nil if resuming
831
874
  return nil unless resolved["new_session_id_flag"]
832
- return nil unless stored_session.to_s.empty?
833
875
 
834
876
  SecureRandom.uuid
835
877
  end
836
878
 
879
+ # Decide resume vs. fresh start for this dispatch, then record this CLI as the last
880
+ # one to run here. Returns [should_resume, minted_session_id].
881
+ def prepare_cli_session(resume, resolved, chdir)
882
+ stored_session = cli_session_id_for(agent_cli: resolved["agent_cli"], worktree: chdir)
883
+ # Auto-resume: only if the provider supports it AND a prior session exists for this CLI here.
884
+ should_resume = resolve_resume(resume, resolved, chdir, session_id: stored_session)
885
+ minted_session_id = mint_cli_session_id(resolved, resuming: should_resume)
886
+ record_last_cli(chdir, resolved["agent_cli"])
887
+ [should_resume, minted_session_id]
888
+ end
889
+
837
890
  # Check if intent detection says to skip dispatching the agent.
838
891
  # Returns true if the message should be skipped, false otherwise.
839
892
  # Only runs if a raw message is provided, an agent is named, and intent is enabled.
@@ -870,12 +923,8 @@ def run_agent(prompt, project_config:, chdir: nil, log_name: "agent", model: nil
870
923
  effort ||= resolved["agent_effort"]
871
924
  agent_config_name = agent_name&.downcase&.gsub(/[^a-z0-9-]/, "-")
872
925
 
873
- stored_session = cli_session_id_for(agent_cli: resolved["agent_cli"], worktree: chdir)
874
926
  work_item_id = find_work_item_by_worktree(chdir)&.first
875
-
876
- # Auto-resume: only if the provider supports it AND a prior session exists for this CLI here.
877
- should_resume = resolve_resume(resume, resolved, chdir, session_id: stored_session)
878
- minted_session_id = mint_cli_session_id(resolved, stored_session: stored_session, resuming: should_resume)
927
+ should_resume, minted_session_id = prepare_cli_session(resume, resolved, chdir)
879
928
 
880
929
  # Pre-dispatch hook — plugins can prep the working directory (e.g., copy config files, clean up)
881
930
  Brainiac.emit(:pre_dispatch, chdir: chdir, project_config: project_config, agent_name: agent_name)
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Brainiac
4
4
  # @return [String] the current gem version
5
- VERSION = "0.1.9"
5
+ VERSION = "0.1.10"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainiac
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Davis