Compare commits

...

1398 Commits

Author SHA1 Message Date
claude[bot] 48cee6766a fix: auto-title conversations after Beam success
Add optional onSuccess callback to beamInvoke() so callers can inject
post-success behavior (auto-titling) without introducing a dependency
from common/ to modules/aifn/. All chat call sites now pass the
auto-title hook, matching the existing chat-persona flow.

Closes #1078

Co-authored-by: Enrico Ros <enricoros@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 04:22:56 +00:00
Enrico Ros 9bb178413b Upstream removal: Update language 2026-04-23 15:46:07 -07:00
Enrico Ros d85f0ebfc4 AIX: Upstream Deletion via both CSF or tRPC 2026-04-23 15:29:39 -07:00
Enrico Ros 8f84dc2f24 AIX: more clenaups 2026-04-23 15:09:24 -07:00
Enrico Ros c8b4301bcd AIX: Client: cleanups 2026-04-23 14:50:21 -07:00
Enrico Ros bd8eaf0b9f Bits 2026-04-23 14:03:46 -07:00
Enrico Ros a4148cf694 BlockPartModelAux: reasoning: detection of markdown ignores newlines 2026-04-23 14:02:42 -07:00
Enrico Ros 4cb0b493dc BlockPartPlaceholder: timeout of a week for very long ops 2026-04-23 13:51:26 -07:00
Enrico Ros e6354e9089 ChatMessage: link to star 2026-04-23 13:42:19 -07:00
Enrico Ros 08506abaee AIX: Gemini Interactions: rewrap to nullify retry errors, to not re-submit expensive Deep Research runs 2026-04-23 03:08:10 -07:00
Enrico Ros 078c80d572 AIX: Gemini Interactions: full SSE migration (no post + get_loop anymore) 2026-04-23 02:15:35 -07:00
Enrico Ros b1c9f6be45 AIX: ContentReassembler: improve not-wiping ops on conent (yes to wiping vp) 2026-04-23 02:15:35 -07:00
Enrico Ros fc497e9beb AIX: Gemini Interactions: improve wires 2026-04-23 02:15:35 -07:00
Enrico Ros 6ad01fd981 AIX: update _upstream 2026-04-23 02:15:35 -07:00
Enrico Ros 44ed8664c8 Placeholder: elevate to 6hrs the UI counter 2026-04-22 23:28:27 -07:00
Enrico Ros 4cb16ee715 AIX: upstream protocol docs cache; local copy of the specs, let's see if it's useful 2026-04-22 23:16:14 -07:00
Enrico Ros 2dc9b87cda AIX: Gemini Interactions: allow multiple reattaches, use the Gemini default timeout 2026-04-22 22:29:57 -07:00
Enrico Ros 0e587c4889 ContentReassembler: report image conversion fail 2026-04-22 19:15:57 -07:00
Enrico Ros 41d42d82fb AIX: Gemini interactions: improvements 2026-04-22 18:28:16 -07:00
Enrico Ros f703c8a8c9 AIX: Cleanups 2026-04-22 18:20:40 -07:00
Enrico Ros bf753eab55 AIX: XAI: support for reasoning items 2026-04-22 17:59:32 -07:00
Enrico Ros 698b67af06 AIX: Gemini Interactions: images are usually figures, skip conversion 2026-04-22 17:59:10 -07:00
Enrico Ros 377d61056a ChatMessageList: resume: remove pending and update only on done 2026-04-22 17:50:54 -07:00
Enrico Ros 94b32c8fe3 BlockOpUpstreamResume: update style 2026-04-22 17:47:25 -07:00
Enrico Ros 1e70a59ad6 ChatMessageList: do not remove the connection button on error - tradeoff: less removal on 404, but not removal on network error 2026-04-22 17:40:38 -07:00
Enrico Ros 44d05181f4 AIX: Gemini Interactions: update with support for Audio, Thougts 2026-04-22 17:37:20 -07:00
Enrico Ros 996998a5cc AIX: Gemini Interactions: In/Out of images, Out of Audio 2026-04-22 17:37:20 -07:00
Enrico Ros 98474b2721 AIX: OpenAI Responses: Encrypted reasoning 2026-04-22 17:37:20 -07:00
Enrico Ros 198dc0e23f AIX: OpenAI Responses: Wires: allow encrypted reasoning 2026-04-22 17:37:20 -07:00
Enrico Ros 079731c573 ContentReassembler: recreate Ops placeholder part with anchored CTS, to show the correct start time 2026-04-22 17:37:20 -07:00
Enrico Ros 492c89650a tRPC 4xx (!ok): return quoted reason 2026-04-22 17:35:56 -07:00
Enrico Ros 5b5bbb7649 dMessageUtils: update gemini namings 2026-04-22 16:15:54 -07:00
Enrico Ros 27d1f081ab AI Inspector: memstored collapse state, and disable auto-snap 2026-04-22 16:15:54 -07:00
Enrico Ros 76183fd840 LLMs: flush openai 2026-04-22 13:55:56 -07:00
Enrico Ros 345165eabf AIX: fix OpenAI Responses - Tool re-parsing 2026-04-22 13:52:14 -07:00
Enrico Ros c186732b3b AI Inspector: collapsable header/body/particlews 2026-04-22 13:39:14 -07:00
Enrico Ros 04916b700e AIX: Reattach: preserve the creation time and don't overwrite handle on reattach 2026-04-22 13:15:25 -07:00
Enrico Ros 013dab185c ChatMessageList: remove the button if Gemini Reattach is 404 2026-04-22 13:15:25 -07:00
Enrico Ros 5ab93faccf AIX: ContentReassembler: document filtering causes 2026-04-22 13:15:25 -07:00
Enrico Ros fa301e3675 Chat: move message timestamps to the tooltip 2026-04-22 13:01:05 -07:00
claude[bot] fa6e7dd9c5 Chat: show inline message timestamps - TimeAgo for today, locale date for older
Shows a lightweight timestamp at the bottom of each message in the chat view.
Messages from today or currently generating display relative time via TimeAgo.
Older messages show the locale-formatted date. Hidden in zen mode and during edits.

Closes #1065
2026-04-22 12:45:19 -07:00
Enrico Ros 01736ad5da AIX: ContentReassembler: consider refusals as failure modes, and add the error messages too 2026-04-22 02:49:20 -07:00
Enrico Ros ce682b1f85 AIX: Client: CSF for resuming chat generate content 2026-04-22 02:34:22 -07:00
Enrico Ros 96d801f40a AIX: Gemini Interactions: elevate polling to 10 2026-04-22 02:15:20 -07:00
Enrico Ros 8985868f63 Roll AIX 2026-04-22 01:35:55 -07:00
Enrico Ros 8febdcd0c0 ChatMessageList: pass generator to the resume request 2026-04-22 01:35:18 -07:00
Enrico Ros 4d21d5134a AIX: Gemini Interactions: Alpha support - fresh with 2-stages poller, plus reconnect - both feed into the same stream and parser 2026-04-22 01:23:36 -07:00
Enrico Ros 09d44a4314 AIX: Dispatch: custom-connect suppport, for non-single-request solutions; add connection ownership 2026-04-22 01:22:44 -07:00
Enrico Ros 40066e975a AIX: Dispatch: cleanup router 2026-04-22 01:14:17 -07:00
Enrico Ros 202382c80a BlockPartPlaceholder: format as min/sec 2026-04-22 00:57:26 -07:00
Enrico Ros 6ffbb32c57 BlockPartPlaceholder: bump seconds timer to 1h 2026-04-22 00:54:11 -07:00
Enrico Ros 9b8a3ca503 ChatMessage: wire resume 2026-04-22 00:49:33 -07:00
Enrico Ros cdd7892077 AIX: Client: resume support with entry point for future resumes 2026-04-22 00:46:54 -07:00
Enrico Ros 974aa12137 DMessages/AIX: broaden upstreamHandle 2026-04-21 16:15:37 -07:00
Enrico Ros d8f8999333 LLMs: extract isometric/free host matching 2026-04-21 15:26:34 -07:00
Enrico Ros 0efd87b522 T2I: GPT-Image-2 support 2026-04-21 14:16:25 -07:00
Enrico Ros ec76e1c5cf AIX: OpenAI Responses: image generation: add details 2026-04-21 14:16:25 -07:00
Enrico Ros 1e04efe748 LLMs: OpenAI: gpt-image-2 non chat 2026-04-21 14:16:25 -07:00
Enrico Ros 69c135ae78 LLMs: Moonshot: add Kinmi K2.6 2026-04-20 23:22:47 -07:00
Enrico Ros 205fb1bb5b LLMs: sync scores 2026-04-20 23:13:56 -07:00
Enrico Ros c8e7315de3 Roll AIX 2026-04-20 22:16:58 -07:00
Enrico Ros 725f3b0fd7 AutoBlocksRenderer: optimize inline md flicker (zenMode only)
Uses a 512 chars bypass too.
2026-04-20 17:46:18 -07:00
Enrico Ros 7ee3701607 AIX Inspector: bits 2026-04-20 16:05:28 -07:00
Enrico Ros 9537ce59e8 LLM: cap initial max response to 128k 2026-04-20 16:05:28 -07:00
Enrico Ros 6c0a60e0d1 CSF/DC: update docs 2026-04-20 16:05:27 -07:00
Enrico Ros 436a858cb0 AIX Inspector: render as code 2026-04-20 10:46:40 -07:00
Enrico Ros 6ea6c55f65 LLMs: xAI: align-params 2026-04-20 10:46:40 -07:00
Enrico Ros c477fa86ce LLMs: Gemini: align-params 2026-04-20 10:46:40 -07:00
Enrico Ros 08cd5ed5b6 LLMs: OpenAI/Gemini: sync Fn, remove Json 2026-04-20 10:46:40 -07:00
Enrico Ros b5f2cd35f2 LLMs: deprecate Json 2026-04-20 10:46:40 -07:00
Enrico Ros 4cb0f6d67e Parameters sweep: xAI 2026-04-20 10:45:58 -07:00
Enrico Ros 5260ec68cc Remove Code Editors - unused 2026-04-19 22:47:22 -07:00
Enrico Ros 72ce4d2884 CC: Sweep: update verify-params 2026-04-19 22:26:06 -07:00
Enrico Ros ed65f989d9 Parameters sweep: Ant,Gem,Oai 2026-04-19 22:26:06 -07:00
Enrico Ros 588ebf4993 Sweep: add fn(auto,required,roundtrip) measure 2026-04-19 22:26:06 -07:00
Enrico Ros 22969033a7 LLMs: Gemini: restore 3 Pro Preview (still served) 2026-04-17 13:59:32 -07:00
Enrico Ros 8b5e00480b Tests: +listModels: list models for all vendors and show Model IDs per test (or DEV warns/failures)
Each test either asserts live behavior or skips with "needs <ENV_VAR>" -no silent passes.

Requires:
- NODE_ENV=development (DEV-gated validators; ESM hoisting blocks setting
  it in-file)
- Per-vendor API keys; otherwise that dialect is skipped

Returns:
- Model IDs per test in IntelliJ's output panel / spec reporter
- Failure on any [DEV] validator output, pointing at llms:update-models-*
- 4 no-creds live tests (perplexity, minimax-host, zai, openrouter)

Run: NODE_ENV=development npx tsx --test src/modules/llms/server/listModels.test.ts
2026-04-17 13:52:53 -07:00
Enrico Ros aaf752fa9c CC: code:thread-progress 2026-04-17 12:48:05 -07:00
Enrico Ros 82d3b36048 Roll AIX 2026-04-17 08:31:50 -07:00
Enrico Ros 588c81f9ad AnthropicSkillsConfig: improve select (now default) 2026-04-17 00:11:33 -07:00
Enrico Ros 4013a3f997 ConversationsManager: early null warning 2026-04-16 16:37:33 -07:00
Enrico Ros 5823e18904 ExpanderSection: allow persistent divider 2026-04-16 16:36:46 -07:00
Enrico Ros 31ea6863aa LLMs: OpenRouter: extend 2026-04-16 15:57:03 -07:00
Enrico Ros f3f58f26ae LLMs: Chutes: parse model attributes 2026-04-16 15:57:03 -07:00
Enrico Ros 67132f285e LLMs: Misc: sync models 2026-04-16 15:57:03 -07:00
Enrico Ros 20a638a8c9 LLMs: Ollama: sync models 2026-04-16 15:57:00 -07:00
Enrico Ros c9174e995f LLMs: Anthropic: notes on API reported tokens 2026-04-16 15:56:55 -07:00
Enrico Ros 656c507c94 LLMs: Gemini: add 3.1 Flash TTS and Robotics-ER 1.6 2026-04-16 15:56:55 -07:00
Enrico Ros a1fb744eb1 Share Service Add Button 2026-04-16 15:56:42 -07:00
Enrico Ros 28367547fd LLMs: Ant Skills: show by default nwo 2026-04-16 14:14:35 -07:00
Enrico Ros 6610211eac AIX: Ant: change tools label 2026-04-16 14:14:23 -07:00
Enrico Ros b66e3e2afa LLMs: Anthropic 1M tokens review 2026-04-16 13:39:39 -07:00
Enrico Ros 4bf965953a LLMs/AIX: Anthropic Claude Opus 4.7 full support 2026-04-16 13:30:40 -07:00
Enrico Ros 1bd6513d59 AIX: ReassemberTransform: Embed/Delete Anthropic Files 2026-04-16 04:55:04 -07:00
Enrico Ros 6ce457913e AIX: ReassemblerParticleTransform: framework 2026-04-16 04:34:20 -07:00
Enrico Ros ef84ca5a04 AIX: CSF Dispatch: remove unsafe transforms that the client does not support 2026-04-16 04:10:18 -07:00
Enrico Ros f76524c650 BlockPartHostedResource: show meta info message on error 2026-04-16 04:03:33 -07:00
Enrico Ros 0be676229f AIX: Dispatch: tag the Anthropic server-side tranform-fileInline as csfUnsafe because incurs into CORS block by the Anthropic File API servers 2026-04-16 03:44:44 -07:00
Enrico Ros 40a0ca7235 Bits 2026-04-16 03:41:01 -07:00
Enrico Ros 1563c3a9dc Improve more image icons usage 2026-04-16 01:22:50 -07:00
Enrico Ros 80f32be80d Improve image icons usage 2026-04-16 01:15:09 -07:00
Enrico Ros eea53714cc Ph: add ImaegeSquare, Wrench 2026-04-16 01:12:25 -07:00
Enrico Ros 148f1ec22c ExpanderControlledBox: fix a regression with ERC's OverlayButtons' viewport-fixed positioning 2026-04-14 16:12:18 -07:00
Enrico Ros b5a2a70e73 RenderCode: correctly un-tooltip code being written 2026-04-14 15:30:14 -07:00
Enrico Ros e7667e4b7d AIX: Resiliency: detect hard TLS disconnections by the AI service 2026-04-14 15:02:43 -07:00
Enrico Ros 9250eb9aff RenderCode: change fullscreen wrapper 2026-04-14 14:41:09 -07:00
Enrico Ros 92883caaab RenderCode: extract syntax style 2026-04-14 14:38:53 -07:00
Enrico Ros 6d57450efc RenderCode: extract styles 2026-04-14 14:33:38 -07:00
Enrico Ros 5dd4c600ea Roll packages misc 2026-04-14 14:17:34 -07:00
Enrico Ros 392a3b7949 Optimization: Code: memo style & stable copy handler 2026-04-14 14:11:40 -07:00
Enrico Ros e22c40c7e4 Optimization: Memo reasoning Chips (UI component) 2026-04-14 13:56:55 -07:00
Enrico Ros c7abee6969 Roll packages 2026-04-14 13:46:20 -07:00
Enrico Ros 4772e63fdb SyncExternalStorable: helper for useSyncExternalStore, to declare state/snapshot + a lifecycle hook helper 2026-04-14 13:40:20 -07:00
Enrico Ros f3d7abefec Optimization: Code Render Highlight: throttle highlighting of large/partial streams 2026-04-14 13:03:17 -07:00
Enrico Ros ac76b156cf Optimization: Code Render Highlighted: defer pre-coloring, saving even more CPU, avoiding system instability 2026-04-14 11:34:39 -07:00
Enrico Ros 97e65efc31 Optimization: Code Render Highlighted: defer code syntax coloring 2026-04-14 09:46:54 -07:00
Enrico Ros 13dcaa0a57 Optimization: Code language infer: max input size 2026-04-14 09:46:54 -07:00
Enrico Ros 1f42b0ae66 Optimization: AutoBlocks: don't bust fianlized sub-fragment Code/Markdown blocks 2026-04-14 09:46:54 -07:00
Enrico Ros 003a50f181 Optimization: Draft attachments: cache tokens compute 2026-04-14 09:45:16 -07:00
Enrico Ros 32c5849a50 useShallowObject: add lint rule for deps 2026-04-14 09:44:53 -07:00
Enrico Ros 44a8ee0593 useShallowObject: add useMemoShallowStable 2026-04-14 09:44:53 -07:00
Enrico Ros 1ad70c7b1b AGENTS.md as symlink 2026-04-12 23:12:05 -07:00
Enrico Ros 7413983159 Per-Chat stores: debug break on lazy creation 2026-04-12 16:54:32 -07:00
Enrico Ros 6c3e8c6a8f Per-Chat stores: lazily create (with warning)
This also breaks the eager module-scope chain that caused
UKV:exec-defaults getState() to fire 14+ times during build.
2026-04-12 16:54:28 -07:00
Enrico Ros 7e3e9854ac FormInputKey: update icons 2026-04-12 16:51:41 -07:00
Enrico Ros 41fc93345c FormInputKey: allow size 2026-04-12 16:51:40 -07:00
Enrico Ros b9275177e3 Merge pull request #1066 from enricoros/dependabot/github_actions/docker/build-push-action-7.1.0
chore(deps): bump docker/build-push-action from 7.0.0 to 7.1.0
2026-04-12 12:22:06 -07:00
Enrico Ros 5ea95e4095 Merge pull request #1067 from enricoros/dependabot/github_actions/actions/upload-artifact-7.0.1
chore(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1
2026-04-12 12:21:56 -07:00
dependabot[bot] 0ea041ed5b chore(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-11 11:32:23 +00:00
dependabot[bot] 037e3b62d8 chore(deps): bump docker/build-push-action from 7.0.0 to 7.1.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.0.0 to 7.1.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/d08e5c354a6adb9ed34480a06d141179aa583294...bcafcacb16a39f128d818304e6c9c0c18556b85f)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-11 11:32:19 +00:00
Enrico Ros 517c18c902 BlockPartHostedResource: enable always-embed 2026-04-10 03:17:23 -07:00
Enrico Ros 685b5c5130 AIX: Apply global AI settings 2026-04-10 03:17:07 -07:00
Enrico Ros cfdab2f900 Anthropic File Embed: change global setting 2026-04-10 03:17:07 -07:00
Enrico Ros 1a743ff264 Store-AI: global AI settings 2026-04-10 03:17:07 -07:00
Enrico Ros 85463fafb1 AIX: Anthropic: Container -> File API Images inlining 2026-04-10 03:17:07 -07:00
Enrico Ros 0641b0df97 AIX: Anthropic: Container -> File API Text inlining 2026-04-10 03:17:07 -07:00
Enrico Ros 98825081a9 AIX: Dispatch: ChatGenerateParticleTransformFunction 2026-04-10 03:17:07 -07:00
Enrico Ros f549c13465 LLMs: Anthropic: file get metadata schema 2026-04-10 00:40:48 -07:00
Enrico Ros 8bf7fd7106 BlockPartHostedResource: support copy of images 2026-04-09 17:07:30 -07:00
Enrico Ros d8d889c706 BlockPartHostedResource: remove disabled button 2026-04-09 16:24:46 -07:00
Enrico Ros 90665ed84a BlockPartPlaceholder.tsx: space inputs 2026-04-09 16:24:15 -07:00
Enrico Ros dd3d10a391 MIME: support for Anthropic File API mimes 2026-04-09 16:24:04 -07:00
Enrico Ros 19ebd399a8 AIX: Anthropic: parser: improve server_tool_use ends 2026-04-09 16:22:25 -07:00
Enrico Ros f21a2973e9 BlockPartHostedResource: further simplify Anthropic ops 2026-04-09 15:15:27 -07:00
Enrico Ros 04bb8f9c12 BlockPartHostedResource: improve Anthropic documents fetching (with cache), more reliable 2026-04-09 14:54:55 -07:00
Enrico Ros 5ea63c8734 LLMs: store: FP NOTICE - hook to resolve access for a llm id
Note: to make this portable across machines with different configurations, we also allow to fall back
to the first access of a certain type for the
llm.
2026-04-09 14:36:26 -07:00
Enrico Ros f4f4ad9373 LLMs: improve DModelVendor typings, and reverse Id->type mappings 2026-04-09 14:25:30 -07:00
Enrico Ros ba06d70c05 BlockPartHostedResource: Anthropic text documents inlining 2026-04-09 05:43:31 -07:00
Enrico Ros 62ddd17715 Fix Chat Store improper zero-state.
No point in always inserting a chat beyond the zero-state (i.e. even if many are loaded).
Now it's only created if it matters.
2026-04-09 04:20:53 -07:00
Enrico Ros f76db1d19e Merge branch 'main' of https://github.com/alexdenton123/big-AGI into alexdenton123-main 2026-04-08 19:02:09 -07:00
Enrico Ros f0901dbc03 Merge pull request #1063 from enricoros/claude/issue-1061-20260406-2309
fix: hide voice features in browsers without Speech Recognition support
2026-04-08 19:00:22 -07:00
Enrico Ros c65a2ce387 LLMs: Anthropic: auto-detect features and 0-day models (Mythos) 2026-04-08 18:41:17 -07:00
Enrico Ros eaee372938 ModelsList: bolden customized models 2026-04-08 18:08:32 -07:00
Enrico Ros d8836534cb LLMs: Anthropic: Sonnet 4.6 can effort: max 2026-04-08 18:01:53 -07:00
Enrico Ros 7d2e64b458 LLMs: Ollama: relax enrichment 2026-04-08 17:38:40 -07:00
Enrico Ros bc942c5581 LLMs: Ollama: fix missing descriptions 2026-04-08 17:35:44 -07:00
Alex Denton 4ca24f8314 Add 'New Chat on Startup' setting to reopen last chat
Adds a toggle in Preferences > Chat that controls whether a new empty
chat is created on startup (default, current behavior) or the last
conversation is reopened instead.
2026-04-09 00:24:07 +02:00
Enrico Ros b299dec68e BlockPartPlaceholder: spacing 2026-04-08 14:14:05 -07:00
Enrico Ros b9f07d011b CC: code:thread-progress 2026-04-07 23:39:02 -07:00
Enrico Ros 9259be8dbb CC: +code:thread-progress 2026-04-07 20:39:29 -07:00
Enrico Ros 4b0b7c4493 ChatMessage: add info popup 2026-04-07 16:42:29 -07:00
Enrico Ros 73f0760809 BlockPartHostedResource: follow-ups 2026-04-07 14:25:09 -07:00
Enrico Ros db6c2b1620 BlockPartHostedResource: alllow deletion, copy 2026-04-07 13:45:58 -07:00
Enrico Ros 1233e846db Beam Gather: error improvements 2026-04-07 13:38:20 -07:00
Enrico Ros 27312537a7 AIX Client errors: reflect 413 2026-04-07 13:38:20 -07:00
Enrico Ros 1dfd4d8395 BlockPartHostedResource: fix: react to service changes 2026-04-07 05:09:15 -07:00
Enrico Ros ccd9f0980f AIX: bits 2026-04-07 04:50:00 -07:00
Enrico Ros 5cc48d24ec AIX: Anthropic: Download Files (AIX hosted resource support) 2026-04-07 04:31:34 -07:00
Enrico Ros 7929d4eb30 AIX: Anthropic: Containers support (1h) - allows to continue Skills, bash sessions, dynamic filtering, temp files, etc. 2026-04-07 03:06:29 -07:00
Enrico Ros 14c5c83f91 AIX: Anthropic: Dispatch: Headers (beta flags) update 2026-04-07 01:36:21 -07:00
Enrico Ros 263412c422 AIX: Anthropic: Files download 2026-04-07 00:21:35 -07:00
Enrico Ros d395fa817d AIX: Anthropic: Containers: parsing support via 'svs' 2026-04-07 00:21:35 -07:00
Enrico Ros 9cfc8c513b AIX: Anthropic: show return code errors in blocks 2026-04-06 16:44:04 -07:00
Enrico Ros c92a1cfcb1 Merge pull request #1059 from enricoros/dependabot/github_actions/docker/login-action-4.1.0
chore(deps): bump docker/login-action from 4.0.0 to 4.1.0
2026-04-06 16:17:39 -07:00
claude[bot] f45e45ca8f fix: hide voice features in browsers without Speech Recognition support
Add Brave browser detection to pwaUtils.ts since Brave exposes the
SpeechRecognition API but silently blocks it from returning results,
causing false positive feature detection.

- Add `Is.Browser.Brave` detection via `navigator.brave` property
- Update `browserSpeechRecognitionCapability()` to mark Brave as
  unsupported with a clear warning message
- Gate Call button (both mobile and desktop) on speech recognition
  capability since Call fundamentally requires voice input
- CallWizard already displays capability warnings, so Brave users
  navigating directly to /call will see a clear explanation

Closes #1061

Co-authored-by: Enrico Ros <enricoros@users.noreply.github.com>
2026-04-06 23:12:45 +00:00
Enrico Ros e44d4b8b01 AIX: make stop reason setting idempotent 2026-04-06 16:05:50 -07:00
Enrico Ros c342f553db AIX: bits 2026-04-06 16:05:27 -07:00
Enrico Ros 2fab208ccf package: tsclint 2026-04-06 13:59:53 -07:00
Enrico Ros eab3eee19f roll posthog 2026-04-06 13:59:41 -07:00
Enrico Ros fcb3903b5f AIX: flush bits 2026-04-06 13:43:41 -07:00
Enrico Ros 90ccb64bd0 AIX: Core: immutable structural sharing, typed outcome, improve layering
Refactor the AIX client streaming pipeline for Zustand-style immutability
and clean outcome classification, preparing for the agentic execution layer.

ContentReassembler:
- All fragment mutations go through _pushFragment/_replaceFragmentAt/_spliceFragment
  (new array refs per update, no in-place mutation)
- Generator fields (genModelName, genProviderInfraLabel, genUpstreamHandle,
  legacyGenTokenStopReason) consolidated into a single `generator` object,
  replaced immutably when particles arrive
- _classifyTermination() replaces _deriveTokenStopReasonOrAppendError() -
  pure function returning { outcome, tsr, errorMessage }
- finalizeReassembly() returns AixChatGenerateContent_LL_Result (extends
  streaming type with outcome + cgMetricsLg) instead of void
- Initial state snapshot for full reset (replaces initialGenerator field)

Type system:
- AixChatGenerateContent_LL: streaming-only (fragments + generator)
- AixChatGenerateContent_LL_Result: extends LL with outcome + cgMetricsLg
- AixChatGenerateTerminal_LL: 'completed' | 'failed' | 'aborted'
- Outcome flows LL -> L2 -> L3 without leaking into DMessage/stores
- Unified vocabulary throughout (no more success/errored mapping)

LL streaming loop:
- Restructured with break/continue for guaranteed finalizeReassembly()
- Drain in-flight processing before retry/terminal decisions
- Abort-during-retry-backoff surfaces original error (not 'aborted')
- Retryable path first, terminal fallthrough

Callers:
- Remove structuredClone() calls (structural sharing makes them unnecessary)
- Spread fragments/generator directly into stores
2026-04-06 12:53:33 -07:00
Enrico Ros 1772db5e98 AIX: Anthropic Wires/Parser: improve 2026-04-05 07:50:39 -07:00
Enrico Ros a04ee4de95 LLMs: openai-autocomplete: improve descriptions 2026-04-04 18:21:53 -07:00
Enrico Ros 73b6a54f9e LLMs: MiniMax: update models 2026-04-04 15:48:15 -07:00
Enrico Ros 52b08b407c ChatMessage: optimize messageFragmentsReduceText 2026-04-04 15:27:22 -07:00
Enrico Ros 269a3a9991 CC: llms:update-models-minimax 2026-04-04 13:51:41 -07:00
Enrico Ros 1b2050cd96 MiniMax: add auto-configure UI option and icon 2026-04-04 13:51:25 -07:00
Enrico Ros a71dd5e3aa LLMs: add MiniMax with hardcoded models 2026-04-04 13:51:25 -07:00
Enrico Ros 8d91ea0413 AIX: ListModels: support server-side env-var match 2026-04-04 13:33:21 -07:00
dependabot[bot] 81b39c7f9c chore(deps): bump docker/login-action from 4.0.0 to 4.1.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/b45d80f862d83dbcd57f89517bcf500b2ab88fb2...4907a6ddec9925e35a0a9e82d7399ccc52663121)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-04 11:32:21 +00:00
Enrico Ros a3200e1aab AIX: remove the pause_continue token stop reason, as we handle it in the server-side loop 2026-04-03 16:21:12 -07:00
Enrico Ros 4c8fa8e477 next.config: restore 2026-04-03 12:09:31 -07:00
Enrico Ros f64aae10c5 /tools: add tsconfig for node types 2026-04-03 11:48:14 -07:00
Enrico Ros bd8f484cd2 next.config: single title on build, not dev (4) 2026-04-02 23:47:54 -07:00
Enrico Ros 4c3151e3be roll posthog 2026-04-02 23:08:25 -07:00
Enrico Ros 4e3377f1df roll eslint 2026-04-02 23:06:42 -07:00
Enrico Ros f95b643a5c roll Typescript 6.0.2 2026-04-02 23:05:21 -07:00
Enrico Ros 85083f323d AIX: OpenaI parser: cleanup 2026-04-02 22:36:33 -07:00
Enrico Ros b884386143 LLMs: link autocomplete icons 2026-04-02 22:33:08 -07:00
Enrico Ros 01a8d858cf LLMs: optimize icons 2026-04-02 22:32:54 -07:00
Enrico Ros 08fed36a61 LLMs: add new icons 2026-04-02 22:17:12 -07:00
Enrico Ros f8b110e108 LLMs: Groq: update models 2026-04-02 21:35:12 -07:00
Enrico Ros b78b0f1323 LLMs: OpenAI autocomplete: icons support 2026-04-02 21:31:29 -07:00
Enrico Ros 148c0b1d77 CC: do not git stash 2026-04-02 21:20:09 -07:00
Enrico Ros fe501831b2 Roll AIX 2026-04-02 21:15:39 -07:00
Enrico Ros 1862b72ba5 LLMs: Arcee AI: add OpenAI-compatible provider, with auto-qualified models 2026-04-02 21:12:47 -07:00
Enrico Ros a609071966 AIX: Arcee AI: fix for null fields (protocol breakage; they shall be optional, not null) 2026-04-02 20:50:10 -07:00
Enrico Ros dc2d162e6e Roll AIX 2026-04-02 18:02:43 -07:00
Enrico Ros 07f2cd291e AIX: Arcee AI: fix trinity with some null chatCompletions fields 2026-04-02 18:02:43 -07:00
Enrico Ros a6e040e3e5 AIX: Reassembly: Snapshots for continuation & retry reset
Also includes:
- move Accumulator inside the Reassembler
- drain in-flight before client-retry
- improved continue/retry visualizations
- retrier has less status inside (removed resume handle, now external)

Fixes #1055
2026-04-02 17:36:43 -07:00
Enrico Ros 3e6cfc9775 AIX: Anthropic: parser: signal text vs bash script 2026-04-02 16:13:59 -07:00
Enrico Ros 0e2abd2615 CC: slashcommands: update llms:ollama 2026-04-02 12:50:06 -07:00
Enrico Ros 394e79510e LLMs: Ollama: sync models 2026-04-02 12:47:57 -07:00
Enrico Ros 848977820e LLMs: LocalAI: search models 2026-04-02 12:17:09 -07:00
Enrico Ros c893f1969c LLMs: Gemini: add Gemma4 models 2026-04-02 11:59:49 -07:00
Enrico Ros bb9a8b81d1 BlockPartModelAux: improve Reasoning render 2026-03-31 18:04:19 -07:00
Enrico Ros 188b338bdc CC: mv -> git mv 2026-03-31 18:04:19 -07:00
Enrico Ros 463ef406a7 AIX: CG Eexecutor: Anthropic retry 2026-03-31 13:06:46 -07:00
Enrico Ros a916ff46dc BlockPartPlaceholder: shrink 2026-03-31 13:06:43 -07:00
Enrico Ros db3a5c0b1b BlockPartPlaceholder: improve quality of render with timeouts 2026-03-30 23:21:45 -07:00
Enrico Ros b760250da1 AIX: CGR: respect source ordering of messages, and remove the Tool messages in AIX up 2026-03-28 09:04:12 -07:00
Enrico Ros b5829ac541 AIX: Gemini: comment 2026-03-28 06:55:53 -07:00
Enrico Ros fa4f2b8fcd AIX: Reassembler: persistence-of-vision of 500ms for VP fragments
Allows for a more natural read.
2026-03-28 06:55:49 -07:00
Enrico Ros 333c318a62 AIX: Anthropic: parse code exec/bash failures 2026-03-28 06:55:49 -07:00
Enrico Ros 5f6f7086d0 AIX: Anthropic: trace bash_code_execution ops 2026-03-28 06:55:49 -07:00
Enrico Ros a7495bd4cf LLMs: document the llm-reset-no-duplicates behavior 2026-03-28 06:55:49 -07:00
Enrico Ros 76c4919e9c LLMs: when resetting parameters, preserve the ones on User Clones 2026-03-28 01:42:18 -07:00
Enrico Ros 5530a0253e AIX: Gemini: wires: safer 2026-03-28 01:00:44 -07:00
Enrico Ros 86aaa65d10 CC: code:grep-history 2026-03-28 00:07:58 -07:00
Enrico Ros 65bf147e04 DMessage/AIX: ToolInvocationResponse parts and AIX ToolResponsePart['FunctionCallResponse'] must carry the function name 2026-03-27 22:25:53 -07:00
Enrico Ros f76ad186f0 AIX: Wires: FIX: fix aix.wires function name (_name was silently stripped) 2026-03-27 21:51:19 -07:00
Enrico Ros e5e333db70 AIX: Gemini: improve tool hosted/user cohexistence 2026-03-27 21:51:19 -07:00
Enrico Ros ddee08c2da AIX: Gemini: improve wires 2026-03-27 21:51:19 -07:00
Enrico Ros 93b7686f18 AIX: Gemini: Hosted (Server) Tools Notifications 2026-03-27 21:49:15 -07:00
Enrico Ros e61e9626e2 AIX: Reassembler: Fix: PH termination on aix client only iof active 2026-03-27 21:49:15 -07:00
Enrico Ros 3c6bfe0152 BlockPartPlaceholder: (small) ops not on zen 2026-03-27 21:49:14 -07:00
Enrico Ros e4fc44bc9c LLMs: Gemini: sync models 2026-03-27 21:45:50 -07:00
Enrico Ros 51e23ad3a4 Bits 2026-03-27 06:48:36 -07:00
Enrico Ros 5ebbe45a63 BlockPartPlaceholder: improve incomplete 2026-03-27 06:31:06 -07:00
Enrico Ros 6df276d51d DMessage: remove pendingIncomplete on duplication 2026-03-27 06:06:23 -07:00
Enrico Ros f811500b60 AIX: Trace Hosted Operations 2026-03-27 05:42:35 -07:00
Enrico Ros 2b51605c18 ChatFragments: rendering of trees of operations in 'vp' 2026-03-27 05:35:57 -07:00
Enrico Ros 513b840b47 ChatFragments: VoidPlaceholder with alternative presentations - improve a single model op to a list of ops 2026-03-27 05:29:51 -07:00
Enrico Ros d94c8c8a3b AIX: aix-info/aix-retry-reset 2026-03-27 05:11:58 -07:00
Enrico Ros 3dd641a398 AIX: Anthropic: small protocol doc 2026-03-27 05:03:02 -07:00
Enrico Ros 8e545f1738 AIX: OpenAI: protocol bits 2026-03-27 05:00:41 -07:00
Enrico Ros 2a12597567 AIX: OpenAI: parse code execution images 2026-03-27 04:45:54 -07:00
Enrico Ros e003683040 Chat converters: only convert the last VP to E
Other placeholders can stay they're void anyway, however
converting the last allows to signal incomplete in-progress ops
2026-03-27 04:31:25 -07:00
Enrico Ros 0338b3d2e9 AIX: client error: describe Failed to fetch
This happens when for instance Chrome queues up a connection, and while still queued
the WiFi goes off.
2026-03-27 04:20:59 -07:00
Enrico Ros 5d5bc403c4 Wire: cleanup wire print 2026-03-27 04:16:53 -07:00
Enrico Ros b646149980 AIX: misc client.errors notice 2026-03-27 04:16:47 -07:00
Enrico Ros 1e7e8ac632 LLMParametersEditor: improve code-based Antropic web refiner 2026-03-27 04:16:28 -07:00
Enrico Ros 309786e01e ChatDrawerItem: round frequency to 1 decimal, if fractional 2026-03-25 13:39:43 -07:00
Enrico Ros 08e3caf8c2 Logger: ignore defaultPrevented 2026-03-25 03:52:05 -07:00
Enrico Ros 21b68d7660 Update canonic 2026-03-25 00:14:16 -07:00
Enrico Ros 4986c61b2a Composer: remove the alt+enter hint 2026-03-24 22:47:36 -07:00
Enrico Ros 801479cb5c Composer: remove the ctrl+enter hint 2026-03-24 22:45:12 -07:00
Enrico Ros 1d18e21018 CC: update release-open 2026-03-24 22:44:22 -07:00
Enrico Ros 4c329a8f51 AIX: Anthropic: Parser: ignore server-side recovered errors, #1010 2026-03-24 22:10:50 -07:00
Enrico Ros 1eb4eeea42 2.0.4: update readme 2026-03-24 19:17:52 -07:00
Enrico Ros 5ca094111c 2.0.4: update news (removing old beam callout) 2026-03-24 19:16:04 -07:00
Enrico Ros 4ce4202750 2.0.4: update package 2026-03-24 19:03:28 -07:00
Enrico Ros 4873c0c390 Json-ld: OS 2026-03-24 15:33:56 -07:00
Enrico Ros 351a28f34f Json-ld: ALTS 2026-03-24 14:50:55 -07:00
Enrico Ros a2e99ed84f Big-AGI: descs 2026-03-24 13:05:51 -07:00
Enrico Ros 7d2a26ab66 Roll AIX 2026-03-24 12:59:59 -07:00
Enrico Ros 94268187f1 Big-AGI: Capitalize 2026-03-24 12:36:08 -07:00
Enrico Ros 5aafa98f1c README: remove expired link 2026-03-24 12:33:31 -07:00
Enrico Ros c42c34acb4 KB: adding LLM vendors 2026-03-24 11:56:28 -07:00
Enrico Ros f052963da3 Md cleanup 2026-03-24 11:53:01 -07:00
Enrico Ros 07fa93609d CC: allow head|tail 2026-03-24 11:38:29 -07:00
Enrico Ros cbef9e5a57 BlockPartPlaceholder: slight render change 2026-03-23 18:59:10 -07:00
Enrico Ros 0b342339d4 AIX/Fragments: preserve placeholder location 2026-03-23 18:59:06 -07:00
Enrico Ros 9de3d5a26f AIX: Anthropic: parser: bits 2026-03-23 18:58:58 -07:00
Enrico Ros 78878076c2 errorUtils: add convenience fucntion for proper signal abort() 2026-03-23 17:55:06 -07:00
Enrico Ros 65cca958a6 AIX: Transmitter: show dialect 2026-03-23 17:51:59 -07:00
Enrico Ros 19263f8494 AIX: CG Exeuctor: Continuation ephemeral notice. #1010 2026-03-23 17:28:27 -07:00
Enrico Ros 5f71cbed47 AIX: CG Exeuctor: Continuation framework for Anthropic. #1010, #1005 2026-03-23 17:28:27 -07:00
Enrico Ros fe93a66d3b AIX: CG Exeuctor: rename to operation retry signal 2026-03-23 17:27:45 -07:00
Enrico Ros aa3b451e00 AIX: CG Exeuctor: slight rename 2026-03-23 17:27:45 -07:00
Enrico Ros ca245bf8b8 AIX: Retriers: cleanup name 2026-03-23 17:27:45 -07:00
Enrico Ros 9868068cd6 AIX: Anthropic: disable the fix for reusing blocks (seems to have been fixed upstream now) 2026-03-23 17:27:37 -07:00
Enrico Ros 5fd27629d0 idUtils: safer fallback for browser not having the crypto function (shall NEVER happen, but people may deploy on HTTP connections). Fixes #1034 2026-03-23 13:47:29 -07:00
Enrico Ros 4bfc7636c9 Beam: Merge: perform merges discarding the reasoning fragments if the policy says so. Fixes #1042 2026-03-23 13:36:58 -07:00
Enrico Ros 305a7784ee ChatThinkingPolicy: backport. #1042 2026-03-23 13:15:07 -07:00
Enrico Ros 87ecc11661 Allow for 2 Gemini vendors. Fixes #1045 2026-03-23 12:36:12 -07:00
Enrico Ros 0faf5d5957 Roll AIX 2026-03-21 19:51:58 -07:00
Enrico Ros 55d7ebd804 AIX/LLMS: Anthropic: Dynamic Web Filtering 2026-03-21 19:51:30 -07:00
Enrico Ros 842b5b96c2 AIX: Anthropic: parser: cleanup 2026-03-21 18:53:48 -07:00
Enrico Ros b07fc759c2 AIX: Anthropic: wires: update with new API features and tools
- tools allowed callers for client and server
- all tool definitions common options
- new code_execution, web_fetch, web_search tools
- top-level cache_contol
- thinking with disabled summaries for speed
- message updates with container variants
-fix tool_search_tool results
2026-03-21 18:53:48 -07:00
Enrico Ros 0afa70aaab System Theme: partially revert c8a33a06 to keep the default to the light mode 2026-03-21 16:14:32 -07:00
Enrico Ros c2cf93bf1a Events: remove dead code 2026-03-21 16:12:13 -07:00
Enrico Ros 88639b8b57 AttachmentSources: raise popups 2026-03-21 16:12:13 -07:00
Enrico Ros bfecc63d0d CC: allow select eslint tsc 2026-03-21 16:12:13 -07:00
Enrico Ros 20bea327e4 AIX: Anthropic: stremaing FC parser edge case 2026-03-21 16:12:13 -07:00
Enrico Ros 1e5c26b490 AIX: Anthropic: fix double newline elision post start 2026-03-21 16:12:13 -07:00
Enrico Ros d9183c9658 LLMs: xAI: add Grok 4.20 models, including multi-agent 2026-03-21 16:12:13 -07:00
Enrico Ros 3ecbbc3b70 LLMs: OpenAI: sweep align (add images support on select models) 2026-03-21 16:12:13 -07:00
Enrico Ros 1c1d21eed7 Sweep: update OpenAI params (more image supports) 2026-03-21 16:12:13 -07:00
Enrico Ros 6129971bb2 LLMs: OpenAI: add 5.4 mini/nano 2026-03-21 16:12:13 -07:00
Enrico Ros 8a3d75f077 Merge pull request #1033
feat(ui): add system theme mode for dark mode controls
2026-03-21 16:11:56 -07:00
Enrico Ros 9c249b513f Merge pull request #1041 from dLo999/fix/issue-1037-export-filename-local-time
fix: use local time for flash backup export filename (#1037)
2026-03-21 15:48:20 -07:00
Dustin 04d3fe6e99 fix: use local time for flash backup export filename (#1037)
Replace inline toISOString() with prettyTimestampForFilenames(false)
to match the other two export options that already use local time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 08:04:50 -07:00
Enrico Ros ea7283b96e Merge pull request #1028 from enricoros/dependabot/github_actions/actions/download-artifact-8.0.1
chore(deps): bump actions/download-artifact from 8.0.0 to 8.0.1
2026-03-18 22:24:20 -07:00
Enrico Ros 295fc111c4 Expander: update 2026-03-18 02:33:36 -07:00
Enrico Ros 58d73d5d81 ModelsList: show Code designation as well. Fixes #1039 2026-03-17 22:07:43 -07:00
Enrico Ros fd8ce2e99a model.domains.registry: do not include a model name. Fixes #1038 2026-03-17 22:07:43 -07:00
blacksuan19 c8a33a06fa feat(ui): add system theme mode for dark mode controls
- default Joy color scheme to system
- cycle theme control through light, dark, and system modes
- update labels and icons to reflect the active theme preference

Signed-off-by: blacksuan19 <abubakaryagob@gmail.com>
2026-03-15 20:18:51 -05:00
Enrico Ros 874be92a56 ChatDrawer: include current chat, if missing 2026-03-14 16:00:48 -07:00
Enrico Ros 6bdb01e3c5 BlockOpOptions: allow spaces after the bold 2026-03-14 14:47:41 -07:00
dependabot[bot] ba03ab3aa8 chore(deps): bump actions/download-artifact from 8.0.0 to 8.0.1
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3...3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-14 11:32:12 +00:00
Enrico Ros 3d554e513d PostHog: more proper way to disable /flags refresh 2026-03-14 00:14:56 -07:00
Enrico Ros e516b9dae9 PostHog: we don't use Feature Flags - stop them 2026-03-14 00:06:32 -07:00
Enrico Ros 281d5a611e BlockOpOptions: support numbered lists 2026-03-13 14:10:52 -07:00
Enrico Ros 03eec23efe BlockOpOptions: supports bold options 2026-03-13 14:02:31 -07:00
Enrico Ros e3d01f6615 Reverting 61a60c5b: "Markdown: bundle in main chunk instead of lazy-loading" because of bundle size (for now) 2026-03-13 13:49:48 -07:00
Enrico Ros 99e15333cb Roll posthog again 2026-03-13 13:47:07 -07:00
Enrico Ros 5efd16c060 LLMs: LocalAI/Ollama/LMStudio: always allow CSF 2026-03-13 12:58:30 -07:00
Enrico Ros b4a6c80d8c Composer: correct browsing flag 2026-03-13 12:37:31 -07:00
Enrico Ros 7991920f08 Attachments: show disabled 2026-03-13 12:37:17 -07:00
Enrico Ros a113b8223b Roll deps 2026-03-13 12:25:24 -07:00
Enrico Ros 7bb720a903 Beam: Fusion: fix stop/stage 2026-03-13 04:00:55 -07:00
Enrico Ros 515de2679e InlineTextarea: size support 2026-03-13 01:57:59 -07:00
Enrico Ros 38caacf816 Expander component, externally controllable 2026-03-13 00:47:30 -07:00
Enrico Ros 676b0537e6 ChatMessage: chat/words count 2026-03-12 23:15:56 -07:00
Enrico Ros a24341cda6 Sel highlighter: export type 2026-03-12 23:15:54 -07:00
Enrico Ros d937bc246a AppChat: filter by open beam (support) 2026-03-12 21:45:40 -07:00
Enrico Ros 5d2543131a selHighlighter: cut also copies 2026-03-12 21:42:54 -07:00
Enrico Ros ca5d6872b5 clipboardUtils: improve dom copy 2026-03-12 21:42:51 -07:00
Enrico Ros a97ce26072 Replace PhTreeStructure for diagrams 2026-03-12 19:55:29 -07:00
Enrico Ros c698f78f92 FormRadioControl: fix hierarchy 2026-03-12 17:50:56 -07:00
Enrico Ros 77782a63eb Radio Controls: support tooltips 2026-03-12 16:35:56 -07:00
Enrico Ros 41e1e44ef0 TooltipOutlined: support size 2026-03-12 16:35:54 -07:00
Enrico Ros 7b1fc56320 LLMs: Deepseek: misc comment 2026-03-12 15:03:06 -07:00
Enrico Ros c0ed41a529 llms.parameters: find Spec and TS fix 2026-03-12 15:03:06 -07:00
Enrico Ros ba47fe1cfe AttachmentSources: strings again 2026-03-12 04:10:05 -07:00
Enrico Ros f1356d8fdc AttachmentSources: optimize RichMenuItem 2026-03-12 04:10:05 -07:00
Enrico Ros 7a899c538f Sources: bits 2026-03-12 01:28:57 -07:00
Enrico Ros 3daac973b1 AttachmentSources: tooltips on live 2026-03-11 15:17:53 -07:00
Enrico Ros b0ec5f7459 Attachments: add live types 2026-03-10 23:12:36 -07:00
Enrico Ros 71d6868512 AttachmentSources: bits 2026-03-10 23:12:36 -07:00
Enrico Ros 605bb83eb3 Components: add MediaStreamPreview 2026-03-10 23:12:36 -07:00
Enrico Ros 3092e02ce9 DBlobs: allow attachment image on destination scope (rather than moving it later) 2026-03-10 23:12:36 -07:00
Enrico Ros 5d82374975 DBlobs: GC: debug option 2026-03-10 23:12:36 -07:00
Enrico Ros ab4d63e596 screenCaptureUtils: export stream 2026-03-10 17:16:16 -07:00
Enrico Ros f800bb8dae CameraCaptureModal: open with options 2026-03-10 17:16:16 -07:00
Enrico Ros 18862c0ff4 Fragments: set origin Id in place 2026-03-10 11:32:10 -07:00
Enrico Ros 3765e8c69e Fragments: set origin Id 2026-03-10 11:28:58 -07:00
Enrico Ros 70d54a9aa3 Labs: option to skip image compression. Fixes #1024 2026-03-10 01:24:24 -07:00
Enrico Ros 50c6ee69af FormSwitchControl: pass through tooltipWarning 2026-03-10 01:05:49 -07:00
Enrico Ros dd2532e269 AttachmentSources: allow external menu button 2026-03-10 00:42:16 -07:00
Enrico Ros 16a54b3452 Audio: catch low-level errors 2026-03-10 00:08:21 -07:00
Enrico Ros 8373c1c785 AudioPlayer: make them cancelable & renames 2026-03-09 23:37:14 -07:00
Enrico Ros 39beda5519 revert AudioPlayer reason changes 2026-03-09 22:45:10 -07:00
Enrico Ros c7d1eae327 Speex: voice url preview with cancelation 2026-03-09 22:33:57 -07:00
Enrico Ros ec81e2ff5b AudioPlayer: pre-open 2026-03-09 22:33:57 -07:00
Enrico Ros 697090b695 AIX: Reassembler: audio player 2026-03-09 22:13:36 -07:00
Enrico Ros 8680fcc3db Image rendering: view on click 2026-03-09 21:30:59 -07:00
Enrico Ros 233037edd2 RenderImageRefDBlob: only regen if prompt is present 2026-03-09 21:29:38 -07:00
Enrico Ros 81c3251c6e AIX: Gemini: small note 2026-03-09 21:29:35 -07:00
Enrico Ros dc0fe7f4ca Beam Briefinx/Speex: use speakText with the rpc audio hint 2026-03-09 17:08:47 -07:00
Enrico Ros 2c9c0f2e0b Merge pull request #1019 from enricoros/dependabot/github_actions/docker/login-action-4.0.0
chore(deps): bump docker/login-action from 3.7.0 to 4.0.0
2026-03-09 01:20:51 -07:00
Enrico Ros 9c3fb9aadb Merge pull request #1018 from enricoros/dependabot/github_actions/docker/build-push-action-7.0.0
chore(deps): bump docker/build-push-action from 6.19.2 to 7.0.0
2026-03-09 01:20:43 -07:00
Enrico Ros de37ac2c51 Merge pull request #1017 from enricoros/dependabot/github_actions/docker/metadata-action-6.0.0
chore(deps): bump docker/metadata-action from 5.10.0 to 6.0.0
2026-03-09 01:20:35 -07:00
Enrico Ros d6b57702bd Merge pull request #1016 from enricoros/dependabot/github_actions/docker/setup-buildx-action-4.0.0
chore(deps): bump docker/setup-buildx-action from 3.12.0 to 4.0.0
2026-03-09 01:20:25 -07:00
dependabot[bot] d94642c29f chore(deps): bump docker/login-action from 3.7.0 to 4.0.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.7.0 to 4.0.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/c94ce9fb468520275223c153574b00df6fe4bcc9...b45d80f862d83dbcd57f89517bcf500b2ab88fb2)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-07 11:32:35 +00:00
dependabot[bot] 75378ea88f chore(deps): bump docker/build-push-action from 6.19.2 to 7.0.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.19.2 to 7.0.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/10e90e3645eae34f1e60eeb005ba3a3d33f178e8...d08e5c354a6adb9ed34480a06d141179aa583294)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-07 11:32:31 +00:00
dependabot[bot] d539c1369b chore(deps): bump docker/metadata-action from 5.10.0 to 6.0.0
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5.10.0 to 6.0.0.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](https://github.com/docker/metadata-action/compare/c299e40c65443455700f0fdfc63efafe5b349051...030e881283bb7a6894de51c315a6bfe6a94e05cf)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-07 11:32:27 +00:00
dependabot[bot] 555ee6f333 chore(deps): bump docker/setup-buildx-action from 3.12.0 to 4.0.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.12.0 to 4.0.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/8d2750c68a42422c14e847fe6c8ac0403b4cbd6f...4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-07 11:32:23 +00:00
Enrico Ros ad989d8a0b CameraCaptureModal: improve multi-attach 2026-03-06 19:11:50 -08:00
Enrico Ros aae7af4713 useCameraCapture: vastly improve state, flow, remove race conditions, add detach 2026-03-06 17:53:01 -08:00
Enrico Ros df0a204767 CameraCaptureModal: full promised control 2026-03-06 16:36:34 -08:00
Enrico Ros 5cdefc7b5e AttachmentSources: live streams support 2026-03-06 15:04:18 -08:00
Enrico Ros c1bdb1fc61 Merge pull request #1014 from enricoros/claude/issue-1013-20260306-1801
feat: add Ctrl+( / Ctrl+) shortcuts to toggle left drawer and right panel
2026-03-06 10:13:33 -08:00
claude[bot] dde22a080b feat: add Ctrl+( / Ctrl+) shortcuts to toggle left drawer and right panel
Add keyboard shortcuts for toggling left drawer (Ctrl+() and right panel
(Ctrl+)). Also adds a reusable `skipIfInput` flag on ShortcutObject that
skips shortcuts when a text input, textarea, or contenteditable element
(or child thereof) is focused - not applied to these layout shortcuts but
available for future use.

Co-authored-by: Enrico Ros <enricoros@users.noreply.github.com>
2026-03-06 18:05:06 +00:00
Enrico Ros 7f5ff30f97 Speex: unmarkdown 2026-03-05 19:16:54 -08:00
Enrico Ros 38e1708e91 AIX: Gemini: Parser: improve finish reason reporting 2026-03-05 18:36:12 -08:00
Enrico Ros fe4e755304 AIX: Dispatch: nit 2026-03-05 18:36:09 -08:00
Enrico Ros 67f1c87d3a AIX: OpenAI Responses: infer image type 2026-03-05 18:36:09 -08:00
Enrico Ros eef88ffae2 AIX: OpenAI Responses: Queued 2026-03-05 18:36:08 -08:00
Enrico Ros 319965c55c FormChipGroupControl: must stretch 2026-03-05 18:36:05 -08:00
Enrico Ros 1f309b5c81 Speex: future northbridge nav 2026-03-05 16:55:58 -08:00
Enrico Ros 5273352ae9 Speex: Engine: pass labels 2026-03-05 16:45:59 -08:00
Enrico Ros 5a48256d77 AIX: OpenAI: small fixes 2026-03-05 16:45:46 -08:00
Enrico Ros 1d41294c1d LLMs/Sweep: OpenAI GPT-5.4, -Pro, and non-thinking (with temperature control) 2026-03-05 16:27:55 -08:00
Enrico Ros ff76229706 LLMs: Bedrock: respell 2026-03-04 22:13:07 -08:00
Enrico Ros b0f4b30ebe ChipGroupControl: single chip multiple options 2026-03-04 16:31:31 -08:00
Enrico Ros 7be8f6c6a7 OptimaPanelGroupedList: absorb collapsed pad 2026-03-04 16:28:28 -08:00
Enrico Ros b003993961 No mdashes in comments 2026-03-04 14:29:22 -08:00
Enrico Ros 4878f361b5 CLAUDE.md: no emdashes 2026-03-04 14:27:56 -08:00
Enrico Ros a82a3899c5 Beam: strip reasoning traces per user's thinking policy. Fixes #1003 2026-03-04 13:28:05 -08:00
Enrico Ros ff0685e6e8 Nit 2026-03-04 13:19:24 -08:00
Enrico Ros a597489526 Merge pull request #1011 from Blacksuan19/fix-sherpa-ssr
store-logic-sherpa: guard usage count increment against SSR
2026-03-04 13:03:07 -08:00
Enrico Ros 32e8890f62 LLMs: Sync Sweep params 2026-03-04 12:44:50 -08:00
Enrico Ros 211a43eab4 Parameters sweep: 2026-03-04.2 2026-03-04 12:42:10 -08:00
Enrico Ros 8c28df77cc Parameters sweep: resorting 2026-03-04 12:23:22 -08:00
Enrico Ros 4e82a12899 AIX: Gemini: Disable URL Context for Nano Banana models 2026-03-04 12:20:04 -08:00
Enrico Ros 8d0e0dea89 Parameters sweep: 2026-03-04 2026-03-04 12:09:13 -08:00
Enrico Ros 5703f23b99 Roll AIX 2026-03-04 11:37:46 -08:00
Enrico Ros 196d08b4fd CLAUDE.md: try stopping compound 2026-03-04 11:37:38 -08:00
Enrico Ros 2f9738f6fb LLMs: Gemini: Nano Banana 2 (aka 3.1 flash image) and 3.1 Flash-Lite 2026-03-04 11:34:51 -08:00
Enrico Ros d4db225d1e LLMs: OpenAI: remove shut down 2026-03-04 11:30:10 -08:00
Enrico Ros efff785713 LLMs: OpenAI: 5.3 Instant 2026-03-04 11:29:40 -08:00
Enrico Ros 234accad3f LLMs: ANT: Sync retired 2026-03-04 11:15:57 -08:00
blacksuan19 588b4b2c64 store-logic-sherpa: guard usage count increment against SSR
The useLogicSherpaStore.setState() call at module level ran during
server-side rendering where localStorage is unavailable, causing a
hydration crash. Wrap with isBrowser so it only executes in the
browser context.

Signed-off-by: blacksuan19 <abubakaryagob@gmail.com>
2026-03-04 12:49:46 -06:00
Enrico Ros 7de34d8478 InReferenceToBubble: fix h-compression 2026-03-03 23:46:42 -08:00
Enrico Ros 741980adfc Allow new attachments for previous messages in a chat. Fixes #945 2026-03-03 20:18:07 -08:00
Enrico Ros 2690380bfd ChatMessage: support changing attachments in mesages. #945 2026-03-03 18:43:12 -08:00
Enrico Ros b482b07335 Composer: use the standard Attachment hanlders 2026-03-03 18:43:06 -08:00
Enrico Ros 03b4c6f941 Attachments: standard handlers 2026-03-03 18:43:06 -08:00
Enrico Ros b7fd1b13de Remove setLabsEnhanceCodeLiveFile 2026-03-03 10:47:02 -08:00
Enrico Ros 10a6f2d3c7 Rename getLabsHighPerformance 2026-03-03 10:03:21 -08:00
Enrico Ros ba149d3b43 Remove labsEnhanceCodeBlocks - always on now 2026-03-03 10:03:08 -08:00
Enrico Ros f175d071c4 Remove labsShowCosts - always on now 2026-03-03 10:00:16 -08:00
Enrico Ros 874d0bca05 Attachments: by default use the Menu on desktop, not the inlines 2026-03-03 09:53:50 -08:00
Enrico Ros 81ad0328b7 Remove labsAttachScreenCapture/labsCameraDesktop - always on now 2026-03-03 09:53:50 -08:00
Enrico Ros 5198fa66cf Attachments: consolidated/unified menu 2026-03-03 09:53:50 -08:00
Enrico Ros a807bdd6b6 InlineTextArea: remove the alt key - only usage 2026-03-02 21:18:05 -08:00
Enrico Ros 2b209bb679 LLMParametersEditor: improve config. Fixes #1004 2026-03-02 20:04:02 -08:00
Enrico Ros 2f018dce9f AIX: do not set a default fox max anymore - as the underlying APIs may change and it's a user param now. #1004 2026-03-02 20:03:33 -08:00
Enrico Ros 2eb77f532a FormNumberInput: add number|undefined input 2026-03-02 20:03:30 -08:00
Enrico Ros 69063bb544 ExpanderControlledBox - allow compression (issue introduced by f21fe411 on the ChatPanelModelParameters with log model names) 2026-03-02 20:03:30 -08:00
Enrico Ros 7fad2f8790 LLMs/AIX: Parameters: Anthropic: max Fetch/Search depth. #1004 2026-03-02 14:58:46 -08:00
Enrico Ros 620275a1f5 Attachments: move GDrive/Web sources 2026-03-02 14:36:55 -08:00
Enrico Ros ba583fc448 Attachments: move buttons 2026-03-02 14:28:29 -08:00
Enrico Ros 0b96870644 Camera: share and rationalize use 2026-03-02 13:40:25 -08:00
Enrico Ros eb2b682eb5 Attachments: centralize components, make composible 2026-03-02 11:59:52 -08:00
Enrico Ros 577b52120a Update #984 2026-03-01 20:33:07 -08:00
Enrico Ros b69ae3edae Beam: raise max rays to 24, add 16 to presets. Fixes #1001 2026-03-01 20:30:43 -08:00
Enrico Ros 624b177996 Merge pull request #999 from enricoros/dependabot/github_actions/actions/upload-artifact-7.0.0
chore(deps): bump actions/upload-artifact from 6.0.0 to 7.0.0
2026-03-01 20:30:07 -08:00
Enrico Ros bbf01b49c0 Merge pull request #998 from enricoros/dependabot/github_actions/actions/download-artifact-8.0.0
chore(deps): bump actions/download-artifact from 7.0.0 to 8.0.0
2026-03-01 20:29:42 -08:00
Enrico Ros 86b2d8ae71 LLMs: Anthropic PowerPoint -> PPT 2026-03-01 15:41:07 -08:00
dependabot[bot] d18af42d43 chore(deps): bump actions/upload-artifact from 6.0.0 to 7.0.0
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/b7c566a772e6b6bfb58ed0dc250532a479d7789f...bbbca2ddaa5d8feaa63e36b76fdaad77386f024f)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-28 11:32:12 +00:00
dependabot[bot] 4f6e110bf9 chore(deps): bump actions/download-artifact from 7.0.0 to 8.0.0
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7.0.0 to 8.0.0.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/37930b1c2abaa49bbe596cd826c3c89aef350131...70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-28 11:32:08 +00:00
Enrico Ros 62cf334e2f AIX: Z.ai: handle their network errors 2026-02-28 02:12:02 -08:00
Enrico Ros 8bd6fd40fd Focus-mode for mobile 2026-02-28 01:59:16 -08:00
Enrico Ros f21fe41188 ExpanderControlledBox - fix lagging of content vs parent reveal
Instead of clipping on the Collapsee box, we just use it as the FR target
with a minHeight of 0; have the parent take the correct height, and clip all to the parent.
2026-02-28 01:29:08 -08:00
Enrico Ros cfff23164c Claude.md: CSF 2026-02-26 14:12:13 -08:00
Enrico Ros a8d9233dc4 Claude.md: improve in structure 2026-02-26 14:03:54 -08:00
Enrico Ros 9c973efbbf LLMs: Bedrock: support Converse API for Nova models 2026-02-26 03:39:44 -08:00
Enrico Ros e2c4255920 LLMs: Bedrock: hide inputs on prio 2026-02-26 02:52:47 -08:00
Enrico Ros e01b9ff6a9 LLMs: Bedrock: improve sort 2026-02-26 02:52:22 -08:00
Enrico Ros 0084a635f1 AIX: Debugger: fix URL display 2026-02-26 02:18:24 -08:00
Enrico Ros 0cd20b8d48 Update claude.md 2026-02-26 00:13:42 -08:00
Enrico Ros 7c4094b4c2 OpenAI Service config: rename provider when selecting the host 2026-02-25 23:52:44 -08:00
Enrico Ros acd8430d51 Models List: show free only 2026-02-25 23:50:15 -08:00
Enrico Ros 6ae2195d10 LLMs: add LLMAPI via OpenAI-Compatible and custom host. Fixes #993, Fixes #989. 2026-02-25 23:38:43 -08:00
Enrico Ros 6bcc0dd177 LLMs: Bedrock: auto-interfaces frmo model enumeration 2026-02-25 21:27:55 -08:00
Enrico Ros 2de42c2010 AIX/LLMs: Bedrock: support Mantle (OpenAI-compatible) including model enumeration. Fixes #965 2026-02-25 21:11:27 -08:00
Enrico Ros a231ccb492 LLMs: remove IF_OAI_Complete 2026-02-25 18:27:06 -08:00
Enrico Ros 35875d5837 AIX/LLMs: Bedrock: default to us-east-1 2026-02-25 17:13:59 -08:00
Enrico Ros c36ff1edfa AIX/LLMs: Bedrock: support Bedrock Long-term API Keys 2026-02-25 17:13:59 -08:00
Enrico Ros ed35d5b541 tRPC fetchers: improve local debug output 2026-02-25 17:13:59 -08:00
Enrico Ros 2b2a2d84a9 LLMs: Bedrock: report listModels issues up 2026-02-25 17:13:59 -08:00
Enrico Ros a645a4066c docs: bit 2026-02-25 17:13:58 -08:00
Enrico Ros 508a3beff7 CC: patch cd chaining 2026-02-25 14:26:37 -08:00
Enrico Ros df0c133056 AIX: OpenAI: fix return code 2026-02-24 23:25:06 -08:00
Enrico Ros 2da3942ce2 LLMs: OpenAI: Update models 2026-02-24 23:24:32 -08:00
Enrico Ros 26547dec0d Docs: update 2026-02-24 22:56:00 -08:00
Enrico Ros aa4804bdd5 Docs: update for bedrock 2026-02-24 22:46:00 -08:00
Enrico Ros eafa1f02cb AIX: Bedrock: update msg 2026-02-24 21:53:17 -08:00
Enrico Ros 836533a8c2 AIX: Bedrock: update icon 2026-02-24 21:49:30 -08:00
Enrico Ros cfeb134c20 AIX: Bedrock: disclaimer about unsupported functionality 2026-02-24 21:44:01 -08:00
Enrico Ros 35798b5568 AIX: Bedrock: bolster transformer 2026-02-24 21:43:47 -08:00
Enrico Ros 7a250f0848 AIX: Bedrock: chat generate. #965, #170, #980 2026-02-24 21:05:51 -08:00
Enrico Ros 0a4e6d5142 AIX: Anthropic: reuse model to beta 2026-02-24 20:45:22 -08:00
Enrico Ros f4254a5ffb LLMs: Bedrock: list models. #965 2026-02-24 20:35:45 -08:00
Enrico Ros 7b7718e578 LLMs: Anthropic: review headers 2026-02-24 20:35:39 -08:00
Enrico Ros c261b2b156 Bedrock: sigining utility (client and server compatible) 2026-02-24 17:44:24 -08:00
Enrico Ros 237065553e AIX: Anthropic: make beta headers reusable 2026-02-24 17:44:24 -08:00
Enrico Ros 6116af42df AIX: make createChatGenerateDispatch async 2026-02-24 17:44:24 -08:00
Enrico Ros 08b28cfde8 LLMs: IModelVendor: slight csf mention 2026-02-24 17:26:00 -08:00
Enrico Ros b019655518 LLMs: listModels: update dispatch 2026-02-24 17:14:40 -08:00
Enrico Ros 1264a2ebaf Icons: crab svg 2026-02-24 16:32:37 -08:00
Enrico Ros 1960b4f618 Wire: bits 2026-02-24 16:32:14 -08:00
Enrico Ros c75fbd89e6 Shortcuts: new symbols 2026-02-23 22:38:55 -08:00
Enrico Ros 3e67201665 Shortcuts: new modal 2026-02-23 22:34:52 -08:00
Enrico Ros b60e2bae65 LLM Params: bits2 2026-02-23 21:02:31 -08:00
Enrico Ros 19c7fa4285 LLM Params: bits 2026-02-23 20:58:56 -08:00
Enrico Ros f450dd3eac Models List: improve looks, content 2026-02-23 20:58:41 -08:00
Enrico Ros d366cdd542 BlockPartModelAux: render markdown and buttons appear at the end 2026-02-23 20:24:12 -08:00
Enrico Ros c1ba83fddb ViewDocPartModal/RenderCodePanelFrame: fix properties render on mobile (ellipsize) 2026-02-23 20:12:33 -08:00
Enrico Ros 617d6038b1 LLMs: LocalAI: restore n+1 render 2026-02-23 20:08:53 -08:00
Enrico Ros 0abee15c30 LLMs: LocalAI: safer parsing 2026-02-23 19:57:34 -08:00
Enrico Ros 1aa2e68e4a Merge pull request #982 from enricoros/dependabot/github_actions/docker/build-push-action-6.19.2
chore(deps): bump docker/build-push-action from 6.18.0 to 6.19.2
2026-02-23 15:49:53 -08:00
Enrico Ros cd692218ce Bits 2026-02-23 15:00:15 -08:00
Enrico Ros a5b7191185 DEV Mode: fully remove 2026-02-23 15:00:15 -08:00
Enrico Ros 56baba4cae DEV Mode: remove hardcoded leftover 2026-02-23 15:00:15 -08:00
Enrico Ros b696447be4 DEV Mode: graduated streaming 2026-02-23 15:00:15 -08:00
Enrico Ros e1ef2e72d7 ModelsList: Modal Submenus + DC-all config 2026-02-23 15:00:14 -08:00
Enrico Ros e85905e63c AIX Inspector: option to disable streaming for the current session. #980 2026-02-23 15:00:14 -08:00
Enrico Ros c6208a2900 CSF: global DC status 2026-02-23 12:14:04 -08:00
Enrico Ros 01299e4f19 CloseablePopup: workaround to keep the popup 2026-02-23 12:14:04 -08:00
Enrico Ros 1771575641 LLMs: services: type fix 2026-02-23 12:14:03 -08:00
Enrico Ros 88a796fd87 Tools: sweep: sync openai 2026-02-19 19:00:36 -08:00
Enrico Ros e403467d6d LLMs: Gemini 3.1 Pro. Fixes #987 2026-02-19 19:00:06 -08:00
Enrico Ros 1914a2a8a3 Tools: sweep: add sweeps for oai-thinking-depentent-temp 2026-02-18 17:19:37 -08:00
Enrico Ros 683892afef Tools: sweep: disable the no-temperature fix, as by default we don't set it, and it prevents our sweep with it 2026-02-18 17:19:37 -08:00
Enrico Ros 470f8aab70 LLMs: Together updates 2026-02-18 17:19:36 -08:00
Enrico Ros 7a561d6b42 LLMs: OpenPipe updates 2026-02-18 17:19:36 -08:00
Enrico Ros affff0df4a LLMs: Groq updates 2026-02-18 17:19:36 -08:00
Enrico Ros f5a81bdc94 LLMs: Gemini small updates 2026-02-18 17:19:36 -08:00
Enrico Ros 818ed53b53 LLMs: Sweep Alignment 2026-02-18 17:19:36 -08:00
Enrico Ros 12c875f4e3 AIX: OpenAI responses: fix for the older Deep Research models 2026-02-18 17:19:33 -08:00
Enrico Ros 6ff715c0f0 AIX: aixChatGenerateContent_DMessage_FromConversation: classify an errored outcome when the message is interrupted 2026-02-18 17:19:31 -08:00
Enrico Ros c4a89822d8 LLMs: typo 2026-02-18 15:51:18 -08:00
Enrico Ros a8a917f786 Roll AIX 2026-02-18 15:35:44 -08:00
Enrico Ros 3aa9a71a4b LLM Effort: split definition for UI namings with unified backend. #940 2026-02-18 14:55:00 -08:00
Enrico Ros 3758612ed6 LLMs: improve (Registry's) initialValue 2026-02-17 23:49:30 -08:00
Enrico Ros b71a4265f8 LLMs: dissolve requiredFallback 2026-02-17 23:07:55 -08:00
Enrico Ros 870cdb67cf Tools: sweep: update script and results 2026-02-17 22:21:03 -08:00
Enrico Ros 902c9dc3f4 AIX/LLMs: support search disablement client/server correctly 2026-02-17 22:20:59 -08:00
Enrico Ros 0d1db0a360 AIX: OpenAI Responses: remove forcing of no temperature, LLM_IF_HOTFIX_NoTemperature works well 2026-02-17 22:20:44 -08:00
Enrico Ros ddd784f041 LLM Effort: client-side domain check 2026-02-17 20:09:40 -08:00
Enrico Ros 830d45c06d LLM Effort: server-side dev check 2026-02-17 20:09:40 -08:00
Enrico Ros 6e27a31013 LLM Effort: Unified definition. #944, #940 2026-02-17 20:09:40 -08:00
Enrico Ros ed87595e17 LLMs: Anthropic: bit 2026-02-17 19:17:51 -08:00
Enrico Ros da01b59ae3 AIX: Anthropic: Effort is GA - no header needed 2026-02-17 19:17:51 -08:00
Enrico Ros 79046b808b AIX: Gemini: do not use alpha any longer 2026-02-17 19:17:51 -08:00
Enrico Ros 5a71153390 Custom Names: reset with warning. #970 2026-02-17 13:50:17 -08:00
Enrico Ros 94056cdf4b AutoBlocks: #983 option which does not improve things 2026-02-17 13:23:55 -08:00
Enrico Ros 41cb35c6b9 Custom Names: lingering. #970 2026-02-17 12:42:45 -08:00
Enrico Ros e133fc81f6 Custom Names: preserve. #970 2026-02-17 12:16:26 -08:00
Enrico Ros 418c2e496c LLMs: Anthropic: dMessageUtils 2026-02-17 12:01:46 -08:00
Enrico Ros 3690202b38 LLMs: Anthropic: Sonnet 4.6 2026-02-17 11:51:46 -08:00
Enrico Ros f069c2e5ab Fix: safe iteration over navItems.links in mobile nav
Fixes #984
2026-02-17 11:06:44 -08:00
dependabot[bot] 97bf6ca276 chore(deps): bump docker/build-push-action from 6.18.0 to 6.19.2
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.18.0 to 6.19.2.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/263435318d21b8e681c14492fe198d362a7d2c83...10e90e3645eae34f1e60eeb005ba3a3d33f178e8)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 6.19.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-14 11:32:12 +00:00
Enrico Ros a1390b152f CC: .gitignore 2026-02-13 18:55:05 -08:00
Enrico Ros 4e8c7d46f6 Cleanup: remove ems 2026-02-13 18:44:35 -08:00
Enrico Ros 02944d2015 AIX: Add no-op method for setting provider infra label 2026-02-13 18:41:49 -08:00
Enrico Ros 58726f0425 AIX: OpenRouter: provider infra label 2026-02-13 17:30:26 -08:00
Enrico Ros 85f796fb1d AIX: ContentReassembler: note 2026-02-13 16:46:47 -08:00
Enrico Ros 311a9c2bf2 Roll AIX 2026-02-13 15:58:27 -08:00
Enrico Ros 6768917d44 Bits 2026-02-13 15:56:52 -08:00
Enrico Ros 7beb412738 AIX: Report broken messages. #980 2026-02-13 15:56:50 -08:00
Enrico Ros cf724625cc AIX: CSF: emulate tRPC's client-side abort as a response to the abortSignal being fired. #980
This is because the exception gets actually trapped locally in the deeper layers
due to client-side processing, which then created a particle for the abort,
which then is never used because the outer will discard it without notice
2026-02-13 15:56:49 -08:00
Enrico Ros f60b2410dd AIX: do not fake logical ends. #980 2026-02-13 15:56:07 -08:00
Enrico Ros bbdc16b06a LLMs: Together.AI: fix wire parser 2026-02-13 12:11:38 -08:00
Enrico Ros 0fa2d06725 AIX: logging: bits 2026-02-13 12:08:04 -08:00
Enrico Ros 36cdc4b55f AIX: Parser: capitalized STOP reason 2026-02-13 12:04:25 -08:00
Enrico Ros c2b4a50bfa AIX: Retriers: consolidated denylist 2026-02-13 12:02:05 -08:00
Enrico Ros 73f88d4715 AIX: OpenRouter: don't log on empty reasoning 2026-02-13 12:01:52 -08:00
Enrico Ros af919be2ac AIX: store end reason - for further debug. #980 2026-02-12 16:31:41 -08:00
Enrico Ros facffbc6c8 AIX: require clean connection ends. #980 2026-02-12 16:31:41 -08:00
Enrico Ros dd5b7cb8c2 AIX: dispatch: increase debugging vendor-initiated disconnect. #980 2026-02-12 14:12:25 -08:00
Enrico Ros 3dc61109d7 AIX: Server: debug recovered packets 2026-02-12 01:34:10 -08:00
Enrico Ros 9ef84260b0 Z.ai: no bits 2026-02-11 22:09:54 -08:00
Enrico Ros cf2df7d7f9 Z.ai: dMessageUtils 2026-02-11 22:09:27 -08:00
Enrico Ros 16a883526b Z.ai: readme 2026-02-11 17:44:33 -08:00
Enrico Ros 7b66b1a2eb Z.ai: readme 2026-02-11 17:44:22 -08:00
Enrico Ros a4adce5c79 Z.ai: AIX: fix reasoning effort 2026-02-11 17:43:23 -08:00
Enrico Ros 9e4174df53 Z.ai: AIX: fix dispatch 2026-02-11 17:36:04 -08:00
Enrico Ros b5975713a3 Z.ai: OCR does not support WebP 2026-02-11 17:26:23 -08:00
Enrico Ros 0cd04266b7 Z.ai: improve model spec 2026-02-11 17:26:23 -08:00
Enrico Ros 5cbd162454 Z.ai: Reasoning settings support 2026-02-11 17:26:23 -08:00
Enrico Ros bea1600358 AIX: OpenAI ChatCompletions: empty reasoning_content yields to non-empty content 2026-02-11 17:26:22 -08:00
Enrico Ros 6a2e201cf5 Z.ai: discovered + curated models support 2026-02-11 17:26:22 -08:00
Enrico Ros 960551933e Z.ai LLM vendor support
Note: we don't include server-side config anymore starting from this. To stress test the config system.
2026-02-11 17:26:22 -08:00
Enrico Ros 8b38b6416d Z.ai: icon & sprite 2026-02-11 17:26:22 -08:00
Enrico Ros fac4c39f48 Fix copying of message Sources. Fixes #977. Fixes #978. 2026-02-11 13:02:32 -08:00
Enrico Ros 4c930efbf0 Fix GC on Beams with reference collectors. 2026-02-11 12:59:36 -08:00
Enrico Ros 5a2a47cb87 AIX: Anthropic: Fast mode - unsupported message 2026-02-10 13:31:28 -08:00
Enrico Ros 4912a03250 LLMs: Anthropic: Fast mode research preview 2026-02-10 13:22:47 -08:00
Enrico Ros 3b13580613 LLMs: parameter-value-based enum price multipliers 2026-02-10 13:04:05 -08:00
Enrico Ros 95905113ac LLMs: cached isLLMChatFree_cached 2026-02-10 12:17:21 -08:00
Enrico Ros c6b34bb252 LLMs: Parameters: type guard enums 2026-02-10 11:53:31 -08:00
Enrico Ros e5387c2323 AIX: Moonshot: remove empty messages 2026-02-10 11:07:09 -08:00
Enrico Ros d3b4447669 CLAUDE.md: update 2026-02-10 01:51:56 -08:00
Enrico Ros d5c5eac9ec CC: allow git mv 2026-02-10 01:51:56 -08:00
Enrico Ros 49b61495d0 LLMs: Vendor Settings: unbreak hide advanced despite initially in CSF. Fixes #969 2026-02-09 23:30:41 -08:00
Enrico Ros e8298e9d30 workflows: CC: enable auth 2026-02-09 13:41:23 -08:00
Enrico Ros b29681e1f7 workflows: CC: cleanups 2026-02-09 13:30:35 -08:00
Enrico Ros 1e0b9a2f0c workflows: CC: do not trigger triage on assignment 2026-02-09 13:08:45 -08:00
Enrico Ros 442b8e95b1 workflows: CC: lock in the dm 2026-02-09 12:53:10 -08:00
Enrico Ros 27090d9e28 -Spaces 2026-02-09 05:41:55 -08:00
Enrico Ros c37b4fa076 Chat: option to discard all reasoning traces 2026-02-09 04:51:42 -08:00
Enrico Ros 83161bbe98 AIX: Anthropic: Parser: hotfix for 4.6 to elide the double-newline at the beginning when present 2026-02-09 04:50:14 -08:00
Enrico Ros 4b166120e6 AIX: Anthropic: Dispatch: hotFix for 4.6 interleaved reasoning blocks back-to-back 2026-02-09 04:23:28 -08:00
Enrico Ros 04494ac752 AIX: Anthropic: Dispatch: hotFix for empty text blocks produced by 4.6 - incoming from the Anthropic API 2026-02-09 04:23:27 -08:00
Enrico Ros 979809ddb1 AIX: Anthropic: Parser: rename hotFix 2026-02-09 04:23:26 -08:00
Enrico Ros 5d797c3339 AIX: Anthropic: warn if blocks come out of order, now that Anthropic has fixed it 2026-02-09 04:22:35 -08:00
Enrico Ros 2ff74f6b80 Wire: separate debug wire request and response 2026-02-09 04:22:33 -08:00
Enrico Ros 06b1195f9a workflows: CC: triade with workarounds: restore some 2026-02-09 01:48:51 -08:00
Enrico Ros c337b70a42 LLMs: Anthropic: copy 2026-02-09 01:40:11 -08:00
Enrico Ros 5047354892 CC: /code:review-inflight bits 2026-02-09 01:40:11 -08:00
Enrico Ros ce4e405fc6 workflows: CC: r/o triage 2026-02-09 01:40:11 -08:00
Enrico Ros 30c8d66cd1 workflows: CC: update model 2026-02-09 01:38:37 -08:00
Enrico Ros fb5c8aad29 workflows: CC: update dm 2026-02-09 01:38:19 -08:00
Enrico Ros 08d221d00f Attachments: Text: warn if empty 2026-02-08 17:31:40 -08:00
Enrico Ros af918178f6 Attachments: Markdown table conversion issue fallback 2026-02-08 17:31:40 -08:00
Enrico Ros ed19896e3c LLMs: llms.parameters: remove 'as const' 2026-02-08 17:31:39 -08:00
Enrico Ros 47ad135e4b CC: slashcommands: update-models catch-all 2026-02-08 17:27:08 -08:00
Enrico Ros 0eff7825c8 CC: slashcommands: xAI Reponses API sync 2026-02-08 17:27:08 -08:00
Enrico Ros 5c8baee390 CC: /code:review-inflight 2026-02-07 13:46:01 -08:00
Enrico Ros 3f71facb49 CLAUDE.md: update 2026-02-07 13:46:01 -08:00
Enrico Ros eba42cc8f2 CLAUDE.md: dev env 2026-02-07 13:46:01 -08:00
Enrico Ros 53092cee51 CC: allow tsc, eslint 2026-02-07 13:46:01 -08:00
Enrico Ros 4bf621f128 LLMs: OpenAI GPT-5.3-Codex speculative support 2026-02-07 13:42:12 -08:00
Enrico Ros 33505dbb8e LLMs: Anthropic/OpenRouter: align behavior, align UI #962 2026-02-06 22:40:55 -08:00
Enrico Ros c81e1f144f AIX: OpenRouter: protocol bits 2026-02-06 20:56:39 -08:00
Enrico Ros ee788b967b Roll AIX 2026-02-06 20:11:10 -08:00
Enrico Ros 38ac8733f6 AIX: OpenRouter: comment on debug: too risky 2026-02-06 20:10:48 -08:00
Enrico Ros 737a20ee06 AIX: OpenRouter: enable the stricter 'require_parametrs' mode. #948 2026-02-06 20:05:05 -08:00
Enrico Ros 19f48b8001 AIX: OpenRouter: wires for OR debug parameters 2026-02-06 19:51:50 -08:00
Enrico Ros 3471d6b4f5 Roll AIX 2026-02-06 19:30:49 -08:00
Enrico Ros 2dc7ba72b3 AIX/LLMs: bits 2026-02-06 19:30:18 -08:00
Enrico Ros e12279dab0 AIX: Anthropic: show the US inference setting when on 2026-02-06 19:24:04 -08:00
Enrico Ros 2e0c79cb64 LLMs: OpenRouter: also inherit the initial temperature from upstreams 2026-02-06 19:19:33 -08:00
Enrico Ros aa697edb8c AIX: Anthropic: minor API changes 2026-02-06 19:18:54 -08:00
Enrico Ros c72e3c58dd AIX: Anthropic: allow US servers 2026-02-06 19:17:01 -08:00
Enrico Ros 1de30c8bd5 AIX: Anthropic: accomodate some API changes 2026-02-06 18:52:58 -08:00
Enrico Ros 3a8eea6fb7 Roll AIX 2026-02-06 18:37:05 -08:00
Enrico Ros b7fd0bdba7 LLMs: OpenRouter: auto-inherit configurable parameters from Anthropic, Gemini and OpenAI.
Fixes #948: OpenAI-through-OR verbosity is sync'd with OpenAI models.

Fixes #893: Gemini-through-OR parameters are synchronized with Gemini models

Fixes #940: OpenAI-through-OR reasoning effort is synced with OpenAI models and much improved. We will have to still fix #944 for OpenAI levels to be fully sync'd with upstream (in progress)
2026-02-06 18:27:38 -08:00
Enrico Ros 58457cac50 LLMs: OR/Anthropic: support effort and adaptive.
Fixes #962
2026-02-06 18:27:38 -08:00
Enrico Ros 0fbacee7dc LLMs: Anthropic: editable Max effort. #962 2026-02-06 18:27:38 -08:00
Enrico Ros a498f28d14 LLMs: Anthropic: support for max effort. #962 2026-02-06 18:26:07 -08:00
Enrico Ros 5b9c6a2d0e LLMs: Anthropic: support adaptive thinking correctly. #962 2026-02-06 18:26:07 -08:00
Enrico Ros 4c7f50ab98 LLMs: Anthropic: inline thinking budget 2026-02-06 18:26:07 -08:00
Enrico Ros ef03d33bbf LLMs: Anthropic: GA skills 2026-02-06 18:26:07 -08:00
Enrico Ros 22c9fc56c0 LLMs: Opus 4.6: naming 2026-02-06 18:26:07 -08:00
Enrico Ros c952fd734f LLMs: Opus 4.6: remove forcing 2026-02-06 18:26:07 -08:00
Enrico Ros 310e99af23 LLMs: Opus 4.6: sort order, unhide 4.5 2026-02-06 18:26:07 -08:00
Enrico Ros e78446904a Docker: remove broken command directive. Fixes #964 2026-02-06 18:25:24 -08:00
Enrico Ros 760e9d8279 CC: Anthropic: update sources of info 2026-02-06 18:25:24 -08:00
Enrico Ros 61a60c5b9f Markdown: bundle in main chunk instead of lazy-loading 2026-02-06 12:41:41 -08:00
Enrico Ros 3054e1b88d Node 24: add .nvmrc, drop 26 from engines 2026-02-06 12:41:41 -08:00
Enrico Ros 6f4fabf147 Claude Opus 4.6 baseline support 2026-02-05 12:02:21 -08:00
Enrico Ros b0c791a055 Sweep: bits 2026-02-05 03:35:40 -08:00
Enrico Ros 748991249a LLMs: OpenAI: Update tooling availabiltiy across models 2026-02-05 02:36:28 -08:00
Enrico Ros 1aea7122cc Sweep: improve detection of connection issues 2026-02-05 02:35:47 -08:00
Enrico Ros 9a83b428f1 AppBreadcrumbs: auto-ellipsize 2026-02-05 01:21:46 -08:00
Enrico Ros 2cd38bc02b Sweep: update baseline with improved OpenAI chatCompletion values. remove verbosity when the only value is medium (aka, no parameter) 2026-02-05 00:44:48 -08:00
Enrico Ros e586142190 AIX: OpenAI-compatible: ChatCompletions: support verbosity for all (not just openrouter) 2026-02-05 00:07:36 -08:00
Enrico Ros a10d0dcf5d LLMs: auto-inject image output 2026-02-05 00:07:36 -08:00
Enrico Ros 6fdff488a9 Sweep: neutered values 2026-02-05 00:07:36 -08:00
Enrico Ros 8af0d78127 Sweep: adapt to the interfaces like aix.client.ts 2026-02-04 23:07:21 -08:00
Enrico Ros 177686a7fc Sweep: add option to merge models instead of wiping the file 2026-02-04 23:01:40 -08:00
Enrico Ros 09b6e47036 Sweep: fix Responses interface application 2026-02-04 21:14:27 -08:00
Enrico Ros 704187ba3e Models Modal: change visibility 2026-02-04 20:49:39 -08:00
Enrico Ros 4ea8a06503 LLMs: auto-inject web search 2026-02-04 20:49:39 -08:00
Enrico Ros 80fcc7d3e3 Security: client-dominated credential isolation for OpenAI access 2026-02-04 20:09:16 -08:00
Enrico Ros a04c62da6f LLMs: OpenAI: fix verbosity (automated). Fixes #947 2026-02-04 19:57:50 -08:00
Enrico Ros fcb518a050 Security: prevent key exfil 2026-02-04 19:43:09 -08:00
Enrico Ros a222626933 CC: sweep: small note 2026-02-04 19:31:41 -08:00
Enrico Ros a3ceade738 Security: anti-dns-spoofing anthropic 2026-02-04 19:26:57 -08:00
Enrico Ros 51d58223b4 Sweep: more succinct output 2026-02-04 19:12:50 -08:00
Enrico Ros d37a603db2 LLMs: OpenAI: Auto 0-day Responses suport. Fixes e458bca1a. #937 2026-02-04 19:04:13 -08:00
Enrico Ros ea984f3ddf Security: anti-dns-spoofing matching 2026-02-04 18:49:31 -08:00
Enrico Ros a9d3e3dead CC: llms: verify-parameters 2026-02-04 18:49:31 -08:00
Enrico Ros 5499e57205 Tools: sweep: json: fold some sweeps into a 'tools' array 2026-02-04 17:45:50 -08:00
Enrico Ros 6f8ee0247f Tools: sweep: baselines 2026-02-04 17:33:23 -08:00
Enrico Ros 05ee5cc3d1 Tools: sweep: merge id-based parameters 2026-02-04 17:12:36 -08:00
Enrico Ros cb6b569330 Tools: sweep: remove unnecessary configs 2026-02-04 17:05:30 -08:00
Enrico Ros 53073ff109 Tools: sweep: remove opanti summary 2026-02-04 17:05:16 -08:00
Enrico Ros 26d362d7a6 Tools: sweep: partition per-dialect 2026-02-04 16:40:35 -08:00
Enrico Ros 91d99e1a63 Tools: sweep: improvements for Gemini and Anthropic, and to save/load of results 2026-02-04 16:17:19 -08:00
Enrico Ros a20917c971 Tools: sweep: incremental output save 2026-02-04 15:23:00 -08:00
Enrico Ros af9bf9e5b3 Tools: sweep: parallel support 2026-02-04 15:13:39 -08:00
Enrico Ros 46b473b8a0 Tools: sweep: Gemini sweeps. #953 2026-02-04 15:03:31 -08:00
Enrico Ros e2b4028223 Tools: sweep: only select from the predefined sweeps inside the config file, #944, #947, #953 2026-02-04 14:52:09 -08:00
Enrico Ros bac2a31782 Tools: sweep: add opeanai image generation and search tool presence, #944, #947, #953 2026-02-04 14:51:57 -08:00
Enrico Ros 3d20e6bf91 Tools: llm parameter sweep. #944, #947, #953 2026-02-04 14:12:44 -08:00
Enrico Ros 9337216092 tRPC fetchers: console logging on connect/response/parsing can be disabled via env 2026-02-04 14:12:44 -08:00
Enrico Ros cd35d0ca55 Add TSX as a dev dependency 2026-02-04 10:54:44 -08:00
Enrico Ros 6d591b98b8 Roll packages (deep) 2026-02-04 10:53:53 -08:00
Enrico Ros 486381ab9d Sprites: run the gen node native, as module 2026-02-04 10:34:14 -08:00
Enrico Ros c619b4debb ListItemGroupCollapser: sm everywhere 2026-02-04 01:35:55 -08:00
Enrico Ros 383a3085ec Chat Dropdown: adapt Optima Dropdown. #955 2026-02-04 01:03:18 -08:00
Enrico Ros 5a3bb3d817 Chat Dropdown: adapt llmSelect. #955 2026-02-04 01:03:02 -08:00
Enrico Ros d1ba758887 Chat Dropdown: reuse toggleable set and Collapser. #955 2026-02-04 00:55:39 -08:00
Enrico Ros 6fef149997 Sprites: port models-modal 2026-02-03 23:38:50 -08:00
Enrico Ros aad3b16ff2 Sprites: port useLLMSelect, Beam 2026-02-03 23:38:50 -08:00
Enrico Ros 819ba14523 Sprites: Generate and wire 2026-02-03 23:38:50 -08:00
Enrico Ros d3c25ca16a Sprites: update generator with class 2026-02-03 23:38:27 -08:00
Enrico Ros 99a65f72ac Sprites: generator update 2026-02-03 22:35:55 -08:00
Enrico Ros be9080d392 Sprites: generator 2026-02-03 22:35:55 -08:00
Enrico Ros f32d991413 Chat Dropdown: reusable parts. #955 2026-02-03 22:34:12 -08:00
Enrico Ros 94b68ebefa CloseablePopup: memo. #955 2026-02-03 22:33:35 -08:00
Enrico Ros 0450eaaceb CC: rel:release-open 2026-02-03 09:20:11 -08:00
Enrico Ros 408c5ce088 Readme: update counter 2026-02-02 17:13:13 -08:00
Enrico Ros d936629ead 2.0.3: update readme 2026-02-02 15:48:02 -08:00
Enrico Ros 9bd1a66208 2.0.3: update news 2026-02-02 15:43:30 -08:00
Enrico Ros 1a0c029ee8 2.0.3: update package 2026-02-02 15:26:53 -08:00
Enrico Ros e7be228703 Roll AIX 2026-02-02 15:16:57 -08:00
Enrico Ros 0ab4dc972f Dockerfile: suppress CopyIgnoredFile warning for whitelist-style .dockerignore 2026-02-02 15:16:15 -08:00
Enrico Ros 5f1ca8954f Force touch to doubleClick support (disabled) 2026-02-02 15:09:11 -08:00
Enrico Ros 3ec1b033ce BlockEdit_TextFragment: support 'xs' editing. #961 2026-02-02 14:47:56 -08:00
Enrico Ros 0caf27af9b LLMs: skip prod warning for connection errors, they're still shown in the router warnings in dev 2026-02-02 12:55:38 -08:00
Enrico Ros bd67e14fa4 Debug: Wire: off 2026-02-02 12:37:13 -08:00
Enrico Ros 494c3b542c AIX/LLMs: LMStudio: generic conversion 2026-02-02 12:26:36 -08:00
Enrico Ros 8e0884eb64 AIX/LLMs: LMStudio: convert WebP -> JPG instead 2026-02-02 12:21:54 -08:00
Enrico Ros 73c4dc4ac8 AIX/LLMs: support for WebP -> PNG conversion at the hotfix (pre-CGR) stage 2026-02-02 12:18:31 -08:00
Enrico Ros d77274058d LLMs: LMStudio: use native API for detailed model information 2026-02-02 12:07:45 -08:00
Enrico Ros 0c8460419b AIX: ImageContentPart: allow not detail 2026-02-02 11:34:10 -08:00
Enrico Ros eabb589390 AIX: relax error parsing to .error: { message: '..' } 2026-02-02 11:29:52 -08:00
Enrico Ros 62f860ae93 Debug: Wire: clip curl to 4096 inner 2026-02-02 11:26:57 -08:00
Enrico Ros 605aae873c Roll packages with net removal 2026-01-31 16:40:23 -08:00
Enrico Ros 62e9ee5b05 Roll react hook form which shall be even lighter 2026-01-31 16:32:02 -08:00
Enrico Ros d686f5d143 Roll verified changes 2026-01-31 16:26:44 -08:00
Enrico Ros 3922f232ae Roll some types and prettier 2026-01-31 16:22:31 -08:00
Enrico Ros 6735b438d3 Roll Next to fix CVE 2026-01-31 16:15:57 -08:00
Enrico Ros fb1e30ab32 Roll PostHog-node 2026-01-31 16:11:32 -08:00
Enrico Ros 0ec06edb57 Roll PostHog-js 2026-01-31 16:10:21 -08:00
Enrico Ros 2a52673c56 Merge pull request #959 from enricoros/dependabot/github_actions/docker/login-action-3.7.0
chore(deps): bump docker/login-action from 3.6.0 to 3.7.0
2026-01-31 16:09:49 -08:00
Enrico Ros cc20d00d8a Drive picker: improve token handling with expiration 2026-01-31 15:52:24 -08:00
Enrico Ros 3d9201f7dc Drive picker: add a button to close and reset 2026-01-31 15:12:26 -08:00
dependabot[bot] 176732a6c0 chore(deps): bump docker/login-action from 3.6.0 to 3.7.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.6.0 to 3.7.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/5e57cd118135c172c3672efd75eb46360885c0ef...c94ce9fb468520275223c153574b00df6fe4bcc9)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-31 11:32:23 +00:00
Enrico Ros 39815b3af3 CustomMarkdownRenderer: reduce log 2026-01-31 03:13:46 -08:00
Enrico Ros bcce517089 Drive: token provider interface 2026-01-31 03:01:36 -08:00
Enrico Ros a4b50d0d97 OpenAI: Raise instancelimit to 10 2026-01-31 03:01:36 -08:00
Enrico Ros 2a124e7588 Drive: text bits 2026-01-30 20:04:24 -08:00
Enrico Ros a85556ab5b Attach content (docs, images, pdf, etc.) from Google Drive. Fixes #943 2026-01-30 19:18:58 -08:00
Enrico Ros cef93d6084 Attachments: cloud types 2026-01-30 17:00:57 -08:00
Enrico Ros 207e257778 AIX: Demuxers: add recovery of incomplete buffers and server-side logging 2026-01-30 14:23:29 -08:00
Enrico Ros 12203daa22 LLMs: New Heuristic model enumeration for the OpenAI protocol 2026-01-30 12:59:14 -08:00
Enrico Ros 27f8e9248d ModelsList: hidden LLMs get faded chips 2026-01-30 12:42:37 -08:00
Enrico Ros 51384dc984 AIX: remove unused OAI Realtime IF 2026-01-30 12:36:44 -08:00
Enrico Ros bc76cbb5ad Server-side fetchers: opt-in optional headers map 2026-01-30 11:55:18 -08:00
Enrico Ros 5a1ca83f6d Server-side fetchers: debug print headers 2026-01-30 11:50:27 -08:00
Enrico Ros c9f585f808 Server/Client Wire improvement, including listModels 2026-01-30 11:39:35 -08:00
Enrico Ros 9f559e1dbf LLMs: Groq: re-add SDAIA 2026-01-30 11:10:52 -08:00
Enrico Ros e458bca1a7 Revert "LLMs: OpenAI Responses API by default for new models. Fixes #937"
This caused all unknown models to default to the responses API.
We need heuristics for determining OpenAI vs OpenAI-compatible.

This reverts commit a6862d8c58.
2026-01-30 03:09:16 -08:00
Enrico Ros 43d2226019 AIX: Fix LiteLLM breakage 2026-01-30 02:01:21 -08:00
Enrico Ros 122bc34701 AIX: don't retry insufficient balance errors 2026-01-29 23:46:19 -08:00
Enrico Ros e01358e268 LRS: add back mmmu 2026-01-29 23:00:59 -08:00
Enrico Ros 847c84c3e6 LLMs: remove cbaMmmu 2026-01-29 22:39:47 -08:00
Enrico Ros b11cac4328 LLMs: sync CB 2026-01-29 22:31:09 -08:00
Enrico Ros f617b06109 LLMs: copy over initialtemperature if/when available on a per-model basis for 'fromManualMapping' 2026-01-29 22:31:08 -08:00
Enrico Ros 345ccf3369 DLLM/ModelDescription: remove trainigDataCutoff: not used anymore in this day and age 2026-01-29 21:43:03 -08:00
Enrico Ros d111b8af62 LLMs: Update XAI verified 2026-01-29 21:23:43 -08:00
Enrico Ros 8f964c5c49 LLMs: Update OpenPipe 2026-01-29 21:22:34 -08:00
Enrico Ros b6f3f4538f LLMs: Update OpenAI Instant models 2026-01-29 21:22:02 -08:00
Enrico Ros f6dd30d5d8 LLMs: Update Mistral 2026-01-29 21:21:12 -08:00
Enrico Ros af8b79f849 LLMs: Update Groq 2026-01-29 21:20:24 -08:00
Enrico Ros 0cfccc423b LLMs: Update Gemini (deprecations) 2026-01-29 21:17:40 -08:00
Enrico Ros f9a5d582d4 LLMs: Update Ollama 2026-01-29 21:14:25 -08:00
Enrico Ros 684e00d594 Model Services: bits2 2026-01-29 21:08:20 -08:00
Enrico Ros 3cd2df0b50 Model Services: Duplicates removal 2026-01-29 21:01:44 -08:00
Enrico Ros 02197f4ee6 OpenAI: fix sequence number validation - broken by LiteLLM. Fixes #957 2026-01-29 13:49:46 -08:00
Enrico Ros f9049a3fea ModelsWizard: fix build 2026-01-29 13:36:05 -08:00
Enrico Ros 462bddc271 Model Service: Service menu 2026-01-29 13:16:25 -08:00
Enrico Ros f79000cf39 Model Service: 3 dots button 2026-01-29 13:16:25 -08:00
Enrico Ros 1d95273f4d Models Refetch: update icon 2026-01-29 13:16:25 -08:00
Enrico Ros 6c4579f434 LLM Duplication copy 2026-01-29 13:16:25 -08:00
Enrico Ros 4ef56ade21 LLMs: OpenAI: default 5.2 to medium, since we have the no-thinking model too 2026-01-29 13:05:16 -08:00
Enrico Ros 7c1369d6e9 LLM Store: allow for removal/reset service-wide 2026-01-29 13:05:16 -08:00
Enrico Ros 533d54b106 LLM Options: reflect status elsewhere 2026-01-29 12:36:33 -08:00
Enrico Ros cce0ca6560 LLM Options: Clone advanced. #941 2026-01-29 12:36:01 -08:00
Enrico Ros e87ce2593c LLM Options: bits 2026-01-29 12:32:32 -08:00
Enrico Ros 431dc8b667 LLM Temperature: allow for Vendor-set no temperature (future) 2026-01-29 12:32:32 -08:00
Enrico Ros 5caf614bf7 LLM Clones: correctly group services when updating, inserting custom models 2026-01-29 12:32:32 -08:00
Enrico Ros ecf9703570 LLM Clones: User can create clones. #941 2026-01-29 12:32:32 -08:00
Enrico Ros e7641393a0 LLMParametersEditor: fix controlled component 2026-01-29 12:32:31 -08:00
Enrico Ros 2201f6ff5a ModelsList: memo feature chips 2026-01-29 12:31:59 -08:00
Enrico Ros 557e1ce293 Clipboard Content Transform: fix copying of code 2026-01-29 11:10:56 -08:00
Enrico Ros cbe9a6b9a5 LLMOptions: style a bit 2026-01-29 00:36:16 -08:00
Enrico Ros 9bbcb038d4 LLMOptions: launch purpose (not on) 2026-01-29 00:28:28 -08:00
Enrico Ros 3602204420 LLMOptions: add commands 2026-01-28 23:52:10 -08:00
Enrico Ros 6f485e5589 GoodModal: shrink on xs 2026-01-28 23:49:29 -08:00
Enrico Ros 2f46a3dfaf LLM Options: Details/Override 2026-01-28 17:45:39 -08:00
Enrico Ros 267845bba3 LLM Options: LLM actions 2026-01-28 17:21:52 -08:00
Enrico Ros 6f33a8eebf LLMs: improve variants handling across the board. #941 2026-01-28 17:03:59 -08:00
Enrico Ros b0d2b09a2e AIX: Fix show injector 2026-01-28 17:03:58 -08:00
Enrico Ros c699b6b16b OpenAI: add a no-thinking variant for GPT-5.2, which allows to change temperature. #941 2026-01-28 17:03:58 -08:00
Enrico Ros 1789bac28d Roll AIX 2026-01-28 03:21:30 -08:00
Enrico Ros 60c05f615f AIX Debugger: unfiler 2026-01-28 03:02:12 -08:00
Enrico Ros bd84523671 LLMs: Gemini: removed models 2026-01-28 02:48:58 -08:00
Enrico Ros eb21b9c770 Speex: open config if closed 2026-01-28 02:42:24 -08:00
Enrico Ros ff3ac11afb LLMParametersEditor: survive undefined temperature 2026-01-28 02:23:39 -08:00
Enrico Ros 1ef8c3d02b LLMs: Gemini: temperature defaults to 1.0 and can be changed 2026-01-28 02:01:55 -08:00
Enrico Ros 2ebaf6279b AIX: Injector: works well 2026-01-28 01:42:50 -08:00
Enrico Ros a5ee40e184 Speex: fix build 2026-01-28 01:15:56 -08:00
Enrico Ros b17a97eac7 AIX: request body injection. #953 2026-01-28 01:09:32 -08:00
Enrico Ros 63908bfaf6 Speex: update README 2026-01-27 23:53:27 -08:00
Enrico Ros 3f9a419a19 Speex: +Inworld Config 2026-01-27 23:50:33 -08:00
Enrico Ros bae691e33e Speex: +Inworld 2026-01-27 23:50:33 -08:00
Enrico Ros 91539346ee Speex: Fix #624 2026-01-27 22:08:39 -08:00
Enrico Ros 4842ca81b3 Speex: Cancellable preview 2026-01-27 22:08:38 -08:00
Enrico Ros 9c77a1a4ab Speex: Chunk test: remove button 2026-01-27 22:08:36 -08:00
Enrico Ros 4af284be42 Speex: prevent voice/engine mismatch 2026-01-27 22:08:15 -08:00
Enrico Ros 6aec68bb3c Speex: fix unlimited chunking 2026-01-27 22:08:15 -08:00
Enrico Ros d4e2b0834f Speex: allow inner calls, for bytes access 2026-01-27 20:23:10 -08:00
Enrico Ros 24c2702f96 Speex: ghost key to 'tts' for remembering the pass 2026-01-27 20:18:05 -08:00
Enrico Ros 4691fc9bad Speex: pre-wrap errors 2026-01-27 20:17:58 -08:00
Enrico Ros 8c6c60b6f1 Speex: fix webspeech voice selection 2026-01-27 20:17:02 -08:00
Enrico Ros bc482407fe Speex: overhaul for chunking and future synchroniciy / controllability 2026-01-27 20:11:49 -08:00
Enrico Ros ff05593db8 AudioAutoPlayer: handler for any streaming or full-file play, with stop and await ending 2026-01-27 20:11:49 -08:00
Enrico Ros 3d304d9374 AudioLivePlayer: extra safety 2026-01-27 20:11:49 -08:00
Enrico Ros 1734f0c2f1 AudioLivePlayer: extra safety, if stop was called already, waitForPlaybackEnd would return immediately 2026-01-27 19:38:48 -08:00
Enrico Ros 1b25e5df85 AudioLivePlayer: anti-leak the objectUrl and resolve wait on stop 2026-01-27 19:38:48 -08:00
Enrico Ros ea8eb32b0b AudioLivePlayer: await until done 2026-01-27 19:38:48 -08:00
Enrico Ros 614a1f95de AudioPlayer: improve straight play function 2026-01-27 19:38:48 -08:00
Enrico Ros d36bc28914 blobUtils: combine arrayBuffers 2026-01-27 19:38:48 -08:00
Enrico Ros deec48d7c1 CC: enable gh issues list 2026-01-27 19:38:48 -08:00
Enrico Ros b318ec8d39 Merge pull request #951 from jayrepo/patch-3
Add middleware.ts to docker image
2026-01-26 23:11:08 -08:00
Jay Chen b4b0e2befc Update .dockerignore 2026-01-27 14:22:22 +08:00
Enrico Ros 51d3fe13da Roll AIX 2026-01-26 19:51:41 -08:00
Enrico Ros 58220216d3 LLMs/AIX: support for Kimi Thinking On/Off 2026-01-26 19:43:06 -08:00
Enrico Ros cac75cca42 LLMs: Detail Kimi-K2.5 2026-01-26 19:24:09 -08:00
Enrico Ros 47f247907f LLMs: Add Kimi-K2.5 2026-01-26 18:57:50 -08:00
Enrico Ros 81e04b7322 ChatDrawer: buckets: fewer splits, more stability 2026-01-25 19:39:05 -08:00
Enrico Ros 56a964b700 AIX debugger: highlight non-conversation frames 2026-01-25 19:37:44 -08:00
Enrico Ros 458341d79f AIX debugger: don't auto-advance frame for support operations 2026-01-25 19:37:43 -08:00
Enrico Ros d1d212b075 Copy: intercept to others too 2026-01-24 20:24:52 -08:00
Enrico Ros 59c9996489 LLM Params update: TS improvements 2026-01-24 19:33:25 -08:00
Enrico Ros bf8221a2f1 LLM Params update: MDS with int (not float) 2026-01-24 19:33:25 -08:00
Enrico Ros 787a11a040 LLM Params system: Improve types definition 2026-01-24 19:33:25 -08:00
Enrico Ros 05d114be2f Copy: redo visual copy and copy interception (Ctrl+c, etc) for Plain text and HTML 2026-01-24 19:33:25 -08:00
Enrico Ros 3c04a7dbac Copy: also disable copy of collapsed Expanders 2026-01-24 19:33:25 -08:00
Enrico Ros 1673e1148d Copy: annotate what to Not copy 2026-01-24 19:33:25 -08:00
Enrico Ros de416b035d Copy: remove overlay copy button on the message 2026-01-24 19:33:25 -08:00
Enrico Ros 08aaf2989d Beam: always show model selector for Custom fusion 2026-01-24 15:49:54 -08:00
Enrico Ros a50964060c Stop ResizeObserver issue notifications 2026-01-24 15:41:41 -08:00
Enrico Ros 54b6108719 Beam: hide Merge Model selector for Custom fusion 2026-01-24 15:32:58 -08:00
Enrico Ros 585e5c254a Roll AIX 2026-01-23 11:42:32 -08:00
Enrico Ros 477808c9bb AIX: OAI Responses: allow 'failed' on web_search_call 2026-01-23 11:42:22 -08:00
Enrico Ros 6c58a2b688 AIX: OAI Responses: allow 'failed' on web_search_call 2026-01-23 11:42:10 -08:00
Enrico Ros c9854bf30f LLMs: OpenAI: partial Reasoning Effort updates. #944 2026-01-23 11:28:03 -08:00
Enrico Ros cfed4bbd41 LLMs: OpenAI: remove restore markdown on GPT-5 models 2026-01-23 11:20:53 -08:00
Enrico Ros 2dd6485b0e LLMParametersEditor: align to XAI X search default off 2026-01-23 11:19:32 -08:00
Enrico Ros bf1dd5b860 LLMs: Toggle code execution in Params Editor only (not quick) 2026-01-23 10:52:32 -08:00
Enrico Ros 765c373f7d LLMs: OAI: allow code execution 2026-01-23 10:52:32 -08:00
Enrico Ros 32d752e82b LLMs: OAI Responses: (unused) parameter for OpenAI code execution 2026-01-23 10:35:58 -08:00
Enrico Ros 4623e438fa AIX: OAI Responses: code interpreter Hosted tool def 2026-01-23 10:35:08 -08:00
Enrico Ros 8a44ff396f AIX: XAI: relax annotation title presence 2026-01-23 10:16:59 -08:00
Enrico Ros 086d7ecae4 Speex: TTS character limit settings. Fixes #942 2026-01-23 10:05:35 -08:00
Enrico Ros d6adebb711 Attachment buttons: full name in tooltip. Fixes #946 2026-01-23 09:55:29 -08:00
Enrico Ros 8325fe7b3c Roll AIX 2026-01-23 09:29:41 -08:00
Enrico Ros 7cf83f878b AIX: XAI: Response API Request + wiretypes. Fixes #938 2026-01-23 04:29:13 -08:00
Enrico Ros 597ba26424 AIX: Code Executor wires 2026-01-23 04:29:06 -08:00
Enrico Ros 7bccea47f5 AIX: OpenAI Responses: parse Code Execution and Custom Tools 2026-01-23 04:29:06 -08:00
Enrico Ros 5770116779 DMessage: Code Executor 2026-01-23 04:29:06 -08:00
Enrico Ros 0679144f69 LLMs/AIX: XAI new parametrization 2026-01-23 04:29:05 -08:00
Enrico Ros c9fd288b52 AIX: OpenAI chatCompletions: remove obsolete X search params 2026-01-23 04:16:52 -08:00
Enrico Ros 9ae449fcfd LLMs: type check server params against the client params def 2026-01-23 00:46:07 -08:00
Enrico Ros 249f67f796 AIX: improve dispatch messaging validation for 4 protocols 2026-01-23 00:46:07 -08:00
Enrico Ros e91c0bb554 AIX: stripUndefined 2026-01-23 00:28:05 -08:00
Enrico Ros 5e306d9598 AIX: XAI: models update 2026-01-23 00:25:33 -08:00
Enrico Ros 42ebc81cbb AIX: XAI: models update 2026-01-22 23:56:11 -08:00
Enrico Ros f624c37db5 AIX: XAI: models update 2026-01-22 17:51:03 -08:00
Enrico Ros 22b6f42936 AIX: OAI: Responses wiretypes changes 2026-01-22 17:25:54 -08:00
Enrico Ros 760c66cac8 Attachments: reposition menu to see the tokens bar 2026-01-22 17:18:08 -08:00
Enrico Ros 1d91e9da03 Attachments: client-side Markdown conversion and Text/HTML cleanup & Markdown conversion 2026-01-22 17:17:57 -08:00
Enrico Ros 7eac409ec6 AIX: XAI: model removal 2026-01-22 13:54:36 -08:00
Enrico Ros 128558420c AIX: XAI: model validation 2026-01-22 13:54:17 -08:00
Enrico Ros ca3e664690 AIX: spill part type cleanup 2026-01-22 13:12:29 -08:00
Enrico Ros 7eb37462d7 LLMs: update ollama models 2026-01-22 03:06:17 -08:00
Enrico Ros 31e02c2d39 CC: slashcommands: update llms:ollama 2026-01-22 03:02:55 -08:00
Enrico Ros 003a68b9b8 CustomMarkdownRenderer.tsx: allow for <br/> tags inside Table Cells. Fixes #939 2026-01-22 02:14:42 -08:00
Enrico Ros f418708389 AIX: Inspector: improve render 2026-01-22 01:55:14 -08:00
Enrico Ros d23a564035 AIX: Inspector: reassembler 'transport' data and ui 2026-01-22 01:45:20 -08:00
Enrico Ros 7fe586244c AIX: Inspector: debugger object client sync 2026-01-22 01:38:33 -08:00
Enrico Ros f1a597cdc6 AIX: move Inspector frames selector 2026-01-22 01:36:54 -08:00
Enrico Ros 9b68c8f58c CC: slashcommands: update llms:ollama 2026-01-22 01:06:11 -08:00
Enrico Ros be5b57ea71 LLMs: shared model definition validators 2026-01-22 00:54:00 -08:00
Enrico Ros 425c82f26d CC: slashcommands: improve parsing of ollama models 2026-01-22 00:08:07 -08:00
Enrico Ros 942421c1fb LLMs: together: fix key validation 2026-01-21 23:52:15 -08:00
Enrico Ros b1184f6928 AIX: CSF: also support client-side exceptions 2026-01-21 23:39:10 -08:00
Enrico Ros ffeb6d1b98 LLMs: models bits 2026-01-21 23:34:31 -08:00
Enrico Ros b2718b56b7 CC: shashcommands: improve kimi 2026-01-21 23:16:57 -08:00
Enrico Ros 455f834957 CC: allow llms:update 2026-01-21 23:05:56 -08:00
Enrico Ros 8a14c80ff8 CC: slashcommands: llms:groq update 2026-01-21 23:04:09 -08:00
Enrico Ros e268e733c7 LLMs: Groq: overlap check 2026-01-21 23:03:29 -08:00
Enrico Ros 8933a8dfb3 LLMs: Gemini: deprecations 2026-01-21 22:53:15 -08:00
Enrico Ros 9796cc525c LLMs: xAI verified 2026-01-21 22:37:11 -08:00
Enrico Ros cdbf9a9190 Speex: CSF support - auto-detected from linked services - client-unbundled-dynamic 2026-01-21 18:38:43 -08:00
Enrico Ros c26792292d Speex: extract rpc common core 2026-01-21 18:14:03 -08:00
Enrico Ros 4698e0ee03 LLMs: OpenAI: remove /v1/ from the user input, to immedialy give feedback on the correct way of doing it 2026-01-21 16:58:57 -08:00
Enrico Ros 68afcb2f4b AIX: OpenAI: disable reasoning summaries when disabling Streaming as well. Fixes #932 2026-01-21 16:52:36 -08:00
Enrico Ros e8f61e46e3 AIX: Fetchers: don't retry on 'request too large' 2026-01-21 16:22:50 -08:00
Enrico Ros 317bb2b7c8 useLLMSelect: preserve scrolling on cat toggle 2026-01-21 16:00:43 -08:00
Enrico Ros d1b3c6b468 ContentFragments: improve zero state add text look. #934 2026-01-21 16:00:42 -08:00
Enrico Ros b35eccc984 AIX: increase resilience to new values across 3 parsers. Fixes #918
Note: relaxed throws on Anthropic and Gemini (all throws), while on OAI-Responses we are raising to throws in dev.
2026-01-21 15:08:17 -08:00
Enrico Ros a780c92047 AIX: speculative support for keepalives on chatCompletions API. Fixes #918 2026-01-21 14:36:40 -08:00
Enrico Ros 5fc65698ba Collapsible Model Groups, #936 2026-01-21 14:10:30 -08:00
Enrico Ros c923b5ec4c Restyle llm select model groups #936 2026-01-21 13:36:43 -08:00
Enrico Ros 609b2b9a7b Group models correctly by service in Beam drop down list. Fixes #936 2026-01-21 13:36:31 -08:00
Enrico Ros a257278004 dMessageUtils: OSB 2026-01-21 13:15:26 -08:00
Enrico Ros 273daed634 Chat Messages: label heuristic to ignore the vendor-N- 2026-01-21 13:13:49 -08:00
Enrico Ros a6862d8c58 LLMs: OpenAI Responses API by default for new models. Fixes #937 2026-01-21 13:07:58 -08:00
Enrico Ros 323e5b4ea7 LLMs: OpenAI OSB speculative support 2026-01-21 13:06:47 -08:00
Enrico Ros 89217a5308 CC: allow gh issue view 2026-01-21 13:03:05 -08:00
Enrico Ros a45e995d2f AIX: OpenRouter: improve reasoning through OpenAI-completions across models. Fixes #893 2026-01-20 11:32:11 -08:00
Enrico Ros 8700b4c8ca Roll AIX 2026-01-20 02:07:55 -08:00
Enrico Ros 1f7f5fb488 Data (personas): more concise default 2026-01-20 01:43:45 -08:00
Enrico Ros afde8ee864 LLMs: OpenRouter: 'verbosity' support for OpenAI gpt-5 models, and Anthropic Claude Opus 4.5 (remapped to reasoning effort by OpenRouter). Fixes #927 2026-01-20 01:42:54 -08:00
Enrico Ros 3884c26b15 LLMs: OpenAI: Reviewed 5.1 Instant / 5.2 Params support. Closes #930 2026-01-20 01:21:45 -08:00
Enrico Ros 24dce7eae9 LLMs: further improve the LLMParametersEditor's sync with the dialog. #926 2026-01-20 01:09:04 -08:00
Enrico Ros 1db4e9b771 LLMs: Anthropic: Fix Effort in the LLM Options Dialog. Fixes #926 2026-01-20 00:31:39 -08:00
Enrico Ros b2ed7eae00 CC: CMDs: llms:align-params-uis 2026-01-20 00:31:39 -08:00
Enrico Ros 3169fd67e8 LLMs: OpenRouter: fix Antrhopic thinking models. Fixes #925 2026-01-20 00:15:00 -08:00
Enrico Ros 773ceb1396 Tools: data/llm: remove obsolete registry 2026-01-19 23:40:56 -08:00
Enrico Ros 8c62ee1720 LLMs/AIX: fully remove moderation
Doesn't seem to be used anymore by anyone, nor was active in the code
2026-01-19 23:32:15 -08:00
Enrico Ros 5fa1f52922 LLMs: openai service setup: bits 2026-01-19 23:09:20 -08:00
Enrico Ros d2180c010c LLMs: Helicone: start unformize 2026-01-19 22:42:16 -08:00
Enrico Ros b73df7b2ce LLMs: OpenAI: Autocomplete + suggest hosts for Chutes, Fireworks, Novita. #921 2026-01-19 22:42:16 -08:00
Enrico Ros 971f737846 LLMs: support Novita.ai models with capability auto-detection. #921 2026-01-19 22:39:32 -08:00
Enrico Ros a393353907 LLMs: Azure: rename custom field 2026-01-19 22:39:32 -08:00
Enrico Ros 751f609554 LLMs: OpenAI: unify paths 2026-01-19 22:39:31 -08:00
Enrico Ros e8cd5c6552 LLMs: Ant: unify paths 2026-01-19 22:39:31 -08:00
Enrico Ros 86e387b270 LLMs: allow OpenAI/Azure OpenAI services renaming. Fixes #922 2026-01-19 15:54:13 -08:00
Enrico Ros 32f15aa621 FormTextField: allow for end decorator 2026-01-19 15:54:13 -08:00
Enrico Ros bfc889a9e5 LLMs: fix reset of non-declared params at models update. Fixes #924 2026-01-19 14:53:46 -08:00
Enrico Ros bd907625a8 UpDate 2026-01-15 17:48:00 -08:00
Enrico Ros 60004926d7 Recommend DC (CSF) for Local services 2026-01-15 16:28:00 -08:00
Enrico Ros ac751dfd1a Roll AIX 2026-01-14 16:42:06 -08:00
Enrico Ros 6828eee17f LLMs: Perplexity: sync 2026-01-14 16:40:01 -08:00
Enrico Ros 19c97f397b LLMs: OpenAI: sync a GPT Audio model 2026-01-14 16:38:32 -08:00
Enrico Ros 0167a8bdd8 LLMs: Mistral: update 2026-01-14 16:36:31 -08:00
Enrico Ros 93e5044603 LLMs: Groq: strings 2026-01-14 16:36:19 -08:00
Enrico Ros 024d930677 LLMs: Gemini: small update 2026-01-14 16:35:22 -08:00
Enrico Ros 98873446a8 LLMs: Ollama: update tags 2026-01-14 16:35:15 -08:00
Enrico Ros 5318b7a406 OCR: cache tesseract's import 2026-01-14 16:30:57 -08:00
Enrico Ros 4a6c3cbcd2 Roll AIX 2026-01-14 15:41:58 -08:00
Enrico Ros ac0a39c202 LLMs: OpenAI: GPT-5.2 Codex support 2026-01-14 15:40:40 -08:00
Enrico Ros 88d39345a5 Attachments: PDF: add a PDF->OCR (via interim images) and an 'Auto' (default)
The Auto mode tries plain Text, then Text to Images to OCR, then falls back to pure images.
2026-01-14 15:09:40 -08:00
Enrico Ros 7aa9cb07b2 OCR: extract util functions 2026-01-14 13:18:44 -08:00
Enrico Ros ef30c8d28d Tesseract: roll package 2026-01-14 13:17:11 -08:00
Enrico Ros 2727f690b4 Attachments: PDFs: use Density to attach images 2026-01-14 10:59:43 -08:00
Enrico Ros 5945c24301 Speex: RPC: fallback to full buffer play if streaming is unavailable (Firefox) 2026-01-14 10:32:41 -08:00
Enrico Ros 7b6aff1f95 AudioLivePlayer: Firefix doesn't support MPEG streaming 2026-01-14 10:32:39 -08:00
Enrico Ros cb0fe3aadd AIX: OpenAI Responses: support for keepalive packets 2026-01-13 19:39:47 -08:00
Enrico Ros 4f9d69f9c2 AIX: Anthropic: Fix for out-of-order block start. Fixes #917 2026-01-12 16:40:16 -08:00
Enrico Ros c18aeabe06 CC: changelog cmd update 2026-01-12 04:18:02 -08:00
Enrico Ros 550742323a CC: changelog cmd 2026-01-12 04:02:17 -08:00
Enrico Ros c71f789a08 Draw PromptComposer: fix for CJK 2026-01-12 03:44:00 -08:00
Enrico Ros a9b4b195bf Extend #916 to InlineTextArea and editing of a Text Fragment 2026-01-12 03:37:02 -08:00
Enrico Ros 52e8177f42 Simplify #916 2026-01-12 03:36:33 -08:00
Enrico Ros b0743efc48 Merge branch 'fork/tantanorange/feat/bug-Input-Method-Editor' 2026-01-12 03:30:25 -08:00
Enrico Ros 6dfd652dac LLMParametersEditor: shrink label 2026-01-12 03:23:42 -08:00
Enrico Ros 3f93cb2e6d Phone: work over an empty conversation id 2026-01-12 03:11:49 -08:00
Enrico Ros 8f7b9b7f19 Optima Page Heading: support disabled 2026-01-12 02:10:38 -08:00
Enrico Ros abff89ab6b CC: ignore temp files 2026-01-12 02:10:20 -08:00
tantanorange d4f03f743a bug(issue-784): fixed 'Enter' trigger unexpected Chat under Iput Method Editor. 2026-01-11 18:32:55 -08:00
Enrico Ros c3714f6651 Camera Capture: darker 2026-01-10 15:20:30 -08:00
Enrico Ros 9b4d0ddf2f Merge pull request #913 from enricoros/dependabot/github_actions/actions/download-artifact-7.0.0
chore(deps): bump actions/download-artifact from 4.3.0 to 7.0.0
2026-01-10 14:46:32 -08:00
Enrico Ros 2c9ac2f549 Merge pull request #914 from enricoros/dependabot/github_actions/actions/upload-artifact-6.0.0
chore(deps): bump actions/upload-artifact from 4.6.2 to 6.0.0
2026-01-10 14:46:20 -08:00
dependabot[bot] c1292de2a0 chore(deps): bump actions/upload-artifact from 4.6.2 to 6.0.0
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 6.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...b7c566a772e6b6bfb58ed0dc250532a479d7789f)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-10 11:54:05 +00:00
dependabot[bot] 21d5e4cd29 chore(deps): bump actions/download-artifact from 4.3.0 to 7.0.0
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.3.0 to 7.0.0.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/d3f86a106a0bac45b974a628896c90dbdf5c8093...37930b1c2abaa49bbe596cd826c3c89aef350131)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-10 11:54:01 +00:00
Enrico Ros a9495a3e15 Roll eslint 2026-01-09 19:47:24 -08:00
Enrico Ros bff5b3d765 Roll posthog 2026-01-09 19:46:49 -08:00
Enrico Ros a4ff37eecc Roll safe packages 2026-01-09 19:40:14 -08:00
Enrico Ros 460209f486 GH Actions: fix manifest format 2026-01-09 17:36:28 -08:00
Enrico Ros 96c68c86a4 GH Actions: fix tag case 2026-01-09 17:16:22 -08:00
Enrico Ros 8b152fdff8 GH Actions: improve parallelism of the docker image build 2026-01-09 17:10:53 -08:00
Enrico Ros 25c9a52873 Dependabot: basic configuration 2026-01-09 16:40:28 -08:00
Enrico Ros 44302d903c CC Actions: checkout v6 2026-01-09 16:24:31 -08:00
Enrico Ros c7b8668609 GH Actions: docker-image: pin versions 2026-01-09 14:36:28 -08:00
Enrico Ros 7d60df6266 Docker: save 0.5GB 2026-01-09 14:27:04 -08:00
Enrico Ros b7f898a5e5 Docker: move to Node 24 and cleanup. #907 2026-01-09 13:55:02 -08:00
Enrico Ros 04c4dbe4b8 Docker: remove compose version 2026-01-09 13:53:31 -08:00
Enrico Ros 8d04c494df Docker: negate .dockerignore 2026-01-09 13:53:31 -08:00
Enrico Ros a6aadf76f3 Revert "Fix Node 25 build..." - breaks other Node versions.
This reverts commit b70d57d878.
2026-01-09 13:53:30 -08:00
Enrico Ros a685ef97bf AIX: chatGenerate executor: object-string-ellipsize when replaying input (received from the llm) 2026-01-09 13:36:06 -08:00
Enrico Ros d46c29689f AIX: OpenRouter: support image generation through OpenAI's OR-extended API, including supporting advanced Gemini params. Fixes #906 2026-01-09 13:36:06 -08:00
Enrico Ros 65ce07395b Fix drag-to-update on mobile 2026-01-09 13:36:06 -08:00
Enrico Ros cc1542fe95 Wire: improve debug print with object-ellipsize-strings 2026-01-09 13:36:06 -08:00
Enrico Ros b70d57d878 Fix Node 25 build, by using --no-webstorage with node - otherwise Zustand's persist middleware will break the build 2026-01-09 10:45:50 -08:00
Enrico Ros 5aa857362b Merge pull request #912 from enricoros/claude/issue-909-20260109-1034
feat(deepseek): add API Host field to DeepSeek settings
2026-01-09 02:42:29 -08:00
Enrico Ros c92fc34051 Merge pull request #911 from enricoros/claude/issue-902-20251229-1701
docs: remove Midori AI Subsystem section from installation guide
2026-01-09 02:39:46 -08:00
claude[bot] b01e66f12a feat(deepseek): add API Host field to DeepSeek settings
Add the ability for users to configure a custom API host for DeepSeek,
allowing them to use alternative endpoints like https://api.deepseek.com/beta.

Changes:
- Add `deepseekHost` to DDeepseekServiceSettings interface
- Wire deepseekHost to oaiHost in transport layer
- Add API Host form field visible in advanced settings

Closes #909

Co-authored-by: Enrico Ros <enricoros@users.noreply.github.com>
2026-01-09 10:38:11 +00:00
Enrico Ros a88d20784a Roll AIX 2026-01-09 02:27:54 -08:00
Enrico Ros 63486ed6cf LLMs/AIX: support 4 levels for Gemini 3 Flash. Fixes #905 2026-01-09 02:27:53 -08:00
Enrico Ros 3ceec773f2 LLMs: DeepSeek: remove 3.2 Speciale 2026-01-09 02:08:54 -08:00
Enrico Ros 817fa56ec4 LLMs: Anthropic: remove Claude 3 Opus 2026-01-09 02:05:33 -08:00
Enrico Ros 088fb21a90 LLMs: Gemini: update cache pricing 2026-01-09 01:55:53 -08:00
Enrico Ros 79c755a469 Wire: ellipsize AixDemuxers.DemuxedEvents 2026-01-09 01:31:39 -08:00
Enrico Ros a091d3f011 OpenAI: support for gpt-image-1.5 2026-01-09 01:22:26 -08:00
Enrico Ros c7c01a5d7c AIX: Gemini: sync API: FC with multimodal responses, validated FC-Config, retrieval config, multiple voices, seed, responseId 2026-01-09 01:03:29 -08:00
Enrico Ros cdc0f48973 AIX: Gemini: support MISSING_THOUGHT_SIGNATURE 2026-01-09 00:46:10 -08:00
Enrico Ros e884f6b962 LLMs: Gemini: mark Deep Research Pro Preview as hidden for now - Interactions API coming 2026-01-08 20:46:15 -08:00
Enrico Ros 485a9bea71 LLMs: Gemini: remove removed models 2026-01-08 20:44:57 -08:00
Enrico Ros f3c3b667ca LLMs: OpenAI: remove chatgpt-image from llms 2026-01-08 17:51:58 -08:00
Enrico Ros 3b0c4f31b6 LLMs: Gemini: add 3-flash-preview 2026-01-08 17:47:06 -08:00
Enrico Ros 5e54600766 Deps: set peers 2026-01-08 17:43:41 -08:00
claude[bot] c3e54f69b7 docs: remove Midori AI Subsystem section from installation guide
The Midori AI Subsystem is being sunset as announced in issue #902.
This removes the deployment section from the installation documentation.

Closes #902

Co-authored-by: Enrico Ros <enricoros@users.noreply.github.com>
2025-12-29 17:02:49 +00:00
Enrico Ros c4022d1c9b Roll small 2025-12-20 21:53:18 +01:00
Enrico Ros 6e13a78a24 Roll next 2025-12-20 21:40:15 +01:00
Enrico Ros c7cacd9727 LLMs: Gemini: remove 'medium' thinking level support - too early. Fixes #900 2025-12-20 21:08:41 +01:00
Enrico Ros a77110f704 LLMs: remove parameters set to a former enum value if then removed 2025-12-20 21:07:38 +01:00
Enrico Ros 83a6069de5 CC: update workflows 2025-12-14 03:45:26 +01:00
Enrico Ros e9a1890e54 Beam: rays/fusions can edit, delete 2025-12-11 23:50:06 +01:00
Enrico Ros bf928aa06e AIX: 'searching' item state with 5.2 Pro 2025-12-11 20:38:54 +01:00
Enrico Ros b2dc50590c LLMs: OpenAI GPT 5.2 Pro: enable web search 2025-12-11 20:33:53 +01:00
Enrico Ros 229e53ac32 Roll AIX 2025-12-11 20:20:26 +01:00
Enrico Ros 51e8a47615 OpenAI: Support X-Hight reasoning modes for 5.2-class models 2025-12-11 20:19:57 +01:00
Enrico Ros e80b58a412 UI: support 52 / 52Pro X-High/None reasoning efforts 2025-12-11 20:19:37 +01:00
Enrico Ros 48ced8b079 LLMs: support 52 / 52Pro X-High/None reasoning efforts 2025-12-11 20:19:30 +01:00
Enrico Ros c07e2aea1e AIX: support 52 / 52Pro X-High/None reasoning efforts 2025-12-11 20:19:19 +01:00
Enrico Ros f3194aa30e LLMs: Add GPT 5.2 2025-12-11 19:30:23 +01:00
Enrico Ros cb3e4cd951 LLMs: Mistral: update models 2025-12-09 13:33:01 -08:00
Enrico Ros f5d8d029ea CC: update workflows 2025-12-08 16:54:27 -08:00
Enrico Ros 7c946c4126 CC: add cherry-pick 2025-12-07 12:12:30 -08:00
Enrico Ros ded4ea0d69 Personas: disable YouTube transcript (unsupported API) 2025-12-07 12:10:27 -08:00
Enrico Ros c180c549fe BYOM: improve message 2025-12-07 11:53:49 -08:00
Enrico Ros 1f30f1168f Friction: Model Wizard: also warn if some keys are not saved 2025-12-07 11:52:51 -08:00
Enrico Ros 9446f15922 Friction: better remember Wizard model data 2025-12-07 11:51:35 -08:00
Enrico Ros e13b2c9cd9 Tutorial: 'BYOM' message 2025-12-07 11:49:18 -08:00
Enrico Ros e9e14e0292 LLMs: OpenRouter: add to the wizard 2025-12-07 11:46:04 -08:00
Enrico Ros added19656 Roll posthogs 2025-12-05 19:37:01 -08:00
Enrico Ros 4fa3c4d479 Remove old material (wrong) path 2025-12-05 19:32:34 -08:00
Enrico Ros 690738de9a Fix CVE-2025-55182 2025-12-05 18:41:13 -08:00
Enrico Ros cb31d27e68 Copy: strip background/colors on copy (keep font size and structure) 2025-12-05 11:17:17 -08:00
Enrico Ros e6658df123 Attachment: show dl issues on console 2025-12-05 11:15:15 -08:00
Enrico Ros 0b7154a14c LLMs: OpenAI: remove obsoleted models 2025-12-04 15:52:42 -08:00
Enrico Ros 02c1838de5 LLMs: OpenAI: add gpt-5.1-codex-max 2025-12-04 15:52:18 -08:00
Enrico Ros fc455fceb8 LLMs: Mistral: rmeove obsoleted models 2025-12-02 07:56:29 -08:00
Enrico Ros 8d40cdd234 LLMs: Mistral: sort 2025-12-02 07:53:15 -08:00
Enrico Ros 40145c669a LLMs: Mistral: add Mistral-Large and Ministral 2025-12-02 07:53:09 -08:00
Enrico Ros 34d2fc233f LLMs: Mistral: adapt wires 2025-12-02 07:52:55 -08:00
Enrico Ros 670ec0381a Speex: collapse configure - recollapse with shift 2025-12-01 09:11:48 -08:00
Enrico Ros 2128f255fe Speex: collapse configure when not used 2025-12-01 09:09:50 -08:00
Enrico Ros b717bd9a9a Settings: max-height to not jump around too much 2025-12-01 08:58:20 -08:00
Enrico Ros 8aab9311f5 Roll AIX 2025-12-01 08:33:32 -08:00
Enrico Ros ff3e16ea67 DeepSeek: still images are not supported 2025-12-01 08:30:16 -08:00
Enrico Ros 1de039c315 AIX: OpenAI ChatCompletion: remove multipart hotfix (not needed anymore) 2025-12-01 08:27:55 -08:00
Enrico Ros d05e1786d7 Model namings: speciale 2025-12-01 08:16:44 -08:00
Enrico Ros e34b5a7372 AIX: support Deepseek Speciale 2025-12-01 08:16:29 -08:00
Enrico Ros a1b3d1b508 DeepSeek: 3.2 and Speciale 2025-12-01 08:16:18 -08:00
Enrico Ros 1ebccdf420 Speex: Readmes 2025-12-01 02:59:56 -08:00
Enrico Ros e5f674509c 2.0.2 News 2025-11-30 16:54:56 -08:00
Enrico Ros 197a4ae5c0 2.0.2 Package 2025-11-30 16:53:25 -08:00
Enrico Ros 64d2dcf39c AudioLivePlayer: tryfix for the persistent android notification 2025-11-30 15:05:17 -08:00
Enrico Ros caf54c736b Speex: do not stop the playback too early 2025-11-30 14:31:43 -08:00
Enrico Ros 423c2cce28 speakText: port to Speex 2025-11-30 12:51:55 -08:00
Enrico Ros a1af51efcb Call: port to Speex 2025-11-30 06:55:51 -08:00
Enrico Ros ffc1bf9c58 Remove src/modules/elevenlabs 2025-11-30 06:55:51 -08:00
Enrico Ros a54bfdb342 Settings: port to Speex 2025-11-30 06:55:51 -08:00
Enrico Ros 03861d2dbd Speex: map instead of array 2025-11-30 06:38:14 -08:00
Enrico Ros 8c080da6bf Speex: Autoconfig WebSpeech best 2025-11-30 06:38:14 -08:00
Enrico Ros a8c98056b6 Speex: Config UI Done 2025-11-30 06:38:14 -08:00
Enrico Ros 78e663f955 Speex: important fixes 2025-11-30 06:38:14 -08:00
Enrico Ros 70546a5039 Speex: Almost Done 2025-11-30 06:38:14 -08:00
Enrico Ros 30f78b33cb Speex: diable Azure 2025-11-30 06:38:14 -08:00
Enrico Ros 712e8c1f16 Speex: UI update: Selects and Persona Voice changer 2025-11-30 06:38:14 -08:00
Enrico Ros 933dfdfb53 Speex: improve types 2025-11-30 06:38:14 -08:00
Enrico Ros 9ce86b029f Speex: UI settings modal 2025-11-30 06:38:14 -08:00
Enrico Ros 13580cc69d Speex: UI config improvements 2025-11-30 06:38:14 -08:00
Enrico Ros a7dee0002d Speex: debug instrumentation 2025-11-30 06:38:14 -08:00
Enrico Ros c84b2df3fa Speex: fix elevenlabs 2025-11-30 06:38:14 -08:00
Enrico Ros d9471a8684 Speex: fix types 2025-11-30 06:38:14 -08:00
Enrico Ros ef630c2272 Speex: improve UI and errors 2025-11-30 06:38:14 -08:00
Enrico Ros e188c71652 Speex: RPC: shared downstreaming 2025-11-30 06:38:14 -08:00
Enrico Ros 910260c2c8 Speex: UI: credentials edit and add new 2025-11-30 06:38:14 -08:00
Enrico Ros 22752abc38 Speex: relax engine validation 2025-11-30 06:38:14 -08:00
Enrico Ros 92bc3a5d64 Speex: DVoice -> wire_Voice 2025-11-30 06:38:14 -08:00
Enrico Ros 1383752cc1 Speex: reduce logging 2025-11-30 06:38:13 -08:00
Enrico Ros 66af16fb81 Speex: manual refactor 2025-11-30 06:38:13 -08:00
Enrico Ros fc019d7b46 Speex: client cleanups 2025-11-30 06:38:13 -08:00
Enrico Ros ac4f0fcb12 Speex: LocalAI: Preview 2025-11-30 06:38:13 -08:00
Enrico Ros a6c2bc663d Speex: arrange files 2025-11-30 06:38:13 -08:00
Enrico Ros e62ffa02e9 Speex: LocalAI vendor 2025-11-30 06:38:13 -08:00
Enrico Ros a003600839 Speex: some UI 2025-11-30 06:38:13 -08:00
Enrico Ros ea73feb06d Speex: remove elevenlabs, with key migration 2025-11-30 06:38:13 -08:00
Enrico Ros 3bdf69e1b7 Speex: ui: begin 2025-11-30 06:38:13 -08:00
Enrico Ros 590fe78bd1 Speex: client cleanup 2025-11-30 06:38:13 -08:00
Enrico Ros 76187ba0e7 Speex: rpc backend 2025-11-30 06:38:13 -08:00
Enrico Ros 5eba375f4d Speex: add webspeech (with detection) and synthesize-openai 2025-11-30 06:38:13 -08:00
Enrico Ros 8fa6a8251f Speex: vendors, engine store, client, router, skel-synthesize 2025-11-30 06:38:13 -08:00
Enrico Ros 75fa046f30 Speex: centralize capability 2025-11-30 06:38:13 -08:00
Enrico Ros 08a8cd1430 Speex: Types & Client 2025-11-30 06:38:13 -08:00
Enrico Ros 3afbb78a39 Icons: port to PhVoice 2025-11-30 06:38:12 -08:00
Enrico Ros fca6ccd816 Badge: transparent BG to not overlap text. Fixes #889 2025-11-29 14:52:13 -08:00
Enrico Ros 8d351822c1 Niy 2025-11-29 13:25:36 -08:00
Enrico Ros 7d274a31fe AIX: CGR: use shared objectUtils 2025-11-29 12:40:04 -08:00
Enrico Ros e36dde0d25 objectUtils: estimate JSON size, deep clone with string limit, find largestStringPaths 2025-11-29 12:17:28 -08:00
Enrico Ros 51cc6e5ae5 CSF: only show the option for server-side (not client-side) disconnect 2025-11-29 11:12:30 -08:00
Enrico Ros 28d911c617 ElevenLabsIcon: add icon 2025-11-28 05:49:33 -08:00
Enrico Ros b1e9fe58fb objectUtils: add stripUndefined 2025-11-28 04:23:11 -08:00
Enrico Ros 16ba014ade GoodBadge: for 'new' 2025-11-28 04:23:11 -08:00
Enrico Ros e9d5a20c1a FormTextField: support inputSx 2025-11-28 04:23:11 -08:00
Enrico Ros 6e0036f9c4 FormSecretField: crystal clear keys input 2025-11-28 04:23:11 -08:00
Enrico Ros d7e189aa1c FormSliderControl: allow sliderSx 2025-11-28 04:23:11 -08:00
Enrico Ros ea2b444fb2 FormChipControl: alignEnd 2025-11-28 04:23:11 -08:00
Enrico Ros cd1efaf26e FormChipControl: support descriptions 2025-11-28 04:23:11 -08:00
Enrico Ros e47f0e5d43 LanguageSelect: imrove select 2025-11-28 04:23:11 -08:00
Enrico Ros 5284d37984 AudioLivePlayer: ignore a closure error 2025-11-28 04:23:11 -08:00
Enrico Ros 1bf6fa0e4d Browse service: improve error reporting 2025-11-27 19:12:08 -08:00
Enrico Ros fc294c82f1 Pdfjs: lock to 5.4.54
more recent 5.4 have trouble with await import('pdfjs-dist'), throwing.
2025-11-27 18:33:20 -08:00
Enrico Ros 7b1dc49dda Roll pdfjs 2025-11-27 18:19:51 -08:00
Enrico Ros d15ddeea24 Roll react-player 2025-11-27 18:15:19 -08:00
Enrico Ros eaac213859 Ph: add Voice 2025-11-27 18:07:54 -08:00
Enrico Ros 02c1460351 Roll posthog 2025-11-27 18:04:06 -08:00
Enrico Ros 2fff35b7d9 Roll superjson 2025-11-27 18:03:37 -08:00
Enrico Ros c5b9072bde LLMs: LocalAI publish interface 2025-11-26 19:01:44 -08:00
Enrico Ros 8a570e912a CSF: docs 2025-11-26 07:37:56 -08:00
Enrico Ros 1dcc40afb8 CSF: Propagate everywhere 2025-11-26 07:37:09 -08:00
Enrico Ros c2092f8035 BlockPartError: vendor name 2025-11-26 06:50:11 -08:00
Enrico Ros 886c4b411e Revert "Test Edge on node"
This reverts commit 8888fd40cd.
2025-11-26 06:13:28 -08:00
Enrico Ros 8888fd40cd Test Edge on node 2025-11-26 04:56:26 -08:00
Enrico Ros 31cd01bccf BlockPartError: CSF enabled 2025-11-26 04:42:50 -08:00
Enrico Ros c59b221004 BlockPartError: allow retrying disconnected errors too 2025-11-26 04:27:52 -08:00
Enrico Ros cb3cc3e74c PostHog: disable the info level 2025-11-26 04:05:03 -08:00
Enrico Ros 9e90015fcc PostHog: disable the info level 2025-11-26 03:56:55 -08:00
Enrico Ros 95e0517056 60s - disable any maxDuration 2025-11-26 03:56:25 -08:00
Enrico Ros 2b2f47915f AIX: OpenAI: Fix CSF! 2025-11-26 03:11:12 -08:00
Enrico Ros 9acd178ce1 AudioPlayer: safe end of stream 2025-11-26 03:11:08 -08:00
Enrico Ros f381f80184 AIX: Anthropic: add strict to tool defs on wiretypes 2025-11-24 16:44:13 -08:00
Enrico Ros c83be61343 AIX: Anthropic: newlines for text broken by tool calls 2025-11-24 16:05:44 -08:00
Enrico Ros f6e49d31ec PWA-Desktop detect. Fixes #887 2025-11-24 15:48:50 -08:00
Enrico Ros cc0429a362 Update readme 2025-11-24 15:14:49 -08:00
Enrico Ros b35901d94c 2.0.1 Roll AIX 2025-11-24 15:06:39 -08:00
Enrico Ros c0df1a23f4 2.0.1 Update news 2025-11-24 15:05:40 -08:00
Enrico Ros 495619af2c LLMs: Interfaces fix 2025-11-24 15:00:09 -08:00
Enrico Ros 72dfadf106 AIX: Anthropic: auto-header for programmatic tool calling (calling from code, not just llm) 2025-11-24 14:58:34 -08:00
Enrico Ros 5825909e45 AIX: Anthropic: programmatic tool calling support 2025-11-24 14:42:20 -08:00
Enrico Ros d3f6d87ee0 AIX: remove legacy unconstrained 'json mode' 2025-11-24 14:29:36 -08:00
Enrico Ros c4f4c5ddad AIX: cross-vendor json output | strict tool invocation 2025-11-24 14:23:25 -08:00
Enrico Ros 2921d7ca27 Anthropic: Structured Outputs | Strict Tools 2025-11-24 13:59:20 -08:00
Enrico Ros 2021cbc988 Anthropic: MessageDeltaUsage 2025-11-24 13:58:57 -08:00
Enrico Ros e9e29861b2 Anthropic: cleanup models 2025-11-24 13:21:25 -08:00
Enrico Ros 8e6da36059 LLM interface types - relax for bw comp 2025-11-24 13:21:13 -08:00
Enrico Ros 5e1469e12e Anthropic: Tool Search Tool 2025-11-24 13:20:58 -08:00
Enrico Ros bd7465f8b1 Roll packages 2025-11-24 12:34:52 -08:00
Enrico Ros 570397a616 Anthropic: add Effort parameter 2025-11-24 12:34:39 -08:00
Enrico Ros b3b5f1daef Anthropic: raise default thinking to 16384 2025-11-24 12:13:50 -08:00
Enrico Ros 25ec3ae47c Anthropic: add Opus 4.5 2025-11-24 12:09:41 -08:00
Enrico Ros 5ba5e3da58 2.0.1 Roll AIX, news 2025-11-24 04:11:39 -08:00
Enrico Ros 9296c14ca0 2.0.1 News 2025-11-24 04:11:39 -08:00
Enrico Ros 310b5d3422 2.0.1 Package 2025-11-24 03:57:17 -08:00
Enrico Ros 1c5967112e Rolled posthog as there's still no local min 2025-11-24 03:19:08 -08:00
Enrico Ros 49a3d8ee71 Roll deep 2025-11-24 03:14:58 -08:00
Enrico Ros cf8b61e8d9 Packages: locked dexie 2025-11-24 03:11:26 -08:00
Enrico Ros 967ae5723e Roll posthog - next.config.ts fix 2025-11-24 02:39:28 -08:00
Enrico Ros 03421acf2f Roll posthog - security fix (details below)
https://helixguard.ai/blog/malicious-sha1hulud-2025-11-24
2025-11-24 02:39:15 -08:00
Enrico Ros d43896cc5a Package: cmd to fix sharp on win32/x64 2025-11-24 02:33:50 -08:00
Enrico Ros b283124a2f Roll packages 2025-11-24 02:05:37 -08:00
Enrico Ros 8c39be01f8 Roll packages 2025-11-24 02:04:23 -08:00
Enrico Ros fb2bd4ccd8 Error Hints: nit 2025-11-23 23:34:36 -08:00
Enrico Ros 5b826ffc45 Error Hints: control AI Service advanced setup 2025-11-23 23:26:56 -08:00
Enrico Ros 0b2ab365d3 Error Hints: Render Reconnect 2025-11-23 23:26:56 -08:00
Enrico Ros 93fc54992c Error Hints: AIX Client and Reassembler -> Fragment 2025-11-23 23:26:56 -08:00
Enrico Ros 60b7326deb Error Hints: Fragments 2025-11-23 23:26:56 -08:00
Enrico Ros d6e6139244 AIX: Gemini: change log 2025-11-23 23:26:56 -08:00
Enrico Ros 0892911ddc Next config: conditional strict mode 2025-11-23 23:26:56 -08:00
Enrico Ros 30267ac50c LLMs: Nano Banana message names 2025-11-23 23:16:43 -08:00
Enrico Ros ffef0ef31d PWA detect. Fixes #887 2025-11-23 23:15:56 -08:00
Enrico Ros fc047087ce CSF: direct connect actions hook 2025-11-23 23:15:03 -08:00
Enrico Ros 81d4966535 CSF: improve vendors 2025-11-23 20:02:06 -08:00
Enrico Ros 004d63fda1 FormRadioControl: gap 1 2025-11-23 16:23:35 -08:00
Enrico Ros 23e2dbb354 tRPC fetchers: increase error message to 240 2025-11-23 16:19:25 -08:00
Enrico Ros 28e9899b97 Settings: looks 2025-11-23 16:19:22 -08:00
Enrico Ros 7441d41550 FormRadioControl: descriptions 2025-11-23 16:19:11 -08:00
Enrico Ros 99e2d5597a LLMs: CSF: OpenAI 2025-11-23 02:56:08 -08:00
Enrico Ros 74321a44ca LLMs: Client-side .listModels 2025-11-23 02:46:28 -08:00
Enrico Ros 7b664affb7 AIX: Client-side .chatGenerate 2025-11-23 02:46:28 -08:00
Enrico Ros c411835f3b LLMs: listModels dispatch: cleanup 2025-11-23 02:36:08 -08:00
Enrico Ros 7b62c946a5 LLMs: Vendors: type the access 2025-11-23 02:35:59 -08:00
Enrico Ros 252e2fcd29 LLMs: Access extraction rewires 2025-11-23 02:28:38 -08:00
Enrico Ros aa2731bccc LLMs: Access extraction 2025-11-23 02:28:38 -08:00
Enrico Ros 282c439963 LLMs: CSF: UI configs 2025-11-23 02:28:38 -08:00
Enrico Ros e99459aba0 LLMs: CSF: vendors 2025-11-23 02:28:38 -08:00
Enrico Ros 4c35cbbe34 LLMs: CSF: access 2025-11-23 02:28:38 -08:00
Enrico Ros cab3537ae2 CSF: activate stubs 2025-11-23 02:28:38 -08:00
Enrico Ros c3f211389b AIX: edgeProcedure rename 2025-11-23 02:28:38 -08:00
Enrico Ros a4de84a842 AIX: dispatch: extract debugger / move security 2025-11-23 02:28:38 -08:00
Enrico Ros 2bf1eaaa0f Partially remove app.config 2025-11-23 01:57:29 -08:00
Enrico Ros 7f5ddd1629 Client stubs: env with log 2025-11-23 01:35:12 -08:00
Enrico Ros ed798fec65 Client stubs: PostHog 2025-11-22 19:09:38 -08:00
Enrico Ros 90386f5794 Client stubs: Env 2025-11-22 19:09:36 -08:00
Enrico Ros 8ada8811bf Build/Env: remove superfluous function 2025-11-22 19:09:33 -08:00
Enrico Ros b24badabef Revert "PostHog: server-client-safe import"
This reverts commit 2c8b713ff3.
2025-11-22 18:58:21 -08:00
Enrico Ros 4e20cb12cd Env: server-only naming 2025-11-22 16:38:05 -08:00
Enrico Ros 245da9e6cc App: server-client-safe vercel import 2025-11-22 16:30:36 -08:00
Enrico Ros a800b34aa7 App: prioritize posthog 2025-11-22 16:30:36 -08:00
Enrico Ros 50c3941f42 Posthog: client: cleanup 2025-11-22 16:30:36 -08:00
Enrico Ros 6e5d5ee36c Posthog: server: exceptions: trpc change 2025-11-22 16:25:50 -08:00
Enrico Ros 2c8b713ff3 PostHog: server-client-safe import 2025-11-22 16:06:00 -08:00
Enrico Ros 8162a6706d PostHog: server: add templates 2025-11-22 16:06:00 -08:00
Enrico Ros 952f6883fa PostHog: server: exceptions 2025-11-22 16:06:00 -08:00
Enrico Ros 373f3e3698 PostHog: server: cleanups 2025-11-22 16:06:00 -08:00
Enrico Ros 17791f631f AIX: extract consts for client-side bundles 2025-11-22 16:06:00 -08:00
Enrico Ros 6987c67cc7 AIX: Images: further resize the last generated image - can be very large, so >0.5M we resize 2025-11-21 03:11:08 -08:00
Enrico Ros 65a59e5d2d Blocks: Reasoning: mx 1.5 2025-11-21 01:58:34 -08:00
Enrico Ros 05b9a6d412 AIX: OpenAI: avoid prefixing with [summary] the reasoning 2025-11-21 01:41:16 -08:00
Enrico Ros 6608f4f164 AIX: Gemini: collapse empty text in between reasoning 2025-11-21 01:40:52 -08:00
Enrico Ros 93378ad6b0 VoidFragments -> ContentFragments 2025-11-21 01:19:23 -08:00
Enrico Ros bd4a60203e In-order rendering: transfer aux 2025-11-21 00:52:23 -08:00
Enrico Ros c9e6a62641 Fragments: Aux: add delete aux 2025-11-21 00:35:08 -08:00
Enrico Ros 68d797fa99 Fragments: Aux: show reasoning progress (assumed, not in the Aux fragment) and disable the 'realize' button while incomplete 2025-11-21 00:35:05 -08:00
Enrico Ros 08011d8cf2 ChatMessage: fix Void Fragment to text 2025-11-21 00:34:43 -08:00
Enrico Ros 2f91bf7f52 In-order rendering: cleanups 2025-11-21 00:27:52 -08:00
Enrico Ros d5182c05c1 In-order rendering of parts 2025-11-20 23:09:29 -08:00
Enrico Ros 8e0947a833 AIX: GG Transmitter: also faster body size estimation 2025-11-20 22:56:15 -08:00
Enrico Ros 1d88fc37b0 AIX: GG Transmitter: smaller echo request 2025-11-20 20:22:43 -08:00
Enrico Ros 46bd8e6f4d AIX debugger: wrap 2025-11-20 20:22:43 -08:00
Enrico Ros b95b427331 AIX debugger: unbreak layout 2025-11-20 20:22:43 -08:00
Enrico Ros 9b574c60eb Roll AIX 2025-11-20 19:52:32 -08:00
Enrico Ros a8b39cc0a4 LLMs: Gemini: support image size 2025-11-20 19:51:51 -08:00
Enrico Ros cdbc7dd9b8 AIX: Gemini: parse and recreate thought signatures 2025-11-20 19:11:42 -08:00
Enrico Ros 08dfec4fcf AIX: expend parts to include per-part vendor opaque information 2025-11-20 19:11:42 -08:00
Enrico Ros 7f4553225b AIX: transfer/reassemble per-fragment opaque vendor data 2025-11-20 19:11:42 -08:00
Enrico Ros f37e65a91e DMessageFragments: per-fragment vendor-specific 2025-11-20 19:11:42 -08:00
Enrico Ros c022f8a68c LLMs: improve params editing 2025-11-20 19:11:42 -08:00
Enrico Ros daa7a506a5 AIX: Gemini: include thoughts when thinking is requested 2025-11-20 19:11:42 -08:00
Enrico Ros f3dcf39c15 LLMs: Gemini: update cba 2025-11-20 17:01:39 -08:00
Enrico Ros 06cbef16d4 LLMs: Gemini: add Nano Banana Pro
LLMs: Gemini: show thoughts
2025-11-20 17:01:39 -08:00
Enrico Ros ab31bcd3e3 LLMs: Gemini: remove obsolete 2025-11-20 17:01:39 -08:00
Enrico Ros 563a99864f LLMs: showThoughts: default to false 2025-11-20 17:01:39 -08:00
Enrico Ros 39b8abc2c6 Fix: LLMs: cleanup stale userParameters 2025-11-20 17:01:39 -08:00
Enrico Ros f3dd837076 AIX: Gemini: UrlContext (fetching website) not supported by Nano Bananas 2025-11-20 17:01:39 -08:00
Enrico Ros d6b3a5259d fix eslint warnings 2025-11-20 17:01:39 -08:00
Enrico Ros 9fea1d5c64 LLMs: xAI: add Grok 4.1 Fast 2025-11-19 16:24:46 -08:00
Enrico Ros 0adb5355c7 Debug Wire: mark sessions 2025-11-19 15:44:13 -08:00
Enrico Ros 01d807b61e Browsing: allow time for screenshot 2025-11-19 15:44:10 -08:00
Enrico Ros 285bb812d0 LocalAI: fix list and virtualize 2025-11-19 14:43:56 -08:00
Enrico Ros d897155d6e LocalAI: fix gallery parsing 2025-11-19 14:43:53 -08:00
Enrico Ros 7154426279 packages: add react-virtual 2025-11-19 14:43:50 -08:00
Enrico Ros 4526084e4d roll packages 2025-11-19 12:20:18 -08:00
Enrico Ros 0c5c786ae3 Beam: starring selects 2025-11-19 12:14:47 -08:00
Enrico Ros 8a2c4aa356 useLLMSelect: show starred models only 2025-11-19 12:14:16 -08:00
Enrico Ros 4cba819edd State: show starred models only 2025-11-19 12:11:24 -08:00
Enrico Ros 4db42a2b29 StarIcons: improve 2025-11-19 12:11:21 -08:00
Enrico Ros fc0ee5b698 LLMs: fix OpenAI models overlap check 2025-11-19 12:11:11 -08:00
Enrico Ros 2c0c3f1c70 CC: zustand fix 2025-11-19 12:11:01 -08:00
Enrico Ros 3f3976b73c eslint: migrate to flat conf 2025-11-19 12:09:53 -08:00
Enrico Ros 82d5dcced5 LLMs: Gemini 3: fixed temperature, as Google Strongly Recommends to keep it at 1 2025-11-18 20:29:31 -08:00
Enrico Ros f4eaed694a LLMParametersEditor: allow code execution 2025-11-18 20:19:26 -08:00
Enrico Ros 05d9869326 Improve CG tool appearance 2025-11-18 20:19:09 -08:00
Enrico Ros 2675934ff8 LLMs: Gemini 3 - enable code execution 2025-11-18 20:10:01 -08:00
Enrico Ros fb6e19d3ea Roll AIX 2025-11-18 19:51:56 -08:00
Enrico Ros f1151d54e1 LLMs: Gemini 3.0 with Thinking Level, media Resolution, Google Search. Fixes #884 2025-11-18 19:51:55 -08:00
Enrico Ros 6a0fa4f9fa LLMs: Gemini Parameters 2025-11-18 19:44:16 -08:00
Enrico Ros 20d96fffc8 AIX: Gemini: wires upgrade 2025-11-18 19:42:29 -08:00
Enrico Ros ad6c06308a AIX: Gemini: -> thinkingLevel, -> mediaResolution, -> codeExecution, -> urlContext 2025-11-18 19:36:40 -08:00
Enrico Ros 84ee4171a4 AIX: Gemini: thought signature logger 2025-11-18 19:36:40 -08:00
Enrico Ros 6bc4f8a1e4 AIX: Gemini: wiretypes for thinkingLevel (param), urlContext (tool), thoughtSignature (fc invocation arg) 2025-11-18 19:36:40 -08:00
Enrico Ros 8876aa0866 RenderCode: reload button when html is rendered. Fixes #885 2025-11-18 19:36:39 -08:00
Enrico Ros 691d2e7228 Starring: models on top 2025-11-18 05:34:04 -08:00
Enrico Ros 7a12755de9 T2I: LocalAI: temporary mappings of models names and sizes to OpenAI gpt-image (GI) family equivalents
Maps OpenAI model IDs to LocalAI models:
- gpt-image-1 → stablediffusion
- gpt-image-1-mini → dreamshaper
- dall-e-3 → sd-3.5-large-ggml
- dall-e-2 → sd-3.5-medium-ggml
2025-11-18 04:36:09 -08:00
Enrico Ros 8573f56d03 T2I: Enable LocalAI, over 'stablediffusion' 2025-11-18 04:05:16 -08:00
Enrico Ros 8f3e683321 T2I: Azure disable WebP 2025-11-18 02:59:02 -08:00
Enrico Ros 64867b0b67 T2I: Azure support - LocalAI likely. Fixes #832 2025-11-18 02:59:01 -08:00
Enrico Ros e42d060e57 T2I: OpenAI: honor options 2025-11-18 02:55:47 -08:00
Enrico Ros 2ca9ab8a0c T2I: add options 2025-11-18 02:54:43 -08:00
Enrico Ros fdc0c6b371 T2I: propagate abort signal 2025-11-18 02:48:01 -08:00
Enrico Ros 8f8779c3cd Selection Operations: improve with fuzzy matching: matches more. Helps #881 2025-11-18 02:43:11 -08:00
Enrico Ros 851877ad8b LLMs: Azure: send the image_generation request anyway, for future compatibility - #832 2025-11-18 01:19:21 -08:00
Enrico Ros 8df74529ad LLMs: Azure: still inline image generation does not work - #832 2025-11-18 01:16:13 -08:00
Enrico Ros 353f51ebf0 LLMs: Azure: more explicitly named no-web-search var 2025-11-18 01:07:31 -08:00
Enrico Ros 6c5cb08118 ModelsList: fix list jumpiness on starring. Fixes #880. 2025-11-18 00:49:35 -08:00
Enrico Ros 54fee92b15 ModelsList: improve performance in large lists (e.g. OpenRouter) 2025-11-18 00:49:05 -08:00
Enrico Ros 776431c801 LLMs: Mistral: silence the off-by-2 warning 2025-11-17 14:58:49 -08:00
Enrico Ros 9f893ce999 LLMs: Groq: update models 2025-11-17 14:58:49 -08:00
Enrico Ros 820447670c LLMs registry: move 2025-11-17 05:05:27 -08:00
Enrico Ros b43c49cd64 Type annotation 2025-11-17 03:58:40 -08:00
Enrico Ros f9c3558975 Remove warning 2025-11-17 03:49:03 -08:00
Enrico Ros 1b75250824 LLMs: enumeration 2025-11-17 03:43:10 -08:00
Enrico Ros 3fa3bb5d03 LLMs: Central Dispatch 2025-11-17 03:29:40 -08:00
Enrico Ros ef0ff55f1f LLMs: extract LocalAI, LMStudio 2025-11-17 01:42:26 -08:00
Enrico Ros 66aa8ed177 Composer: autoFocus only on Desktop 2025-11-17 00:27:52 -08:00
Enrico Ros 519286bc69 DocumentAttachmentFragments: doc number limiter 2025-11-17 00:13:46 -08:00
Enrico Ros 9882f45fd2 DocumentAttachmentFragments: rename into pane 2025-11-17 00:09:31 -08:00
Enrico Ros 634f6216a0 Roll packages 2025-11-17 00:07:08 -08:00
Enrico Ros 69574a7d1c AIX: OpenRouter: fix reasoning summaries 2025-11-16 04:36:41 -08:00
Enrico Ros eddd4b9be8 ModelsServiceSelector: improve +1 2025-11-16 04:36:26 -08:00
Enrico Ros 9a9c31ff53 DocumentAttachmentFragments: performance: memo 2025-11-16 04:36:06 -08:00
Enrico Ros 41ee7a1c85 Nav support: remessage 2025-11-15 13:35:26 -08:00
Enrico Ros 2f9bbf373c Nav support: with AI triage 2025-11-15 13:26:30 -08:00
Enrico Ros d662e10ebb Support: with AI triage 2025-11-15 13:23:42 -08:00
Enrico Ros cd31092333 Update AI triage 2025-11-15 13:23:31 -08:00
Enrico Ros 1eae7ab6f3 Update AI triage 2025-11-15 13:15:51 -08:00
Enrico Ros ba378f852f Tryout AI triage 2025-11-15 12:51:56 -08:00
Enrico Ros 5cfd1e557d Update README 2025-11-15 12:46:39 -08:00
Enrico Ros df31d79eaf Update README 2025-11-15 12:21:54 -08:00
Enrico Ros 12d7304325 Update README 2025-11-15 12:19:38 -08:00
Enrico Ros 41424cbdfd Update README 2025-11-15 12:17:06 -08:00
Enrico Ros 05dda519a2 CC: add tree 2025-11-15 12:04:07 -08:00
Enrico Ros 120d39282e Add screenshot section to README
Added a section for screenshots and usage examples.
2025-11-15 11:40:34 -08:00
Enrico Ros 8e7d0fd13b Update README 2025-11-15 11:32:21 -08:00
Enrico Ros 3d979fdfbb Update Docker deployment link in README 2025-11-15 01:58:19 -08:00
Enrico Ros 6ab47ae3cb Sweet readme
Updated README to enhance project visibility and features.
2025-11-15 01:56:56 -08:00
Enrico Ros a4977b4924 AI Inspector: 5Hz updates limit 2025-11-14 17:42:43 -08:00
Enrico Ros bac9c692b8 AI Inspector: toggle visibility on shortcut 2025-11-14 17:27:23 -08:00
Enrico Ros 6ab15356e1 AI Inspector: show Desktop shortcut 2025-11-14 17:19:21 -08:00
Enrico Ros 73cc7121c3 CC: add npx eslint 2025-11-14 15:40:34 -08:00
Enrico Ros 1aeef06f49 AppBeam: nits 2025-11-14 01:51:45 -08:00
Enrico Ros 3b16bcf01d OpenAI: officially updated 5.1 models 2025-11-14 01:15:09 -08:00
Enrico Ros f6351fda41 Ph: +Megaphone 2025-11-13 01:49:34 -08:00
Enrico Ros 007e91480d Roll posthog 2025-11-13 01:49:00 -08:00
Enrico Ros 163ef9296e HBWA: note 2025-11-13 01:48:18 -08:00
Enrico Ros fa042f7d68 AIX: prenorm 2025-11-12 22:53:50 -08:00
Enrico Ros 8a11040dde optimization: faster 'hasKeys' Object non-emptiness check (avoids allocation) 2025-11-12 22:40:46 -08:00
Enrico Ros a88971d557 Models: Vendor (service) selection: vastly improve 2025-11-12 17:45:34 -08:00
Enrico Ros 5867e5fcc5 OpenRouter: more config beauty 2025-11-12 17:32:43 -08:00
Enrico Ros 20e587d6d3 OpenRouter: more config cleanup 2025-11-12 16:58:14 -08:00
Enrico Ros 6bfa8471cd Models Modal: option for fullscreen 2025-11-12 16:01:14 -08:00
Enrico Ros 5c10bce2f4 ModelsList: disable the large popups 2025-11-12 15:53:52 -08:00
Enrico Ros f1663f6668 DataStreamViz: optimize with intersection observers for 1k Beams 2025-11-12 15:39:15 -08:00
Enrico Ros 90c27e0e74 LLMs: add displayGroup 2025-11-12 15:31:32 -08:00
Enrico Ros b5eac0d907 OpenRouter: more config improvement 2025-11-12 15:20:30 -08:00
Enrico Ros 4eabe2cb3a Roll AIX 2025-11-12 15:11:17 -08:00
Enrico Ros a1c0d30a06 LLMs: GPT-5 optimistic updates (coming later this week) 2025-11-12 15:10:50 -08:00
Enrico Ros 63c9f65040 Merge remote-tracking branch 'opensource/claude/issue-879-20251112-2245' 2025-11-12 15:05:01 -08:00
Enrico Ros f58a066bff OpenRouter: improve config 2025-11-12 15:02:21 -08:00
Enrico Ros 952ea6357a tRPC: newline on dev warnings 2025-11-12 14:57:59 -08:00
Enrico Ros 6695973035 tRPC: raise the correct server-side exceptions 2025-11-12 14:57:44 -08:00
claude[bot] 3dc28635f4 Add support for GPT-5.1 models
- Add gpt-5.1-2025-11-12 (GPT-5.1 Thinking) with adaptive reasoning
- Add gpt-5.1-chat-latest (GPT-5.1 Instant) with adaptive reasoning
- Both models include full feature set: chat, vision, function calling, JSON, prompt caching, reasoning, web search
- Pricing set to match GPT-5 (to be updated when official pricing is announced)
- Added models to manual ordering list for proper UI sorting

Co-authored-by: Enrico Ros <enricoros@users.noreply.github.com>
2025-11-12 22:47:51 +00:00
Enrico Ros 0bde01a85f Llms: vector ops 2025-11-12 14:43:26 -08:00
Enrico Ros b9840c2074 Warn downgrade 2025-11-12 14:43:23 -08:00
Enrico Ros 8228a76875 LLMs: LocalAI enumeration less verbose 2025-11-11 18:40:52 -08:00
Enrico Ros 46b370a2e3 AIX: OpenAI ChatGenerate: fixup for malformed NS objects - best-effort 2025-11-11 18:37:34 -08:00
Enrico Ros 820e9513ba Fragments: Void reasoning priority 2025-11-11 18:22:14 -08:00
Enrico Ros bd71d64db3 LLMs: OpenRouter: fix context window max_tokens issue 2025-11-11 18:09:50 -08:00
Enrico Ros 9d4baf827c LLMs: OpenRouter: auto-detection of capabilities (i/o modalities, features, etc). Thanks OpenRouter, you're the best! 2025-11-11 17:47:31 -08:00
Enrico Ros d6843d7fcf AIX: OpenRouter: write/parse the new reasoning request / reasoning_details response
Removes older system(s) from OpenRouter.
2025-11-11 17:46:58 -08:00
Enrico Ros babb1dd962 LLMs: OpenRouter: parser 2025-11-11 16:46:13 -08:00
claude[bot] aa32e396a7 Tryfix speech recognition on Android 2025-11-11 14:07:51 -08:00
Enrico Ros 1068efcb49 CC: commands: openrouter 2025-11-11 14:01:08 -08:00
Enrico Ros 576c7f1458 CC: improve triage 3 2025-11-11 13:48:20 -08:00
Enrico Ros 37c857b055 CC: improve triage 2 2025-11-11 13:37:46 -08:00
claude[bot] 794dfb44d1 Add date to README
Added today's date (2025-11-11) to README.md as requested in issue #876.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 21:34:04 +00:00
Enrico Ros 929bb6dc66 CC: improve triage 2025-11-11 13:32:34 -08:00
Enrico Ros 28337e31eb Token Badge: show for half a cent+ 2025-11-11 12:48:32 -08:00
Enrico Ros 09a38c0e4b UserInputChecklistComponent: fix crash 2025-11-11 12:30:02 -08:00
Enrico Ros 645b8fb9cd LLMs: OpenRouter: fix 400 2025-11-11 12:14:37 -08:00
Enrico Ros 541588948c LLMs: OpenRouter: add future PKCE 2025-11-11 12:13:09 -08:00
Enrico Ros bdd6fcfbbc Ph: add Gift/Key 2025-11-11 12:13:08 -08:00
Enrico Ros 9e50286c66 LLMs: Moonshot: remove images from the request for those models 2025-11-10 02:00:42 -08:00
Enrico Ros 418e4649dc Analytics: Client send 2025-11-10 00:59:28 -08:00
Enrico Ros 4a70f20f4a Roll packages
Note: fix Posthog/nextjs-config to 1.3.2 because starting from 1.3.3 there are new dependencies not evaluated yet
2025-11-10 00:33:28 -08:00
Enrico Ros d6eabfcb6d Roll posthog 2025-11-10 00:27:07 -08:00
Enrico Ros d88889d760 Extra: disable 0.1 opacity; makes the code less usable 2025-11-10 00:07:27 -08:00
Enrico Ros 85146d8af0 LLMs: Moonshot: native search parameter (disabled here and in the model - upstream not good enough) 2025-11-09 20:16:39 -08:00
Enrico Ros 9612572f07 AIX: Moonshot: native search dispatch/parse support 2025-11-09 20:15:02 -08:00
Enrico Ros 4bb1dddf4d ApproximateCosts: only display on Extra 2025-11-09 20:15:02 -08:00
Enrico Ros b066a86962 AIX: fix exhaustive check 2025-11-09 20:15:02 -08:00
Enrico Ros 6086455782 LLMs/AIX: Moonshot AI support 2025-11-09 20:15:02 -08:00
Enrico Ros 9020b3cbad AIX: Fix Mistral's response breakage in NS mode - Fixes #873. 2025-11-09 17:23:07 -08:00
Enrico Ros 5822dea270 AIX: Further breakdown logging levels - with Retry entry points. 2025-11-09 17:14:55 -08:00
Enrico Ros c445f59664 AIX: Fix Logging, with warn only for real server-side solvable issues. Fixes #872. Fixes #874.Fixes #875 2025-11-09 17:07:14 -08:00
Enrico Ros 737e4cb4f9 AIX - fix Gemini parser. Fixes #871 2025-11-09 16:31:52 -08:00
Enrico Ros dba7368d01 Rename platform format 2025-11-07 23:35:29 -08:00
Enrico Ros 314c4cd8cc Error correction: render placeholder notification 2025-11-07 23:11:31 -08:00
Enrico Ros 3e46f99e14 AIX: Error correction: client-side reporting 2025-11-07 22:45:11 -08:00
Enrico Ros e0cc552b8d AIX: Error correction: operation reporting (Anthropic only for now, but generic) 2025-11-07 22:45:11 -08:00
Enrico Ros 6b5be403af AIX: Error correction: dispatch reporting 2025-11-07 22:45:11 -08:00
Enrico Ros 269d5989bc Fetchers: Error correction: callback before retry 2025-11-07 22:43:12 -08:00
Enrico Ros edfe3d9b65 DFragments: Error correction: keep results in placeholder fragments (backward-comp) 2025-11-07 22:43:12 -08:00
Enrico Ros ffb2c42a26 imageUtils: non-aliased rescaling, multi-pass for downscales 2025-11-07 14:11:23 -08:00
Enrico Ros b7de19b020 AIX: turn on operation-retrier for Anthropic's error-in-stream. Fixes #869 2025-11-07 12:03:16 -08:00
Enrico Ros 77cd659b39 AIX: support operation-level retrier with reassembly wipe #869 2025-11-07 12:03:12 -08:00
Enrico Ros fbba9d8357 Block parts: show the retry-followup 2025-11-07 12:02:13 -08:00
Enrico Ros f464a9efdf LLMs: listModels: openAI, deprio 401. Fixes #870 2025-11-07 11:42:22 -08:00
Enrico Ros 7ec4290582 AIX: Anthropic: retriable errors: extended parsing 2025-11-07 11:04:21 -08:00
Enrico Ros 3f887a1d3a AIX: Gemini: fix other proxy errors. Fixes #868 2025-11-07 10:50:25 -08:00
Enrico Ros ffd76dc587 *Image Captioning with a dedicated (configurable) model. Fixes #862 2025-11-05 14:15:50 -08:00
Enrico Ros d7f3594a73 FormInputKey: smaller key 2025-11-05 12:32:18 -08:00
Enrico Ros 32fa5f206b AudioGenerator: underwater 2025-11-05 10:41:53 -08:00
Enrico Ros 70d2c09e81 Env: drop requirements on non-staging/non-prod 2025-11-05 09:01:47 -08:00
Enrico Ros 17f03806d0 AIX: rename DMessage gen to throw 2025-11-05 07:07:05 -08:00
Enrico Ros b6aba0efa4 AIX: type change to DMessageGuts for correctness 2025-11-04 17:01:26 -08:00
Enrico Ros 65a5e06935 DMessage: Generator helpers 2025-11-03 14:53:53 -08:00
Enrico Ros f459cb9805 PhPencilSimple: add 2025-11-03 09:04:28 -08:00
Enrico Ros f5470aca5d AIX: OpenAI Responses: remove patch for deep-research 2025-11-02 20:12:07 -08:00
Enrico Ros c26af97fe7 LLMs: OpenAI: deep research with standard params path 2025-11-02 20:11:17 -08:00
Enrico Ros 766ec458a2 CC: add permission 2025-11-02 15:43:28 -08:00
Enrico Ros 48ff78580c typos 2025-11-02 13:49:12 -08:00
Enrico Ros 396f7524d7 Panel Resize: rename inset 2025-11-01 18:08:31 -07:00
Enrico Ros da19ef42f5 AIX: OpenAI Responses: use the web_search (non preview) tool 2025-11-01 17:19:57 -07:00
Enrico Ros 91abe5aa43 DLLM: FC/FR: rendering improvement 2025-11-01 12:05:37 -07:00
Enrico Ros 682435321b DLLM: FC/FR: rendering improvement 2025-11-01 12:01:23 -07:00
Enrico Ros 76f0d60224 LLMs/AIX: Gemini: computer use comment 2025-11-01 11:28:34 -07:00
Enrico Ros 628b88ef9f LLMs/AIX: Gemini: computer use test 2025-11-01 11:18:12 -07:00
Enrico Ros 6a792814ce LLMs/AIX: Gemini: computer use mixed-tool (hosted + client) test. 2025-11-01 11:09:41 -07:00
Enrico Ros 05ce15d677 LLMOptionsModal: auto-open if user pricing is set or custom tokens are set 2025-11-01 11:02:26 -07:00
Enrico Ros 4a9d0d4f8e LLMs: fix post user-pricing, #860 2025-11-01 10:54:55 -07:00
Enrico Ros 16f0552682 CC: unbreak settings 2025-11-01 10:34:04 -07:00
claude[bot] 9e3819b9c7 feat: Add user pricing override for hypothetical cost tracking
Add userPricing field to DLLM interface following the established pattern
for user overrides (similar to userContextTokens and userMaxOutputTokens).

This enables users to set custom pricing for local models (Ollama, LM Studio, etc.)
to track "what if" costs and compare with cloud models.

Changes:
- Added userPricing field to DLLM interface (llms.types.ts)
- Added getLLMPricing() getter function with override precedence
- Updated store to preserve userPricing during model updates
- Updated all llm.pricing access points to use getLLMPricing()
- Added pricing override UI in LLMOptionsModal (Details section)
  - Input price ($/M tokens)
  - Output price ($/M tokens)
  - Reset buttons for each field
- Cost calculations automatically use user pricing when set
- Existing cost display in tooltips works with user pricing

Resolves #860

Co-authored-by: Enrico Ros <enricoros@users.noreply.github.com>
2025-10-31 08:37:58 +00:00
Enrico Ros 233a0d4b35 LLMs: xAI: rerank 4 2025-10-29 15:53:41 -07:00
Enrico Ros bd95b808ae InlineTextareaEditable: click to edit 2025-10-29 13:53:59 -07:00
Enrico Ros 96132c4585 Export: subordinate tslug warn to the downgrade 2025-10-29 09:50:12 -07:00
Enrico Ros 3edacef572 Export: messaging 2025-10-29 09:43:34 -07:00
Enrico Ros 36889c1695 Export: robustness 2025-10-29 09:30:45 -07:00
Enrico Ros cd2c6c1d8f Export: nits 2025-10-29 09:29:06 -07:00
Enrico Ros d8c78b1a00 Export: disable when beam open, as it's not exported for now 2025-10-29 09:28:18 -07:00
Enrico Ros 74a22c26cf Export: relax file export 2025-10-29 09:26:55 -07:00
Enrico Ros f742eba4c1 Ph: Terminal Icon 2025-10-29 09:11:01 -07:00
Enrico Ros 36c2812157 Export: warn on import from a downgrade or different tenant 2025-10-29 09:07:07 -07:00
Enrico Ros d353fc4c63 Export: save file variant 1 2025-10-29 08:54:05 -07:00
Enrico Ros 98bd3d6da0 LLMs: Ollama: Update models 2025-10-28 16:36:43 -07:00
Enrico Ros cd5ec8d295 LLMs: Perplexity: Update models 2025-10-28 16:34:24 -07:00
Enrico Ros f91c6456bd LLMs: xAI: Update models 2025-10-28 16:31:53 -07:00
Enrico Ros 67af87968e workflows: CC: ollama update 2025-10-28 16:30:48 -07:00
Enrico Ros 58ea3e1b35 workflows: CC: permissions 2025-10-28 16:27:15 -07:00
Enrico Ros a9435c10e8 LLMs: OpenPipe: Update models 2025-10-28 16:23:40 -07:00
Enrico Ros a86860fe76 LLMs: Groq: Update models 2025-10-28 16:19:40 -07:00
Enrico Ros a3d707f78a LLMs: Mistral: Update models 2025-10-28 16:17:34 -07:00
Enrico Ros c502426249 LLMs: Anthropic: Update models 2025-10-28 16:17:06 -07:00
Enrico Ros 2fb5ffcecf LLMs: Anthropic: remove retired Claude 2 models 2025-10-28 16:09:36 -07:00
Enrico Ros 6d995c1253 LLMs: Anthropic: remove retired Sonnet 3 models 2025-10-28 16:08:39 -07:00
Enrico Ros a860c1c490 LLMs: Anthropic: remove retired Sonnet 3.5 models - So long and thanks!! 2025-10-28 16:06:42 -07:00
Enrico Ros 481d9cc745 LLMs: Anthropic: only display 'obsoleted models' in 2025-10-28 16:03:02 -07:00
Enrico Ros 7e53a7bc2b Server: tRPC: Retriers: carve0out 429 quota 2025-10-28 15:59:05 -07:00
Enrico Ros 4df10e3782 Lint 2025-10-28 15:59:05 -07:00
Enrico Ros 396da65178 AIX: OpenRouter: don't display processing messages 2025-10-28 15:49:37 -07:00
Enrico Ros 87e8faf383 workflows: docker: limit to 1hr 2025-10-28 13:11:28 -07:00
Enrico Ros 9eb3e6d398 workflows: CC: raise to 30min 2025-10-28 13:11:21 -07:00
604 changed files with 69637 additions and 12456 deletions
+1
View File
@@ -0,0 +1 @@
commands/code/apply-issue-main.md
@@ -0,0 +1,49 @@
---
description: Sync OpenRouter API implementation with latest upstream documentation
argument-hint: specific feature to check
---
Review the OpenRouter implementation:
- Models list: `src/modules/llms/server/openai/openrouter.wiretypes.ts` (list API response schema)
- Chat wire types: `src/modules/aix/server/dispatch/wiretypes/openai.wiretypes.ts` (OpenAI-compatible)
- Request adapter: `src/modules/aix/server/dispatch/chatGenerate/adapters/openai.chatCompletions.ts` ('openrouter' dialect)
- Response parser: `src/modules/aix/server/dispatch/chatGenerate/parsers/openai.parser.ts` (shared OpenAI parser)
- Vendor config: `src/modules/llms/vendors/openrouter/openrouter.vendor.ts`
GOAL: Ensure complete support for OpenRouter's API including advanced features like reasoning/thinking tokens, tool use, search integration, and multi-modal capabilities. OpenRouter is OpenAI-compatible but has important extensions and differences.
Use Task tool with subagent_type=Explore and thoroughness="very thorough" to discover:
1. Map API structure - all endpoints, parameters, capabilities from https://openrouter.ai/docs
2. **Advanced features** - How to use: reasoning/thinking tokens (o1, DeepSeek R1), tool use/function calling, search integration, multi-modal (vision/audio)
3. Changelog location - How does OpenRouter communicate API updates and breaking changes?
4. Model metadata - What capabilities are exposed in the models list API? How to detect feature support?
5. OpenAI deviations - Extensions, special headers (HTTP-Referer, X-Title), response fields, streaming differences
Then check the latest API information. Try these sources (be creative if blocked):
**Primary Sources:**
- API Reference: https://openrouter.ai/docs/api-reference
- Chat Completions: https://openrouter.ai/docs/api-reference#chat-completions
- Models List: https://openrouter.ai/docs/api-reference#models-list
- Parameters Guide: https://openrouter.ai/docs/parameters
- Announcements: https://openrouter.ai/announcements (feature launches, API updates, new models)
- Models Directory: https://openrouter.ai/models (check metadata for capabilities)
**Alternative Sources:**
- GitHub: https://github.com/OpenRouterTeam (SDKs, examples, issues for recent changes)
- Web Search: "openrouter api changelog" or "openrouter reasoning tokens" or "openrouter tool use"
**If blocked:** Ask user to provide documentation.
$ARGUMENTS
Focus on discrepancies and gaps:
- **Request/Response structure**: New fields, changed requirements, streaming event types
- **Feature support**: Thinking tokens format, tool calling protocol, search parameters
- **Model capabilities**: How to detect and enable advanced features per model
- **OpenRouter extensions**: Headers, routing, fallbacks, rate limiting (free vs paid)
- **Breaking changes**: Protocol updates, deprecated fields, new required parameters
Report differences in wire types, adapter logic, parser handling, or dialect-specific quirks.
Prioritize new capabilities that improve user experience (reasoning visibility, better tool use, etc.).
When making changes, add comments with date: `// [OpenRouter, 2026-MM-DD]: explanation`
+56
View File
@@ -0,0 +1,56 @@
---
description: Sync xAI Responses API implementation with latest upstream documentation
argument-hint: specific feature to check
---
Review the xAI Responses API implementation:
- xAI wire types: `src/modules/aix/server/dispatch/wiretypes/xai.wiretypes.ts` (xAI-specific request schema, tools)
- Request adapter: `src/modules/aix/server/dispatch/chatGenerate/adapters/xai.responsesCreate.ts` (AIX → xAI Responses API)
- Response parser: `src/modules/aix/server/dispatch/chatGenerate/parsers/openai.responses.parser.ts` (shared with OpenAI Responses)
- Dispatch routing: `src/modules/aix/server/dispatch/chatGenerate/chatGenerate.dispatch.ts` (dialect='xai' routing)
- OpenAI shared types: `src/modules/aix/server/dispatch/wiretypes/openai.wiretypes.ts` (InputItem/OutputItem schemas reused by xAI)
IMPORTANT context:
- We use ONLY the xAI Responses API (`POST /v1/responses`). We do NOT use the Chat Completions API (`/v1/chat/completions`) for xAI anymore.
- xAI's Responses API is similar to OpenAI's but has key differences - the skill should find what changed since our last sync.
- Response streaming/parsing reuses the OpenAI Responses parser since the format is compatible.
- We do NOT implement: Files API, Collections Search, Remote MCP tools, Voice Agent API, Image/Video generation, Batch API, or Deferred Completions.
Then take a look at the newest API information available. Try these sources, and be creative if some are blocked:
**Primary Sources (guide pages work well with WebFetch despite being JS-rendered):**
- Responses API Guide: https://docs.x.ai/docs/guides/chat
- Stateful Responses: https://docs.x.ai/docs/guides/responses-api
- Tools Overview: https://docs.x.ai/docs/guides/tools/overview
- Search Tools (web_search, x_search): https://docs.x.ai/docs/guides/tools/search-tools
- Code Execution Tool: https://docs.x.ai/docs/guides/tools/code-execution-tool
- Function Calling: https://docs.x.ai/docs/guides/function-calling
- Streaming: https://docs.x.ai/docs/guides/streaming-response
- Reasoning: https://docs.x.ai/docs/guides/reasoning
- Structured Outputs: https://docs.x.ai/docs/guides/structured-outputs
- Models & Pricing: https://docs.x.ai/developers/models
- Release Notes: https://docs.x.ai/developers/release-notes
- API Reference: https://docs.x.ai/developers/api-reference#create-new-response
**Alternative Sources if primary blocked:**
- xAI Python SDK: https://github.com/xai-org/xai-sdk-python
- Web Search for "xai grok api changelog 2026" or "xai responses api new features"
**If all blocked:** Explain what you attempted and ask user to provide documentation manually.
$ARGUMENTS
Check carefully for discrepancies between our implementation and the current API docs:
1. **Request fields**: Compare `XAIWire_API_Responses.Request_schema` against current docs - any new, changed, or deprecated parameters?
2. **Tool definitions**: Compare `XAIWire_Responses_Tools` - any new parameters on web_search/x_search/code_interpreter? Any new hosted tool types?
3. **Input/Output item types**: Any xAI-specific output items not handled by the shared OpenAI parser (e.g., x_search_call, web_search_call, code_interpreter_call)?
4. **Streaming events**: Any xAI-specific SSE event types beyond what the OpenAI Responses parser handles?
5. **Response shape**: Usage reporting differences, new fields in the response object?
6. **Adapter logic**: Message role mapping, content type handling, system message approach - still correct?
7. **Include options**: Any new values for the `include` array?
8. **Reasoning config**: Which models support it and with what values?
Prioritize breaking changes and new capabilities that would improve the user experience.
When making changes, add comments with date: `// [xAI, 2026-MM-DD]: explanation`
**Self-update this skill**: After completing the sync, if your research reveals that assumptions in THIS skill file (`.claude/commands/aix/sync-xai-api.md`) are wrong or outdated - e.g., new APIs we now implement, new tool types added, URLs moved, file paths changed - update this skill file to stay accurate for next time.
+63
View File
@@ -0,0 +1,63 @@
---
description: Search git history for commits that introduce or remove an exact string, within a commit range
argument-hint: "[search-string] [ancestor-commit]"
allowed-tools: Bash(git *)
---
Search git history using `git log -S` (pickaxe) to find commits that add or remove an exact string.
This repo has 7000+ commits, so pickaxe searches can take 30-60+ seconds - this is expected.
## Parameters
- `$0` - The exact string to search for in file contents (not commit messages). Examples: `getLabsSUDO`, `EXPERIMENT_ON_SUDO`, `myFunctionName`
- `$1` - A commit hash or unique commit message substring to identify the start of the range. Examples: `5af80b96a8`, `"Sudo Mode": 10-click`
## Example
```
/code:grep-history EXPERIMENT_ON_SUDO "Sudo Mode": 10-click
```
This searches all commits between the `"Sudo Mode": 10-click` commit and HEAD for any that add or remove the string `EXPERIMENT_ON_SUDO` in file contents.
## Procedure
### Step 1: Resolve the ancestor commit
If `$1` looks like a commit hash (hex string), use it directly.
Otherwise, search for it by message, restricting to ancestors of HEAD:
```bash
git log --oneline --grep='$1' HEAD | head -5
```
This only walks commits reachable from HEAD, so every result is a guaranteed ancestor - no verification loop needed.
If multiple results, pick the oldest (last listed) since it represents the earliest matching commit.
If none, report the error and stop.
### Step 2: Run pickaxe search
```bash
git log -S "$0" --oneline <resolved_ancestor>..HEAD
```
This finds commits where the count of `$0` in the codebase changes (i.e., it was added or removed).
This can be slow on 7000+ commits - wait for it.
### Step 3: Check endpoints
Also check whether the string exists at HEAD and at the ancestor commit:
```bash
git grep -l "$0" HEAD 2>/dev/null || echo "(not found at HEAD)"
git grep -l "$0" <resolved_ancestor> 2>/dev/null || echo "(not found at ancestor)"
```
### Step 4: Report
Present results concisely:
- Number of commits found (or "none")
- List of matching commits (hash + subject line)
- Whether the string exists at HEAD and/or at the ancestor
- If found, suggest next steps (e.g., `git show <hash>` to inspect specific commits)
+34
View File
@@ -0,0 +1,34 @@
---
description: Review in-flight changes for coherence, completeness, and quality
---
Review the current in-flight changes in the big-agi-private repository (dev branch, continuously rebased ~1800 commits on top of main).
**Step 1: Scope and read**
`git diff --stat` + `git status` for breadth. Then full `git diff` (if empty: `git diff --cached`, then `git diff HEAD~1`).
For every file in the diff, read surrounding context in the actual source file - the diff alone hides bugs in adjacent untouched code.
**Step 2: Reverse-engineer the intent**
From the diff, determine the **what**, **how**, and **why**. Present this concisely so the author can confirm or correct,
but don't stop here, continue to the full review in the same response.
**Step 3: Validate**
Run `tsc --noEmit --pretty` and `npm run lint` (in parallel). Report any errors with the review.
If the diff removes/renames identifiers, grep the codebase for stale references to the OLD names. This catches broken guards, stale imports, and incomplete migrations.
**Step 4: Deep review**
Evaluate every file in the diff.
Leave no rocks unturned - correctness, coherence, completeness, excess, generalization, maintenance burden,
codebase consistency, etc.
**Step 5: Prioritized next steps**
Think about what happens when the next developer touches this code.
Rank findings by severity (bug > correctness > cleanup > cosmetic). Be specific about what to change and where.
Remember: design values for this codebase: orthogonal features, features that generalize well, modularized and reusable code,
type-discriminated data, optimized code, zero maintenance burden. Minimize future pain, etc.
+57
View File
@@ -0,0 +1,57 @@
---
description: Show a hierarchical progress tree of the current conversation thread
---
Analyze this conversation thread and produce a **hierarchical progress tree** - a vertical breadcrumb of the chat and actions from the very start to now.
**Format:**
A tree, where every rabbithole that was taken adds a level.
```
[ ] Brief initial phase/ask/goal description
[x] Specific thing done or decided - "user quote if relevant"
[x] Another step
[ ] Sub-phase/rabbithole/etc
[x] Done step (if important)
[ ] Sub-sub-phase
[ ] Current step doing <-- HERE
[ ] Next step since this sub-sub-phase was broken out
[ ] Remaining step
[ ] ...
[ ] Missing, back to the main goal
[ ] ...
### What do we rewind the rabbithole to (once the current level is complete)?
...
### What's up (towards user value) and down (towards deeper code levels) the rabbithole?
...
### What's a good hyphenated title for this chat?
...
```
**Rules:**
- `[x]` done, `[ ]` not done. Parent is done only when ALL children on the next level are `[x]`
- Each node: a few words, specific. Quote the user briefly when it captures the intent
- Group by logical phases or rabbitholes (when descending to a deeper level of implementation or going off for a temporary tangent or sub-quest), not by messages
- Earlier levels that are fully completed don't need to be expanded in subtasks
- Root nodes/completed nodes need to show what was "wanted" from them, not being checked because they are shown as earlier phases (i.e. upper hierarchy contains more)
- Some earlier sub-phases or even levels of rabbitholes can be marked as done as indented [x] below each other (do not add non-major bullets on already completed nodes)
- Insert newlines in between large groups of items
- Decisions: state what was chosen, not the alternatives
- If a former phase produced no code change or decision, omit
- Very important to insert incomplete `[ ]` items for things that wre mentioned and are likely useful but mentioned at higher levels of the rabbithole so they must come after, when unwinding the stack
- Keep it short, tight (min 0 max item count below *ONE QUARTER the user messages*). This is a navigation aid, not a transcript
It's important for this to represent a high-level sequence of important actions and turns and pivots and rabbiholes, all focuses on trying to solve something.
First think through it looking at all the chat from the back to the front, then front to back, user requests, and understand the main storybeats. This is useful especially to remove already done leaves that don't add much if shown.
So think about the full list, so you have it all in front of you when you do the last pass to show it to me.
It's important to see the progress of what we were doing (e.g. see that we set out to do something at the beginning, but a few items of those are still incomplete, also because we took 2 detours to fix more things in the meantime...).
At the end anser the questions in the Format, with brief bullet points.
+63
View File
@@ -0,0 +1,63 @@
---
description: Sync LLM parameter options between full model dialog and chat side panel
---
Audit and sync LLM parameter configurations between the two UI editors. Goal: identical `value` fields in option arrays + equivalent onChange logic. Labels/descriptions can differ for UI space.
**Files to Compare:**
1. **Full Model Dialog**: `src/modules/llms/models-modal/LLMParametersEditor.tsx` (main branch)
2. **Chat Side Panel**: `src/apps/chat/components/layout-panel/ChatPanelModelParameters.tsx` (main derived branches only)
**Reference Documentation:**
- Parameter system: `kb/systems/LLM-parameters-system.md`
- Parameter registry: `src/common/stores/llms/llms.parameters.ts`
**Task: Perform a comprehensive audit**
1. **Read both files** and extract all option arrays (e.g., `_reasoningEffortOptions`, `_antEffortOptions`, `_geminiThinkingLevelOptions`, etc.)
2. **Check for missing parameters:**
- Parameters handled in `LLMParametersEditor.tsx` but NOT in `ChatPanelModelParameters.tsx`
- Parameters in `ChatPanelModelParameters.tsx`'s `_interestingParameters` array but missing UI controls
- Note: The side panel intentionally shows only "interesting" parameters - focus on those listed in `_interestingParameters`
3. **Check for value mismatches** between corresponding option arrays:
- Different number of options (e.g., 3 vs 4 options)
- Same label but different `value` (this causes the bug in issue #926)
- Different labels for the same `value`
- Missing `_UNSPECIFIED`/Default option in one but not the other
4. **Check onChange handler consistency:**
- Both should remove parameter on `_UNSPECIFIED` selection
- Both should set explicit values the same way
- Watch for conditions like `value === 'high'` that may differ
**Output Format:**
```
## Parameter Sync Audit Report
### Missing Parameters
- [ ] `llmVndXyz` - In full dialog, missing from side panel
### Value Mismatches
- [ ] `_xyzOptions`:
- Full dialog: [values...]
- Side panel: [values...]
- Issue: [description]
### Handler Inconsistencies
- [ ] `llmVndXyz` onChange differs: [explanation]
### Recommended Fixes
1. [Specific fix with code snippet if needed]
```
**Fix Direction:** Full dialog is source of truth. Update side panel to match its values when mismatched.
**Notes:**
- Side panel uses shorter descriptions (space-constrained) - that's fine
- Variable names may differ (e.g., `_anthropicEffortOptions` vs `_antEffortOptions`) - that's fine, but same is better
- `value` fields must be identical sets
- `_UNSPECIFIED` must mean the same thing in both
- onChange: remove on `_UNSPECIFIED`, set explicit value otherwise
@@ -4,7 +4,7 @@ description: Update Alibaba model definitions with latest pricing and capabiliti
Update `src/modules/llms/server/openai/models/alibaba.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Models & Pricing: https://www.alibabacloud.com/help/en/model-studio/models
@@ -4,17 +4,46 @@ description: Update Anthropic model definitions with latest pricing and capabili
Update `src/modules/llms/server/anthropic/anthropic.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference files (for context only, do not modify):
- `src/modules/llms/server/llm.server.types.ts`
- `src/modules/llms/server/models.mappings.ts`
- `src/common/stores/llms/llms.parameters.ts`
**Primary Sources:**
- Models: https://docs.claude.com/en/docs/about-claude/models/overview
- Pricing: https://claude.com/pricing#api
- Deprecations: https://docs.claude.com/en/docs/about-claude/model-deprecations
**Workflow: Start with recent changes, then verify the full model list.**
**Fallbacks if blocked:** Check Anthropic TypeScript SDK at https://github.com/anthropics/anthropic-sdk-typescript, search "anthropic models latest pricing", "anthropic latest models", or search GitHub for latest model prices and context windows
**Primary Sources (append `.md` to any path for clean markdown):**
1. Recent changes: https://platform.claude.com/docs/en/release-notes/overview.md
2. Models & IDs: https://platform.claude.com/docs/en/about-claude/models/overview.md
3. Pricing (base, cache, batch, long context): https://platform.claude.com/docs/en/about-claude/pricing.md
4. Deprecations & retirement dates: https://platform.claude.com/docs/en/about-claude/model-deprecations.md
**Discovering feature docs:** The release notes and models overview markdown
contain inline links to feature-specific pages (thinking modes, effort,
context windows, what's-new pages, etc.). When a new capability is
referenced, follow those links - append `.md` to get markdown. Examples of
pages you might discover this way:
- `about-claude/models/whats-new-claude-*` - per-generation changes
- `build-with-claude/extended-thinking` - thinking budget configuration
- `build-with-claude/effort` - effort parameter levels
- `build-with-claude/adaptive-thinking` - adaptive thinking mode
**Fallback web pages** (crawl if `.md` paths break or structure changes):
- https://platform.claude.com/docs/en/about-claude/models/overview
- https://platform.claude.com/docs/en/about-claude/pricing
- https://platform.claude.com/docs/en/release-notes/overview
- https://claude.com/pricing
**Fallbacks if blocked:** Check the Anthropic TypeScript SDK at
https://github.com/anthropics/anthropic-sdk-typescript, or web-search
for "anthropic models latest pricing" / "anthropic latest models".
**Important:**
- Review the full model list for additions, removals, and price changes
- For new models: check which `parameterSpecs` are needed (thinking mode,
effort levels, 1M context, skills, web tools) by reading the linked
feature docs and comparing with existing model entries
- When thinking/effort semantics change between generations
(e.g. adaptive vs manual thinking), document in comments
- Minimize whitespace/comment changes, focus on content
- Preserve comments to make diffs easy to review
- Flag broken links or unexpected content
@@ -4,7 +4,7 @@ description: Update DeepSeek model definitions with latest pricing and capabilit
Update `src/modules/llms/server/openai/models/deepseek.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Pricing: https://api-docs.deepseek.com/quick_start/pricing
@@ -0,0 +1,91 @@
---
description: Update/validate dynamic vendor model parsers (OpenRouter, TogetherAI, Alibaba, Azure, Novita, ChutesAI, FireworksAI, TLUS, LM Studio, LocalAI, FastAPI)
---
Validate that the dynamic (API-fetched) vendor model parsers are up to date and not silently broken.
These vendors do NOT have hardcoded model lists - they fetch models from APIs at runtime. But their parsers, filters, heuristic detection, and capability mapping can break if upstream APIs change. This skill covers all dynamic vendors NOT covered by the other `llms:update-models-{vendor}` skills.
## Vendors to Validate
### High Risk
**OpenRouter** - `src/modules/llms/server/openai/models/openrouter.models.ts`
- Most complex parser. Vendor-specific parameter inheritance (Anthropic thinking variants, Gemini thinking/image, OpenAI reasoning effort, xAI/DeepSeek reasoning).
- Hardcoded family ordering list (lines ~24-37) - check if new leading vendors are missing.
- Hardcoded old/deprecated model hiding list (lines ~39-49) - check if stale.
- Cache pricing detection (Anthropic-style vs OpenAI-style) - verify format still valid.
- Variant injection for Anthropic thinking/non-thinking - verify still correct.
- Reference: https://openrouter.ai/docs/models
### Medium Risk
**Novita** - `src/modules/llms/server/openai/models/novita.models.ts`
- Features array mapping (`function-calling`, `reasoning`, `structured-outputs`) and input modalities parsing.
- Pricing unit conversion (hundredths of cent per million → dollars per 1K).
- Hostname heuristic: `novita.ai`.
**ChutesAI** - `src/modules/llms/server/openai/models/chutesai.models.ts`
- Custom `max_model_len` field for context window.
- Assumes all models support Vision + Functions (aggressive).
- Hostname heuristic: `.chutes.ai`.
**FireworksAI** - `src/modules/llms/server/openai/models/fireworksai.models.ts`
- Relies on provider capability flags: `supports_chat`, `supports_image_input`, `supports_tools`.
- Hostname heuristic: `fireworks.ai/`.
**TogetherAI** - `src/modules/llms/server/openai/models/together.models.ts`
- Type allow-list (`type: 'chat'`), vision detection by string match.
- Custom wire schema with pricing conversion.
**TLUS** - `src/modules/llms/server/openai/models/tlusapi.models.ts`
- Detected by response structure (`total_models`, `free_models`, `pro_models` fields).
- Capability enum mapping (`text`, `vision`, `audio`, `tool-calling`, `reasoning`, `websearch`).
- Tier-based pricing (`free` vs paid).
**Alibaba** - `src/modules/llms/server/openai/models/alibaba.models.ts`
- Model list was cleared (dynamic-only). Exclusion patterns for non-chat models.
- Assumes 128K context and Vision+Functions for all models (overly permissive).
- Check if hardcoded data should be restored now that naming has stabilized.
### Low Risk (local/generic - validate only if issues reported)
**Azure** - `src/modules/llms/server/openai/models/azure.models.ts`
- Custom deployments API, not `/v1/models`. User-specific. Deployment name fallback logic.
**LM Studio** - `src/modules/llms/server/openai/models/lmstudio.models.ts`
- Local service, native API (`/api/v1/models`). GGUF metadata parsing, capability flags.
**LocalAI** - `src/modules/llms/server/openai/models/localai.models.ts`
- Local service. String-based hide list, vision/reasoning detection by name pattern.
**FastAPI** - `src/modules/llms/server/openai/models/fastapi.models.ts`
- Generic passthrough. Detected by `owned_by === 'fastchat'`. Minimal parsing.
## Validation Checklist
For each vendor (prioritize High > Medium > Low):
1. **Read the parser file** and check for:
- Deny/allow lists that may be stale (new model families missing)
- Capability assumptions that may be wrong (e.g. "all models support vision")
- Field names that may have changed upstream
- Pricing conversion math that may use wrong units
2. **Check upstream docs** (where available) for:
- API response schema changes
- New model types or capability fields
- Deprecated fields
3. **Cross-reference with OpenRouter** (aggregator):
- OpenRouter surfaces models from many of these vendors
- If OpenRouter shows capabilities that a vendor's parser misses, the parser is stale
4. **Fix issues found** - update parsers, filters, deny lists as needed.
5. Run `tsc --noEmit` after changes.
**Important:**
- Do NOT convert dynamic vendors to hardcoded lists - the dynamic approach is intentional
- Focus on parser correctness, not model coverage
- Flag any vendor whose API response format seems to have changed substantially
@@ -4,7 +4,7 @@ description: Update Gemini model definitions with latest pricing and capabilitie
Update `src/modules/llms/server/gemini/gemini.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.types.ts`, `src/modules/llms/server/llm.server.types.ts`, and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.types.ts`, `src/modules/llms/server/llm.server.types.ts`, and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Models: https://ai.google.dev/gemini-api/docs/models
+4 -4
View File
@@ -4,13 +4,13 @@ description: Update Groq model definitions with latest pricing and capabilities
Update `src/modules/llms/server/openai/models/groq.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Models: https://console.groq.com/docs/models
**Primary Source:**
- Fetch https://console.groq.com/docs/models.md directly (markdown format, no search needed)
- Pricing: https://groq.com/pricing/
**Fallbacks if blocked:** Search "groq models latest pricing", "groq latest models", "groq api models", or search GitHub for latest model prices and context windows
**Do NOT use web search.** The `.md` endpoint provides structured markdown content directly.
**Important:**
- Review the full model list for additions, removals, and price changes
@@ -0,0 +1,19 @@
---
description: Update Kimi model definitions with latest pricing and capabilities
---
Update `src/modules/llms/server/openai/models/moonshot.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources (fetch directly, no search needed):**
- Pricing: https://platform.moonshot.ai/docs/pricing/chat
- API Reference: https://platform.moonshot.ai/docs/api/chat
**Do NOT use web search.** Fetch the URLs directly, or ask the user to provide data, if unaccessible.
**Important:**
- Review the full model list for additions, removals, and price changes
- Minimize whitespace/comment changes, focus on content
- Preserve comments to make diffs easy to review
- Flag broken links or unexpected content
@@ -0,0 +1,26 @@
---
description: Update MiniMax model definitions with latest pricing and capabilities
---
Update `src/modules/llms/server/openai/models/minimax.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Models & Changelog: https://platform.minimax.io/docs/release-notes/models.md
- Pricing: https://platform.minimax.io/docs/guides/pricing-paygo.md
- Pricing Overview: https://platform.minimax.io/docs/pricing/overview.md
- Text Generation API: https://platform.minimax.io/docs/guides/text-generation.md
**Note:** MiniMax is a hardcoded-only vendor (no `/v1/models` API yet). All model IDs, context windows, and pricing must be manually maintained from the docs. Pay attention to new model releases (M-series), highspeed variants, and deprecated models.
**Fallbacks if blocked:** Search "minimax api models pricing", "minimax m2 m3 models", "minimax api changelog" or check https://openrouter.ai models list for MiniMax entries.
**Important:**
- Models are `ModelDescriptionSchema[]` objects (not ManualMappings) - match existing pattern in the file
- Review the full model list for additions, removals, and price changes
- Check for new `-highspeed` variants and new model families
- Verify context window sizes and max completion tokens against docs
- Minimize whitespace/comment changes, focus on content
- Preserve comments to make diffs easy to review
- Flag broken links or unexpected content
@@ -4,7 +4,7 @@ description: Update Mistral model definitions with latest pricing and capabiliti
Update `src/modules/llms/server/openai/models/mistral.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Models: https://docs.mistral.ai/getting-started/models/models_overview/
+12 -11
View File
@@ -4,32 +4,33 @@ description: Update Ollama model definitions with latest featured models
Update `src/modules/llms/server/ollama/ollama.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Automated Workflow:**
```bash
# 1. Fetch the HTML
curl -s "https://ollama.com/library?sort=featured" -o /tmp/ollama-featured.html
# 1. Fetch the HTML to a cross-platform temp path (sorted by newest for stable ordering)
curl -s "https://ollama.com/library?sort=newest" -o "$(node -p "require('os').tmpdir()")/ollama-newest.html"
# 2. Parse it with the script
node .claude/scripts/parse-ollama-models.js > /tmp/ollama-parsed.txt 2>&1
# 3. Review the parsed output
cat /tmp/ollama-parsed.txt
# 2. Parse it with the script (auto-finds the file in os.tmpdir())
node .claude/scripts/parse-ollama-models.js 2>&1
```
The parser outputs: `modelName|pulls|capabilities|sizes`
- Example: `deepseek-r1|66200000|tools,thinking|1.5b,7b,8b,14b,32b,70b,671b`
**Primary Sources:**
- Model Library: https://ollama.com/library?sort=featured
- Model Library: https://ollama.com/library?sort=newest
- Parser script: `.claude/scripts/parse-ollama-models.js`
**Fallbacks if blocked:** Check https://github.com/ollama/ollama, search "ollama featured models", "ollama latest models", or search GitHub for latest model info
**Important:**
- Skip models below 50,000 pulls (parser does this automatically)
- Sort them in the EXACT same order as the source (featured models)
- Parser filtering rules:
- Top 30 newest models are always included (regardless of pull count)
- After top 30, only models with 50K+ pulls are included
- Models with 'cloud' capability are automatically excluded
- Models with 'embedding' capability are automatically excluded
- Sort them in the EXACT same order as the source (newest first, for stable ordering)
- Extract tags: 'tools' → hasTools, 'vision' → hasVision, 'embedding' → isEmbeddings (note the 's'), 'thinking' → tags only
- Extract 'b' tags (1.5b, 7b, 32b) to tags field
- Set today's date (YYYYMMDD format) for newly added models only
@@ -4,7 +4,7 @@ description: Update OpenAI model definitions with latest pricing and capabilitie
Update `src/modules/llms/server/openai/models/openai.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Manual hint:** For pricing page, expand all tables before copying content.
@@ -4,7 +4,7 @@ description: Update OpenPipe model definitions with latest pricing and capabilit
Update `src/modules/llms/server/openai/models/openpipe.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Base Models: https://docs.openpipe.ai/base-models
@@ -4,7 +4,7 @@ description: Update Perplexity model definitions with latest pricing and capabil
Update `src/modules/llms/server/openai/models/perplexity.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Models: https://docs.perplexity.ai/getting-started/models
+1 -1
View File
@@ -4,7 +4,7 @@ description: Update xAI model definitions with latest pricing and capabilities
Update `src/modules/llms/server/openai/models/xai.models.ts` with latest model definitions.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.data.ts` for context only. Focus on the model file, do not descend into other code.
Reference `src/modules/llms/server/llm.server.types.ts` and `src/modules/llms/server/models.mappings.ts` for context only. Focus on the model file, do not descend into other code.
**Primary Sources:**
- Models & Pricing: https://docs.x.ai/docs/models?cluster=us-east-1#detailed-pricing-for-all-grok-models
@@ -0,0 +1,66 @@
---
description: Verify model parameterSpecs match API-validated sweep data
argument-hint: openai | anthropic | gemini | xai (or empty for all)
---
# Verify LLM Parameters
Compare model `parameterSpecs` in definition files against API-validated sweep data.
If `$ARGUMENTS` provided, verify only that dialect, which includes reading the pair of sweep results and model defintions. Otherwise verify all four, and read the pairs in sequence.
## Files
**Sweep results** (source of truth for select parameters):
- `tools/develop/llm-parameter-sweep/llm-{dialect}-parameters-sweep.json`
By the time you see these files, the repo owner has already updated them via `tools/develop/llm-parameter-sweep/sweep.sh` (very long running, 15 min per vendor).
**Model definitions (source of truth for model defintions for the user and application, including constants, interfaces, supported parameters and sometimes allowed parameter values)**:
- OpenAI: `src/modules/llms/server/openai/models/openai.models.ts`
- Anthropic: `src/modules/llms/server/anthropic/anthropic.models.ts`
- Gemini: `src/modules/llms/server/gemini/gemini.models.ts`
- xAI: `src/modules/llms/server/openai/models/xai.models.ts`
## Task
The sweep data is the source of truth for allowed model parameter values or value ranges, and for the `fn` function-calling capability probe.
For each model in the sweep, verify the model definition exposes exactly those capabilities - no more, no less. This includes:
- The parameter is present in parameterSpecs
- The paramId variant covers exactly the values from the sweep, if applicable
- `LLM_IF_OAI_Fn` in `interfaces` matches `"roundtrip"` in the sweep's `fn` array (see below)
- etc.
Report models where the definition doesn't match the sweep.
## Parameter Mapping
Example parameter mapping. Note that new parameters may have been added to both the definition, and the sweep.
The objective of the sweep is to hint at model definition values, but the model definitions are what matters for Big-AGI,
and need to be carefully updated, otherwise thousands of clients may break.
| Dialect | Sweep Key | Model paramId |
|-----------|--------------------------|------------------------------|
| OpenAI | `oai-reasoning-effort` | `llmVndOaiEffort` |
| OpenAI | `oai-verbosity` | `llmVndOaiVerbosity` |
| OpenAI | `oai-image-generation` | `llmVndOaiImageGeneration` |
| OpenAI | `oai-web-search` | `llmVndOaiWebSearchContext` |
| Anthropic | `ant-effort` | `llmVndAntEffort` |
| Anthropic | `ant-thinking-budget` | `llmVndAntThinkingBudget` |
| Gemini | `gemini-thinking-level` | `llmVndGemEffort` |
| Gemini | `gemini-thinking-budget` | `llmVndGeminiThinkingBudget` |
| xAI | `xai-web-search` | `llmVndXaiWebSearch` |
## Function-Calling Capability (`fn`)
The sweep `fn` array is a capability probe (not a paramId). `"roundtrip"` is the authoritative signal - full tool-call -> response -> coherent follow-up. `LLM_IF_OAI_Fn` in the model's `interfaces` must track `"roundtrip"`: present iff present.
Flag:
- `"roundtrip"` in sweep but `LLM_IF_OAI_Fn` missing (or vice versa)
- `fn` contains `"auto"`/`"required"` without `"roundtrip"` - partial capability, call it out
## Output
Report first for every model the expected values from the sweep, then the actual values from the definition, then the mismatches.
Finally make one table for each dialect listing all models with mismatches and the specific issues.
+56
View File
@@ -0,0 +1,56 @@
---
description: Generate changelog bullets for big-agi.com/changes
argument-hint: date like "2026-01-10" or empty for auto-detect
---
Generate changelog bullets for a single entry in https://big-agi.com/changes
**Step 1: Find the starting date**
IMPORTANT: This repo rebases frequently, so commits are INTERLEAVED throughout history.
New commits can appear at line 10, 500, or 1800. Use AUTHOR DATE (`%ad`) to filter - it's preserved during rebases.
If `$ARGUMENTS` provided, use it as the cutoff date.
If NO argument:
1. Fetch https://big-agi.com/changes to get the most recent changelog date
2. Use that date as the cutoff
**Step 2: Get commits by author date**
Filter commits by author date to catch ALL new commits regardless of position in history:
```bash
# For commits after Jan 10, 2026 (adjust date pattern as needed)
git log --oneline --no-merges --format="%h %ad %s" --date=short | grep "2026-01-1[1-9]\|2026-01-2\|2026-02"
# Verify interleaving by checking line numbers
git log --oneline --no-merges --format="%h %ad %s" --date=short | grep -n "2026-01-1[1-9]"
```
The line numbers prove commits are scattered (e.g., lines 14, 638, 1156, 1803 = interleaved).
**Step 3: Write bullets**
Real examples from big-agi.com/changes:
- "Gemini 3 Flash support with 4-level thinking: high, medium, low, minimal"
- "Cloud Sync launched! - long awaited and top requested"
- "Deepseek V3.2 Speciale comes with almost Gemini 3 Pro performance but 20 times cheaper"
- "Anthropic Opus 4.5 with controls for effort (speed tradeoff), thinking budget, search"
- "Login with email, via magic link"
- "Mobile UX fixes for popups drag/interaction"
**Rules:**
1. **Order by importance** - most significant changes first, minor fixes last
2. **Feature-first, no verb prefixes** - "Gemini 3 support" not "Add Gemini 3 support"
3. **Model names lead** when it's about LLMs
4. **Specific details** - "4-level thinking: high, medium, low, minimal" not "multiple thinking levels"
5. **One-liners** - short, no fluff
6. **Consolidate commits** - 10 persona editor commits = 1 bullet
7. **No corporate speak** - no "enhanced", "streamlined", "robust", "leverage"
**Skip:** WIP, internal refactors, KB docs, automation, review cleanups, trivial fixes, deps bumps, CI changes.
**Output:** Just bullets, ready to paste. 2-5 bullets but adapt depending on scope, especially
in relation to the usual https://big-agi.com/changes entries.
+149
View File
@@ -0,0 +1,149 @@
---
description: Execute the Big-AGI release process
argument-hint: version like "2.0.4" or empty to auto-increment patch
---
Execute the release process for Big-AGI. Go step-by-step, waiting for user approval between major steps.
## Step 1: Determine Version
If `$ARGUMENTS` provided, use it. Otherwise, read `package.json` and increment patch version.
## Step 2: Gather Context
Before drafting, gather what changed:
1. `git log --oneline` since last release tag to see all commits
2. Fetch https://big-agi.com/changes to see what daily entries already covered
3. `gh issue list --state closed --search "closed:>LAST_RELEASE_DATE"` to find closed issues
4. Check auto-generated release notes (`gh release create --generate-notes --draft`) for community PRs and new contributors
## Step 3: Update Files
1. **package.json** - Update `version` field
2. **src/common/app.release.ts** - Increment `Monotonics.NewsVersion` (e.g., 203 → 204)
3. **src/apps/news/news.data.tsx** - Add new entry at top of `NewsItems` array
For the news entry, ask user for release name and key highlights.
**News entry style** - Draft is a starting point, user will refine:
- Models lead when model-heavy, grouped together
- Callout features get own bullet with colon explanation
- UX items grouped, minimal bold
- Fixes last, brief
- Release name stays subtle - don't oversell the theme
- Apply the draft, then let the user edit manually and re-read after - don't over-iterate
Use `<B>`, `<B issue={N}>`, `<B href='url'>`. Re-read file after user edits.
4. User runs `npm i` to update lockfile
## Step 4: README
Update `README.md`:
- Line ~46: Update model examples if new flagship models
- Line ~147: Add release bullet above previous version
**Style:** `- Open X.Y.Z: **Name** feature1, feature2, feature3`
## Step 5: Git Operations
User commits changes, then:
```bash
git tag vX.Y.Z
git push opensource vX.Y.Z
```
## Step 6: GitHub Release
Create release with `gh release create` using `--notes` (not `--body`).
**Structure** - discursive intro paragraph, then themed sections, not a generic "What's New" header:
```
# Big-AGI X.Y.Z - Name
### Theme tagline.
1-2 sentence discursive paragraph setting the release theme - what it means, not a feature list.
### Section Name (e.g., Models & Parameters)
- Bullet points for specifics
- Group by theme, not by commit order
### Vendor/Platform Section (when enough substance)
- Give a vendor its own section if 3+ related changes (e.g., Anthropic, AWS Bedrock)
### Also New
- Remaining features, scannable
## New Contributors
* @user made their first contribution (brief description) in PR_URL
**Full Changelog**: https://github.com/enricoros/big-AGI/compare/vPREV...vNEW
## Get Started
Available now at [big-agi.com](https://big-agi.com), via Docker, or self-host from source.
```
## Step 7: Changelog (big-agi.com/changes)
The Open release entry on big-agi.com/changes is lightweight - just 1-2 bullets announcing the stable release, since daily entries already covered the individual features. Use `/rel:changelog` to generate.
**Style:** `- Open X.Y.Z Name stable release on GitHub and Docker`
followed by 1 bullet summarizing what landed in the final days since the last daily entry.
## Step 8: Announcements
Draft for user to post:
**Twitter** - Thematic, not feature dumps. Talk about what it means, not what it lists:
```
Big-AGI Open X.Y.Z is out!
[Theme - e.g., "Lots of love to models: native support, latest protocols, total configuration - puts you in control."]
[One more angle, natural prose]
[Optional link]
```
**Discord** - Structured with bold headers:
```
## :partyblob: Big-AGI **Open** X.Y.Z
**Category:** Items
**Category:** Items
**More:** Count of commits/fixes
```
## Step 9: Cover Image Prompts
Offer cover image prompt alternatives for the release. Read past prompts from `news.data.tsx` comments (lines ~24-37) for the pattern.
**Pattern:** Always a capybara sculpture made of crystal glass, wearing rayban-like oversized black sunglasses. Each release has a unique theme/activity that symbolizes the release.
**Shared prefix:** `High-key white scene, very clean, hero framing. A close-up photo of a capybara sculpture made of crystal glass. The capybara wears rayban-like oversized black sunglasses.`
**Also offer future release concepts** tied to vision vectors from `kb/vision-inlined.md` (e.g., agency, inhabitation, sculpting, safe exploration).
## Tone Guide
**Good:**
- "Lots of love to models: native support, latest protocols, total configuration"
- "UX quality of life improvements, from Google Drive to message reorder"
- "Gemini 3 Flash support with 4-level thinking: high, medium, low, minimal"
**Bad:**
- "Rolling out the red carpet for top models!" (too salesy)
- "Enhanced and streamlined the robust model experience" (corporate speak)
- "Added support for Gemini 3 Flash model with multiple thinking levels" (verb prefix, vague)
## Reference
Find previous copy at:
- **GitHub releases:** https://github.com/enricoros/big-AGI/releases
- **News entries:** `src/apps/news/news.data.tsx`
- **README:** `README.md` release notes section
- **Changelog:** https://big-agi.com/changes
Match the existing tone - professional but human, specific not generic, features not marketing.
+43 -9
View File
@@ -1,23 +1,38 @@
#!/usr/bin/env node
/**
* Parse Ollama featured models from HTML
* Parse Ollama models from HTML (sorted by newest for stable ordering)
*
* Usage:
* 1. Fetch HTML: curl -s "https://ollama.com/library?sort=featured" -o /tmp/ollama-featured.html
* 1. Fetch HTML: curl -s "https://ollama.com/library?sort=newest" -o /tmp/ollama-newest.html
* 2. Parse: node .claude/scripts/parse-ollama-models.js
*
* Outputs: pipe-delimited format: modelName|pulls|capabilities|sizes
* Example: deepseek-r1|66200000|tools,thinking|1.5b,7b,8b,14b,32b,70b,671b
*
* Filtering rules:
* - Top 30 newest models are always included (regardless of pull count)
* - After top 30, only models with 50K+ pulls are included
* - Models with 'cloud' capability are always excluded
* - Models with 'embedding' capability are always excluded
*
* Pull counts are rounded to significant figures for stable diffs:
* - >=10M: round to 100K (e.g., 109,123,456 -> 109,100,000)
* - >=1M: round to 10K (e.g., 5,432,100 -> 5,430,000)
* - <1M: round to 1K (e.g., 88,700 -> 89,000)
*/
const fs = require('fs');
const os = require('os');
const path = require('path');
const htmlPath = process.argv[2] || '/tmp/ollama-featured.html';
const htmlPath = process.argv[2] || path.join(os.tmpdir(), 'ollama-newest.html');
const TOP_N_ALWAYS_INCLUDE = 30;
const MIN_PULLS_THRESHOLD = 50000;
if (!fs.existsSync(htmlPath)) {
console.error(`Error: HTML file not found at ${htmlPath}`);
console.error('Please fetch it first with:');
console.error(' curl -s "https://ollama.com/library?sort=featured" -o /tmp/ollama-featured.html');
console.error(' curl -s "https://ollama.com/library?sort=newest" -o /tmp/ollama-newest.html');
process.exit(1);
}
@@ -25,7 +40,7 @@ const html = fs.readFileSync(htmlPath, 'utf8');
// Split into model sections - each starts with <a href="/library/
const modelSections = html.split(/<a href="\/library\//);
const models = [];
const allParsedModels = [];
for (let i = 1; i < modelSections.length; i++) {
const section = modelSections[i].substring(0, 5000); // Large enough window to capture all data
@@ -65,10 +80,27 @@ for (let i = 1; i < modelSections.length; i++) {
sizes.push(sizeMatch[1].trim());
}
// Only include models with 50K+ pulls
if (pulls >= 50000) {
models.push({ name, pulls, capabilities, sizes });
// Skip models with 'cloud' or 'embedding' capability
if (capabilities.includes('cloud') || capabilities.includes('embedding')) {
continue;
}
allParsedModels.push({ name, pulls: roundPulls(pulls), capabilities, sizes });
}
// Apply filtering: top 30 always included, rest need 50K+ pulls
const models = allParsedModels.filter((model, index) => {
return index < TOP_N_ALWAYS_INCLUDE || model.pulls >= MIN_PULLS_THRESHOLD;
});
/**
* Round pulls to significant figures for stable output.
* This reduces churn from daily fluctuations while preserving magnitude.
*/
function roundPulls(pulls) {
if (pulls >= 10000000) return Math.round(pulls / 100000) * 100000; // >=10M: round to 100K
if (pulls >= 1000000) return Math.round(pulls / 10000) * 10000; // >=1M: round to 10K
return Math.round(pulls / 1000) * 1000; // <1M: round to 1K
}
// Output in pipe-delimited format (in the order they appear on the page)
@@ -78,4 +110,6 @@ models.forEach(m => {
console.log(`${m.name}|${m.pulls}|${caps}|${tags}`);
});
console.error(`\nTotal models with 50K+ pulls: ${models.length}`);
const topNCount = Math.min(TOP_N_ALWAYS_INCLUDE, allParsedModels.length);
const thresholdCount = models.length - topNCount;
console.error(`\nTotal models: ${models.length} (top ${topNCount} newest + ${thresholdCount} with ${MIN_PULLS_THRESHOLD / 1000}K+ pulls)`);
+15 -1
View File
@@ -3,23 +3,37 @@
"allow": [
"Bash(cat:*)",
"Bash(cp:*)",
"Bash(curl:*)",
"Bash(eslint:*)",
"Bash(find:*)",
"Bash(gh issue list:*)",
"Bash(gh issue view:*)",
"Bash(git branch:*)",
"Bash(git cherry-pick:*)",
"Bash(git describe:*)",
"Bash(git grep:*)",
"Bash(git log:*)",
"Bash(git log:*)",
"Bash(git ls-tree:*)",
"Bash(git mv:*)",
"Bash(git show:*)",
"Bash(grep:*)",
"Bash(head:*)",
"Bash(ls:*)",
"Bash(mkdir:*)",
"Bash(node:*)",
"Bash(npm install)",
"Bash(npm install:*)",
"Bash(npm run:*)",
"Bash(npx eslint:*)",
"Bash(npx tsc:*)",
"Bash(rg:*)",
"Bash(rm:*)",
"Bash(sed:*)",
"Bash(tail:*)",
"Bash(tree:*)",
"Bash(tsc:*)",
"Read(//tmp/**)",
"Skill(llms:update-models*)",
"WebFetch",
"WebFetch(domain:big-agi.com)",
"WebSearch",
+15 -40
View File
@@ -1,43 +1,18 @@
# big-AGI non-code files
/docs/
/dist/
README.md
*
# Ignore build and log files
Dockerfile
/.dockerignore
!app/
!kb/
!pages/
!public/
!src/
!tools/
# Node build artifacts
/node_modules
/.pnp
.pnp.js
!*.mjs
!middleware_BASIC_AUTH.ts
!middleware.ts
!next.config.ts
!package*.json
!tsconfig.json
# next.js
/.next/
/out/
# production
/build
# versioning
.git/
.github/
# IDEs
.idea/
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
!LICENSE
!README.md
-3
View File
@@ -1,3 +0,0 @@
{
"extends": "next/core-web-vitals"
}
+70
View File
@@ -0,0 +1,70 @@
name: 🔥 Make AI Fix This
description: Bug, question, or feedback - AI analyzes and changes Big-AGI appropriately
labels: [ 'claude-triage' ]
body:
- type: markdown
attributes:
value: |
Thanks for opening an issue! Our AI will analyze it and change Big-AGI appropriately.
**What happens next:**
- AI searches the codebase and documentation
- You get a response, typically within 30 minutes
- Ticket gets follow-up and community votes
- type: textarea
attributes:
label: What's happening?
description: Describe the bug, feature request, or question. Be as detailed as you can.
placeholder: |
Bug example: "In Beam, Anthropic models seem to have search off..."
Model request: "Add Claude Opus 4.5 out today, see https://..."
Feature example: "Add the option to to save frequent prompt templates for reuse..."
validations:
required: true
- type: dropdown
attributes:
label: Where does this happen?
description: If this is a bug or issue, where are you experiencing it?
options:
- Big-AGI Pro (big-agi.com)
- Self-deployed from GitHub
- Docker deployment
- Local development
- Not applicable (question/feedback)
- Other
validations:
required: false
- type: dropdown
attributes:
label: Impact on your workflow
description: How does this affect your use of Big-AGI?
options:
- Blocking - Can't use Big-AGI
- High - Major feature broken
- Medium - Workaround exists
- Low - Minor inconvenience
- None - Just a question/suggestion
validations:
required: false
- type: textarea
attributes:
label: Environment (if applicable)
description: Device, OS, browser - only if reporting a bug
placeholder: |
Device: Macbook Pro M3
OS: macOS 15.2
Browser: Chrome 131
validations:
required: false
- type: textarea
attributes:
label: Additional context
description: Screenshots, error messages, or anything else that helps
placeholder: Paste screenshots or error messages here
validations:
required: false
+69
View File
@@ -0,0 +1,69 @@
version: 2
updates:
- package-ecosystem: docker
directory: /
schedule:
interval: weekly
commit-message:
prefix: "chore(deps)"
ignore:
- dependency-name: "node"
versions: [">=25", "<26"] # Node 25 breaks the build because of a dummy localStorage object
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
commit-message:
prefix: "chore(deps)"
# Disabled npm updates for now - will need precise package pinning, as some packages changed behavior upstream
# - package-ecosystem: npm
# directory: /
# schedule:
# interval: weekly
# commit-message:
# prefix: "chore(deps)"
# cooldown:
# semver-patch: 3
# semver-minor: 7
# semver-major: 14
# # Ignore packages intentionally pinned due to upstream issues
# ignore:
# # Issue #857: v11.6+ breaks streaming; tried 11.4.4/11.6/11.7, only 11.5.1 works
# - dependency-name: "@trpc/*"
# versions: [">=11.5.1", "<12"]
# # Pinned during tRPC #857 debugging - may be safe to unpin, test first
# - dependency-name: "@tanstack/react-query"
# versions: [">=5.90.10", "<6"]
# # Pinned because 5.0.8 changes signatures so return set({ .. }) != void;
# - dependency-name: "zustand"
# versions: [">=5.0.7", "<6"]
# groups:
# next:
# patterns:
# - "@next/*"
# - "eslint-config-next"
# - "next"
# react:
# patterns:
# - "react"
# - "react-dom"
# - "@types/react"
# - "@types/react-dom"
# emotion:
# patterns:
# - "@emotion/*"
# mui:
# patterns:
# - "@mui/*"
# dnd-kit:
# patterns:
# - "@dnd-kit/*"
# prisma:
# patterns:
# - "@prisma/*"
# - "prisma"
# vercel:
# patterns:
# - "@vercel/*"
+14 -12
View File
@@ -12,27 +12,30 @@ on:
jobs:
claude-dm:
# Only allow repository owner to trigger DMs with @claude (blocks other users and bots)
if: |
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) ||
github.actor == 'enricoros' &&
github.triggering_actor == 'enricoros' &&
((github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude'))
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')))
runs-on: ubuntu-latest
timeout-minutes: 20
timeout-minutes: 30
permissions:
contents: read
pull-requests: write
contents: write # Required for code creation and commits
issues: write
id-token: write
pull-requests: write
actions: read # Required for Claude to read CI results on PRs
id-token: write # required to use OIDC to authenticate to Claude Code API
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-depth: 0 # 1 -> 0: full history helps with git blame, etc.
- name: Run Claude Code DM Response
id: claude
@@ -41,6 +44,7 @@ jobs:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Security: Only users with write access can trigger (DMs allow code execution)
# Note: contents:write permission enables code creation and commits
# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
@@ -49,9 +53,7 @@ jobs:
# Optional: Add claude_args to customize behavior and configuration
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
# claude_args: '--allowed-tools Bash(gh pr:*)'
# disabling opus for now claude-opus-4-1-20250805
claude_args: |
--model claude-sonnet-4-5-20250929
--model claude-opus-4-6
--max-turns 100
--allowedTools "Edit,Read,Write,WebFetch,WebSearch,Bash(cat:*),Bash(cp:*),Bash(find:*),Bash(git branch:*),Bash(grep:*),Bash(ls:*),Bash(mkdir:*),Bash(npm install),Bash(npm install:*),Bash(npm run:*),Bash(gh issue:*),Bash(gh search:*),Bash(gh label:*),Bash(gh pr:*),mcp__chrome-devtools,SlashCommand"
--allowedTools "Edit,Read,Write,WebFetch,WebSearch,Bash(cat:*),Bash(cp:*),Bash(find:*),Bash(git branch:*),Bash(grep:*),Bash(ls:*),Bash(mkdir:*),Bash(npm run:*),Bash(gh issue:*),Bash(gh search:*),Bash(gh label:*),Bash(gh pr:*),SlashCommand"
+23 -11
View File
@@ -2,7 +2,7 @@ name: Claude Code Auto-Triage Issues
on:
issues:
types: [ opened, assigned ]
types: [ opened ]
jobs:
claude-issue-triage:
@@ -12,19 +12,20 @@ jobs:
!contains(github.event.issue.body, '@claude')
runs-on: ubuntu-latest
timeout-minutes: 20
timeout-minutes: 30
permissions:
contents: read
issues: write
pull-requests: read
id-token: write
pull-requests: read # was write, but we're not altering PRs here
actions: read
id-token: write # required to use OIDC to authenticate to Claude Code API
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-depth: 0 # 1 -> 0: full history helps with git blame, etc.
- name: Analyze issue and provide help
uses: anthropics/claude-code-action@v1
@@ -34,6 +35,11 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: '*'
# track_progress: true # Enables tracking comments
show_full_output: ${{ github.event.repository.private }} # security: do not log verbosely in private repo
# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read
prompt: |
REPO: ${{ github.repository }}
@@ -49,9 +55,11 @@ jobs:
**Use web search**: When potentially outside Big-AGI (e.g. user configuration), search the web for similar errors or related issues
**Provide a solution**:
- Provide multiple solutions if uncertain, and say so
- If you can fix it in code, propose the fix
- If possible also suggest fixes or workarounds for immediate relief
- Analyze the code and suggest specific fixes with code examples
- If possible also suggest fixes or workarounds for immediate relief
- Reference specific files and line numbers
- Suggest workarounds for immediate relief if applicable
- Use web search to find similar issues and solutions
- Test selectively and even npm install and run build if needed to verify the solution
2. Always add the 'claude-triage' issue label to indicate this issue was triaged by Claude
3. Comment with:
@@ -60,12 +68,16 @@ jobs:
- Next steps or clarification needed
- Link duplicates if found
Remember: design values for this codebase: orthogonal features, features that generalize well, modularized and reusable code,
type-discriminated data, optimized code, zero maintenance burden. Minimize future pain, etc.
IMPORTANT: You are in READ-ONLY triage mode. Analyze and suggest solutions in your comment, but do NOT attempt to push code changes.
If you're uncertain, say so and suggest next steps.
Be welcoming, helpful, professional, solution-focused and no-BS.
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
claude_args: |
--model claude-sonnet-4-5-20250929
--max-turns 60
--allowedTools "Edit,Read,Write,WebFetch,WebSearch,Bash(cat:*),Bash(cp:*),Bash(find:*),Bash(git branch:*),Bash(grep:*),Bash(ls:*),Bash(mkdir:*),Bash(npm install),Bash(npm install:*),Bash(npm run:*),Bash(gh issue:*),Bash(gh search:*),Bash(gh label:*),Bash(gh pr:*),mcp__chrome-devtools,SlashCommand"
--model claude-opus-4-6
--max-turns 75
--allowedTools "Edit,Read,Write,WebFetch,WebSearch,Bash(cat:*),Bash(cp:*),Bash(find:*),Bash(git branch:*),Bash(grep:*),Bash(ls:*),Bash(mkdir:*),Bash(npm run:*),Bash(gh issue:*),Bash(gh search:*),Bash(gh label:*),Bash(gh pr:*),SlashCommand"
-77
View File
@@ -1,77 +0,0 @@
name: Claude Code PR Review
on:
pull_request:
types: [ opened, synchronize, ready_for_review ]
# Limit branches
branches: [ main, dev, v1 ]
# Optional: Only run on specific file changes
# paths:
# - "src/**/*.ts"
# - "src/**/*.tsx"
jobs:
claude-pr-review:
# Skip draft PRs
# Optional: filter authors: github.event.pull_request.user.login != 'enricoros'
if: |
github.event.pull_request.draft == false
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
pull-requests: write
issues: read
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run PR Review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Security: Allow any user to trigger reviews (read-only PR analysis is safe)
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: '*'
# track_progress: true # Enables tracking comments
# This setting allows Claude to read CI results on PRs
additional_permissions: |
actions: read
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
Please review this pull request and provide feedback on:
- Potential bugs or issues
- Adherence to Big-AGI architecture and design patterns
- Code quality and best practices, including TypeScript types, error handling, and edge cases
- Performance considerations: bundle size, React patterns, streaming efficiency
- Security concerns if applicable
Use the repository's CLAUDE.md for guidance on style and conventions.
Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
Use `gh pr review comment` for inline suggestions on specific lines.
IMPORTANT: After completing your review, always add the 'claude-review' label to the PR to indicate it was reviewed by Claude:
gh pr edit ${{ github.event.pull_request.number }} --add-label "claude-review"
Be constructive, helpful, no-BS, and specific with file:line references.
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
claude_args: |
--model claude-sonnet-4-5-20250929
--max-turns 100
--allowedTools "Edit,Read,Write,WebFetch,WebSearch,Bash(cat:*),Bash(cp:*),Bash(find:*),Bash(git branch:*),Bash(grep:*),Bash(ls:*),Bash(mkdir:*),Bash(npm install),Bash(npm install:*),Bash(npm run:*),Bash(gh issue:*),Bash(gh search:*),Bash(gh label:*),Bash(gh pr:*),mcp__chrome-devtools"
+120 -36
View File
@@ -20,28 +20,122 @@ env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Build job: runs on native runners for each platform (no QEMU emulation)
build:
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
name: Build ${{ matrix.platform }}
timeout-minutes: 30
permissions:
contents: read
packages: write
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
echo "IMAGE_NAME_LC=${IMAGE_NAME,,}" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.title=Big-AGI Open
org.opencontainers.image.description=Big-AGI Open - Multi-model AI workspace for experts who need to think broader, decide smarter, and build with confidence.
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.documentation=https://big-agi.com
- name: Build and push by digest
id: build
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
file: Dockerfile
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}
build-args: |
NEXT_PUBLIC_GA4_MEASUREMENT_ID=${{ secrets.GA4_MEASUREMENT_ID }}
NEXT_PUBLIC_BUILD_HASH=${{ github.sha }}
NEXT_PUBLIC_BUILD_REF_NAME=${{ github.ref_name }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true
provenance: false
cache-from: type=gha,scope=${{ github.repository }}-${{ matrix.platform }}
cache-to: type=gha,scope=${{ github.repository }}-${{ matrix.platform }},mode=max
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
# Merge job: combines platform-specific images into a unified multi-arch manifest
merge:
name: Merge manifests
runs-on: ubuntu-latest
timeout-minutes: 10
needs: build
permissions:
contents: read
packages: write
steps:
- name: Prepare
run: echo "IMAGE_NAME_LC=${IMAGE_NAME,,}" >> $GITHUB_ENV
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Log in to the Container registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -49,7 +143,7 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -65,28 +159,18 @@ jobs:
# Version tags (v2.0.0, 2.0.0)
type=ref,event=tag
type=semver,pattern={{version}}
labels: |
org.opencontainers.image.title=Big-AGI Open
org.opencontainers.image.description=Big-AGI Open - Multi-model AI workspace for experts who need to think broader, decide smarter, and build with confidence.
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.documentation=https://big-agi.com
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
NEXT_PUBLIC_GA4_MEASUREMENT_ID=${{ secrets.GA4_MEASUREMENT_ID }}
NEXT_PUBLIC_BUILD_HASH=${{ github.sha }}
NEXT_PUBLIC_BUILD_REF_NAME=${{ github.ref_name }}
# Enable build cache (future)
#cache-from: type=gha
#cache-to: type=gha,mode=max
# Enable provenance and SBOM (future)
#provenance: true
#sbom: true
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
--annotation='index:org.opencontainers.image.title=Big-AGI Open' \
--annotation='index:org.opencontainers.image.description=Big-AGI Open - Multi-model AI workspace for experts who need to think broader, decide smarter, and build with confidence.' \
--annotation='index:org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}' \
--annotation='index:org.opencontainers.image.documentation=https://big-agi.com' \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}:${{ steps.meta.outputs.version }}
+3
View File
@@ -53,3 +53,6 @@ next-env.d.ts
.env*.local
/.run/dev (ENV).run.xml
/src/modules/3rdparty/aider/scratch*
# Ignore temporary CC files
/tmpclaude*
-3
View File
@@ -1,3 +0,0 @@
overrides=@mui/material@^5.0.0:
dependencies:
@mui/material: replaced-by=@mui/joy
+1
View File
@@ -0,0 +1 @@
24
Symlink
+1
View File
@@ -0,0 +1 @@
CLAUDE.md
+92 -94
View File
@@ -1,22 +1,44 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Guidance to Claude Code when working with code in this repository.
## Development Commands
```bash
# Targeted Code Quality (safe while dev server runs)
npx tsc --noEmit # Type check without building
npx eslint src/path/to/file.ts # Lint specific file
npm run lint # Lint entire project
```
## Architecture Overview
Big-AGI is a Next.js 15 application with a modular architecture built for advanced AI interactions. The codebase follows a three-layer structure with distinct separation of concerns.
Big-AGI is a Next.js 15 application with a sophisticated modular architecture built for professional AI interactions.
### Development Commands
Dev servers may be already running on ports 3000, 3001, 3002, or 3003 (not always this app - other projects may occupy these ports). Never start or stop dev servers, let the user do it.
```bash
# Validate (~5s, safe while dev server runs, do NOT use `next build` ~45s for same checks)
tsc --noEmit --pretty && npm run lint # Type check (~3.5s) + ESLint (~2s)
eslint src/path/to/file.ts # Lint specific file
# Full build (~60s+, only when suspecting runtime/bundle issues)
npm run build # next build runs compile+lint+types but stops at first type-error file; tsc shows all at once
# Database & External Services
# npm run supabase:local-update-types # Generate TypeScript types
# npm run stripe:listen # Listen for Stripe webhooks
```
### Git/GitHub remotes
The `gh` command is available to interact with GitHub from the terminal, but **NEVER PUSH TO ANY BRANCH**. The user manages all 'write' git operations.
- `opensource` -> `enricoros/big-AGI` (public, default branch: `main`, MIT) - community issues/PRs/releases
- `private` -> `big-agi/big-agi-private` (private, default branch: `dev`) - main dev repo with `dev`->`staging`->`prod` pipeline
- **Always use `git mv` instead of `mv`** when renaming or moving files - preserves git history tracking
- **NEVER run `git stash`** - it causes work loss
### Core Directory Structure
You are started from the root of the repository (i.e. where the git folder is or scripts should be run from).
**ISSUE ALL COMMANDS FROM THE ROOT, OMITTING 'cd' COMMANDS. DO NOT CHAIN CD AND OTHER COMMANDS**
**NEVER RUN COMPOUND `cd` COMMANDS LIKE `cd some-folder && command` - ONLY RUN `command` FROM THE ROOT, ALWAYS.**
The directory structure is as follows:
```
/app/api/ # Next.js App Router (API routes only, mostly -> /src/server/)
/pages/ # Next.js Pages Router (file-based, mostly -> /src/apps/)
@@ -31,11 +53,11 @@ Big-AGI is a Next.js 15 application with a modular architecture built for advanc
### Key Technologies
- **Frontend**: Next.js 15, React 18, Material-UI Joy, Emotion (CSS-in-JS)
- **State Management**: Zustand with localStorge/IndexedDB (single cell) persistence
- **API Layer**: tRPC with React Query for type-safe communication
- **State Management**: Zustand with localStorage/IndexedDB (single cell) persistence
- **API Layer**: tRPC with TanStack React Query for type-safe communication
- **Runtime**: Edge Runtime for AI operations, Node.js for data processing
### Apps Architecture Pattern
### "Apps" Architecture Pattern
Each app in `/src/apps/` is a self-contained feature module:
- Main component (`App*.tsx`)
@@ -51,20 +73,20 @@ Modules in `/src/modules/` provide reusable business logic:
- **`aix/`** - AI communication framework for real-time streaming
- **`beam/`** - Multi-model AI reasoning system (scatter/gather pattern)
- **`blocks/`** - Content rendering (markdown, code, images, etc.)
- **`llms/`** - Language model abstraction supporting 16 vendors
- **`llms/`** - Language model abstraction supporting 20+ vendors
### Key Subsystems & Their Patterns
#### 1. AIX - Real-time AI Communication
#### AIX - Real-time AI Communication
**Location**: `/src/modules/aix/`
**Pattern**: Client-server streaming architecture with provider abstraction
- **Client** tRPC **Server** **AI Providers**
- **Client** -> tRPC -> **Server** -> **AI Providers**
- Handles streaming/non-streaming responses with batching and error recovery
- Particle-based streaming: `AixWire_Particles` `ContentReassembler` `DMessage`
- Particle-based streaming: `AixWire_Particles` -> `ContentReassembler` -> `DMessage`
- Provider-agnostic through adapter pattern (OpenAI, Anthropic, Gemini protocols)
#### 3. Beam - Multi-Model Reasoning
#### Beam - Multi-Model Reasoning
**Location**: `/src/modules/beam/`
**Pattern**: Scatter/Gather for parallel AI processing
@@ -73,15 +95,24 @@ Modules in `/src/modules/` provide reusable business logic:
- Real-time UI updates via vanilla Zustand stores
- BeamStore per conversation via ConversationHandler
#### 4. Conversation Management
#### Conversation Management
**Location**: `/src/common/stores/chat/` and `/src/common/chat-overlay/`
**Pattern**: Overlay architecture with handler per conversation
- `ConversationHandler` orchestrates chat, beam, ephemerals
- Per-chat stores: `PerChatOverlayStore` + `BeamStore`
- Message structure: `DMessage` `DMessageFragment[]`
- Message structure: `DMessage` -> `DMessageFragment[]`
- Supports multi-pane with independent conversation states
#### Layout System ("Optima")
The Optima layout system provides:
- **Responsive design** adapting desktop/mobile
- **Drawer(left)/Toolbar/Panel(right)** composition
- **Portal-based rendering** for flexible component placement
Located in `/src/common/layout/optima/`
### Storage System
Big-AGI uses a local-first architecture with Zustand + IndexedDB:
@@ -89,7 +120,6 @@ Big-AGI uses a local-first architecture with Zustand + IndexedDB:
- **localStorage** for persistent settings/all storage (via Zustand persist middleware)
- **IndexedDB** for persistent chat-only storage (via Zustand persist middleware) on a single key-val cell
- **Local-first** architecture with offline capability
- **Migration system** for upgrading data structures across versions
Key storage patterns:
- Stores use `createIDBPersistStorage()` for IndexedDB persistence
@@ -101,26 +131,18 @@ Located in `/src/common/stores/` with stores like:
- `chat/store-chats.ts`: Conversations and messages
- `llms/store-llms.ts`: Model configurations
### Layout System ("Optima")
The Optima layout system provides:
- **Responsive design** adapting desktop/mobile
- **Drawer/Panel/Toolbar** composition
- **Split-pane support** for multi-conversation views
- **Portal-based rendering** for flexible component placement
Located in `/src/common/layout/optima/`
### State Management Patterns
1. **Global Stores** (Zustand with IndexedDB persistence)
- `store-chats`: Conversations and messages
- `store-llms`: Model configurations
- `store-ux-labs`: UI preferences and labs features
- **Zustand pattern**: Always wrap multi-property selectors with `useShallow` from `zustand/react/shallow` to prevent re-renders on reference changes
2. **Per-Instance Stores** (Vanilla Zustand)
- `store-beam_vanilla`: Beam scatter/gather state
- `store-perchat_vanilla`: Chat overlay state
- `store-attachment-drafts_vanilla`: Attachment drafts
- High-performance, no React integration
3. **Module Stores**
@@ -130,94 +152,60 @@ Located in `/src/common/layout/optima/`
### User Flows & Interdependencies
#### Chat Message Flow
1. User input `Composer` `DMessage` creation
2. `ConversationHandler.messageAppend()` Store update
3. `_handleExecute()` / `ConversationHandler.executeChatMessages()` AIX client request
4. AIX streaming `ContentReassembler` UI updates
5. Zustand auto-persistence IndexedDB
1. User input -> `Composer` -> `DMessage` creation
2. `ConversationHandler.messageAppend()` -> Store update
3. `_handleExecute()` / `ConversationHandler.executeChatMessages()` -> AIX client request
4. AIX streaming -> `ContentReassembler` -> UI updates
5. Zustand auto-persistence -> IndexedDB
#### Beam Multi-Model Flow
1. User triggers Beam `BeamStore.open()` state update
1. User triggers Beam -> `BeamStore.open()` state update
2. Scatter: Parallel `aixChatGenerateContent()` to N models
3. Real-time ray updates UI progress
4. Gather: User selects fusion Combined output
5. Result New message in conversation
3. Real-time ray updates -> UI progress
4. Gather: User selects fusion -> Combined output
5. Result -> New message in conversation
### Development Patterns
#### TypeScript & Code Quality
- Type-safe through strict TypeScript interfaces
- Clear interface-first approach for modules and components
- Use latest TypeScript 5.9+ features
- Use forward-looking patterns to minimize future refactors (e.g., discriminated unions, `satisfies` operator, as const assertions)
- Type guards and exhaustiveChecks for robustness
- Type inference where possible
- Runtime validation with Zod schemas for API inputs/outputs (usually server-side, with the client importing as types the inferred types)
#### Module Integration
- Each module exports its functionality through index files
- Modules register with central registries (e.g., `vendors.registry.ts`)
- Configuration objects define module behavior
- Type-safe integration through strict TypeScript interfaces
#### Component Patterns
- **Controlled components** with clear prop interfaces
- **Hook-based logic** extraction for reusability
- **Portal rendering** for overlays and modals
- **Suspense boundaries** for async operations
#### API Patterns
- **tRPC routers** for type-safe API endpoints
- **Zod schemas** for runtime validation
- **Middleware** for request/response processing
- **Edge functions** for performance-critical AI operations
- **tRPC procedures middleware** for authorization and logging (authorization is on a httpOnly cookie)
- **Edge functions** for performance-critical operations
## Security Considerations
- API keys stored client-side in localStorage (user-provided)
- Server-side API keys in environment variables only
#### Security Considerations
- API keys in environment variables only (server-side); on the client they're in localStorage for now, but we want to move away from this
- XSS protection through proper content escaping
- No credential transmission to third parties
## Knowledge Base
#### Writing Style
- **Never use emdashes (—).** Use normal dashes (-) instead, in all generated text, code comments, and documentation.
Architecture and system documentation is available in the `/kb/` knowledge base:
@kb/KB.md
## Common Development Tasks
### Testing & Quality
- Run `npm run lint` before committing
- Type-check with `npx tsc --noEmit`
- Type-check with `tsc --noEmit`
- Test critical user flows manually
### Adding a New LLM Vendor
1. Create vendor in `/src/modules/llms/vendors/[vendor]/`
2. Implement `IModelVendor` interface
3. Register in `vendors.registry.ts`
4. Add environment variables to `env.ts` (if server-side keys needed)
### Debugging Storage Issues
- Check IndexedDB: DevTools Application IndexedDB `app-chats`
- Check IndexedDB: DevTools -> Application -> IndexedDB -> `app-chats`
- Monitor Zustand state: Use Zustand DevTools
- Check migration logs in console during rehydration
## Code Examples
### AIX Streaming Pattern
```typescript
// Efficient streaming with decimation
aixChatGenerateContent_DMessage(
llmId,
request,
{ abortSignal, throttleParallelThreads: 1 },
async (update, isDone) => {
// Real-time UI updates
}
);
```
### Model Registry Pattern
```typescript
// Registry pattern for extensibility
const MODEL_VENDOR_REGISTRY: Record<ModelVendorId, IModelVendor> = {
openai: ModelVendorOpenAI,
anthropic: ModelVendorAnthropic,
// ... 14 more vendors
};
```
## Server Architecture
@@ -225,9 +213,13 @@ The server uses a split architecture with two tRPC routers:
### Edge Network (`trpc.router-edge`)
Distributed edge runtime for low-latency AI operations:
- **AIX** - AI streaming and communication
- **LLM Routers** - Direct vendor integrations (OpenAI, Anthropic, Gemini, Ollama)
- **External Services** - ElevenLabs (TTS), Google Search, YouTube transcripts
- **AIX** [1] - AI streaming and communication
- **LLM Routers** [1] - Vendor-specific operations such as list models (OpenAI, Anthropic, Gemini, Ollama)
- **Speex** [1] - Unified TTS router (ElevenLabs, Inworld, and other TTS vendors)
- **External Services** - Google Search, YouTube transcripts
[1]: also supports client-side fetch (CSF) via client-side inclusion (rebundling with stubs),
for direct browser-to-API communication when possible (CORS), to reduce latency and network barriers
Located at `/src/server/trpc/trpc.router-edge.ts`
@@ -239,3 +231,9 @@ Centralized server for data processing operations:
Located at `/src/server/trpc/trpc.router-cloud.ts`
**Key Pattern**: Edge runtime for AI (fast, distributed), Cloud runtime for data ops (centralized, Node.js)
@kb/KB.md
@kb/vision-inlined.md
As a side note, the product tiers (independent, non-VC-funded) are: **Open** (self-host, MIT) · **Free** (big-agi.com) · **Pro** (paid, includes Sync + backup). All tiers use the user's own API keys.
+19 -10
View File
@@ -1,5 +1,8 @@
# syntax=docker/dockerfile:1
# check=skip=CopyIgnoredFile
# Base
FROM node:22-alpine AS base
FROM node:24-alpine AS base
ENV NEXT_TELEMETRY_DISABLED=1
# Dependencies
@@ -39,19 +42,20 @@ ENV NEXT_PUBLIC_GA4_MEASUREMENT_ID=${NEXT_PUBLIC_GA4_MEASUREMENT_ID}
ARG NEXT_PUBLIC_POSTHOG_KEY
ENV NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
# Optional argument to configure Google Drive Picker at build time (can reuse AUTH_GOOGLE_ID value)
ARG NEXT_PUBLIC_GOOGLE_DRIVE_CLIENT_ID
ENV NEXT_PUBLIC_GOOGLE_DRIVE_CLIENT_ID=${NEXT_PUBLIC_GOOGLE_DRIVE_CLIENT_ID}
# Copy development deps and source
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# link ssl3 for latest Alpine
RUN sh -c '[ ! -e /lib/libssl.so.3 ] && ln -s /usr/lib/libssl.so.3 /lib/libssl.so.3 || echo "Link already exists"'
# Build the application
ENV NODE_ENV=production
RUN npm run build
# Reduce installed packages to production-only
RUN npm prune --production
RUN npm prune --omit=dev
# Runner
@@ -59,18 +63,23 @@ FROM base AS runner
WORKDIR /app
# As user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 nextjs \
&& apk add --no-cache openssl
# Copy Built app
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/src/server/prisma ./src/server/prisma
# Instead of `COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next`, we only extract some parts, excluding .next/cache which is build time only:
COPY --from=builder --chown=nextjs:nodejs /app/.next/BUILD_ID ./.next/
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/.next/server ./.next/server
COPY --from=builder --chown=nextjs:nodejs /app/.next/types ./.next/types
COPY --from=builder --chown=nextjs:nodejs /app/.next/*.json ./.next/
# Minimal ENV for production
ENV NODE_ENV=production
ENV PATH=$PATH:/app/node_modules/.bin
# Run as non-root user
USER nextjs
@@ -79,4 +88,4 @@ USER nextjs
EXPOSE 3000
# Start the application
CMD ["next", "start"]
CMD ["/app/node_modules/.bin/next", "start"]
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2023-2025 Enrico Ros
Copyright (c) 2023-2026 Enrico Ros
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+171 -95
View File
@@ -1,3 +1,32 @@
<div align="center">
<img width="256" height="256" alt="Big-AGI Logo" src="https://big-agi.com/assets/logo-bright-github.svg" />
<h1><a href="https://big-agi.com">Big-AGI</a></h1>
[![Use Free ⋅ Go Pro](https://img.shields.io/badge/Use_Free-Get_Pro-d5ec31?style=for-the-badge&logo=rocket&logoColor=white&labelColor=000)](https://big-agi.com)
[![Deploy on Docker](https://img.shields.io/badge/Self--Host-Docker-blue?style=for-the-badge&logo=docker&logoColor=white&labelColor=000)](https://github.com/enricoros/big-AGI/pkgs/container/big-agi)
[![Deploy on Vercel](https://img.shields.io/badge/Vercel-Deploy-blue?style=for-the-badge&logo=vercel&logoColor=white&labelColor=000)](https://vercel.com/new/clone?repository-url=https://github.com/enricoros/big-agi)
[![Discord](https://img.shields.io/discord/1098796266906980422?style=for-the-badge&label=Discord&logo=discord&logoColor=white&labelColor=000000&color=purple)](https://discord.gg/MkH4qj2Jp9)
<br/>
[![GitHub Monthly Commits](https://img.shields.io/github/commit-activity/m/enricoros/big-agi?style=for-the-badge&x=3&logo=github&logoColor=white&label=commits&labelColor=000&color=green)](https://github.com/enricoros/big-agi/commits)
[![GHCR Pulls](https://img.shields.io/badge/ghcr.io-800k_dl-12b76a?style=for-the-badge&logo=Xdocker&logoColor=white&labelColor=000&color=A8E6CF)](https://github.com/enricoros/big-AGI/pkgs/container/big-agi)
[![Contributors](https://img.shields.io/github/contributors/enricoros/big-agi?style=for-the-badge&x=2&logo=Xgithub&logoColor=white&label=cooks&labelColor=000&color=A8E6CF)](https://github.com/enricoros/big-AGI/graphs/contributors)
[![License: MIT](https://img.shields.io/badge/License-MIT-A8E6CF?style=for-the-badge&labelColor=000)](https://opensource.org/licenses/MIT)
<br/>
[![Open an Issue](https://img.shields.io/badge/Open_Issue-AI_Will_Help-ff8c00?style=for-the-badge&logo=fireship&logoColor=fff&labelColor=8b0000)](https://github.com/enricoros/big-agi/issues/new?template=ai-triage.yml)
[//]: # ([![Uptime Robot ratio &#40;30 days&#41;]&#40;https://img.shields.io/uptimerobot/ratio/m801796948-868b22ed7ceaa0acac4dc765?style=for-the-badge&labelColor=000&color=green&#41;]&#40;https://stats.uptimerobot.com/59MXcnmjrM&#41;)
[//]: # ([![Open Version]&#40;https://img.shields.io/github/v/release/enricoros/big-AGI?label=Open+Release&style=flat-square&logo=github&logoColor=white&labelColor=000&#41;]&#40;https://github.com/enricoros/big-AGI/releases/latest&#41;)
[//]: # (![GitHub Stars]&#40;https://img.shields.io/github/stars/enricoros/big-agi?style=flat-square&logo=github&logoColor=white&labelColor=000&color=yellow&#41;)
[//]: # ([![GitHub Forks]&#40;https://img.shields.io/github/forks/enricoros/big-agi?style=flat-square&logo=github&logoColor=white&labelColor=000&#41;]&#40;#&#41;)
[//]: # ([![Follow on X]&#40;https://img.shields.io/twitter/follow/enricoros?style=flat-square&logo=X&logoColor=white&labelColor=000&color=000&#41;]&#40;https://x.com/enricoros&#41;)
</div>
<br/>
# Big-AGI Open 🧠
This is the open-source foundation of **Big-AGI**, ___the multi-model AI workspace for experts___.
@@ -8,18 +37,71 @@ You need to think broader, decide faster, and build with confidence, then you ne
It comes packed with **world-class features** like Beam, and is praised for its **best-in-class AI chat UX**.
**As an independent, non-VC-funded project, Pro subscriptions at $10.99/mo fund development for everyone, including the free and open-source tiers.**
**What makes Big-AGI different:**
**Intelligence**: with [Beam & Merge](https://big-agi.com/beam) for multi-model de-hallucination, native search, and bleeding-edge AI models like Nano Banana, or GPT-5 Pro -
**Control**: with personas, data ownership, requests inspection, unlimited usage with API keys, and *no vendor lock-in* -
![LLM Vendors](https://img.shields.io/badge/20+_LLM_Services-500+_Models-black?style=for-the-badge&logo=anthropic&logoColor=white&labelColor=purple)&nbsp;
[![Feature Beam](https://img.shields.io/badge/AI--Validation-BEAM-000?style=for-the-badge&labelColor=purple)](https://big-agi.com/beam)&nbsp;
[![Feature Inspector](https://img.shields.io/badge/Expert_Mode-AI_Inspector-000?style=for-the-badge&labelColor=purple)](https://big-agi.com/inspector)
### What makes Big-AGI different:
**Intelligence**: with [Beam & Merge](https://big-agi.com/beam) for multi-model de-hallucination, native search, and bleeding-edge AI models like Opus 4.7, Nano Banana Pro, Kimi K2.6 or GPT 5.4 -
**Control**: with personas, data ownership, requests inspection, unlimited usage with API keys, and *no vendor lock-in* -
and **Speed**: with a local-first, over-powered, zero-latency, madly optimized web app.
**Who uses Big-AGI:**
<table>
<tr>
<td align="center" width="25%">
<b>🧠 Intelligence</b><br/>
<img src="https://img.shields.io/badge/Multi--Model-Trust-4285F4?style=for-the-badge" alt="Multi-Model"/>
</td>
<td align="center" width="25%">
<b>✨ Experience</b><br/>
<img src="https://img.shields.io/badge/Clean-UX-34A853?style=for-the-badge" alt="Clean UX"/>
</td>
<td align="center" width="25%">
<b>⚡ Performance</b><br/>
<img src="https://img.shields.io/badge/Zero-Latency-EA4335?style=for-the-badge" alt="Zero Latency"/>
</td>
<td align="center" width="25%">
<b>🔒 Control</b><br/>
<img src="https://img.shields.io/badge/No-Lock--in-FBBC04?style=for-the-badge" alt="No Lock-in"/>
</td>
</tr>
<tr>
<td align="center" valign="top">
Beam & Merge<br/>
No context junk<br/>
Purest AI outputs
</td>
<td align="center" valign="top">
Flow-state interface<br/>
Highly customizable<br/>
Best-in-class UX
</td>
<td align="center" valign="top">
Local-first<br/>
Highly parallel<br/>
Madly optimized
</td>
<td align="center" valign="top">
No vendor lock-in<br/>
Your API keys<br/>
AI Inspector
</td>
</tr>
</table>
### Who uses Big-AGI:
Loved by engineers, founders, researchers, self-hosters, and IT departments for its power, reliability, and transparency.
<img width="830" height="370" alt="image" src="https://github.com/user-attachments/assets/513c4f77-0970-4a56-b23b-1416c8246174" />
Choose Big-AGI because you don't need another clone or slop - you need an AI tool that scales with you.
### Show me a screenshot:
Sure - here is real-world screeengrab as I'm writing this, while running a Beam to extract SVG from an image with Sonnet 4.5, Opus 4.1, GPT 5.1, Gemini 2.5 Pro, Nano Banana, etc.
<img alt="Real-world screen capture as of Nov 15 2025, 2am" src="https://github.com/user-attachments/assets/853f4160-27cb-4ac9-826b-402f1e63d4af" />
## Get Started
| Tier | Best For | What You Get | Setup |
@@ -31,15 +113,12 @@ Choose Big-AGI because you don't need another clone or slop - you need an AI too
\*: **Configuration requires your API keys**. *Big-AGI does not charge for model usage or limit your access*.
**Why Pro?** As an independent project, Pro subscriptions fund all development. Early subscribers shape the roadmap directly.
<a href="https://big-agi.com">
<img width="210" height="68" alt="image" src="https://github.com/user-attachments/assets/b2f8a7b8-415f-4c92-b228-4f5a54fe2bdd" />
</a>
[![Use Free ⋅ Go Pro](https://img.shields.io/badge/Use_Free-Get_Pro-d5ec31?style=for-the-badge&logo=rocket&logoColor=white&labelColor=000)](https://big-agi.com)
**Self-host and developers** (full control)
- Develop locally or self-host with Docker on your own infrastructure [guide](docs/installation.md)
- Or fork & run on Vercel:
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fenricoros%2Fbig-AGI&env=OPENAI_API_KEY&envDescription=Backend%20API%20keys%2C%20optional%20and%20may%20be%20overridden%20by%20the%20UI.&envLink=https%3A%2F%2Fgithub.com%2Fenricoros%2Fbig-AGI%2Fblob%2Fmain%2Fdocs%2Fenvironment-variables.md&project-name=big-AGI)
- Or fork & run on Vercel:
[![Deploy on Vercel](https://img.shields.io/badge/Deploy-black?style=for-the-badge&logo=vercel&logoColor=white&labelColor=000)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fenricoros%2Fbig-AGI&env=OPENAI_API_KEY&envDescription=Backend%20API%20keys%2C%20optional%20and%20may%20be%20overridden%20by%20the%20UI.&envLink=https%3A%2F%2Fgithub.com%2Fenricoros%2Fbig-AGI%2Fblob%2Fmain%2Fdocs%2Fenvironment-variables.md&project-name=big-AGI)
[//]: # (**For the latest Big-AGI:**)
@@ -60,9 +139,16 @@ so you **are not vendor locked-in**, and obsessed over a powerful UI that works,
NOTE: this is a powerful tool - if you need a toy UI or clone, this ain't it.
## What's New in 2.0 · Oct 31, 2025 · Open
---
👉 **[See the full changelog](https://big-agi.com/changes)**
## Release Notes
👉 **[See the Live Release Notes](https://big-agi.com/changes)**
- Open 2.0.4: **Hyper Params** **Opus 4.6**, **GPT-5.4**, **Gemini 3.1 Pro**, AWS Bedrock, parameter accuracy, Anthropic continuation/Fast mode
- Open 2.0.3: **Red Carpet** **Kimi K2.5**, **Gemini 3 Flash**, **GPT 5.2**, Google Drive, Inworld, Novita.ai, Speech/UX improvements
- Open 2.0.2: **Speex** multi-vendor speech synthesis, **Opus 4.5**, **Gemini 3 Pro**, **Nano Banana Pro**, **Grok 4.1**, **GPT-5.1**, **Kimi K2** + 280 fixes
### What's New in 2.0 · Oct 31, 2025 · Open
- **Big-AGI Open** is ready and more productive and faster than ever, with:
- **Beam 2**: multi-modal, program-based, follow-ups, save presets
@@ -75,7 +161,7 @@ NOTE: this is a powerful tool - if you need a toy UI or clone, this ain't it.
<img width="830" height="385" alt="image" src="https://github.com/user-attachments/assets/ad52761d-7e3f-44d8-b41e-947ce8b4faa1" />
### Open links: 👉 [changelog](https://big-agi.com/changes) 👉 [installation](docs/installation.md) 👉 [roadmap](https://github.com/users/enricoros/projects/4/views/2) 👉 [documentation](docs/README.md)
#### **Open** links: 👉 [changelog](https://big-agi.com/changes) 👉 [installation](docs/installation.md) 👉 [roadmap](https://github.com/users/enricoros/projects/4/views/2) 👉 [documentation](docs/README.md)
**For teams and institutions:** Need shared prompts, SSO, or managed deployments? Reach out at enrico@big-agi.com. We're actively collecting requirements from research groups and IT departments.
@@ -97,8 +183,11 @@ The new architecture is solid and the speed improvements are real.
</details>
<details>
<summary>What's New in 1.16.1...1.16.10 · 2024-2025 (patch releases)</summary>
<summary>What's New in 1.16.1...1.16.13 · (patch releases)</summary>
- 1.16.13: Docker fix ([#840](https://github.com/enricoros/big-AGI/issues/840))
- 1.16.12: Dockerfile update ([#840](https://github.com/enricoros/big-AGI/issues/840))
- 1.16.11: v1 final release, documentation updates
- 1.16.10: OpenRouter models support
- 1.16.9: Docker Gemini fix, R1 models support
- 1.16.8: OpenAI ChatGPT-4o Latest, o1 models support
@@ -160,7 +249,7 @@ The new architecture is solid and the speed improvements are real.
- New **[Perplexity](https://www.perplexity.ai/)** and **[Groq](https://groq.com/)** integration (thanks @Penagwin). [#407](https://github.com/enricoros/big-AGI/issues/407), [#427](https://github.com/enricoros/big-AGI/issues/427)
- **[LocalAI](https://localai.io/models/)** deep integration, including support for [model galleries](https://github.com/enricoros/big-AGI/issues/411)
- **Mistral** Large and Google **Gemini 1.5** support
- Performance optimizations: runs [much faster](https://twitter.com/enricoros/status/1756553038293303434?utm_source=localhost:3000&utm_medium=big-agi), saves lots of power, reduces memory usage
- Performance optimizations: runs [much faster](https://x.com/enricoros/status/1756553038293303434?utm_source=localhost:3000&utm_medium=big-agi), saves lots of power, reduces memory usage
- Enhanced UX with auto-sizing charts, refined search and folder functionalities, perfected scaling
- And with more UI improvements, documentation, bug fixes (20 tickets), and developer enhancements
@@ -225,96 +314,83 @@ https://github.com/enricoros/big-AGI/assets/1590910/a6b8e172-0726-4b03-a5e5-10cf
For full details and former releases, check out the [archived versions changelog](docs/changelog.md).
## 👉 Key Features
## 👉 Supported Models & Integrations
| ![Advanced AI](https://img.shields.io/badge/Advanced%20AI-32383e?style=for-the-badge&logo=ai&logoColor=white) | ![100+ AI Models](https://img.shields.io/badge/100%2B%20AI%20Models-32383e?style=for-the-badge&logo=ai&logoColor=white) | ![Flow-state UX](https://img.shields.io/badge/Flow--state%20UX-32383e?style=for-the-badge&logo=flow&logoColor=white) | ![Privacy First](https://img.shields.io/badge/Privacy%20First-32383e?style=for-the-badge&logo=privacy&logoColor=white) | ![Advanced Tools](https://img.shields.io/badge/Fun%20To%20Use-f22a85?style=for-the-badge&logo=tools&logoColor=white) |
Delightful UX with latest models exclusive features like Beam for **multi-model AI validation**.
> ![LLM Vendors](https://img.shields.io/badge/20_LLM_Services-500+_Models-black?style=for-the-badge&logo=openai&logoColor=white&labelColor=purple)&nbsp;
> [![Feature Beam](https://img.shields.io/badge/AI--Validation-BEAM-000?style=for-the-badge&logo=anthropic&labelColor=purple)](https://big-agi.com/beam)
| ![Advanced AI](https://img.shields.io/badge/Advanced%20AI-32383e?style=for-the-badge&logo=ai&logoColor=white) | ![500+ AI Models](https://img.shields.io/badge/500%2B%20AI%20Models-32383e?style=for-the-badge&logo=ai&logoColor=white) | ![Flow-state UX](https://img.shields.io/badge/Flow--state%20UX-32383e?style=for-the-badge&logo=flow&logoColor=white) | ![Privacy First](https://img.shields.io/badge/Privacy%20First-32383e?style=for-the-badge&logo=privacy&logoColor=white) | ![Advanced Tools](https://img.shields.io/badge/Fun%20To%20Use-f22a85?style=for-the-badge&logo=tools&logoColor=white) |
|---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------|
| **Chat**<br/>**Call**<br/>**Beam**<br/>**Draw**, ... | Local & Cloud<br/>Open & Closed<br/>Cheap & Heavy<br/>Google, Mistral, ... | Attachments<br/>Diagrams<br/>Multi-Chat<br/>Mobile-first UI | Stored Locally<br/>Easy self-Host<br/>Local actions<br/>Data = Gold | AI Personas<br/>Voice Modes<br/>Screen Capture<br/>Camera + OCR |
![big-AGI screenshot](docs/pixels/big-AGI-compo-20240201_small.png)
You can easily configure 100s of AI models in big-AGI:
### AI Models & Vendors
| **AI models** | _supported vendors_ |
|:--------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Opensource Servers | [LocalAI](https://localai.io/) (multimodal) · [Ollama](https://ollama.com/) |
| Local Servers | [LM Studio](https://lmstudio.ai/) |
| Multimodal services | [Azure](https://azure.microsoft.com/en-us/products/ai-services/openai-service) · [Anthropic](https://anthropic.com) · [Google Gemini](https://ai.google.dev/) · [OpenAI](https://platform.openai.com/docs/overview) |
| Language services | [Alibaba](https://www.alibabacloud.com/en/product/modelstudio) · [DeepSeek](https://deepseek.com) · [Groq](https://wow.groq.com/) · [Mistral](https://mistral.ai/) · [OpenRouter](https://openrouter.ai/) · [Perplexity](https://www.perplexity.ai/) · [Together AI](https://www.together.ai/) · [xAI](https://x.ai/) |
| Image services | OpenAI · Google Gemini |
| Speech services | [ElevenLabs](https://elevenlabs.io) (Voice synthesis / cloning) |
Configure 100s of AI models from 20+ providers:
Add extra functionality with these integrations:
| **AI models** | _supported vendors_ |
|:--------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Opensource Servers | [LocalAI](https://localai.io/) · [Ollama](https://ollama.com/) |
| Local Servers | [LM Studio](https://lmstudio.ai/) (non-open) |
| Multimodal services | [Anthropic](https://anthropic.com) · [AWS Bedrock](https://aws.amazon.com/bedrock/) · [Azure](https://azure.microsoft.com/en-us/products/ai-services/openai-service) · [Google Gemini](https://ai.google.dev/) · [OpenAI](https://platform.openai.com/docs/overview) |
| LLM services | [Alibaba](https://www.alibabacloud.com/en/product/modelstudio) · [DeepSeek](https://deepseek.com) · [Groq](https://wow.groq.com/) · [Mistral](https://mistral.ai/) · [Moonshot](https://www.moonshot.cn/) · [OpenPipe](https://openpipe.ai/) · [OpenRouter](https://openrouter.ai/) · [Perplexity](https://www.perplexity.ai/) · [Together AI](https://www.together.ai/) · [xAI](https://x.ai/) · [Z.ai](https://z.ai/) |
| OpenAI-compatible | Any OpenAI-compatible endpoint - models, pricing, and capabilities are auto-detected |
| Image services | OpenAI · Google Gemini (Nano Banana) · LocalAI |
| Speech services | [ElevenLabs](https://elevenlabs.io) · [Inworld](https://inworld.ai) · [OpenAI TTS](https://platform.openai.com/docs/guides/text-to-speech) · LocalAI · Browser (Web Speech API) |
| **More** | _integrations_ |
|:-------------|:---------------------------------------------------------------------------------------------------------------|
| Web Browse | [Browserless](https://www.browserless.io/) · [Puppeteer](https://pptr.dev/)-based |
| Web Search | [Google CSE](https://programmablesearchengine.google.com/) |
| Code Editors | [CodePen](https://codepen.io/pen/) · [StackBlitz](https://stackblitz.com/) · [JSFiddle](https://jsfiddle.net/) |
| Tracking | [Helicone](https://www.helicone.ai) (LLM Observability) |
### Additional Integrations
[//]: # (- [x] **Flow-state UX** for uncompromised productivity)
[//]: # (- [x] **AI Personas**: Tailor your AI interactions with customizable personas)
[//]: # (- [x] **Sleek UI/UX**: A smooth, intuitive, and mobile-responsive interface)
[//]: # (- [x] **Efficient Interaction**: Voice commands, OCR, and drag-and-drop file uploads)
[//]: # (- [x] **Privacy First**: Self-host and use your own API keys for full control)
[//]: # (- [x] **Advanced Tools**: Execute code, import PDFs, and summarize documents)
[//]: # (- [x] **Seamless Integrations**: Enhance functionality with various third-party services)
[//]: # (- [x] **Open Roadmap**: Contribute to the progress of big-AGI)
<br/>
## 🚀 Installation
To get started with big-AGI, follow our comprehensive [Installation Guide](docs/installation.md).
The guide covers various installation options, whether you're spinning it up on
your local computer, deploying on Vercel, on Cloudflare, or rolling it out
through Docker.
Whether you're a developer, system integrator, or enterprise user, you'll find step-by-step instructions
to set up big-AGI quickly and easily.
[![Installation Guide](https://img.shields.io/badge/Installation%20Guide-blue?style=for-the-badge&logo=read-the-docs&logoColor=white)](docs/installation.md)
Or bring your API keys and jump straight into our free instance on [big-AGI.com](https://big-agi.com).
<br/>
# 🌟 Get Involved!
[//]: # ([![Official Discord]&#40;https://img.shields.io/discord/1098796266906980422?label=discord&logo=discord&logoColor=%23fff&style=for-the-badge&#41;]&#40;https://discord.gg/MkH4qj2Jp9&#41;)
[![Official Discord](https://discordapp.com/api/guilds/1098796266906980422/widget.png?style=banner2)](https://discord.gg/MkH4qj2Jp9)
- [ ] 📢️ [**Chat with us** on Discord](https://discord.gg/MkH4qj2Jp9)
- [ ]**Give us a star** on GitHub 👆
- [ ] 🚀 **Do you like code**? You'll love this gem of a project! [_Pick up a task!_](https://github.com/users/enricoros/projects/4/views/4) - _easy_ to _pro_
- [ ] 💡 Got a feature suggestion? [_Add your roadmap ideas_](https://github.com/enricoros/big-agi/issues/new?&template=roadmap-request.md)
- [ ] ✨ [Deploy](docs/installation.md) your [fork](docs/customizations.md) for your friends and family, or [customize it for work](docs/customizations.md)
<br/>
[//]: # ([![GitHub stars]&#40;https://img.shields.io/github/stars/enricoros/big-agi&#41;]&#40;https://github.com/enricoros/big-agi/stargazers&#41;)
[//]: # ([![GitHub forks]&#40;https://img.shields.io/github/forks/enricoros/big-agi&#41;]&#40;https://github.com/enricoros/big-agi/network&#41;)
[//]: # ([![GitHub pull requests]&#40;https://img.shields.io/github/issues-pr/enricoros/big-agi&#41;]&#40;https://github.com/enricoros/big-agi/pulls&#41;)
[//]: # ([![License]&#40;https://img.shields.io/github/license/enricoros/big-agi&#41;]&#40;https://github.com/enricoros/big-agi/LICENSE&#41;)
## 📜 Licensing
Big-AGI incorporates third-party software components that are subject
to separate license terms. For detailed information about these
components and their respective licenses, please refer to
the [Third-Party Notices](src/modules/3rdparty/THIRD_PARTY_NOTICES.md).
| **More** | _integrations_ |
|:--------------|:---------------------------------------------------------------------------------------------------------------|
| Web Browse | [Browserless](https://www.browserless.io/) · [Puppeteer](https://pptr.dev/)-based |
| Web Search | [Google CSE](https://programmablesearchengine.google.com/) |
| Observability | [Helicone](https://www.helicone.ai) |
---
2023-2025 · Enrico Ros x [Big-AGI](https://big-agi.com) · Like this project? Leave a star! 💫⭐
## 🚀 Installation
Self-host with Docker, deploy on Vercel, or develop locally. Full setup guide:
[![Installation Guide](https://img.shields.io/badge/Installation%20Guide-blue?style=for-the-badge&logo=read-the-docs&logoColor=white)](docs/installation.md)
Or use the hosted version at [big-agi.com](https://big-agi.com) with your API keys.
---
## 👋 Community & Contributing
### Connect
[![Official Discord](https://discordapp.com/api/guilds/1098796266906980422/widget.png?style=banner2)](https://discord.gg/MkH4qj2Jp9)
⭐ [Star the repo](https://github.com/enricoros/big-agi) if Big-AGI is useful to you
### Contribute
**🤖 AI-Powered Issue Assistance**
When you open an issue, our custom AI triage system (powered by [Claude Code](https://github.com/anthropics/claude-code-action) with Big-AGI architecture documentation) analyzes it, searches the codebase, and provides solutions - typically within 30 minutes. We've trained the system on our modules and subsystems so it handles most issues effectively. Your feedback drives development!
[![Open an Issue](https://img.shields.io/badge/Open_Issue-AI_Will_Help-ff8c00?style=for-the-badge&logo=fireship&logoColor=fff&labelColor=8b0000)](https://github.com/enricoros/big-agi/issues/new?template=ai-triage.yml)
[![Request Feature](https://img.shields.io/badge/Request_Feature-Roadmap_Idea-orange?style=for-the-badge&logo=lightbulb&logoColor=white)](https://github.com/enricoros/big-agi/issues/new?&template=roadmap-request.md)
[![Good First Issues](https://img.shields.io/badge/Good_First_Issues-Start-blue?style=for-the-badge&logo=github&logoColor=white)](https://github.com/users/enricoros/projects/4/views/4)
[![Customization](https://img.shields.io/badge/Fork_&_Customize-Your_Own-purple?style=for-the-badge&logo=git&logoColor=white)](docs/customizations.md)
[![Roadmap](https://img.shields.io/badge/Open_Roadmap-View-0366d6?style=for-the-badge&logo=github&logoColor=white)](https://github.com/users/enricoros/projects/4/views/2)
#### Contributors
<a href="https://github.com/enricoros/big-agi/graphs/contributors">
<img src="https://contrib.rocks/image?repo=enricoros/big-agi&max=48&columns=12" />
</a>
---
## License
MIT License · [Third-Party Notices](src/modules/3rdparty/THIRD_PARTY_NOTICES.md)
**2023-2026** · [Enrico Ros](https://www.enricoros.com) × [Token Fabrics](https://www.tokenfabrics.com)
+5 -5
View File
@@ -2,7 +2,7 @@ import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { appRouterCloud } from '~/server/trpc/trpc.router-cloud';
import { createTRPCFetchContext } from '~/server/trpc/trpc.server';
import { posthogCaptureServerException } from '~/server/posthog/posthog.server';
import { posthogServerSendException } from '~/server/posthog/posthog.server';
const handlerNodeRoutes = (req: Request) => fetchRequestHandler({
endpoint: '/api/cloud',
@@ -16,15 +16,15 @@ const handlerNodeRoutes = (req: Request) => fetchRequestHandler({
console.error(`❌ tRPC-cloud failed on ${path ?? 'unk-path'}: ${error.message}`);
// -> Capture node errors
await posthogCaptureServerException(error, {
await posthogServerSendException(error, undefined, {
domain: 'trpc-onerror',
runtime: 'nodejs',
endpoint: path ?? 'unknown',
method: req.method,
url: req.url,
additionalProperties: {
errorCode: error.code,
errorType: type,
error_code: error.code,
error_type: type,
},
});
},
@@ -33,7 +33,7 @@ const handlerNodeRoutes = (req: Request) => fetchRequestHandler({
// NOTE: the following statement breaks the build on non-pro deployments, and conditionals don't work either
// so we resorted to raising the timeout from 10s to 60s in the vercel.json file instead
export const maxDuration = 60;
// export const maxDuration = 60;
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
export { handlerNodeRoutes as GET, handlerNodeRoutes as POST };
+3 -1
View File
@@ -10,9 +10,11 @@ const handlerEdgeRoutes = (req: Request) => fetchRequestHandler({
createContext: createTRPCFetchContext,
onError:
process.env.NODE_ENV === 'development'
? ({ path, error }) => console.error(`❌ tRPC-edge failed on ${path ?? 'unk-path'}: ${error.message}`)
? ({ path, error }) => console.error(`\n❌ tRPC-edge failed on ${path ?? 'unk-path'}: ${error.message}`)
: undefined,
});
// NOTE: we don't set maxDuration explicitly here - however we set it in the Vercel project settings, raising to the limit of 300s
// export const maxDuration = 60;
export const runtime = 'edge';
export { handlerEdgeRoutes as GET, handlerEdgeRoutes as POST };
-3
View File
@@ -2,8 +2,6 @@
#
# For more examples, such running big-AGI alongside a web browsing service, see the `docs/docker` folder.
version: '3.9'
services:
big-agi:
image: ghcr.io/enricoros/big-agi:latest
@@ -11,4 +9,3 @@ services:
- "3000:3000"
env_file:
- .env
command: [ "next", "start", "-p", "3000" ]
+4
View File
@@ -1,3 +1,7 @@
---
unlisted: true
---
# AIX dispatch server - API features comparison
This is updated as of 2024-07-09, and includes the latest features and capabilities of the three major AI APIs: Anthropic, Gemini, and OpenAI.
+13 -5
View File
@@ -10,6 +10,8 @@ Essential guides:
- **[FAQ](help-faq.md)**: Common questions and answers
- **[Enabling Microphone](help-feature-microphone.md)**: Configure speech recognition in your browser
- **[Data Ownership](help-data-ownership.md)**: How your data is stored and managed
- **[Live File](help-feature-livefile.md)**: Live file attachment feature
## AI Services
@@ -21,18 +23,21 @@ How to set up AI models and features in big-AGI.
- Easy API key configuration:
[Alibaba](https://bailian.console.alibabacloud.com/?apiKey=1#/api-key),
[Anthropic](https://console.anthropic.com/settings/keys),
[AWS Bedrock](https://console.aws.amazon.com/bedrock/),
[Deepseek](https://platform.deepseek.com/api_keys),
[Google Gemini](https://aistudio.google.com/app/apikey),
[Groq](https://console.groq.com/keys),
[Mistral](https://console.mistral.ai/api-keys/),
[Moonshot](https://platform.moonshot.cn/console/api-keys),
[OpenAI](https://platform.openai.com/api-keys),
[OpenPipe](https://app.openpipe.ai/settings),
[Perplexity](https://www.perplexity.ai/settings/api),
[TogetherAI](https://api.together.xyz/settings/api-keys),
[xAI](http://x.ai/api)
[xAI](https://x.ai/api),
[Z.ai](https://z.ai/)
- **[Azure OpenAI](config-azure-openai.md)** guide
- **FireworksAI** ([API keys](https://fireworks.ai/account/api-keys), via custom OpenAI endpoint: https://api.fireworks.ai/inference)
- **[OpenRouter](config-openrouter.md)** guide
- **OpenAI-compatible endpoints**: Any provider with an OpenAI-compatible API works out of the box - models, pricing, and capabilities are auto-detected
- **Local AI Integrations**:
@@ -42,8 +47,9 @@ How to set up AI models and features in big-AGI.
- **Enhanced AI Features**:
- **[Web Browsing](config-feature-browse.md)**: Enable web page download through third-party services or your own cloud
- **Web Search**: Google Search API (see '[Environment Variables](environment-variables.md)')
- **Image Generation**: GPT Image (gpt-image-1), DALL·E 3 and 2
- **Voice Synthesis**: ElevenLabs API for voice generation
- **Image Generation**: GPT Image (gpt-image-1), Nano Banana, DALL·E 3 and 2
- **Voice Synthesis**: ElevenLabs, Inworld, OpenAI TTS, LocalAI, or browser Web Speech API
- **[Google Drive](config-feature-google-drive.md)**: Attach files from Google Drive
## Deployment & Customization
@@ -60,8 +66,10 @@ For deploying a custom big-AGI instance:
- **Advanced Setup**:
- **[Source Code Customization](customizations.md)**: Modify the source code
- **[Access Control](deploy-authentication.md)**: Optional, add basic user authentication
- **[Database Setup](deploy-database.md)**: Optional, enables "Chat Link Sharing"
- **[Reverse Proxy](deploy-reverse-proxy.md)**: Optional, enables custom domains and SSL
- **[Docker Deployment](deploy-docker.md)**: Deploy with Docker containers
- **[Kubernetes](deploy-k8s.md)**: Deploy on Kubernetes clusters
- **[Analytics](deploy-analytics.md)**: Set up usage analytics
- **[Environment Variables](environment-variables.md)**: Pre-configures models and services
## Community & Support
+5 -3
View File
@@ -20,8 +20,11 @@ by release.
- And all of the [Big-AGI 2 changes](https://github.com/enricoros/big-AGI/issues/567#issuecomment-2262187617) and more
- Built for the future, madly optimized
### What's New in 1.16.1...1.16.9 · Jan 21, 2025 (patch releases)
### What's New in 1.16.1...1.16.13 · (patch releases)
- 1.16.13: Docker fix (#840)
- 1.16.12: Dockerfile update (#840)
- 1.16.11: v1 final release, documentation updates
- 1.16.10: OpenRouter models support
- 1.16.9: Docker Gemini fix, R1 models support
- 1.16.8: OpenAI ChatGPT-4o Latest, o1 models support
@@ -70,7 +73,7 @@ by release.
- New **[Perplexity](https://www.perplexity.ai/)** and **[Groq](https://groq.com/)** integration (thanks @Penagwin). [#407](https://github.com/enricoros/big-AGI/issues/407), [#427](https://github.com/enricoros/big-AGI/issues/427)
- **[LocalAI](https://localai.io/models/)** deep integration, including support for [model galleries](https://github.com/enricoros/big-AGI/issues/411)
- **Mistral** Large and Google **Gemini 1.5** support
- Performance optimizations: runs [much faster](https://twitter.com/enricoros/status/1756553038293303434?utm_source=localhost:3000&utm_medium=big-agi), saves lots of power, reduces memory usage
- Performance optimizations: runs [much faster](https://x.com/enricoros/status/1756553038293303434?utm_source=localhost:3000&utm_medium=big-agi), saves lots of power, reduces memory usage
- Enhanced UX with auto-sizing charts, refined search and folder functionalities, perfected scaling
- And with more UI improvements, documentation, bug fixes (20 tickets), and developer enhancements
- [Release notes](https://github.com/enricoros/big-AGI/releases/tag/v1.14.0), and changes [v1.13.1...v1.14.0](https://github.com/enricoros/big-AGI/compare/v1.13.1...v1.14.0) (233 commits, 8,000+ lines changed)
@@ -228,7 +231,6 @@ For Developers:
- **[Install Mobile APP](../docs/pixels/feature_pwa.png)** 📲 looks like native (@harlanlewis)
- **[UI language](../docs/pixels/feature_language.png)** with auto-detect, and future app language! (@tbodyston)
- **PDF Summarization** 🧩🤯 - ask questions to a PDF! (@fredliubojin)
- **Code Execution: [Codepen](https://codepen.io/)** 💻 (@harlanlewis)
- **[SVG Drawing](../docs/pixels/feature_svg_drawing.png)** - draw with AI 🎨
- Chats: multiple chats, AI titles, Import/Export, Selection mode
- Rendering: Markdown, SVG, improved Code blocks
+55
View File
@@ -0,0 +1,55 @@
# Google Drive Integration
Attach files from Google Drive directly in the chat composer.
## Setup
### 1. Enable APIs
In [Google Cloud Console](https://console.cloud.google.com/):
1. Go to **APIs & Services > Library**
2. Enable **Google Drive API** and **Google Picker API**
### 2. Configure OAuth
1. Go to **APIs & Services > OAuth consent screen**
2. Create consent screen (External or Internal)
3. Add scope: `https://www.googleapis.com/auth/drive.file`
4. Add test users if in testing mode
### 3. Create Credentials
1. Go to **APIs & Services > Credentials**
2. Create **OAuth client ID** (Web application)
3. Add JavaScript origins:
- `http://localhost:3000` (dev)
- `https://your-domain.com` (prod)
### 4. Set Environment Variable
```bash
NEXT_PUBLIC_GOOGLE_DRIVE_CLIENT_ID=your-client-id.apps.googleusercontent.com
```
## Usage
- Click **Drive** button in attachment menu
## Supported Files
| Type | Export Format |
|-----------------|---------------------|
| Regular files | Downloaded directly |
| Google Docs | Markdown (.md) |
| Google Sheets | CSV (.csv) |
| Google Slides | PDF (.pdf) |
| Google Drawings | SVG (.svg) |
## Troubleshooting
**Picker won't open**: Check `NEXT_PUBLIC_GOOGLE_DRIVE_CLIENT_ID` is set and APIs are enabled.
**OAuth errors**: Verify your domain is in authorized JavaScript origins. Add yourself as test user if app is in testing mode.
**Download fails**: Check file permissions and that Drive API is enabled.
+3 -1
View File
@@ -41,6 +41,8 @@ In addition to using the UI, configuration can also be done using
### Integration: Models Gallery
> Note: The Gallery Admin feature described below may have been removed or renamed in recent versions of big-AGI.
If the running LocalAI instance is configured with a [Model Gallery](https://localai.io/models/):
- Go to Models > LocalAI
@@ -54,7 +56,7 @@ If the running LocalAI instance is configured with a [Model Gallery](https://loc
At the time of writing, LocalAI does not publish the model `context window size`.
Every model is assumed to be capable of chatting, and with a context window of 4096 tokens.
Please update the [src/modules/llms/transports/server/openai/models/models.data.ts](../src/modules/llms/server/openai/models/models.data.ts)
Please update the [src/modules/llms/server/models.mappings.ts](../src/modules/llms/server/models.mappings.ts)
file with the mapping information between LocalAI model IDs and names/descriptions/tokens, etc.
# 🤝 Support
+4 -5
View File
@@ -1,8 +1,7 @@
# OpenRouter Configuration
[OpenRouter](https://openrouter.ai) is a standalone, premium service
that provides access to <Link href='https://openrouter.ai/docs#models' target='_blank'>exclusive AI models</Link>
such as GPT-4 32k, Claude, and more. These models are typically not available to the public.
that provides access to a wide range of AI models from multiple providers through a single API.
This document details the process of integrating OpenRouter with big-AGI.
### 1. OpenRouter Account Setup and API Key Generation
@@ -20,7 +19,7 @@ This document details the process of integrating OpenRouter with big-AGI.
![feature-openrouter-add.png](pixels/feature-openrouter-add.png)
3. Input the API key into the **OpenRouter API Key** field, and load the Models.
![feature-openrouter-configure.png](pixels/feature-openrouter-configure.png)
4. OpenAI GPT4-32k and other models will now be accessible and selectable in the application.
4. Models from all supported providers will now be accessible and selectable in the application.
In addition to using the UI, configuration can also be done using
[environment variables](environment-variables.md).
@@ -30,5 +29,5 @@ In addition to using the UI, configuration can also be done using
OpenRouter independently manages its service and pricing and is not affiliated with big-AGI.
For more detailed information, please visit [this page](https://openrouter.ai/docs#models).
Please note that running large models such as GPT-4 32k can be costly and may rapidly consume
credits - a single prompt may cost $1 or more, at the time of writing.
Please note that running large models can be costly and may rapidly consume credits.
Check model pricing on the OpenRouter website before use.
+3 -3
View File
@@ -49,8 +49,8 @@ Edit the `src/data.ts` file to customize personas. This file houses the default
Adapt the UI to match your project's aesthetic, incorporate new features, or exclude unnecessary ones.
- [ ] Adjust `src/common/app.theme.ts` for theme changes: colors, spacing, button appearance, animations, etc
- [ ] Modify `src/common/app.config.tsx` to alter the application's name
- [ ] Update `src/common/app.nav.tsx` to revise the navigation bar
- [ ] Modify `src/common/app.release.ts` to alter the application's name
- [ ] Update `src/common/app.nav.ts` to revise the navigation bar
### Add a Message of the Day
@@ -71,7 +71,7 @@ Example: `NEXT_PUBLIC_MOTD=🚀 New features available in {{app_build_pkgver}}!
Test your application thoroughly using local development (refer to README.md for local build instructions). Deploy using your preferred hosting service. big-AGI supports deployment on platforms like Vercel, Docker, or any Node.js-compatible service, especially those supporting NextJS's "Edge Runtime."
- [deploy-cloudflare.md](deploy-cloudflare.md): for Cloudflare Workers deployment
- [deploy-cloudflare.md](deploy-cloudflare.md): for Cloudflare Pages deployment (limited support)
- [deploy-docker.md](deploy-docker.md): for Docker deployment instructions and examples
- [deploy-k8s.md](deploy-k8s.md): for Kubernetes deployment instructions and examples
+3 -3
View File
@@ -51,13 +51,13 @@ Vercel Analytics and Speed Insights are local API endpoints deployed to your dom
domain. Furthermore, the Vercel Analytics service is privacy-friendly, and does not track individual users.
This service is avaialble to system administrators when deploying to Vercel. It is automatically enabled when deploying to Vercel.
The code that activates Vercel Analytics is located in the `src/pages/_app.tsx` file:
The code that activates Vercel Analytics is located in the `pages/_app.tsx` file:
```tsx
const MyApp = ({ Component, emotionCache, pageProps }: MyAppProps) => <>
...
{isVercelFromFrontend && <VercelAnalytics debug={false} />}
{isVercelFromFrontend && <VercelSpeedInsights debug={false} sampleRate={1 / 2} />}
{Is.Deployment.VercelFromFrontend && <VercelAnalytics debug={false} />}
{Is.Deployment.VercelFromFrontend && <VercelSpeedInsights debug={false} sampleRate={1 / 2} />}
...
</>;
```
+11 -9
View File
@@ -1,18 +1,20 @@
---
unlisted: true
---
# Deploying a Next.js App on Cloudflare Pages
> WARNING: Cloudflare Pages does not support traditional NodeJS runtimes, but only Edge Runtime functions.
> WARNING: Cloudflare Pages only supports Edge Runtime functions, not the full Node.js runtime.
>
> In this project we use Prisma connected to serverless Postgres, which at the moment cannot run on
> edge functions, so we cannot deploy this project on Cloudflare Pages.
> The cloud router in this project requires a Node.js runtime for Supabase SDK, authentication,
> sync, and other server-side features that cannot run on Cloudflare's edge runtime.
>
> Workaround: Step 3.4. has been added below, to DELETE the NodeJS traditional runtime - which means that some
> Workaround: Step 3.4. has been added below, to DELETE the Node.js cloud router - which means that some
> parts of this application will not work.
> - [Side effects](https://github.com/enricoros/big-agi/blob/main/src/apps/chat/trade/server/trade.router.ts#L19):
> Sharing functionality to DB, and import from ChatGPT share, and post to Paste.GG will not work
> - [Side effects](https://github.com/enricoros/big-agi/blob/main/src/modules/trade/server/trade.router.ts):
> Sharing functionality, import from ChatGPT share, and post to Paste.GG will not work
> - Cloud features (sync, auth, payments) will not be available
> - See [Issue 174](https://github.com/enricoros/big-agi/issues/174).
>
> Longer term: follow [prisma/prisma: Support Edge Function deployments](https://github.com/prisma/prisma/issues/21394)
> and convert the Node runtime to Edge runtime once Prisma supports it.
This guide provides steps to deploy your Next.js app on Cloudflare Pages.
It is based on the [official Cloudflare developer documentation](https://developers.cloudflare.com/pages/framework-guides/deploy-a-nextjs-site/),
@@ -19,7 +19,6 @@ services:
- .env
environment:
- PUPPETEER_WSS_ENDPOINT=ws://browserless:3000
command: [ "next", "start", "-p", "3000" ]
depends_on:
- browserless
-14
View File
@@ -1,14 +0,0 @@
# Why big-AGI?
Placeholder for a document that demonstrates the productivity and unique features of Big-AGI.
## Exclusive features
- [x] Call AGI
- [x] Continuous Voice mode
- [x] Diagram generation
- [ ] ...
## Productivity Features
- [x] Multi-window to never wait
- [x] Multi-Chat to explore different solutions
- [x] Rendering of graphs, charts, mindmaps
- [ ] ...
+20 -5
View File
@@ -3,7 +3,7 @@
This document provides an explanation of the environment variables used in the big-AGI application.
**All variables are optional**; and _UI options_ take precedence over _backend environment variables_,
which take place over _defaults_. This file is kept in sync with [`../src/server/env.ts`](../src/server/env.ts).
which take place over _defaults_. This file is kept in sync with [`../src/server/env.server.ts`](../src/server/env.server.ts).
### Setting Environment Variables
@@ -29,12 +29,18 @@ AZURE_OPENAI_API_ENDPOINT=
AZURE_OPENAI_API_KEY=
ANTHROPIC_API_KEY=
ANTHROPIC_API_HOST=
BEDROCK_BEARER_TOKEN=
BEDROCK_ACCESS_KEY_ID=
BEDROCK_SECRET_ACCESS_KEY=
BEDROCK_SESSION_TOKEN=
BEDROCK_REGION=
DEEPSEEK_API_KEY=
GEMINI_API_KEY=
GROQ_API_KEY=
LOCALAI_API_HOST=
LOCALAI_API_KEY=
MISTRAL_API_KEY=
MOONSHOT_API_KEY=
OLLAMA_API_HOST=
OPENPIPE_API_KEY=
OPENROUTER_API_KEY=
@@ -65,8 +71,9 @@ HTTP_BASIC_AUTH_PASSWORD=
# Frontend variables
NEXT_PUBLIC_MOTD=
NEXT_PUBLIC_GA4_MEASUREMENT_ID=
NEXT_PUBLIC_POSTHOG_KEY=
NEXT_PUBLIC_GOOGLE_DRIVE_CLIENT_ID=
NEXT_PUBLIC_PLANTUML_SERVER_URL=
NEXT_PUBLIC_POSTHOG_KEY=
```
## Backend Variables
@@ -98,13 +105,19 @@ requiring the user to enter an API key
| `AZURE_OPENAI_API_VERSION` | API version for traditional deployment-based endpoints | Optional, defaults to '2025-04-01-preview' |
| `AZURE_DEPLOYMENTS_API_VERSION` | API version for the deployments listing endpoint | Optional, defaults to '2023-03-15-preview' |
| `ANTHROPIC_API_KEY` | The API key for Anthropic | Optional |
| `ANTHROPIC_API_HOST` | Changes the backend host for the Anthropic vendor, to enable platforms such as AWS Bedrock | Optional |
| `ANTHROPIC_API_HOST` | Changes the backend host for the Anthropic vendor, for proxies or custom endpoints | Optional |
| `BEDROCK_BEARER_TOKEN` | Bedrock long-term API key (`ABSK...`). Takes priority over IAM credentials. Short-term keys only work for runtime, not model listing | Optional |
| `BEDROCK_ACCESS_KEY_ID` | AWS IAM Access Key ID for Bedrock (Claude models via AWS) | Optional, but if set `BEDROCK_SECRET_ACCESS_KEY` must also be set |
| `BEDROCK_SECRET_ACCESS_KEY` | AWS IAM Secret Access Key for Bedrock | Optional, but if set `BEDROCK_ACCESS_KEY_ID` must also be set |
| `BEDROCK_SESSION_TOKEN` | AWS Session Token for temporary/STS credentials | Optional |
| `BEDROCK_REGION` | AWS region for Bedrock (e.g., `us-east-1`, `us-west-2`, `eu-west-1`) | Optional, defaults to `us-east-1` |
| `DEEPSEEK_API_KEY` | The API key for Deepseek AI | Optional |
| `GEMINI_API_KEY` | The API key for Google AI's Gemini | Optional |
| `GROQ_API_KEY` | The API key for Groq Cloud | Optional |
| `LOCALAI_API_HOST` | Sets the URL of the LocalAI server, or defaults to http://127.0.0.1:8080 | Optional |
| `LOCALAI_API_KEY` | The (Optional) API key for LocalAI | Optional |
| `MISTRAL_API_KEY` | The API key for Mistral | Optional |
| `MOONSHOT_API_KEY` | The API key for Moonshot AI | Optional |
| `OLLAMA_API_HOST` | Changes the backend host for the Ollama vendor. See [config-local-ollama.md](config-local-ollama.md) | |
| `OPENPIPE_API_KEY` | The API key for OpenPipe | Optional |
| `OPENROUTER_API_KEY` | The API key for OpenRouter | Optional |
@@ -130,10 +143,11 @@ Enable the app to Talk, Draw, and Google things up.
| Variable | Description |
|:---------------------------|:------------------------------------------------------------------------------------------------------------------------|
| **Text-To-Speech** | [ElevenLabs](https://elevenlabs.io/) is a high quality speech synthesis service |
| **Text-To-Speech** | ElevenLabs, Inworld, OpenAI TTS, LocalAI, and browser Web Speech API are supported |
| `ELEVENLABS_API_KEY` | ElevenLabs API Key - used for calls, etc. |
| `ELEVENLABS_API_HOST` | Custom host for ElevenLabs |
| `ELEVENLABS_VOICE_ID` | Default voice ID for ElevenLabs |
| | *Note: OpenAI TTS and LocalAI TTS reuse credentials from your configured LLM services (no separate env vars needed)* |
| **Google Custom Search** | [Google Programmable Search Engine](https://programmablesearchengine.google.com/about/) produces links to pages |
| `GOOGLE_CLOUD_API_KEY` | Google Cloud API Key, used with the '/react' command - [Link to GCP](https://console.cloud.google.com/apis/credentials) |
| `GOOGLE_CSE_ID` | Google Custom/Programmable Search Engine ID - [Link to PSE](https://programmablesearchengine.google.com/) |
@@ -152,8 +166,9 @@ The value of these variables are passed to the frontend (Web UI) - make sure the
| `NEXT_PUBLIC_DEBUG_BREAKS` | (optional, development) When set to 'true', enables automatic debugger breaks on DEV/error/critical logs in development builds |
| `NEXT_PUBLIC_MOTD` | Message of the Day - displays a dismissible banner at the top of the app (see [customizations](customizations.md) for the template variables). Example: 🔔 Welcome to our deployment! Version {{app_build_pkgver}} built on {{app_build_time}}. |
| `NEXT_PUBLIC_GA4_MEASUREMENT_ID` | (optional) The measurement ID for Google Analytics 4. (see [deploy-analytics](deploy-analytics.md)) |
| `NEXT_PUBLIC_POSTHOG_KEY` | (optional) Key for PostHog analytics. (see [deploy-analytics](deploy-analytics.md)) |
| `NEXT_PUBLIC_GOOGLE_DRIVE_CLIENT_ID` | (optional) Google OAuth Client ID for Drive Picker. Can reuse `AUTH_GOOGLE_ID`. See [Google Drive](config-feature-google-drive.md) |
| `NEXT_PUBLIC_PLANTUML_SERVER_URL` | The URL of the PlantUML server, used for rendering UML diagrams. Allows using custom local servers. |
| `NEXT_PUBLIC_POSTHOG_KEY` | (optional) Key for PostHog analytics. (see [deploy-analytics](deploy-analytics.md)) |
> Important: these variables must be set at build time, which is required by Next.js to pass them to the frontend.
> This is in contrast to the backend variables, which can be set when starting the local server/container.
+4
View File
@@ -1,3 +1,7 @@
---
unlisted: true
---
# Big-AGI Advanced Tips & Tricks
> 🚨 This file is not meant for publication, and it's just been created as a handbook with tips
+28 -1
View File
@@ -30,6 +30,12 @@ You can see your data in your browser's local storage and IndexedDB - try it you
![Browser local storage showing API keys and chat data](pixels/data_ownership_local_storage.png)
### Sync for Authenticated Users
Users with accounts on big-agi.com who opt into Sync (a Pro feature) have their entity data - such as conversations and personas - replicated to the server for multi-device access.
Server-side data is isolated per-user using Row Level Security (RLS), ensuring that no other user can access your synced data.
Sync is entirely optional; without it, all data remains local to your browser.
### What This Means For You
Storing data in your browser means:
@@ -43,7 +49,7 @@ Storing data in your browser means:
Big-AGI generates a _device identifier_ that combines timestamp and random components, stored only on your device. This identifier:
- Is used only for the **optional sync functionality** between your devices (not yet ready)
- Is used only for the **optional sync functionality** between your devices
- Helps maintain data consistency when using Big-AGI across multiple devices
- Remains completely local unless you explicitly enable sync
- Is not used for tracking, analytics, or telemetry
@@ -74,6 +80,27 @@ and then are send to the upstream AI services.
![data_ownership_hosted.png](pixels/data_ownership_hosted.png)
### Direct Connection (Browser → AI Service)
Most AI services offer a **Direct Connection** toggle (under a service's Advanced settings). When enabled, the browser calls the AI provider's API directly, skipping the Big-AGI server entirely.
Benefits:
- **No 4.5 MB upload limit** - the Vercel body-size cap does not apply, so larger attachments and long prompts go through.
- **No 300-second timeout** - the Vercel function timeout does not apply, so long-running generations keep streaming.
- **More privacy** - connection metadata (IP, timestamp, edge region, Vercel telemetry) is not observable by the Big-AGI edge server.
Tradeoff:
- **Slightly more downlink bandwidth**: when traffic passes through the Big-AGI edge, repetitive streaming frames are compacted; direct streams arrive verbatim from the provider.
Availability requires both:
1. The API key is set in your browser (client-side), not via server environment variables. Server-key deployments cannot use Direct Connection because the browser has no credential to send.
2. The AI service allows CORS (browser-origin requests). Most major providers do; Big-AGI sets any extra headers they require.
Direct Connection is a net win on speed, limits, and privacy whenever the provider permits it.
## Security Best Practices
**Basic Security**:
+20
View File
@@ -2,6 +2,26 @@
Quick answers to common questions about Big-AGI. For detailed documentation, see our [Website Docs](https://big-agi.com/docs).
### Connectivity
<details open>
<summary><b>What is "Direct Connection" and should I enable it?</b></summary>
Direct Connection lets the browser call the AI provider's API directly, skipping the Big-AGI edge server. It appears as a toggle in each AI service's Advanced settings when your API key is set client-side.
**When available, it is a net win**: faster, fewer restrictions, more privacy.
- **No 4.5 MB upload limit** (Vercel body-size cap does not apply).
- **No 300-second timeout** (Vercel function timeout does not apply; call length is bound only by the AI service).
- **More privacy** - connection metadata (IP, timestamp, edge region, Vercel telemetry) is not observable by the Big-AGI edge server.
- **Slightly more downlink bandwidth** - when passing through the edge, Big-AGI sheds repetitive streaming frames; direct streams arrive verbatim.
**When it is unavailable**:
1. **Server-side keys** - if the deployment stores API keys in server environment variables, the browser has no credential to send directly.
2. **Provider does not allow CORS** - browsers cannot call APIs that block cross-origin requests. Most major providers permit it; Big-AGI sets any required headers.
</details>
### Versions
<details open>
+4 -10
View File
@@ -7,7 +7,7 @@ process for your own instance of big-AGI and related products.
**Try big-AGI** - You don't need to install anything if you want to play with big-AGI
and have your API keys to various model services. You can access our free instance on [big-AGI.com](https://big-agi.com).
The free instance runs the latest `main-stable` branch from this repository.
The free instance runs the latest `main` branch from this repository.
## 🧩 Build-your-own
@@ -72,9 +72,8 @@ Create your GitHub fork, create a Vercel project over that fork, and deploy it.
### Deploy on Cloudflare
Deploy on Cloudflare's global network by installing big-AGI on
Cloudflare Pages. Check out the [Cloudflare Installation Guide](deploy-cloudflare.md)
for step-by-step instructions.
> Note: Cloudflare Pages deployment has limitations due to Edge Runtime constraints.
> See the [Cloudflare guide](deploy-cloudflare.md) for details and known issues.
### Docker Deployments
@@ -136,11 +135,6 @@ Deploy big-AGI on a Kubernetes cluster for enhanced scalability and management.
For more detailed instructions on Kubernetes deployment, including updating and troubleshooting, refer to our [Kubernetes Deployment Guide](deploy-k8s.md).
### Midori AI Subsystem for Docker Deployment
Follow the instructions found on [Midori AI Subsystem Site](https://io.midori-ai.xyz/subsystem/manager/)
for your host OS. After completing the setup process, install the Big-AGI docker backend to the Midori AI Subsystem.
## Enterprise-Grade Installation
For businesses seeking a fully-managed, scalable solution, consider our managed installations.
@@ -151,6 +145,6 @@ Enjoy all the features of big-AGI without the hassle of infrastructure managemen
Join our vibrant community of developers, researchers, and AI enthusiasts. Share your projects, get help, and collaborate with others.
- [Discord Community](https://discord.gg/MkH4qj2Jp9)
- [Twitter](https://twitter.com/enricoros)
- [X (Twitter)](https://x.com/enricoros)
For any questions or inquiries, please don't hesitate to [reach out to our team](mailto:hello@big-agi.com).
+1
View File
@@ -28,6 +28,7 @@ stringData:
LOCALAI_API_HOST: ""
LOCALAI_API_KEY: ""
MISTRAL_API_KEY: ""
MOONSHOT_API_KEY: ""
OLLAMA_API_HOST: ""
OPENPIPE_API_KEY: ""
OPENROUTER_API_KEY: ""
+4
View File
@@ -1,3 +1,7 @@
---
unlisted: true
---
# ReAct: question answering with Reasoning and Actions
## What is ReAct?
+23
View File
@@ -0,0 +1,23 @@
import { defineConfig } from "eslint/config";
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});
export default defineConfig([{
extends: compat.extends("next/core-web-vitals"),
rules: {
//
"react-hooks/exhaustive-deps": ["warn", {
additionalHooks: "(useMemoShallowStable)",
}],
},
}]);
+12 -8
View File
@@ -1,35 +1,39 @@
# Knowledge Base
## Knowledge Base
Internal documentation for Big-AGI architecture and systems, for use by AI agents and developers.
Architecture and system documentation is available in the `/kb/` knowledge base, for use by AI agents and developers.
**Structure:**
- `/kb/KB.md` - Already in context: this text
- `/kb/vision-inlined.md` - Already in context (next section): long-term vision and north stars
- `/kb/modules/` - Core business logic (e.g. AIX)
- `/kb/systems/` - Infrastructure (routing, startup)
## Index
### Modules Documentation
#### AIX - AI Communication Framework
- **[AIX.md](modules/AIX.md)** - AIX streaming architecture documentation
- **[AIX-callers-analysis.md](modules/AIX-callers-analysis.md)** - Analysis of AIX entry points, call chains, common and different rendering, error handling, etc.
#### CSF - Client-Side Fetch
- **[CSF.md](systems/client-side-fetch.md)** - Direct browser-to-API communication for LLM requests
### Systems Documentation
#### Core Platform Systems
- **[app-routing.md](systems/app-routing.md)** - Next.js routing, provider stack, and display state hierarchy
- **[LLM-parameters-system.md](systems/LLM-parameters-system.md)** - Language model parameter flow across the system
- **[LLM-vendor-integration.md](modules/LLM-vendor-integration.md)** - Adding new LLM providers
## Guidelines
### KB Guidelines
### Writing Style
#### Writing Style
- **Direct and factual** - No marketing language
- **Present tense** - "AIX handles streaming" not "AIX will handle"
- **Active voice** - "The system processes" not "Processing is done by"
- **Concrete examples** - Show actual code/config when helpful, briefly
### Maintenance
#### Maintenance
- Remove outdated information when detected!
- Remove outdated knowledge base information when detected
- Keep cross-references current when files move
+3 -2
View File
@@ -7,8 +7,8 @@ This document analyzes all AIX function callers and their patterns for message r
### Three-Tier Call Hierarchy
**Core AIX Functions** (Direct tRPC API callers):
- `aixChatGenerateContent_DMessage_FromConversation` - 8 callers (conversation streaming)
- `aixChatGenerateContent_DMessage` - 6 callers (direct request/response)
- `aixChatGenerateContent_DMessage_FromConversation` - 9 callers (conversation streaming)
- `aixChatGenerateContent_DMessage_orThrow` - 6 callers (direct request/response)
- `aixChatGenerateText_Simple` - 12 callers (text-only utilities)
**Utility Layer** (Hooks & Functions):
@@ -24,6 +24,7 @@ This document analyzes all AIX function callers and their patterns for message r
| **Caller** | **Context** | **Message Removal** | **Placeholder** | **Error Handling** |
|------------|-------------|-------------------|----------------|-------------------|
| **Chat Persona** | `'conversation'` | `messageWasInterruptedAtStart()``removeMessage()` | None | Error fragments |
| **XE Chat Generate** | `'conversation'` | `messageWasInterruptedAtStart()``removeMessage()` | `'...'` placeholder | Error fragments via messageEditor |
| **Beam Scatter** | `'beam-scatter'` | `messageWasInterruptedAtStart()` → empty message | `SCATTER_PLACEHOLDER` | Ray status update |
| **Beam Gather** | `'beam-gather'` | `messageWasInterruptedAtStart()` → clear fragments | `GATHER_PLACEHOLDER` | Re-throw errors |
| **Beam Follow-up** | `'beam-followup'` | `messageWasInterruptedAtStart()` → remove message | `FOLLOWUP_PLACEHOLDER` | Status updates |
+5 -4
View File
@@ -37,6 +37,7 @@ Built with tRPC, it manages the lifecycle of AI-generated content from request t
| Perplexity | ✅ | ❌ (rejected) | | ✅ | Yes + 📦 | |
| TogetherAI | ✅ | ✅ | | ✅ | Yes + 📦 | |
| xAI | | | | | | |
| Z.ai | ✅ | ✅ | Img: ✅ | ✅ | Yes + 📦 | Thinking mode |
| Ollama (2) | ❌ (broken) | ? | | | | |
Notes:
@@ -91,12 +92,12 @@ AIX is organized into the following files and folders:
- Dispatch (`/server/dispatch/`) - Server to AI Provider communication:
- `/server/dispatch/chatGenerate/`: Content Generation with chat-style inputs:
- `./adapters/`: Adapters for creating API requests for different AI protocols (Anthropic, Gemini, OpenAI).
- `./parsers/`: Parsers for parsing streaming/non-streamin responses from different AI protocols (same 3).
- `./adapters/`: Adapters for creating API requests for different AI protocols (Anthropic, Bedrock, Gemini, OpenAI Chat Completions, OpenAI Responses, xAI Responses).
- `./parsers/`: Parsers for parsing streaming/non-streaming responses from different AI protocols (Anthropic, Bedrock Converse, Gemini, OpenAI, OpenAI Responses).
- `chatGenerate.dispatch.ts`: Creates a pipeline to execute Chat Generation to a specific provider.
- `ChatGenerateTransmitter.ts`: Used to serialize and transmit AixWire_Particles to the client.
- `/server/dispatch/wiretypes/`: AI provider Wire Types:
- Type definitions for different AI providers/protocols (Anthropic, Gemini, OpenAI).
- Type definitions for different AI providers/protocols (Anthropic, Bedrock Converse, Gemini, OpenAI, xAI).
- `stream.demuxers.ts`: Handles demuxing of different stream formats.
## 3. Architecture Diagram
@@ -159,7 +160,7 @@ sequenceDiagram
AIX Client ->> AIX Client: Display error message
else DMessageDocPart
AIX Client ->> AIX Client: Process and display document
else DMetaPlaceholderPart
else DVoidPlaceholderPart
AIX Client ->> AIX Client: Handle placeholder (non-submitted)
end
end
+126
View File
@@ -0,0 +1,126 @@
# LLM Vendor Integration Guide
How to add support for new LLM providers in Big-AGI. There are two integration paths, and
the dynamic backend path is strongly preferred for new vendors.
## Integration Paths
### Path 1: Dynamic Backend (preferred)
For any provider with an **OpenAI-compatible API** (which is nearly all new providers).
**Surface area**: 1-2 files, no UI changes, no registry changes.
A dynamic backend provides:
- Hostname-based auto-detection when the user adds the provider's API URL
- Automatic model list parsing with vendor-specific metadata (pricing, context windows, capabilities)
- Zero UI code - uses the existing "Custom OpenAI-compatible" service setup
**Files touched**:
- `src/modules/llms/server/openai/models/{vendor}.models.ts` (required) - model definitions + hostname heuristic
- `src/modules/llms/server/openai/wiretypes/{vendor}.wiretypes.ts` (optional) - Zod schemas for vendor-specific wire format
- `src/modules/llms/server/listModels.dispatch.ts` - add heuristic to the detection chain (2 lines)
**What the model file must export**:
```typescript
// 1. Hostname heuristic - returns true when the user's API URL matches this vendor
export function vendorHeuristic(hostname: string): boolean {
return hostname.includes('.vendor-domain.com');
}
// 2. Model converter - transforms vendor's /v1/models response to ModelDescriptionSchema[]
export function vendorModelsToModelDescriptions(wireModels: unknown): ModelDescriptionSchema[] {
// Parse wire format, map to ModelDescriptionSchema with:
// - id, label, description
// - contextWindow, maxCompletionTokens
// - interfaces (Chat, Vision, Fn, Reasoning, etc.)
// - chatPrice (input/output per token)
// - parameterSpecs (temperature, etc.)
}
```
**Existing examples**: `novita.models.ts`, `chutesai.models.ts`, `fireworksai.models.ts`
MUST also provide the updated vendor icon like other icons in `src/common/components/icons/vendors/`.
Make sure all the information is available if in the future we want to promote those to full registered vendors.
### Path 2: Registered Vendor (heavyweight, discouraged for new providers)
Full first-class integration with dedicated UI, own dialect, and registry entry. Reserved for
providers with **non-OpenAI protocols** (Anthropic, Gemini, Ollama) or providers with enough
user demand to warrant a dedicated setup flow.
**Surface area**: 5+ files across 3 directories.
**Files touched**:
- `src/modules/llms/vendors/{vendor}/{vendor}.vendor.ts` - IModelVendor implementation
- `src/modules/llms/vendors/{vendor}/{VendorName}ServiceSetup.tsx` - React UI setup component
- `src/modules/llms/vendors/vendors.registry.ts` - registry entry + ModelVendorId union
- `src/modules/llms/server/openai/models/{vendor}.models.ts` - model definitions
- `src/modules/llms/server/listModels.dispatch.ts` - dispatch case
- Possibly server protocol adapter if not OpenAI-compatible
- Possibly more files, e.g. wires, etc.
- See existing providers and commits that added them for full scope
**When to use this path**: Only when the provider has a meaningfully different API protocol
(not OpenAI-compatible), or when there is significant user demand AND the provider offers
unique capabilities that benefit from dedicated UI (e.g., Ollama's local model management).
When using this path, please add links to upstream documentation. Make sure all constants
are correctly handled everywhere, especially for provider-based switches.
## Decision Criteria
| Question | Dynamic | Registered |
|----------|---------|------------|
| OpenAI-compatible API? | Yes - use dynamic | Only if not OAI-compatible |
| Needs custom auth UI? | No - uses generic fields | Yes - custom setup form |
| Unique protocol? | No | Yes (Anthropic, Gemini, Ollama) |
| User demand level | Any | High + sustained |
| Maintenance burden | Minimal | Significant (5+ files) |
## For External Contributors / Vendor Requests
When vendors or community members request integration via GitHub issues:
1. **Point them to the dynamic backend path** - it's faster to implement, review, and maintain
2. **Requirements for a dynamic backend PR**:
- Model file with heuristic + converter exporting `ModelDescriptionSchema[]`
- Wire types if the vendor's `/v1/models` response has non-standard fields
- Vendor icon (SVG preferred) in `src/common/components/icons/vendors/`
- Two-line addition to the heuristic chain in `listModels.dispatch.ts`
3. **Do not accept**: New registered vendors for OpenAI-compatible providers. The maintenance
cost of a full vendor (UI component, registry entry, dispatch case) is not justified when
dynamic detection achieves the same result with a fraction of the code.
## Architecture Notes
### How Dynamic Detection Works
In `listModels.dispatch.ts`, the `case 'openai':` handler:
1. Fetches `/v1/models` from the user-provided API host
2. Runs the hostname through a chain of heuristics (in order)
3. First matching heuristic's converter is used to parse models
4. Falls back to stock OpenAI parsing if no heuristic matches
### Hostname Security
Hostname matching uses `llmsHostnameMatches()` from `openai.access.ts` which parses the
URL properly to prevent DNS spoofing. Always use `.includes()` on the parsed hostname,
never on the raw URL string.
### Key Types
- `ModelDescriptionSchema` (`llm.server.types.ts`) - output type for all model converters
- `DModelInterfaceV1` (`llms.types.ts`) - capability flags (Chat, Vision, Fn, Reasoning, etc.)
- `IModelVendor` (`vendors/IModelVendor.ts`) - interface for registered vendors only
- `ManualMappings` / `KnownModel` (`models.mappings.ts`) - server-side model patches
### File Locations
- Dynamic backends: `src/modules/llms/server/openai/models/`
- Wire types: `src/modules/llms/server/openai/wiretypes/`
- Dispatch: `src/modules/llms/server/listModels.dispatch.ts`
- Registered vendors: `src/modules/llms/vendors/*/`
- Vendor icons: `src/common/components/icons/vendors/`
- Type definitions: `src/modules/llms/server/llm.server.types.ts`
+8 -19
View File
@@ -13,12 +13,9 @@ The LLM parameters system operates across five layers that transform parameters
The `DModelParameterRegistry` defines all available parameters with their constraints and metadata. Each parameter includes type information, validation rules, and default behavior.
**Example**: `llmVndOaiReasoningEffort4` defines a 4-value enum with 'medium' as the required fallback.
**Default Value System**: The registry supports multiple default mechanisms:
- `initialValue` - Parameter's base default (e.g., `llmVndOaiRestoreMarkdown: true`)
- `requiredFallback` - Fallback for required parameters (e.g., `llmTemperature: 0.5`)
- `nullable` - Parameters that can be explicitly null to skip API transmission
- `initialValue` - Parameter's base default (e.g., `llmVndOaiRestoreMarkdown: true`)
### Layer 2: Model Specifications
**File**: `src/modules/llms/server/llm.server.types.ts`
@@ -27,7 +24,6 @@ Models declare which parameters they support through `parameterSpecs` arrays. Ea
```typescript
parameterSpecs: [
{ paramId: 'llmVndOaiReasoningEffort4' },
{ paramId: 'llmVndAntThinkingBudget', initialValue: 1024 }, // Override default
{ paramId: 'llmVndGeminiThinkingBudget', rangeOverride: [0, 8192] }, // Custom range
]
@@ -51,20 +47,14 @@ Shows only parameters that are:
- Not marked as `hidden`
**Value Resolution**: Both UIs use `getAllModelParameterValues()` to merge:
1. **Fallback values** - Required parameters get their `requiredFallback` values
1. **Fallback values** - Implicit parameters get their `LLMImplicitParametersRuntimeFallback` values
2. **Initial values** - Model's `initialParameters` (populated during model creation)
3. **User values** - User's `userParameters` (highest priority)
### Layer 4: AIX Translation
**File**: `src/modules/aix/client/aix.client.ts`
The AIX client transforms DLLM parameters to wire protocol format. This layer handles parameter precedence rules and name transformations:
```typescript
// Parameter precedence: newer 4-value version takes priority over 3-value
...((llmVndOaiReasoningEffort4 || llmVndOaiReasoningEffort) ?
{ vndOaiReasoningEffort: llmVndOaiReasoningEffort4 || llmVndOaiReasoningEffort } : {})
```
The AIX client transforms DLLM parameters to wire protocol format. This layer handles parameter precedence rules and name transformations.
**Client Options**: The system supports parameter overrides through `llmOptionsOverride` and complete replacement via `llmUserParametersReplacement`.
@@ -73,7 +63,7 @@ The AIX client transforms DLLM parameters to wire protocol format. This layer ha
Server-side adapters translate AIX parameters to vendor APIs. Each vendor may interpret parameters differently:
- **OpenAI**: `vndOaiReasoningEffort` `reasoning_effort`
- **OpenAI**: `vndEffort` -> `reasoning_effort`
- **Perplexity**: Reuses OpenAI parameter format
- **OpenAI Responses API**: Maps to structured reasoning config with additional logic
@@ -81,8 +71,8 @@ Server-side adapters translate AIX parameters to vendor APIs. Each vendor may in
When a model is loaded:
1. **Model Creation**: `modelDescriptionToDLLM()` creates the DLLM with empty `initialParameters`
2. **Initial Value Application**: `applyModelParameterInitialValues()` populates initial values from:
1. **Model Creation**: `_createDLLMFromModelDescription()` creates the DLLM with empty `initialParameters`
2. **Initial Value Application**: `applyModelParameterSpecsInitialValues()` populates initial values from:
- Model spec `initialValue` (highest priority)
- Registry `initialValue` (fallback)
3. **Runtime Resolution**: `getAllModelParameterValues()` creates final parameter set:
@@ -105,7 +95,7 @@ When a model is loaded:
The system maintains type safety through:
- `DModelParameterId` union from registry keys
- `DModelParameterValue<T>` conditional types for values
- `DModelParameterSpec<T>` interfaces for specifications
- `DModelParameterSpecAny` interfaces for specifications
- Runtime validation via Zod schemas at API boundaries
## Model Variant Pattern
@@ -117,7 +107,6 @@ Some vendors use model variants to enable features, for instance:
## Migration and Compatibility
The architecture supports parameter evolution:
- **Version Coexistence**: Both `llmVndOaiReasoningEffort` and `llmVndOaiReasoningEffort4` exist simultaneously
- **Precedence Rules**: Newer parameters take priority during AIX translation
- **Graceful Degradation**: Unknown parameters log warnings but don't break functionality
@@ -128,4 +117,4 @@ The architecture supports parameter evolution:
- **UI Controls**: `src/modules/llms/models-modal/LLMParametersEditor.tsx`
- **AIX Translation**: `src/modules/aix/client/aix.client.ts`
- **Wire Types**: `src/modules/aix/server/api/aix.wiretypes.ts`
- **Vendor Adapters**: `src/modules/aix/server/dispatch/chatGenerate/adapters/*.ts`
- **Vendor Adapters**: `src/modules/aix/server/dispatch/chatGenerate/adapters/*.ts`
+29
View File
@@ -0,0 +1,29 @@
# CSF - Client-Side Fetch
Client-Side Fetch (CSF), surfaced to users as **"Direct Connection"**, enables direct browser-to-API communication, bypassing the server for LLM requests. When enabled, the browser makes requests directly to vendor APIs (e.g., `api.openai.com`, `api.groq.com`) instead of routing through the Next.js server. This reduces latency, decreases server load, and is particularly useful for local models where the browser can communicate directly with Ollama or LM Studio.
## User-facing tradeoffs (Direct Connection vs via-server)
Wins when Direct Connection is on:
- **No 4.5MB upload limit** (Vercel body-size cap does not apply to direct browser-to-API requests).
- **No 300s function timeout** (Vercel serverless/edge timeout does not apply; call duration is bound only by the AI service).
- **More privacy**: connection metadata (IP, timestamp, edge region, Vercel telemetry) is not observable by the Big-AGI edge server.
Costs:
- **Slightly more downlink bandwidth**: when traffic passes through the Big-AGI server, repetitive streaming frames are shed/compacted; direct streams arrive verbatim.
Availability requires both:
1. The API key is on the **client** (localStorage), not a server-side env var. Server-key deployments cannot use CSF because the browser has no credential to send.
2. The AI service **allows CORS** from browsers. Most major providers do; some require specific headers which Big-AGI sets.
Net: Direct Connection is a win on speed, limits, and privacy whenever the provider permits it. It is unavailable when keys are server-side or the provider blocks browser-origin requests.
## Implementation
CSF is implemented as an opt-in setting stored as `csf: boolean` in each vendor's service settings. The vendor interface exposes `csfAvailable?: (setup) => boolean` to determine if CSF can be enabled (typically checking if an API key or host is configured). The actual execution happens in `aix.client.direct-chatGenerate.ts` which dynamically imports when CSF is active, making direct fetch calls using the same wire protocols as the server.
All 20+ supported vendors (OpenAI, Anthropic, Gemini, Ollama, LocalAI, Deepseek, Groq, Mistral, xAI, OpenRouter, Perplexity, Together AI, Alibaba, Moonshot, OpenPipe, LM Studio, Z.ai, Azure, Bedrock) support CSF. Cloud vendors require CORS support from the API provider (all tested vendors return `access-control-allow-origin: *`). Local vendors (Ollama, LocalAI, LM Studio) require CORS to be enabled on the local server.
## UI
The CSF toggle appears in each vendor's setup panel under "Advanced" settings, labeled "Direct Connection". It becomes visible when the prerequisites are met (API key present for cloud vendors, host configured for local vendors). The setting is managed through `useModelServiceClientSideFetch` hook which provides `csfAvailable`, `csfActive`, `csfToggle`, and `csfReset` for UI consumption.
+3
View File
@@ -0,0 +1,3 @@
## Strategic Vision
If provided, the following influences the long-term vision, product and architectural goals/north stars for Big-AGI.
+29 -8
View File
@@ -1,4 +1,5 @@
import type { NextConfig } from 'next';
import type { WebpackConfigContext } from 'next/dist/server/config-shared';
import { execSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
@@ -17,7 +18,7 @@ process.env.NEXT_PUBLIC_BUILD_HASH = (buildHash || '').slice(0, 10);
process.env.NEXT_PUBLIC_BUILD_PKGVER = JSON.parse('' + readFileSync(new URL('./package.json', import.meta.url))).version;
process.env.NEXT_PUBLIC_BUILD_TIMESTAMP = new Date().toISOString();
process.env.NEXT_PUBLIC_DEPLOYMENT_TYPE = process.env.NEXT_PUBLIC_DEPLOYMENT_TYPE || (process.env.VERCEL_ENV ? `vercel-${process.env.VERCEL_ENV}` : 'local'); // Docker or custom, Vercel
console.log(` 🧠 \x1b[1mbig-AGI\x1b[0m v${process.env.NEXT_PUBLIC_BUILD_PKGVER} (@${process.env.NEXT_PUBLIC_BUILD_HASH})`);
console.log(` 🧠 \x1b[1mbig-AGI\x1b[0m v${process.env.NEXT_PUBLIC_BUILD_PKGVER} (@${process.env.NEXT_PUBLIC_BUILD_HASH}${process.env.VERCEL_ENV ? `, \x1b[2mV:\x1b[0m${process.env.VERCEL_ENV}` : ''}, \x1b[2mN:\x1b[0m${process.env.NODE_ENV})`);
// Non-default build types
const buildType =
@@ -29,7 +30,7 @@ buildType && console.log(` 🧠 big-AGI: building for ${buildType}...\n`);
/** @type {import('next').NextConfig} */
let nextConfig: NextConfig = {
reactStrictMode: true,
reactStrictMode: !process.env.NO_STRICT_MODE, // default: enabled
// [exports] https://nextjs.org/docs/advanced-features/static-html-export
...(buildType && {
@@ -47,7 +48,7 @@ let nextConfig: NextConfig = {
// NOTE: we may not be needing this anymore, as we use '@cloudflare/puppeteer'
serverExternalPackages: ['puppeteer-core'],
webpack: (config: any, { isServer }: { isServer: boolean }) => {
webpack: (config: any, { isServer, webpack /*, dev, nextRuntime*/ }: WebpackConfigContext) => {
// @mui/joy: anything material gets redirected to Joy
config.resolve.alias['@mui/material'] = '@mui/joy';
@@ -57,8 +58,28 @@ let nextConfig: NextConfig = {
layers: true,
};
// fix warnings for async functions in the browser (https://github.com/vercel/next.js/issues/64792)
// client-side bundling
if (!isServer) {
/**
* AIX client-side
* We replace certain server-only modules with client-side mocks, to reuse the exact same imports
* while avoiding importing server-only code which would break the build or break at runtime.
*/
const serverToClientMocks: ReadonlyArray<[RegExp, string]> = [
[/\/posthog\.server/, '/posthog.client-mock'],
[/\/env\.server/, '/env.client-mock'],
];
config.plugins = [
...config.plugins,
...serverToClientMocks.map(([pattern, replacement]) =>
new webpack.NormalModuleReplacementPlugin(pattern, (resource: any) => {
// console.log(' 🧠 [WEBPACK REPLACEMENT]:', resource.request, '->', resource.request.replace(pattern, replacement));
resource.request = resource.request.replace(pattern, replacement);
}),
),
];
// cosmetic: fix warnings for (absent!) top-level awaits in the browser (https://github.com/vercel/next.js/issues/64792)
config.output.environment = { ...config.output.environment, asyncFunction: true };
}
@@ -108,9 +129,9 @@ let nextConfig: NextConfig = {
// },
};
// Validate environment variables, if set at build time. Will be actually read and used at runtime.
import { verifyBuildTimeVars } from '~/server/env';
verifyBuildTimeVars();
// Validate environment variables at build time, if required. Server env vars will be actually read and used at runtime (cloud/edge).
import { env as validateEnv } from '~/server/env.server';
void validateEnv; // Triggers env validation - throws if required vars are missing
// PostHog error reporting with source maps for production builds
import { withPostHogConfig } from '@posthog/nextjs-config';
@@ -120,7 +141,7 @@ if (process.env.POSTHOG_API_KEY && process.env.POSTHOG_ENV_ID) {
personalApiKey: process.env.POSTHOG_API_KEY,
envId: process.env.POSTHOG_ENV_ID,
host: 'https://us.i.posthog.com', // backtrace upload host
verbose: false,
logLevel: 'error', // lowered, too noisy
sourcemaps: {
enabled: process.env.NODE_ENV === 'production',
project: 'big-agi',
+2789 -1371
View File
File diff suppressed because it is too large Load Diff
+41 -33
View File
@@ -1,8 +1,9 @@
{
"name": "big-agi",
"version": "2.0.0",
"version": "2.0.4",
"private": true,
"author": "Enrico Ros <enrico.ros@gmail.com>",
"author": "Enrico Ros <enrico@big-agi.com> (https://www.enricoros.com)",
"homepage": "https://big-agi.com",
"repository": "https://github.com/enricoros/big-agi",
"scripts": {
"dev": "next dev --turbopack",
@@ -11,10 +12,13 @@
"build": "next build",
"start": "next start",
"lint": "next lint",
"tsclint": "tsc --noEmit --pretty",
"postinstall": "prisma generate --no-hints",
"gen:icon-sprites": "node tools/develop/gen-icon-sprites/generate-llm-sprites.ts",
"db:push": "prisma db push",
"db:studio": "prisma studio",
"vercel:env:pull": "npx vercel env pull .env.development.local"
"vercel:env:pull": "npx vercel env pull .env.development.local",
"sharp:win32_x64": "npm install --os=win32 --cpu=x64 sharp"
},
"prisma": {
"schema": "src/server/prisma/schema.prisma"
@@ -28,70 +32,74 @@
"@emotion/react": "^11.14.0",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.14.1",
"@googleworkspace/drive-picker-react": "^0.2.0",
"@mui/icons-material": "^5.18.0",
"@mui/joy": "^5.0.0-beta.52",
"@next/bundle-analyzer": "~15.1.8",
"@next/bundle-analyzer": "~15.1.12",
"@prisma/client": "~5.22.0",
"@tanstack/react-query": "5.90.3",
"@tanstack/react-query": "5.90.21",
"@tanstack/react-virtual": "^3.13.22",
"@trpc/client": "11.5.1",
"@trpc/next": "11.5.1",
"@trpc/react-query": "11.5.1",
"@trpc/server": "11.5.1",
"@vercel/analytics": "^1.5.0",
"@vercel/speed-insights": "^1.2.0",
"@vercel/analytics": "^1.6.1",
"@vercel/speed-insights": "^1.3.1",
"aws4fetch": "^1.0.20",
"browser-fs-access": "^0.38.0",
"cheerio": "^1.1.2",
"csv-stringify": "^6.6.0",
"dexie": "^4.0.11",
"dexie-react-hooks": "^1.1.7",
"diff": "^8.0.2",
"eventemitter3": "^5.0.1",
"dexie": "~4.0.11",
"dexie-react-hooks": "~1.1.7",
"diff": "^8.0.3",
"eventemitter3": "^5.0.4",
"idb-keyval": "^6.2.2",
"mammoth": "^1.11.0",
"nanoid": "^5.1.6",
"next": "~15.1.8",
"next": "~15.1.12",
"nprogress": "^0.2.0",
"pdfjs-dist": "5.4.54",
"posthog-js": "^1.275.3",
"posthog-node": "^5.10.0",
"posthog-js": "^1.369.0",
"posthog-node": "^5.29.2",
"prismjs": "^1.30.0",
"puppeteer-core": "^24.25.0",
"puppeteer-core": "^24.40.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.65.0",
"react-hook-form": "^7.71.2",
"react-markdown": "^10.1.0",
"react-player": "^3.3.3",
"react-player": "^3.4.0",
"react-resizable-panels": "^3.0.6",
"react-timeago": "^8.3.0",
"rehype-katex": "^7.0.1",
"remark-gfm": "^4.0.1",
"remark-mark-highlight": "^0.1.1",
"remark-math": "^6.0.0",
"sharp": "^0.33.5",
"superjson": "^2.2.2",
"tesseract.js": "^6.0.1",
"sharp": "^0.34.5",
"superjson": "^2.2.6",
"tesseract.js": "^7.0.0",
"tiktoken": "^1.0.22",
"turndown": "^7.2.1",
"zod": "^4.1.12",
"turndown": "^7.2.2",
"zod": "^4.3.6",
"zustand": "5.0.7"
},
"devDependencies": {
"@posthog/nextjs-config": "^1.3.2",
"@types/node": "^24.7.2",
"@posthog/nextjs-config": "~1.6.4",
"@types/node": "^25.6.0",
"@types/nprogress": "^0.2.3",
"@types/prismjs": "^1.26.5",
"@types/react": "^19.2.2",
"@types/prismjs": "^1.26.6",
"@types/react": "^19.2.14",
"@types/react-csv": "^1.1.10",
"@types/react-dom": "^19.2.2",
"@types/turndown": "^5.0.5",
"@types/react-dom": "^19.2.3",
"@types/turndown": "^5.0.6",
"cross-env": "^10.1.0",
"eslint": "^9.37.0",
"eslint-config-next": "~15.1.8",
"prettier": "^3.6.2",
"eslint": "^9.39.4",
"eslint-config-next": "~15.1.12",
"prettier": "^3.8.2",
"prisma": "~5.22.0",
"typescript": "^5.9.3"
"tsx": "^4.21.0",
"typescript": "^6.0.2"
},
"engines": {
"node": "^26.0.0 || ^24.0.0 || ^22.0.0 || ^20.0.0"
"node": "^24.0.0 || ^22.0.0 || ^20.0.0"
}
}
+9 -4
View File
@@ -1,12 +1,17 @@
import * as React from 'react';
import Head from 'next/head';
import dynamic from 'next/dynamic';
import { MyAppProps } from 'next/app';
import { Analytics as VercelAnalytics } from '@vercel/analytics/next';
import { SpeedInsights as VercelSpeedInsights } from '@vercel/speed-insights/next';
import { Brand } from '~/common/app.config';
import { apiQuery } from '~/common/util/trpc.client';
// [server-client-safe] dynamic imports to avoid webpack bundling issues with next/navigation
const VercelAnalytics = dynamic(() => import('@vercel/analytics/next').then(mod => mod.Analytics), { ssr: false });
const VercelSpeedInsights = dynamic(() => import('@vercel/speed-insights/next').then(mod => mod.SpeedInsights), { ssr: false });
import 'katex/dist/katex.min.css';
import '~/common/styles/CodePrism.css';
import '~/common/styles/GithubMarkdown.css';
@@ -55,10 +60,10 @@ const Big_AGI_App = ({ Component, emotionCache, pageProps }: MyAppProps) => {
</ProviderSingleTab>
</ProviderTheming>
{Is.Deployment.VercelFromFrontend && <VercelAnalytics debug={false} />}
{Is.Deployment.VercelFromFrontend && <VercelSpeedInsights debug={false} sampleRate={1 / 2} />}
{hasGoogleAnalytics && <OptionalGoogleAnalytics />}
{hasPostHogAnalytics && <OptionalPostHogAnalytics />}
{Is.Deployment.VercelFromFrontend && <VercelAnalytics debug={false} />}
{Is.Deployment.VercelFromFrontend && <VercelSpeedInsights debug={false} sampleRate={1 / 2} />}
</>;
};
+20 -4
View File
@@ -37,14 +37,31 @@ export default function MyDocument({ emotionStyleTags }: MyDocumentProps) {
<meta property='og:site_name' content={Brand.Meta.SiteName} />
<meta property='og:type' content='website' />
{/* Twitter */}
<meta property='twitter:card' content='summary_large_image' />
{/* Twitter / X */}
<meta name='twitter:card' content='summary_large_image' />
<meta property='twitter:url' content={Brand.URIs.Home} />
<meta property='twitter:title' content={Brand.Title.Common} />
<meta property='twitter:description' content={Brand.Meta.Description} />
{Brand.URIs.CardImage && <meta property='twitter:image' content={Brand.URIs.CardImage} />}
<meta name='twitter:site' content={Brand.Meta.TwitterSite} />
<meta name='twitter:card' content='summary_large_image' />
<meta name='twitter:creator' content='@enricoros' />
<link rel='canonical' href={Brand.URIs.Home} />
{/* Author & Structured Data */}
<meta name='author' content='Enrico Ros' />
<link rel='author' href='https://www.enricoros.com' />
<script type='application/ld+json' dangerouslySetInnerHTML={{ __html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
'name': 'Big-AGI',
'url': 'https://big-agi.com',
'applicationCategory': 'ProductivityApplication',
'operatingSystem': 'All, Web',
'description': Brand.Meta.Description,
'sameAs': ['https://github.com/enricoros/big-agi', 'https://discord.gg/MkH4qj2Jp9',],
'author': { '@type': 'Person', 'name': 'Enrico Ros', 'url': 'https://www.enricoros.com' },
'publisher': { '@type': 'Organization', 'name': 'Token Fabrics LLC', 'url': 'https://www.tokenfabrics.com' },
}) }} />
{/* Style Sheets (injected and server-side) */}
<meta name='emotion-insertion-point' content='' />
@@ -111,7 +128,6 @@ MyDocument.getInitialProps = async (ctx: DocumentContext) => {
<style
data-emotion={`${style.key} ${style.ids.join(' ')}`}
key={style.key}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: style.css }}
/>
));
+1 -2
View File
@@ -18,7 +18,7 @@ import { ROUTE_APP_CHAT, ROUTE_INDEX } from '~/common/app.routes';
import { Release } from '~/common/app.release';
// capabilities access
import { useCapabilityBrowserSpeechRecognition, useCapabilityElevenLabs, useCapabilityTextToImage } from '~/common/components/useCapabilities';
import { useCapabilityBrowserSpeechRecognition, useCapabilityTextToImage } from '~/common/components/useCapabilities';
// stores access
import { getLLMsDebugInfo } from '~/common/stores/llms/store-llms';
@@ -95,7 +95,6 @@ function AppDebug() {
const cProduct = {
capabilities: {
mic: useCapabilityBrowserSpeechRecognition(),
elevenLabs: useCapabilityElevenLabs(),
textToImage: useCapabilityTextToImage(),
},
models: getLLMsDebugInfo(),
+1 -1
View File
@@ -3,7 +3,7 @@
"short_name": "big-AGI",
"theme_color": "#32383E",
"background_color": "#9FA6AD",
"description": "Your Generative AI Suite",
"description": "Open-source AI workspace. Multi-model reasoning and personas for maximum control.",
"categories": [
"productivity",
"AI",
+1 -1
View File
@@ -20,7 +20,7 @@ function initTestConversation(): DConversation {
return conversation;
}
function initTestBeamStore(messages: DMessage[], beamStore: BeamStoreApi = createBeamVanillaStore()): BeamStoreApi {
function initTestBeamStore(messages: DMessage[], beamStore: BeamStoreApi): BeamStoreApi {
beamStore.getState().open(messages, null, false, (content) => alert(content));
return beamStore;
}
+16 -13
View File
@@ -6,13 +6,15 @@ import ChatIcon from '@mui/icons-material/Chat';
import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import MicIcon from '@mui/icons-material/Mic';
import RecordVoiceOverTwoToneIcon from '@mui/icons-material/RecordVoiceOverTwoTone';
import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
import { useSpeexGlobalEngine } from '~/modules/speex/store-module-speex';
import { PhVoice } from '~/common/components/icons/phosphor/PhVoice';
import { animationColorRainbow } from '~/common/util/animUtils';
import { navigateBack } from '~/common/app.routes';
import { optimaOpenPreferences } from '~/common/layout/optima/useOptima';
import { useCapabilityBrowserSpeechRecognition, useCapabilityElevenLabs } from '~/common/components/useCapabilities';
import { useCapabilityBrowserSpeechRecognition } from '~/common/components/useCapabilities';
import { useChatStore } from '~/common/stores/chat/store-chats';
import { useUICounter } from '~/common/stores/store-ui';
@@ -45,7 +47,7 @@ export function CallWizard(props: { strict?: boolean, conversationId: string | n
// external state
const recognition = useCapabilityBrowserSpeechRecognition();
const synthesis = useCapabilityElevenLabs();
const speexGlobalEngine = useSpeexGlobalEngine();
const chatIsEmpty = useChatStore(state => {
if (!props.conversationId)
return false;
@@ -56,17 +58,18 @@ export function CallWizard(props: { strict?: boolean, conversationId: string | n
// derived state
const outOfTheBlue = !props.conversationId;
const overriddenEmptyChat = chatEmptyOverride || !chatIsEmpty;
const overriddenEmptyChat = outOfTheBlue || chatEmptyOverride || !chatIsEmpty;
const overriddenRecognition = recognitionOverride || recognition.mayWork;
const allGood = overriddenEmptyChat && overriddenRecognition && synthesis.mayWork;
const fatalGood = overriddenRecognition && synthesis.mayWork;
const synthesisShallWork = !!speexGlobalEngine;
const allGood = overriddenEmptyChat && overriddenRecognition && synthesisShallWork;
const fatalGood = overriddenRecognition && synthesisShallWork;
const handleOverrideChatEmpty = React.useCallback(() => setChatEmptyOverride(true), []);
const handleOverrideRecognition = React.useCallback(() => setRecognitionOverride(true), []);
const handleConfigureElevenLabs = React.useCallback(() => optimaOpenPreferences('voice'), []);
const handleConfigureVoice = React.useCallback(() => optimaOpenPreferences('voice'), []);
const handleFinishButton = React.useCallback(() => {
if (!allGood)
@@ -128,17 +131,17 @@ export function CallWizard(props: { strict?: boolean, conversationId: string | n
{/* Text to Speech status */}
<StatusCard
icon={<RecordVoiceOverTwoToneIcon />}
icon={<PhVoice />}
text={
(synthesis.mayWork ? 'Voice synthesis should be ready.' : 'There might be an issue with ElevenLabs voice synthesis.')
+ (synthesis.isConfiguredServerSide ? '' : (synthesis.isConfiguredClientSide ? '' : ' Please add your API key in the settings.'))
(synthesisShallWork ? 'Voice synthesis should be ready.' : 'There might be an issue with voice synthesis.')
// + (synthesis.isConfiguredServerSide ? '' : (synthesis.isConfiguredClientSide ? '' : ' Please add your API key in the settings.'))
}
button={synthesis.mayWork ? undefined : (
<Button variant='outlined' onClick={handleConfigureElevenLabs} sx={{ mx: 1 }}>
button={synthesisShallWork ? undefined : (
<Button variant='outlined' onClick={handleConfigureVoice} sx={{ mx: 1 }}>
Configure
</Button>
)}
hasIssue={!synthesis.mayWork}
hasIssue={!synthesisShallWork}
/>
{/*<Typography>*/}
+1 -1
View File
@@ -317,7 +317,7 @@ export function Contacts(props: { setCallIntent: (intent: AppCallIntent) => void
issue={354}
text='Call App: Support thread and compatibility matrix'
note={<>
Voice input uses the HTML Web Speech API, and speech output requires an ElevenLabs API Key.
Voice input uses the HTML Web Speech API.
</>}
// note2='Please report any issues you encounter'
sx={{
+24 -37
View File
@@ -7,16 +7,15 @@ import CallEndIcon from '@mui/icons-material/CallEnd';
import CallIcon from '@mui/icons-material/Call';
import MicIcon from '@mui/icons-material/Mic';
import MicNoneIcon from '@mui/icons-material/MicNone';
import RecordVoiceOverTwoToneIcon from '@mui/icons-material/RecordVoiceOverTwoTone';
import { ScrollToBottom } from '~/common/scroll-to-bottom/ScrollToBottom';
import { ScrollToBottomButton } from '~/common/scroll-to-bottom/ScrollToBottomButton';
import { useChatLLMDropdown } from '../chat/components/layout-bar/useLLMDropdown';
import { SystemPurposeId, SystemPurposes } from '../../data';
import { elevenLabsSpeakText } from '~/modules/elevenlabs/elevenlabs.client';
import { AixChatGenerateContent_DMessage, aixChatGenerateContent_DMessage_FromConversation } from '~/modules/aix/client/aix.client';
import { useElevenLabsVoiceDropdown } from '~/modules/elevenlabs/useElevenLabsVoiceDropdown';
import { aixChatGenerateContent_DMessage_FromConversation, AixChatGenerateContent_DMessageGuts } from '~/modules/aix/client/aix.client';
import { speakText } from '~/modules/speex/speex.client';
import type { OptimaBarControlMethods } from '~/common/layout/optima/bar/OptimaBarDropdown';
import { AudioPlayer } from '~/common/util/audio/AudioPlayer';
@@ -24,13 +23,14 @@ import { Link } from '~/common/components/Link';
import { OptimaPanelGroupedList } from '~/common/layout/optima/panel/OptimaPanelGroupedList';
import { OptimaPanelIn, OptimaToolbarIn } from '~/common/layout/optima/portals/OptimaPortalsIn';
import { SpeechResult, useSpeechRecognition } from '~/common/components/speechrecognition/useSpeechRecognition';
import { clipboardInterceptCtrlCForCleanup } from '~/common/util/clipboardUtils';
import { conversationTitle, remapMessagesSysToUsr } from '~/common/stores/chat/chat.conversation';
import { createDMessageFromFragments, createDMessageTextContent, DMessage, messageFragmentsReduceText, messageWasInterruptedAtStart } from '~/common/stores/chat/chat.message';
import { createErrorContentFragment } from '~/common/stores/chat/chat.fragments';
import { launchAppChat, navigateToIndex } from '~/common/app.routes';
import { useChatStore } from '~/common/stores/chat/store-chats';
import { useGlobalShortcuts } from '~/common/components/shortcuts/useGlobalShortcuts';
import { usePlayUrl } from '~/common/util/audio/usePlayUrl';
import { usePlayUrlInterval } from './state/usePlayUrlInterval';
import type { AppCallIntent } from './AppCall';
import { CallAvatar } from './components/CallAvatar';
@@ -43,18 +43,13 @@ import { useAppCallStore } from './state/store-app-call';
function CallMenu(props: {
pushToTalk: boolean,
setPushToTalk: (pushToTalk: boolean) => void,
override: boolean,
setOverride: (overridePersonaVoice: boolean) => void,
}) {
// external state
const { grayUI, toggleGrayUI } = useAppCallStore();
const { voicesDropdown } = useElevenLabsVoiceDropdown(false, !props.override);
const handlePushToTalkToggle = () => props.setPushToTalk(!props.pushToTalk);
const handleChangeVoiceToggle = () => props.setOverride(!props.override);
return <OptimaPanelGroupedList title='Call'>
<MenuItem onClick={handlePushToTalkToggle}>
@@ -63,17 +58,6 @@ function CallMenu(props: {
<Switch checked={props.pushToTalk} onChange={handlePushToTalkToggle} sx={{ ml: 'auto' }} />
</MenuItem>
<MenuItem onClick={handleChangeVoiceToggle}>
<ListItemDecorator><RecordVoiceOverTwoToneIcon /></ListItemDecorator>
Change Voice
<Switch checked={props.override} onChange={handleChangeVoiceToggle} sx={{ ml: 'auto' }} />
</MenuItem>
<MenuItem>
<ListItemDecorator>{' '}</ListItemDecorator>
{voicesDropdown}
</MenuItem>
<ListDivider />
<MenuItem onClick={toggleGrayUI}>
@@ -98,7 +82,6 @@ export function Telephone(props: {
const [avatarClickCount, setAvatarClickCount] = React.useState<number>(0);// const [micMuted, setMicMuted] = React.useState(false);
const [callElapsedTime, setCallElapsedTime] = React.useState<string>('00:00');
const [callMessages, setCallMessages] = React.useState<DMessage[]>([]);
const [overridePersonaVoice, setOverridePersonaVoice] = React.useState<boolean>(false);
const [personaTextInterim, setPersonaTextInterim] = React.useState<string | null>(null);
const [pushToTalk, setPushToTalk] = React.useState(true);
const [stage, setStage] = React.useState<'ring' | 'declined' | 'connected' | 'ended'>('ring');
@@ -118,7 +101,7 @@ export function Telephone(props: {
}));
const persona = SystemPurposes[props.callIntent.personaId as SystemPurposeId] ?? undefined;
const personaCallStarters = persona?.call?.starters ?? undefined;
const personaVoiceId = overridePersonaVoice ? undefined : (persona?.voices?.elevenLabs?.voiceId ?? undefined);
// const personaVoiceSelector = React.useMemo(() => personaGetVoiceSelector(persona), [persona]);
const personaSystemMessage = persona?.systemMessage ?? undefined;
// hooks and speech
@@ -144,11 +127,11 @@ export function Telephone(props: {
// pickup / hangup
React.useEffect(() => {
!isRinging && AudioPlayer.playUrl(isConnected ? '/sounds/chat-begin.mp3' : '/sounds/chat-end.mp3');
!isRinging && void AudioPlayer.playUrl(isConnected ? '/sounds/chat-begin.mp3' : '/sounds/chat-end.mp3').catch(() => {/* autoplay may be blocked */});
}, [isRinging, isConnected]);
// ringtone
usePlayUrl(isRinging ? '/sounds/chat-ringtone.mp3' : null, 300, 2800 * 2);
usePlayUrlInterval(isRinging ? '/sounds/chat-ringtone.mp3' : null, 300, 2800 * 2);
/// Shortcuts
@@ -165,7 +148,6 @@ export function Telephone(props: {
};
// [E] pickup -> seed message and call timer
// FIXME: Overriding the voice will reset the call - not a desired behavior
React.useEffect(() => {
if (!isConnected) return;
@@ -185,11 +167,14 @@ export function Telephone(props: {
setCallMessages([createDMessageTextContent('assistant', firstMessage)]); // [state] set assistant:hello message
// fire/forget
void elevenLabsSpeakText(firstMessage, personaVoiceId, true, true);
// fire/forget - use 'fast' priority for real-time conversation
void speakText(firstMessage,
undefined,
{ label: 'Call', priority: 'fast' },
);
return () => clearInterval(interval);
}, [isConnected, personaCallStarters, personaVoiceId]);
}, [isConnected, personaCallStarters]);
// [E] persona streaming response - upon new user message
React.useEffect(() => {
@@ -254,7 +239,7 @@ export function Telephone(props: {
'call',
callMessages[0].id,
{ abortSignal: responseAbortController.current.signal },
(update: AixChatGenerateContent_DMessage, _isDone: boolean) => {
(update: AixChatGenerateContent_DMessageGuts, _isDone: boolean) => {
const updatedText = messageFragmentsReduceText(update.fragments).trim();
if (updatedText)
setPersonaTextInterim(finalText = updatedText);
@@ -265,14 +250,17 @@ export function Telephone(props: {
if (messageWasInterruptedAtStart(status.lastDMessage))
return;
// whether status.outcome === 'success' or not, we get a valid DMessage, eventually with Error Fragments inside
// whether status.outcome === 'completed' or not, we get a valid DMessage, eventually with Error Fragments inside
const fullMessage = createDMessageFromFragments('assistant', status.lastDMessage.fragments);
fullMessage.generator = status.lastDMessage.generator;
setCallMessages(messages => [...messages, fullMessage]); // [state] append assistant:call_response
// fire/forget
if (status.outcome === 'success' && finalText?.length >= 1)
void elevenLabsSpeakText(finalText, personaVoiceId, true, true);
// fire/forget - use 'fast' priority for real-time conversation
if (status.outcome === 'completed' && finalText?.length >= 1)
void speakText(finalText,
undefined,
{ label: 'Call', priority: 'fast' },
);
}).catch((err: DOMException) => {
if (err?.name !== 'AbortError') {
@@ -288,7 +276,7 @@ export function Telephone(props: {
responseAbortController.current?.abort();
responseAbortController.current = null;
};
}, [isConnected, callMessages, modelId, personaVoiceId, personaSystemMessage, reMessages]);
}, [callMessages, isConnected, modelId, personaSystemMessage, reMessages]);
// [E] Message interrupter
const abortTrigger = isConnected && recognitionState.hasSpeech;
@@ -325,7 +313,6 @@ export function Telephone(props: {
<OptimaPanelIn>
<CallMenu
pushToTalk={pushToTalk} setPushToTalk={setPushToTalk}
override={overridePersonaVoice} setOverride={setOverridePersonaVoice}
/>
</OptimaPanelIn>
@@ -373,7 +360,7 @@ export function Telephone(props: {
<ScrollToBottom stickToBottomInitial>
<Box sx={{ minHeight: '100%', p: 1, display: 'flex', flexDirection: 'column', gap: 1 }}>
<Box onCopy={clipboardInterceptCtrlCForCleanup} sx={{ minHeight: '100%', p: 1, display: 'flex', flexDirection: 'column', gap: 1 }}>
{/* Call Messages [] */}
{callMessages.map((message) =>
@@ -1,4 +1,5 @@
import * as React from 'react';
import { AudioPlayer } from '~/common/util/audio/AudioPlayer';
@@ -8,15 +9,16 @@ import { AudioPlayer } from '~/common/util/audio/AudioPlayer';
* @param firstDelay The delay before the first play, in milliseconds.
* @param repeatMs The delay between each repeat, in milliseconds. If 0, the sound will only play once.
*/
export function usePlayUrl(url: string | null, firstDelay: number = 0, repeatMs: number = 0) {
export function usePlayUrlInterval(url: string | null, firstDelay: number = 0, repeatMs: number = 0) {
React.useEffect(() => {
if (!url) return;
const abortController = new AbortController();
let timer2: any = null;
const playFirstTime = () => {
const playAudio = () => AudioPlayer.playUrl(url);
void playAudio();
const playAudio = () => void AudioPlayer.playUrl(url, abortController.signal).catch(() => {/* autoplay may be blocked */});
playAudio();
timer2 = repeatMs > 0 ? setInterval(playAudio, repeatMs) : null;
};
@@ -24,8 +26,8 @@ export function usePlayUrl(url: string | null, firstDelay: number = 0, repeatMs:
return () => {
clearTimeout(timer1);
if (timer2)
clearInterval(timer2);
timer2 && clearInterval(timer2);
abortController?.abort();
};
}, [firstDelay, repeatMs, url]);
}
+19 -25
View File
@@ -4,13 +4,11 @@ import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import type { SxProps } from '@mui/joy/styles/types';
import { Box, useTheme } from '@mui/joy';
import { DEV_MODE_SETTINGS } from '../settings-modal/UxLabsSettings';
import type { DiagramConfig } from '~/modules/aifn/digrams/DiagramsModal';
import type { TradeConfig } from '~/modules/trade/TradeModal';
import { autoConversationTitle } from '~/modules/aifn/autotitle/autoTitle';
import { downloadSingleChat, importConversationsFromFilesAtRest, openConversationsAtRestPicker } from '~/modules/trade/trade.client';
import { imaginePromptFromTextOrThrow } from '~/modules/aifn/imagine/imaginePromptFromText';
import { elevenLabsSpeakText } from '~/modules/elevenlabs/elevenlabs.client';
import { useAreBeamsOpen } from '~/modules/beam/store-beam.hooks';
import { useCapabilityTextToImage } from '~/modules/t2i/t2i.client';
@@ -21,7 +19,7 @@ import { ConversationsManager } from '~/common/chat-overlay/ConversationsManager
import { ErrorBoundary } from '~/common/components/ErrorBoundary';
import { getLLMContextTokens, LLM_IF_ANT_PromptCaching, LLM_IF_OAI_Vision } from '~/common/stores/llms/llms.types';
import { OptimaDrawerIn, OptimaPanelIn, OptimaToolbarIn } from '~/common/layout/optima/portals/OptimaPortalsIn';
import { PanelResizeInset } from '~/common/components/panes/GoodPanelResizeHandler';
import { PanelResizeInset } from '~/common/components/PanelResizeInset';
import { Release } from '~/common/app.release';
import { ScrollToBottom } from '~/common/scroll-to-bottom/ScrollToBottom';
import { ScrollToBottomButton } from '~/common/scroll-to-bottom/ScrollToBottomButton';
@@ -33,7 +31,7 @@ import { createErrorContentFragment, createTextContentFragment, DMessageAttachme
import { gcChatImageAssets } from '~/common/stores/chat/chat.gc';
import { getChatLLMId } from '~/common/stores/llms/store-llms';
import { getConversation, getConversationSystemPurposeId, useConversation } from '~/common/stores/chat/store-chats';
import { optimaActions, optimaOpenModels, optimaOpenPreferences } from '~/common/layout/optima/useOptima';
import { optimaActions, optimaOpenModels, optimaOpenPreferences, useOptimaChromeless } from '~/common/layout/optima/useOptima';
import { useFolderStore } from '~/common/stores/folders/store-chat-folders';
import { useIsMobile, useIsTallScreen } from '~/common/components/useMatchMedia';
import { useLLM } from '~/common/stores/llms/llms.hooks';
@@ -41,8 +39,6 @@ import { useModelDomain } from '~/common/stores/llms/hooks/useModelDomain';
import { useOverlayComponents } from '~/common/layout/overlays/useOverlayComponents';
import { useRouterQuery } from '~/common/app.routes';
import { useUIComplexityIsMinimal } from '~/common/stores/store-ui';
import { useUXLabsStore } from '~/common/stores/store-ux-labs';
import { ChatPane } from './components/layout-pane/ChatPane';
import { ChatBarBeam } from './components/layout-bar/ChatBarBeam';
import { ChatBarAltTitle } from './components/layout-bar/ChatBarAltTitle';
@@ -58,6 +54,7 @@ import { usePanesManager } from './components/panes/store-panes-manager';
import type { ChatExecuteMode } from './execute-mode/execute-mode.types';
import { _handleExecute } from './editors/_handleExecute';
import { getChatAutoAI } from './store-app-chat';
// what to say when a chat is new and has no title
@@ -152,8 +149,6 @@ export function AppChat() {
const intent = useRouterQuery<Partial<AppChatIntent>>();
const showAltTitleBar = useUXLabsStore(state => DEV_MODE_SETTINGS && state.labsChatBarAlt === 'title');
const { domainModelId: chatLLMId } = useModelDomain('primaryChat');
const chatLLM = useLLM(chatLLMId) ?? null;
@@ -186,6 +181,7 @@ export function AppChat() {
const beamOpenStoreInFocusedPane = focusedPaneIndex === null ? null
: !beamsOpens?.[focusedPaneIndex] ? null
: paneBeamStores?.[focusedPaneIndex] ?? null;
const focusedChatBeamOpen = focusedPaneIndex !== null && !!beamsOpens?.[focusedPaneIndex];
const {
// focused
@@ -215,7 +211,8 @@ export function AppChat() {
});
// Composer Auto-hiding
const forceComposerHide = !!beamOpenStoreInFocusedPane /* || !focusedPaneConversationId */; // auto-hide when no chat (the 'please select a conversation...' state) doesn't feel good
const isChromeless = useOptimaChromeless() && isMobile; // auto-hide on Chromeless too
const forceComposerHide = isChromeless || !!beamOpenStoreInFocusedPane /* || !focusedPaneConversationId */; // auto-hide when no chat (the 'please select a conversation...' state) doesn't feel good
const composerAutoHide = useComposerAutoHide(forceComposerHide, composerHasContent);
// Window actions
@@ -320,10 +317,11 @@ export function AppChat() {
// replace the prompt in history
const lastMessage = inputHistory[inputHistory.length - 1];
const _autoTitle = () => getChatAutoAI().autoTitleChat && void autoConversationTitle(focusedPaneConversationId, false);
if (lastMessage.role === 'assistant')
cHandler.beamInvoke(inputHistory.slice(0, -1), [lastMessage], lastMessage.id);
cHandler.beamInvoke(inputHistory.slice(0, -1), [lastMessage], lastMessage.id, _autoTitle);
else if (lastMessage.role === 'user')
cHandler.beamInvoke(inputHistory, [], null);
cHandler.beamInvoke(inputHistory, [], null, _autoTitle);
}, [focusedPaneConversationId]);
const handleTextDiagram = React.useCallback((diagramConfig: DiagramConfig | null) => setDiagramConfig(diagramConfig), []);
@@ -345,11 +343,6 @@ export function AppChat() {
});
}, [handleExecuteAndOutcome]);
const handleTextSpeak = React.useCallback(async (text: string): Promise<void> => {
await elevenLabsSpeakText(text, undefined, true, true);
}, []);
// Chat actions
const handleConversationNewInFocusedPane = React.useCallback((forceNoRecycle: boolean, isIncognito: boolean) => {
@@ -468,7 +461,7 @@ export function AppChat() {
// Pluggable Optima components
const barAltTitle = showAltTitleBar ? focusedChatTitle ?? 'No Chat' : null;
const barAltTitle = null;
const focusedBarContent = React.useMemo(() => beamOpenStoreInFocusedPane
? <ChatBarBeam conversationTitle={focusedChatTitle ?? 'No Chat'} beamStore={beamOpenStoreInFocusedPane} isMobile={isMobile} />
@@ -479,7 +472,7 @@ export function AppChat() {
);
// Disabled by default, as it lags the opening of the drawer and immediatly vanishes during the closing animation
// Disabled by default, as it lags the opening of the drawer and immediately vanishes during the closing animation
const isDrawerOpen = true; // useOptimaDrawerOpen();
const drawerContent = React.useMemo(() => !isDrawerOpen ? null :
@@ -489,6 +482,7 @@ export function AppChat() {
activeFolderId={activeFolderId}
chatPanesConversationIds={paneUniqueConversationIds}
disableNewButton={disableNewButton}
focusedChatBeamOpen={focusedChatBeamOpen}
onConversationActivate={handleOpenConversationInFocusedPane}
onConversationBranch={handleConversationBranch}
onConversationNew={handleConversationNewInFocusedPane}
@@ -497,11 +491,12 @@ export function AppChat() {
onConversationsImportDialog={handleConversationImportDialog}
setActiveFolderId={setActiveFolderId}
/>,
[activeFolderId, disableNewButton, focusedPaneConversationId, handleConversationBranch, handleConversationExport, handleConversationImportDialog, handleConversationNewInFocusedPane, handleDeleteConversations, handleOpenConversationInFocusedPane, isDrawerOpen, paneUniqueConversationIds],
[activeFolderId, disableNewButton, focusedChatBeamOpen, focusedPaneConversationId, handleConversationBranch, handleConversationExport, handleConversationImportDialog, handleConversationNewInFocusedPane, handleDeleteConversations, handleOpenConversationInFocusedPane, isDrawerOpen, paneUniqueConversationIds],
);
const focusedChatPanelContent = React.useMemo(() => !focusedPaneConversationId ? null :
<ChatPane
isMobile={isMobile}
conversationId={focusedPaneConversationId}
disableItems={!focusedPaneConversationId || isFocusedChatEmpty}
hasConversations={hasConversations}
@@ -523,7 +518,7 @@ export function AppChat() {
React.useEffect(() => {
// Debug: open a null chat
if (Release.IsNodeDevBuild && intent.initialConversationId === 'null')
openConversationInFocusedPane(null! /* for debugging purporse */);
openConversationInFocusedPane(null! /* for debugging purpose */);
// Open the initial conversation if set
else if (intent.initialConversationId)
openConversationInFocusedPane(intent.initialConversationId);
@@ -651,7 +646,7 @@ export function AppChat() {
setFocusedPaneIndex(idx);
}}
onCollapse={() => {
// NOTE: despite the delay to try to let the draggin settle, there seems to be an issue with the Pane locking the screen
// NOTE: despite the delay to try to let the dragging settle, there seems to be an issue with the Pane locking the screen
// setTimeout(() => removePane(idx), 50);
// more than 2 will result in an assertion from the framework
if (chatPanes.length === 2) removePane(idx);
@@ -678,7 +673,7 @@ export function AppChat() {
// NOTE: this is a workaround for the 'stuck-after-collapse-close' issue. We will collapse the 'other' pane, which
// will get it removed (onCollapse), and somehow this pane will be stuck with a pointerEvents: 'none' style, which de-facto
// disables further interaction with the chat. This is a workaround to re-enable the pointer events.
// The root cause seems to be a Dragstate not being reset properly, however the pointerEvents has been set since 0.0.56 while
// The root cause seems to be a Drag state not being reset properly, however the pointerEvents has been set since 0.0.56 while
// it was optional before: https://github.com/bvaughn/react-resizable-panels/issues/241
pointerEvents: 'auto',
}),
@@ -723,7 +718,6 @@ export function AppChat() {
onConversationNew={handleConversationNewInFocusedPane}
onTextDiagram={handleTextDiagram}
onTextImagine={handleImagineFromText}
onTextSpeak={handleTextSpeak}
sx={chatMessageListSx}
/>
)}
@@ -779,7 +773,7 @@ export function AppChat() {
</Box>
{/* Hover zone for auto-hide */}
{!forceComposerHide && composerAutoHide.isHidden && <Box {...composerAutoHide.detectorProps} />}
{!isChromeless && !forceComposerHide && composerAutoHide.isHidden && <Box {...composerAutoHide.detectorProps} />}
{/* Diagrams */}
{!!diagramConfig && (
+78 -19
View File
@@ -7,18 +7,19 @@ import { Box, List } from '@mui/joy';
import type { SystemPurposeExample } from '../../../data';
import type { DiagramConfig } from '~/modules/aifn/digrams/DiagramsModal';
import { autoConversationTitle } from '~/modules/aifn/autotitle/autoTitle';
import { speakText } from '~/modules/speex/speex.client';
import type { ConversationHandler } from '~/common/chat-overlay/ConversationHandler';
import type { DLLMContextTokens } from '~/common/stores/llms/llms.types';
import { DConversationId, excludeSystemMessages } from '~/common/stores/chat/chat.conversation';
import { ShortcutKey, useGlobalShortcuts } from '~/common/components/shortcuts/useGlobalShortcuts';
import { clipboardInterceptCtrlCForCleanup } from '~/common/util/clipboardUtils';
import { convertFilesToDAttachmentFragments } from '~/common/attachment-drafts/attachment.pipeline';
import { createDMessageFromFragments, createDMessageTextContent, DMessage, DMessageId, DMessageUserFlag, DMetaReferenceItem, MESSAGE_FLAG_AIX_SKIP, messageHasUserFlag } from '~/common/stores/chat/chat.message';
import { createDMessageFromFragments, createDMessageTextContent, DMessage, DMessageGenerator, DMessageId, DMessageUserFlag, DMetaReferenceItem, MESSAGE_FLAG_AIX_SKIP, messageHasUserFlag } from '~/common/stores/chat/chat.message';
import { createTextContentFragment, DMessageFragment, DMessageFragmentId } from '~/common/stores/chat/chat.fragments';
import { openFileForAttaching } from '~/common/components/ButtonAttachFiles';
import { optimaOpenPreferences } from '~/common/layout/optima/useOptima';
import { useBrowserTranslationWarning } from '~/common/components/useIsBrowserTranslating';
import { useCapabilityElevenLabs } from '~/common/components/useCapabilities';
import { useChatOverlayStore } from '~/common/chat-overlay/store-perchat_vanilla';
import { useChatStore } from '~/common/stores/chat/store-chats';
import { useScrollToBottom } from '~/common/scroll-to-bottom/useScrollToBottom';
@@ -28,7 +29,7 @@ import { ChatMessage, ChatMessageMemo } from './message/ChatMessage';
import { CleanerMessage, MessagesSelectionHeader } from './message/CleanerMessage';
import { Ephemerals } from './Ephemerals';
import { PersonaSelector } from './persona-selector/PersonaSelector';
import { useChatAutoSuggestHTMLUI, useChatShowSystemMessages } from '../store-app-chat';
import { getChatAutoAI, useChatAutoSuggestHTMLUI, useChatShowSystemMessages } from '../store-app-chat';
const stableNoMessages: DMessage[] = [];
@@ -51,7 +52,6 @@ export function ChatMessageList(props: {
onConversationNew: (forceNoRecycle: boolean, isIncognito: boolean) => void,
onTextDiagram: (diagramConfig: DiagramConfig | null) => void,
onTextImagine: (conversationId: DConversationId, selectedText: string) => Promise<void>,
onTextSpeak: (selectedText: string) => Promise<void>,
setIsMessageSelectionMode: (isMessageSelectionMode: boolean) => void,
sx?: SxProps,
}) {
@@ -65,7 +65,6 @@ export function ChatMessageList(props: {
const { notifyBooting } = useScrollToBottom();
const danger_experimentalHtmlWebUi = useChatAutoSuggestHTMLUI();
const [showSystemMessages] = useChatShowSystemMessages();
const optionalTranslationWarning = useBrowserTranslationWarning();
const { conversationMessages, historyTokenCount } = useChatStore(useShallow(({ conversations }) => {
const conversation = conversations.find(conversation => conversation.id === props.conversationId);
return {
@@ -77,10 +76,9 @@ export function ChatMessageList(props: {
_composerInReferenceToCount: state.inReferenceTo?.length ?? 0,
ephemerals: state.ephemerals?.length ? state.ephemerals : null,
})));
const { mayWork: isSpeakable } = useCapabilityElevenLabs();
// derived state
const { conversationHandler, conversationId, capabilityHasT2I, onConversationBranch, onConversationExecuteHistory, onTextDiagram, onTextImagine, onTextSpeak } = props;
const { conversationHandler, conversationId, capabilityHasT2I, onConversationBranch, onConversationExecuteHistory, onTextDiagram, onTextImagine } = props;
const composerCanAddInReferenceTo = _composerInReferenceToCount < 5;
const composerHasInReferenceto = _composerInReferenceToCount > 0;
@@ -126,6 +124,61 @@ export function ChatMessageList(props: {
}
}, [conversationHandler, conversationId, onConversationExecuteHistory]);
const handleMessageUpstreamResume = React.useCallback(async (generator: DMessageGenerator, messageId: DMessageId) => {
if (!conversationId || !conversationHandler) return;
if (!generator.upstreamHandle) throw new Error('No upstream handle on generator');
// For AIX generators the DLLMId is at .aix.mId
const llmId = generator.mgt === 'aix' ? generator.aix.mId : undefined;
if (!llmId) throw new Error('No model id on generator');
const { aixCreateChatGenerateContext, aixReattachContent_DMessage_orThrow } = await import('~/modules/aix/client/aix.client');
const result = await aixReattachContent_DMessage_orThrow(
llmId,
generator,
aixCreateChatGenerateContext('conversation', conversationId),
{ abortSignal: 'NON_ABORTABLE', throttleParallelThreads: 0 },
async (update, isDone) => {
conversationHandler.messageEdit(messageId, {
fragments: update.fragments,
generator: update.generator,
pendingIncomplete: update.pendingIncomplete,
}, isDone, isDone); // remove the pending state and updte only when done
},
);
// Manual reattach is one-shot: on failure (e.g. upstream 404 from expired or already-consumed handle),
// drop the upstreamHandle so the Resume button doesn't keep luring the user into the same error.
// On 'aborted' we keep it so the user can try again later; on 'completed' the reassembler already cleared it.
// 2026-04-22: disabled; it was removing the connect button on a connection error (e.g. wifi drop)
// if (result.outcome === 'failed' && result.generator?.upstreamHandle)
// conversationHandler.messageEdit(messageId, {
// generator: { ...result.generator, upstreamHandle: undefined },
// }, false /* messageComplete */, true /* touch */);
}, [conversationHandler, conversationId]);
const handleMessageUpstreamDelete = React.useCallback(async (generator: DMessageGenerator, messageId: DMessageId) => {
if (!conversationId || !conversationHandler) return;
if (!generator.upstreamHandle) throw new Error('No upstream handle on generator');
// For AIX generators the DLLMId is at .aix.mId
const llmId = generator.mgt === 'aix' ? generator.aix.mId : undefined;
if (!llmId) throw new Error('No model id on generator');
const { aixDeleteUpstreamContent_orThrow } = await import('~/modules/aix/client/aix.client');
const result = await aixDeleteUpstreamContent_orThrow(llmId, generator);
// On success (or 404 already-gone), clear the handle locally so the buttons disappear
if (result.ok) {
conversationHandler.messageEdit(messageId, {
generator: { ...generator, upstreamHandle: undefined },
}, false /* messageComplete */, true /* touch */);
return;
}
// On failure: surface to the button's error UI
throw new Error(result.message || `Delete failed${result.httpStatus ? ` (HTTP ${result.httpStatus})` : ''}`);
}, [conversationHandler, conversationId]);
// message menu methods proxy
@@ -149,17 +202,20 @@ export function ChatMessageList(props: {
const lastTruncatedMessage = truncatedHistory[truncatedHistory.length - 1];
if (!lastTruncatedMessage) return;
// auto-title callback (injected to avoid common/ -> apps/ dependency)
const _autoTitle = conversationId ? () => getChatAutoAI().autoTitleChat && void autoConversationTitle(conversationId, false) : undefined;
// assistant: do an in-place beam
if (lastTruncatedMessage.role === 'assistant') {
if (truncatedHistory.length >= 2)
conversationHandler.beamInvoke(truncatedHistory.slice(0, -1), [lastTruncatedMessage], lastTruncatedMessage.id);
conversationHandler.beamInvoke(truncatedHistory.slice(0, -1), [lastTruncatedMessage], lastTruncatedMessage.id, _autoTitle);
} else if (lastTruncatedMessage.role === 'user') {
// user: truncate and append (but if the next message is an assistant message, import it)
const possibleNextMessage = inputHistory[truncatedHistory.length];
if (possibleNextMessage?.role === 'assistant')
conversationHandler.beamInvoke(truncatedHistory, [possibleNextMessage], null);
conversationHandler.beamInvoke(truncatedHistory, [possibleNextMessage], null, _autoTitle);
else
conversationHandler.beamInvoke(truncatedHistory, [], null);
conversationHandler.beamInvoke(truncatedHistory, [], null, _autoTitle);
}
}, [conversationHandler, conversationId]);
@@ -214,12 +270,15 @@ export function ChatMessageList(props: {
}, [capabilityHasT2I, conversationId, onTextImagine]);
const handleTextSpeak = React.useCallback(async (text: string) => {
if (!isSpeakable)
return optimaOpenPreferences('voice');
// sandwich the speaking with the indicator
setIsSpeaking(true);
await onTextSpeak(text);
const result = await speakText(text, undefined, { label: 'Chat speak' });
setIsSpeaking(false);
}, [isSpeakable, onTextSpeak]);
// open voice preferences
if (!result.success && (result.errorType === 'tts-no-engine' || result.errorType === 'tts-unconfigured'))
optimaOpenPreferences('voice');
}, []);
// operate on the local selection set
@@ -324,9 +383,7 @@ export function ChatMessageList(props: {
);
return (
<List role='chat-messages-list' sx={listSx}>
{optionalTranslationWarning}
<List role='chat-messages-list' sx={listSx} onCopy={clipboardInterceptCtrlCForCleanup}>
{props.isMessageSelectionMode && (
<MessagesSelectionHeader
@@ -373,6 +430,8 @@ export function ChatMessageList(props: {
onMessageBeam={handleMessageBeam}
onMessageBranch={handleMessageBranch}
onMessageContinue={handleMessageContinue}
onMessageUpstreamResume={handleMessageUpstreamResume}
onMessageUpstreamDelete={handleMessageUpstreamDelete}
onMessageDelete={handleMessageDelete}
onMessageFragmentAppend={handleMessageAppendFragment}
onMessageFragmentDelete={handleMessageDeleteFragment}
@@ -381,7 +440,7 @@ export function ChatMessageList(props: {
onMessageTruncate={handleMessageTruncate}
onTextDiagram={handleTextDiagram}
onTextImagine={capabilityHasT2I ? handleTextImagine : undefined}
onTextSpeak={isSpeakable ? handleTextSpeak : undefined}
onTextSpeak={handleTextSpeak}
/>
);
+88 -131
View File
@@ -1,10 +1,8 @@
import * as React from 'react';
import { useShallow } from 'zustand/react/shallow';
import type { FileWithHandle } from 'browser-fs-access';
import { Box, Button, ButtonGroup, Card, Dropdown, Grid, IconButton, Menu, MenuButton, MenuItem, Textarea, Typography } from '@mui/joy';
import { ColorPaletteProp, SxProps, VariantProp } from '@mui/joy/styles/types';
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
import type { ColorPaletteProp, SxProps, VariantProp } from '@mui/joy/styles/types';
import { Box, Button, ButtonGroup, Card, Grid, IconButton, Textarea, Typography } from '@mui/joy';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import PsychologyIcon from '@mui/icons-material/Psychology';
import SendIcon from '@mui/icons-material/Send';
@@ -18,6 +16,7 @@ import { useAgiAttachmentPrompts } from '~/modules/aifn/agiattachmentprompts/use
import { useBrowseCapability } from '~/modules/browse/store-module-browsing';
import { DLLM, getLLMContextTokens, LLM_IF_OAI_Vision } from '~/common/stores/llms/llms.types';
import { llmChatPricing_adjusted } from '~/common/stores/llms/llms.pricing';
import { AudioGenerator } from '~/common/util/audio/AudioGenerator';
import { AudioPlayer } from '~/common/util/audio/AudioPlayer';
import { ButtonAttachFilesMemo, openFileForAttaching } from '~/common/components/ButtonAttachFiles';
@@ -25,6 +24,7 @@ import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
import { ConfirmationModal } from '~/common/components/modals/ConfirmationModal';
import { ConversationsManager } from '~/common/chat-overlay/ConversationsManager';
import { DMessageId, DMessageMetadata, DMetaReferenceItem, messageFragmentsReduceText } from '~/common/stores/chat/chat.message';
import { PhPaintBrush } from '~/common/components/icons/phosphor/PhPaintBrush';
import { ShortcutKey, ShortcutObject, useGlobalShortcuts } from '~/common/components/shortcuts/useGlobalShortcuts';
import { addSnackbar } from '~/common/components/snackbar/useSnackbarsStore';
import { animationEnterBelow } from '~/common/util/animUtils';
@@ -34,12 +34,13 @@ import { copyToClipboard, supportsClipboardRead } from '~/common/util/clipboardU
import { createTextContentFragment, DMessageAttachmentFragment, DMessageContentFragment, duplicateDMessageFragments } from '~/common/stores/chat/chat.fragments';
import { glueForMessageTokens, marshallWrapDocFragments } from '~/common/stores/chat/chat.tokens';
import { isValidConversation, useChatStore } from '~/common/stores/chat/store-chats';
import { getModelParameterValueOrThrow } from '~/common/stores/llms/llms.parameters';
import { getModelParameterValueWithFallback } from '~/common/stores/llms/llms.parameters';
import { launchAppCall, removeQueryParam, useRouterQuery } from '~/common/app.routes';
import { lineHeightTextareaMd, themeBgAppChatComposer } from '~/common/app.theme';
import { optimaOpenPreferences } from '~/common/layout/optima/useOptima';
import { platformAwareKeystrokes } from '~/common/components/KeyStroke';
import { supportsCameraCapture } from '~/common/components/camera/useCameraCapture';
import { supportsScreenCapture } from '~/common/util/screenCaptureUtils';
import { useAttachHandler_CameraOpen, useAttachHandler_Files, useAttachHandler_PasteIntercept, useAttachHandler_ScreenCapture, useAttachHandler_UrlWebLinks } from '~/common/attachment-drafts/attachment-sources/useAttachmentSourceHandlers';
import { useChatComposerOverlayStore } from '~/common/chat-overlay/store-perchat_vanilla';
import { useComposerStartupText, useLogicSherpaStore } from '~/common/logic/store-logic-sherpa';
import { useOverlayComponents } from '~/common/layout/overlays/useOverlayComponents';
@@ -52,19 +53,15 @@ import { providerCommands } from './actile/providerCommands';
import { providerStarredMessages, StarredMessageItem } from './actile/providerStarredMessage';
import { useActileManager } from './actile/useActileManager';
import type { AttachmentDraftId } from '~/common/attachment-drafts/attachment.types';
import { LLMAttachmentDraftsAction, LLMAttachmentsList } from './llmattachments/LLMAttachmentsList';
import { PhPaintBrush } from '~/common/components/icons/phosphor/PhPaintBrush';
import type { AttachmentDraftId, AttachmentDraftsAction } from '~/common/attachment-drafts/attachment.types';
import { AttachmentSourcesMemo } from '~/common/attachment-drafts/attachment-sources/AttachmentSources';
import { useAttachmentDrafts } from '~/common/attachment-drafts/useAttachmentDrafts';
import { useLLMAttachmentDrafts } from './llmattachments/useLLMAttachmentDrafts';
import { useAttachmentDraftsEnrichment } from '~/common/attachment-drafts/llm-enrichment/useAttachmentDraftsEnrichment';
import { useGoogleDrivePicker } from '~/common/attachment-drafts/attachment-sources/useGoogleDrivePicker';
import type { ChatExecuteMode } from '../../execute-mode/execute-mode.types';
import { chatExecuteModeCanAttach, useChatExecuteMode } from '../../execute-mode/useChatExecuteMode';
import { ButtonAttachCameraMemo, useCameraCaptureModalDialog } from './buttons/ButtonAttachCamera';
import { ButtonAttachClipboardMemo } from './buttons/ButtonAttachClipboard';
import { ButtonAttachScreenCaptureMemo } from './buttons/ButtonAttachScreenCapture';
import { ButtonAttachWebMemo } from './buttons/ButtonAttachWeb';
import { ButtonBeamMemo } from './buttons/ButtonBeam';
import { ButtonCallMemo } from './buttons/ButtonCall';
import { ButtonGroupDrawRepeat } from './buttons/ButtonGroupDrawRepeat';
@@ -72,6 +69,7 @@ import { ButtonMicContinuationMemo } from './buttons/ButtonMicContinuation';
import { ButtonMicMemo } from './buttons/ButtonMic';
import { ButtonMultiChatMemo } from './buttons/ButtonMultiChat';
import { ButtonOptionsDraw } from './buttons/ButtonOptionsDraw';
import { ComposerAttachmentDraftsList } from './llmattachments/ComposerAttachmentDraftsList';
import { ComposerTextAreaActions } from './textarea/ComposerTextAreaActions';
import { ComposerTextAreaDrawActions } from './textarea/ComposerTextAreaDrawActions';
import { StatusBarMemo } from '../StatusBar';
@@ -79,7 +77,6 @@ import { TokenBadgeMemo } from './tokens/TokenBadge';
import { TokenProgressbarMemo } from './tokens/TokenProgressbar';
import { useComposerDragDrop } from './useComposerDragDrop';
import { useTextTokenCount } from './tokens/useTextTokenCounter';
import { useWebInputModal } from './WebInputModal';
// configuration
@@ -136,16 +133,13 @@ export function Composer(props: {
// external state
const { showPromisedOverlay } = useOverlayComponents();
const { newChat: appChatNewChatIntent } = useRouterQuery<Partial<AppChatIntent>>();
const { labsAttachScreenCapture, labsCameraDesktop, labsShowCost, labsShowShortcutBar } = useUXLabsStore(useShallow(state => ({
labsAttachScreenCapture: state.labsAttachScreenCapture,
labsCameraDesktop: state.labsCameraDesktop,
labsShowCost: state.labsShowCost,
const { labsComposerAttachmentsInline, labsShowShortcutBar } = useUXLabsStore(useShallow(state => ({
labsComposerAttachmentsInline: state.labsComposerAttachmentsInline,
labsShowShortcutBar: state.labsShowShortcutBar,
})));
const timeToShowTips = useLogicSherpaStore(state => state.usageCount >= SHOW_TIPS_AFTER_RELOADS);
const { novel: explainShiftEnter, touch: touchShiftEnter } = useUICounter('composer-shift-enter');
const { novel: explainAltEnter, touch: touchAltEnter } = useUICounter('composer-alt-enter');
const { novel: explainCtrlEnter, touch: touchCtrlEnter } = useUICounter('composer-ctrl-enter');
const [startupText, setStartupText] = useComposerStartupText();
const enterIsNewline = useUIPreferencesStore(state => state.enterIsNewline);
const composerQuickButton = useUIPreferencesStore(state => state.composerQuickButton);
@@ -174,8 +168,8 @@ export function Composer(props: {
const chatLLMSupportsImages = !!props.chatLLM?.interfaces?.includes(LLM_IF_OAI_Vision);
// don't load URLs if the user is typing a command or there's no capability
const hasComposerBrowseCapability = useBrowseCapability().inComposer;
const enableLoadURLsInComposer = hasComposerBrowseCapability && !composeText.startsWith('/');
const browseCapability = useBrowseCapability();
const enableLoadURLsInComposer = browseCapability.inComposer && !composeText.startsWith('/');
// user message for attachments
const { onConversationBeamEdit, onConversationsImportFromFiles } = props;
@@ -197,12 +191,12 @@ export function Composer(props: {
const showChatAttachments = chatExecuteModeCanAttach(chatExecuteMode, props.capabilityHasT2IEdit);
const {
/* items */ attachmentDrafts,
/* append */ attachAppendClipboardItems, attachAppendDataTransfer, attachAppendEgoFragments, attachAppendFile, attachAppendUrl,
/* append */ attachAppendClipboardItems, attachAppendCloudFile, attachAppendDataTransfer, attachAppendEgoFragments, attachAppendFile, attachAppendUrl,
/* take */ attachmentsRemoveAll, attachmentsTakeAllFragments, attachmentsTakeFragmentsByType,
} = useAttachmentDrafts(conversationOverlayStore, enableLoadURLsInComposer, chatLLMSupportsImages, handleFilterAGIFile, showChatAttachments === 'only-images');
// attachments derived state
const llmAttachmentDraftsCollection = useLLMAttachmentDrafts(attachmentDrafts, props.chatLLM, chatLLMSupportsImages);
const { enrichment: attEnrichment, summary: attEnrichSummary } = useAttachmentDraftsEnrichment(attachmentDrafts, props.chatLLM, chatLLMSupportsImages);
// drag/drop
const { dragContainerSx, dropComponent, handleContainerDragEnter, handleContainerDragStart } = useComposerDragDrop(!props.isMobile, attachAppendDataTransfer);
@@ -227,13 +221,13 @@ export function Composer(props: {
// tokens derived state
const tokensComposerTextDebounced = useTextTokenCount(composeText, props.chatLLM, 800, 1600);
let tokensComposer = (tokensComposerTextDebounced ?? 0) + (llmAttachmentDraftsCollection.llmTokenCountApprox || 0);
let tokensComposer = (tokensComposerTextDebounced ?? 0) + (attEnrichSummary.totalTokensApprox || 0);
if (props.chatLLM && tokensComposer > 0)
tokensComposer += glueForMessageTokens(props.chatLLM);
const tokensHistory = _historyTokenCount;
const tokensResponseMax = getModelParameterValueOrThrow('llmResponseTokens', props.chatLLM?.initialParameters, props.chatLLM?.userParameters, 0) ?? 0;
const tokensResponseMax = getModelParameterValueWithFallback('llmResponseTokens', props.chatLLM?.initialParameters, props.chatLLM?.userParameters, 0) ?? 0 /* if null, assume 0*/;
const tokenLimit = getLLMContextTokens(props.chatLLM) ?? 0;
const tokenChatPricing = props.chatLLM?.pricing?.chat;
const tokenChatPricing = React.useMemo(() => llmChatPricing_adjusted(props.chatLLM), [props.chatLLM]);
// Effect: load initial text if queued up (e.g. by /link/share_targetF)
@@ -271,7 +265,7 @@ export function Composer(props: {
// Confirmation Modals
const confirmProceedIfAttachmentsNotSupported = React.useCallback(async (): Promise<boolean> => {
if (llmAttachmentDraftsCollection.canAttachAllFragments) return true;
if (attEnrichSummary.allCompatible) return true;
return await showPromisedOverlay('composer-unsupported-attachments', { rejectWithValue: false }, ({ onResolve, onUserReject }) => (
<ConfirmationModal
open
@@ -283,7 +277,7 @@ export function Composer(props: {
title='Attachment Compatibility Notice'
/>
));
}, [llmAttachmentDraftsCollection.canAttachAllFragments, showPromisedOverlay]);
}, [attEnrichSummary.allCompatible, showPromisedOverlay]);
// Primary button
@@ -545,20 +539,21 @@ export function Composer(props: {
// Enter: primary action
if (e.key === 'Enter') {
// Skip if composing (e.g., CJK input methods) - issue #784
if (e.nativeEvent.isComposing)
return;
// Alt (Windows) or Option (Mac) + Enter: append the message instead of sending it
if (e.altKey && !e.metaKey && !e.ctrlKey) {
if (await handleSendAction('append-user', composeText)) // 'alt+enter' -> write
touchAltEnter();
e.stopPropagation();
return e.preventDefault();
}
// Ctrl (Windows) or Command (Mac) + Enter: send for beaming
if (e.ctrlKey && !e.metaKey && !e.altKey) {
if (await handleSendAction('beam-content', composeText)) { // 'ctrl+enter' -> beam
touchCtrlEnter();
if (await handleSendAction('beam-content', composeText)) // 'ctrl+enter' -> beam
e.stopPropagation();
}
return e.preventDefault();
}
@@ -572,7 +567,7 @@ export function Composer(props: {
}
}
}, [actileInterceptKeydown, assistantAbortible, chatExecuteMode, composeText, enterIsNewline, handleSendAction, touchAltEnter, touchCtrlEnter, touchShiftEnter]);
}, [actileInterceptKeydown, assistantAbortible, chatExecuteMode, composeText, enterIsNewline, handleSendAction, touchShiftEnter]);
// Focus mode
@@ -589,41 +584,19 @@ export function Composer(props: {
const handleToggleMinimized = React.useCallback(() => setIsMinimized(hide => !hide), []);
// Attachment Up
// Attachments Up
const handleAttachCtrlV = React.useCallback(async (event: React.ClipboardEvent) => {
if (await attachAppendDataTransfer(event.clipboardData, 'paste', false) === 'as_files')
event.preventDefault();
}, [attachAppendDataTransfer]);
const handleAttachCameraImage = React.useCallback((file: FileWithHandle) => {
void attachAppendFile('camera', file);
}, [attachAppendFile]);
const { openCamera, cameraCaptureComponent } = useCameraCaptureModalDialog(handleAttachCameraImage);
const handleAttachScreenCapture = React.useCallback((file: File) => {
void attachAppendFile('screencapture', file);
}, [attachAppendFile]);
const handleAttachFiles = React.useCallback(async (files: FileWithHandle[], errorMessage: string | null) => {
if (errorMessage)
addSnackbar({ key: 'attach-files-open-fail', message: `Unable to open files: ${errorMessage}`, type: 'issue' });
for (let file of files)
await attachAppendFile('file-open', file)
.catch((error: any) => addSnackbar({ key: 'attach-file-open-fail', message: `Unable to attach the file "${file.name}" (${error?.message || error?.toString() || 'unknown error'})`, type: 'issue' }));
}, [attachAppendFile]);
const handleAttachWebLinks = React.useCallback(async (links: { url: string }[]) => {
links.forEach(link => void attachAppendUrl('input-link', link.url));
}, [attachAppendUrl]);
const { openWebInputDialog, webInputDialogComponent } = useWebInputModal(handleAttachWebLinks, composeText);
const handleAttachCtrlV = useAttachHandler_PasteIntercept(attachAppendDataTransfer);
const handleAttachFiles = useAttachHandler_Files(attachAppendFile);
const handleOpenCamera = useAttachHandler_CameraOpen(attachAppendFile);
const handleAttachScreenCapture = useAttachHandler_ScreenCapture(attachAppendFile);
const { openWebInputDialog, webInputDialogComponent } = useAttachHandler_UrlWebLinks(attachAppendUrl, composeText);
const { openGoogleDrivePicker, googleDrivePickerComponent } = useGoogleDrivePicker(attachAppendCloudFile, isMobile);
// Attachments Down
const handleAttachmentDraftsAction = React.useCallback((attachmentDraftIdOrAll: AttachmentDraftId | null, action: LLMAttachmentDraftsAction) => {
const handleAttachmentDraftsAction = React.useCallback((attachmentDraftIdOrAll: AttachmentDraftId | null, action: AttachmentDraftsAction) => {
switch (action) {
case 'copy-text':
const copyFragments = attachmentsTakeFragmentsByType('doc', attachmentDraftIdOrAll, false);
@@ -652,7 +625,7 @@ export function Composer(props: {
if (supportsClipboardRead())
composerShortcuts.push({ key: 'v', ctrl: true, shift: true, action: attachAppendClipboardItems, description: 'Attach Clipboard' });
// Future: keep reactive state here to support Live Screen Capture and more
// if (labsAttachScreenCapture && supportsScreenCapture)
// if (supportsScreenCapture)
// composerShortcuts.push({ key: 's', ctrl: true, shift: true, action: openScreenCaptureDialog, description: 'Attach Screen Capture' });
}
if (recognitionState.isActive) {
@@ -685,12 +658,13 @@ export function Composer(props: {
const showChatInReferenceTo = !!inReferenceTo?.length;
const showChatExtras = isText && !showChatInReferenceTo && !assistantAbortible && composerQuickButton !== 'off';
const speechMayWork = browserSpeechRecognitionCapability().mayWork;
const sendButtonVariant: VariantProp = (isAppend || (isMobile && isTextBeam)) ? 'outlined' : 'solid';
const sendButtonColor: ColorPaletteProp =
assistantAbortible ? 'warning'
: !llmAttachmentDraftsCollection.canAttachAllFragments ? 'warning'
: !attEnrichSummary.allCompatible ? 'warning'
: chatExecuteModeSendColor;
const sendButtonLabel = chatExecuteModeSendLabel;
@@ -704,7 +678,7 @@ export function Composer(props: {
: <TelegramIcon />;
const beamButtonColor: ColorPaletteProp | undefined =
!llmAttachmentDraftsCollection.canAttachAllFragments ? 'warning'
!attEnrichSummary.allCompatible ? 'warning'
: undefined;
const showTint: ColorPaletteProp | undefined = isDraw ? 'warning' : isReAct ? 'success' : undefined;
@@ -731,10 +705,6 @@ export function Composer(props: {
if (isDesktop && timeToShowTips && !isDraw) {
if (explainShiftEnter)
textPlaceholder += !enterIsNewline ? '\n\n⏎ Shift + Enter to add a new line' : '\n\n➤ Shift + Enter to send';
// else if (explainAltEnter)
// textPlaceholder += platformAwareKeystrokes('\n\n⭳ Tip: Alt + Enter to just append the message');
else if (explainCtrlEnter)
textPlaceholder += platformAwareKeystrokes('\n\n⫷ Tip: Ctrl + Enter to beam');
}
const stableGridSx: SxProps = React.useMemo(() => ({
@@ -775,37 +745,24 @@ export function Composer(props: {
{/* [mobile] Mic button */}
{recognitionState.isAvailable && <ButtonMicMemo variant={micVariant} color={micColor === 'danger' ? 'danger' : showTint || micColor} errorMessage={recognitionState.errorMessage} onClick={handleToggleMic} />}
{/* Responsive Camera OCR button */}
{showChatAttachments && <ButtonAttachCameraMemo color={showTint} isMobile onOpenCamera={openCamera} />}
{/* [mobile] Attach file button (in draw with image mode) */}
{showChatAttachments === 'only-images' && <ButtonAttachFilesMemo color={showTint} isMobile onAttachFiles={handleAttachFiles} fullWidth multiple />}
{showChatAttachments === 'only-images' && <ButtonAttachFilesMemo color={showTint} isMobile onAttachFiles={handleAttachFiles} multiple />}
{/* [mobile] [+] button */}
{/* [mobile] [+] attachment sources menu */}
{showChatAttachments === true && (
<Dropdown>
<MenuButton slots={{ root: IconButton }}>
<AddCircleOutlineIcon />
</MenuButton>
<Menu>
{/* Responsive Open Files button */}
<MenuItem>
<ButtonAttachFilesMemo onAttachFiles={handleAttachFiles} fullWidth multiple />
</MenuItem>
{/* Responsive Web button */}
<MenuItem>
<ButtonAttachWebMemo disabled={!hasComposerBrowseCapability} onOpenWebInput={openWebInputDialog} />
</MenuItem>
{/* Responsive Paste button */}
{supportsClipboardRead() && <MenuItem>
<ButtonAttachClipboardMemo onAttachClipboard={attachAppendClipboardItems} />
</MenuItem>}
</Menu>
</Dropdown>
<AttachmentSourcesMemo
mode='menu-compact'
canBrowse={browseCapability.mayWork}
hasScreenCapture={supportsScreenCapture}
hasCamera={supportsCameraCapture()}
onlyImages={false /* because if yes, we only show the attach files above */}
onAttachClipboard={attachAppendClipboardItems}
onAttachFiles={handleAttachFiles}
onAttachScreenCapture={handleAttachScreenCapture}
onOpenCamera={handleOpenCamera}
onOpenGoogleDrivePicker={openGoogleDrivePicker}
onOpenWebInput={openWebInputDialog}
/>
)}
{/* [Mobile] MultiChat button */}
@@ -816,28 +773,27 @@ export function Composer(props: {
{/* [Desktop, Col1] Insert Multi-modal content buttons */}
{isDesktop && showChatAttachments && (
<Box sx={{ flexGrow: 0, display: 'grid', gap: (labsAttachScreenCapture && labsCameraDesktop) ? 0.5 : 1, alignSelf: 'flex-start' }}>
<Box sx={{ flexGrow: 0, display: 'grid', gap: 0.5, alignSelf: 'flex-start' }}>
{/*<FormHelperText sx={{ mx: 'auto' }}>*/}
{/* Attach*/}
{/*</FormHelperText>*/}
{/* [desktop] Attachment Sources: dropdown menu or inline buttons */}
<AttachmentSourcesMemo
mode={!labsComposerAttachmentsInline ? 'menu-rich' : 'inline-buttons'}
color={!labsComposerAttachmentsInline ? (showTint || 'neutral') : showTint}
richButtonStandOut={!isText && !isAppend}
canBrowse={browseCapability.mayWork}
hasScreenCapture={supportsScreenCapture}
hasCamera={supportsCameraCapture()}
onlyImages={showChatAttachments === 'only-images'}
onAttachClipboard={attachAppendClipboardItems}
onAttachFiles={handleAttachFiles}
onAttachScreenCapture={handleAttachScreenCapture}
onOpenCamera={handleOpenCamera}
onOpenGoogleDrivePicker={openGoogleDrivePicker}
onOpenWebInput={openWebInputDialog}
/>
{/* Responsive Open Files button */}
<ButtonAttachFilesMemo color={showTint} onAttachFiles={handleAttachFiles} fullWidth multiple />
{/* Responsive Web button */}
{showChatAttachments !== 'only-images' && <ButtonAttachWebMemo color={showTint} disabled={!hasComposerBrowseCapability} onOpenWebInput={openWebInputDialog} />}
{/* Responsive Paste button */}
{supportsClipboardRead() && showChatAttachments !== 'only-images' && <ButtonAttachClipboardMemo color={showTint} onAttachClipboard={attachAppendClipboardItems} />}
{/* Responsive Screen Capture button */}
{labsAttachScreenCapture && supportsScreenCapture && <ButtonAttachScreenCaptureMemo color={showTint} onAttachScreenCapture={handleAttachScreenCapture} />}
{/* Responsive Camera OCR button */}
{labsCameraDesktop && <ButtonAttachCameraMemo color={showTint} onOpenCamera={openCamera} />}
</Box>)}
</Box>
)}
{/* Top: Textarea & Mic & Overlays, Bottom, Attachment Drafts */}
@@ -859,7 +815,7 @@ export function Composer(props: {
<Textarea
variant='outlined'
color={isDraw ? 'warning' : isReAct ? 'success' : undefined}
autoFocus
autoFocus={isDesktop}
minRows={isMobile ? 3.5 : isDraw ? 4 : agiAttachmentPrompts.hasData ? 3 : showChatInReferenceTo ? 4 : 5}
maxRows={isMobile ? 8 : 10}
placeholder={textPlaceholder}
@@ -905,7 +861,7 @@ export function Composer(props: {
)}
{!showChatInReferenceTo && !isDraw && tokenLimit > 0 && (
<TokenBadgeMemo hideBelowDollars={0.0001} chatPricing={tokenChatPricing} direct={tokensComposer} history={tokensHistory} responseMax={tokensResponseMax} limit={tokenLimit} showCost={labsShowCost} enableHover={!isMobile} showExcess absoluteBottomRight />
<TokenBadgeMemo showCost hideBelowDollars={0.01} chatPricing={tokenChatPricing} direct={tokensComposer} history={tokensHistory} responseMax={tokensResponseMax} limit={tokenLimit} enableHover={!isMobile} showExcess absoluteBottomRight />
)}
</Box>
@@ -984,11 +940,12 @@ export function Composer(props: {
{/* Render any Attachments & menu items */}
{!!conversationOverlayStore && showChatAttachments && (
<LLMAttachmentsList
agiAttachmentPrompts={agiAttachmentPrompts}
<ComposerAttachmentDraftsList
attachmentDraftsStoreApi={conversationOverlayStore}
canInlineSomeFragments={llmAttachmentDraftsCollection.canInlineSomeFragments}
llmAttachmentDrafts={llmAttachmentDraftsCollection.llmAttachmentDrafts}
attachmentDrafts={attachmentDrafts}
enrichment={attEnrichment}
enrichmentSummary={attEnrichSummary}
agiAttachmentPrompts={agiAttachmentPrompts}
onAttachmentDraftsAction={handleAttachmentDraftsAction}
/>
)}
@@ -1008,7 +965,7 @@ export function Composer(props: {
{/* [mobile] bottom-corner secondary button */}
{isMobile && (showChatExtras
? (composerQuickButton === 'call'
? (composerQuickButton === 'call' && speechMayWork
? <ButtonCallMemo isMobile disabled={noConversation || noLLM} onClick={handleCallClicked} />
: <ButtonBeamMemo isMobile disabled={noConversation /*|| noLLM*/} color={beamButtonColor} hasContent={!!composeText} onClick={handleSendTextBeamClicked} />)
: isDraw
@@ -1099,8 +1056,8 @@ export function Composer(props: {
{/* [desktop] secondary bottom-buttons (aligned to bottom for now, and mutually exclusive) */}
{isDesktop && <Box sx={{ mt: 'auto', display: 'grid', gap: 1 }}>
{/* [desktop] Call secondary button */}
{showChatExtras && <ButtonCallMemo disabled={noConversation || noLLM || assistantAbortible} onClick={handleCallClicked} />}
{/* [desktop] Call secondary button - hidden when speech recognition is not available */}
{showChatExtras && speechMayWork && <ButtonCallMemo disabled={noConversation || noLLM || assistantAbortible} onClick={handleCallClicked} />}
{/* [desktop] Draw Options secondary button */}
{isDraw && <ButtonOptionsDraw onClick={handleDrawOptionsClicked} />}
@@ -1120,8 +1077,8 @@ export function Composer(props: {
{/* Execution Mode Menu */}
{chatExecuteMenuComponent}
{/* Camera (when open) */}
{cameraCaptureComponent}
{/* Google Drive Picker (when open) */}
{googleDrivePickerComponent}
{/* Web Input Dialog (when open) */}
{webInputDialogComponent}
@@ -0,0 +1,76 @@
import * as React from 'react';
import { CircularProgress, ListDivider, ListItemDecorator, MenuItem } from '@mui/joy';
import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
import type { AgiAttachmentPromptsData } from '~/modules/aifn/agiattachmentprompts/useAgiAttachmentPrompts';
import type { AttachmentDraft, AttachmentDraftId, AttachmentDraftsAction } from '~/common/attachment-drafts/attachment.types';
import type { AttachmentDraftsStoreApi } from '~/common/attachment-drafts/store-attachment-drafts_slice';
import type { AttachmentEnrichmentSummary, IAttachmentEnrichment } from '~/common/attachment-drafts/llm-enrichment/attachment.enrichment';
import { AttachmentDraftsList } from '~/common/attachment-drafts/attachment-drafts-ui/AttachmentDraftsList';
import { LLMAttachmentsPromptsButtonMemo } from './LLMAttachmentsPromptsButton';
import { ViewDocPartModal } from '../../message/fragments-content/ViewDocPartModal';
import { ViewImageRefPartModal } from '../../message/fragments-content/ViewImageRefPartModal';
/**
* Composer-specific wrapper around the generic AttachmentDraftsList.
* Provides: viewer modals, AI prompts button, "What can I do?" menu item.
*/
export function ComposerAttachmentDraftsList(props: {
attachmentDrafts: AttachmentDraft[],
attachmentDraftsStoreApi: AttachmentDraftsStoreApi,
enrichment: IAttachmentEnrichment,
enrichmentSummary: AttachmentEnrichmentSummary,
agiAttachmentPrompts: AgiAttachmentPromptsData,
onAttachmentDraftsAction: (attachmentDraftId: AttachmentDraftId | null, actionId: AttachmentDraftsAction) => void,
}) {
const { agiAttachmentPrompts, attachmentDrafts } = props;
// memo components
const startDecorator = React.useMemo(() =>
!agiAttachmentPrompts.isVisible && !agiAttachmentPrompts.hasData ? undefined
: <LLMAttachmentsPromptsButtonMemo data={agiAttachmentPrompts} />
, [agiAttachmentPrompts]);
// memo rendering functions
const renderDocViewer = React.useCallback(
(part: React.ComponentProps<typeof ViewDocPartModal>['docPart'], onClose: () => void) =>
<ViewDocPartModal docPart={part} onClose={onClose} />
, []);
const renderImageViewer = React.useCallback(
(part: React.ComponentProps<typeof ViewImageRefPartModal>['imageRefPart'], onClose: () => void) =>
<ViewImageRefPartModal imageRefPart={part} onClose={onClose} />
, []);
const renderOverallMenuExtra = React.useCallback(() => <>
<MenuItem color='primary' variant='soft' onClick={agiAttachmentPrompts.refetch} disabled={!attachmentDrafts.length || agiAttachmentPrompts.isFetching}>
<ListItemDecorator>{agiAttachmentPrompts.isFetching ? <CircularProgress size='sm' /> : <AutoFixHighIcon />}</ListItemDecorator>
What can I do?
</MenuItem>
<ListDivider />
</>, [agiAttachmentPrompts.isFetching, agiAttachmentPrompts.refetch, attachmentDrafts.length]);
return (
<AttachmentDraftsList
attachmentDraftsStoreApi={props.attachmentDraftsStoreApi}
attachmentDrafts={attachmentDrafts}
enrichment={props.enrichment}
enrichmentSummary={props.enrichmentSummary}
onAttachmentDraftsAction={props.onAttachmentDraftsAction}
startDecorator={startDecorator}
renderDocViewer={renderDocViewer}
renderImageViewer={renderImageViewer}
renderOverallMenuExtra={renderOverallMenuExtra}
/>
);
}
@@ -1,98 +0,0 @@
import * as React from 'react';
import type { AttachmentDraft } from '~/common/attachment-drafts/attachment.types';
import type { DLLM } from '~/common/stores/llms/llms.types';
import type { DMessageAttachmentFragment } from '~/common/stores/chat/chat.fragments';
import { estimateTokensForFragments } from '~/common/stores/chat/chat.tokens';
export interface LLMAttachmentDraftsCollection {
llmAttachmentDrafts: LLMAttachmentDraft[];
canAttachAllFragments: boolean;
canInlineSomeFragments: boolean;
llmTokenCountApprox: number | null;
hasImageFragments: boolean;
}
export interface LLMAttachmentDraft {
attachmentDraft: AttachmentDraft;
llmSupportsAllFragments: boolean;
llmSupportsTextFragments: boolean;
llmTokenCountApprox: number | null;
hasImageFragments: boolean;
}
export function useLLMAttachmentDrafts(attachmentDrafts: AttachmentDraft[], chatLLM: DLLM | null, chatLLMSupportsImages: boolean): LLMAttachmentDraftsCollection {
/* [Optimization] Use a Ref to store the previous state of llmAttachmentDrafts and chatLLM
*
* Note that this works on 2 levels:
* - 1. avoids recomputation, but more importantly,
* - 2. avoids re-rendering by keeping those llmAttachmentDrafts objects stable.
*
* Important to notice that the attachmentDraft objects[] are stable to start with, so we can
* safely use reference equality to check if internal properties (or order) have changed.
*/
const prevStateRef = React.useRef<{
chatLLM: DLLM | null;
llmAttachmentDrafts: LLMAttachmentDraft[];
}>({ llmAttachmentDrafts: [], chatLLM: null });
return React.useMemo(() => {
// [Optimization]
const equalChatLLM = chatLLM === prevStateRef.current.chatLLM;
// LLM-dependent multi-modal enablement
// TODO: consider also Audio inputs, maybe PDF binary inputs
// FIXME: reference fragments could refer to non-image as well
const imageTypes: DMessageAttachmentFragment['part']['pt'][] = ['reference', 'image_ref'];
const supportedTypes: DMessageAttachmentFragment['part']['pt'][] = chatLLMSupportsImages ? [...imageTypes, 'doc'] : ['doc'];
const supportedTextTypes: DMessageAttachmentFragment['part']['pt'][] = supportedTypes.filter(pt => pt === 'doc');
// Add LLM-specific properties to each attachment draft
const llmAttachmentDrafts = attachmentDrafts.map((a, index) => {
// [Optimization] If not change in LLM and the attachmentDraft is the same object reference, reuse the previous LLMAttachmentDraft
let prevDraft: LLMAttachmentDraft | undefined = prevStateRef.current.llmAttachmentDrafts[index];
// if not found, search by id
if (!prevDraft)
prevDraft = prevStateRef.current.llmAttachmentDrafts.find(_pd => _pd.attachmentDraft.id === a.id);
if (equalChatLLM && prevDraft && prevDraft.attachmentDraft === a)
return prevDraft;
// Otherwise, create a new LLMAttachmentDraft
return {
attachmentDraft: a,
llmSupportsAllFragments: !a.outputFragments ? false : a.outputFragments.every(op => supportedTypes.includes(op.part.pt)),
llmSupportsTextFragments: !a.outputFragments ? false : a.outputFragments.some(op => supportedTextTypes.includes(op.part.pt)),
llmTokenCountApprox: chatLLM
? estimateTokensForFragments(chatLLM, 'user', a.outputFragments, true, 'useLLMAttachmentDrafts')
: null,
hasImageFragments: !a.outputFragments ? false : a.outputFragments.some(op => imageTypes.includes(op.part.pt)),
};
});
// Calculate the overall properties
const canAttachAllFragments = llmAttachmentDrafts.every(a => a.llmSupportsAllFragments);
const canInlineSomeFragments = llmAttachmentDrafts.some(a => a.llmSupportsTextFragments);
const llmTokenCountApprox = chatLLM
? llmAttachmentDrafts.reduce((acc, a) => acc + (a.llmTokenCountApprox || 0), 0)
: null;
const hasImageFragments = llmAttachmentDrafts.some(a => a.hasImageFragments);
// [Optimization] Update the ref with the new state
prevStateRef.current = { llmAttachmentDrafts, chatLLM };
return {
llmAttachmentDrafts,
canAttachAllFragments,
canInlineSomeFragments,
llmTokenCountApprox,
hasImageFragments,
};
}, [attachmentDrafts, chatLLM, chatLLMSupportsImages]); // Dependencies for the outer useMemo
}
@@ -47,9 +47,9 @@ function TokenBadge(props: {
const showAltCosts = !!props.showCost && !!costMax && costMin !== undefined;
if (showAltCosts) {
// Note: switched to 'min cost (>= ...)' on mobile as well, to restore the former behavior, just uncomment the !props.enableHover (a proxy for isMobile)
badgeValue = (/*!props.enableHover ||*/ isHovering)
? '< ' + formatModelsCost(costMax)
: '> ' + formatModelsCost(costMin);
badgeValue =
// (/*!props.enableHover ||*/ isHovering) ? '< ' + formatModelsCost(costMax) :
'> ' + formatModelsCost(costMin);
} else {
// show the direct tokens, unless we exceed the limit and 'showExcess' is enabled
@@ -77,7 +77,7 @@ function TokenBadge(props: {
slotProps={{
root: {
sx: {
...((props.absoluteBottomRight) && { position: 'absolute', bottom: 8, right: 8 }),
...((props.absoluteBottomRight) && { position: 'absolute', bottom: 8, right: '1rem' }),
cursor: 'help',
...(shallInvisible && {
opacity: 0,
@@ -92,6 +92,13 @@ function TokenBadge(props: {
fontFamily: 'code',
fontSize: 'xs',
...((props.absoluteBottomRight || props.inline) && { position: 'static', transform: 'none' }),
// make it transparent over text
// backgroundColor: `rgb(var(--joy-palette-${color}-lightChannel) / 15%)`, // similar to success.50
background: 'transparent',
boxShadow: 'none', // outline
'&:hover': {
backgroundColor: `${color}.softHoverBg`,
},
},
},
}}
@@ -8,7 +8,7 @@ import SettingsIcon from '@mui/icons-material/Settings';
import { findModelVendor } from '~/modules/llms/vendors/vendors.registry';
import type { DModelsServiceId } from '~/common/stores/llms/llms.service.types';
import { DLLM, DLLMId, isLLMVisible } from '~/common/stores/llms/llms.types';
import { DLLM, DLLMId, getLLMLabel, isLLMVisible } from '~/common/stores/llms/llms.types';
import { DebouncedInputMemo } from '~/common/components/DebouncedInput';
import { GoodTooltip } from '~/common/components/GoodTooltip';
import { KeyStroke } from '~/common/components/KeyStroke';
@@ -65,7 +65,7 @@ function LLMDropdown(props: {
return true;
// filter-out models that don't contain the search string
if (lcFilterString && !llm.label.toLowerCase().includes(lcFilterString))
if (lcFilterString && !getLLMLabel(llm).toLowerCase().includes(lcFilterString))
return false;
// filter-out hidden models from the dropdown
@@ -89,7 +89,7 @@ function LLMDropdown(props: {
// add the model item
llmItems[llm.id] = {
title: llm.label,
title: getLLMLabel(llm),
...(llm.userStarred ? { symbol: '⭐' } : {}),
// icon: llm.id.startsWith('some vendor') ? <VendorIcon /> : undefined,
};
@@ -66,6 +66,7 @@ function ChatDrawer(props: {
activeFolderId: string | null,
chatPanesConversationIds: DConversationId[],
disableNewButton: boolean,
focusedChatBeamOpen: boolean,
onConversationActivate: (conversationId: DConversationId) => void,
onConversationBranch: (conversationId: DConversationId, messageId: string | null, addSplitPane: boolean) => void,
onConversationNew: (forceNoRecycle: boolean, isIncognito: boolean) => void,
@@ -291,6 +292,17 @@ function ChatDrawer(props: {
toggleFilterHasDocFragments, toggleFilterHasImageAssets, toggleFilterHasStars, toggleFilterIsArchived, toggleShowPersonaIcons, toggleShowRelativeSize,
]);
const displayNavItems = React.useMemo(() => {
if (renderLimit === Infinity || renderLimit >= renderNavItems.length) return renderNavItems;
// return sliced if it contains the active conversation
const sliced = renderNavItems.slice(0, renderLimit);
if (!props.activeConversationId || sliced.some(i => i.type === 'nav-item-chat-data' && i.conversationId === props.activeConversationId)) return sliced;
// include the active conversation if it's beyond the fold
const activeItem = renderNavItems.find((i, idx) => idx >= renderLimit && i.type === 'nav-item-chat-data' && i.conversationId === props.activeConversationId);
return activeItem ? [...sliced, activeItem] : sliced;
}, [renderNavItems, renderLimit, props.activeConversationId]);
return <>
@@ -379,7 +391,7 @@ function ChatDrawer(props: {
{/* Chat Titles List (shrink as half the rate as the Folders List) */}
<Box sx={{ flexGrow: 1, flexShrink: 1, flexBasis: '20rem', overflowY: 'auto', ...themeScalingMap[contentScaling].chatDrawerItemSx }}>
{renderNavItems.slice(0, renderLimit).map((item, idx) => item.type === 'nav-item-chat-data' ? (
{displayNavItems.map((item, idx) => item.type === 'nav-item-chat-data' ? (
<ChatDrawerItemMemo
key={'nav-chat-' + item.conversationId}
item={item}
@@ -456,7 +468,7 @@ function ChatDrawer(props: {
{/*<OpenAIIcon sx={{ ml: 'auto' }} />*/}
</ListItemButton>
<ListItemButton disabled={filteredChatsAreEmpty} onClick={handleConversationsExport} sx={{ flex: 1 }}>
<ListItemButton disabled={filteredChatsAreEmpty || props.focusedChatBeamOpen} onClick={handleConversationsExport} sx={{ flex: 1 }}>
<ListItemDecorator>
<FileUploadOutlinedIcon />
</ListItemDecorator>
@@ -282,7 +282,7 @@ function ChatDrawerItem(props: {
{searchFrequency > 0 ? (
// Display search frequency if it exists and is greater than 0
<Typography level='body-sm'>
{searchFrequency}
{Math.round(searchFrequency * 10) / 10}
</Typography>
) : (props.showSymbols && (userFlagsSummary || containsDocAttachments || containsImageAssets)) ? (
<Box sx={{
@@ -5,7 +5,7 @@ import { useModuleBeamStore } from '~/modules/beam/store-module-beam';
import type { DFolder } from '~/common/stores/folders/store-chat-folders';
import { DMessage, DMessageUserFlag, MESSAGE_FLAG_STARRED, messageFragmentsReduceText, messageHasUserFlag, messageUserFlagToEmoji } from '~/common/stores/chat/chat.message';
import { conversationTitle, DConversationId } from '~/common/stores/chat/chat.conversation';
import { getLocalMidnightInUTCTimestamp, getTimeBucketEn } from '~/common/util/timeUtils';
import { createTimeBucketClassifierEn } from '~/common/util/timeUtils';
import { isAttachmentFragment, isContentOrAttachmentFragment, isDocPart, isImageRefPart, isZyncAssetImageReferencePart } from '~/common/stores/chat/chat.fragments';
import { shallowEquals } from '~/common/util/hooks/useShallowObject';
import { useChatStore } from '~/common/stores/chat/store-chats';
@@ -235,14 +235,14 @@ export function useChatDrawerRenderItems(
break;
}
const midnightTime = getLocalMidnightInUTCTimestamp();
const getTimeBucket = createTimeBucketClassifierEn();
const grouped = chatNavItems.reduce((acc, item) => {
// derive the bucket name
let bucket: string;
switch (grouping) {
case 'date':
bucket = getTimeBucketEn(item.updatedAt || midnightTime, midnightTime);
bucket = getTimeBucket(item.updatedAt || Date.now());
break;
case 'persona':
bucket = item.systemPurposeId;
@@ -6,7 +6,6 @@ import AddIcon from '@mui/icons-material/Add';
import ArchiveOutlinedIcon from '@mui/icons-material/ArchiveOutlined';
import CleaningServicesOutlinedIcon from '@mui/icons-material/CleaningServicesOutlined';
import CompressIcon from '@mui/icons-material/Compress';
import EngineeringIcon from '@mui/icons-material/Engineering';
import ForkRightIcon from '@mui/icons-material/ForkRight';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import RestartAltIcon from '@mui/icons-material/RestartAlt';
@@ -14,15 +13,14 @@ import SettingsSuggestOutlinedIcon from '@mui/icons-material/SettingsSuggestOutl
import UnarchiveOutlinedIcon from '@mui/icons-material/UnarchiveOutlined';
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
import { ChromelessItemButton } from '~/common/layout/optima/ChromelessItemButton';
import { CodiconSplitHorizontal } from '~/common/components/icons/CodiconSplitHorizontal';
import { CodiconSplitHorizontalRemove } from '~/common/components/icons/CodiconSplitHorizontalRemove';
import { CodiconSplitVertical } from '~/common/components/icons/CodiconSplitVertical';
import { CodiconSplitVerticalRemove } from '~/common/components/icons/CodiconSplitVerticalRemove';
import { FormLabelStart } from '~/common/components/forms/FormLabelStart';
import { OptimaPanelGroupedList, OptimaPanelGroupGutter } from '~/common/layout/optima/panel/OptimaPanelGroupedList';
import { optimaActions } from '~/common/layout/optima/useOptima';
import { useChatStore } from '~/common/stores/chat/store-chats'; // may be replaced with a dedicated hook for the chat pane
import { useLabsDevMode } from '~/common/stores/store-ux-labs';
import { useChatShowSystemMessages } from '../../store-app-chat';
import { panesManagerActions, usePaneDuplicateOrClose } from '../panes/store-panes-manager';
@@ -40,6 +38,7 @@ function VariformPaneFrame() {
export function ChatPane(props: {
isMobile: boolean,
conversationId: DConversationId | null,
disableItems: boolean,
hasConversations: boolean,
@@ -55,7 +54,6 @@ export function ChatPane(props: {
// external state
const { canAddPane, isMultiPane } = usePaneDuplicateOrClose();
const [showSystemMessages, setShowSystemMessages] = useChatShowSystemMessages();
const labsDevMode = useLabsDevMode();
const { isArchived, setArchived } = useChatStore(useShallow((state) => {
const conversation = state.conversations.find(_c => _c.id === props.conversationId);
@@ -147,6 +145,8 @@ export function ChatPane(props: {
</ListItemButton>
</ListItem>
{props.isMobile && <ChromelessItemButton />}
</OptimaPanelGroupedList>
{/* Chat Actions group */}
@@ -213,15 +213,5 @@ export function ChatPane(props: {
</ListItemButton>
</OptimaPanelGroupedList>
{/* [DEV] Development */}
{labsDevMode && (
<OptimaPanelGroupedList title='[Developers]'>
<MenuItem onClick={optimaActions().openAIXDebugger}>
<ListItemDecorator><EngineeringIcon /></ListItemDecorator>
AIX: Show Last Request...
</MenuItem>
</OptimaPanelGroupedList>
)}
</>;
}
@@ -4,7 +4,8 @@ import type { SxProps } from '@mui/joy/styles/types';
import { Box, Button, ColorPaletteProp } from '@mui/joy';
import type { ContentScaling } from '~/common/app.theme';
import { DMessageContentFragment, DMessageTextPart, isTextContentFragment } from '~/common/stores/chat/chat.fragments';
import type { InterleavedFragment } from '~/common/stores/chat/hooks/useFragmentBuckets';
import { DMessageTextPart, isTextContentFragment } from '~/common/stores/chat/chat.fragments';
// configuration
@@ -35,7 +36,7 @@ const optionGroupSx: SxProps = {
flexDirection: 'column',
alignItems: 'flex-start',
gap: 0,
};
} as const;
const optionSx: SxProps = {
// style
@@ -51,10 +52,22 @@ const optionSx: SxProps = {
// layout
justifyContent: 'flex-start',
};
} as const;
const optionBoldSx: SxProps = {
...optionSx,
fontWeight: 'lg',
} as const;
export function optionsExtractFromFragments_dangerModifyFragment(enabled: boolean, fragments: DMessageContentFragment[]): { fragments: DMessageContentFragment[], options: string[], } {
// '1. **text**' -> '1. text', or: **text** -> text
function _stripMarkdownBold(text: string): { text: string; isBold: boolean } {
const stripped = text.replace(/(\*{2,})(.+)\1\s*$/, '$2').trimEnd();
return { text: stripped, isBold: stripped !== text };
}
export function optionsExtractFromFragments_dangerModifyFragment(enabled: boolean, fragments: InterleavedFragment[]): { fragments: InterleavedFragment[], options: string[] } {
if (enabled && fragments.length) {
const fragment = fragments[fragments.length - 1];
if (isTextContentFragment(fragment)) {
@@ -163,21 +176,25 @@ export function BlockOpOptions(props: {
options: string[],
onContinue: (continueText: null | string) => void,
}) {
const buttonSx = React.useMemo(() => ({ ...optionSx, fontSize: props.contentScaling }), [props.contentScaling]);
const normalSx = React.useMemo(() => ({ ...optionSx, fontSize: props.contentScaling }), [props.contentScaling]);
const boldSx = React.useMemo(() => ({ ...optionBoldSx, fontSize: props.contentScaling }), [props.contentScaling]);
return (
<Box sx={optionGroupSx}>
{props.options.map((option, index) => (
<Button
key={index}
color={OPTION_ACTIVE_COLOR}
variant='soft'
size={props.contentScaling === 'md' ? 'md' : 'sm'}
onClick={() => props.onContinue(option.endsWith('?') ? option.slice(0, -1) : option)}
sx={buttonSx}
>
{option}
</Button>
))}
{props.options.map((option, index) => {
const { text, isBold } = _stripMarkdownBold(option);
return (
<Button
key={index}
color={OPTION_ACTIVE_COLOR}
variant='soft'
size={props.contentScaling === 'md' ? 'md' : 'sm'}
onClick={() => props.onContinue(text.endsWith('?') ? text.slice(0, -1) : text)}
sx={isBold ? boldSx : normalSx}
>
{text}
</Button>
);
})}
</Box>
);
}
@@ -1,11 +1,16 @@
import * as React from 'react';
import TimeAgo from 'react-timeago';
import { Box, Button, ButtonGroup, Tooltip, Typography } from '@mui/joy';
import PlayArrowRoundedIcon from '@mui/icons-material/PlayArrowRounded';
import StopRoundedIcon from '@mui/icons-material/StopRounded';
import type { DMessageGenerator } from '~/common/stores/chat/chat.message';
const ARM_TIMEOUT_MS = 4000;
/**
* FIXME: COMPLETE THIS
*/
@@ -20,8 +25,14 @@ export function BlockOpUpstreamResume(props: {
const [isResuming, setIsResuming] = React.useState(false);
const [isCancelling, setIsCancelling] = React.useState(false);
const [isDeleting, setIsDeleting] = React.useState(false);
const [deleteArmed, setDeleteArmed] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);
// expiration: boolean is evaluated at render (may lag briefly if nothing re-renders past expiry).
// TimeAgo handles its own tick for the label; the button's disabled state is the only consumer of this flag.
const { expiresAt, runId = '' } = props.upstreamHandle;
const isExpired = expiresAt != null && Date.now() > expiresAt;
// handlers
const handleResume = React.useCallback(async () => {
@@ -50,8 +61,14 @@ export function BlockOpUpstreamResume(props: {
}
}, [props]);
// Two-click arm: first click arms (visible red "Confirm?"), second click (within ARM_TIMEOUT_MS) executes.
const handleDelete = React.useCallback(async () => {
if (!props.onDelete) return;
if (!deleteArmed) {
setDeleteArmed(true);
return;
}
setDeleteArmed(false);
setError(null);
setIsDeleting(true);
try {
@@ -61,7 +78,15 @@ export function BlockOpUpstreamResume(props: {
} finally {
setIsDeleting(false);
}
}, [props]);
}, [deleteArmed, props]);
// Auto-disarm after ARM_TIMEOUT_MS so the armed state can't leak into a later session
React.useEffect(() => {
if (!deleteArmed) return;
const t = setTimeout(() => setDeleteArmed(false), ARM_TIMEOUT_MS);
return () => clearTimeout(t);
}, [deleteArmed]);
return (
<Box
@@ -77,9 +102,9 @@ export function BlockOpUpstreamResume(props: {
{props.onResume && (
<Tooltip title='Resume generation from last checkpoint'>
<Button
disabled={isResuming || isCancelling || isDeleting}
disabled={isResuming || isCancelling || isDeleting || isExpired}
loading={isResuming}
startDecorator={<PlayArrowRoundedIcon sx={{ color: 'success.solidBg' }} />}
startDecorator={<PlayArrowRoundedIcon color='success' />}
onClick={handleResume}
>
Resume
@@ -101,14 +126,16 @@ export function BlockOpUpstreamResume(props: {
)}
{props.onDelete && (
<Tooltip title='Delete the stored response'>
<Tooltip title={deleteArmed ? 'Click again to confirm - cancels the run upstream (no resume after)' : 'Cancel the upstream run'}>
<Button
loading={isDeleting}
// startDecorator={<DeleteIcon />}
color={deleteArmed ? 'danger' : 'neutral'}
variant={deleteArmed ? 'solid' : 'outlined'}
startDecorator={<StopRoundedIcon />}
onClick={handleDelete}
disabled={isResuming || isCancelling || isDeleting}
>
Delete
{deleteArmed ? 'Confirm?' : 'Cancel'}
</Button>
</Tooltip>
)}
@@ -120,9 +147,11 @@ export function BlockOpUpstreamResume(props: {
</Typography>
)}
<Typography level='body-xs' sx={{ fontSize: '0.65rem', opacity: 0.6 }}>
Response ID: {props.upstreamHandle.responseId.slice(0, 12)}...
</Typography>
{!!expiresAt && <Typography level='body-xs' sx={{ fontSize: '0.65rem', opacity: 0.6 }}>
{/*Run ID: {runId.slice(0, 12)}...*/}
{/*{!!expiresAt && <> · Expires <TimeAgo date={expiresAt} /></>}*/}
Expires <TimeAgo date={expiresAt} />
</Typography>}
</Box>
);
}
+137 -66
View File
@@ -5,8 +5,6 @@ import TimeAgo from 'react-timeago';
import type { SxProps } from '@mui/joy/styles/types';
import { Box, ButtonGroup, CircularProgress, Divider, IconButton, ListDivider, ListItem, ListItemDecorator, MenuItem, Switch, Tooltip, Typography } from '@mui/joy';
import { ClickAwayListener, Popper } from '@mui/base';
import AccountTreeOutlinedIcon from '@mui/icons-material/AccountTreeOutlined';
import AlternateEmailIcon from '@mui/icons-material/AlternateEmail';
import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
@@ -17,11 +15,10 @@ import EditRoundedIcon from '@mui/icons-material/EditRounded';
import ForkRightIcon from '@mui/icons-material/ForkRight';
import FormatBoldIcon from '@mui/icons-material/FormatBold';
import FormatPaintOutlinedIcon from '@mui/icons-material/FormatPaintOutlined';
import InsertLinkIcon from '@mui/icons-material/InsertLink';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import NotificationsActiveIcon from '@mui/icons-material/NotificationsActive';
import NotificationsOutlinedIcon from '@mui/icons-material/NotificationsOutlined';
import RecordVoiceOverOutlinedIcon from '@mui/icons-material/RecordVoiceOverOutlined';
import ReplayIcon from '@mui/icons-material/Replay';
import ReplyAllRoundedIcon from '@mui/icons-material/ReplyAllRounded';
import ReplyRoundedIcon from '@mui/icons-material/ReplyRounded';
@@ -37,22 +34,26 @@ import { ModelVendorAnthropic } from '~/modules/llms/vendors/anthropic/anthropic
import { AnthropicIcon } from '~/common/components/icons/vendors/AnthropicIcon';
import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
import { CloseablePopup } from '~/common/components/CloseablePopup';
import { DMessage, DMessageId, DMessageUserFlag, DMetaReferenceItem, MESSAGE_FLAG_AIX_SKIP, MESSAGE_FLAG_NOTIFY_COMPLETE, MESSAGE_FLAG_STARRED, MESSAGE_FLAG_VND_ANT_CACHE_AUTO, MESSAGE_FLAG_VND_ANT_CACHE_USER, messageFragmentsReduceText, messageHasUserFlag } from '~/common/stores/chat/chat.message';
import { DMessage, DMessageGenerator, DMessageId, DMessageUserFlag, DMetaReferenceItem, MESSAGE_FLAG_AIX_SKIP, MESSAGE_FLAG_NOTIFY_COMPLETE, MESSAGE_FLAG_STARRED, MESSAGE_FLAG_VND_ANT_CACHE_AUTO, MESSAGE_FLAG_VND_ANT_CACHE_USER, messageFragmentsReduceText, messageHasUserFlag } from '~/common/stores/chat/chat.message';
import { KeyStroke } from '~/common/components/KeyStroke';
import { MarkHighlightIcon } from '~/common/components/icons/MarkHighlightIcon';
import { PhTreeStructure } from '~/common/components/icons/phosphor/PhTreeStructure';
import { PhVoice } from '~/common/components/icons/phosphor/PhVoice';
import { Release } from '~/common/app.release';
import { StarredState } from '~/common/components/StarIcons';
import { TooltipOutlined } from '~/common/components/TooltipOutlined';
import { adjustContentScaling, themeScalingMap, themeZIndexChatBubble } from '~/common/app.theme';
import { avatarIconSx, makeMessageAvatarIcon, messageBackground, useMessageAvatarLabel } from '~/common/util/dMessageUtils';
import { copyToClipboard } from '~/common/util/clipboardUtils';
import { clipboardCopyDOMSelectionOrFallback, copyToClipboard } from '~/common/util/clipboardUtils';
import { createTextContentFragment, DMessageFragment, DMessageFragmentId, updateFragmentWithEditedText } from '~/common/stores/chat/chat.fragments';
import { useFragmentBuckets } from '~/common/stores/chat/hooks/useFragmentBuckets';
import { useUIPreferencesStore } from '~/common/stores/store-ui';
import { useUXLabsStore } from '~/common/stores/store-ux-labs';
import { BlockOpContinue } from './BlockOpContinue';
import { BlockOpOptions, optionsExtractFromFragments_dangerModifyFragment } from './BlockOpOptions';
import { BlockOpUpstreamResume } from './BlockOpUpstreamResume';
import { ChatMessageEditAttachments, type EditModeAttachmentsHandle } from './ChatMessageEditAttachments';
import { ChatMessageInfoPopup } from './ChatMessageInfoPopup';
import { ContentFragments } from './fragments-content/ContentFragments';
import { DocumentAttachmentFragments } from './fragments-attachment-doc/DocumentAttachmentFragments';
import { ImageAttachmentFragments } from './fragments-attachment-image/ImageAttachmentFragments';
@@ -69,7 +70,7 @@ const ENABLE_BUBBLE = true;
export const BUBBLE_MIN_TEXT_LENGTH = 3;
// Enable the hover button to copy the whole message. The Copy button is also available in Blocks, or in the Avatar Menu.
const ENABLE_COPY_MESSAGE_OVERLAY: boolean = false;
// const ENABLE_COPY_MESSAGE_OVERLAY: boolean = false;
const messageBodySx: SxProps = {
@@ -160,6 +161,8 @@ export function ChatMessage(props: {
onMessageBeam?: (messageId: string) => Promise<void>,
onMessageBranch?: (messageId: string) => void,
onMessageContinue?: (messageId: string, continueText: null | string) => void,
onMessageUpstreamResume?: (generator: DMessageGenerator, messageId: string) => Promise<void>,
onMessageUpstreamDelete?: (generator: DMessageGenerator, messageId: string) => Promise<void>,
onMessageDelete?: (messageId: string) => void,
onMessageFragmentAppend?: (messageId: DMessageId, fragment: DMessageFragment) => void
onMessageFragmentDelete?: (messageId: DMessageId, fragmentId: DMessageFragmentId) => void,
@@ -180,6 +183,8 @@ export function ChatMessage(props: {
const [contextMenuAnchor, setContextMenuAnchor] = React.useState<HTMLElement | null>(null);
const [opsMenuAnchor, setOpsMenuAnchor] = React.useState<HTMLElement | null>(null);
const [textContentEditState, setTextContentEditState] = React.useState<ChatMessageTextPartEditState | null>(null);
const [showInfoModal, setShowInfoModal] = React.useState(false);
const attachmentsEditRef = React.useRef<EditModeAttachmentsHandle>(null);
// external state
const { adjContentScaling, disableMarkdown, doubleClickToEdit, uiComplexityMode } = useUIPreferencesStore(useShallow(state => ({
@@ -188,7 +193,6 @@ export function ChatMessage(props: {
doubleClickToEdit: state.doubleClickToEdit,
uiComplexityMode: state.complexityMode,
})));
const labsEnhanceCodeBlocks = useUXLabsStore(state => state.labsEnhanceCodeBlocks);
const [showDiff, setShowDiff] = useChatShowTextDiff();
@@ -217,15 +221,15 @@ export function ChatMessage(props: {
const isVndAndCacheUser = !!props.showAntPromptCaching && messageHasUserFlag(props.message, MESSAGE_FLAG_VND_ANT_CACHE_USER);
const {
annotationFragments, // Web Citations, References (rendered at top)
interleavedFragments, // Reasoning, Placeholders, Text, Code, Tools (interleaved in temporal order)
imageAttachments, // Stamp-sized Images
voidFragments, // Model-Aux, Placeholders
contentFragments, // Text (Markdown + Code + ... blocks), Errors, (large) Images
nonImageAttachments, // Document Attachments, likely the User dropped them in
lastFragmentIsError,
} = useFragmentBuckets(messageFragments);
const fragmentFlattenedText = React.useMemo(() => messageFragmentsReduceText(messageFragments), [messageFragments]);
const handleHighlightSelText = useSelHighlighterMemo(messageId, selText, contentFragments, fromAssistant, props.onMessageFragmentReplace);
const handleHighlightSelText = useSelHighlighterMemo(messageId, selText, interleavedFragments.filter(f => f.ft === 'content'), fromAssistant, props.onMessageFragmentReplace);
const textSubject = selText ? selText : fragmentFlattenedText;
const isSpecialT2I = textSubject.startsWith('/draw ') || textSubject.startsWith('/imagine ') || textSubject.startsWith('/img ');
@@ -243,7 +247,7 @@ export function ChatMessage(props: {
// const wordsDiff = useWordsDifference(textSubject, props.diffPreviousText, showDiff);
const { onMessageAssistantFrom, onMessageDelete, onMessageFragmentAppend, onMessageFragmentDelete, onMessageFragmentReplace, onMessageContinue } = props;
const { onMessageAssistantFrom, onMessageDelete, onMessageFragmentAppend, onMessageFragmentDelete, onMessageFragmentReplace, onMessageContinue, onMessageUpstreamResume, onMessageUpstreamDelete } = props;
const handleFragmentNew = React.useCallback(() => {
onMessageFragmentAppend?.(messageId, createTextContentFragment(''));
@@ -261,6 +265,16 @@ export function ChatMessage(props: {
onMessageContinue?.(messageId, continueText);
}, [messageId, onMessageContinue]);
const handleUpstreamResume = React.useCallback(() => {
if (!messageGenerator) return;
return onMessageUpstreamResume?.(messageGenerator, messageId);
}, [messageGenerator, messageId, onMessageUpstreamResume]);
const handleUpstreamDelete = React.useCallback(() => {
if (!messageGenerator) return;
return onMessageUpstreamDelete?.(messageGenerator, messageId);
}, [messageGenerator, messageId, onMessageUpstreamDelete]);
// Text Editing
@@ -280,14 +294,25 @@ export function ChatMessage(props: {
}, [handleFragmentDelete, handleFragmentReplace, messageFragments]);
const handleApplyAllEdits = React.useCallback(async (withControl: boolean) => {
const state = textContentEditState || {};
// 0. take state, including new attachment drafts BEFORE clearing state
const fragmentsEdits = textContentEditState || {};
const newFragments = await attachmentsEditRef.current?.takeAllFragments() ?? [];
// 1. clear edit state (unmounts EditModeAttachments, triggers cleanup)
setTextContentEditState(null);
for (const [fragmentId, editedText] of Object.entries(state))
// 2A. apply text fragment edits
for (const [fragmentId, editedText] of Object.entries(fragmentsEdits))
handleApplyEdit(fragmentId, editedText);
// if the user pressed Ctrl, we begin a regeneration from here
// 2B. append new attachment fragments
for (const fragment of newFragments)
onMessageFragmentAppend?.(messageId, fragment);
// 3. if the user pressed Ctrl, we begin a regeneration from here
if (withControl && onMessageAssistantFrom)
await onMessageAssistantFrom(messageId, 0);
}, [handleApplyEdit, messageId, onMessageAssistantFrom, textContentEditState]);
}, [handleApplyEdit, messageId, onMessageAssistantFrom, onMessageFragmentAppend, textContentEditState]);
const handleEditsApplyClicked = React.useCallback(() => handleApplyAllEdits(false), [handleApplyAllEdits]);
@@ -314,11 +339,17 @@ export function ChatMessage(props: {
const handleCloseOpsMenu = React.useCallback(() => setOpsMenuAnchor(null), []);
const handleOpsCopy = (e: React.MouseEvent) => {
copyToClipboard(textSubject, 'Text');
const handleOpsMessageCopySrc = React.useCallback((e: React.MouseEvent) => {
e.preventDefault();
// copy full source text (ops menu) - bypasses DOM, always gets pre-collapsed content
copyToClipboard(fragmentFlattenedText, 'Message');
handleCloseOpsMenu();
closeContextMenu();
}, [fragmentFlattenedText, handleCloseOpsMenu]);
const handleBubbleCopyDOM = (e: React.MouseEvent) => {
e.preventDefault();
// copy cleaned DOM selection (bubble) - rich text for pasting into Google Docs, etc.
clipboardCopyDOMSelectionOrFallback(blocksRendererRef.current, textSubject, 'Selection');
closeBubble();
};
@@ -342,6 +373,13 @@ export function ChatMessage(props: {
onMessageToggleUserFlag?.(messageId, MESSAGE_FLAG_STARRED);
}, [messageId, onMessageToggleUserFlag]);
const handleOpsShowInfo = React.useCallback(() => {
setOpsMenuAnchor(null);
setShowInfoModal(true);
}, []);
const handleInfoClose = React.useCallback(() => setShowInfoModal(false), []);
const handleOpsToggleNotifyComplete = React.useCallback(() => {
// also remember the preference, for auto-setting flags by the persona
setIsNotificationEnabledForModel(messageId, !isUserNotifyComplete);
@@ -579,9 +617,9 @@ export function ChatMessage(props: {
const lookForOptions = props.onMessageContinue !== undefined && props.isBottom === true && messageGenerator?.tokenStopReason !== 'out-of-tokens' && fromAssistant && !messagePendingIncomplete && !isEditingText && uiComplexityMode !== 'minimal' && false;
const { fragments: renderContentFragments, options: continuationOptions } = React.useMemo(() => {
return optionsExtractFromFragments_dangerModifyFragment(lookForOptions, contentFragments);
}, [contentFragments, lookForOptions]);
const { fragments: renderInterleavedFragments, options: continuationOptions } = React.useMemo(() => {
return optionsExtractFromFragments_dangerModifyFragment(lookForOptions, interleavedFragments);
}, [interleavedFragments, lookForOptions]);
// style
@@ -589,7 +627,7 @@ export function ChatMessage(props: {
const listItemSx: SxProps = React.useMemo(() => ({
// vars
'--AGI-overlay-start-opacity': uiComplexityMode === 'extra' ? 0.1 : 0,
// '--AGI-overlay-start-opacity': uiComplexityMode === 'extra' ? 0.1 : 0, // disabled - looks worse
// style
backgroundColor: backgroundColor,
@@ -773,20 +811,23 @@ export function ChatMessage(props: {
/>
)}
{/* Void Fragments */}
{voidFragments.length >= 1 && (
{/* Annotation Fragments (absolute top: citations, references) */}
{annotationFragments.length >= 1 && (
<VoidFragments
voidFragments={voidFragments}
nonVoidFragmentsCount={renderContentFragments.length}
voidFragments={annotationFragments}
nonVoidFragmentsCount={interleavedFragments.filter(f => f.ft === 'content').length}
contentScaling={adjContentScaling}
uiComplexityMode={uiComplexityMode}
messageRole={messageRole}
messagePendingIncomplete={messagePendingIncomplete}
onFragmentDelete={!props.onMessageFragmentDelete ? undefined : handleFragmentDelete}
onFragmentReplace={!props.onMessageFragmentReplace ? undefined : handleFragmentReplace}
/>
)}
{/* Content Fragments */}
{/* Interleaved Fragments (reasoning + content in temporal order) */}
<ContentFragments
contentFragments={renderContentFragments}
contentFragments={renderInterleavedFragments}
showEmptyNotice={!messageFragments.length && !messagePendingIncomplete}
contentScaling={adjContentScaling}
@@ -794,10 +835,11 @@ export function ChatMessage(props: {
fitScreen={props.fitScreen}
isMobile={props.isMobile}
messageRole={messageRole}
messageGeneratorLlmId={messageGenerator?.mgt === 'aix' ? messageGenerator.aix?.mId : undefined}
messagePendingIncomplete={messagePendingIncomplete}
optiAllowSubBlocksMemo={!!messagePendingIncomplete}
disableMarkdownText={disableMarkdown || fromUser /* User messages are edited as text. Try to have them in plain text. NOTE: This may bite. */}
showUnsafeHtmlCode={props.showUnsafeHtmlCode}
enhanceCodeBlocks={labsEnhanceCodeBlocks}
textEditsState={textContentEditState}
setEditedText={(!props.onMessageFragmentReplace || messagePendingIncomplete) ? undefined : handleEditSetText}
@@ -828,6 +870,14 @@ export function ChatMessage(props: {
/>
)}
{/* [Edit Mode] Add new attachments (right below the Document Fragments) */}
{isEditingText && !fromAssistant && !!onMessageFragmentAppend && (
<ChatMessageEditAttachments
ref={attachmentsEditRef}
isMobile={props.isMobile}
/>
)}
{/* [SYSTEM, REAL] Image Attachment Fragments - just for a realistic display below the system instruction text/docs */}
{fromSystem && imageAttachments.length >= 1 && (
<ImageAttachmentFragments
@@ -848,13 +898,12 @@ export function ChatMessage(props: {
/>
)}
{/* Upstream Resume... */}
{props.isBottom && fromAssistant && lastFragmentIsError && messageGenerator?.upstreamHandle?.responseId && (
{/* Upstream Resume - shows whenever there's a stored handle (incl. post-reload, where no error fragment is present) */}
{!messagePendingIncomplete && props.isBottom && fromAssistant && messageGenerator?.upstreamHandle && (!!onMessageUpstreamResume || !!onMessageUpstreamDelete) && (
<BlockOpUpstreamResume
upstreamHandle={messageGenerator.upstreamHandle}
onResume={console.error}
onCancel={console.error}
onDelete={console.error}
onResume={onMessageUpstreamResume ? handleUpstreamResume : undefined}
onDelete={onMessageUpstreamDelete ? handleUpstreamDelete : undefined}
/>
)}
@@ -867,6 +916,13 @@ export function ChatMessage(props: {
/>
)}
{/* Char & Word count */}
{/*{!zenMode && !isEditingText && !messagePendingIncomplete && fragmentFlattenedText.length > 0 && (*/}
{/* <Typography level='body-xs' sx={{ mx: 1.5, mt: 0.5, textAlign: fromAssistant ? 'left' : 'right', opacity: 0.5 }}>*/}
{/* {fragmentFlattenedText.length.toLocaleString()} chars · {(fragmentFlattenedText.match(/\S+/g) || []).length.toLocaleString()} words*/}
{/* </Typography>*/}
{/*)}*/}
</Box>
@@ -888,18 +944,18 @@ export function ChatMessage(props: {
{/* Overlay copy icon */}
{ENABLE_COPY_MESSAGE_OVERLAY && !fromSystem && !isEditingText && (
<Tooltip title={messagePendingIncomplete ? null : (fromAssistant ? 'Copy message' : 'Copy input')} variant='solid'>
<IconButton
variant='outlined' onClick={handleOpsCopy}
sx={{
position: 'absolute', ...(fromAssistant ? { right: { xs: 12, md: 28 } } : { left: { xs: 12, md: 28 } }), zIndex: 10,
opacity: 0, transition: 'opacity 0.16s cubic-bezier(.17,.84,.44,1)',
}}>
<ContentCopyIcon />
</IconButton>
</Tooltip>
)}
{/*{ENABLE_COPY_MESSAGE_OVERLAY && !fromSystem && !isEditingText && (*/}
{/* <Tooltip title={messagePendingIncomplete ? null : (fromAssistant ? 'Copy message' : 'Copy input')} variant='solid'>*/}
{/* <IconButton*/}
{/* variant='outlined' onClick={handleOpsMessageCopySrc}*/}
{/* sx={{*/}
{/* position: 'absolute', ...(fromAssistant ? { right: { xs: 12, md: 28 } } : { left: { xs: 12, md: 28 } }), zIndex: 10,*/}
{/* opacity: 0, transition: 'opacity 0.16s cubic-bezier(.17,.84,.44,1)',*/}
{/* }}>*/}
{/* <ContentCopyIcon />*/}
{/* </IconButton>*/}
{/* </Tooltip>*/}
{/*)}*/}
{/* Message Operations Menu (3 dots) */}
@@ -929,25 +985,22 @@ export function ChatMessage(props: {
</MenuItem>
)}
{/* Copy */}
<MenuItem onClick={handleOpsCopy} sx={{ flex: 1 }}>
<MenuItem onClick={handleOpsMessageCopySrc} sx={{ flex: 1 }}>
<ListItemDecorator><ContentCopyIcon /></ListItemDecorator>
Copy
</MenuItem>
{/* Starred */}
{!!onMessageToggleUserFlag && (
<MenuItem onClick={handleOpsToggleStarred} sx={{ flexGrow: 0, px: 1 }}>
<Tooltip disableInteractive title={!isUserStarred ? 'Link message - use @ to refer to it from another chat' : 'Remove link'}>
{isUserStarred
? <AlternateEmailIcon color='primary' sx={{ fontSize: 'xl' }} />
: <InsertLinkIcon sx={{ rotate: '45deg' }} />
}
{/*{isUserStarred*/}
{/* ? <StarRoundedIcon color='primary' sx={{ fontSize: 'xl2' }} />*/}
{/* : <StarOutlineRoundedIcon sx={{ fontSize: 'xl2' }} />*/}
{/*}*/}
<Tooltip disableInteractive title={!isUserStarred ? 'Star message - use @ to refer to it from another chat' : 'Remove star'}>
<StarredState isStarred={isUserStarred} />
</Tooltip>
</MenuItem>
)}
{/* Info */}
<MenuItem onClick={handleOpsShowInfo} sx={{ flexGrow: 0, px: 1 }}>
<InfoOutlinedIcon sx={{ fontSize: 'xl' }} />
</MenuItem>
</Box>
{/* Notify Complete */}
@@ -1010,7 +1063,7 @@ export function ChatMessage(props: {
{!!props.onTextDiagram && <ListDivider />}
{!!props.onTextDiagram && (
<MenuItem onClick={handleOpsDiagram} disabled={!couldDiagram}>
<ListItemDecorator><AccountTreeOutlinedIcon /></ListItemDecorator>
<ListItemDecorator><PhTreeStructure /></ListItemDecorator>
Auto-Diagram ...
</MenuItem>
)}
@@ -1022,7 +1075,7 @@ export function ChatMessage(props: {
)}
{!!props.onTextSpeak && (
<MenuItem onClick={handleOpsSpeak} disabled={!couldSpeak || props.isSpeaking}>
<ListItemDecorator>{props.isSpeaking ? <CircularProgress size='sm' /> : <RecordVoiceOverOutlinedIcon />}</ListItemDecorator>
<ListItemDecorator>{props.isSpeaking ? <CircularProgress size='sm' /> : <PhVoice />}</ListItemDecorator>
Speak
</MenuItem>
)}
@@ -1140,7 +1193,7 @@ export function ChatMessage(props: {
{/* Intelligent functions */}
{!!props.onTextDiagram && <Tooltip disableInteractive arrow placement='top' title={couldDiagram ? 'Auto-Diagram...' : 'Too short to Auto-Diagram'}>
<IconButton color='success' onClick={couldDiagram ? handleOpsDiagram : undefined}>
<AccountTreeOutlinedIcon sx={{ color: couldDiagram ? 'primary' : 'neutral.plainDisabledColor' }} />
<PhTreeStructure sx={{ color: couldDiagram ? 'primary' : 'neutral.plainDisabledColor' }} />
</IconButton>
</Tooltip>}
{!!props.onTextImagine && <Tooltip disableInteractive arrow placement='top' title='Auto-Draw'>
@@ -1150,18 +1203,26 @@ export function ChatMessage(props: {
</Tooltip>}
{!!props.onTextSpeak && <Tooltip disableInteractive arrow placement='top' title='Speak'>
<IconButton color='success' onClick={handleOpsSpeak} disabled={!couldSpeak || props.isSpeaking}>
{!props.isSpeaking ? <RecordVoiceOverOutlinedIcon /> : <CircularProgress sx={{ '--CircularProgress-size': '16px' }} />}
{!props.isSpeaking ? <PhVoice /> : <CircularProgress sx={{ '--CircularProgress-size': '16px' }} />}
</IconButton>
</Tooltip>}
{(!!props.onTextDiagram || !!props.onTextImagine || !!props.onTextSpeak) && <Divider />}
{/* Bubble Copy */}
<Tooltip disableInteractive arrow placement='top' title='Copy Selection'>
<IconButton onClick={handleOpsCopy}>
<IconButton onClick={handleBubbleCopyDOM}>
<ContentCopyIcon />
</IconButton>
</Tooltip>
{/* Selection char & word count */}
{!!selText && <Divider />}
{!!selText && (
<Typography level='body-xs' sx={{ px: 1, whiteSpace: 'nowrap' }}>
{selText.length.toLocaleString()}c · {(selText.match(/\S+/g) || []).length.toLocaleString()}w
</Typography>
)}
</ButtonGroup>
</ClickAwayListener>
</Popper>
@@ -1176,13 +1237,13 @@ export function ChatMessage(props: {
minWidth={220}
placement='bottom-start'
>
<MenuItem onClick={handleOpsCopy} sx={{ flex: 1, alignItems: 'center' }}>
<MenuItem onClick={(e) => { handleOpsMessageCopySrc(e); closeContextMenu(); }} sx={{ flex: 1, alignItems: 'center' }}>
<ListItemDecorator><ContentCopyIcon /></ListItemDecorator>
Copy
</MenuItem>
{!!props.onTextDiagram && <ListDivider />}
{!!props.onTextDiagram && <MenuItem onClick={handleOpsDiagram} disabled={!couldDiagram || props.isImagining}>
<ListItemDecorator><AccountTreeOutlinedIcon /></ListItemDecorator>
<ListItemDecorator><PhTreeStructure /></ListItemDecorator>
Auto-Diagram ...
</MenuItem>}
{!!props.onTextImagine && <MenuItem onClick={handleOpsImagine} disabled={!couldImagine || props.isImagining}>
@@ -1190,12 +1251,22 @@ export function ChatMessage(props: {
Auto-Draw
</MenuItem>}
{!!props.onTextSpeak && <MenuItem onClick={handleOpsSpeak} disabled={!couldSpeak || props.isSpeaking}>
<ListItemDecorator>{props.isSpeaking ? <CircularProgress size='sm' /> : <RecordVoiceOverOutlinedIcon />}</ListItemDecorator>
<ListItemDecorator>{props.isSpeaking ? <CircularProgress size='sm' /> : <PhVoice />}</ListItemDecorator>
Speak
</MenuItem>}
</CloseablePopup>
)}
{/* Message Info Modal */}
{showInfoModal && (
<ChatMessageInfoPopup
open
onClose={handleInfoClose}
message={props.message}
/>
)}
</Box>
);
}
@@ -0,0 +1,155 @@
import * as React from 'react';
import type { SxProps } from '@mui/joy/styles/types';
import { Sheet } from '@mui/joy';
import { useBrowseCapability } from '~/modules/browse/store-module-browsing';
import type { AttachmentDraftsStoreApi } from '~/common/attachment-drafts/store-attachment-drafts_slice';
import type { DMessageAttachmentFragment } from '~/common/stores/chat/chat.fragments';
import { AttachmentDraftsList } from '~/common/attachment-drafts/attachment-drafts-ui/AttachmentDraftsList';
import { AttachmentSourcesMemo } from '~/common/attachment-drafts/attachment-sources/AttachmentSources';
import { useAttachHandler_CameraOpen, useAttachHandler_Files, useAttachHandler_ScreenCapture, useAttachHandler_UrlWebLinks } from '~/common/attachment-drafts/attachment-sources/useAttachmentSourceHandlers';
import { createAttachmentDraftsVanillaStore } from '~/common/attachment-drafts/store-attachment-drafts_vanilla';
import { supportsCameraCapture } from '~/common/components/camera/useCameraCapture';
import { supportsScreenCapture } from '~/common/util/screenCaptureUtils';
import { useAttachmentDrafts } from '~/common/attachment-drafts/useAttachmentDrafts';
import { useGoogleDrivePicker } from '~/common/attachment-drafts/attachment-sources/useGoogleDrivePicker';
import { ViewDocPartModal } from './fragments-content/ViewDocPartModal';
import { ViewImageRefPartModal } from './fragments-content/ViewImageRefPartModal';
/**
* Imperative interface used outside
*/
export interface EditModeAttachmentsHandle {
takeAllFragments: () => Promise<DMessageAttachmentFragment[]>;
}
const _styles = {
box: {
overflow: 'hidden',
p: 0.5,
// looks - exactly from BoxTextArea - the Text editor
boxShadow: 'inset 1px 0px 3px -2px var(--joy-palette-warning-softColor)',
outline: '1px solid',
outlineColor: 'var(--joy-palette-warning-solidBg)',
borderRadius: 'sm',
// layout
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
gap: 1,
// shade to the buttons inside this > div > div > button
'& > div > div > button': {
// backgroundColor: 'warning.softActiveBg',
borderColor: 'warning.outlinedBorder',
borderRadius: 'sm',
boxShadow: 'sm',
},
},
} as const satisfies Record<string, SxProps>;
/**
* Encapsulates all attachment wiring for ChatMessage edit mode.
* Owns a standalone attachment drafts store (one per edit session).
* Exposes an imperative handle for the parent to "take" fragments on save.
*/
export const ChatMessageEditAttachments = React.forwardRef<EditModeAttachmentsHandle, { isMobile: boolean }>(
function EditModeAttachments(props, ref) {
// state
const storeApiRef = React.useRef<AttachmentDraftsStoreApi | null>(null);
if (!storeApiRef.current) storeApiRef.current = createAttachmentDraftsVanillaStore(); // created only on mount
// external state
const {
attachmentDrafts,
attachAppendClipboardItems, attachAppendCloudFile, attachAppendFile, attachAppendUrl, // attachAppendDataTransfer
attachmentsTakeAllFragments,
} = useAttachmentDrafts(storeApiRef.current, false, false, undefined, false);
const browseCapability = useBrowseCapability();
// imperative handle for parent to take fragments on save
React.useImperativeHandle(ref, () => ({
takeAllFragments: () => attachmentsTakeAllFragments('global', 'app-chat'),
}), [attachmentsTakeAllFragments]);
// [effect] cleanup on unmount - remove all drafts (deleted their DBlob assets, except for 'taken' ones)
React.useEffect(() => {
const store = storeApiRef.current;
return () => {
store?.getState().removeAllAttachmentDrafts();
};
}, []);
// handlers - composed from shared attachment source hooks
const handleAttachFiles = useAttachHandler_Files(attachAppendFile);
const handleOpenCamera = useAttachHandler_CameraOpen(attachAppendFile);
const handleAttachScreenCapture = useAttachHandler_ScreenCapture(attachAppendFile);
const { openWebInputDialog, webInputDialogComponent } = useAttachHandler_UrlWebLinks(attachAppendUrl);
const { openGoogleDrivePicker, googleDrivePickerComponent } = useGoogleDrivePicker(attachAppendCloudFile, props.isMobile);
// viewer render props - same pattern as ComposerAttachmentDraftsList.tsx:44-52
const renderDocViewer = React.useCallback(
(part: React.ComponentProps<typeof ViewDocPartModal>['docPart'], onClose: () => void) =>
<ViewDocPartModal docPart={part} onClose={onClose} />,
[],
);
const renderImageViewer = React.useCallback(
(part: React.ComponentProps<typeof ViewImageRefPartModal>['imageRefPart'], onClose: () => void) =>
<ViewImageRefPartModal imageRefPart={part} onClose={onClose} />,
[],
);
return <>
<Sheet color='warning' variant='soft' sx={_styles.box}>
{/* [+] Attachment Sources menu */}
<AttachmentSourcesMemo
mode='menu-message'
canBrowse={browseCapability.mayWork}
hasScreenCapture={supportsScreenCapture}
hasCamera={supportsCameraCapture()}
// onlyImages={showAttachOnlyImages}
onAttachClipboard={attachAppendClipboardItems}
onAttachFiles={handleAttachFiles}
onAttachScreenCapture={handleAttachScreenCapture}
onOpenCamera={handleOpenCamera}
onOpenGoogleDrivePicker={openGoogleDrivePicker}
onOpenWebInput={openWebInputDialog}
/>
{/* Attachment Drafts list */}
{attachmentDrafts.length > 0 ? (
<AttachmentDraftsList
attachmentDraftsStoreApi={storeApiRef.current!}
attachmentDrafts={attachmentDrafts}
buttonsCanWrap
renderDocViewer={renderDocViewer}
renderImageViewer={renderImageViewer}
/>
) : null}
</Sheet>
{/* Modal portals */}
{webInputDialogComponent}
{googleDrivePickerComponent}
</>;
},
);
@@ -0,0 +1,104 @@
import * as React from 'react';
import TimeAgo from 'react-timeago';
import type { SxProps } from '@mui/joy/styles/types';
import { Box } from '@mui/joy';
import { llmsGetVendorIcon } from '~/modules/llms/components/LLMVendorIcon';
import type { DMessage } from '~/common/stores/chat/chat.message';
import type { Immutable } from '~/common/types/immutable.types';
import { GoodModal } from '~/common/components/modals/GoodModal';
import { tooltipMetricsGridSx, prettyMessageMetrics, prettyShortChatModelName, prettyTokenStopReason } from '~/common/util/dMessageUtils';
const contentSx: SxProps = {
fontSize: 'sm',
display: 'grid',
gap: 1.5,
};
const vendorIconContainerSx: SxProps = {
display: 'flex',
alignItems: 'center',
gap: 1,
};
const timestampSx: SxProps = {
fontSize: 'xs',
color: 'text.tertiary',
};
export function ChatMessageInfoPopup(props: {
open: boolean,
onClose: () => void,
message: Immutable<DMessage>,
}) {
const { message } = props;
const { generator, created, updated, tokenCount, role } = message;
const isAix = generator?.mgt === 'aix';
const vendorId = isAix ? generator.aix?.vId ?? null : null;
const VendorIcon = vendorId ? llmsGetVendorIcon(vendorId) : null;
const metrics = generator?.metrics ? prettyMessageMetrics(generator.metrics, 'extra') : null;
const stopReason = generator?.tokenStopReason ? prettyTokenStopReason(generator.tokenStopReason, 'extra') : null;
return (
<GoodModal
open={props.open}
onClose={props.onClose}
title='Message Info'
hideBottomClose
sx={{ minWidth: { xs: 300, sm: 400 }, maxWidth: 480 }}
>
<Box sx={contentSx}>
{/* Model / Generator */}
{generator && (
<Box sx={tooltipMetricsGridSx}>
<div>Model:</div>
<div>
{VendorIcon
? <Box sx={vendorIconContainerSx}><VendorIcon />{prettyShortChatModelName(generator.name)}</Box>
: prettyShortChatModelName(generator.name)}
</div>
{isAix && generator.aix?.mId && <>
<div>ID:</div>
<div style={{ opacity: 0.75 }}>{generator.aix.mId}</div>
</>}
{generator.providerInfraLabel && <>
<div>Provider:</div>
<div>{generator.providerInfraLabel}</div>
</>}
{stopReason && <>
<div>Status:</div>
<div>{stopReason}</div>
</>}
</Box>
)}
{/* Metrics (tokens, speed, cost, time) */}
{metrics}
{/* Message metadata */}
<Box sx={tooltipMetricsGridSx}>
<div>Role:</div>
<div>{role}</div>
{tokenCount > 0 && <>
<div>Tokens:</div>
<div>{tokenCount.toLocaleString()} (visible text ~approx)</div>
</>}
</Box>
{/* Timestamps */}
<Box sx={timestampSx}>
{!!created && <div>Created <TimeAgo date={created} /> - {new Date(created).toLocaleString()}</div>}
{!!updated && <div>Updated <TimeAgo date={updated} /> - {new Date(updated).toLocaleString()}</div>}
</Box>
</Box>
</GoodModal>
);
}
@@ -5,13 +5,13 @@ import AttachFileRoundedIcon from '@mui/icons-material/AttachFileRounded';
import ClearIcon from '@mui/icons-material/Clear';
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
import ErrorIcon from '@mui/icons-material/ErrorRounded';
import ImageIcon from '@mui/icons-material/ImageRounded';
import TextFieldsIcon from '@mui/icons-material/TextFieldsRounded';
import VisibilityIcon from '@mui/icons-material/Visibility';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import { DMessage, MESSAGE_FLAG_AIX_SKIP, messageFragmentsReduceText, messageHasUserFlag } from '~/common/stores/chat/chat.message';
import { DMessageAttachmentFragment, DMessageFragment, isAttachmentFragment, isContentFragment, isImageRefPart, isZyncAssetImageReferencePart } from '~/common/stores/chat/chat.fragments';
import { PhImageSquare } from '~/common/components/icons/phosphor/PhImageSquare';
import { makeMessageAvatarIcon, messageBackground } from '~/common/util/dMessageUtils';
import { TokenBadgeMemo } from '../composer/tokens/TokenBadge';
@@ -273,7 +273,7 @@ export function CleanerMessage(props: { message: DMessage, selected: boolean, re
</Chip>
)}
{analysis.imageCount > 0 && (
<Chip size='sm' variant='solid' color='success' startDecorator={<ImageIcon />} sx={{ px: 1 }}>
<Chip size='sm' variant='solid' color='success' startDecorator={<PhImageSquare />} sx={{ px: 1 }}>
{analysis.imageCount} image{analysis.imageCount > 1 ? 's' : ''}
</Chip>
)}

Some files were not shown because too many files have changed in this diff Show More