@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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/models.ts
2
2
  var MODEL_ALIASES = {
3
- // Claude
3
+ // Claude - short names
4
4
  claude: "anthropic/claude-sonnet-4",
5
5
  sonnet: "anthropic/claude-sonnet-4",
6
6
  opus: "anthropic/claude-opus-4.6",
@@ -8,6 +8,11 @@ var MODEL_ALIASES = {
8
8
  "opus-46": "anthropic/claude-opus-4.6",
9
9
  "opus-45": "anthropic/claude-opus-4.5",
10
10
  haiku: "anthropic/claude-haiku-4.5",
11
+ // Claude - provider/shortname patterns (common in agent frameworks)
12
+ "anthropic/sonnet": "anthropic/claude-sonnet-4",
13
+ "anthropic/opus": "anthropic/claude-opus-4.6",
14
+ "anthropic/haiku": "anthropic/claude-haiku-4.5",
15
+ "anthropic/claude": "anthropic/claude-sonnet-4",
11
16
  // OpenAI
12
17
  gpt: "openai/gpt-4o",
13
18
  gpt4: "openai/gpt-4o",
@@ -3474,174 +3479,6 @@ var PROXY_PORT = (() => {
3474
3479
  return DEFAULT_PORT;
3475
3480
  })();
3476
3481
 
3477
- // src/journal.ts
3478
- var DEFAULT_CONFIG2 = {
3479
- maxEntries: 100,
3480
- maxAgeMs: 24 * 60 * 60 * 1e3,
3481
- // 24 hours
3482
- maxEventsPerResponse: 5
3483
- };
3484
- var SessionJournal = class {
3485
- journals = /* @__PURE__ */ new Map();
3486
- config;
3487
- constructor(config) {
3488
- this.config = { ...DEFAULT_CONFIG2, ...config };
3489
- }
3490
- /**
3491
- * Extract key events from assistant response content.
3492
- * Looks for patterns like "I created...", "I fixed...", "Successfully..."
3493
- */
3494
- extractEvents(content) {
3495
- if (!content || typeof content !== "string") {
3496
- return [];
3497
- }
3498
- const events = [];
3499
- const seen = /* @__PURE__ */ new Set();
3500
- const patterns = [
3501
- // Creation patterns
3502
- /I (?:also |then |have |)?(?:created|implemented|added|wrote|built|generated|set up|initialized) ([^.!?\n]{10,150})/gi,
3503
- // Fix patterns
3504
- /I (?:also |then |have |)?(?:fixed|resolved|solved|patched|corrected|addressed|debugged) ([^.!?\n]{10,150})/gi,
3505
- // Completion patterns
3506
- /I (?:also |then |have |)?(?:completed|finished|done with|wrapped up) ([^.!?\n]{10,150})/gi,
3507
- // Update patterns
3508
- /I (?:also |then |have |)?(?:updated|modified|changed|refactored|improved|enhanced|optimized) ([^.!?\n]{10,150})/gi,
3509
- // Success patterns
3510
- /Successfully ([^.!?\n]{10,150})/gi,
3511
- // Tool usage patterns (when agent uses tools)
3512
- /I (?:also |then |have |)?(?:ran|executed|called|invoked) ([^.!?\n]{10,100})/gi
3513
- ];
3514
- for (const pattern of patterns) {
3515
- pattern.lastIndex = 0;
3516
- let match;
3517
- while ((match = pattern.exec(content)) !== null) {
3518
- const action = match[0].trim();
3519
- const normalized = action.toLowerCase();
3520
- if (seen.has(normalized)) {
3521
- continue;
3522
- }
3523
- if (action.length >= 15 && action.length <= 200) {
3524
- events.push(action);
3525
- seen.add(normalized);
3526
- }
3527
- if (events.length >= this.config.maxEventsPerResponse) {
3528
- break;
3529
- }
3530
- }
3531
- if (events.length >= this.config.maxEventsPerResponse) {
3532
- break;
3533
- }
3534
- }
3535
- return events;
3536
- }
3537
- /**
3538
- * Record events to the session journal.
3539
- */
3540
- record(sessionId, events, model) {
3541
- if (!sessionId || !events.length) {
3542
- return;
3543
- }
3544
- const journal = this.journals.get(sessionId) || [];
3545
- const now = Date.now();
3546
- for (const action of events) {
3547
- journal.push({
3548
- timestamp: now,
3549
- action,
3550
- model
3551
- });
3552
- }
3553
- const cutoff = now - this.config.maxAgeMs;
3554
- const trimmed = journal.filter((e) => e.timestamp > cutoff).slice(-this.config.maxEntries);
3555
- this.journals.set(sessionId, trimmed);
3556
- }
3557
- /**
3558
- * Check if the user message indicates a need for historical context.
3559
- */
3560
- needsContext(lastUserMessage) {
3561
- if (!lastUserMessage || typeof lastUserMessage !== "string") {
3562
- return false;
3563
- }
3564
- const lower = lastUserMessage.toLowerCase();
3565
- const triggers = [
3566
- // Direct questions about past work
3567
- "what did you do",
3568
- "what have you done",
3569
- "what did we do",
3570
- "what have we done",
3571
- // Temporal references
3572
- "earlier",
3573
- "before",
3574
- "previously",
3575
- "this session",
3576
- "today",
3577
- "so far",
3578
- // Summary requests
3579
- "remind me",
3580
- "summarize",
3581
- "summary of",
3582
- "recap",
3583
- // Progress inquiries
3584
- "your work",
3585
- "your progress",
3586
- "accomplished",
3587
- "achievements",
3588
- "completed tasks"
3589
- ];
3590
- return triggers.some((t) => lower.includes(t));
3591
- }
3592
- /**
3593
- * Format the journal for injection into system message.
3594
- * Returns null if journal is empty.
3595
- */
3596
- format(sessionId) {
3597
- const journal = this.journals.get(sessionId);
3598
- if (!journal?.length) {
3599
- return null;
3600
- }
3601
- const lines = journal.map((e) => {
3602
- const time = new Date(e.timestamp).toLocaleTimeString("en-US", {
3603
- hour: "2-digit",
3604
- minute: "2-digit",
3605
- hour12: true
3606
- });
3607
- return `- ${time}: ${e.action}`;
3608
- });
3609
- return `[Session Memory - Key Actions]
3610
- ${lines.join("\n")}`;
3611
- }
3612
- /**
3613
- * Get the raw journal entries for a session (for debugging/testing).
3614
- */
3615
- getEntries(sessionId) {
3616
- return this.journals.get(sessionId) || [];
3617
- }
3618
- /**
3619
- * Clear journal for a specific session.
3620
- */
3621
- clear(sessionId) {
3622
- this.journals.delete(sessionId);
3623
- }
3624
- /**
3625
- * Clear all journals.
3626
- */
3627
- clearAll() {
3628
- this.journals.clear();
3629
- }
3630
- /**
3631
- * Get stats about the journal.
3632
- */
3633
- getStats() {
3634
- let totalEntries = 0;
3635
- for (const entries of this.journals.values()) {
3636
- totalEntries += entries.length;
3637
- }
3638
- return {
3639
- sessions: this.journals.size,
3640
- totalEntries
3641
- };
3642
- }
3643
- };
3644
-
3645
3482
  // src/proxy.ts
3646
3483
  var BLOCKRUN_API = "https://blockrun.ai/api";
3647
3484
  var AUTO_MODEL = "blockrun/auto";
@@ -4051,7 +3888,6 @@ async function startProxy(options) {
4051
3888
  const deduplicator = new RequestDeduplicator();
4052
3889
  const responseCache = new ResponseCache(options.cacheConfig);
4053
3890
  const sessionStore = new SessionStore(options.sessionConfig);
4054
- const sessionJournal = new SessionJournal();
4055
3891
  const connections = /* @__PURE__ */ new Set();
4056
3892
  const server = createServer(async (req, res) => {
4057
3893
  req.on("error", (err) => {
@@ -4147,8 +3983,7 @@ async function startProxy(options) {
4147
3983
  deduplicator,
4148
3984
  balanceMonitor,
4149
3985
  sessionStore,
4150
- responseCache,
4151
- sessionJournal
3986
+ responseCache
4152
3987
  );
4153
3988
  } catch (err) {
4154
3989
  const error = err instanceof Error ? err : new Error(String(err));
@@ -4349,7 +4184,7 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
4349
4184
  };
4350
4185
  }
4351
4186
  }
4352
- async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, deduplicator, balanceMonitor, sessionStore, responseCache, sessionJournal) {
4187
+ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, deduplicator, balanceMonitor, sessionStore, responseCache) {
4353
4188
  const startTime = Date.now();
4354
4189
  const upstreamUrl = `${apiBase}${req.url}`;
4355
4190
  const bodyChunks = [];
@@ -4362,38 +4197,13 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4362
4197
  let modelId = "";
4363
4198
  let maxTokens = 4096;
4364
4199
  let routingProfile = null;
4365
- let accumulatedContent = "";
4366
4200
  const isChatCompletion = req.url?.includes("/chat/completions");
4367
- const sessionId = getSessionId(req.headers);
4368
4201
  if (isChatCompletion && body.length > 0) {
4369
4202
  try {
4370
4203
  const parsed = JSON.parse(body.toString());
4371
4204
  isStreaming = parsed.stream === true;
4372
4205
  modelId = parsed.model || "";
4373
4206
  maxTokens = parsed.max_tokens || 4096;
4374
- if (sessionId && Array.isArray(parsed.messages)) {
4375
- const messages = parsed.messages;
4376
- const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
4377
- const lastContent = typeof lastUserMsg?.content === "string" ? lastUserMsg.content : "";
4378
- if (sessionJournal.needsContext(lastContent)) {
4379
- const journalText = sessionJournal.format(sessionId);
4380
- if (journalText) {
4381
- const sysIdx = messages.findIndex((m) => m.role === "system");
4382
- if (sysIdx >= 0 && typeof messages[sysIdx].content === "string") {
4383
- messages[sysIdx] = {
4384
- ...messages[sysIdx],
4385
- content: journalText + "\n\n" + messages[sysIdx].content
4386
- };
4387
- } else {
4388
- messages.unshift({ role: "system", content: journalText });
4389
- }
4390
- parsed.messages = messages;
4391
- console.log(
4392
- `[ClawRouter] Injected session journal (${journalText.length} chars) for session ${sessionId.slice(0, 8)}...`
4393
- );
4394
- }
4395
- }
4396
- }
4397
4207
  let bodyModified = false;
4398
4208
  if (parsed.stream === true) {
4399
4209
  parsed.stream = false;
@@ -4433,18 +4243,18 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4433
4243
  latencyMs: 0
4434
4244
  });
4435
4245
  } else {
4436
- const sessionId2 = getSessionId(
4246
+ const sessionId = getSessionId(
4437
4247
  req.headers
4438
4248
  );
4439
- const existingSession = sessionId2 ? sessionStore.getSession(sessionId2) : void 0;
4249
+ const existingSession = sessionId ? sessionStore.getSession(sessionId) : void 0;
4440
4250
  if (existingSession) {
4441
4251
  console.log(
4442
- `[ClawRouter] Session ${sessionId2?.slice(0, 8)}... using pinned model: ${existingSession.model}`
4252
+ `[ClawRouter] Session ${sessionId?.slice(0, 8)}... using pinned model: ${existingSession.model}`
4443
4253
  );
4444
4254
  parsed.model = existingSession.model;
4445
4255
  modelId = existingSession.model;
4446
4256
  bodyModified = true;
4447
- sessionStore.touchSession(sessionId2);
4257
+ sessionStore.touchSession(sessionId);
4448
4258
  } else {
4449
4259
  const messages = parsed.messages;
4450
4260
  let lastUserMsg;
@@ -4473,10 +4283,10 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4473
4283
  parsed.model = routingDecision.model;
4474
4284
  modelId = routingDecision.model;
4475
4285
  bodyModified = true;
4476
- if (sessionId2) {
4477
- sessionStore.setSession(sessionId2, routingDecision.model, routingDecision.tier);
4286
+ if (sessionId) {
4287
+ sessionStore.setSession(sessionId, routingDecision.model, routingDecision.tier);
4478
4288
  console.log(
4479
- `[ClawRouter] Session ${sessionId2.slice(0, 8)}... pinned to model: ${routingDecision.model}`
4289
+ `[ClawRouter] Session ${sessionId.slice(0, 8)}... pinned to model: ${routingDecision.model}`
4480
4290
  );
4481
4291
  }
4482
4292
  options.onRouted?.(routingDecision);
@@ -4811,9 +4621,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4811
4621
  const content = stripThinkingTokens(rawContent);
4812
4622
  const role = choice.message?.role ?? choice.delta?.role ?? "assistant";
4813
4623
  const index = choice.index ?? 0;
4814
- if (content) {
4815
- accumulatedContent += content;
4816
- }
4817
4624
  const roleChunk = {
4818
4625
  ...baseChunk,
4819
4626
  choices: [{ index, delta: { role }, logprobs: null, finish_reason: null }]
@@ -4927,22 +4734,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
4927
4734
  });
4928
4735
  console.log(`[ClawRouter] Cached response for ${modelId} (${responseBody.length} bytes)`);
4929
4736
  }
4930
- try {
4931
- const rspJson = JSON.parse(responseBody.toString());
4932
- if (rspJson.choices?.[0]?.message?.content) {
4933
- accumulatedContent = rspJson.choices[0].message.content;
4934
- }
4935
- } catch {
4936
- }
4937
- }
4938
- if (sessionId && accumulatedContent) {
4939
- const events = sessionJournal.extractEvents(accumulatedContent);
4940
- if (events.length > 0) {
4941
- sessionJournal.record(sessionId, events, actualModelUsed);
4942
- console.log(
4943
- `[ClawRouter] Recorded ${events.length} events to session journal for session ${sessionId.slice(0, 8)}...`
4944
- );
4945
- }
4946
4737
  }
4947
4738
  if (estimatedCostMicros !== void 0) {
4948
4739
  balanceMonitor.deductEstimated(estimatedCostMicros);