Commit Graph
1742 Commits
Author SHA1 Message Date
NJX 6a50da8e82 feat(stage-ui): added AbortController for inference utils (#1682) 2026-04-24 23:42:55 +08:00
NJXandCopilot d85709f900 feat(stage-ui): webgpu detect improved (#1681)
---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-24 23:33:09 +08:00
NJXandautofix-ci[bot] f7ac65289a feat(stage-ui): should handle WebGPU device-loss (#1680)
---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-24 23:30:58 +08:00
Richard Pinedo 4e6da5ef04 feat(stage-*): port artistry & chatbox enhancements (#1636)
Co-authored-by-agent: Unknown <unknown@example.com>
2026-04-24 23:25:04 +08:00
Neko Ayaka 47074021c0 chore(deps): updated eventa 2026-04-24 04:12:25 +08:00
Lilia_Chen 6a61248cd4 refactor(stage-tamagotchi-godot): move to engines dir (#1715) 2026-04-23 19:30:53 +08:00
chaosreloadandautofix-ci[bot] a189536489 feat(providers): add Amazon Bedrock provider (#1256)
## Summary

Add support for Amazon Bedrock as an LLM provider using the native
**Converse API** with API Key authentication.

## Motivation

AWS Bedrock provides access to frontier models (Claude, Amazon Nova,
Llama, DeepSeek etc.) with enterprise-grade security and compliance.
Many teams running AI workloads on AWS infrastructure want to use
Bedrock directly, keeping all traffic within the AWS network.

## Implementation

- Uses Amazon Bedrock's native **Converse API**
(`bedrock-runtime.{region}.amazonaws.com/model/{modelId}/converse`)
- Authentication via **Amazon Bedrock API Key** (`Authorization: Bearer
<key>`) — no SigV4 signing, no extra dependencies
- Config: `apiKey` (Bedrock API key) + `region` (AWS region, default:
`us-east-1`)
- All Bedrock-specific config is declared via the generic
`onboardingFields` mechanism on the provider definition — no
`isAmazonBedrock` branching, no `ProviderConfigData` type changes
- Dynamic model listing via `ListFoundationModels` +
`ListInferenceProfiles` APIs, with fallback to a static list
- Streaming: calls `/converse` (standard JSON response), then re-emits
the full text as `text/event-stream` character-by-character —
bearer-token auth does not support the binary AWS Event Stream protocol
required by `/converse-stream`

## Supported Models

**Anthropic Claude (via Bedrock)**
- Claude Opus/Sonnet/Haiku 4.x
- Claude Sonnet 3.7 (hybrid reasoning)
- Claude Sonnet 3.5 v2

**Amazon Nova**
- Nova Pro (multimodal)
- Nova Lite (multimodal, low cost)
- Nova Micro (text-only, lowest cost)

**Meta / Others**
- Llama 3.3 70B Instruct
- DeepSeek, Moonshot, Minimax models available via inference profiles

## Authentication

Generate a Bedrock API key in: **AWS Console → Amazon Bedrock → API
Keys**

> Note: Long-term API keys have a 30-day expiry. AWS recommends them for
development/exploration use.

## Notes

⚠️ **CORS in browser**: Like other providers (Anthropic, etc.), direct
browser calls to Bedrock are subject to CORS restrictions. Works out of
the box in Tauri desktop app and Node.js server environments. For
browser use, a CORS proxy is needed.

## Testing

```
pnpm vitest run packages/stage-ui/src/libs/providers/providers/amazon-bedrock/index.test.ts
```

---------
Co-authored-by-agent: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-22 17:37:29 +00:00
Neko Ayaka a3249ccd68 feat(stage-tamagotchi,stage-ui,ui): input should not flink, added retry for errored item, adjusted button 2026-04-23 01:09:46 +08:00
Neko Ayaka ee86608195 fix(stage-ui): overflow chat bubble 2026-04-23 01:09:45 +08:00
567fd6666e feat(stage-tamagotchi-godot): initiation of Godot stage (#1697)
## Description

This PR introduces `@proj-airi/stage-tamagotchi-godot` as the initial
Godot C# workspace package for the desktop-only `stage-tamagotchi` stage
runtime track.

The current scope is intentionally limited to G0 bootstrap work:
- add the Godot/.NET project files and workspace wrapper files
- establish the package boundary for the Godot-backed desktop stage
runtime
- add a minimal runnable scene and script so the Godot project can be
opened, built, and executed inside the repo

Concretely, this PR adds:
- the new `packages/stage-tamagotchi-godot` package
- Godot project files (`project.godot`, `.csproj`, `.sln`, editor/config
files)
- a minimal `stage-root` scene and `StageRoot.cs` script
- basic visible scene contents for runtime validation (`Camera3D`,
`OmniLight3D`, `Box`)
- a package README describing scope and ownership boundaries
- minimal package scripts for build/typecheck via `dotnet build`

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: LemonNeko <self@lemonneko.moe>
Co-authored-by: Garfield Lee <Garfield550@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Neko <neko@ayaka.moe>
2026-04-23 01:04:01 +08:00
0xSelenicDove c259cec35f feat(pipelines-audio): Universal Speech Transformer port with CJK & keep-text support (#1702) 2026-04-22 02:48:41 -07:00
Neko Ayaka 94031bf1c4 fix(stage-ui,ui): histoire wasn't configured correctly 2026-04-22 16:57:35 +08:00
Neko Ayaka ca4c99f074 fix(stage-pages,stage-ui): plugin host update 2026-04-22 14:23:45 +08:00
Neko Ayaka c7cf0c6a47 fix(stage-pages,stage-shared,stage-ui): rollback 3f82942 falsy fix 2026-04-22 14:14:02 +08:00
DrHuangMHT 32d2ebfe73 fix(stage-ui): use duckdb singleton to prevent memory leak (#1679) 2026-04-22 14:03:57 +08:00
Iro 3f829421d3 fix(server-runtime): enforce auth & routing safety, fix lifecycle leaks (#1686) 2026-04-22 14:03:16 +08:00
Neko Ayaka 36ee517e1e chore(README.md): updated for more instructions 2026-04-22 13:54:02 +08:00
Neko Ayaka 509c00d9a5 feat(plugin-sdk,stage-tamagotchi): rework of plugin structure, integrated kits api, now plugin manifest is plugin.airi.json 2026-04-22 13:52:11 +08:00
Neko Ayaka ea2b30e2b8 fix(stage-ui): outdated for mcp.ts 2026-04-22 03:37:58 +08:00
Neko Ayaka 5bbf9559a4 refactor(stage-ui,stage-tamagotchi): have plugin-tools, mcp-tools to register directly to llm.ts 2026-04-22 03:34:40 +08:00
DrHuangMHT 7e4486c068 chore(ci): fix typecheck on navigator.gpu (#1700) 2026-04-21 20:27:17 +08:00
Neko Ayaka 3390122085 feat(plugin-sdk-tamagotchi,airi-plugin-game-chess): tools api, gamelet api, init chess gamelet 2026-04-21 17:17:20 +08:00
Neko Ayaka 0294dad6ef feat(plugin-sdk): kits api, binding api, and better comments 2026-04-21 16:46:04 +08:00
Neko Ayaka 60456c7567 fix(ui): SelectTab size issue 2026-04-18 19:27:02 +08:00
Neko Ayaka 2ab21879dd chore(deps): bump dependencies 2026-04-18 19:18:17 +08:00
Luluandautofix-ci[bot] a40cbd67cf fix(stage-layouts): mount LoginDrawer in settings layout on mobile (#1675)
---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by-agent: Cursor <unknown@example.com>
2026-04-18 18:26:19 +08:00
github-actions[bot]andCrowdin Bot 2a444245ae chore(i18n): update translations (#1678)
This PR contains updated translations from Crowdin. Created from [GitHub
Actions](https://github.com/moeru-ai/airi/blob/main/.github/workflows/crowdin-cron-sync.yml).

You can review the source of translations
[here](https://crowdin.com/project/proj-airi)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-04-18 18:20:48 +08:00
Neko Ayaka 70495439ad refactor(core-agent,stage-ui): move spark-notify agent to core-agent 2026-04-17 16:18:42 +08:00
github-actions[bot]andCrowdin Bot 8d6905481b chore(i18n): update translations (#1672)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-04-17 15:09:06 +08:00
RainbowBird bef1598179 fix(stage-ui): refresh token concurrency 2026-04-17 02:59:14 +08:00
RainbowBird 8967bbe211 feat(server): add TTS support with per-character billing 2026-04-17 02:59:14 +08:00
Jensen Huang c14e9547d9 feat(stage-tamagotchi): improve updater cleanup lane and admin diagnostics 2026-04-16 22:58:10 +08:00
NJX 5187572c42 fix(stage-ui/inference): correctness and resilience fixes for browser-side inference infra (#1663)
## Summary

Addresses **Phase 1** of the inference infrastructure roadmap (#1661).
Six correctness and resilience issues fixed across adapters, workers,
and the unified protocol layer.

**Scope:** `packages/stage-ui/src/libs/inference/`,
`packages/stage-ui/src/libs/workers/`, `packages/stage-ui/src/workers/`

---

## Problems & Motivation

### 1. Kokoro Singleton cannot recover from terminal state

`getKokoroAdapter()` creates a singleton that is never reset. Once the
adapter reaches `terminated` or `error` (restarts exhausted), the
singleton is permanently dead -- users must refresh the page.

**Root cause:** `globalAdapter` is only re-created when `null`, never
checks the state of the existing instance. `scheduleRestart()` silently
returns when retries are exhausted, leaving state stuck at `'error'`
instead of transitioning to `'terminated'`.

**Fix:**
- `getKokoroAdapter()` now detects `terminated` / `error` states and
re-creates the adapter automatically
- `scheduleRestart()` in both Kokoro and Whisper adapters transitions to
`'terminated'` when max restarts are exhausted, making the dead state
detectable

### 2. `voices!` non-null assertion after nullable assignment

`kokoro.ts:275` assigns `voices = (response.metadata?.voices as Voices)
?? null` (can be null), but L288 returns `voices!` -- if the worker
returns unexpected metadata, callers receive `null` but the type system
promises `Voices`, causing downstream crashes.

**Fix:** Replaced with explicit null check + throw, routing into the
existing error recovery path.

### 3. Whisper Worker silently drops concurrent requests

The worker's `runInference()` has `if (processing) return` which
silently drops the request. The adapter's `waitForMessage()` never
receives a response, causing the Promise to hang for 120 seconds until
timeout.

**Root cause:** The bare boolean is safe in a single-threaded worker --
the real bug is the silent `return` with no error response.

**Fix:** Replaced with `sendError(requestId, ...)` so the adapter
receives an immediate rejection.

### 4. Whisper adapter leaks event listeners on worker restart

`ensureWorker()` attaches anonymous `message` and `error` listeners each
time a new Worker is created. `destroyWorker()` only calls
`worker.terminate()` without removing listeners. On restart paths
(`scheduleRestart -> ensureWorker`), old Worker listener closures may
prevent GC.

**Impact:** Whisper is most critical (2 listeners + restart logic).
Kokoro and Background Removal have the same pattern but lower risk.

**Fix:** All 3 adapters now store listener references and call
`removeEventListener` before `terminate()`. Whisper's
`terminateAdapter()` routes through `destroyWorker()` instead of direct
`worker.terminate()`.

### 5. Error classification is incomplete

`classifyError()` only matches 3 string patterns (OOM, DEVICE_LOST,
TIMEOUT). `LOAD_FAILED` and `INFERENCE_FAILED` are defined in the
`InferenceErrorCode` type but never produced. All workers hardcode
`recoverable: false`.

**Fix:**
- `classifyError(error, phase?)` gains a `phase` parameter: specific
patterns (OOM etc.) take priority, unmatched errors fall through to
`LOAD_FAILED` / `INFERENCE_FAILED` based on phase
- New `isRecoverable(code)` helper: TIMEOUT and DEVICE_LOST are
recoverable
- All 3 workers' `sendError()` updated to pass phase and use dynamic
recoverability

### 6. No dtype/device fallback chain

Kokoro Worker attempts model loading once with the requested dtype;
failure is terminal. Whisper Worker hardcodes `encoder_model: 'fp16'`
which crashes on devices that don't support it.

**Fix:**
- **Kokoro Worker:** New `DTYPE_FALLBACK` and `DEVICE_FALLBACK` maps.
Tries `fp16 -> fp32 -> q8 -> q4` on the same device, then `webgpu ->
wasm` device fallback. Reports `actualDtype` and `actualDevice` in
`ModelReadyResponse.metadata`
- **Whisper Worker:** Wraps fp16 encoder load in try-catch; falls back
to fp32

---

## State after changes

| Component | Before | After |
|-----------|--------|-------|
| Kokoro singleton | Returns dead instance forever after terminal error
| Auto-detects and re-creates |
| `voices` return | `voices!` can return null, lying to type system |
Explicit throw, enters error recovery path |
| Whisper Worker concurrency | Silent drop, Promise hangs 120s |
Immediate error response |
| Event listeners | Anonymous, never cleaned up | Stored references,
removeEventListener on destroy |
| Error classification | 4/6 codes reachable, recoverable hardcoded
false | 6/6 codes reachable, dynamic recoverability |
| dtype loading | Single attempt, failure is terminal | Progressive
fallback chain, reports actual config used |

---

## Files changed

| File | Changes |
|------|---------|
| `libs/inference/protocol.ts` | `classifyError` phase param, new
`isRecoverable` helper |
| `libs/inference/protocol.test.ts` | **New** -- 14 tests for
classification and recoverability |
| `libs/workers/worker.ts` | Silent drop fix, sendError phase, fp16
fallback |
| `workers/kokoro/worker.ts` | sendError phase, dtype/device fallback
chain |
| `workers/background-removal/worker.ts` | sendError phase |
| `libs/inference/adapters/whisper.ts` | Listener cleanup,
terminateAdapter uses destroyWorker, scheduleRestart terminal state |
| `libs/inference/adapters/kokoro.ts` | Singleton recovery, voices
assertion fix, listener cleanup, scheduleRestart terminal state |
| `libs/inference/adapters/kokoro.test.ts` | **New** -- 5 tests for
singleton and state transitions |
| `libs/inference/adapters/background-removal.ts` | Listener cleanup,
extracted destroyWorker |

## Test plan

- [x] `pnpm exec vitest run packages/stage-ui/src/libs/inference/` --
30/30 tests pass (protocol, kokoro adapter, GPU coordinator, load queue)
- [x] `pnpm -F @proj-airi/stage-ui typecheck` -- clean
- [x] `npx eslint` on all 9 changed files -- clean
- [x] Pre-commit hooks pass

Co-authored-by-agent: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:11:05 +08:00
Nashchenncandautofix-ci[bot] bf41655dbb feat(core-agent): extract pure runtime logic from stage-ui into core-agent (#1524)
Depends on #1487 

## Summary

- Introduce `packages/core-agent` — a new pure-runtime package that
extracts zero-Vue/Pinia algorithmic logic from `@proj-airi/stage-ui`,
following a "compatible facade + core sinking" strategy
- Migrate shared chat types, LLM streaming types, chat hook registry,
session message merge logic, context registry algorithm, and LLM service
utilities into `core-agent`
- `stage-ui` files are preserved as re-exports / thin wrappers — all
external imports, store IDs, and public APIs remain unchanged

## Motivation

`stage-ui` currently mixes pure agent runtime logic (algorithms, type
definitions, stateless utilities) with Vue/Pinia state management and
browser-specific adapters. This coupling makes it hard to:
- Test agent logic in isolation
- Reuse agent algorithms outside of Vue contexts (e.g., server-side,
CLI, other frameworks)
- Reason about the boundary between "what the agent does" vs "how the UI
manages state"

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by-agent: Unknown <unknown@example.com>
2026-04-16 16:09:22 +08:00
Octopus 11ac511dd9 feat(stage-ui,i18n): add MiniMax Speech TTS provider (#1594)
## Summary

- Add `minimax-speech` TTS provider using MiniMax's T2A v2 API
- Implement streaming SSE response with hex-encoded audio decoding (no
external dependency required)
- Include a curated static voice list (English and Mandarin voices)
- Add `speech-2.8-hd` (default) and `speech-2.8-turbo` model entries
- Support configurable base URL defaulting to `https://api.minimax.io`
- Add i18n translations for all 9 supported locales

Closes #1274

## Implementation Details

The provider uses a custom `fetch` interceptor within the
`SpeechProvider` interface to:
1. Parse the incoming OpenAI-style request (`input`, `voice`, `model`)
2. Call MiniMax's `/v1/t2a_v2` SSE streaming endpoint
3. Decode hex-encoded audio chunks from SSE events (skipping the summary
chunk with `status=2`)
4. Return a concatenated `audio/mpeg` response

## API Reference

- TTS: https://platform.minimax.io/docs/api-reference/speech-t2a-http
2026-04-16 16:07:30 +08:00
github-actions[bot]andCrowdin Bot b867980087 chore(i18n): update translations (#1669)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-04-16 15:59:40 +08:00
Makito 186a70fbc7 fix(stage-pages): replace with vueuse utilities 2026-04-16 01:35:14 +09:00
DrHuangMHT 9d5c9e9332 chore(deps): remove deprecated unplugin-vue-router (#1664) 2026-04-15 15:02:10 +08:00
akrlin e75b6618b3 fix(stage-ui,i18n) fix a bug when change language (#1666) 2026-04-15 14:47:26 +08:00
Neko Ayaka b9f88ef84f style: lint 2026-04-15 14:44:59 +08:00
Neko Ayaka f286464e03 chore(deps): bump dependencies 2026-04-15 14:44:59 +08:00
github-actions[bot]andCrowdin Bot fff6560e2d chore(i18n): update translations (#1665)
This PR contains updated translations from Crowdin. Created from [GitHub
Actions](https://github.com/moeru-ai/airi/blob/main/.github/workflows/crowdin-cron-sync.yml).

You can review the source of translations
[here](https://crowdin.com/project/proj-airi)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-04-15 11:15:08 +08:00
Neko Ayaka f7a9a7bf76 refactor(vishot-*,scenarios-*): better structure, better api, and markup components 2026-04-15 04:51:00 +08:00
Makito bcd89786a0 fix(stage-pages,stage-shared,stage-ui): auto fit IO tracer 2026-04-15 02:56:04 +09:00
Makito a620c2395b feat(stage-tamagotchi,i18n,stage-pages): localize IO Tracer title and update route metadata 2026-04-15 02:17:10 +09:00
Makito b0b48840ec feat(stage-tamagotchi,stage-pages): initialize IO trace viewer 2026-04-15 02:17:10 +09:00
Makito dbe85583bf feat(stage-pages,stage-shared,stage-ui): better OTel identifiers 2026-04-15 02:17:09 +09:00
Makito 7d544d03a1 feat(stage-shared,stage-ui): add store and integrations for IO tracer 2026-04-15 02:17:09 +09:00
0c3655ee8d refactor(inference): replace custom AsyncMutex with async-mutex package (#1660)
## Summary

Address maintainer feedback from #1622 ([@nekomeowww's
comment](https://github.com/moeru-ai/airi/pull/1622#discussion_r2342632282)).

The project already uses `async-mutex` in other packages
(`stage-tamagotchi`, `electron-screen-capture`), and it's in the
workspace catalog. This replaces the custom `AsyncMutex` implementation
with the shared dependency.

- Replace `AsyncMutex.run()` → `Mutex.runExclusive()`
- Replace `AsyncMutex.reset()` → `Mutex.cancel()`
- Remove `async-mutex.ts` and its unit tests
- Remove `AsyncMutex` from inference barrel exports
- Add `async-mutex` as direct dependency of `@proj-airi/stage-ui`

**Regarding `@moeru/eventa` suggestion**
([comment](https://github.com/moeru-ai/airi/pull/1622#discussion_r2342631692)):
The `waitForMessage` pattern is a thin request-response abstraction over
`postMessage`, where the worker is driven by `@huggingface/transformers`
internally. Eventa's transport-agnostic RPC is better suited for
bidirectional channels (Electron IPC, WebSocket) than for this one-way
"post and wait" pattern. No change for now.

## Test plan

- [x] `pnpm exec vitest run packages/stage-ui/src/libs/inference/` — 11
tests pass (4 removed with custom impl)
- [x] `pnpm -F @proj-airi/stage-ui typecheck` — no errors
- [x] `pnpm lint:fix` — no new errors in changed files

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-04-14 11:47:33 +08:00
github-actions[bot]andCrowdin Bot 803442f5d8 chore(i18n): update translations (#1659)
This PR contains updated translations from Crowdin. Created from [GitHub
Actions](https://github.com/moeru-ai/airi/blob/main/.github/workflows/crowdin-cron-sync.yml).

You can review the source of translations
[here](https://crowdin.com/project/proj-airi)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-04-14 10:07:31 +08:00