@lobehub/chat 1.111.1 → 1.111.3

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 (131) hide show
  1. package/.cursor/rules/code-review.mdc +2 -19
  2. package/.cursor/rules/cursor-ux.mdc +0 -72
  3. package/.cursor/rules/project-introduce.mdc +5 -5
  4. package/.cursor/rules/react-component.mdc +92 -73
  5. package/.cursor/rules/rules-attach.mdc +28 -61
  6. package/.cursor/rules/system-role.mdc +8 -20
  7. package/.cursor/rules/typescript.mdc +55 -14
  8. package/CHANGELOG.md +52 -0
  9. package/changelog/v1.json +14 -0
  10. package/locales/ar/models.json +21 -3
  11. package/locales/bg-BG/models.json +21 -3
  12. package/locales/de-DE/models.json +21 -3
  13. package/locales/en-US/models.json +21 -3
  14. package/locales/es-ES/models.json +21 -3
  15. package/locales/fa-IR/models.json +21 -3
  16. package/locales/fr-FR/models.json +21 -3
  17. package/locales/it-IT/models.json +21 -3
  18. package/locales/ja-JP/models.json +21 -3
  19. package/locales/ko-KR/models.json +21 -3
  20. package/locales/nl-NL/models.json +21 -3
  21. package/locales/pl-PL/models.json +21 -3
  22. package/locales/pt-BR/models.json +21 -3
  23. package/locales/ru-RU/models.json +21 -3
  24. package/locales/tr-TR/models.json +21 -3
  25. package/locales/vi-VN/models.json +21 -3
  26. package/locales/zh-CN/models.json +21 -3
  27. package/locales/zh-TW/models.json +21 -3
  28. package/package.json +1 -1
  29. package/packages/types/src/aiModel.ts +67 -46
  30. package/packages/types/src/hotkey.ts +2 -0
  31. package/packages/types/src/llm.ts +3 -3
  32. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/PinList/index.tsx +3 -3
  33. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/TopActions.test.tsx +1 -0
  34. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/TopActions.tsx +11 -2
  35. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/index.tsx +2 -2
  36. package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Main.tsx +2 -2
  37. package/src/app/[variants]/(main)/chat/_layout/Desktop/SessionPanel.tsx +2 -2
  38. package/src/app/[variants]/(main)/discover/(detail)/model/[...slugs]/features/Details/Overview/ProviderList/index.tsx +23 -12
  39. package/src/app/[variants]/(main)/discover/(detail)/provider/[...slugs]/features/Details/Overview/ModelList/index.tsx +23 -10
  40. package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelItem.tsx +21 -12
  41. package/src/components/Thinking/index.tsx +53 -13
  42. package/src/config/aiModels/ai21.ts +8 -4
  43. package/src/config/aiModels/ai360.ts +28 -14
  44. package/src/config/aiModels/aihubmix.ts +174 -86
  45. package/src/config/aiModels/anthropic.ts +97 -38
  46. package/src/config/aiModels/azure.ts +54 -32
  47. package/src/config/aiModels/azureai.ts +63 -37
  48. package/src/config/aiModels/baichuan.ts +24 -12
  49. package/src/config/aiModels/bedrock.ts +60 -30
  50. package/src/config/aiModels/cohere.ts +60 -30
  51. package/src/config/aiModels/deepseek.ts +10 -6
  52. package/src/config/aiModels/fireworksai.ts +88 -44
  53. package/src/config/aiModels/giteeai.ts +1 -1
  54. package/src/config/aiModels/github.ts +44 -26
  55. package/src/config/aiModels/google.ts +119 -68
  56. package/src/config/aiModels/groq.ts +48 -24
  57. package/src/config/aiModels/higress.ts +617 -310
  58. package/src/config/aiModels/hunyuan.ts +105 -54
  59. package/src/config/aiModels/infiniai.ts +104 -52
  60. package/src/config/aiModels/internlm.ts +16 -8
  61. package/src/config/aiModels/jina.ts +4 -2
  62. package/src/config/aiModels/minimax.ts +11 -10
  63. package/src/config/aiModels/mistral.ts +40 -20
  64. package/src/config/aiModels/moonshot.ts +42 -22
  65. package/src/config/aiModels/novita.ts +196 -98
  66. package/src/config/aiModels/openai.ts +270 -137
  67. package/src/config/aiModels/openrouter.ts +205 -100
  68. package/src/config/aiModels/perplexity.ts +36 -6
  69. package/src/config/aiModels/ppio.ts +76 -38
  70. package/src/config/aiModels/qwen.ts +257 -133
  71. package/src/config/aiModels/sambanova.ts +56 -28
  72. package/src/config/aiModels/sensenova.ts +100 -50
  73. package/src/config/aiModels/siliconcloud.ts +224 -112
  74. package/src/config/aiModels/stepfun.ts +44 -22
  75. package/src/config/aiModels/taichu.ts +8 -4
  76. package/src/config/aiModels/tencentcloud.ts +12 -6
  77. package/src/config/aiModels/upstage.ts +8 -4
  78. package/src/config/aiModels/v0.ts +15 -12
  79. package/src/config/aiModels/vertexai.ts +49 -27
  80. package/src/config/aiModels/volcengine.ts +110 -51
  81. package/src/config/aiModels/wenxin.ts +179 -73
  82. package/src/config/aiModels/xai.ts +33 -19
  83. package/src/config/aiModels/zeroone.ts +48 -24
  84. package/src/config/aiModels/zhipu.ts +118 -69
  85. package/src/config/modelProviders/ai21.ts +0 -8
  86. package/src/config/modelProviders/ai360.ts +0 -20
  87. package/src/config/modelProviders/anthropic.ts +0 -56
  88. package/src/config/modelProviders/baichuan.ts +0 -30
  89. package/src/config/modelProviders/bedrock.ts +0 -74
  90. package/src/config/modelProviders/deepseek.ts +0 -13
  91. package/src/config/modelProviders/fireworksai.ts +0 -88
  92. package/src/config/modelProviders/google.ts +0 -59
  93. package/src/config/modelProviders/groq.ts +0 -48
  94. package/src/config/modelProviders/higress.ts +0 -727
  95. package/src/config/modelProviders/hunyuan.ts +0 -45
  96. package/src/config/modelProviders/infiniai.ts +0 -60
  97. package/src/config/modelProviders/internlm.ts +0 -8
  98. package/src/config/modelProviders/mistral.ts +0 -48
  99. package/src/config/modelProviders/modelscope.ts +2 -1
  100. package/src/config/modelProviders/openai.ts +5 -100
  101. package/src/config/modelProviders/openrouter.ts +0 -77
  102. package/src/config/modelProviders/ppio.ts +0 -95
  103. package/src/config/modelProviders/qwen.ts +0 -165
  104. package/src/config/modelProviders/sensenova.ts +0 -45
  105. package/src/config/modelProviders/siliconcloud.ts +0 -266
  106. package/src/config/modelProviders/stepfun.ts +0 -60
  107. package/src/config/modelProviders/taichu.ts +0 -10
  108. package/src/config/modelProviders/wenxin.ts +0 -90
  109. package/src/config/modelProviders/xai.ts +0 -16
  110. package/src/config/modelProviders/zeroone.ts +0 -60
  111. package/src/config/modelProviders/zhipu.ts +0 -80
  112. package/src/const/hotkeys.ts +6 -0
  113. package/src/features/Conversation/Extras/Usage/UsageDetail/ModelCard.tsx +4 -3
  114. package/src/features/Conversation/Extras/Usage/UsageDetail/pricing.ts +25 -15
  115. package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.test.ts +7 -5
  116. package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.ts +6 -5
  117. package/src/hooks/useHotkeys/chatScope.ts +2 -2
  118. package/src/hooks/useHotkeys/globalScope.ts +16 -4
  119. package/src/hooks/usePinnedAgentState.ts +21 -0
  120. package/src/hooks/useSwitchSession.ts +1 -1
  121. package/src/libs/model-runtime/utils/openaiCompatibleFactory/index.test.ts +54 -8
  122. package/src/locales/default/hotkey.ts +4 -0
  123. package/src/server/routers/lambda/agent.ts +2 -2
  124. package/src/server/routers/lambda/config/__snapshots__/index.test.ts.snap +0 -28
  125. package/src/server/services/discover/index.ts +7 -6
  126. package/src/server/services/user/index.ts +1 -2
  127. package/src/utils/__snapshots__/parseModels.test.ts.snap +28 -4
  128. package/src/utils/_deprecated/__snapshots__/parseModels.test.ts.snap +0 -8
  129. package/src/utils/parseModels.test.ts +60 -9
  130. package/src/utils/pricing.test.ts +183 -0
  131. package/src/utils/pricing.ts +90 -0
@@ -112,8 +112,20 @@ exports[`transformToChatModelCards > should have file with builtin models like g
112
112
  "enabled": true,
113
113
  "id": "gpt-4-0125-preview",
114
114
  "pricing": {
115
- "input": 10,
116
- "output": 30,
115
+ "units": [
116
+ {
117
+ "name": "textInput",
118
+ "rate": 10,
119
+ "strategy": "fixed",
120
+ "unit": "millionTokens",
121
+ },
122
+ {
123
+ "name": "textOutput",
124
+ "rate": 30,
125
+ "strategy": "fixed",
126
+ "unit": "millionTokens",
127
+ },
128
+ ],
117
129
  },
118
130
  "providerId": "openai",
119
131
  "releasedAt": "2024-01-25",
@@ -132,8 +144,20 @@ exports[`transformToChatModelCards > should have file with builtin models like g
132
144
  "enabled": true,
133
145
  "id": "gpt-4-turbo-2024-04-09",
134
146
  "pricing": {
135
- "input": 10,
136
- "output": 30,
147
+ "units": [
148
+ {
149
+ "name": "textInput",
150
+ "rate": 10,
151
+ "strategy": "fixed",
152
+ "unit": "millionTokens",
153
+ },
154
+ {
155
+ "name": "textOutput",
156
+ "rate": 30,
157
+ "strategy": "fixed",
158
+ "unit": "millionTokens",
159
+ },
160
+ ],
137
161
  },
138
162
  "providerId": "openai",
139
163
  "releasedAt": "2024-04-09",
@@ -89,10 +89,6 @@ exports[`transformToChatModelCards > should have file with builtin models like g
89
89
  "files": true,
90
90
  "functionCall": true,
91
91
  "id": "gpt-4-0125-preview",
92
- "pricing": {
93
- "input": 10,
94
- "output": 30,
95
- },
96
92
  },
97
93
  {
98
94
  "contextWindowTokens": 128000,
@@ -102,10 +98,6 @@ exports[`transformToChatModelCards > should have file with builtin models like g
102
98
  "files": true,
103
99
  "functionCall": true,
104
100
  "id": "gpt-4-turbo-2024-04-09",
105
- "pricing": {
106
- "input": 10,
107
- "output": 30,
108
- },
109
101
  "vision": true,
110
102
  },
111
103
  ]
@@ -732,9 +732,26 @@ describe('transformToChatModelCards', () => {
732
732
  id: 'gpt-4o',
733
733
  maxOutput: 4096,
734
734
  pricing: {
735
- cachedInput: 1.25,
736
- input: 2.5,
737
- output: 10,
735
+ units: [
736
+ {
737
+ name: 'textInput_cacheRead',
738
+ rate: 1.25,
739
+ strategy: 'fixed',
740
+ unit: 'millionTokens',
741
+ },
742
+ {
743
+ name: 'textInput',
744
+ rate: 2.5,
745
+ strategy: 'fixed',
746
+ unit: 'millionTokens',
747
+ },
748
+ {
749
+ name: 'textOutput',
750
+ rate: 10,
751
+ strategy: 'fixed',
752
+ unit: 'millionTokens',
753
+ },
754
+ ],
738
755
  },
739
756
  providerId: 'azure',
740
757
  releasedAt: '2024-05-13',
@@ -753,9 +770,26 @@ describe('transformToChatModelCards', () => {
753
770
  id: 'gpt-4o-mini',
754
771
  maxOutput: 4096,
755
772
  pricing: {
756
- cachedInput: 0.075,
757
- input: 0.15,
758
- output: 0.6,
773
+ units: [
774
+ {
775
+ name: 'textInput_cacheRead',
776
+ rate: 0.075,
777
+ strategy: 'fixed',
778
+ unit: 'millionTokens',
779
+ },
780
+ {
781
+ name: 'textInput',
782
+ rate: 0.15,
783
+ strategy: 'fixed',
784
+ unit: 'millionTokens',
785
+ },
786
+ {
787
+ name: 'textOutput',
788
+ rate: 0.6,
789
+ strategy: 'fixed',
790
+ unit: 'millionTokens',
791
+ },
792
+ ],
759
793
  },
760
794
  type: 'chat',
761
795
  },
@@ -772,9 +806,26 @@ describe('transformToChatModelCards', () => {
772
806
  id: 'o1-mini',
773
807
  maxOutput: 65536,
774
808
  pricing: {
775
- cachedInput: 0.55,
776
- input: 1.1,
777
- output: 4.4,
809
+ units: [
810
+ {
811
+ name: 'textInput_cacheRead',
812
+ rate: 0.55,
813
+ strategy: 'fixed',
814
+ unit: 'millionTokens',
815
+ },
816
+ {
817
+ name: 'textInput',
818
+ rate: 1.1,
819
+ strategy: 'fixed',
820
+ unit: 'millionTokens',
821
+ },
822
+ {
823
+ name: 'textOutput',
824
+ rate: 4.4,
825
+ strategy: 'fixed',
826
+ unit: 'millionTokens',
827
+ },
828
+ ],
778
829
  },
779
830
  releasedAt: '2024-09-12',
780
831
  type: 'chat',
@@ -0,0 +1,183 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { Pricing } from '@/types/aiModel';
4
+
5
+ import {
6
+ getAudioInputUnitRate,
7
+ getAudioOutputUnitRate,
8
+ getCachedAudioInputUnitRate,
9
+ getCachedTextInputUnitRate,
10
+ getTextInputUnitRate,
11
+ getTextOutputUnitRate,
12
+ getUnitRateByName,
13
+ getWriteCacheInputUnitRate,
14
+ } from './pricing';
15
+
16
+ describe('pricing utilities (new)', () => {
17
+ describe('getUnitRateByName', () => {
18
+ it('returns undefined when pricing or unitName is missing', () => {
19
+ expect(getUnitRateByName()).toBeUndefined();
20
+ const p = { units: [] } as Pricing;
21
+ expect(getUnitRateByName(p)).toBeUndefined();
22
+ });
23
+
24
+ it('returns undefined when unit not found', () => {
25
+ const pricing: Pricing = {
26
+ units: [{ name: 'textOutput', strategy: 'fixed', unit: 'millionTokens', rate: 0.002 }],
27
+ };
28
+ expect(getUnitRateByName(pricing, 'textInput')).toBeUndefined();
29
+ });
30
+
31
+ it('handles fixed strategy', () => {
32
+ const pricing: Pricing = {
33
+ units: [{ name: 'textInput', strategy: 'fixed', unit: 'millionTokens', rate: 0.001 }],
34
+ };
35
+ expect(getUnitRateByName(pricing, 'textInput')).toBe(0.001);
36
+ });
37
+
38
+ it('handles tiered strategy (first tier)', () => {
39
+ const pricing: Pricing = {
40
+ units: [
41
+ {
42
+ name: 'audioInput',
43
+ strategy: 'tiered',
44
+ unit: 'second',
45
+ tiers: [
46
+ { rate: 0.01, upTo: 3600 },
47
+ { rate: 0.008, upTo: 'infinity' },
48
+ ],
49
+ },
50
+ ],
51
+ };
52
+ expect(getUnitRateByName(pricing, 'audioInput')).toBe(0.01);
53
+ });
54
+
55
+ it('returns undefined when tiered.tiers is absent or empty', () => {
56
+ const noTiers: Pricing = {
57
+ units: [
58
+ { name: 'textInput', strategy: 'tiered', unit: 'millionTokens', tiers: undefined as any },
59
+ ],
60
+ };
61
+ const emptyTiers: Pricing = {
62
+ units: [{ name: 'textInput', strategy: 'tiered', unit: 'millionTokens', tiers: [] }],
63
+ };
64
+ expect(getUnitRateByName(noTiers, 'textInput')).toBeUndefined();
65
+ expect(getUnitRateByName(emptyTiers, 'textInput')).toBeUndefined();
66
+ });
67
+
68
+ it('handles lookup strategy (first price value)', () => {
69
+ const pricing: Pricing = {
70
+ units: [
71
+ {
72
+ name: 'textInput',
73
+ strategy: 'lookup',
74
+ unit: 'millionTokens',
75
+ lookup: {
76
+ pricingParams: ['model'],
77
+ prices: { a: 0.001, b: 0.03 },
78
+ },
79
+ },
80
+ ],
81
+ };
82
+ expect(getUnitRateByName(pricing, 'textInput')).toBe(0.001);
83
+ });
84
+
85
+ it('returns undefined when lookup missing or has no prices', () => {
86
+ const missingLookup: Pricing = {
87
+ units: [
88
+ {
89
+ name: 'textInput',
90
+ strategy: 'lookup',
91
+ unit: 'millionTokens',
92
+ lookup: undefined as any,
93
+ },
94
+ ],
95
+ } as any;
96
+ const emptyPrices: Pricing = {
97
+ units: [
98
+ {
99
+ name: 'textInput',
100
+ strategy: 'lookup',
101
+ unit: 'millionTokens',
102
+ lookup: { pricingParams: ['model'], prices: {} },
103
+ },
104
+ ],
105
+ };
106
+ expect(getUnitRateByName(missingLookup, 'textInput')).toBeUndefined();
107
+ expect(getUnitRateByName(emptyPrices, 'textInput')).toBeUndefined();
108
+ });
109
+
110
+ it('works with multiple units', () => {
111
+ const pricing: Pricing = {
112
+ units: [
113
+ { name: 'textInput', strategy: 'fixed', unit: 'millionTokens', rate: 0.001 },
114
+ { name: 'textOutput', strategy: 'fixed', unit: 'millionTokens', rate: 0.002 },
115
+ {
116
+ name: 'audioInput',
117
+ strategy: 'tiered',
118
+ unit: 'second',
119
+ tiers: [
120
+ { rate: 0.01, upTo: 3600 },
121
+ { rate: 0.008, upTo: 'infinity' },
122
+ ],
123
+ },
124
+ ],
125
+ };
126
+ expect(getUnitRateByName(pricing, 'textInput')).toBe(0.001);
127
+ expect(getUnitRateByName(pricing, 'textOutput')).toBe(0.002);
128
+ expect(getUnitRateByName(pricing, 'audioInput')).toBe(0.01);
129
+ });
130
+ });
131
+
132
+ describe('wrapper helpers', () => {
133
+ it('return the same values as getUnitRateByName for each unit', () => {
134
+ const pricing: Pricing = {
135
+ units: [
136
+ { name: 'textInput', strategy: 'fixed', unit: 'millionTokens', rate: 0.001 },
137
+ { name: 'textOutput', strategy: 'fixed', unit: 'millionTokens', rate: 0.002 },
138
+ {
139
+ name: 'audioInput',
140
+ strategy: 'tiered',
141
+ unit: 'second',
142
+ tiers: [
143
+ { rate: 0.01, upTo: 3600 },
144
+ { rate: 0.008, upTo: 'infinity' },
145
+ ],
146
+ },
147
+ { name: 'audioOutput', strategy: 'fixed', unit: 'second', rate: 0.015 },
148
+ { name: 'textInput_cacheRead', strategy: 'fixed', unit: 'millionTokens', rate: 0.0005 },
149
+ {
150
+ name: 'textInput_cacheWrite',
151
+ strategy: 'lookup',
152
+ unit: 'millionTokens',
153
+ lookup: { pricingParams: ['ttl'], prices: { '5': 0.2, '60': 0.6 } },
154
+ },
155
+ { name: 'audioInput_cacheRead', strategy: 'fixed', unit: 'second', rate: 0.005 },
156
+ ],
157
+ };
158
+
159
+ expect(getTextInputUnitRate(pricing)).toBe(getUnitRateByName(pricing, 'textInput'));
160
+ expect(getTextOutputUnitRate(pricing)).toBe(getUnitRateByName(pricing, 'textOutput'));
161
+ expect(getAudioInputUnitRate(pricing)).toBe(getUnitRateByName(pricing, 'audioInput'));
162
+ expect(getAudioOutputUnitRate(pricing)).toBe(getUnitRateByName(pricing, 'audioOutput'));
163
+ expect(getCachedTextInputUnitRate(pricing)).toBe(
164
+ getUnitRateByName(pricing, 'textInput_cacheRead'),
165
+ );
166
+ expect(getWriteCacheInputUnitRate(pricing)).toBe(
167
+ getUnitRateByName(pricing, 'textInput_cacheWrite'),
168
+ );
169
+ expect(getCachedAudioInputUnitRate(pricing)).toBe(
170
+ getUnitRateByName(pricing, 'audioInput_cacheRead'),
171
+ );
172
+
173
+ // also validate expected concrete values for clarity
174
+ expect(getTextInputUnitRate(pricing)).toBe(0.001);
175
+ expect(getTextOutputUnitRate(pricing)).toBe(0.002);
176
+ expect(getAudioInputUnitRate(pricing)).toBe(0.01);
177
+ expect(getAudioOutputUnitRate(pricing)).toBe(0.015);
178
+ expect(getCachedTextInputUnitRate(pricing)).toBe(0.0005);
179
+ expect(getWriteCacheInputUnitRate(pricing)).toBe(0.2);
180
+ expect(getCachedAudioInputUnitRate(pricing)).toBe(0.005);
181
+ });
182
+ });
183
+ });
@@ -0,0 +1,90 @@
1
+ import { Pricing, PricingUnit, PricingUnitName } from '@/types/aiModel';
2
+
3
+ /**
4
+ * Internal helper to extract the displayed unit rate from a pricing unit by strategy
5
+ * - fixed → rate
6
+ * - tiered → tiers[0].rate
7
+ * - lookup → first price value
8
+ */
9
+ const getRateFromUnit = (unit: PricingUnit): number | undefined => {
10
+ switch (unit.strategy) {
11
+ case 'fixed': {
12
+ return unit.rate;
13
+ }
14
+ case 'tiered': {
15
+ return unit.tiers?.[0]?.rate;
16
+ }
17
+ case 'lookup': {
18
+ const prices = Object.values(unit.lookup?.prices || {});
19
+ return prices[0];
20
+ }
21
+ default: {
22
+ return undefined;
23
+ }
24
+ }
25
+ };
26
+
27
+ /**
28
+ * Get unit rate by unit name, used to deduplicate logic across helpers
29
+ */
30
+ export const getUnitRateByName = (
31
+ pricing?: Pricing,
32
+ unitName?: PricingUnitName,
33
+ ): number | undefined => {
34
+ if (!pricing?.units || !unitName) return undefined;
35
+ const unit = pricing.units.find((u) => u.name === unitName);
36
+ if (!unit) return undefined;
37
+ return getRateFromUnit(unit);
38
+ };
39
+
40
+ /**
41
+ * Get text input unit rate from pricing
42
+ * - fixed → rate
43
+ * - tiered → tiers[0].rate
44
+ * - lookup → Object.values(lookup.prices)[0]
45
+ */
46
+ export function getTextInputUnitRate(pricing?: Pricing): number | undefined {
47
+ return getUnitRateByName(pricing, 'textInput');
48
+ }
49
+
50
+ /**
51
+ * Get text output unit rate from pricing
52
+ */
53
+ export function getTextOutputUnitRate(pricing?: Pricing): number | undefined {
54
+ return getUnitRateByName(pricing, 'textOutput');
55
+ }
56
+
57
+ /**
58
+ * Get audio input unit rate from pricing
59
+ */
60
+ export function getAudioInputUnitRate(pricing?: Pricing): number | undefined {
61
+ return getUnitRateByName(pricing, 'audioInput');
62
+ }
63
+
64
+ /**
65
+ * Get audio output unit rate from pricing
66
+ */
67
+ export function getAudioOutputUnitRate(pricing?: Pricing): number | undefined {
68
+ return getUnitRateByName(pricing, 'audioOutput');
69
+ }
70
+
71
+ /**
72
+ * Get cached text input unit rate from pricing
73
+ */
74
+ export function getCachedTextInputUnitRate(pricing?: Pricing): number | undefined {
75
+ return getUnitRateByName(pricing, 'textInput_cacheRead');
76
+ }
77
+
78
+ /**
79
+ * Get write cache input unit rate from pricing (TextInputCacheWrite)
80
+ */
81
+ export function getWriteCacheInputUnitRate(pricing?: Pricing): number | undefined {
82
+ return getUnitRateByName(pricing, 'textInput_cacheWrite');
83
+ }
84
+
85
+ /**
86
+ * Get cached audio input unit rate from pricing
87
+ */
88
+ export function getCachedAudioInputUnitRate(pricing?: Pricing): number | undefined {
89
+ return getUnitRateByName(pricing, 'audioInput_cacheRead');
90
+ }