Commit Graph
55 Commits
Author SHA1 Message Date
Oneflyandqin-ctx 0fc2a2cb46 fix(web-studio): normalize service worker scope (#3963)
* fix(web-studio): normalize service worker scope

* test(web-studio): remove service worker unit tests

---------

Co-authored-by: qin-ctx <qinhaojie.exe@bytedance.com>
2026-08-13 14:26:20 +08:00
yufeng c54f724da2 feat(web-studio): improve resource import options (#3940)
* feat(web-studio): improve resource import options

* fix(web-studio): harden resource import flows

* fix(web-studio): harden resource import mode transitions

* docs(web-studio): remove resource import research notes

* fix(web-studio): address resource import review findings

* fix(web-studio): align resource import options with server

* fix(web-studio): expose unsupported TOS watch option

* refactor(web-studio): defer resource validation to server

* refactor(web-studio): centralize resource import requests

* fix(web-studio): 保留资源导入解析模式

* fix(web-studio): hide unfinished TOS import entry
2026-08-12 11:54:27 +08:00
yufeng cc5ba899d5 feat(web-studio): group skills by scope (#3931)
* feat(web-studio): 按作用域分组展示技能

* fix(web-studio): 完善技能详情交互
2026-08-11 18:09:57 +08:00
yufeng 668637f344 feat(web-studio): add account deletion workflow (#3912)
* feat(web-studio): add account deletion workflow

* fix(web-studio): address account deletion review
2026-08-10 16:00:45 +08:00
yufeng 42a7ff088a feat(web-studio): add scheduled resource sync management (#3909)
* feat(web-studio): add scheduled resource sync

* feat(web-studio): complete watch management workflow

* fix(web-studio): refine watch management workflow

* fix(web-studio): recover watch sync progress polling

* fix(web-studio): expose watch edit action
2026-08-10 14:56:10 +08:00
Ziyang Guo d94d133bef fix(studio): open Markdown links in resource preview (#3723) (#3726)
Route internal viking:// Markdown targets through the existing resource navigator instead of the attachment download endpoint. Preserve download fallback behavior for previews without a navigation callback and add a click regression test.

Test: NODE_OPTIONS='--localstorage-file=/tmp/openviking-vitest-localstorage' pnpm test\nTest: pnpm build
2026-08-07 19:54:18 +08:00
444cc87bf8 feat: OIDC and LDAP as new auth mode for OpenViking (#3708)
* feat: support oidc and ldap auth

* feat: support oidc and ldap auth

* fix: remove heima partner, clean up auth docs, add web-studio unsupported auth banner

- Remove heima from partner list in README (en/zh/ja)
- Remove unsupported env var references (OPENVIKING_AUTH_MODE, OPENVIKING_USERNAME,
  OPENVIKING_PASSWORD) from LDAP auth docs
- Remove temporary switch bash snippets from auth docs
- Fix ldap_password description
- Add web-studio unsupported-auth-mode banner for oidc/ldap servers

* fix: address OIDC/LDAP review comments on auth plugin design

Key changes driven by PR review:

- **Role mapping**: OIDC and LDAP external identities always resolve to
  USER role. Removed map_role() calls and group_membership-based role
  mapping. Admin access is gated by the root API key mechanism only.

- **LDAP credential extraction**: Removed query-parameter-based username/
  password extraction (security concern — passwords in URLs can leak via
  shell history, proxy logs, and monitoring). Clients must use Basic Auth
  header or form data.

- **OIDC identifier sanitization**: Auth0 and other providers may include
  characters like "|" in the `sub` claim. These are now replaced with "_"
  to produce valid OpenViking user identifiers.

- **Dead code removal**: Removed _extract_groups, memberof_attribute,
  require_root_api_key_for_admin, _initialize_api_key_manager, and
  get_request_context_checks from both plugins since they are no longer
  needed.

- **Docs**: Removed query-parameter curl example, memberof_attribute and
  require_root_api_key_for_admin config references.

Co-authored-by: TRAE CLI <noreply@bytedance.com>

* feat: support oidc and ldap auth

* feat: support oidc and ldap auth

* fix(auth): bind lazy OIDC imports at module scope

---------

Co-authored-by: TRAE CLI <noreply@bytedance.com>
Co-authored-by: qin-ctx <qinhaojie.exe@bytedance.com>
2026-08-06 12:36:37 +08:00
yufeng 2a2a674dee fix(web-studio): restore terminal history icon (#3735) 2026-08-04 19:09:41 +08:00
yufeng d59bdebb27 fix(web-studio): optimize large JSON previews (#3644) 2026-07-31 11:12:19 +08:00
Qin Haojie fd42b1ad92 feat(tasks): support task cancellation (#3577)
* feat(tasks): support task cancellation

* refactor(tasks): scope cancellation to current user

* feat(cli): support task cancellation

* refactor(tasks): make cancellation queue-aware

* refactor(tasks): simplify cancellation bookkeeping

* test: remove task cancellation coverage

* refactor(tasks): trim cancellation coordination

* fix(tasks): contain cancellation to owned work

* feat(tasks): persist resource source metadata

* fix(tasks): handle cancelled work consistently

* refactor(tasks): make completion queue-aware

* fix(tasks): persist terminal state before queue ack

* test(tasks): remove added lifecycle tests

* docs(tasks): document task cancellation
2026-07-30 20:34:27 +08:00
DuTao 6b416cd66d feat(bot): support image inputs in VikingBot Chat API (#3619)
* bot支持图片对话、去除Lite llm无效逻辑

* fix error

* clarify remote image URL validation
2026-07-30 14:00:48 +08:00
yufeng 291e9c580f feat(web-studio): enhance retrieval workflows and result inspection (#3576)
* feat(web-studio): add recall and advanced retrieval

* feat(web-studio): refine retrieval filters and result details

* fix(web-studio): harden retrieval interactions

* style(web-studio): refine dashboard panel sizing

* fix(web-studio): refine retrieval page behavior
2026-07-29 17:30:31 +08:00
yufeng c67222c3d4 fix(web-studio): standardize streamed event rendering (#3517)
* fix: render bot stream events consistently

* style: separate studio sidebar from content

* fix: standardize studio chat stream rendering

* fix: finalize chat on terminal response

* fix: complete reasoning fallback state

* fix: show agent session title

* style: consolidate playground panel controls

* fix: persist playground tree state

* style: improve session chat contrast

* fix: make session content width responsive

* feat: filter memory impact by type

* fix: widen memory impact drawer

* fix(web-studio): address streaming review feedback
2026-07-27 00:04:47 +09:00
yufeng feb51ffd05 fix(web-studio): preserve identity probe credential (#3509) 2026-07-24 22:14:45 +08:00
yufeng 0ac4b87b03 feat(web-studio): improve operational navigation and workflows (#3506)
* feat(web-studio): add operational navigation and views

* feat(web-studio): complete core management workflows

* feat(web-studio): show current user in header

* feat(web-studio): add task detail panel

* fix(web-studio): harden operational workflows

* fix(studio): widen navigation sidebar
2026-07-24 18:28:25 +08:00
DuTao 0ab85f450a feat(session): add turn-aware retention and reliable archive recovery (#3380)
* 优化OpenViking的 session compact逻辑,active message 改为turn,压缩 assistant,保留完整user。
详见RFC:https://github.com/volcengine/OpenViking/discussions/3330

* Vikingbot 使用 ov turn session

* fix pr comment

* 更新文档

* fix pr issue
2026-07-24 14:26:46 +08:00
yufeng feba7e78a2 feat(web-studio): add account switching and user management (#3500)
* feat(web-studio): add account switching and user management

* fix(web-studio): harden account identity switching
2026-07-24 14:03:43 +08:00
Jiahui Zhou 1c46d44fbc Fix/reindex preserve owners (#3096)
* fix: preserve reindex content owners

feat: allow trusted admin role assertion

feat: prune orphan vectors during reindex

fix: harden reindex memory body reads

feat: expose reindex prune options in clients

fix(cli): prefer workspace sdk for compat clients

fix: harden reindex prune orphans

* test: align reindex expectations after rebase
2026-07-14 20:38:30 +08:00
Zayn Jarvis cc0281ac70 fix(studio): sort limited listings by mtime (#3212)
* fix(studio): sort limited listings by mtime

* fix(client): forward ls ordering options
2026-07-13 16:17:02 +08:00
cd9add7a27 fix(feishu): surface permission errors clearly and keep users on page (#3032)
* fix(feishu): surface permission errors clearly and keep users on page

Map Feishu/Lark API failures to typed OpenViking errors with actionable hints, and keep Web Studio from treating HTTP 403 permission denials as session logout.

* fix(feishu): simplify API error mapping

* refactor(feishu): inline API error mapping

---------

Co-authored-by: wugj <wugj@g-bits.com>
Co-authored-by: qin-ctx <qinhaojie.exe@bytedance.com>
2026-07-07 19:55:43 +08:00
Evo fe3bdf4139 fix: treat studio dev mode as root (#3020) 2026-07-06 11:25:12 +08:00
Yangfan Wu b0533b55a7 fix(web-studio): clarify usage audit access requirements (#2955) 2026-07-03 16:34:22 +08:00
Zayn Jarvis 8109ecc56b fix(web-studio): send identity headers in /health identity probe (#2983)
In trusted mode, /health identity resolution requires X-OpenViking-Account
and X-OpenViking-User headers alongside X-API-Key. Without them, the
trusted auth plugin raises InvalidArgumentError, the exception is swallowed
by the health handler, and the response omits role/account_id/user_id —
so the studio falls back to connectionRole='unknown' and gates the admin
UI behind 'Usage/Audit 未初始化'.

Sending the headers is always safe: in api_key mode the server strips
them from the request scope; in trusted mode they are required.

Closes #2977 for the web-studio side.
2026-07-03 16:09:44 +08:00
Zayn Jarvis 6f97624d8e feat(sessions): sort session list by filesystem modTime (#2972)
* fix(web-studio): lazy-create playground sessions to prevent orphans

The AgentPanel used to call POST /sessions on every page load (via a
useEffect gated on botHealth.isSuccess), creating empty UUID sessions
even when the user never sent a message. These orphan sessions cluttered
the session list.

Fix: generate a client-side UUID as the initial sessionId instead of an
empty string. The session is lazily created on the backend by the first
addMessage call (POST /sessions/{id}/messages uses auto_create=True).

- Remove startSession() and its auto-create useEffect
- Always have a sessionId (createRandomUuid fallback)
- Simplify useChat params (persistMessages always true, no preview fallback)
- Remove dead isCreating UI branch
- Call onSessionChange on mount so the URL stays in sync
- Error retry button now uses handleNewSession()

Closes: orphan empty sessions created on playground page load

* feat(sessions): sort session list by filesystem modTime

- Backend: add mod_time to session list API response (from viking_fs.ls stat)
- Frontend: useSessionListByRecency sorts by mod_time instead of N detail fetches
- Frontend: sidebar and playground history use recency-sorted list
- Frontend: sortTreeEntries sorts directories by modTime descending

Reduces session list load from 1+N requests to 1 request.
2026-07-03 11:05:35 +08:00
Zayn JarvisandClaude Opus 4.8 e1fdaf458a fix(web-studio): pin assumed account to admin key's own account (#2910)
When the Root API Key field holds an account-admin key (rather than a
root key), the studio kept using the previously selected / default
assumed account. An account-admin key is scoped to its own account, so
admin and data calls against any other account were rejected by the
server with "ADMIN can only manage account: <x>".

/health already resolves the presented key and echoes back its identity
(role + account_id + user_id). Read account_id alongside role and, when
the key resolves as an admin key, pin the assumed account to the admin
key's own account so admin/data calls target the right tenant. Root keys
are not account-scoped, so their account selection is left untouched.

Also relabel the field "Root API Key" -> "Root or Admin API Key" (en + zh)
to reflect that an account-admin key is accepted there too.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 21:39:31 +08:00
Zayn JarvisandClaude Opus 4.8 c65a74569e feat(web-studio): redesign connection & identity settings (#2896)
Replace the connection setup with a clean three-field model plus a
dedicated User Management panel.

- Connection card is now exactly Server URL, Root API Key, User API Key.
  The Root key is the sole control-plane credential (unlocks User
  Management); the User key powers Playground / tenant data APIs and is
  set via "Use as User API Key". Removes the duplicated account/user
  dropdowns and the dual-purpose API-key field.
- Admin access is gated on the Root key only, never the User key.
- Stop normalizing the base URL on every keystroke (it collapsed
  "http://" back to "http:"); normalize at request time instead.
- Disable autocapitalize/autocorrect/spellcheck on URL/key/id inputs
  (the browser was capitalizing "http" -> "Http").
- Debounce field edits and key live behaviour off the committed
  connection, so typing no longer re-probes / refetches per keystroke.
- Guard the account-filter effect against a render loop and add
  keepPreviousData to the probe so adopting/rotating a key no longer
  blanks the panel.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 20:02:01 +08:00
yufeng 83cba39b9c perf: split web studio heavy chunks (#2886) 2026-06-29 16:10:03 +08:00
yufeng 65f80c46c8 feat: open studio metrics to users (#2882) 2026-06-29 15:08:36 +08:00
yufeng 91749e40c5 Fix web studio i18n literals (#2847) 2026-06-26 14:01:03 +08:00
Zayn Jarvis f6732b7dd5 fix: Web Studio playground mobile fullscreen actions (#2766)
* fix(web-studio): move playground actions into mobile drawer

* fix(web-studio): make mobile playground actions fullscreen

* docs: add web studio mobile screenshots
2026-06-23 11:03:41 +08:00
Zayn Jarvis 85069d0717 fix(studio): stabilize account selection (#2722)
* fix(studio): stabilize account selection

* fix(studio): use single selected api key state
2026-06-22 10:27:01 +08:00
yufeng 9be0124c36 fix(studio): improve terminal command guidance (#2552) 2026-06-10 20:56:34 +08:00
t0saki 8a3bfb68ff chore(oauth): remove dead push-OTP, repurpose footer to cross-device verify (#2538)
The push-OTP feature (mint an OTP in Studio to hand to an MCP client) was never
wired to a consumer: consume_otp had zero production callers and no endpoint or
grant ever redeemed an OTP. The 'full happy path' test actually exercised the
display_code flow, not OTP. So the sidebar footer's 'OAuth setup' entry minted a
code with nowhere to use it — dead, confusing UX.

Remove it end-to-end and repurpose the footer slot into an entry for the
cross-device verify page (enter the 6-char display_code), which previously had no
discoverable entry point in Studio.

Frontend:
- delete oauth-setup-dialog.tsx + /oauth/setup route (+ routeTree, i18n)
- extract CrossDeviceVerifyForm from verify.tsx; add CrossDeviceVerifyDialog
- footer 'OAuth verify' entry opens the verify dialog (desktop) / page (mobile)

Backend:
- drop issue_otp route + OTPRequest/OTPResponse, storage insert_otp/consume_otp,
  oauth_config.otp_ttl_seconds, and the OTP-specific tests
- keep otp.py generate_otp (cross-device display_code) + hash_secret, the shared
  _atomic_consume_code, and the oauth_codes.kind column
- convert the race/expiry/revoke/GC storage tests to auth-code rows

Docs: update 11-oauth, 06-mcp-integration, and the design doc to reflect removal.
2026-06-10 12:52:54 +08:00
yufeng 37507571a9 fix: harden Studio resource search (#2521)
* fix studio playground resource search

* fix: harden studio resource search

* test: handle missing user skills directory

* fix: preserve lazy user directory listing

* test: prepare user skills directory
2026-06-09 19:11:33 +08:00
t0saki a4f43c9770 feat(web-studio): select account/user in OAuth consent when permitted (#2528)
Iterate the OAuth consent/verify pages to match the Studio Connection &
Identity UX: when the caller is root/admin in api_key mode, let them pick a
concrete account + user from dropdowns instead of pasting a raw API key. The
selected user's api_key becomes the Bearer that binds the OAuth grant.

This is required for root, not just nicer UX: the backend oauth-verify
rejects identities without a per-user key fingerprint, so root cannot
authorize as itself and must select a concrete user.

- IdentityPicker: add 'select' mode + optional directory prop (presentational)
- useIdentityDirectory: gate on api_key + root/admin, list accounts/users,
  detect root vs account-admin via GET /accounts 403, resolve user keys
- consent.tsx / verify.tsx: default-mode effect (root -> select), keep select
  payload in sync, soften the sign-in prompt
- Extract shared admin data layer (#/lib/admin) + AccountSelect/UserSelect
  (#/components/identity-select) so settings and consent share one source
- i18n: add oauth.identityPicker.select* keys (en + zh-CN)

No backend changes.
2026-06-09 16:15:12 +08:00
bbed0c422a feat: save images from pdf and doc to vikingfs (#2429)
* feat: save images in Markdown to vikingfs

* feat: save images in doc to vikingfs

* fix: change the image file reading operation to asynchronous.

* feat: support generating L0 and L1 from images in Markdown and importing them into vector indexes

* fix: add updating image links when modifying existing files; restrict accessible paths for image loading; revise the unit tests raised for images

* fix: 限制保存的图片所在目录,避免将其他目录下的内容加入 vikingfs;对markdown代码中的图片链接保持不变

---------

Co-authored-by: zhanghaoyu.la <zhanghaoyu.la@bytedance.com>
Co-authored-by: Qin Haojie <qinhaojie.exe@bytedance.com>
2026-06-08 10:52:08 +08:00
Zayn Jarvis 6b3d261b61 docs: remove stale agent header references (#2462) 2026-06-05 17:27:07 +08:00
yufeng 1a1f32bfb6 fix: stabilize studio identity and streaming chat (#2435)
* fix: stabilize studio identity and streaming chat

* fix: hide unsupported studio terminal commands

* fix: remove unsupported terminal command copy

* fix: run selected terminal suggestion on enter

* fix: group supported terminal commands

* fix: add terminal quick start and history

* fix: scope session visibility by user

* fix: harden bot user scoping

* fix: forward request scoped bot identity

* fix: add terminal quick start translations

* fix: add terminal command group translations

* fix: simplify studio identity scoping

* fix: support api key copy on dev urls

* fix: stop passing agent id to ov http client

* fix: search follow-up memory questions
2026-06-05 16:44:35 +08:00
Zayn Jarvis 0dc206ae4e Fix Studio admin/data API key handling (#2449)
* Fix Studio admin and data API key handling

* Refine Studio connection identity UI

* Polish Studio header alignment

* Remove duplicate Playground directory header

* Show processing tasks in Playground context tree

* Fix Playground folder focus toggling

* Remove Context Management route
2026-06-05 14:36:29 +08:00
Qin Haojie ff258768c2 feat(memory): 引入 User/Peer 记忆隔离模型 (#2236)
* feat(memory): introduce user and peer memory isolation

Unify agent-scoped memory behavior into user-owned memory spaces, add peer_id compatibility for session and retrieval paths, and wire memory_policy through session commit flows.

* feat(memory): align session identity around peer IDs

* feat(search): pass peer id through retrieval

* refactor(memory): remove agent identity from integrations

* fix(memory): isolate peer identity from self extraction

* fix(tau2): provision benchmark user configs

* fix(auth): allow admin keys to access data APIs

* fix(openclaw): enable peer memory policy for peer roles

* fix(openclaw): resolve sender for peer recall

* refactor(session): simplify memory extraction routing

* refactor(ov-cli): reduce formatting-only diff

* refactor(message): remove unused message helpers

* refactor(retrieval): simplify peer target resolution

* refactor(namespace): remove deprecated agent namespace policy

* fix(agent): propagate peer id through integrations

* fix(auth): align integration clients with api-key mode
2026-06-05 10:55:48 +08:00
yufeng c9abc2e8af fix: improve playground bot flow (#2381)
* fix: improve playground bot flow

* fix: preserve playground trace refs

* fix: limit playground backend scope

* fix: show automatic memory tool events

* fix: cap automatic memory search results

* fix: limit memory result refs to entries

* fix: cap automatic memory context total

* fix: show memory commit refs

* chore: format memory helper
2026-06-02 16:52:50 +08:00
Feichuan 7bcd66a451 fix(web-studio): improve resource browser navigation, save latency, and palette L2 (#2346)
* feat(web-studio): pass create_parent param in resource upload

The backend supports auto-creating parent directories via create_parent,
but the frontend upload form never sent it. Add the parameter (default true)
with a checkbox in advanced options.

* fix(web-studio): improve file save performance and tree collapse behavior

Set wait=false for content write to skip blocking on vector indexing.
Reset expandedKeys on navigation to collapse tree to current directory,
and clear descendant expanded state on folder expand for cleaner UX.

* style(web-studio): enhance language switcher styling and active state indication

* refactor(web-studio): unify resource browser palette state

Refactor the resource browser palette so directory browsing, keyboard handling, and palette mode parsing have a single owner.

Changes:
- make DirBrowser a controlled view owned by FindPalette
- remove DirBrowser internal focusUri/startUri syncing
- remove internalNavRef and document-level keydown listener
- move palette keyboard handling to FindPalette container onKeyDown
- add explicit PaletteMode parsing for idle/search/dirBrowse states
- centralize directory browse query parsing and URI-to-query writing
- lift directory list loading and active cursor state into FindPalette
- add shared useListNavigation hook for active index movement
- debounce directory peek requests by 150ms
- debounce file stat preview requests by 150ms
- extract reusable ItemColumn list component
- export existing useDebouncedValue hook
- add scope reset/back navigation UI copy

This keeps the current browse directory, keyboard dispatch, and palette mode state in one place, avoiding the previous two-way sync loop between FindPalette and DirBrowser.

* refactor(web-studio): flatten DirBrowser detail pane into a switch

Replace the 6-way nested ternary in DirBrowser's right pane with an
explicit DetailView discriminated union computed in one useMemo, rendered
by a flat DetailPane switch (preview/loading/error/subdir/empty/idle).

Merge ItemColumn's onSelect/onSelectFile into a single onSelect(entry,
index); callers branch on entry.isDir. Behavior is unchanged except the
transient peek flash during the 150ms debounce window is gone, since all
directory states are now gated behind cursorItem.isDir.

* fix(web-studio): handle palette pane navigation focus

Use the clicked right-pane entry URI when navigating from the DirBrowser detail pane, instead of reusing the left-pane cursor item.

Clamp list navigation when visible entries change, and restore palette input focus after window focus or visibility changes so keyboard cursor handling remains active after switching apps.

* feat(web-studio): add onOpenFile prop to DirBrowser and FindPalette components

* fix(web-studio): prevent invalid dir scope confirmation and expandedKeys conflict

- Guard Enter in dirBrowse mode with dirListQuery.isSuccess so only
  existing directories can be confirmed as search scope
- Remove handleToggle() from handleSelect to eliminate double-write
  conflict on expandedKeys when clicking directory rows
- Add dirListQuery.isSuccess to handleKeyDown deps to fix stale closure
  preventing scope confirmation in empty directories on cold cache
2026-06-01 19:54:54 +08:00
yufeng 93aab7761e feat: add Studio playground workspace (#2352)
* feat: add studio playground workspace

* fix: address studio playground review feedback

* chore: remove studio design docs from PR
2026-06-01 15:50:09 +08:00
yufeng ba973cc626 fix: handle Studio random UUID fallback (#2338) 2026-05-31 17:09:47 +08:00
Zayn Jarvis 919309c879 feat: add web studio account user management (#2309)
* Add web studio identity management

* Polish web studio settings header

* Match language toggle and simplify user actions

* Align header controls with site chrome

* Tighten studio chrome spacing

* Shrink header language toggle text
2026-05-29 19:22:34 +08:00
Ferry 8271aa2045 fix(server): update server mode terminology from 'dev-implicit' to 'dev' (#2260) 2026-05-27 17:02:54 +08:00
Qin Haojie 53c8947f42 fix(web-studio): show raw memory preview by agent (#2225) 2026-05-25 21:56:27 +08:00
Zayn Jarvis a29a098204 fix(web-studio): drop client-side heatmap tz rebucket — now done server-side (#2194)
PR #2178 (4e947340) shipped a `shiftBucketToLocal` helper that re-bucketed
the commit heatmap from UTC to viewer-local. PR #2190 (0d63f0e3) landed
right after and added the equivalent shift server-side: backend now
accepts ?timezone= and returns rows already bucketed in the requested tz.
Keeping the client-side shift double-shifts every row by the viewer's tz
offset (e.g. UTC+8 ends up at UTC+16), so today's bucket displays under
the wrong local date.

This was supposed to be reverted on the #2178 branch before merge but the
revert commit (37e04500) was pushed after the PR had already been merged,
so it never reached main. Apply the same revert directly here.

normalizeCommitHeatmapData now keys the aggregation map by item.date as
the server returns it (already in viewer tz post-#2190).
2026-05-22 17:58:24 +08:00
Zayn JarvisandClaude Opus 4.7 0d63f0e3c4 fix(observability): persist usage/audit in UTC and bucket per request tz (#2190)
* fix(observability): persist usage/audit in UTC and bucket per request tz

Dashboard, token-trend, and context-commit-heatmap previously bucketed by
server-process local timezone (`server/config.py` default `local`, which
on Railway / Docker without `TZ` is UTC). UTC+8 viewers saw "today" and
4h heatmap edges shifted relative to their wall clock.

Root cause: `projection.py` applied `astimezone(self._tz)` before writing
the rollup PKs, so date/hour columns were already locked to the
container's tz; a read-side `?timezone=` could not recover the buckets
because the raw UTC instants were no longer in storage.

Fix: persist all time-keyed columns (`date_utc`, `hour_utc`,
`created_at`) in UTC and accept `?timezone=` per request on
`/api/v1/console/{dashboard/summary,tokens,context-commits}`. The viewer
tz is resolved with `zoneinfo`, then the SQLite reads pull the spanning
UTC window and rebucket in Python to user-local days / 4h buckets. DST
is handled by `ZoneInfo` automatically.

Schema bump (v1 -> v2): `usage_token_daily` becomes `usage_token_hourly`
and `usage_retrieval_daily` becomes `usage_retrieval_hourly` (extra
`hour_utc` column in PK so cross-tz "today" slicing is precise). Other
tables keep their shape; `date` is renamed to `date_utc` to make the
semantic shift unambiguous. On boot, the store DROPs the legacy tables
once and recreates the new layout - acceptable because retention is 14
days and the product is pre-GA.

Frontend (`web-studio`) now passes
`Intl.DateTimeFormat().resolvedOptions().timeZone` on every console
fetch; `getLastDaysRange` derives the date range in the viewer's tz so
its boundaries match the backend interpretation. No visual / component
changes were needed.

Tests:
- Backend: existing 15 cases ported to the new keyword-only `tz=` API;
  three new cases exercise UTC+8 day-boundary, America/New_York day
  rebucketing across UTC midnight, and Asia/Shanghai 4h heatmap hour
  shift. All 20 observability tests pass.
- Frontend: typecheck + lint clean (no new errors).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(observability): reset legacy usage audit sqlite schema

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 17:03:14 +08:00
Zayn Jarvis 4e9473406b feat(web-studio): PWA, mobile UI polish, OAuth-setup tab, request-logs touch-ups (#2178)
* feat(web-studio): PWA, mobile UI polish, OAuth-setup tab, request-logs touch-ups

PWA & install
- manifest 192/512 + maskable icons, service-worker registration in main.tsx,
  apple-mobile-web-app meta + viewport-fit=cover in index.html.
- openviking/server/app.py: redirect "/" -> "/studio/" so the PWA install
  start_url resolves correctly when accessed from the bare host.

OAuth setup as its own tab
- New /studio/oauth/setup route + OAuthSetupDialog; sidebar footer entry
  routes to the dialog on >=md and to the dedicated page on phone (mobile
  fullscreen dialogs are hard to dismiss). OTP form extracted from the
  connection dialog into a reusable component.

Mobile UI fixes
- Home metric chips: grid minmax 92px -> 140px, removed truncate so chips
  wrap instead of clipping.
- Context-commits tooltip: clamps into viewport on narrow screens.
- Context-commits heatmap: auto-scrolls to rightmost (latest) on items
  change so phone view opens on the current week.
- Dialog: max-h-[calc(100dvh-2rem)] + overflow-y-auto for phone overflow.
- FS page (resources):
  * full-height container uses calc(100svh-6rem) + symmetric -my-6 so the
    outer ScrollArea no longer overflows by parent's py-6.
  * inner overlay-style scrollbars on phone (matches iOS / Atlas).
  * PWA standalone mode hides the outer page scrollbar on this route.
  * Tighter row density on phone (text-xs / py-1) to match Atlas.
  * FolderIcon size-5 -> size-4 so folder and file text columns align.
  * Folder highlight only when no file is selected (clean single-select).
  * Toolbar refresh button: size-icon-sm + pl-4 to align with the header
    sidebar trigger on phone.
- Find-palette: phone-center + max-h-[calc(100svh-2rem)] (was top-anchored
  + 84vh). Search input min font-size 16px to dodge iOS auto-zoom; same
  treatment in the retrieval search bar.

Request logs
- Time column: dot-separated YYYY.MM.DD HH:MM:SSam/pm (compact, no locale
  variance).
- Total calls clamps display at "999+".
- Pagination row: justify-center on phone (sm:justify-between preserved).

i18n
- Retrieval placeholder: "Search context" / "输入检索内容".
- Find-palette placeholder: "Search" / "搜索".
- Context-commits title: drop "in the last year" (range chip still shows).
- find / search labels: drop the parentheses.
- Workspace sidebar header: "OpenViking Studio".

Build verified after each change. Phone view validated via Chromium
emulation; iOS PWA-mode scrollbar fix scoped behind
@media (display-mode: standalone).

* feat(web-studio): more mobile polish and viewer-tz bucket shift for commit heatmap

PR #2178 follow-ups based on phone PWA testing:

Context commits heatmap (Home)
- Re-bucket UTC (date, hour_bucket) 4h rows into viewer-local (date,
  hour) before daily aggregation, so a UTC+8 viewer's "today" cell holds
  the right local-day count instead of UTC's. Pure client-side relabel —
  each bucket's count is preserved, just attributed to the correct local
  date. Daily / "today_tokens" aggregates can't be rebucketed this way
  and still need the backend tz work (separate follow-up).
- Auto-scroll: align viewport's right edge with the rightmost rendered
  rect's right edge (not the SVG's hardcoded width=820 right edge), so
  the ~50px of trailing SVG padding stays off-screen on phone.
- Wrap the scroll write in requestAnimationFrame so HeatMap has a tick
  to lay out its SVG; otherwise scrollWidth equals clientWidth and the
  scroll snaps to the left (oldest) edge.

FS / resources route polish
- File tree: clicking a folder row now toggles expand/collapse in
  addition to opening the folder (chevron icon still works alone via
  stopPropagation, no double-toggle).
- File tree: parent passes selectedFileUri only when the selected entry
  is actually a file; opening a folder no longer leaves it competing
  with the parent's directory highlight.
- File tree: session subtree (any URI under viking://session/) sorts
  children by modTimestamp DESC instead of name, so the most recent
  session shows first.
- FolderIcon size-5 -> size-4 to match File icon and chevron, so folder
  and file rows share the same text x-offset at every depth.
- Toolbar: refresh Button now uses size="icon-sm" + pl-4 on the toolbar
  so its icon center aligns vertically with the header's sidebar
  trigger on phone.
- Breadcrumb nav: overflow-hidden -> overflow-x-auto + whitespace-nowrap
  + flex-1 so long paths scroll horizontally on phone instead of being
  cut off invisibly.

formatModTime
- Parse time-only mod_time strings ("HH:MM:SS", "12:34am" etc) against
  UTC today + Z marker — backend's format_simplified uses UTC's "today"
  reference, not the viewer's local today, so the prior local-today
  prefix mis-attributed days for non-UTC viewers.
- Date-only mod_time ("YYYY-MM-DD") renders as-is; we don't fake an
  "00:00" time component that doesn't exist.

JSONL dialog
- Cards: drop ml-auto / mx-auto / mr-auto chat-bubble alignment;
  switch w-fit max-w-[min(820px,88%)] to w-full min-w-0 max-w-full so
  long expanded messages, tool-call JSON, and markdown tables can use
  the full pane width and trigger their own internal overflow-auto
  instead of pushing the article wider than the viewport.
- List container picks up min-w-0 so the flex column can shrink.
- Kind distinction now color-only (bg / border).

Request-logs pagination
- justify-center on phone for both the summary row and the pagination
  control row; sm:justify-between / sm:justify-end preserved on tablet+.
2026-05-22 02:43:38 +08:00