duet-cli 0.2.3__tar.gz → 0.2.5__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: duet-cli
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Two CLI agents in conversation. One Python file. Stdlib only.
5
5
  Author: Volkan Altan
6
6
  License-Expression: MIT
@@ -3371,6 +3371,10 @@ def _build_arg_parser() -> argparse.ArgumentParser:
3371
3371
  help="partner agent spec, e.g. codex:coder, claude:reviewer, gemini:coder, copilot:coder (default codex:coder)")
3372
3372
  ap.add_argument("--lead", default="claude:planner",
3373
3373
  help="lead agent spec, e.g. claude:planner, gemini:reviewer, copilot:planner (default; ignored if --resume-claude given)")
3374
+ ap.add_argument("--lead-model", metavar="MODEL", default=None,
3375
+ help="model name to pass to the lead agent's backend via --model")
3376
+ ap.add_argument("--partner-model", metavar="MODEL", default=None,
3377
+ help="model name to pass to the partner agent's backend via --model")
3374
3378
  ap.add_argument("--cwd", default=".", help="working dir for both agents")
3375
3379
  ap.add_argument("--turns", type=int, default=DEFAULT_TURNS, help=f"max turns (default {DEFAULT_TURNS})")
3376
3380
  ap.add_argument("--sentinel", default=DEFAULT_SENTINEL,
@@ -3542,9 +3546,18 @@ def _build_cfg_from_cli(args: argparse.Namespace, ap: argparse.ArgumentParser,
3542
3546
  parser=ap,
3543
3547
  stdin_cache=stdin_cache,
3544
3548
  )
3549
+ agents = [
3550
+ dataclasses.replace(
3551
+ parse_partner(args.lead, default_role="planner"),
3552
+ model=args.lead_model or None,
3553
+ ),
3554
+ dataclasses.replace(
3555
+ parse_partner(args.partner, default_role="coder"),
3556
+ model=args.partner_model or None,
3557
+ ),
3558
+ ]
3545
3559
  agents = apply_resume_overrides(
3546
- [parse_partner(args.lead, default_role="planner"),
3547
- parse_partner(args.partner, default_role="coder")],
3560
+ agents,
3548
3561
  resume_claude=args.resume_claude,
3549
3562
  resume_codex=args.resume_codex,
3550
3563
  rename_slots=True,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: duet-cli
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Two CLI agents in conversation. One Python file. Stdlib only.
5
5
  Author: Volkan Altan
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "duet-cli"
7
- version = "0.2.3"
7
+ version = "0.2.5"
8
8
  description = "Two CLI agents in conversation. One Python file. Stdlib only."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -825,6 +825,45 @@ class TestParsePartner(unittest.TestCase):
825
825
  self.assertEqual(agent.name, "copilot-coder")
826
826
 
827
827
 
828
+ # ---------- _build_cfg_from_cli ----------
829
+
830
+
831
+ class TestBuildCfgFromCli(unittest.TestCase):
832
+ def _parse(self, *argv: str):
833
+ parser = duet._build_arg_parser()
834
+ return parser, parser.parse_args(list(argv))
835
+
836
+ def test_lead_and_partner_models_attach_to_cli_agents(self) -> None:
837
+ parser, args = self._parse(
838
+ "--task", "x",
839
+ "--lead", "claude:reviewer",
840
+ "--partner", "codex:coder",
841
+ "--lead-model", "claude-opus-4-5",
842
+ "--partner-model", "gpt-5",
843
+ )
844
+
845
+ cfg = duet._build_cfg_from_cli(args, parser, {})
846
+
847
+ self.assertEqual(cfg.agents[0].backend, "claude")
848
+ self.assertEqual(cfg.agents[0].role, "reviewer")
849
+ self.assertEqual(cfg.agents[0].model, "claude-opus-4-5")
850
+ self.assertEqual(cfg.agents[1].backend, "codex")
851
+ self.assertEqual(cfg.agents[1].role, "coder")
852
+ self.assertEqual(cfg.agents[1].model, "gpt-5")
853
+
854
+ def test_empty_cli_model_flags_normalize_to_none(self) -> None:
855
+ parser, args = self._parse(
856
+ "--task", "x",
857
+ "--lead-model", "",
858
+ "--partner-model", "",
859
+ )
860
+
861
+ cfg = duet._build_cfg_from_cli(args, parser, {})
862
+
863
+ self.assertIsNone(cfg.agents[0].model)
864
+ self.assertIsNone(cfg.agents[1].model)
865
+
866
+
828
867
  # ---------- apply_resume_overrides ----------
829
868
 
830
869
 
@@ -878,6 +917,32 @@ class TestApplyResumeOverrides(unittest.TestCase):
878
917
  self.assertEqual(agents[1].role, "coder")
879
918
  self.assertEqual(agents[1].session_id, "codex-sid")
880
919
 
920
+ def test_resume_codex_move_preserves_model(self) -> None:
921
+ agents = duet.apply_resume_overrides(
922
+ [
923
+ duet.Agent(
924
+ name="codex-planner",
925
+ backend="codex",
926
+ role="planner",
927
+ model="gpt-5",
928
+ ),
929
+ duet.Agent(
930
+ name="claude-coder",
931
+ backend="claude",
932
+ role="coder",
933
+ model="claude-sonnet-4-6",
934
+ ),
935
+ ],
936
+ resume_codex="codex-sid",
937
+ rename_slots=True,
938
+ )
939
+
940
+ self.assertEqual(agents[0].backend, "claude")
941
+ self.assertEqual(agents[0].model, "claude-sonnet-4-6")
942
+ self.assertEqual(agents[1].backend, "codex")
943
+ self.assertEqual(agents[1].session_id, "codex-sid")
944
+ self.assertEqual(agents[1].model, "gpt-5")
945
+
881
946
  def test_resume_claude_partner_moves_to_lead(self) -> None:
882
947
  agents = duet.apply_resume_overrides(
883
948
  [
File without changes
File without changes
File without changes