@blockrun/clawrouter 0.9.13 → 0.9.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.
package/dist/cli.js CHANGED
@@ -1356,7 +1356,7 @@ function route(prompt, systemPrompt, maxOutputTokens, options) {
1356
1356
 
1357
1357
  // src/models.ts
1358
1358
  var MODEL_ALIASES = {
1359
- // Claude
1359
+ // Claude - short names
1360
1360
  claude: "anthropic/claude-sonnet-4",
1361
1361
  sonnet: "anthropic/claude-sonnet-4",
1362
1362
  opus: "anthropic/claude-opus-4.6",
@@ -1364,6 +1364,11 @@ var MODEL_ALIASES = {
1364
1364
  "opus-46": "anthropic/claude-opus-4.6",
1365
1365
  "opus-45": "anthropic/claude-opus-4.5",
1366
1366
  haiku: "anthropic/claude-haiku-4.5",
1367
+ // Claude - provider/shortname patterns (common in agent frameworks)
1368
+ "anthropic/sonnet": "anthropic/claude-sonnet-4",
1369
+ "anthropic/opus": "anthropic/claude-opus-4.6",
1370
+ "anthropic/haiku": "anthropic/claude-haiku-4.5",
1371
+ "anthropic/claude": "anthropic/claude-sonnet-4",
1367
1372
  // OpenAI
1368
1373
  gpt: "openai/gpt-4o",
1369
1374
  gpt4: "openai/gpt-4o",
@@ -3334,174 +3339,6 @@ var PROXY_PORT = (() => {
3334
3339
  return DEFAULT_PORT;
3335
3340
  })();
3336
3341
 
3337
- // src/journal.ts
3338
- var DEFAULT_CONFIG2 = {
3339
- maxEntries: 100,
3340
- maxAgeMs: 24 * 60 * 60 * 1e3,
3341
- // 24 hours
3342
- maxEventsPerResponse: 5
3343
- };
3344
- var SessionJournal = class {
3345
- journals = /* @__PURE__ */ new Map();
3346
- config;
3347
- constructor(config) {
3348
- this.config = { ...DEFAULT_CONFIG2, ...config };
3349
- }
3350
- /**
3351
- * Extract key events from assistant response content.
3352
- * Looks for patterns like "I created...", "I fixed...", "Successfully..."
3353
- */
3354
- extractEvents(content) {
3355
- if (!content || typeof content !== "string") {
3356
- return [];
3357
- }
3358
- const events = [];
3359
- const seen = /* @__PURE__ */ new Set();
3360
- const patterns = [
3361
- // Creation patterns
3362
- /I (?:also |then |have |)?(?:created|implemented|added|wrote|built|generated|set up|initialized) ([^.!?\n]{10,150})/gi,
3363
- // Fix patterns
3364
- /I (?:also |then |have |)?(?:fixed|resolved|solved|patched|corrected|addressed|debugged) ([^.!?\n]{10,150})/gi,
3365
- // Completion patterns
3366
- /I (?:also |then |have |)?(?:completed|finished|done with|wrapped up) ([^.!?\n]{10,150})/gi,
3367
- // Update patterns
3368
- /I (?:also |then |have |)?(?:updated|modified|changed|refactored|improved|enhanced|optimized) ([^.!?\n]{10,150})/gi,
3369
- // Success patterns
3370
- /Successfully ([^.!?\n]{10,150})/gi,
3371
- // Tool usage patterns (when agent uses tools)
3372
- /I (?:also |then |have |)?(?:ran|executed|called|invoked) ([^.!?\n]{10,100})/gi
3373
- ];
3374
- for (const pattern of patterns) {
3375
- pattern.lastIndex = 0;
3376
- let match;
3377
- while ((match = pattern.exec(content)) !== null) {
3378
- const action = match[0].trim();
3379
- const normalized = action.toLowerCase();
3380
- if (seen.has(normalized)) {
3381
- continue;
3382
- }
3383
- if (action.length >= 15 && action.length <= 200) {
3384
- events.push(action);
3385
- seen.add(normalized);
3386
- }
3387
- if (events.length >= this.config.maxEventsPerResponse) {
3388
- break;
3389
- }
3390
- }
3391
- if (events.length >= this.config.maxEventsPerResponse) {
3392
- break;
3393
- }
3394
- }
3395
- return events;
3396
- }
3397
- /**
3398
- * Record events to the session journal.
3399
- */
3400
- record(sessionId, events, model) {
3401
- if (!sessionId || !events.length) {
3402
- return;
3403
- }
3404
- const journal = this.journals.get(sessionId) || [];
3405
- const now = Date.now();
3406
- for (const action of events) {
3407
- journal.push({
3408
- timestamp: now,
3409
- action,
3410
- model
3411
- });
3412
- }
3413
- const cutoff = now - this.config.maxAgeMs;
3414
- const trimmed = journal.filter((e) => e.timestamp > cutoff).slice(-this.config.maxEntries);
3415
- this.journals.set(sessionId, trimmed);
3416
- }
3417
- /**
3418
- * Check if the user message indicates a need for historical context.
3419
- */
3420
- needsContext(lastUserMessage) {
3421
- if (!lastUserMessage || typeof lastUserMessage !== "string") {
3422
- return false;
3423
- }
3424
- const lower = lastUserMessage.toLowerCase();
3425
- const triggers = [
3426
- // Direct questions about past work
3427
- "what did you do",
3428
- "what have you done",
3429
- "what did we do",
3430
- "what have we done",
3431
- // Temporal references
3432
- "earlier",
3433
- "before",
3434
- "previously",
3435
- "this session",
3436
- "today",
3437
- "so far",
3438
- // Summary requests
3439
- "remind me",
3440
- "summarize",
3441
- "summary of",
3442
- "recap",
3443
- // Progress inquiries
3444
- "your work",
3445
- "your progress",
3446
- "accomplished",
3447
- "achievements",
3448
- "completed tasks"
3449
- ];
3450
- return triggers.some((t) => lower.includes(t));
3451
- }
3452
- /**
3453
- * Format the journal for injection into system message.
3454
- * Returns null if journal is empty.
3455
- */
3456
- format(sessionId) {
3457
- const journal = this.journals.get(sessionId);
3458
- if (!journal?.length) {
3459
- return null;
3460
- }
3461
- const lines = journal.map((e) => {
3462
- const time = new Date(e.timestamp).toLocaleTimeString("en-US", {
3463
- hour: "2-digit",
3464
- minute: "2-digit",
3465
- hour12: true
3466
- });
3467
- return `- ${time}: ${e.action}`;
3468
- });
3469
- return `[Session Memory - Key Actions]
3470
- ${lines.join("\n")}`;
3471
- }
3472
- /**
3473
- * Get the raw journal entries for a session (for debugging/testing).
3474
- */
3475
- getEntries(sessionId) {
3476
- return this.journals.get(sessionId) || [];
3477
- }
3478
- /**
3479
- * Clear journal for a specific session.
3480
- */
3481
- clear(sessionId) {
3482
- this.journals.delete(sessionId);
3483
- }
3484
- /**
3485
- * Clear all journals.
3486
- */
3487
- clearAll() {
3488
- this.journals.clear();
3489
- }
3490
- /**
3491
- * Get stats about the journal.
3492
- */
3493
- getStats() {
3494
- let totalEntries = 0;
3495
- for (const entries of this.journals.values()) {
3496
- totalEntries += entries.length;
3497
- }
3498
- return {
3499
- sessions: this.journals.size,
3500
- totalEntries
3501
- };
3502
- }
3503
- };
3504
-
3505
3342
  // src/proxy.ts
3506
3343
  var BLOCKRUN_API = "https://blockrun.ai/api";
3507
3344
  var AUTO_MODEL = "blockrun/auto";
@@ -3911,7 +3748,6 @@ async function startProxy(options) {
3911
3748
  const deduplicator = new RequestDeduplicator();
3912
3749
  const responseCache = new ResponseCache(options.cacheConfig);
3913
3750
  const sessionStore = new SessionStore(options.sessionConfig);
3914
- const sessionJournal = new SessionJournal();
3915
3751
  const connections = /* @__PURE__ */ new Set();
3916
3752
  const server = createServer(async (req, res) => {
3917
3753
  req.on("error", (err) => {
@@ -4007,8 +3843,7 @@ async function startProxy(options) {
4007
3843
  deduplicator,
4008
3844
  balanceMonitor,
4009
3845
  sessionStore,
4010
- responseCache,
4011
- sessionJournal
3846
+ responseCache
4012
3847
  );
4013
3848
  } catch (err) {
4014
3849
  const error = err instanceof Error ? err : new Error(String(err));
@@ -4209,7 +4044,7 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
4209
4044
  };
4210
4045
  }
4211
4046
  }
4212
- async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, deduplicator, balanceMonitor, sessionStore, responseCache, sessionJournal) {
4047
+ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, deduplicator, balanceMonitor, sessionStore, responseCache) {
4213
4048
  const startTime = Date.now();
4214
4049
  const upstreamUrl = `${apiBase}${req.url}`;
4215
4050
  const bodyChunks = [];
@@ -4222,38 +4057,13 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4222
4057
  let modelId = "";
4223
4058
  let maxTokens = 4096;
4224
4059
  let routingProfile = null;
4225
- let accumulatedContent = "";
4226
4060
  const isChatCompletion = req.url?.includes("/chat/completions");
4227
- const sessionId = getSessionId(req.headers);
4228
4061
  if (isChatCompletion && body.length > 0) {
4229
4062
  try {
4230
4063
  const parsed = JSON.parse(body.toString());
4231
4064
  isStreaming = parsed.stream === true;
4232
4065
  modelId = parsed.model || "";
4233
4066
  maxTokens = parsed.max_tokens || 4096;
4234
- if (sessionId && Array.isArray(parsed.messages)) {
4235
- const messages = parsed.messages;
4236
- const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
4237
- const lastContent = typeof lastUserMsg?.content === "string" ? lastUserMsg.content : "";
4238
- if (sessionJournal.needsContext(lastContent)) {
4239
- const journalText = sessionJournal.format(sessionId);
4240
- if (journalText) {
4241
- const sysIdx = messages.findIndex((m) => m.role === "system");
4242
- if (sysIdx >= 0 && typeof messages[sysIdx].content === "string") {
4243
- messages[sysIdx] = {
4244
- ...messages[sysIdx],
4245
- content: journalText + "\n\n" + messages[sysIdx].content
4246
- };
4247
- } else {
4248
- messages.unshift({ role: "system", content: journalText });
4249
- }
4250
- parsed.messages = messages;
4251
- console.log(
4252
- `[ClawRouter] Injected session journal (${journalText.length} chars) for session ${sessionId.slice(0, 8)}...`
4253
- );
4254
- }
4255
- }
4256
- }
4257
4067
  let bodyModified = false;
4258
4068
  if (parsed.stream === true) {
4259
4069
  parsed.stream = false;
@@ -4293,18 +4103,18 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4293
4103
  latencyMs: 0
4294
4104
  });
4295
4105
  } else {
4296
- const sessionId2 = getSessionId(
4106
+ const sessionId = getSessionId(
4297
4107
  req.headers
4298
4108
  );
4299
- const existingSession = sessionId2 ? sessionStore.getSession(sessionId2) : void 0;
4109
+ const existingSession = sessionId ? sessionStore.getSession(sessionId) : void 0;
4300
4110
  if (existingSession) {
4301
4111
  console.log(
4302
- `[ClawRouter] Session ${sessionId2?.slice(0, 8)}... using pinned model: ${existingSession.model}`
4112
+ `[ClawRouter] Session ${sessionId?.slice(0, 8)}... using pinned model: ${existingSession.model}`
4303
4113
  );
4304
4114
  parsed.model = existingSession.model;
4305
4115
  modelId = existingSession.model;
4306
4116
  bodyModified = true;
4307
- sessionStore.touchSession(sessionId2);
4117
+ sessionStore.touchSession(sessionId);
4308
4118
  } else {
4309
4119
  const messages = parsed.messages;
4310
4120
  let lastUserMsg;
@@ -4333,10 +4143,10 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4333
4143
  parsed.model = routingDecision.model;
4334
4144
  modelId = routingDecision.model;
4335
4145
  bodyModified = true;
4336
- if (sessionId2) {
4337
- sessionStore.setSession(sessionId2, routingDecision.model, routingDecision.tier);
4146
+ if (sessionId) {
4147
+ sessionStore.setSession(sessionId, routingDecision.model, routingDecision.tier);
4338
4148
  console.log(
4339
- `[ClawRouter] Session ${sessionId2.slice(0, 8)}... pinned to model: ${routingDecision.model}`
4149
+ `[ClawRouter] Session ${sessionId.slice(0, 8)}... pinned to model: ${routingDecision.model}`
4340
4150
  );
4341
4151
  }
4342
4152
  options.onRouted?.(routingDecision);
@@ -4671,9 +4481,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4671
4481
  const content = stripThinkingTokens(rawContent);
4672
4482
  const role = choice.message?.role ?? choice.delta?.role ?? "assistant";
4673
4483
  const index = choice.index ?? 0;
4674
- if (content) {
4675
- accumulatedContent += content;
4676
- }
4677
4484
  const roleChunk = {
4678
4485
  ...baseChunk,
4679
4486
  choices: [{ index, delta: { role }, logprobs: null, finish_reason: null }]
@@ -4787,22 +4594,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4787
4594
  });
4788
4595
  console.log(`[ClawRouter] Cached response for ${modelId} (${responseBody.length} bytes)`);
4789
4596
  }
4790
- try {
4791
- const rspJson = JSON.parse(responseBody.toString());
4792
- if (rspJson.choices?.[0]?.message?.content) {
4793
- accumulatedContent = rspJson.choices[0].message.content;
4794
- }
4795
- } catch {
4796
- }
4797
- }
4798
- if (sessionId && accumulatedContent) {
4799
- const events = sessionJournal.extractEvents(accumulatedContent);
4800
- if (events.length > 0) {
4801
- sessionJournal.record(sessionId, events, actualModelUsed);
4802
- console.log(
4803
- `[ClawRouter] Recorded ${events.length} events to session journal for session ${sessionId.slice(0, 8)}...`
4804
- );
4805
- }
4806
4597
  }
4807
4598
  if (estimatedCostMicros !== void 0) {
4808
4599
  balanceMonitor.deductEstimated(estimatedCostMicros);