You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Feat: customizable system prompts (personal preferences) (#240)
## Description
### PR Objective
This Pull Request adds customizable system prompts to the chat: users
write global personal preferences (e.g., "be concise", "answer in
Polish", "avoid jargon") that silently shape every conversation — the
model follows them without ever quoting, acknowledging, or parroting
them back.
Resolves **#230**.
---
### What changed?
#### Custom System Prompt
* **Persisted setting** (`store/settingsStore.ts`): A global
`customSystemPrompt` stored via Zustand + persist on AsyncStorage.
* **Guard & injection** (`utils/promptUtils.ts`,
`constants/prompts.ts`): `CUSTOM_PROMPT_GUARD` is prepended to the
user's preference and appended to the system prompt during message
assembly (`store/llmStore.ts`). Empty/whitespace-only preferences are
skipped entirely — neither prompt nor guard is added.
* **Soft token budget** (`constants/settings.ts`): Character cap derived
from a ~256-token × ~4 chars/token approximation, so the preference
can't eat the on-device context — validated on the trimmed value.
#### Settings, Reworked
* **Settings is now a drawer screen** (`app/(drawer)/settings.tsx`,
`app/(drawer)/_layout.tsx`) — a proper destination like Models,
navigated via `replace`, instead of a full-screen modal.
* **Sub-pages as card-push screens** with `ios_from_right`
(`app/_layout.tsx`): The Personal preferences editor
(`app/(modals)/custom-system-prompt.tsx`) and App info.
* **App info moved out of the drawer** into Settings
(`components/drawer/DrawerMenu.tsx`), alongside Personal preferences via
a shared `SettingsRow` (`components/settings/SettingsRow.tsx`).
* **Drawer active-item logic fixed**: Drawer destinations use `replace`
+ path-equality highlighting; modal actions no longer show a stale
active state.
#### Input Error State
* **Animated border** (`components/TextInputBorder.tsx`): Crossfades
between inactive / active / error states via opacity (native driver),
with error taking precedence over active.
* **TextAreaField gains error state** (`components/TextAreaField.tsx`):
Added `error?: boolean` + `errorMessage?: string` props. Renders a red
border and an inline message only when set — no layout change otherwise.
The preferences editor uses it to flag the over-limit case.
#### Chore
* **Deprecation cleanup**: Replaced `StyleSheet.absoluteFillObject` (RN
0.83 `@deprecated`) with `StyleSheet.absoluteFill` across 4 components —
same frozen object, no behavior change.
0 commit comments