@sagentlab/navarch-runtime 0.1.143 → 0.1.145

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.
@@ -87,7 +87,7 @@ function buildPiProviderConfig() {
87
87
  name: "DeepSeek V4 Flash",
88
88
  reasoning: true,
89
89
  input: ["text"],
90
- cost: { input: 0.22, output: 0.66, cacheRead: 0.007, cacheWrite: 0.22 },
90
+ cost: { input: 0.15, output: 0.6, cacheRead: 0.003, cacheWrite: 0.15 },
91
91
  contextWindow: 128_000,
92
92
  maxTokens: 16_384,
93
93
  },
@@ -0,0 +1,264 @@
1
+ {
2
+ "source": "https://models.dev/api.json",
3
+ "fetched_at": "2026-11-09",
4
+ "models": {
5
+ "gpt-4": {
6
+ "input": 30,
7
+ "cachedInput": 30,
8
+ "cacheWrite": 30,
9
+ "output": 60
10
+ },
11
+ "gpt-4-turbo": {
12
+ "input": 10,
13
+ "cachedInput": 10,
14
+ "cacheWrite": 10,
15
+ "output": 30
16
+ },
17
+ "gpt-4.1": {
18
+ "input": 2,
19
+ "cachedInput": 0.5,
20
+ "cacheWrite": 2,
21
+ "output": 8
22
+ },
23
+ "gpt-4.1-mini": {
24
+ "input": 0.4,
25
+ "cachedInput": 0.1,
26
+ "cacheWrite": 0.4,
27
+ "output": 1.6
28
+ },
29
+ "gpt-4.1-nano": {
30
+ "input": 0.1,
31
+ "cachedInput": 0.025,
32
+ "cacheWrite": 0.1,
33
+ "output": 0.4
34
+ },
35
+ "gpt-4o": {
36
+ "input": 2.5,
37
+ "cachedInput": 1.25,
38
+ "cacheWrite": 2.5,
39
+ "output": 10
40
+ },
41
+ "gpt-4o-2024-05-13": {
42
+ "input": 5,
43
+ "cachedInput": 5,
44
+ "cacheWrite": 5,
45
+ "output": 15
46
+ },
47
+ "gpt-4o-2024-08-06": {
48
+ "input": 2.5,
49
+ "cachedInput": 1.25,
50
+ "cacheWrite": 2.5,
51
+ "output": 10
52
+ },
53
+ "gpt-4o-2024-11-20": {
54
+ "input": 2.5,
55
+ "cachedInput": 1.25,
56
+ "cacheWrite": 2.5,
57
+ "output": 10
58
+ },
59
+ "gpt-4o-mini": {
60
+ "input": 0.15,
61
+ "cachedInput": 0.075,
62
+ "cacheWrite": 0.15,
63
+ "output": 0.6
64
+ },
65
+ "gpt-5": {
66
+ "input": 1.25,
67
+ "cachedInput": 0.125,
68
+ "cacheWrite": 1.25,
69
+ "output": 10
70
+ },
71
+ "gpt-5-mini": {
72
+ "input": 0.25,
73
+ "cachedInput": 0.025,
74
+ "cacheWrite": 0.25,
75
+ "output": 2
76
+ },
77
+ "gpt-5-nano": {
78
+ "input": 0.05,
79
+ "cachedInput": 0.005,
80
+ "cacheWrite": 0.05,
81
+ "output": 0.4
82
+ },
83
+ "gpt-5-pro": {
84
+ "input": 15,
85
+ "cachedInput": 15,
86
+ "cacheWrite": 15,
87
+ "output": 120
88
+ },
89
+ "gpt-5.1": {
90
+ "input": 1.25,
91
+ "cachedInput": 0.125,
92
+ "cacheWrite": 1.25,
93
+ "output": 10
94
+ },
95
+ "gpt-5.2": {
96
+ "input": 1.75,
97
+ "cachedInput": 0.175,
98
+ "cacheWrite": 1.75,
99
+ "output": 14
100
+ },
101
+ "gpt-5.2-pro": {
102
+ "input": 21,
103
+ "cachedInput": 21,
104
+ "cacheWrite": 21,
105
+ "output": 168
106
+ },
107
+ "gpt-5.3-codex": {
108
+ "input": 1.75,
109
+ "cachedInput": 0.175,
110
+ "cacheWrite": 1.75,
111
+ "output": 14
112
+ },
113
+ "gpt-5.3-codex-spark": {
114
+ "input": 1.75,
115
+ "cachedInput": 0.175,
116
+ "cacheWrite": 1.75,
117
+ "output": 14
118
+ },
119
+ "gpt-5.4": {
120
+ "input": 2.5,
121
+ "cachedInput": 0.25,
122
+ "cacheWrite": 2.5,
123
+ "output": 15
124
+ },
125
+ "gpt-5.4-mini": {
126
+ "input": 0.75,
127
+ "cachedInput": 0.075,
128
+ "cacheWrite": 0.75,
129
+ "output": 4.5
130
+ },
131
+ "gpt-5.4-nano": {
132
+ "input": 0.2,
133
+ "cachedInput": 0.02,
134
+ "cacheWrite": 0.2,
135
+ "output": 1.25
136
+ },
137
+ "gpt-5.4-pro": {
138
+ "input": 30,
139
+ "cachedInput": 30,
140
+ "cacheWrite": 30,
141
+ "output": 180
142
+ },
143
+ "gpt-5.5": {
144
+ "input": 5,
145
+ "cachedInput": 0.5,
146
+ "cacheWrite": 5,
147
+ "output": 30
148
+ },
149
+ "gpt-5.5-pro": {
150
+ "input": 30,
151
+ "cachedInput": 30,
152
+ "cacheWrite": 30,
153
+ "output": 180
154
+ },
155
+ "gpt-5.6": {
156
+ "input": 4,
157
+ "cachedInput": 0.4,
158
+ "cacheWrite": 5,
159
+ "output": 20
160
+ },
161
+ "gpt-5.6-luna": {
162
+ "input": 0.2,
163
+ "cachedInput": 0.02,
164
+ "cacheWrite": 0.25,
165
+ "output": 1.2
166
+ },
167
+ "gpt-5.6-sol": {
168
+ "input": 4,
169
+ "cachedInput": 0.4,
170
+ "cacheWrite": 5,
171
+ "output": 20
172
+ },
173
+ "gpt-5.6-terra": {
174
+ "input": 2,
175
+ "cachedInput": 0.2,
176
+ "cacheWrite": 2.5,
177
+ "output": 12
178
+ },
179
+ "gpt-6-astra": {
180
+ "input": 10,
181
+ "cachedInput": 1,
182
+ "cacheWrite": 12.5,
183
+ "output": 50
184
+ },
185
+ "gpt-6-luna": {
186
+ "input": 0.1,
187
+ "cachedInput": 0.01,
188
+ "cacheWrite": 0.125,
189
+ "output": 0.5
190
+ },
191
+ "gpt-6-sol": {
192
+ "input": 2,
193
+ "cachedInput": 0.2,
194
+ "cacheWrite": 2.5,
195
+ "output": 10
196
+ },
197
+ "gpt-6.1-sol": {
198
+ "input": 2,
199
+ "cachedInput": 0.1,
200
+ "cacheWrite": 2.5,
201
+ "output": 10
202
+ },
203
+ "gpt-6.1-terra": {
204
+ "input": 1,
205
+ "cachedInput": 0.05,
206
+ "cacheWrite": 1.25,
207
+ "output": 5
208
+ },
209
+ "gpt-daybreak-blue-latest": {
210
+ "input": 4,
211
+ "cachedInput": 0.4,
212
+ "cacheWrite": 5,
213
+ "output": 20
214
+ },
215
+ "gpt-daybreak-red-latest": {
216
+ "input": 12.5,
217
+ "cachedInput": 1.25,
218
+ "cacheWrite": 15.625,
219
+ "output": 75
220
+ },
221
+ "gpt-realtime-2.1": {
222
+ "input": 4,
223
+ "cachedInput": 0.4,
224
+ "cacheWrite": 4,
225
+ "output": 24
226
+ },
227
+ "o1": {
228
+ "input": 15,
229
+ "cachedInput": 7.5,
230
+ "cacheWrite": 15,
231
+ "output": 60
232
+ },
233
+ "o1-pro": {
234
+ "input": 150,
235
+ "cachedInput": 150,
236
+ "cacheWrite": 150,
237
+ "output": 600
238
+ },
239
+ "o3": {
240
+ "input": 2,
241
+ "cachedInput": 0.5,
242
+ "cacheWrite": 2,
243
+ "output": 8
244
+ },
245
+ "o3-mini": {
246
+ "input": 1.1,
247
+ "cachedInput": 0.55,
248
+ "cacheWrite": 1.1,
249
+ "output": 4.4
250
+ },
251
+ "o3-pro": {
252
+ "input": 20,
253
+ "cachedInput": 20,
254
+ "cacheWrite": 20,
255
+ "output": 80
256
+ },
257
+ "o4-mini": {
258
+ "input": 1.1,
259
+ "cachedInput": 0.275,
260
+ "cacheWrite": 1.1,
261
+ "output": 4.4
262
+ }
263
+ }
264
+ }
@@ -1,31 +1,16 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.estimateCodexCostUsd = estimateCodexCostUsd;
7
+ const codex_price_snapshot_json_1 = __importDefault(require("./codex-price-snapshot.json"));
4
8
  /**
5
- * Standard-tier USD prices per 1M tokens. Codex's JSONL stream reports usage
6
- * but not dollars, so the runtime needs a local price snapshot to turn that
7
- * usage into project spend. Keep this deliberately limited to models Navarch
8
- * offers rather than silently applying the wrong price to custom/gateway ids.
9
- *
10
- * Source (checked 2026-09-07): https://developers.openai.com/api/docs/pricing
9
+ * Standard short-context API-equivalent rates. Generated alongside the Worker
10
+ * snapshot by scripts/navarch-refresh-api-model-prices.mjs. This is not a
11
+ * subscription charge or invoice; speed, region and context uplifts are excluded.
11
12
  */
12
- const CODEX_RATES = {
13
- // Standard short-context estimate, verified 2026-09-07 against the pricing
14
- // source above. As with other runtime estimates, this excludes tier uplifts.
15
- "gpt-6-astra": {
16
- input: 10,
17
- cachedInput: 1,
18
- cacheWrite: 12.5,
19
- output: 50,
20
- },
21
- // Promotional standard rates, available at least through 2026-11-21.
22
- "gpt-5.6-sol": {
23
- input: 4,
24
- cachedInput: 0.4,
25
- cacheWrite: 5,
26
- output: 20,
27
- },
28
- };
13
+ const CODEX_RATES = codex_price_snapshot_json_1.default.models;
29
14
  function nonnegative(value) {
30
15
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
31
16
  }
@@ -52,7 +37,12 @@ function priceUsage(usage, rates) {
52
37
  function estimateCodexCostUsd(events, model) {
53
38
  if (!model)
54
39
  return undefined;
55
- const rates = CODEX_RATES[model];
40
+ // Only first-party references and dated snapshots are safe to normalize.
41
+ // Custom gateways may charge different prices and remain unknown.
42
+ const id = model.trim().replace(/^openai\//, "");
43
+ // Own keys only: inherited names such as `constructor` are not models.
44
+ const own = (key) => (Object.hasOwn(CODEX_RATES, key) ? CODEX_RATES[key] : undefined);
45
+ const rates = own(id) ?? own(id.replace(/-20\d{2}-?\d{2}-?\d{2}$/, ""));
56
46
  if (!rates)
57
47
  return undefined;
58
48
  let sawTurnUsage = false;
@@ -225,9 +225,11 @@ class ConversationLoop {
225
225
  ...(shutdownSignal ? { signal: shutdownSignal } : {}),
226
226
  ...this.options.turnOverrides,
227
227
  log: this.log,
228
- prepareWorkspace: async ({ conversationId, repositoryUrl, workingBranch, mode, signal }) => {
228
+ prepareWorkspace: async ({ conversationId, repositoryUrl, workingBranch, gitCredential, mode, signal }) => {
229
+ if (!gitCredential)
230
+ throw new Error("Control plane did not provide the conversation Git credential");
229
231
  const workspace = await (0, workspace_cjs_1.prepareConversationWorkspace)({
230
- workspaceRoot: config.workspaceRoot, conversationId, repositoryUrl, workingBranch, env, signal, mode,
232
+ workspaceRoot: config.workspaceRoot, conversationId, repositoryUrl, workingBranch, gitCredential, env, signal, mode,
231
233
  ...(this.options.gitRunner ? { runner: this.options.gitRunner } : {}),
232
234
  ...(this.mirrors ? { mirrors: this.mirrors } : {}),
233
235
  });
@@ -300,7 +300,7 @@ async function runConversationTurn(deps, conversationId, turnId) {
300
300
  prompt = (0, prompt_cjs_1.buildConversationPrompt)(snapshot, journal.turnId, deps.adapter.agentType === "codex");
301
301
  // Older servers omit the working branch: the checkout stays on the default branch.
302
302
  const workingBranch = (0, workspace_cjs_1.validWorkingBranch)(claim.workingBranch);
303
- prepared = await deps.prepareWorkspace({ conversationId, repositoryUrl, workingBranch, mode: snapshot.mode ?? "read_only", signal: controller.signal });
303
+ prepared = await deps.prepareWorkspace({ conversationId, repositoryUrl, workingBranch, gitCredential: claim.gitCredential, mode: snapshot.mode ?? "read_only", signal: controller.signal });
304
304
  }
305
305
  catch (error) {
306
306
  if (!run.lost)
@@ -76,9 +76,8 @@ function conversationRoot(workspaceRoot, conversationId) {
76
76
  * The first turn clones; later turns of the same conversation reuse the
77
77
  * checkout so a follow-up sees the same revision as the first answer.
78
78
  *
79
- * The clone uses the machine's own git credentials (the same ones a local
80
- * `git clone` would use), never a Navarch server-side provider credential.
81
- * A repository this machine cannot read fails the turn instead of falling back.
79
+ * The control plane's project credential is used only by Git checkout subprocesses.
80
+ * It never enters the checkout URL, git config, journal or agent environment.
82
81
  * With `mirrors`, a new checkout is seeded from this machine's refreshed
83
82
  * mirror of the repository instead of a full network clone (see mirror.cts).
84
83
  */
@@ -127,15 +126,36 @@ async function prepareConversationWorkspace(options) {
127
126
  GIT_CONFIG_COUNT: "1",
128
127
  GIT_CONFIG_KEY_0: "core.hooksPath",
129
128
  GIT_CONFIG_VALUE_0: process.platform === "win32" ? "NUL" : "/dev/null",
129
+ ...(options.gitCredential ? {
130
+ NAVARCH_CONVERSATION_GIT_TOKEN: options.gitCredential,
131
+ GIT_CONFIG_COUNT: "5",
132
+ GIT_CONFIG_KEY_1: "credential.helper", GIT_CONFIG_VALUE_1: "",
133
+ GIT_CONFIG_KEY_2: `credential.${url}.helper`,
134
+ GIT_CONFIG_VALUE_2: `!f() { if [ "$1" = get ]; then printf '%s\\n' 'username=x-access-token' "password=$NAVARCH_CONVERSATION_GIT_TOKEN"; fi; }; f`,
135
+ GIT_CONFIG_KEY_3: "credential.useHttpPath", GIT_CONFIG_VALUE_3: "true",
136
+ GIT_CONFIG_KEY_4: "http.followRedirects", GIT_CONFIG_VALUE_4: "false",
137
+ } : {}),
130
138
  };
131
- const seeded = await options.mirrors?.seedCheckout({ url, branch, checkout: workspace.checkout, env, signal: options.signal }) ?? false;
139
+ let seeded;
140
+ try {
141
+ seeded = await options.mirrors?.seedCheckout({ url, branch, checkout: workspace.checkout, env, signal: options.signal }) ?? false;
142
+ }
143
+ catch {
144
+ throw new Error("Conversation git mirror checkout could not run");
145
+ }
132
146
  if (!seeded) {
133
- const result = await runner.run("git", ["clone", "--quiet", "--filter=blob:none", "--no-tags", ...(branch ? ["--branch", branch] : []), "--", url, workspace.checkout], { cwd: root, env, timeoutMs: CLONE_TIMEOUT_MS, signal: options.signal });
147
+ let result;
148
+ try {
149
+ result = await runner.run("git", ["clone", "--quiet", "--filter=blob:none", "--no-tags", ...(branch ? ["--branch", branch] : []), "--", url, workspace.checkout], { cwd: root, env, timeoutMs: CLONE_TIMEOUT_MS, signal: options.signal });
150
+ }
151
+ catch {
152
+ // A command runner or credential helper can put secrets in an exception.
153
+ throw new Error("Conversation git clone could not run");
154
+ }
134
155
  if (result.code !== 0) {
135
156
  await node_fs_1.promises.rm(workspace.checkout, { recursive: true, force: true }).catch(() => undefined);
136
- throw new Error(`git clone failed with exit ${result.code}: ${result.stderr.slice(-500)}`);
157
+ throw new Error(`git clone failed with exit ${result.code}; check the project's GitHub connection and repository access`);
137
158
  }
138
- // This machine can read the repository: build the mirror for the next conversation.
139
159
  void options.mirrors?.warm(url, env, options.signal);
140
160
  }
141
161
  await node_fs_1.promises.writeFile(marker, identity, { encoding: "utf8", mode: 0o600 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sagentlab/navarch-runtime",
3
- "version": "0.1.143",
3
+ "version": "0.1.145",
4
4
  "description": "Navarch machine-side session manager: claims delivery tasks and runs them through local coding agents.",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",