@usabledev/usable-chat 1.208.0 → 1.209.1

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.
Files changed (2) hide show
  1. package/cli.js +229 -24
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -29452,7 +29452,24 @@ function convertToOpenRouterMessages(messages4, modelId) {
29452
29452
  });
29453
29453
  }
29454
29454
  }
29455
- return messages4.map((msg) => {
29455
+ const normalizedMessages = messages4.flatMap((message2) => {
29456
+ if (message2.role !== "user" || !Array.isArray(message2.content)) return [message2];
29457
+ const blocks2 = message2.content;
29458
+ const results = blocks2.filter((block2) => block2.type === "tool_result");
29459
+ if (!results.length) return [message2];
29460
+ const other2 = blocks2.filter((block2) => block2.type !== "tool_result");
29461
+ return [
29462
+ ...results.map(
29463
+ (block2) => ({
29464
+ role: "tool",
29465
+ tool_call_id: block2.tool_use_id,
29466
+ content: `${block2.is_error ? "[TOOL ERROR] " : ""}${typeof block2.content === "string" ? block2.content : JSON.stringify(block2.content)}`
29467
+ })
29468
+ ),
29469
+ ...other2.length ? [{ ...message2, content: other2 }] : []
29470
+ ];
29471
+ });
29472
+ return normalizedMessages.map((msg) => {
29456
29473
  const extMsg = msg;
29457
29474
  let content = extMsg.content;
29458
29475
  if (Array.isArray(content)) {
@@ -45580,6 +45597,21 @@ var init_model_pricing = __esm({
45580
45597
  "src/lib/model-pricing.ts"() {
45581
45598
  "use strict";
45582
45599
  MODEL_PRICING = {
45600
+ "openai/gpt-6-sol": {
45601
+ input: 2e-6,
45602
+ output: 1e-5,
45603
+ multiplier: 16
45604
+ },
45605
+ "openai/gpt-6-luna": {
45606
+ input: 1e-7,
45607
+ output: 5e-7,
45608
+ multiplier: 1
45609
+ },
45610
+ "anthropic/claude-opus-5.5": {
45611
+ input: 4e-6,
45612
+ output: 2e-5,
45613
+ multiplier: 32
45614
+ },
45583
45615
  // Amazon Models
45584
45616
  "amazon/nova-2-lite-v1": {
45585
45617
  input: 3e-7,
@@ -46912,6 +46944,75 @@ var init_model_registry_generated = __esm({
46912
46944
  "src/lib/model-registry-generated.ts"() {
46913
46945
  "use strict";
46914
46946
  GENERATED_MODELS = [
46947
+ {
46948
+ id: "openai/gpt-6-luna",
46949
+ displayName: "GPT-6 Luna",
46950
+ vendor: "openai",
46951
+ category: "fast",
46952
+ capabilities: {
46953
+ vision: true,
46954
+ reasoning: true,
46955
+ maxTokens: 128e3,
46956
+ contextLength: 105e4
46957
+ },
46958
+ pricing: {
46959
+ inputPer1M: 0.1,
46960
+ outputPer1M: 0.5,
46961
+ multiplier: 1
46962
+ },
46963
+ availability: {
46964
+ mainChat: false,
46965
+ experts: true,
46966
+ embeds: true
46967
+ },
46968
+ createdAt: 1790100786
46969
+ },
46970
+ {
46971
+ id: "openai/gpt-6-sol",
46972
+ displayName: "GPT-6 Sol",
46973
+ vendor: "openai",
46974
+ category: "balanced",
46975
+ capabilities: {
46976
+ vision: true,
46977
+ reasoning: true,
46978
+ maxTokens: 128e3,
46979
+ contextLength: 105e4
46980
+ },
46981
+ pricing: {
46982
+ inputPer1M: 2,
46983
+ outputPer1M: 10,
46984
+ multiplier: 16
46985
+ },
46986
+ availability: {
46987
+ mainChat: false,
46988
+ experts: true,
46989
+ embeds: true
46990
+ },
46991
+ createdAt: 1790100775
46992
+ },
46993
+ {
46994
+ id: "anthropic/claude-opus-5.5",
46995
+ displayName: "Claude Opus 5.5",
46996
+ vendor: "anthropic",
46997
+ category: "powerful",
46998
+ capabilities: {
46999
+ vision: true,
47000
+ reasoning: true,
47001
+ maxTokens: 128e3,
47002
+ contextLength: 1e6
47003
+ },
47004
+ pricing: {
47005
+ inputPer1M: 4,
47006
+ outputPer1M: 20,
47007
+ multiplier: 32
47008
+ },
47009
+ availability: {
47010
+ mainChat: false,
47011
+ experts: true,
47012
+ embeds: true
47013
+ },
47014
+ createdAt: 1790094732
47015
+ },
46915
47016
  {
46916
47017
  id: "openai/gpt-6-astra",
46917
47018
  displayName: "GPT-6 Astra",
@@ -52518,6 +52619,7 @@ var init_model_registry = __esm({
52518
52619
  "claude-sonnet-4-6": { bedrockId: "anthropic.claude-sonnet-4-6", crossRegion: true },
52519
52620
  "claude-sonnet-5": { bedrockId: "global.anthropic.claude-sonnet-5", crossRegion: false },
52520
52621
  "claude-opus-5": { bedrockId: "global.anthropic.claude-opus-5", crossRegion: false },
52622
+ "claude-opus-5-5": { bedrockId: "global.anthropic.claude-opus-5-5", crossRegion: false },
52521
52623
  // Opus 4.7 uses the Global Cross-Region Inference profile (no regional Geo access required)
52522
52624
  "claude-opus-4-7": { bedrockId: "global.anthropic.claude-opus-4-7", crossRegion: false },
52523
52625
  "claude-opus-4-20250514": {
@@ -138126,6 +138228,7 @@ function extractClaudeModel(modelId) {
138126
138228
  "anthropic/claude-opus-4.7": "claude-opus-4-7",
138127
138229
  "anthropic/claude-opus-4.8": "claude-opus-4-8",
138128
138230
  "anthropic/claude-opus-5": "claude-opus-5",
138231
+ "anthropic/claude-opus-5.5": "claude-opus-5-5",
138129
138232
  // Claude Fable models
138130
138233
  "anthropic/claude-fable-5": "claude-fable-5",
138131
138234
  "anthropic/claude-fable-5.1": "claude-fable-5-1",
@@ -165240,8 +165343,8 @@ var init_model_tiers = __esm({
165240
165343
  effort: "medium"
165241
165344
  },
165242
165345
  {
165243
- id: "openai/gpt-5.6-luna",
165244
- displayName: "GPT-5.6 Luna",
165346
+ id: "openai/gpt-6-luna",
165347
+ displayName: "GPT-6 Luna",
165245
165348
  description: "Efficient high-volume reasoning, multimodal input, and 1M+ context",
165246
165349
  provider: "OpenAI",
165247
165350
  multiLingual: true,
@@ -165271,8 +165374,8 @@ var init_model_tiers = __esm({
165271
165374
  zdr: true
165272
165375
  },
165273
165376
  {
165274
- id: "openai/gpt-5.6-terra",
165275
- displayName: "GPT-5.6 Terra",
165377
+ id: "openai/gpt-6-sol",
165378
+ displayName: "GPT-6 Sol",
165276
165379
  description: "Balanced intelligence and cost for reasoning, coding, and agents",
165277
165380
  provider: "OpenAI",
165278
165381
  multiLingual: true,
@@ -165285,8 +165388,8 @@ var init_model_tiers = __esm({
165285
165388
  name: "Deep Research",
165286
165389
  models: [
165287
165390
  {
165288
- id: "anthropic/claude-opus-5",
165289
- displayName: "Claude Opus 5",
165391
+ id: "anthropic/claude-opus-5.5",
165392
+ displayName: "Claude Opus 5.5",
165290
165393
  description: "Frontier coding, agents, architecture, and long-running research",
165291
165394
  provider: "Anthropic",
165292
165395
  costTier: "Very Expensive",
@@ -166063,6 +166166,7 @@ var init_model_config = __esm({
166063
166166
  "anthropic/claude-4.5-sonnet": { vision: true, reasoning: true },
166064
166167
  "anthropic/claude-opus-4.7": { vision: true, reasoning: false },
166065
166168
  "anthropic/claude-opus-5": { vision: true, reasoning: true },
166169
+ "anthropic/claude-opus-5.5": { vision: true, reasoning: true },
166066
166170
  "anthropic/claude-fable-5.1": { vision: true, reasoning: true },
166067
166171
  "google/gemini-2.5-flash": { vision: true, reasoning: true },
166068
166172
  "google/gemini-2.5-flash-lite": { vision: true, reasoning: true },
@@ -166076,6 +166180,8 @@ var init_model_config = __esm({
166076
166180
  "openai/gpt-5.2-codex": { vision: true, reasoning: true },
166077
166181
  "openai/gpt-5.5": { vision: true, reasoning: true },
166078
166182
  "openai/gpt-5.6-sol": { vision: true, reasoning: true },
166183
+ "openai/gpt-6-sol": { vision: true, reasoning: true },
166184
+ "openai/gpt-6-luna": { vision: true, reasoning: true },
166079
166185
  "openai/gpt-6-astra": { vision: true, reasoning: true },
166080
166186
  "deepseek/deepseek-r1": { vision: false, reasoning: true }
166081
166187
  };
@@ -167300,6 +167406,25 @@ var init_logger3 = __esm({
167300
167406
  }
167301
167407
  });
167302
167408
 
167409
+ // src/core/ai/openrouter-tool-format.ts
167410
+ function toOpenRouterToolFormat(tools) {
167411
+ return tools.map(
167412
+ (tool2) => "input_schema" in tool2 ? {
167413
+ type: "function",
167414
+ function: {
167415
+ name: tool2.name,
167416
+ description: tool2.description,
167417
+ parameters: tool2.input_schema
167418
+ }
167419
+ } : tool2
167420
+ );
167421
+ }
167422
+ var init_openrouter_tool_format = __esm({
167423
+ "src/core/ai/openrouter-tool-format.ts"() {
167424
+ "use strict";
167425
+ }
167426
+ });
167427
+
167303
167428
  // src/lib/reasoning-config.ts
167304
167429
  function getReasoningConfig(modelId, hasReasoningCapability = false, forceEnable = true, reasoningEffort) {
167305
167430
  if (reasoningEffort === void 0) {
@@ -359561,30 +359686,99 @@ function matchOriginAgainstDomains(origin, domains) {
359561
359686
  if (!origin || domains.length === 0) {
359562
359687
  return false;
359563
359688
  }
359564
- let originHost;
359689
+ let parsedOrigin;
359565
359690
  try {
359566
- originHost = new URL(origin).hostname;
359691
+ parsedOrigin = new URL(origin);
359692
+ if (!["http:", "https:"].includes(parsedOrigin.protocol) || parsedOrigin.username || parsedOrigin.password)
359693
+ return false;
359567
359694
  } catch {
359568
359695
  return false;
359569
359696
  }
359570
359697
  return domains.some((allowed) => {
359571
- const isWildcard = allowed.startsWith("*.");
359572
- const allowedHost = isWildcard ? allowed.slice(2) : (() => {
359573
- try {
359574
- return new URL(allowed.startsWith("http") ? allowed : `https://${allowed}`).hostname;
359575
- } catch {
359576
- return allowed;
359577
- }
359578
- })();
359579
- if (isWildcard) {
359580
- return originHost.endsWith("." + allowedHost) || originHost === allowedHost;
359581
- }
359582
- return originHost === allowedHost;
359698
+ const rule = parseAllowedDomain(allowed);
359699
+ if (!rule) return false;
359700
+ if (rule.kind === "origin") return rule.value === parsedOrigin.origin;
359701
+ const host = parsedOrigin.hostname;
359702
+ return host === rule.value || rule.kind === "wildcard" && host.endsWith("." + rule.value);
359583
359703
  });
359584
359704
  }
359705
+ function isValidAllowedDomain(value) {
359706
+ return parseAllowedDomain(value) !== null;
359707
+ }
359708
+ function parseAllowedDomain(allowed) {
359709
+ if ([...allowed].some((char2) => char2.charCodeAt(0) <= 32 || char2.charCodeAt(0) === 127))
359710
+ return null;
359711
+ if (/^[a-z][a-z0-9+.-]*:/i.test(allowed)) {
359712
+ if (!explicitOriginPattern.test(allowed) || allowed.includes("*")) return null;
359713
+ try {
359714
+ const configured = new URL(allowed);
359715
+ if (!["http:", "https:"].includes(configured.protocol) || configured.username || configured.password || configured.pathname !== "/" || configured.search || configured.hash)
359716
+ return null;
359717
+ return { kind: "origin", value: configured.origin };
359718
+ } catch {
359719
+ return null;
359720
+ }
359721
+ }
359722
+ const wildcard = allowed.startsWith("*.");
359723
+ const host = wildcard ? allowed.slice(2) : allowed;
359724
+ const ipv63 = !wildcard && ipv6HostPattern.test(host);
359725
+ if (!ipv63 && /[:/\\?#@%\s]/u.test(host)) return null;
359726
+ try {
359727
+ const normalized = new URL(`https://${host}`).hostname;
359728
+ if (!hostnamePattern.test(normalized) && !(ipv63 && ipv6HostPattern.test(normalized)))
359729
+ return null;
359730
+ return { kind: wildcard ? "wildcard" : "host", value: normalized };
359731
+ } catch {
359732
+ return null;
359733
+ }
359734
+ }
359735
+ var explicitOriginPattern, hostnamePattern, ipv6HostPattern, allowedDomainValidationMessage;
359585
359736
  var init_origin_matcher = __esm({
359586
359737
  "src/lib/utils/origin-matcher.ts"() {
359587
359738
  "use strict";
359739
+ explicitOriginPattern = /^https?:\/\/(?:\[[a-f0-9:.]+\]|[^:/\\?#@%\s]+)(?::[0-9]+)?\/?$/i;
359740
+ hostnamePattern = /^(?:[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9_])?\.)*[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9_])?\.?$/i;
359741
+ ipv6HostPattern = /^\[[a-f0-9:.]+\]$/i;
359742
+ allowedDomainValidationMessage = "Use an HTTP(S) origin without a path (https://example.com:8443), a bare hostname, or *.example.com. Scheme wildcards and bare host:port are not supported.";
359743
+ }
359744
+ });
359745
+
359746
+ // src/core/types/embed-key.ts
359747
+ var allowedDomainSchema, createEmbedKeyObjectSchema, createEmbedKeySchema, updateEmbedKeySchema, embedKeyAccessPolicySchema, rawUsablePatSchema;
359748
+ var init_embed_key = __esm({
359749
+ "src/core/types/embed-key.ts"() {
359750
+ "use strict";
359751
+ init_zod();
359752
+ init_origin_matcher();
359753
+ allowedDomainSchema = external_exports.string().min(1).refine(isValidAllowedDomain, allowedDomainValidationMessage);
359754
+ createEmbedKeyObjectSchema = external_exports.object({
359755
+ configId: external_exports.string().uuid(),
359756
+ label: external_exports.string().min(1).max(255),
359757
+ allowedDomains: external_exports.array(allowedDomainSchema).default([]),
359758
+ public: external_exports.boolean().default(false),
359759
+ expiresAt: external_exports.union([external_exports.date(), external_exports.string().datetime()]).optional()
359760
+ });
359761
+ createEmbedKeySchema = createEmbedKeyObjectSchema.refine(
359762
+ (data2) => data2.public || data2.allowedDomains.length > 0,
359763
+ {
359764
+ message: "At least one allowed domain is required when the key is not public",
359765
+ path: ["allowedDomains"]
359766
+ }
359767
+ );
359768
+ updateEmbedKeySchema = external_exports.object({
359769
+ label: external_exports.string().min(1).max(255).optional(),
359770
+ allowedDomains: external_exports.array(allowedDomainSchema).optional(),
359771
+ public: external_exports.boolean().optional(),
359772
+ expiresAt: external_exports.union([external_exports.date(), external_exports.string().datetime()]).nullable().optional()
359773
+ });
359774
+ embedKeyAccessPolicySchema = external_exports.object({
359775
+ public: external_exports.boolean(),
359776
+ allowedDomains: external_exports.array(allowedDomainSchema)
359777
+ }).refine((data2) => data2.public || data2.allowedDomains.length > 0, {
359778
+ message: "At least one allowed domain is required when the key is not public",
359779
+ path: ["allowedDomains"]
359780
+ });
359781
+ rawUsablePatSchema = external_exports.string().min(1).max(4096);
359588
359782
  }
359589
359783
  });
359590
359784
 
@@ -359710,7 +359904,16 @@ async function resolveEmbedKeyUncached(token, origin, options2) {
359710
359904
  if (key2.expiresAt && new Date(key2.expiresAt) < /* @__PURE__ */ new Date()) {
359711
359905
  return { success: false, error: { code: "KEY_EXPIRED", message: "This embed key has expired" } };
359712
359906
  }
359713
- if (key2.allowedDomains.length > 0 && !key2.public && !options2?.skipOriginCheck) {
359907
+ if (!key2.public && key2.allowedDomains.length === 0) {
359908
+ return {
359909
+ success: false,
359910
+ error: {
359911
+ code: "ORIGIN_NOT_ALLOWED",
359912
+ message: "This private embed key has no allowed domains"
359913
+ }
359914
+ };
359915
+ }
359916
+ if (!key2.public && !options2?.skipOriginCheck) {
359714
359917
  if (!origin) {
359715
359918
  return {
359716
359919
  success: false,
@@ -359762,6 +359965,7 @@ var EMBED_KEY_CACHE_TTL_MS, EMBED_KEY_CACHE_MAX_ENTRIES, embedKeyCache, EMBED_KE
359762
359965
  var init_embed_key_service = __esm({
359763
359966
  "src/lib/services/embed-key.service.ts"() {
359764
359967
  "use strict";
359968
+ init_embed_key();
359765
359969
  init_client7();
359766
359970
  init_schema_embed_keys();
359767
359971
  init_schema3();
@@ -364010,7 +364214,7 @@ async function callLLM({
364010
364214
  stream_options: {
364011
364215
  include_usage: true
364012
364216
  },
364013
- tools,
364217
+ tools: tools ? toOpenRouterToolFormat(tools) : void 0,
364014
364218
  tool_choice: shouldEnableTools ? forcedToolName ? { type: "function", function: { name: forcedToolName } } : "auto" : void 0,
364015
364219
  temperature,
364016
364220
  max_tokens: maxTokens,
@@ -368256,6 +368460,7 @@ var init_orchestrator = __esm({
368256
368460
  init_mcp();
368257
368461
  init_model_registry();
368258
368462
  init_openrouter_direct();
368463
+ init_openrouter_tool_format();
368259
368464
  init_codex_direct();
368260
368465
  init_reasoning_config();
368261
368466
  init_claude_stream_adapter();
@@ -391609,7 +391814,7 @@ init_tui_select();
391609
391814
  init_model_registry();
391610
391815
 
391611
391816
  // package.json
391612
- var version2 = "1.208.0";
391817
+ var version2 = "1.209.1";
391613
391818
 
391614
391819
  // src/adapters/cli/model-catalog.ts
391615
391820
  init_codex_auth();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usabledev/usable-chat",
3
- "version": "1.208.0",
3
+ "version": "1.209.1",
4
4
  "description": "usable-chat — terminal harness for usable-chat (headless + TUI)",
5
5
  "type": "module",
6
6
  "bin": {