cortico 0.1.0

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 (311) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/package.json +43 -0
  4. package/src/boot.ts +46 -0
  5. package/src/bot.ts +1342 -0
  6. package/src/config-file.ts +41 -0
  7. package/src/core/README.md +92 -0
  8. package/src/core/billing.ts +26 -0
  9. package/src/core/blobs.ts +106 -0
  10. package/src/core/bus.ts +311 -0
  11. package/src/core/config-schema.ts +201 -0
  12. package/src/core/config.ts +262 -0
  13. package/src/core/core.ts +699 -0
  14. package/src/core/cost.ts +244 -0
  15. package/src/core/event-store.ts +304 -0
  16. package/src/core/fork.ts +113 -0
  17. package/src/core/generation.ts +118 -0
  18. package/src/core/instance-lock.ts +215 -0
  19. package/src/core/ipc-logger.ts +105 -0
  20. package/src/core/language.ts +62 -0
  21. package/src/core/log-context.ts +38 -0
  22. package/src/core/loop.ts +1858 -0
  23. package/src/core/markers.ts +48 -0
  24. package/src/core/prefix.ts +121 -0
  25. package/src/core/run.ts +95 -0
  26. package/src/core/secrets.ts +18 -0
  27. package/src/core/session.ts +56 -0
  28. package/src/core/sessions.ts +261 -0
  29. package/src/core/state.ts +104 -0
  30. package/src/core/template.ts +72 -0
  31. package/src/core/timers.ts +129 -0
  32. package/src/core/tool-log.ts +135 -0
  33. package/src/core/transcript.ts +92 -0
  34. package/src/core/truncate.ts +121 -0
  35. package/src/core/types.ts +1140 -0
  36. package/src/core/usage-log.ts +79 -0
  37. package/src/core/util.ts +386 -0
  38. package/src/deploy-listing.ts +160 -0
  39. package/src/deploy.ts +162 -0
  40. package/src/extensions/README.md +72 -0
  41. package/src/extensions/dry-mount.ts +390 -0
  42. package/src/extensions/manifest.ts +153 -0
  43. package/src/extensions/runtime.ts +42 -0
  44. package/src/extensions.ts +519 -0
  45. package/src/launcher.ts +285 -0
  46. package/src/paths.ts +155 -0
  47. package/src/protocol/open-responses/LICENSE +201 -0
  48. package/src/protocol/open-responses/README.md +14 -0
  49. package/src/protocol/open-responses/context-helpers.ts +27 -0
  50. package/src/protocol/open-responses/context-log.ts +59 -0
  51. package/src/protocol/open-responses/context.ts +89 -0
  52. package/src/protocol/open-responses/generated.ts +115 -0
  53. package/src/protocol/open-responses/index.ts +33 -0
  54. package/src/protocol/open-responses/openapi.json +4230 -0
  55. package/src/protocol/open-responses/stream.ts +146 -0
  56. package/src/protocol/open-responses/tokens.ts +31 -0
  57. package/src/providers/README.md +86 -0
  58. package/src/providers/base.ts +111 -0
  59. package/src/providers/configuration.ts +97 -0
  60. package/src/providers/console/config.ts +21 -0
  61. package/src/providers/console/settings.ts +443 -0
  62. package/src/providers/console/strings.ts +74 -0
  63. package/src/providers/console/types.ts +11 -0
  64. package/src/providers/llamacpp/archive.ts +148 -0
  65. package/src/providers/llamacpp/catalog.ts +247 -0
  66. package/src/providers/llamacpp/config.ts +36 -0
  67. package/src/providers/llamacpp/console/client.ts +6 -0
  68. package/src/providers/llamacpp/console/models-panel.ts +120 -0
  69. package/src/providers/llamacpp/console/runtime-panel.ts +173 -0
  70. package/src/providers/llamacpp/console/server.ts +153 -0
  71. package/src/providers/llamacpp/index.ts +95 -0
  72. package/src/providers/llamacpp/native.ts +51 -0
  73. package/src/providers/llamacpp/options.ts +117 -0
  74. package/src/providers/llamacpp/runtime-store.ts +139 -0
  75. package/src/providers/llamacpp/runtime.ts +214 -0
  76. package/src/providers/llamacpp/server.ts +286 -0
  77. package/src/providers/llamacpp/strings.ts +230 -0
  78. package/src/providers/openai-responses-compat/config.ts +20 -0
  79. package/src/providers/openai-responses-compat/index.ts +89 -0
  80. package/src/providers/openai-responses-compat/native.ts +127 -0
  81. package/src/providers/openai-responses-compat/strings.ts +19 -0
  82. package/src/providers/pricebook.ts +75 -0
  83. package/src/providers/registry.ts +137 -0
  84. package/src/providers/strings.ts +71 -0
  85. package/src/providers/transport/chat.ts +156 -0
  86. package/src/providers/transport/errors.ts +48 -0
  87. package/src/providers/transport/history.ts +68 -0
  88. package/src/providers/transport/native-input.ts +83 -0
  89. package/src/providers/transport/native-types.ts +13 -0
  90. package/src/providers/transport/response-assembly.ts +191 -0
  91. package/src/providers/transport/response-http.ts +196 -0
  92. package/src/providers/transport/response-meters.ts +27 -0
  93. package/src/providers/transport/responses-input.ts +56 -0
  94. package/src/web/README.md +84 -0
  95. package/src/web/client/console-pages/builtins/llm-settings/panel.ts +625 -0
  96. package/src/web/client/console-pages/builtins/llm-settings/pricing-panel.ts +168 -0
  97. package/src/web/client/console-pages/builtins/llm-settings/strings.ts +213 -0
  98. package/src/web/client/console-pages/builtins.ts +10 -0
  99. package/src/web/client/console-pages/context.ts +135 -0
  100. package/src/web/client/console-pages/host.ts +633 -0
  101. package/src/web/client/console-pages/loader.ts +132 -0
  102. package/src/web/client/console-pages/strings.ts +90 -0
  103. package/src/web/client/console-pages/tools/strings.ts +49 -0
  104. package/src/web/client/console-pages/tools/view.ts +215 -0
  105. package/src/web/client/core/api.ts +200 -0
  106. package/src/web/client/core/language.ts +56 -0
  107. package/src/web/client/core/lifecycle.ts +132 -0
  108. package/src/web/client/core/router.ts +199 -0
  109. package/src/web/client/core/stream.ts +157 -0
  110. package/src/web/client/core/websocket.ts +82 -0
  111. package/src/web/client/features/appearance/index.ts +333 -0
  112. package/src/web/client/features/appearance/strings.ts +87 -0
  113. package/src/web/client/features/config/index.ts +11 -0
  114. package/src/web/client/features/config/strings.ts +41 -0
  115. package/src/web/client/features/config/view.ts +428 -0
  116. package/src/web/client/features/core/events.ts +197 -0
  117. package/src/web/client/features/core/index.ts +254 -0
  118. package/src/web/client/features/core/run.ts +56 -0
  119. package/src/web/client/features/core/runlog.ts +214 -0
  120. package/src/web/client/features/core/sessions.ts +53 -0
  121. package/src/web/client/features/core/strings.ts +157 -0
  122. package/src/web/client/features/extensions/index.ts +422 -0
  123. package/src/web/client/features/extensions/strings.ts +164 -0
  124. package/src/web/client/features/feature.ts +93 -0
  125. package/src/web/client/features/live/context.ts +280 -0
  126. package/src/web/client/features/live/fork.ts +156 -0
  127. package/src/web/client/features/live/index.ts +392 -0
  128. package/src/web/client/features/live/onboarding.ts +113 -0
  129. package/src/web/client/features/live/protocol.ts +122 -0
  130. package/src/web/client/features/live/sessions.ts +71 -0
  131. package/src/web/client/features/live/status.ts +68 -0
  132. package/src/web/client/features/live/strings.ts +252 -0
  133. package/src/web/client/features/live/timeline.ts +590 -0
  134. package/src/web/client/features/prompts/editor.ts +292 -0
  135. package/src/web/client/features/prompts/index.ts +346 -0
  136. package/src/web/client/features/prompts/strings.ts +136 -0
  137. package/src/web/client/features/prompts/view.ts +256 -0
  138. package/src/web/client/features/providers/index.ts +100 -0
  139. package/src/web/client/features/providers/strings.ts +23 -0
  140. package/src/web/client/features/settings/general.ts +28 -0
  141. package/src/web/client/features/settings/index.ts +82 -0
  142. package/src/web/client/features/settings/strings.ts +33 -0
  143. package/src/web/client/features/storage/index.ts +1 -0
  144. package/src/web/client/features/storage/strings.ts +45 -0
  145. package/src/web/client/features/storage/view.ts +154 -0
  146. package/src/web/client/features/usage/chart.ts +486 -0
  147. package/src/web/client/features/usage/index.ts +407 -0
  148. package/src/web/client/features/usage/labels.ts +46 -0
  149. package/src/web/client/features/usage/range.ts +36 -0
  150. package/src/web/client/features/usage/state.ts +37 -0
  151. package/src/web/client/features/usage/strings.ts +191 -0
  152. package/src/web/client/features/usage/tooltip.ts +86 -0
  153. package/src/web/client/features/usage/types.ts +96 -0
  154. package/src/web/client/features/worlds/index.ts +424 -0
  155. package/src/web/client/features/worlds/strings.ts +121 -0
  156. package/src/web/client/main.ts +273 -0
  157. package/src/web/client/shell/avatar.ts +233 -0
  158. package/src/web/client/shell/index.ts +549 -0
  159. package/src/web/client/shell/strings.ts +89 -0
  160. package/src/web/client/theme/handoff.ts +43 -0
  161. package/src/web/client/theme/palette.ts +109 -0
  162. package/src/web/client/theme/registry.ts +130 -0
  163. package/src/web/client/theme/storage.ts +72 -0
  164. package/src/web/client/theme/strings.ts +123 -0
  165. package/src/web/client/theme/studio.ts +366 -0
  166. package/src/web/client/ui/actions.ts +109 -0
  167. package/src/web/client/ui/data.ts +185 -0
  168. package/src/web/client/ui/dom.ts +23 -0
  169. package/src/web/client/ui/fields.ts +191 -0
  170. package/src/web/client/ui/format.ts +75 -0
  171. package/src/web/client/ui/icons.ts +183 -0
  172. package/src/web/client/ui/images.ts +91 -0
  173. package/src/web/client/ui/index.ts +89 -0
  174. package/src/web/client/ui/lamp.ts +125 -0
  175. package/src/web/client/ui/log.ts +98 -0
  176. package/src/web/client/ui/overlay.ts +184 -0
  177. package/src/web/client/ui/page.ts +8 -0
  178. package/src/web/client/ui/prompt-input.tsx +311 -0
  179. package/src/web/client/ui/sheet.ts +131 -0
  180. package/src/web/client/ui/strings.ts +71 -0
  181. package/src/web/console-pages.ts +367 -0
  182. package/src/web/files.ts +107 -0
  183. package/src/web/path-picker.ts +296 -0
  184. package/src/web/public/index.html +17 -0
  185. package/src/web/public/styles.css +1715 -0
  186. package/src/web/server.ts +1883 -0
  187. package/src/web/shared/client-panel.ts +603 -0
  188. package/src/web/shared/console-protocol.ts +560 -0
  189. package/src/web/shared/css.d.ts +1 -0
  190. package/src/web/shared/path-picker.ts +23 -0
  191. package/src/web/shared/theme.ts +256 -0
  192. package/src/web/theme-store.ts +37 -0
  193. package/src/world.ts +449 -0
  194. package/src/worlds/bilibili/ENV_PROMPT.md +5 -0
  195. package/src/worlds/bilibili/README.md +176 -0
  196. package/src/worlds/bilibili/audience-admission.ts +995 -0
  197. package/src/worlds/bilibili/client.ts +528 -0
  198. package/src/worlds/bilibili/coalescing-buffer.ts +125 -0
  199. package/src/worlds/bilibili/config.ts +185 -0
  200. package/src/worlds/bilibili/console/client.ts +202 -0
  201. package/src/worlds/bilibili/definition.ts +35 -0
  202. package/src/worlds/bilibili/gift-frame.ts +131 -0
  203. package/src/worlds/bilibili/normalize.ts +452 -0
  204. package/src/worlds/bilibili/overlay/announcement.ts +76 -0
  205. package/src/worlds/bilibili/overlay/assets.ts +82 -0
  206. package/src/worlds/bilibili/overlay/model.ts +494 -0
  207. package/src/worlds/bilibili/overlay/project.ts +202 -0
  208. package/src/worlds/bilibili/overlay/server.ts +286 -0
  209. package/src/worlds/bilibili/overlay/types.ts +217 -0
  210. package/src/worlds/bilibili/overlay/web/app.js +690 -0
  211. package/src/worlds/bilibili/overlay/web/editor.css +297 -0
  212. package/src/worlds/bilibili/overlay/web/editor.html +102 -0
  213. package/src/worlds/bilibili/overlay/web/editor.js +2116 -0
  214. package/src/worlds/bilibili/overlay/web/overlay.html +13 -0
  215. package/src/worlds/bilibili/overlay/web/styles.css +258 -0
  216. package/src/worlds/bilibili/protobuf.ts +123 -0
  217. package/src/worlds/bilibili/wire.ts +94 -0
  218. package/src/worlds/bilibili/world.ts +1389 -0
  219. package/src/worlds/console-fixture/ENV_PROMPT.md +1 -0
  220. package/src/worlds/console-fixture/console/client.ts +72 -0
  221. package/src/worlds/console-fixture/world.ts +73 -0
  222. package/src/worlds/index.ts +15 -0
  223. package/src/worlds/minecraft/ENV_PROMPT.md +32 -0
  224. package/src/worlds/minecraft/ENV_PROMPT_CAMERA.md +2 -0
  225. package/src/worlds/minecraft/LICENSE-mineflayer-pathfinder.txt +21 -0
  226. package/src/worlds/minecraft/README.md +917 -0
  227. package/src/worlds/minecraft/blueprint-plan.ts +915 -0
  228. package/src/worlds/minecraft/blueprint-registry.ts +566 -0
  229. package/src/worlds/minecraft/blueprint-repair.ts +236 -0
  230. package/src/worlds/minecraft/blueprint-resource.ts +272 -0
  231. package/src/worlds/minecraft/blueprint.ts +492 -0
  232. package/src/worlds/minecraft/body-lease.ts +340 -0
  233. package/src/worlds/minecraft/bridge.ts +749 -0
  234. package/src/worlds/minecraft/check.ts +651 -0
  235. package/src/worlds/minecraft/chests.ts +292 -0
  236. package/src/worlds/minecraft/client-launch.ts +272 -0
  237. package/src/worlds/minecraft/client-options.ts +85 -0
  238. package/src/worlds/minecraft/client-skins.ts +164 -0
  239. package/src/worlds/minecraft/client-window.ps1 +91 -0
  240. package/src/worlds/minecraft/client.ts +423 -0
  241. package/src/worlds/minecraft/combat-context.ts +109 -0
  242. package/src/worlds/minecraft/combat.ts +1552 -0
  243. package/src/worlds/minecraft/config.ts +499 -0
  244. package/src/worlds/minecraft/console/access.ts +218 -0
  245. package/src/worlds/minecraft/console/client.ts +244 -0
  246. package/src/worlds/minecraft/console/log.ts +110 -0
  247. package/src/worlds/minecraft/console/mount.ts +420 -0
  248. package/src/worlds/minecraft/console/skin.ts +257 -0
  249. package/src/worlds/minecraft/console/style.css +154 -0
  250. package/src/worlds/minecraft/console/world.ts +449 -0
  251. package/src/worlds/minecraft/deaths.ts +135 -0
  252. package/src/worlds/minecraft/definition.ts +18 -0
  253. package/src/worlds/minecraft/engine-child.ts +274 -0
  254. package/src/worlds/minecraft/engine-ipc.ts +98 -0
  255. package/src/worlds/minecraft/entity-facts.ts +132 -0
  256. package/src/worlds/minecraft/escape.ts +407 -0
  257. package/src/worlds/minecraft/executor.ts +14494 -0
  258. package/src/worlds/minecraft/explored.ts +156 -0
  259. package/src/worlds/minecraft/geometry.ts +205 -0
  260. package/src/worlds/minecraft/goal-plan.ts +647 -0
  261. package/src/worlds/minecraft/item-break.ts +126 -0
  262. package/src/worlds/minecraft/item-facts.ts +146 -0
  263. package/src/worlds/minecraft/item-pick.ts +67 -0
  264. package/src/worlds/minecraft/level-dat.ts +176 -0
  265. package/src/worlds/minecraft/log.ts +132 -0
  266. package/src/worlds/minecraft/mineflayer-fixes.ts +1180 -0
  267. package/src/worlds/minecraft/names.ts +377 -0
  268. package/src/worlds/minecraft/pathfinder-lib.d.ts +13 -0
  269. package/src/worlds/minecraft/pathfinder-perf.ts +796 -0
  270. package/src/worlds/minecraft/piglin.ts +49 -0
  271. package/src/worlds/minecraft/policy.ts +547 -0
  272. package/src/worlds/minecraft/precheck.ts +655 -0
  273. package/src/worlds/minecraft/proxy.ts +445 -0
  274. package/src/worlds/minecraft/ranged.ts +635 -0
  275. package/src/worlds/minecraft/readouts.ts +102 -0
  276. package/src/worlds/minecraft/round.ts +26 -0
  277. package/src/worlds/minecraft/search-observation.ts +92 -0
  278. package/src/worlds/minecraft/server-config.ts +467 -0
  279. package/src/worlds/minecraft/server.ts +658 -0
  280. package/src/worlds/minecraft/show.ts +84 -0
  281. package/src/worlds/minecraft/skills.ts +1763 -0
  282. package/src/worlds/minecraft/terrain.ts +1735 -0
  283. package/src/worlds/minecraft/window.ts +96 -0
  284. package/src/worlds/minecraft/works.ts +179 -0
  285. package/src/worlds/minecraft/world.ts +6438 -0
  286. package/src/worlds/qq/ENV_PROMPT.md +5 -0
  287. package/src/worlds/qq/config.ts +108 -0
  288. package/src/worlds/qq/console/client.ts +126 -0
  289. package/src/worlds/qq/console/events.ts +155 -0
  290. package/src/worlds/qq/console/gate.ts +232 -0
  291. package/src/worlds/qq/console/roster.ts +203 -0
  292. package/src/worlds/qq/console/style.css +65 -0
  293. package/src/worlds/qq/conversation.ts +28 -0
  294. package/src/worlds/qq/definition.ts +62 -0
  295. package/src/worlds/qq/driver.ts +375 -0
  296. package/src/worlds/qq/history-tools.ts +209 -0
  297. package/src/worlds/qq/normalize.ts +323 -0
  298. package/src/worlds/qq/qface-map.ts +282 -0
  299. package/src/worlds/qq/vision-prompt.ts +27 -0
  300. package/src/worlds/qq/vision.ts +642 -0
  301. package/src/worlds/qq/vlm.ts +142 -0
  302. package/src/worlds/qq/world.ts +1503 -0
  303. package/src/worlds/terminal/ENV_PROMPT.md +11 -0
  304. package/src/worlds/terminal/config.ts +9 -0
  305. package/src/worlds/terminal/definition.ts +14 -0
  306. package/src/worlds/terminal/world.ts +700 -0
  307. package/src/worlds/websearch/ENV_PROMPT.md +1 -0
  308. package/src/worlds/websearch/brave-client.ts +261 -0
  309. package/src/worlds/websearch/config.ts +75 -0
  310. package/src/worlds/websearch/definition.ts +20 -0
  311. package/src/worlds/websearch/world.ts +171 -0
@@ -0,0 +1,168 @@
1
+ import type { ConsoleUi } from '../../../../shared/client-panel.ts';
2
+ import type { Language } from '../../../core/language.ts';
3
+ import { panel } from './strings.ts';
4
+
5
+ interface Rule {
6
+ meter: string;
7
+ perMillion: number;
8
+ }
9
+ interface Quote {
10
+ currency: string;
11
+ basis: string;
12
+ rules: Rule[];
13
+ source: string;
14
+ inputBands?: unknown[];
15
+ serviceTiers?: unknown;
16
+ }
17
+ export interface ModelQuote {
18
+ model: string;
19
+ quotes: Quote[];
20
+ }
21
+
22
+ const FORM_METERS = ['cachedInput', 'uncachedInput', 'output'] as const;
23
+
24
+ /** The one shape the three-rate form edits: a single `*` marginal definition with exactly the three meters. */
25
+ interface SimpleCost {
26
+ currency: string;
27
+ rates: [number, number, number];
28
+ }
29
+
30
+ function readSimple(saved: unknown[]): SimpleCost | null {
31
+ if (saved.length !== 1) return null;
32
+ const definition = saved[0] as Record<string, unknown>;
33
+ if (!definition || typeof definition !== 'object') return null;
34
+ const models = definition.models;
35
+ if (!Array.isArray(models) || models.length !== 1 || models[0] !== '*') return null;
36
+ if (definition.basis !== 'marginal' || typeof definition.currency !== 'string') return null;
37
+ if (definition.inputBands !== undefined || definition.serviceTiers !== undefined) return null;
38
+ const rules = definition.rules;
39
+ if (!Array.isArray(rules) || rules.length !== FORM_METERS.length) return null;
40
+ const rates = FORM_METERS.map((meter) => {
41
+ const rule = rules.find((rule: Rule) => rule.meter === meter) as Rule | undefined;
42
+ return rule && typeof rule.perMillion === 'number' ? rule.perMillion : NaN;
43
+ });
44
+ if (rates.some((rate) => Number.isNaN(rate))) return null;
45
+ return { currency: definition.currency, rates: rates as [number, number, number] };
46
+ }
47
+
48
+ function writeSimple(cost: SimpleCost): unknown[] {
49
+ return [
50
+ {
51
+ models: ['*'],
52
+ currency: cost.currency,
53
+ basis: 'marginal',
54
+ source: 'console',
55
+ rules: FORM_METERS.map((meter, i) => ({ meter, perMillion: cost.rates[i] })),
56
+ },
57
+ ];
58
+ }
59
+
60
+ /**
61
+ * Pricing sheet: effective quotes, the three-rate form, the full-rules JSON (`details`) and the
62
+ * quote snapshot. The JSON textarea is the single draft; form edits write through into it, and
63
+ * every change commits the parsed textarea. An endpoint with no pricing keeps the form blank and
64
+ * commits an empty definition list until a rate is typed. Saved pricing the form cannot express
65
+ * opens the textarea and leaves the form blank until edited.
66
+ */
67
+ export function pricingEditor(
68
+ ui: ConsoleUi,
69
+ saved: unknown[],
70
+ quotes: ModelQuote[],
71
+ commit: (pricing: unknown[]) => void,
72
+ language?: Language,
73
+ ) {
74
+ const S = language === 'en' ? panel.en : panel.zh;
75
+ const card = ui.sheet({
76
+ title: S.pricingTitle,
77
+ desc: S.pricingDescription,
78
+ });
79
+ const labels: Record<string, string> = S.meters;
80
+ for (const row of quotes) {
81
+ if (!row.quotes.length) card.body.append(ui.msgline(S.quoteUnknown(row.model)));
82
+ for (const quote of row.quotes) {
83
+ card.body.append(
84
+ ui.kv([
85
+ {
86
+ k: row.model,
87
+ v: `${quote.currency} · ${quote.basis === 'marginal' ? S.marginal : S.equivalent}`,
88
+ },
89
+ ]),
90
+ ui.msgline(
91
+ quote.rules.length
92
+ ? quote.rules
93
+ .map((rule) => S.perMillion(labels[rule.meter] ?? rule.meter, rule.perMillion))
94
+ .join(' · ')
95
+ : S.free,
96
+ ),
97
+ ui.msgline(quote.source),
98
+ );
99
+ if (quote.inputBands?.length || quote.serviceTiers)
100
+ card.body.append(ui.msgline(S.bandsNote));
101
+ }
102
+ }
103
+ const unset = saved.length === 0;
104
+ if (unset) card.body.append(ui.msgline(S.pricingUnset));
105
+ const simple: SimpleCost | null = unset ? null : readSimple(saved);
106
+ const raw = ui.textarea({
107
+ rows: 10,
108
+ value: JSON.stringify(simple ? writeSimple(simple) : saved, null, 2),
109
+ onChange: commitDraft,
110
+ });
111
+ const currency = ui.input({ value: simple?.currency ?? 'USD', onChange: writeThrough });
112
+ currency.setAttribute('aria-label', S.currencyField);
113
+ const problem = ui.msgline();
114
+ const rateLabels = [S.rateCached, S.rateUncached, S.rateOutput];
115
+ const rates = rateLabels.map((label, i) => {
116
+ const input = ui.input({
117
+ type: 'number',
118
+ value: simple ? String(simple.rates[i]) : '',
119
+ onChange: writeThrough,
120
+ });
121
+ input.min = '0';
122
+ input.step = 'any';
123
+ input.setAttribute('aria-label', label);
124
+ return input;
125
+ });
126
+ /** 三格全空 = 没有报价;填了任何一格,空格按 0 计。 */
127
+ function writeThrough() {
128
+ const blank = rates.every((input) => input.value.trim() === '');
129
+ raw.value = blank
130
+ ? '[]'
131
+ : JSON.stringify(
132
+ writeSimple({
133
+ currency: currency.value.trim() || 'USD',
134
+ rates: rates.map((input) => Number(input.value) || 0) as [number, number, number],
135
+ }),
136
+ null,
137
+ 2,
138
+ );
139
+ commitDraft();
140
+ }
141
+ /** 完整规则那格可以写坏;解析不过就停在这张卡上说清楚,不往端点写。 */
142
+ function commitDraft(): void {
143
+ try {
144
+ const pricing = JSON.parse(raw.value) as unknown[];
145
+ problem.textContent = '';
146
+ problem.classList.remove('bad');
147
+ commit(pricing);
148
+ } catch (error) {
149
+ problem.textContent = String(error);
150
+ problem.classList.add('bad');
151
+ }
152
+ }
153
+ card.body.append(
154
+ ui.field(S.currencyField, currency),
155
+ ...rates.map((input, i) => ui.field(rateLabels[i], input)),
156
+ ui.msgline(simple || unset ? S.costFormNote : S.costFormOverridden),
157
+ );
158
+ const advanced = ui.h('details');
159
+ advanced.open = !simple && !unset;
160
+ advanced.append(ui.h('summary', null, S.editFull), raw, ui.msgline(S.fullNote), problem);
161
+ const preview = ui.h('details');
162
+ preview.append(
163
+ ui.h('summary', null, S.viewSnapshot),
164
+ ui.h('pre', 'mono', JSON.stringify(quotes, null, 2)),
165
+ );
166
+ card.body.append(advanced, preview);
167
+ return { el: card.el };
168
+ }
@@ -0,0 +1,213 @@
1
+ /** 端点表面板与报价编辑器的文案。按 `ctx.language` 选表——面板的语言跟着调用它的那一页走。 */
2
+ const zh = {
3
+ saved: '已保存,下一次请求生效。',
4
+ instancesTitle: '供应实例',
5
+ instancesDescription:
6
+ '每个实例独立保存连接、模型档与报价。当前请求与已启动的后台会话保持原有绑定。',
7
+ activeSuffix: ' · 当前',
8
+ instanceField: '供应实例',
9
+ newInstanceName: '新实例名称',
10
+ newInstanceUrl: 'HTTP(S) 供应地址',
11
+ addInstance: '添加实例',
12
+ connectionTitle: '连接',
13
+ connectionDescription: '地址与密钥全局共用:别的部署选中同一实例时读的是同一份。',
14
+ baseUrl: '供应地址',
15
+ secretName: '密钥变量名',
16
+ secretNamePlaceholder: '环境变量名;留空 = 无鉴权',
17
+ secretStatus: '密钥',
18
+ secretSource: { env: '进程环境', file: '端点 .env', none: '未配置' },
19
+ secretValue: '密钥值',
20
+ secretValuePlaceholder: '只写入端点 .env,不回显',
21
+ saveSecret: '写入密钥',
22
+ secretSaved: '密钥已写入端点 .env。',
23
+ secretNameFirst: '先保存密钥变量名,再写入密钥值。',
24
+ multimodal: '接受图片输入',
25
+ endpointPath: '请求路径',
26
+ extraHeaders: '附加请求头(JSON 对象)',
27
+ extraBody: '附加请求体(JSON 对象)',
28
+ jsonObjectRequired: (label: string) => `${label} 必须是 JSON 对象`,
29
+ advancedProtocolTitle: '协议与请求扩展',
30
+ advancedProtocolDescription: '',
31
+ modelFieldLabel: '模型标识',
32
+ effortFieldLabel: '推理强度',
33
+ temperatureFieldLabel: '采样温度',
34
+ specTitle: '模型档',
35
+ specDescription: '此端点的每次调用共用这份模型配置;fork 使用创建时的快照。',
36
+ modelName: '明确模型名',
37
+ fetchModels: '取模型列表',
38
+ modelsFetched: (count: number) => `取到 ${count} 个模型。`,
39
+ modelListFailed: (message: string) => `取不到模型列表:${message}`,
40
+ selectModel: '选择模型',
41
+ unsupportedTier: (current: string) => `当前档位未支持:${current}`,
42
+ thinkingOn: '开启',
43
+ thinkingOff: '关闭',
44
+ effortPlaceholder: '推理强度;空 = 端点默认,none = 关闭',
45
+ effortAria: '推理强度',
46
+ temperaturePlaceholder: '温度默认',
47
+ modelAria: '模型',
48
+ tierAria: '推理档位',
49
+ temperatureAria: '温度',
50
+ maxTokens: '最大输出 token',
51
+ contextWindow: '上下文窗口',
52
+ serviceTier: '服务档',
53
+ serverDefault: '服务端默认',
54
+ activate: '设为当前供应实例',
55
+ probe: '测试可用性',
56
+ probeTitle: '测试结果',
57
+ probeStatus: '状态',
58
+ probeOk: '成功',
59
+ probeFailed: '失败',
60
+ probeLatency: '耗时',
61
+ probeModel: '回显模型',
62
+ probeUsage: '用量',
63
+ probeUsageLine: (input: string, cached: string, output: string, reasoning: string) =>
64
+ `输入 ${input} · 缓存命中 ${cached} · 输出 ${output} · 推理 ${reasoning}`,
65
+ probeEncrypted: '加密思维链',
66
+ yes: '有',
67
+ no: '无',
68
+ probeCost: '本次费用',
69
+ duplicate: '复制',
70
+ duplicateName: '副本名称',
71
+ duplicateConfirm: '复制为',
72
+ duplicated: '已复制。',
73
+ delete: '删除',
74
+ deleteConfirmTitle: (name: string) => `删除实例 ${name}?`,
75
+ deleteConfirmBody: '端点配置与 .env 一并删除。别的部署若选中了它,无法在此得知。',
76
+ deleted: '已删除。',
77
+ pricingTitle: '报价',
78
+ pricingDescription: '历史流水固定使用请求时的报价。自定义报价按模型与费用口径覆盖模块默认值。',
79
+ pricingUnset: '未设报价:这个端点的调用在用量与成本页只计 token,不计金额。',
80
+ meters: {
81
+ input: '输入',
82
+ cachedInput: '缓存命中',
83
+ uncachedInput: '未缓存输入',
84
+ output: '输出',
85
+ reasoning: '推理',
86
+ total: '总量',
87
+ },
88
+ quoteUnknown: (model: string) => `${model}:报价未知`,
89
+ marginal: '边际费用',
90
+ equivalent: 'API 等价费用',
91
+ perMillion: (label: string, rate: number) => `${label} ${rate}/百万`,
92
+ free: '已明确免费',
93
+ bandsNote: '含输入阶梯或服务档;按本次实际用量与服务档计费。',
94
+ rateCached: '缓存命中 / 百万 token',
95
+ rateUncached: '未缓存输入 / 百万 token',
96
+ rateOutput: '输出 / 百万 token',
97
+ currencyField: '币种',
98
+ costFormNote: '基础费率统一适用于全部模型;阶梯或多模型规则请在下方完整规则中配置。',
99
+ costFormOverridden: '当前报价不是三格表能表达的形状,以下方完整规则为准;改动三格表会覆盖它。',
100
+ editFull: '高级定价规则 (JSON)',
101
+ fullNote:
102
+ '空数组恢复模块默认报价;rules 为空数组表示明确免费。完整规则支持输入阶梯、服务档及额外计量单位。',
103
+ viewSnapshot: '查看当前生效报价快照',
104
+ };
105
+ const en: typeof zh = {
106
+ saved: 'Saved; applies from the next request.',
107
+ instancesTitle: 'Provider instances',
108
+ instancesDescription:
109
+ 'Each instance keeps its own connection, model spec and pricing. In-flight requests and running background sessions keep their existing binding.',
110
+ activeSuffix: ' · active',
111
+ instanceField: 'Provider instance',
112
+ newInstanceName: 'New instance name',
113
+ newInstanceUrl: 'HTTP(S) provider URL',
114
+ addInstance: 'Add instance',
115
+ connectionTitle: 'Connection',
116
+ connectionDescription:
117
+ 'URL and key are global: other deployments selecting this instance read the same copy.',
118
+ baseUrl: 'Provider URL',
119
+ secretName: 'Key variable name',
120
+ secretNamePlaceholder: 'Environment variable name; empty = no auth',
121
+ secretStatus: 'API key',
122
+ secretSource: { env: 'process env', file: 'endpoint .env', none: 'not set' },
123
+ secretValue: 'Key value',
124
+ secretValuePlaceholder: 'Written to the endpoint .env only; never shown',
125
+ saveSecret: 'Save key',
126
+ secretSaved: 'Key written to the endpoint .env.',
127
+ secretNameFirst: 'Save the key variable name before writing a key value.',
128
+ multimodal: 'Accepts image input',
129
+ endpointPath: 'Request path',
130
+ extraHeaders: 'Extra headers (JSON object)',
131
+ extraBody: 'Extra body (JSON object)',
132
+ jsonObjectRequired: (label: string) => `${label} must be a JSON object`,
133
+ advancedProtocolTitle: 'Protocol & Request Overrides',
134
+ advancedProtocolDescription: '',
135
+ modelFieldLabel: 'Model identifier',
136
+ effortFieldLabel: 'Reasoning effort',
137
+ temperatureFieldLabel: 'Sampling temperature',
138
+ specTitle: 'Model',
139
+ specDescription: 'Calls on this endpoint share its model configuration; forks use the snapshot from their creation.',
140
+ modelName: 'Exact model name',
141
+ fetchModels: 'Fetch models',
142
+ modelsFetched: (count: number) => `Fetched ${count} models.`,
143
+ modelListFailed: (message: string) => `Could not fetch the model list: ${message}`,
144
+ selectModel: 'Pick a model',
145
+ unsupportedTier: (current: string) => `Unsupported current tier: ${current}`,
146
+ thinkingOn: 'on',
147
+ thinkingOff: 'off',
148
+ effortPlaceholder: 'Reasoning effort; empty = endpoint default, none = off',
149
+ effortAria: 'Reasoning effort',
150
+ temperaturePlaceholder: 'Default temperature',
151
+ modelAria: 'Model',
152
+ tierAria: 'Reasoning tier',
153
+ temperatureAria: 'Temperature',
154
+ maxTokens: 'Max output tokens',
155
+ contextWindow: 'Context window',
156
+ serviceTier: 'Service tier',
157
+ serverDefault: 'Server default',
158
+ activate: 'Set as active provider instance',
159
+ probe: 'Test endpoint',
160
+ probeTitle: 'Test result',
161
+ probeStatus: 'Status',
162
+ probeOk: 'ok',
163
+ probeFailed: 'failed',
164
+ probeLatency: 'Latency',
165
+ probeModel: 'Model echoed',
166
+ probeUsage: 'Usage',
167
+ probeUsageLine: (input: string, cached: string, output: string, reasoning: string) =>
168
+ `input ${input} · cached ${cached} · output ${output} · reasoning ${reasoning}`,
169
+ probeEncrypted: 'Encrypted reasoning',
170
+ yes: 'yes',
171
+ no: 'no',
172
+ probeCost: 'Cost of this call',
173
+ duplicate: 'Duplicate',
174
+ duplicateName: 'Copy name',
175
+ duplicateConfirm: 'Duplicate as',
176
+ duplicated: 'Duplicated.',
177
+ delete: 'Delete',
178
+ deleteConfirmTitle: (name: string) => `Delete instance ${name}?`,
179
+ deleteConfirmBody:
180
+ 'Removes the endpoint config and its .env. Whether another deployment selects it cannot be known here.',
181
+ deleted: 'Deleted.',
182
+ pricingTitle: 'Pricing',
183
+ pricingDescription:
184
+ 'Historical records keep the quote in effect at request time. Custom quotes override module defaults per model and cost basis.',
185
+ pricingUnset: 'No pricing set: calls on this endpoint count tokens but no amount on the usage page.',
186
+ meters: {
187
+ input: 'Input',
188
+ cachedInput: 'Cache hit',
189
+ uncachedInput: 'Uncached input',
190
+ output: 'Output',
191
+ reasoning: 'Reasoning',
192
+ total: 'Total',
193
+ },
194
+ quoteUnknown: (model: string) => `${model}: quote unknown`,
195
+ marginal: 'Marginal cost',
196
+ equivalent: 'API-equivalent cost',
197
+ perMillion: (label: string, rate: number) => `${label} ${rate}/M`,
198
+ free: 'Explicitly free',
199
+ bandsNote: 'Includes input bands or service tiers; billed by actual usage and service tier per request.',
200
+ rateCached: 'Cache hit / M tokens',
201
+ rateUncached: 'Uncached input / M tokens',
202
+ rateOutput: 'Output / M tokens',
203
+ currencyField: 'Currency',
204
+ costFormNote:
205
+ 'Base rates apply to all models; input bands and service tiers go in the full rules below.',
206
+ costFormOverridden:
207
+ 'The saved pricing is not a shape the three-rate form can express; the full rules below apply. Editing the form replaces them.',
208
+ editFull: 'Advanced Pricing Rules (JSON)',
209
+ fullNote:
210
+ 'An empty array restores the module default quote; an empty rules array means explicitly free. Full rules support input bands, service tiers and extra meters.',
211
+ viewSnapshot: 'View active pricing snapshot',
212
+ };
213
+ export const panel = { zh, en };
@@ -0,0 +1,10 @@
1
+ /** 内置面板注册表,键对应 ConsolePanelDecl.builtin。 */
2
+
3
+ import type { ConsolePanel } from '../../shared/client-panel.ts';
4
+ import { llmSettingsPanel } from './builtins/llm-settings/panel.ts';
5
+
6
+ export type BuiltinPanels = Readonly<Record<string, ConsolePanel>>;
7
+
8
+ export const BUILTIN_PANELS: BuiltinPanels = {
9
+ 'llm-settings': llmSettingsPanel,
10
+ };
@@ -0,0 +1,135 @@
1
+ /**
2
+ * ConsolePanelContext 组装入口,为扩展提供调用、UI、流与资源管理。signal、interval、frame、own、guardLeave 及 UI 资源均绑定本次面板挂载的生命周期。
3
+ */
4
+
5
+ import {
6
+ type ConsoleMemo,
7
+ type ConsolePanelContext,
8
+ type ConsoleStreamHandle,
9
+ type ConsoleStreamHandlers,
10
+ type Disposable,
11
+ } from '../../shared/client-panel.ts';
12
+ import { panelStreamRoute } from '../../shared/console-protocol.ts';
13
+ import {
14
+ invokePanel,
15
+ invokePanelBinary,
16
+ pickPath as pickHostPath,
17
+ setConfig as writeConfig,
18
+ } from '../core/api.ts';
19
+ import { LANGUAGE } from '../core/language.ts';
20
+ import { Lifecycle } from '../core/lifecycle.ts';
21
+ import { openStream, type SocketLike } from '../core/stream.ts';
22
+ import { createConsoleUi } from '../ui/index.ts';
23
+
24
+ export interface PanelContextDeps {
25
+ pageId: string;
26
+ panelId: string;
27
+ root: HTMLElement;
28
+ /** 该面板的资源账本。host 建、host 在 unmount 时 dispose。 */
29
+ lifecycle: Lifecycle;
30
+ /** 浮层宿主。**不能是 `root`**——那个 unmount 时会被清空。 */
31
+ overlayHost: HTMLElement;
32
+ /** 重取 manifest 刷新 host 那部分(徽标 / 导航 / 三态)。 */
33
+ refresh(): Promise<void>;
34
+ /** 注册离开拦截,返回解除函数。由 router 提供。 */
35
+ addLeaveGuard(fn: () => string | null): Disposable;
36
+ /** 持久化后端。host 给一个按 `page:panel` 命名空间隔离过的实现。 */
37
+ memo: ConsoleMemo;
38
+ /** WS 构造。注入以便测试。 */
39
+ createSocket(url: string): SocketLike;
40
+ /** 绝对化 WS 地址(`/ws/...` → `ws://host/ws/...`)。 */
41
+ wsUrl(path: string): string;
42
+ onError(err: unknown): void;
43
+ doc?: Document;
44
+ /** 宿主面板挂载本面板时给的作用域;自己占一个页签时为空对象。 */
45
+ scope?: Readonly<Record<string, string>>;
46
+ /** 把本页声明到某插槽的面板挂进容器。host 提供实现。 */
47
+ mountSlot(
48
+ slot: string,
49
+ host: HTMLElement,
50
+ scope: Readonly<Record<string, string>>,
51
+ ): Promise<Disposable>;
52
+ }
53
+
54
+ /**
55
+ * memo 按 page:panel 隔离,命名空间由 context 加入,避免不同面板的同名键互相覆盖。
56
+ */
57
+ export function namespacedMemo(
58
+ backing: ConsoleMemo,
59
+ pageId: string,
60
+ panelId: string,
61
+ ): ConsoleMemo {
62
+ const prefix = `${pageId}${panelId}`;
63
+ return {
64
+ get: (key, fallback) => backing.get(prefix + key, fallback),
65
+ set: (key, value) => backing.set(prefix + key, value),
66
+ };
67
+ }
68
+
69
+ export function createPanelContext(deps: PanelContextDeps): ConsolePanelContext {
70
+ const { pageId, panelId, lifecycle } = deps;
71
+ const signal = lifecycle.signal;
72
+
73
+ const ui = createConsoleUi({
74
+ memo: deps.memo,
75
+ overlayHost: deps.overlayHost,
76
+ signal,
77
+ ...(deps.doc ? { doc: deps.doc } : {}),
78
+ });
79
+
80
+ return {
81
+ pageId,
82
+ panelId,
83
+ language: LANGUAGE,
84
+ root: deps.root,
85
+ signal,
86
+
87
+ invoke: <T>(method: string, args?: unknown[]): Promise<T> =>
88
+ invokePanel<T>(pageId, panelId, method, args, { signal }),
89
+
90
+ invokeBinary: (method: string, args?: unknown[]): Promise<Blob> =>
91
+ invokePanelBinary(pageId, panelId, method, args, { signal }),
92
+
93
+ notifyOnUnmount(method: string, args?: unknown[]): void {
94
+ signal.addEventListener('abort', () => {
95
+ void invokePanel(pageId, panelId, method, args, { keepalive: true }).catch(deps.onError);
96
+ }, { once: true });
97
+ },
98
+
99
+ scope: deps.scope ?? {},
100
+
101
+ mountSlot: (slot, host, scope) => deps.mountSlot(slot, host, scope ?? {}),
102
+
103
+ pickPath: (options) => pickHostPath(options, { signal }),
104
+
105
+ setConfig: (groupId, values) => writeConfig(groupId, values, { signal }),
106
+
107
+ stream(handlers: ConsoleStreamHandlers): ConsoleStreamHandle {
108
+ const handle = openStream({
109
+ url: deps.wsUrl(panelStreamRoute(pageId, panelId)),
110
+ handlers,
111
+ signal,
112
+ createSocket: deps.createSocket,
113
+ setTimer: (fn, ms) => setTimeout(fn, ms) as unknown as number,
114
+ clearTimer: (id) => clearTimeout(id),
115
+ onError: deps.onError,
116
+ });
117
+ // openStream 自己听 signal 收场;再登记一次是为了让"提前 dispose"也走同一条路。
118
+ lifecycle.own(handle);
119
+ return handle;
120
+ },
121
+
122
+ interval: (fn, ms) => lifecycle.interval(fn, ms),
123
+ timeout: (fn, ms) => lifecycle.timeout(fn, ms),
124
+ frame: (fn) => lifecycle.frame(fn),
125
+ own: (d) => lifecycle.own(d),
126
+
127
+ memo: deps.memo,
128
+
129
+ guardLeave: (fn) => lifecycle.own(deps.addLeaveGuard(fn)),
130
+
131
+ ui,
132
+
133
+ refresh: () => deps.refresh(),
134
+ };
135
+ }