indusagi-coding-agent 0.2.11 → 0.2.13

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.
Files changed (46) hide show
  1. package/.env.review.example +25 -0
  2. package/CHANGELOG.md +6 -0
  3. package/README.md +11 -0
  4. package/REVIEW_AGENT.md +137 -0
  5. package/dist/entry.js +103 -25
  6. package/dist/guardrails.js +67 -1
  7. package/dist/index.js +1034 -66
  8. package/dist/review-agent.js +4177 -0
  9. package/dist/review-server.js +4349 -0
  10. package/package.json +15 -10
  11. package/src/boot/contract.ts +1 -1
  12. package/src/boot/runners/session.ts +8 -4
  13. package/src/boot/stages.ts +3 -6
  14. package/src/conductor/catalog/catalog.ts +3 -1
  15. package/src/conductor/conductor.ts +10 -5
  16. package/src/conductor/contract.ts +8 -4
  17. package/src/conductor/index.ts +1 -1
  18. package/src/conductor/signal-hub/translate.ts +2 -2
  19. package/src/console/slash/commands/workbench.ts +2 -2
  20. package/src/index.ts +1 -0
  21. package/src/launch/catalog.ts +4 -2
  22. package/src/launch/contract.ts +1 -0
  23. package/src/launch/invocation/flags.ts +1 -1
  24. package/src/launch/invocation/read.ts +5 -4
  25. package/src/models.ts +90 -0
  26. package/src/review-agent/config.ts +75 -0
  27. package/src/review-agent/contract.ts +59 -0
  28. package/src/review-agent/github.ts +242 -0
  29. package/src/review-agent/index.ts +8 -0
  30. package/src/review-agent/prompt.ts +132 -0
  31. package/src/review-agent/reviewer.ts +118 -0
  32. package/src/review-agent/server.ts +221 -0
  33. package/src/review-agent/service.ts +165 -0
  34. package/src/review-agent/supabase.ts +209 -0
  35. package/src/review-agent/webhook.ts +76 -0
  36. package/src/workspace/brand.ts +1 -1
  37. package/supabase/migrations/20260827031803_indusagi_review_agent.sql +109 -0
  38. package/supabase/migrations/20260827035747_atomic_webhook_enqueue.sql +75 -0
  39. package/supabase/migrations/20260827040104_check_run_reconciliation.sql +8 -0
  40. package/supabase/migrations/20260827041049_owned_job_leases.sql +80 -0
  41. package/supabase/migrations/20260827042500_static_token_webhooks.sql +75 -0
  42. package/src/conductor/signal-hub/translate.test.ts +0 -81
  43. package/src/entry.test.ts +0 -17
  44. package/src/integrations/sarvam/sarvam.test.ts +0 -60
  45. package/src/integrations/zoho/zoho.test.ts +0 -50
  46. package/src/launch/oauth.test.ts +0 -18
@@ -0,0 +1,25 @@
1
+ # Requested Supabase project: sdsdsd (bnaadeovgcqgbrnrfcef)
2
+ SUPABASE_URL=https://bnaadeovgcqgbrnrfcef.supabase.co
3
+ # Server-only secret. Retrieve it from Supabase project settings; never commit it.
4
+ SUPABASE_SERVICE_ROLE_KEY=
5
+
6
+ # GitHub webhook and GitHub App credentials
7
+ GITHUB_WEBHOOK_SECRET=
8
+ GITHUB_APP_ID=
9
+ # PEM may use literal newlines or escaped \n sequences.
10
+ GITHUB_APP_PRIVATE_KEY=
11
+
12
+ # Development-only alternative to GITHUB_APP_ID + GITHUB_APP_PRIVATE_KEY
13
+ # GITHUB_TOKEN=
14
+
15
+ # Indusagi review model
16
+ INDUSAGI_REVIEW_MODEL=anthropic/claude-sonnet-4-6
17
+ ANTHROPIC_API_KEY=
18
+ # OPENAI_API_KEY=
19
+ # GOOGLE_API_KEY=
20
+ # MISTRAL_API_KEY=
21
+
22
+ REVIEW_AGENT_HOST=0.0.0.0
23
+ REVIEW_AGENT_PORT=8787
24
+ REVIEW_AGENT_POLL_MS=2000
25
+ REVIEW_AGENT_JOBS_PER_TICK=5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.12]
4
+
5
+ ### Fixed
6
+ - **One-shot NDJSON routing**: combining `--print --json` now runs one-shot mode with structured signal output instead of selecting the stdin-driven RPC mode.
7
+ - **Structured tool signal contract**: `tool_start` and `tool_end` types now include the arguments, result, and error fields already emitted at runtime.
8
+
3
9
  ## [0.2.11]
4
10
 
5
11
  ### Fixed
package/README.md CHANGED
@@ -127,6 +127,17 @@ First connect may open a browser for Zoho OAuth. Tokens persist under
127
127
 
128
128
  See [`ZOHO_NATIVE_PLAN.md`](./ZOHO_NATIVE_PLAN.md) for architecture and precedence.
129
129
 
130
+ ## GitHub review agent
131
+
132
+ This package also includes `indusagi-review`, a durable GitHub pull-request
133
+ review worker powered by the Indusagi conductor and backed by Supabase. It
134
+ validates signed webhooks, reads repository context through read-only GitHub
135
+ tools, posts inline review findings and a check run, and persists retryable
136
+ jobs without Prisma.
137
+
138
+ See [REVIEW_AGENT.md](./REVIEW_AGENT.md) for GitHub App permissions, Supabase
139
+ schema, environment variables, deployment, and security details.
140
+
130
141
  ## Sarvam AI (native MCP)
131
142
 
132
143
  Indian-language STT / TTS / translate / vision tools via local
@@ -0,0 +1,137 @@
1
+ # Indusagi GitHub Review Agent
2
+
3
+ A Supabase-backed GitHub pull-request reviewer powered by the same Indusagi framework Agent and `SessionConductor` as the terminal coding agent.
4
+
5
+ ## What it does
6
+
7
+ 1. Receives signed GitHub `pull_request` webhooks.
8
+ 2. Atomically deduplicates deliveries and persists durable jobs in Supabase.
9
+ 3. Claims work with PostgreSQL `FOR UPDATE SKIP LOCKED`.
10
+ 4. Exchanges GitHub App credentials for a short-lived installation token.
11
+ 5. Reads PR metadata, every changed-file page, and the unified diff.
12
+ 6. Runs the Indusagi conductor with read-only `github_read_file` and `github_search_code` tools.
13
+ 7. Validates structured findings against actual changed diff lines.
14
+ 8. Posts a formal GitHub review with inline comments; falls back to one sticky timeline comment if GitHub rejects line coordinates.
15
+ 9. Publishes a GitHub check run, stores the result in Supabase, and reconciles failed check updates.
16
+
17
+ The service never checks out or executes pull-request code.
18
+
19
+ ## Supabase
20
+
21
+ This repository is configured to default to the requested project:
22
+
23
+ - Project: `sdsdsd`
24
+ - Project ref: `bnaadeovgcqgbrnrfcef`
25
+ - URL: `https://bnaadeovgcqgbrnrfcef.supabase.co`
26
+
27
+ Migrations:
28
+
29
+ ```text
30
+ supabase/migrations/20260827031803_indusagi_review_agent.sql
31
+ supabase/migrations/20260827035747_atomic_webhook_enqueue.sql
32
+ supabase/migrations/20260827040104_check_run_reconciliation.sql
33
+ supabase/migrations/20260827041049_owned_job_leases.sql
34
+ supabase/migrations/20260827042500_static_token_webhooks.sql
35
+ ```
36
+
37
+ They create RLS-enabled `indusagi_review_deliveries` and `indusagi_review_jobs`
38
+ tables plus atomic webhook-enqueue, ownership-safe renewable job leases,
39
+ periodic stale-recovery, and check-run reconciliation support. No anonymous or authenticated policies are created;
40
+ the backend must use the service-role/secret key.
41
+
42
+ Never commit the service-role key. The publishable/anon key is intentionally not used because the webhook worker requires privileged server-side writes.
43
+
44
+ ## GitHub App setup
45
+
46
+ Create a GitHub App with:
47
+
48
+ ### Repository permissions
49
+
50
+ - Contents: Read
51
+ - Metadata: Read
52
+ - Pull requests: Read and write
53
+ - Issues: Read and write (sticky fallback)
54
+ - Checks: Read and write
55
+
56
+ ### Events
57
+
58
+ Subscribe to `Pull request`. Point the webhook URL to:
59
+
60
+ ```text
61
+ https://YOUR_HOST/webhooks/github
62
+ ```
63
+
64
+ Set a strong webhook secret and configure the same value as `GITHUB_WEBHOOK_SECRET`.
65
+
66
+ The service processes `opened`, `reopened`, `synchronize`, and `ready_for_review`. Drafts are ignored until ready.
67
+
68
+ ## Configuration
69
+
70
+ Copy `.env.review.example` into your deployment secret manager. Required production values:
71
+
72
+ ```text
73
+ SUPABASE_SERVICE_ROLE_KEY
74
+ GITHUB_WEBHOOK_SECRET
75
+ GITHUB_APP_ID
76
+ GITHUB_APP_PRIVATE_KEY
77
+ ANTHROPIC_API_KEY
78
+ ```
79
+
80
+ `GITHUB_TOKEN` is a development-only alternative to GitHub App credentials.
81
+ In this mode, ordinary repository webhooks without an `installation` field are
82
+ accepted and stored with installation ID `0`; the static token provider ignores
83
+ that sentinel value.
84
+
85
+ The private key may contain literal newlines or escaped `\n` sequences.
86
+
87
+ ## Build and run
88
+
89
+ ```bash
90
+ npm install
91
+ npm test
92
+ npm run typecheck
93
+ npm run build
94
+ npm run review:server
95
+ ```
96
+
97
+ The server exposes:
98
+
99
+ - `GET /healthz`
100
+ - `POST /webhooks/github`
101
+
102
+ Default port: `8787`.
103
+
104
+ ## Model
105
+
106
+ Default:
107
+
108
+ ```text
109
+ anthropic/claude-sonnet-4-6
110
+ ```
111
+
112
+ Override with `INDUSAGI_REVIEW_MODEL=provider/model`. Configure the matching provider API key. The review is executed through `createSessionConductor`, with high thinking and only two read-only GitHub tools.
113
+
114
+ ## Security properties
115
+
116
+ - Webhook signatures are mandatory and compared in constant time.
117
+ - GitHub delivery IDs are deduplicated in Supabase.
118
+ - Pull-request content is explicitly marked untrusted in the system and user prompts.
119
+ - No bash, write, edit, process, or local repository tools are exposed.
120
+ - Findings below 0.80 confidence are discarded.
121
+ - Findings not mapped to changed diff lines are discarded.
122
+ - The current PR head SHA is checked immediately before review generation.
123
+ - GitHub App installation tokens are short-lived.
124
+ - GitHub reviews and checks use deterministic markers/external IDs so retries
125
+ reuse already-visible side effects instead of posting duplicates.
126
+ - GitHub and Supabase requests have 30-second deadlines; model reviews have a
127
+ 10-minute deadline and abort the Indusagi conductor when exceeded.
128
+ - Supabase tables have RLS enabled and no client policies.
129
+
130
+ ## Production notes
131
+
132
+ Run at least one always-on worker process. Multiple instances are safe: the
133
+ database claim function serializes each claim with `SKIP LOCKED`, issues a
134
+ unique five-minute lease token, and every running-job mutation verifies that
135
+ token. Workers renew leases every minute. Expired leases are recovered every
136
+ minute without requiring a restart. Failed jobs use bounded exponential
137
+ backoff and stop after three attempts.
package/dist/entry.js CHANGED
@@ -18,7 +18,7 @@ var BRAND = Object.freeze({
18
18
  envShareViewer: "INDUSAGI_SHARE_VIEWER_URL",
19
19
  shareViewerUrl: "https://buildwithindusagi.ai/session/"
20
20
  });
21
- var VERSION = "0.2.11";
21
+ var VERSION = "0.2.12";
22
22
 
23
23
  // src/launch/credentials.ts
24
24
  import { createInterface as createInterface2 } from "node:readline/promises";
@@ -31,7 +31,8 @@ var THINKING_EFFORTS = [
31
31
  "low",
32
32
  "medium",
33
33
  "high",
34
- "xhigh"
34
+ "xhigh",
35
+ "max"
35
36
  ];
36
37
  function isThinkingEffort(value) {
37
38
  return THINKING_EFFORTS.includes(value);
@@ -1157,7 +1158,7 @@ var FLAG_GROUPS = [
1157
1158
  { id: "tools", title: "Tools" },
1158
1159
  { id: "meta", title: "Meta" }
1159
1160
  ];
1160
- var THINKING_CHOICES = ["off", "minimal", "low", "medium", "high", "xhigh"];
1161
+ var THINKING_CHOICES = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
1161
1162
  var FLAG_SPECS = [
1162
1163
  /* ---- Output ---------------------------------------------------------- */
1163
1164
  {
@@ -1330,6 +1331,76 @@ var FLAG_SPECS = [
1330
1331
  }
1331
1332
  ];
1332
1333
 
1334
+ // src/models.ts
1335
+ import { ModelRegistry } from "indusagi/ai";
1336
+ var GPT_6_ASTRA_BASE = {
1337
+ id: "gpt-6-astra",
1338
+ name: "GPT-6 Astra",
1339
+ api: "openai-responses",
1340
+ reasoning: true,
1341
+ reasoningEfforts: ["low", "medium", "high", "xhigh", "max"],
1342
+ input: ["text", "image"],
1343
+ cost: {
1344
+ input: 10,
1345
+ cacheRead: 1,
1346
+ cacheWrite: 12.5,
1347
+ output: 50
1348
+ },
1349
+ contextWindow: 105e4,
1350
+ maxTokens: 128e3,
1351
+ longContextPricing: {
1352
+ threshold: 272e3,
1353
+ multipliers: {
1354
+ input: 2,
1355
+ cacheRead: 2,
1356
+ cacheWrite: 2,
1357
+ output: 1.5
1358
+ }
1359
+ }
1360
+ };
1361
+ var CODING_AGENT_MODELS = [
1362
+ {
1363
+ ...GPT_6_ASTRA_BASE,
1364
+ provider: "openai",
1365
+ baseUrl: "https://api.openai.com/v1"
1366
+ },
1367
+ {
1368
+ ...GPT_6_ASTRA_BASE,
1369
+ api: "openai-codex-responses",
1370
+ provider: "openai-codex",
1371
+ baseUrl: "https://chatgpt.com/backend-api"
1372
+ },
1373
+ {
1374
+ ...GPT_6_ASTRA_BASE,
1375
+ provider: "codex-cli",
1376
+ baseUrl: "bridge:codex-cli"
1377
+ },
1378
+ {
1379
+ ...GPT_6_ASTRA_BASE,
1380
+ id: "openai/gpt-6-astra",
1381
+ provider: "indusagi-cli",
1382
+ baseUrl: "bridge:indusagi-cli"
1383
+ },
1384
+ {
1385
+ ...GPT_6_ASTRA_BASE,
1386
+ id: "openai-codex/gpt-6-astra",
1387
+ api: "openai-codex-responses",
1388
+ provider: "indusagi-cli",
1389
+ baseUrl: "bridge:indusagi-cli"
1390
+ }
1391
+ ];
1392
+ function applyCodingAgentModelOverlay(registry) {
1393
+ for (const model of CODING_AGENT_MODELS) registry.registerCustomModel(model);
1394
+ return registry;
1395
+ }
1396
+ function createCodingAgentModelRegistry() {
1397
+ return applyCodingAgentModelOverlay(new ModelRegistry());
1398
+ }
1399
+ function isReasoningEffortSupported(modelId, effort) {
1400
+ if (modelId?.split("/").at(-1) !== "gpt-6-astra") return true;
1401
+ return GPT_6_ASTRA_BASE.reasoningEfforts.includes(effort);
1402
+ }
1403
+
1333
1404
  // src/launch/invocation/read.ts
1334
1405
  function isFlagToken(token) {
1335
1406
  return token.length > 1 && token.startsWith("-");
@@ -1441,13 +1512,13 @@ function readBool(flags, key) {
1441
1512
  return flags[key] === true;
1442
1513
  }
1443
1514
  function deriveMode(flags) {
1444
- if (readBool(flags, "json")) return "rpc";
1445
1515
  if (readBool(flags, "print") && !readBool(flags, "interactive")) return "json";
1516
+ if (readBool(flags, "json")) return "rpc";
1446
1517
  return "text";
1447
1518
  }
1448
- function resolveThinking(flags) {
1519
+ function resolveThinking(flags, modelId) {
1449
1520
  const raw = readString(flags, "thinking");
1450
- return raw !== void 0 && isThinkingEffort(raw) ? raw : void 0;
1521
+ return raw !== void 0 && isThinkingEffort(raw) && isReasoningEffortSupported(modelId, raw) ? raw : void 0;
1451
1522
  }
1452
1523
  function resolveTools(flags) {
1453
1524
  const raw = readList(flags, "tools");
@@ -1496,7 +1567,7 @@ function readInvocation(argv2) {
1496
1567
  const cwd = readString(flags, "cwd");
1497
1568
  const system = readString(flags, "system");
1498
1569
  const appendSystem = readString(flags, "append-system");
1499
- const thinking = resolveThinking(flags);
1570
+ const thinking = resolveThinking(flags, model);
1500
1571
  const tools = resolveTools(flags);
1501
1572
  return {
1502
1573
  mode,
@@ -1580,7 +1651,7 @@ var MAX_TEXT_BYTES = 10 * 1024 * 1024;
1580
1651
  var MAX_IMAGE_BYTES = 20 * 1024 * 1024;
1581
1652
 
1582
1653
  // src/launch/catalog.ts
1583
- import { ModelRegistry } from "indusagi/ai";
1654
+ import { ModelRegistry as ModelRegistry2 } from "indusagi/ai";
1584
1655
  function defaultCatalogIo() {
1585
1656
  return {
1586
1657
  print(line) {
@@ -1589,10 +1660,11 @@ function defaultCatalogIo() {
1589
1660
  }
1590
1661
  };
1591
1662
  }
1592
- function registrySource(registry = new ModelRegistry()) {
1663
+ function registrySource(registry = new ModelRegistry2()) {
1664
+ const overlaid = applyCodingAgentModelOverlay(registry);
1593
1665
  return {
1594
- providers: () => registry.getProviders(),
1595
- models: (provider) => registry.getModels(provider)
1666
+ providers: () => overlaid.getProviders(),
1667
+ models: (provider) => overlaid.getModels(provider)
1596
1668
  };
1597
1669
  }
1598
1670
  var HEADERS = [
@@ -2139,11 +2211,7 @@ async function loadDefaultSettings() {
2139
2211
  }
2140
2212
  }
2141
2213
  async function loadModelRegistry() {
2142
- const mod = await import("indusagi/ai");
2143
- if (typeof mod.ModelRegistry === "function") {
2144
- return new mod.ModelRegistry();
2145
- }
2146
- return mod.modelRegistry;
2214
+ return createCodingAgentModelRegistry();
2147
2215
  }
2148
2216
  var selectRunnerStage = {
2149
2217
  name: "select-runner",
@@ -5218,7 +5286,7 @@ import * as path3 from "node:path";
5218
5286
 
5219
5287
  // src/conductor/catalog/catalog.ts
5220
5288
  import { z } from "zod";
5221
- import { getModels, getProviders } from "indusagi/ai";
5289
+ import { getModels, getProviders, modelRegistry } from "indusagi/ai";
5222
5290
  var rawModelGate = z.object({
5223
5291
  id: z.string().min(1),
5224
5292
  name: z.string().min(1),
@@ -5228,6 +5296,7 @@ var rawModelGate = z.object({
5228
5296
  contextWindow: z.number().optional()
5229
5297
  });
5230
5298
  var EXCLUDED_PROVIDERS = /* @__PURE__ */ new Set(["mock"]);
5299
+ applyCodingAgentModelOverlay(modelRegistry);
5231
5300
  var frameworkSource = {
5232
5301
  providers: () => getProviders().filter((provider) => !EXCLUDED_PROVIDERS.has(String(provider))),
5233
5302
  models: (provider) => getModels(provider)
@@ -6758,7 +6827,7 @@ function reduceState(prev, action) {
6758
6827
  }
6759
6828
  }
6760
6829
  var DEFAULT_RETRY = { maxAttempts: 2, baseDelayMs: 250 };
6761
- var THINKING_LADDER = ["off", "low", "medium", "high"];
6830
+ var DEFAULT_THINKING_LADDER = ["off", "low", "medium", "high"];
6762
6831
  var PERMISSION_CYCLE = ["default", "acceptEdits", "plan", "bypass"];
6763
6832
  function newSessionId() {
6764
6833
  return `s_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
@@ -6780,6 +6849,10 @@ function isOverloadFault(error) {
6780
6849
  const text = errorText(error).toLowerCase();
6781
6850
  return text.includes("529") || text.includes("overload");
6782
6851
  }
6852
+ function thinkingLadderForModel(model) {
6853
+ const efforts = model?.reasoningEfforts;
6854
+ return efforts?.length ? efforts : DEFAULT_THINKING_LADDER;
6855
+ }
6783
6856
  function withGatewayBaseUrl(model, gatewayBaseUrls) {
6784
6857
  const url = gatewayBaseUrls?.[model.provider];
6785
6858
  return url ? { ...model, baseUrl: url } : model;
@@ -7160,11 +7233,13 @@ ${outcome.output}`.trimEnd(), timestamp: Date.now() }, "note");
7160
7233
  return this.#thinking;
7161
7234
  }
7162
7235
  setThinkingLevel(level) {
7236
+ if (!isReasoningEffortSupported(this.#boundModel?.id, level)) return;
7163
7237
  this.#thinking = level;
7164
7238
  this.agent.setThinkingLevel?.(level);
7165
7239
  }
7166
7240
  cycleThinkingLevel() {
7167
- const next = THINKING_LADDER[(THINKING_LADDER.indexOf(this.#thinking) + 1) % THINKING_LADDER.length];
7241
+ const ladder = thinkingLadderForModel(this.#boundModel);
7242
+ const next = ladder[(ladder.indexOf(this.#thinking) + 1) % ladder.length];
7168
7243
  this.setThinkingLevel(next);
7169
7244
  return next;
7170
7245
  }
@@ -9689,7 +9764,7 @@ var HOTKEYS = [
9689
9764
  ["Tab", "Accept the highlighted completion"],
9690
9765
  ["Ctrl+C", "Interrupt the running turn"],
9691
9766
  ["Ctrl+T", "Toggle reasoning / thinking rows"],
9692
- ["/thinking", "Cycle thinking effort level (off \u2192 low \u2192 medium)"],
9767
+ ["/thinking", "Cycle the selected model's supported reasoning efforts"],
9693
9768
  ["Ctrl+V", "Attach an image from the clipboard"],
9694
9769
  ["Ctrl+G", "Edit the composer in your external editor"],
9695
9770
  ["Ctrl+O", "Expand or collapse full tool output"],
@@ -9771,7 +9846,7 @@ var workbenchCommands = [
9771
9846
  },
9772
9847
  {
9773
9848
  name: "thinking",
9774
- summary: "Cycle thinking effort level (off \u2192 low \u2192 medium \u2192 off)",
9849
+ summary: "Cycle reasoning effort using the selected model's supported levels",
9775
9850
  run: (ctx) => {
9776
9851
  ctx.conductor.cycleThinkingLevel();
9777
9852
  return HANDLED;
@@ -12016,6 +12091,9 @@ var DEFAULT_REDACTOR = createRedactor();
12016
12091
  // src/insight/replay.ts
12017
12092
  var TEXT_DECODER3 = new TextDecoder();
12018
12093
 
12094
+ // src/review-agent/reviewer.ts
12095
+ import { Type as Type8 } from "@sinclair/typebox";
12096
+
12019
12097
  // src/console/overlays/approval-queue.ts
12020
12098
  var EMPTY_APPROVAL_QUEUE = { entries: [] };
12021
12099
  function approvalQueueReducer(state, event) {
@@ -16158,9 +16236,9 @@ function buildKeyResolver(ctx, vault, requestedAccount) {
16158
16236
  }
16159
16237
  };
16160
16238
  }
16161
- var THINKING_LEVELS = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh"]);
16162
- function resolveThinkingLevel(raw) {
16163
- return raw !== void 0 && THINKING_LEVELS.has(raw) ? raw : void 0;
16239
+ var THINKING_LEVELS = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
16240
+ function resolveThinkingLevel(raw, modelId) {
16241
+ return raw !== void 0 && THINKING_LEVELS.has(raw) && isReasoningEffortSupported(modelId, raw) ? raw : void 0;
16164
16242
  }
16165
16243
  function resolveText(value) {
16166
16244
  try {
@@ -16461,7 +16539,7 @@ async function buildSessionConductor(ctx) {
16461
16539
  const tools = wrapToolsWithAddons(concatAddonTools(deck, addons), addons);
16462
16540
  const skills = gatherModelSkills(cwd);
16463
16541
  const system = composeSystem(tools, inv, cwd, skills, memoryDoc);
16464
- const thinking = resolveThinkingLevel(inv.thinking);
16542
+ const thinking = resolveThinkingLevel(inv.thinking, modelId);
16465
16543
  const fallbackModelId = inv.fallbackModelId;
16466
16544
  const planReachable = inv.mode === "repl";
16467
16545
  const canUseTool = buildPermissionGate(permissionRules, permissionMode, tools, planReachable);
@@ -1996,7 +1996,72 @@ import { createZeroUsage as createZeroUsage2 } from "indusagi/ai";
1996
1996
 
1997
1997
  // src/conductor/catalog/catalog.ts
1998
1998
  import { z } from "zod";
1999
- import { getModels, getProviders } from "indusagi/ai";
1999
+ import { getModels, getProviders, modelRegistry } from "indusagi/ai";
2000
+
2001
+ // src/models.ts
2002
+ import { ModelRegistry } from "indusagi/ai";
2003
+ var GPT_6_ASTRA_BASE = {
2004
+ id: "gpt-6-astra",
2005
+ name: "GPT-6 Astra",
2006
+ api: "openai-responses",
2007
+ reasoning: true,
2008
+ reasoningEfforts: ["low", "medium", "high", "xhigh", "max"],
2009
+ input: ["text", "image"],
2010
+ cost: {
2011
+ input: 10,
2012
+ cacheRead: 1,
2013
+ cacheWrite: 12.5,
2014
+ output: 50
2015
+ },
2016
+ contextWindow: 105e4,
2017
+ maxTokens: 128e3,
2018
+ longContextPricing: {
2019
+ threshold: 272e3,
2020
+ multipliers: {
2021
+ input: 2,
2022
+ cacheRead: 2,
2023
+ cacheWrite: 2,
2024
+ output: 1.5
2025
+ }
2026
+ }
2027
+ };
2028
+ var CODING_AGENT_MODELS = [
2029
+ {
2030
+ ...GPT_6_ASTRA_BASE,
2031
+ provider: "openai",
2032
+ baseUrl: "https://api.openai.com/v1"
2033
+ },
2034
+ {
2035
+ ...GPT_6_ASTRA_BASE,
2036
+ api: "openai-codex-responses",
2037
+ provider: "openai-codex",
2038
+ baseUrl: "https://chatgpt.com/backend-api"
2039
+ },
2040
+ {
2041
+ ...GPT_6_ASTRA_BASE,
2042
+ provider: "codex-cli",
2043
+ baseUrl: "bridge:codex-cli"
2044
+ },
2045
+ {
2046
+ ...GPT_6_ASTRA_BASE,
2047
+ id: "openai/gpt-6-astra",
2048
+ provider: "indusagi-cli",
2049
+ baseUrl: "bridge:indusagi-cli"
2050
+ },
2051
+ {
2052
+ ...GPT_6_ASTRA_BASE,
2053
+ id: "openai-codex/gpt-6-astra",
2054
+ api: "openai-codex-responses",
2055
+ provider: "indusagi-cli",
2056
+ baseUrl: "bridge:indusagi-cli"
2057
+ }
2058
+ ];
2059
+ function applyCodingAgentModelOverlay(registry) {
2060
+ for (const model of CODING_AGENT_MODELS) registry.registerCustomModel(model);
2061
+ return registry;
2062
+ }
2063
+
2064
+ // src/conductor/catalog/catalog.ts
2000
2065
  var rawModelGate = z.object({
2001
2066
  id: z.string().min(1),
2002
2067
  name: z.string().min(1),
@@ -2005,6 +2070,7 @@ var rawModelGate = z.object({
2005
2070
  input: z.array(z.string()).optional(),
2006
2071
  contextWindow: z.number().optional()
2007
2072
  });
2073
+ applyCodingAgentModelOverlay(modelRegistry);
2008
2074
 
2009
2075
  // src/conductor/signal-hub/translate.ts
2010
2076
  import { createZeroUsage } from "indusagi/ai";