@maintainabilityai/research-runner 0.1.13 → 0.1.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.
@@ -3,23 +3,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.callLlm = callLlm;
4
4
  const anthropic_client_1 = require("./anthropic-client");
5
5
  const github_models_client_1 = require("./github-models-client");
6
- /** Per-tier per-provider model id lookup. */
6
+ /**
7
+ * Per-tier per-provider model id lookup. `githubModelsFallback` (when
8
+ * present) is tried automatically on 401/403/404 from the primary —
9
+ * how we let users with a GMT (Copilot-Pro user PAT) reach the
10
+ * "custom"-tier `gpt-5-chat` while users on a workflow bot token
11
+ * still work via the "low"-tier fallback.
12
+ */
7
13
  const MODEL_BY_TIER = {
8
- // gpt-4.1-mini outperforms gpt-4o-mini on the per-provider query-plan
9
- // task. Verified empirically against the celeb-api brief: 4.1-mini
10
- // produces more on-topic arxiv phrases ("celebrity identity disambig-
11
- // uation" vs 4o-mini's generic "API integration challenges"), tighter
12
- // patent AND-clauses, and stays inside the spec's word counts more
13
- // reliably. Same "low" rate-limit tier as 4o-mini, so no infra change.
14
- plan: { anthropic: 'claude-haiku-4-5', githubModels: 'openai/gpt-4.1-mini' },
15
- // gpt-5-chat is in the "custom" GH-Models tier (200K input / 100K
16
- // output) and is NON-reasoning — verified end-to-end with a live API
17
- // call (reasoning_tokens=0, finish_reason=stop). Picked over gpt-5
18
- // and gpt-5-mini because those are reasoning models that consume the
14
+ // Plan tier — small structured-JSON output, one shot, fits any cap.
15
+ // Try gpt-5-chat first (custom tier, only reachable with a Copilot-
16
+ // enrolled PAT like GMT). Fall back to gpt-4.1-mini (low tier, works
17
+ // on every token including the Actions bot). Empirically equivalent
18
+ // output quality on the V3-anchor prompt the upgrade is "if free,
19
+ // why not"; the fallback keeps everyone working.
20
+ plan: {
21
+ anthropic: 'claude-haiku-4-5',
22
+ githubModels: 'openai/gpt-5-chat',
23
+ githubModelsFallback: 'openai/gpt-4.1-mini',
24
+ },
25
+ // Synth tier — 200K context, non-reasoning (verified live with
26
+ // reasoning_tokens=0, finish_reason=stop). Picked over gpt-5 and
27
+ // gpt-5-mini because those are reasoning models that consume the
19
28
  // completion budget on hidden chain-of-thought before producing any
20
- // visible markdown bad for the synthesis step where we need
21
- // predictable structured output. Requires the caller's token to have
22
- // Models access through a Copilot subscription (GMT path).
29
+ // visible markdown. Synth needs predictable structured output. No
30
+ // fallback model here synth runs on the agent side now (Copilot
31
+ // Coding Agent / @claude), so the runner doesn't fire synth itself.
23
32
  synth: { anthropic: 'claude-sonnet-4-6', githubModels: 'openai/gpt-5-chat' },
24
33
  };
25
34
  /**
@@ -57,28 +66,54 @@ async function callAnthropicTier(opts, tierModels) {
57
66
  httpStatus: r.httpStatus,
58
67
  };
59
68
  }
69
+ /**
70
+ * GitHub Models returns 401 / 403 / 404 when the token can't reach the
71
+ * requested model (typically the workflow bot token hitting a "custom"-
72
+ * tier model like gpt-5-chat). These are recoverable via fallback;
73
+ * everything else (timeouts, 5xx, 413 cap, parse errors) should
74
+ * propagate.
75
+ */
76
+ function isModelAccessError(err) {
77
+ if (!(err instanceof Error)) {
78
+ return false;
79
+ }
80
+ return /GitHub Models returned 40[134]:/.test(err.message);
81
+ }
60
82
  async function callGitHubModelsTier(opts, tierModels) {
61
83
  if (!opts.githubToken) {
62
84
  throw new Error(`callLlm: provider=github-models requires githubToken (set GITHUB_TOKEN; workflow needs \`permissions: models: read\`).`);
63
85
  }
64
- const r = await (0, github_models_client_1.callGitHubModels)({
65
- token: opts.githubToken,
66
- model: tierModels.githubModels,
67
- system: opts.system,
68
- prompt: opts.prompt,
69
- maxTokens: opts.maxTokens,
70
- temperature: opts.temperature,
71
- fetchImpl: opts.fetchImpl,
72
- });
73
- return {
74
- provider: 'github-models',
75
- model: tierModels.githubModels,
76
- text: r.text,
77
- inputTokens: r.inputTokens,
78
- outputTokens: r.outputTokens,
79
- costUsd: r.costUsd,
80
- httpStatus: r.httpStatus,
86
+ const callOne = async (model) => {
87
+ const r = await (0, github_models_client_1.callGitHubModels)({
88
+ token: opts.githubToken,
89
+ model,
90
+ system: opts.system,
91
+ prompt: opts.prompt,
92
+ maxTokens: opts.maxTokens,
93
+ temperature: opts.temperature,
94
+ fetchImpl: opts.fetchImpl,
95
+ });
96
+ return {
97
+ provider: 'github-models',
98
+ model,
99
+ text: r.text,
100
+ inputTokens: r.inputTokens,
101
+ outputTokens: r.outputTokens,
102
+ costUsd: r.costUsd,
103
+ httpStatus: r.httpStatus,
104
+ };
81
105
  };
106
+ try {
107
+ return await callOne(tierModels.githubModels);
108
+ }
109
+ catch (err) {
110
+ if (tierModels.githubModelsFallback && isModelAccessError(err)) {
111
+ const cause = err instanceof Error ? err.message : String(err);
112
+ process.stderr.write(`[research-runner] ⚠ github-models ${tierModels.githubModels} access-denied, falling back to ${tierModels.githubModelsFallback}. Cause: ${cause.slice(0, 200)}\n`);
113
+ return await callOne(tierModels.githubModelsFallback);
114
+ }
115
+ throw err;
116
+ }
82
117
  }
83
118
  async function callLlm(opts) {
84
119
  const tierModels = MODEL_BY_TIER[opts.tier];
@@ -515,7 +515,9 @@ async function runArcheologist(opts) {
515
515
  provider: brief.llm_provider,
516
516
  // plan_queries is the only LLM hop we run now (synth handed off
517
517
  // to the assigned agent). Surface that model in the Hatter's Tag.
518
- model: 'openai/gpt-4.1-mini',
518
+ // Plan-tier primary (router falls back to gpt-4.1-mini on access denial).
519
+ // Synth runs on the agent side, so this is the only LLM hop the runner makes.
520
+ model: 'openai/gpt-5-chat',
519
521
  input_tokens: totalInputTokens,
520
522
  output_tokens: totalOutputTokens,
521
523
  cost_usd: roundUsd(totalCostUsd),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maintainabilityai/research-runner",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Research + PRD agent runner — orchestrates the Archeologist and PRD pipelines for the MaintainabilityAI governance mesh",
5
5
  "license": "MIT",
6
6
  "author": "MaintainabilityAI",