@codelia/core 0.1.3 → 0.1.10

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.cjs CHANGED
@@ -399,7 +399,12 @@ var CompactionService = class _CompactionService {
399
399
  if (!usage) {
400
400
  return false;
401
401
  }
402
- const contextLimit = await this.resolveContextLimit(llm, usage);
402
+ let contextLimit;
403
+ try {
404
+ contextLimit = await this.resolveContextLimit(llm, usage);
405
+ } catch {
406
+ return false;
407
+ }
403
408
  const threshold = Math.floor(contextLimit * this.config.thresholdRatio);
404
409
  return usage.total_tokens >= threshold;
405
410
  }
@@ -576,8 +581,33 @@ var CompactionService = class _CompactionService {
576
581
  const direct = resolveModel(this.modelRegistry, modelId, provider);
577
582
  if (direct) return direct;
578
583
  const baseId = stripSnapshotSuffix(modelId);
579
- if (!baseId || baseId === modelId) return void 0;
580
- return resolveModel(this.modelRegistry, baseId, provider);
584
+ if (baseId && baseId !== modelId) {
585
+ const baseSpec = resolveModel(this.modelRegistry, baseId, provider);
586
+ if (baseSpec) return baseSpec;
587
+ }
588
+ const qualified = parseQualifiedModelId(modelId);
589
+ if (qualified) {
590
+ const qualifiedDirect = resolveModel(this.modelRegistry, qualified.modelId, qualified.provider) ?? resolveModel(
591
+ this.modelRegistry,
592
+ `${qualified.provider}/${qualified.modelId}`,
593
+ qualified.provider
594
+ );
595
+ if (qualifiedDirect) return qualifiedDirect;
596
+ const qualifiedBaseId = stripSnapshotSuffix(qualified.modelId);
597
+ if (qualifiedBaseId && qualifiedBaseId !== qualified.modelId) {
598
+ const qualifiedBase = resolveModel(
599
+ this.modelRegistry,
600
+ qualifiedBaseId,
601
+ qualified.provider
602
+ ) ?? resolveModel(
603
+ this.modelRegistry,
604
+ `${qualified.provider}/${qualifiedBaseId}`,
605
+ qualified.provider
606
+ );
607
+ if (qualifiedBase) return qualifiedBase;
608
+ }
609
+ }
610
+ return resolveModel(this.modelRegistry, modelId);
581
611
  }
582
612
  static normalizeConfig(config) {
583
613
  const retainLastTurnsRaw = config.retainLastTurns ?? DEFAULT_RETAIN_LAST_TURNS;
@@ -600,6 +630,21 @@ var extractTag = (text, tag) => {
600
630
  return match?.[1]?.trim() ?? "";
601
631
  };
602
632
  var stripSnapshotSuffix = (modelId) => modelId.replace(/-[0-9]{4}-[0-9]{2}-[0-9]{2}$/, "");
633
+ var parseQualifiedModelId = (modelId) => {
634
+ const sep = modelId.indexOf("/");
635
+ if (sep <= 0 || sep >= modelId.length - 1) {
636
+ return null;
637
+ }
638
+ const providerRaw = modelId.slice(0, sep);
639
+ const rest = modelId.slice(sep + 1);
640
+ if (!rest) {
641
+ return null;
642
+ }
643
+ if (providerRaw !== "openai" && providerRaw !== "anthropic" && providerRaw !== "google") {
644
+ return null;
645
+ }
646
+ return { provider: providerRaw, modelId: rest };
647
+ };
603
648
  var extractAssistantText = (messages) => messages.flatMap((message) => {
604
649
  if (message.role !== "assistant" || message.content == null) {
605
650
  return [];
@@ -626,7 +671,7 @@ var extractAssistantText = (messages) => messages.flatMap((message) => {
626
671
  var DEFAULT_MAX_MESSAGE_BYTES = 50 * 1024;
627
672
  var DEFAULT_CONTEXT_RATIO = 0.25;
628
673
  var MIN_CONTEXT_BUDGET = 2e4;
629
- var MAX_CONTEXT_BUDGET = 6e4;
674
+ var MAX_CONTEXT_BUDGET = 1e5;
630
675
  var APPROX_BYTES_PER_TOKEN = 4;
631
676
  var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
632
677
  var contentToText = (content) => {
@@ -744,7 +789,11 @@ var ToolOutputCacheService = class {
744
789
  if (this.config.contextBudgetTokens !== void 0 && this.config.contextBudgetTokens !== null) {
745
790
  return this.config.contextBudgetTokens;
746
791
  }
747
- const modelSpec = resolveModel(this.modelRegistry, llm.model, llm.provider);
792
+ const modelSpec = resolveModelWithQualifiedFallback(
793
+ this.modelRegistry,
794
+ llm.provider,
795
+ llm.model
796
+ );
748
797
  const contextLimit = modelSpec?.contextWindow ?? modelSpec?.maxInputTokens ?? null;
749
798
  if (!contextLimit || contextLimit <= 0) {
750
799
  return MAX_CONTEXT_BUDGET;
@@ -753,6 +802,32 @@ var ToolOutputCacheService = class {
753
802
  return clamp(derived, MIN_CONTEXT_BUDGET, MAX_CONTEXT_BUDGET);
754
803
  }
755
804
  };
805
+ var resolveModelWithQualifiedFallback = (modelRegistry, provider, modelId) => {
806
+ const direct = resolveModel(modelRegistry, modelId, provider);
807
+ if (direct) return direct;
808
+ const qualified = parseQualifiedModelId2(modelId);
809
+ if (!qualified) return resolveModel(modelRegistry, modelId);
810
+ return resolveModel(modelRegistry, qualified.modelId, qualified.provider) ?? resolveModel(
811
+ modelRegistry,
812
+ `${qualified.provider}/${qualified.modelId}`,
813
+ qualified.provider
814
+ );
815
+ };
816
+ var parseQualifiedModelId2 = (modelId) => {
817
+ const sep = modelId.indexOf("/");
818
+ if (sep <= 0 || sep >= modelId.length - 1) {
819
+ return null;
820
+ }
821
+ const providerRaw = modelId.slice(0, sep);
822
+ const rest = modelId.slice(sep + 1);
823
+ if (!rest) {
824
+ return null;
825
+ }
826
+ if (providerRaw !== "openai" && providerRaw !== "anthropic" && providerRaw !== "google") {
827
+ return null;
828
+ }
829
+ return { provider: providerRaw, modelId: rest };
830
+ };
756
831
 
757
832
  // src/services/usage/service.ts
758
833
  var TokenUsageService = class {
@@ -916,10 +991,10 @@ var Agent = class {
916
991
  return null;
917
992
  }
918
993
  const modelId = usage.model ?? this.llm.model;
919
- const modelSpec = resolveModel(
994
+ const modelSpec = resolveModelWithQualifiedFallback2(
920
995
  this.modelRegistry,
921
- modelId,
922
- this.llm.provider
996
+ this.llm.provider,
997
+ modelId
923
998
  );
924
999
  const contextLimit = modelSpec?.contextWindow ?? modelSpec?.maxInputTokens ?? null;
925
1000
  if (!contextLimit || contextLimit <= 0) {
@@ -1151,6 +1226,7 @@ var Agent = class {
1151
1226
  type: "tool_call",
1152
1227
  tool: toolCall.function.name,
1153
1228
  args: jsonArgs,
1229
+ raw_args: toolCall.function.arguments,
1154
1230
  tool_call_id: toolCall.id
1155
1231
  };
1156
1232
  yield toolCallEvent;
@@ -1381,6 +1457,32 @@ ${assistantTexts.join("\n").trim()}`;
1381
1457
  }
1382
1458
  }
1383
1459
  };
1460
+ var resolveModelWithQualifiedFallback2 = (modelRegistry, provider, modelId) => {
1461
+ const direct = resolveModel(modelRegistry, modelId, provider);
1462
+ if (direct) return direct;
1463
+ const qualified = parseQualifiedModelId3(modelId);
1464
+ if (!qualified) return resolveModel(modelRegistry, modelId);
1465
+ return resolveModel(modelRegistry, qualified.modelId, qualified.provider) ?? resolveModel(
1466
+ modelRegistry,
1467
+ `${qualified.provider}/${qualified.modelId}`,
1468
+ qualified.provider
1469
+ );
1470
+ };
1471
+ var parseQualifiedModelId3 = (modelId) => {
1472
+ const sep = modelId.indexOf("/");
1473
+ if (sep <= 0 || sep >= modelId.length - 1) {
1474
+ return null;
1475
+ }
1476
+ const providerRaw = modelId.slice(0, sep);
1477
+ const rest = modelId.slice(sep + 1);
1478
+ if (!rest) {
1479
+ return null;
1480
+ }
1481
+ if (providerRaw !== "openai" && providerRaw !== "anthropic" && providerRaw !== "google") {
1482
+ return null;
1483
+ }
1484
+ return { provider: providerRaw, modelId: rest };
1485
+ };
1384
1486
 
1385
1487
  // src/llm/anthropic/chat.ts
1386
1488
  var import_sdk = __toESM(require("@anthropic-ai/sdk"), 1);
package/dist/index.d.cts CHANGED
@@ -174,6 +174,8 @@ type ModelLimits = {
174
174
  type ModelEntry = {
175
175
  provider: string;
176
176
  modelId: string;
177
+ releaseDate?: string;
178
+ lastUpdated?: string;
177
179
  cost?: ModelCost;
178
180
  limits?: ModelLimits;
179
181
  };
@@ -365,6 +367,19 @@ type RunStartRecord = {
365
367
  input: {
366
368
  type: "text";
367
369
  text: string;
370
+ } | {
371
+ type: "parts";
372
+ parts: Array<{
373
+ type: "text";
374
+ text: string;
375
+ } | {
376
+ type: "image_url";
377
+ image_url: {
378
+ url: string;
379
+ detail?: "auto" | "low" | "high";
380
+ media_type?: "image/png" | "image/jpeg" | "image/webp" | "image/gif";
381
+ };
382
+ }>;
368
383
  };
369
384
  ui_context?: unknown;
370
385
  meta?: Record<string, unknown>;
@@ -535,8 +550,8 @@ declare class Agent {
535
550
  private buildToolContext;
536
551
  private recordLlmRequest;
537
552
  private recordLlmResponse;
538
- run(message: string, options?: AgentRunOptions): Promise<string>;
539
- runStream(message: string, options?: AgentRunOptions): AsyncGenerator<AgentEvent>;
553
+ run(message: string | ContentPart[], options?: AgentRunOptions): Promise<string>;
554
+ runStream(message: string | ContentPart[], options?: AgentRunOptions): AsyncGenerator<AgentEvent>;
540
555
  private generateFinalResponse;
541
556
  private executeToolCall;
542
557
  }
package/dist/index.d.ts CHANGED
@@ -174,6 +174,8 @@ type ModelLimits = {
174
174
  type ModelEntry = {
175
175
  provider: string;
176
176
  modelId: string;
177
+ releaseDate?: string;
178
+ lastUpdated?: string;
177
179
  cost?: ModelCost;
178
180
  limits?: ModelLimits;
179
181
  };
@@ -365,6 +367,19 @@ type RunStartRecord = {
365
367
  input: {
366
368
  type: "text";
367
369
  text: string;
370
+ } | {
371
+ type: "parts";
372
+ parts: Array<{
373
+ type: "text";
374
+ text: string;
375
+ } | {
376
+ type: "image_url";
377
+ image_url: {
378
+ url: string;
379
+ detail?: "auto" | "low" | "high";
380
+ media_type?: "image/png" | "image/jpeg" | "image/webp" | "image/gif";
381
+ };
382
+ }>;
368
383
  };
369
384
  ui_context?: unknown;
370
385
  meta?: Record<string, unknown>;
@@ -535,8 +550,8 @@ declare class Agent {
535
550
  private buildToolContext;
536
551
  private recordLlmRequest;
537
552
  private recordLlmResponse;
538
- run(message: string, options?: AgentRunOptions): Promise<string>;
539
- runStream(message: string, options?: AgentRunOptions): AsyncGenerator<AgentEvent>;
553
+ run(message: string | ContentPart[], options?: AgentRunOptions): Promise<string>;
554
+ runStream(message: string | ContentPart[], options?: AgentRunOptions): AsyncGenerator<AgentEvent>;
540
555
  private generateFinalResponse;
541
556
  private executeToolCall;
542
557
  }
package/dist/index.js CHANGED
@@ -343,7 +343,12 @@ var CompactionService = class _CompactionService {
343
343
  if (!usage) {
344
344
  return false;
345
345
  }
346
- const contextLimit = await this.resolveContextLimit(llm, usage);
346
+ let contextLimit;
347
+ try {
348
+ contextLimit = await this.resolveContextLimit(llm, usage);
349
+ } catch {
350
+ return false;
351
+ }
347
352
  const threshold = Math.floor(contextLimit * this.config.thresholdRatio);
348
353
  return usage.total_tokens >= threshold;
349
354
  }
@@ -520,8 +525,33 @@ var CompactionService = class _CompactionService {
520
525
  const direct = resolveModel(this.modelRegistry, modelId, provider);
521
526
  if (direct) return direct;
522
527
  const baseId = stripSnapshotSuffix(modelId);
523
- if (!baseId || baseId === modelId) return void 0;
524
- return resolveModel(this.modelRegistry, baseId, provider);
528
+ if (baseId && baseId !== modelId) {
529
+ const baseSpec = resolveModel(this.modelRegistry, baseId, provider);
530
+ if (baseSpec) return baseSpec;
531
+ }
532
+ const qualified = parseQualifiedModelId(modelId);
533
+ if (qualified) {
534
+ const qualifiedDirect = resolveModel(this.modelRegistry, qualified.modelId, qualified.provider) ?? resolveModel(
535
+ this.modelRegistry,
536
+ `${qualified.provider}/${qualified.modelId}`,
537
+ qualified.provider
538
+ );
539
+ if (qualifiedDirect) return qualifiedDirect;
540
+ const qualifiedBaseId = stripSnapshotSuffix(qualified.modelId);
541
+ if (qualifiedBaseId && qualifiedBaseId !== qualified.modelId) {
542
+ const qualifiedBase = resolveModel(
543
+ this.modelRegistry,
544
+ qualifiedBaseId,
545
+ qualified.provider
546
+ ) ?? resolveModel(
547
+ this.modelRegistry,
548
+ `${qualified.provider}/${qualifiedBaseId}`,
549
+ qualified.provider
550
+ );
551
+ if (qualifiedBase) return qualifiedBase;
552
+ }
553
+ }
554
+ return resolveModel(this.modelRegistry, modelId);
525
555
  }
526
556
  static normalizeConfig(config) {
527
557
  const retainLastTurnsRaw = config.retainLastTurns ?? DEFAULT_RETAIN_LAST_TURNS;
@@ -544,6 +574,21 @@ var extractTag = (text, tag) => {
544
574
  return match?.[1]?.trim() ?? "";
545
575
  };
546
576
  var stripSnapshotSuffix = (modelId) => modelId.replace(/-[0-9]{4}-[0-9]{2}-[0-9]{2}$/, "");
577
+ var parseQualifiedModelId = (modelId) => {
578
+ const sep = modelId.indexOf("/");
579
+ if (sep <= 0 || sep >= modelId.length - 1) {
580
+ return null;
581
+ }
582
+ const providerRaw = modelId.slice(0, sep);
583
+ const rest = modelId.slice(sep + 1);
584
+ if (!rest) {
585
+ return null;
586
+ }
587
+ if (providerRaw !== "openai" && providerRaw !== "anthropic" && providerRaw !== "google") {
588
+ return null;
589
+ }
590
+ return { provider: providerRaw, modelId: rest };
591
+ };
547
592
  var extractAssistantText = (messages) => messages.flatMap((message) => {
548
593
  if (message.role !== "assistant" || message.content == null) {
549
594
  return [];
@@ -570,7 +615,7 @@ var extractAssistantText = (messages) => messages.flatMap((message) => {
570
615
  var DEFAULT_MAX_MESSAGE_BYTES = 50 * 1024;
571
616
  var DEFAULT_CONTEXT_RATIO = 0.25;
572
617
  var MIN_CONTEXT_BUDGET = 2e4;
573
- var MAX_CONTEXT_BUDGET = 6e4;
618
+ var MAX_CONTEXT_BUDGET = 1e5;
574
619
  var APPROX_BYTES_PER_TOKEN = 4;
575
620
  var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
576
621
  var contentToText = (content) => {
@@ -688,7 +733,11 @@ var ToolOutputCacheService = class {
688
733
  if (this.config.contextBudgetTokens !== void 0 && this.config.contextBudgetTokens !== null) {
689
734
  return this.config.contextBudgetTokens;
690
735
  }
691
- const modelSpec = resolveModel(this.modelRegistry, llm.model, llm.provider);
736
+ const modelSpec = resolveModelWithQualifiedFallback(
737
+ this.modelRegistry,
738
+ llm.provider,
739
+ llm.model
740
+ );
692
741
  const contextLimit = modelSpec?.contextWindow ?? modelSpec?.maxInputTokens ?? null;
693
742
  if (!contextLimit || contextLimit <= 0) {
694
743
  return MAX_CONTEXT_BUDGET;
@@ -697,6 +746,32 @@ var ToolOutputCacheService = class {
697
746
  return clamp(derived, MIN_CONTEXT_BUDGET, MAX_CONTEXT_BUDGET);
698
747
  }
699
748
  };
749
+ var resolveModelWithQualifiedFallback = (modelRegistry, provider, modelId) => {
750
+ const direct = resolveModel(modelRegistry, modelId, provider);
751
+ if (direct) return direct;
752
+ const qualified = parseQualifiedModelId2(modelId);
753
+ if (!qualified) return resolveModel(modelRegistry, modelId);
754
+ return resolveModel(modelRegistry, qualified.modelId, qualified.provider) ?? resolveModel(
755
+ modelRegistry,
756
+ `${qualified.provider}/${qualified.modelId}`,
757
+ qualified.provider
758
+ );
759
+ };
760
+ var parseQualifiedModelId2 = (modelId) => {
761
+ const sep = modelId.indexOf("/");
762
+ if (sep <= 0 || sep >= modelId.length - 1) {
763
+ return null;
764
+ }
765
+ const providerRaw = modelId.slice(0, sep);
766
+ const rest = modelId.slice(sep + 1);
767
+ if (!rest) {
768
+ return null;
769
+ }
770
+ if (providerRaw !== "openai" && providerRaw !== "anthropic" && providerRaw !== "google") {
771
+ return null;
772
+ }
773
+ return { provider: providerRaw, modelId: rest };
774
+ };
700
775
 
701
776
  // src/services/usage/service.ts
702
777
  var TokenUsageService = class {
@@ -860,10 +935,10 @@ var Agent = class {
860
935
  return null;
861
936
  }
862
937
  const modelId = usage.model ?? this.llm.model;
863
- const modelSpec = resolveModel(
938
+ const modelSpec = resolveModelWithQualifiedFallback2(
864
939
  this.modelRegistry,
865
- modelId,
866
- this.llm.provider
940
+ this.llm.provider,
941
+ modelId
867
942
  );
868
943
  const contextLimit = modelSpec?.contextWindow ?? modelSpec?.maxInputTokens ?? null;
869
944
  if (!contextLimit || contextLimit <= 0) {
@@ -1095,6 +1170,7 @@ var Agent = class {
1095
1170
  type: "tool_call",
1096
1171
  tool: toolCall.function.name,
1097
1172
  args: jsonArgs,
1173
+ raw_args: toolCall.function.arguments,
1098
1174
  tool_call_id: toolCall.id
1099
1175
  };
1100
1176
  yield toolCallEvent;
@@ -1325,6 +1401,32 @@ ${assistantTexts.join("\n").trim()}`;
1325
1401
  }
1326
1402
  }
1327
1403
  };
1404
+ var resolveModelWithQualifiedFallback2 = (modelRegistry, provider, modelId) => {
1405
+ const direct = resolveModel(modelRegistry, modelId, provider);
1406
+ if (direct) return direct;
1407
+ const qualified = parseQualifiedModelId3(modelId);
1408
+ if (!qualified) return resolveModel(modelRegistry, modelId);
1409
+ return resolveModel(modelRegistry, qualified.modelId, qualified.provider) ?? resolveModel(
1410
+ modelRegistry,
1411
+ `${qualified.provider}/${qualified.modelId}`,
1412
+ qualified.provider
1413
+ );
1414
+ };
1415
+ var parseQualifiedModelId3 = (modelId) => {
1416
+ const sep = modelId.indexOf("/");
1417
+ if (sep <= 0 || sep >= modelId.length - 1) {
1418
+ return null;
1419
+ }
1420
+ const providerRaw = modelId.slice(0, sep);
1421
+ const rest = modelId.slice(sep + 1);
1422
+ if (!rest) {
1423
+ return null;
1424
+ }
1425
+ if (providerRaw !== "openai" && providerRaw !== "anthropic" && providerRaw !== "google") {
1426
+ return null;
1427
+ }
1428
+ return { provider: providerRaw, modelId: rest };
1429
+ };
1328
1430
 
1329
1431
  // src/llm/anthropic/chat.ts
1330
1432
  import Anthropic from "@anthropic-ai/sdk";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codelia/core",
3
- "version": "0.1.3",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -24,8 +24,8 @@
24
24
  "access": "public"
25
25
  },
26
26
  "dependencies": {
27
- "@codelia/config": "0.1.3",
28
- "@codelia/shared-types": "0.1.3",
27
+ "@codelia/config": "0.1.10",
28
+ "@codelia/shared-types": "0.1.10",
29
29
  "@anthropic-ai/sdk": "^0.71.2",
30
30
  "@google-cloud/vertexai": "^1.10.0",
31
31
  "@google/genai": "^1.37.0",