@askalf/dario 4.8.123 → 4.8.124

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.
@@ -148,14 +148,35 @@ export const CC_AGENT_IDENTITY = TEMPLATE.agent_identity;
148
148
  export const CLIENT_SYSTEM_PREFACE = '\n\n---\n\nIMPORTANT: The operator of this session has supplied the following ' +
149
149
  'task-specific instructions. For this conversation they OVERRIDE any ' +
150
150
  'conflicting general behavior described above. Follow them exactly:\n\n';
151
+ // Memoize the stripped prompt by (base, level) (#642-audit): resolveSystemPrompt
152
+ // runs per request and stripBehavioralConstraints does ~12 regex passes over the
153
+ // ~25KB prompt. Keyed on the base STRING so a runtime template re-capture (a new
154
+ // base) correctly misses and re-strips. Bounded to a few bases; cleared if it
155
+ // somehow grows past a small cap.
156
+ const _stripCache = new Map();
157
+ function stripBehavioralConstraintsMemo(base, level) {
158
+ if (_stripCache.size > 8)
159
+ _stripCache.clear();
160
+ let byLevel = _stripCache.get(base);
161
+ if (!byLevel) {
162
+ byLevel = new Map();
163
+ _stripCache.set(base, byLevel);
164
+ }
165
+ let v = byLevel.get(level);
166
+ if (v === undefined) {
167
+ v = stripBehavioralConstraints(base, level);
168
+ byLevel.set(level, v);
169
+ }
170
+ return v;
171
+ }
151
172
  export function resolveSystemPrompt(arg, model) {
152
173
  const base = systemPromptForModel(model);
153
174
  if (!arg || arg === 'verbatim')
154
175
  return base;
155
176
  if (arg === 'partial')
156
- return stripBehavioralConstraints(base, 'partial');
177
+ return stripBehavioralConstraintsMemo(base, 'partial');
157
178
  if (arg === 'aggressive')
158
- return stripBehavioralConstraints(base, 'aggressive');
179
+ return stripBehavioralConstraintsMemo(base, 'aggressive');
159
180
  return arg;
160
181
  }
161
182
  /**
@@ -220,22 +220,37 @@ function envInt(name, dflt) {
220
220
  }
221
221
  async function fetchUpstreamBases(deps) {
222
222
  const f = deps.fetchImpl ?? fetch;
223
- const headers = {
224
- accept: 'application/json',
225
- 'anthropic-version': ANTHROPIC_VERSION,
226
- };
227
- if (deps.upstreamApiKey) {
228
- headers['x-api-key'] = deps.upstreamApiKey;
229
- }
230
- else {
231
- if (!deps.getToken)
232
- throw new Error('no token source for catalog fetch');
233
- headers['authorization'] = `Bearer ${await deps.getToken()}`;
234
- headers['anthropic-beta'] = OAUTH_BETA;
235
- }
223
+ // Arm the timeout FIRST so it bounds token acquisition too, not just the
224
+ // fetch (#642-audit): a hung getToken() (e.g. a stuck single-account OAuth
225
+ // refresh) would otherwise never settle, leaving the catalog `inflight` guard
226
+ // non-null forever and wedging every future refresh on the baked list.
236
227
  const ctl = new AbortController();
237
228
  const timer = setTimeout(() => ctl.abort(), deps.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS);
238
229
  try {
230
+ const headers = {
231
+ accept: 'application/json',
232
+ 'anthropic-version': ANTHROPIC_VERSION,
233
+ };
234
+ if (deps.upstreamApiKey) {
235
+ headers['x-api-key'] = deps.upstreamApiKey;
236
+ }
237
+ else {
238
+ if (!deps.getToken)
239
+ throw new Error('no token source for catalog fetch');
240
+ // Race token acquisition against the same abort deadline as the fetch.
241
+ const token = await Promise.race([
242
+ deps.getToken(),
243
+ new Promise((_, reject) => {
244
+ const onAbort = () => reject(new Error('catalog token acquisition timed out'));
245
+ if (ctl.signal.aborted)
246
+ onAbort();
247
+ else
248
+ ctl.signal.addEventListener('abort', onAbort, { once: true });
249
+ }),
250
+ ]);
251
+ headers['authorization'] = `Bearer ${token}`;
252
+ headers['anthropic-beta'] = OAUTH_BETA;
253
+ }
239
254
  const res = await f(`${ANTHROPIC_API}/v1/models?limit=100`, { headers, signal: ctl.signal });
240
255
  if (!res.ok)
241
256
  throw new Error(`upstream /v1/models ${res.status}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "4.8.123",
3
+ "version": "4.8.124",
4
4
  "description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
5
5
  "type": "module",
6
6
  "bin": {