Skip to content

Commit ccf4917

Browse files
authored
Release 1Helm 1.6.0 (#96)
Promote the complete locally proven post-1.5.0 update stack and ReRouted 0.5.15.
1 parent 209e9bd commit ccf4917

52 files changed

Lines changed: 2257 additions & 750 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.6.0] - 2026-09-23
11+
12+
### Added
13+
14+
- Channels can opt into Session presentation, per-channel Default/Comfy/Compact density, and Default/By active ordering without changing the underlying conversation model.
15+
- Board now uses authoritative operational lanes—Working, Needs you, Scheduled, Failed, and Complete—with idle and archived sessions kept in collapsed history.
16+
- Messages expose a direct Copy action, and ordinary Work Log steps show user-local timestamps.
17+
- Native vision sends supported human image uploads to compatible models as image content and lets resident agents inspect workspace images through the bounded `view_image` tool.
18+
- Clients record the user's IANA time zone so agent invocations receive both user-local time and the exact UTC instant.
19+
20+
### Changed
21+
22+
- Thread navigation is latest-intent-wins, deduplicates duplicate destinations, paints bounded cached snapshots immediately, loads channel and thread data concurrently, and server-paginates long threads while preserving the visible anchor when older replies load.
23+
- Board and thread listings use lightweight bounded payloads so large channels avoid unnecessary database, transfer, and browser work.
24+
- Provider cache policy is applied after the actual route is selected. Claude receives reusable stable and rolling breakpoints; ChatGPT and xAI receive stable thread-scoped cache keys; provider usage is normalized into cache reads, cache writes, uncached input, and logical input.
25+
- Embedded ReRouted advances to 0.5.15 with bounded model validation, Claude Code 2.1.280 OAuth compatibility, cross-turn Claude cache reuse, and valid atomic serialization of parallel Claude tool results.
26+
27+
### Fixed
28+
29+
- Reader-controlled conversation and Work Log scrolling remains stable through live updates, sidebar changes, message expansion, reconnects, foreground recovery, and growing streamed replies.
30+
- Stopping or cancelling a running scheduled wake authoritatively cancels its durable follow-up, prevents finalization from re-arming it, and keeps cancellation controls visible while it runs.
31+
- Manual provider model tests time out cleanly instead of remaining indefinitely in a testing state.
32+
- Photon outages no longer restart the entire 1Helm service.
33+
- Saved channel density is authoritative on rendered session cards.
34+
1035
## [1.5.0] - 2026-09-06
1136

1237
### Added

‎config/module-budgets.json‎

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,30 @@
66
},
77
"legacy": {
88
"lines": {
9-
"src/client/app.ts": 3672,
10-
"src/client/channel.ts": 1202,
11-
"src/client/cowork.ts": 879,
12-
"src/client/routing.ts": 864,
13-
"src/client/settings.ts": 812,
14-
"src/server/agents.ts": 1353,
15-
"src/server/bots.ts": 2189,
9+
"src/client/app.ts": 3907,
10+
"src/client/channel.ts": 1056,
11+
"src/client/cowork.ts": 878,
12+
"src/client/routing.ts": 821,
13+
"src/server/agents.ts": 1347,
14+
"src/server/bots.ts": 2176,
1615
"src/server/channel-computers.ts": 2217,
1716
"src/server/db.ts": 1158,
18-
"src/server/index.ts": 2284,
19-
"src/server/routing.ts": 1303
17+
"src/server/index.ts": 2334,
18+
"src/server/routing.ts": 1247,
19+
"src/server/store.ts": 808
2020
},
2121
"fanIn": {
22-
"src/client/api.ts": 11,
23-
"src/client/dom.ts": 9,
22+
"src/client/api.ts": 12,
23+
"src/client/dom.ts": 10,
2424
"src/server/agents.ts": 10,
25-
"src/server/db.ts": 30,
25+
"src/server/db.ts": 32,
2626
"src/server/store.ts": 9
2727
},
2828
"fanOut": {
29-
"src/server/bots.ts": 23,
30-
"src/server/index.ts": 33
29+
"src/server/bots.ts": 24,
30+
"src/server/index.ts": 35
3131
},
3232
"cycles": [
33-
[
34-
"src/client/app.ts",
35-
"src/client/channel.ts",
36-
"src/client/cowork.ts",
37-
"src/client/settings.ts",
38-
"src/client/term.ts"
39-
],
4033
[
4134
"src/server/bots.ts",
4235
"src/server/followups.ts"

‎docs/VISION.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ sole visual home for recurring work and its chronological run history; workflow
4141
runs do not spill into Chat, Board, or Threads, while each run remains a normal
4242
interactive thread when opened.
4343

44+
## Session presentation and operational truth
45+
46+
Channels may opt into Session mode without changing navigation or information
47+
architecture. The same Chat tab, sessions, order, content, labels, colors, and
48+
thread behavior remain; only top-level Chat rows receive a compact bordered-card
49+
presentation. Turning the mode off restores the standard Chat presentation.
50+
51+
Board uses operational states for every channel, regardless of Session mode.
52+
Runtime records—not generated prose or the ambiguous database `open` value—own
53+
Working, Needs you, Scheduled, Failed, Complete, Idle, and Archived.
54+
4455
## Honest model usage
4556

4657
A thread's primary token indicator answers how much input context the latest model call processed, not how many repeated prompt-token encounters accumulated across an agent loop. 1Helm calculates this itself from the structured messages and tool schemas it sends, using one stable provider-neutral approximation. Cached is the unchanged leading context shared with the preceding call; output counts response text and tool-call payloads received by 1Helm; calls count successful invocations. These product metrics never depend on provider usage reports. Lifetime output and model-call count remain cumulative because they represent newly generated work and actual invocations; cumulative prompt traffic is never presented as the size of a conversation.

‎package-lock.json‎

Lines changed: 6 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "1helm",
33
"productName": "1Helm",
4-
"version": "1.5.0",
4+
"version": "1.6.0",
55
"private": true,
66
"type": "module",
77
"license": "AGPL-3.0-only",
@@ -87,7 +87,7 @@
8787
"@codemirror/lang-sql": "6.10.0",
8888
"@codemirror/lang-yaml": "6.1.3",
8989
"@excalidraw/excalidraw": "0.18.1",
90-
"@gitcommit90/rerouted": "github:gitcommit90/rerouted#e200e457ad2c6abe17f8f6c2e00d8026ea027e09",
90+
"@gitcommit90/rerouted": "github:gitcommit90/rerouted#df7fd909f2f0d499f7d3e4657df93b780c3837ac",
9191
"@opencoredev/loginwithchatgpt-server": "^0.2.0",
9292
"codemirror": "6.0.2",
9393
"docx": "9.7.1",

‎public/index.html‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@
3030
document.querySelectorAll('meta[name="theme-color"]').forEach(function (m) { m.setAttribute("content", color); });
3131
})();
3232
</script>
33-
<link rel="stylesheet" href="/app.css?v=1d58393a8deb" />
33+
<link rel="stylesheet" href="/app.css?v=0945b06381eb" />
3434
</head>
3535
<body class="h-screen w-screen overflow-hidden antialiased">
3636
<div id="app" class="h-full w-full"></div>
37-
<script type="module" src="/bundle.js?v=22e6e103acb2"></script>
37+
<script type="module" src="/bundle.js?v=0e3fe58a8f17"></script>
3838
</body>
3939
</html>

‎scripts/run-test-suite.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ delete env.HELM_APP_ROOT;
1717
const suites = [
1818
["test/native-world.mjs"],
1919
["--test", "--test-concurrency=1",
20-
"test/phase6-modules.mjs", "test/provider-prompt-cache.mjs", "test/output-truncation.mjs",
20+
"test/phase6-modules.mjs", "test/provider-prompt-cache.mjs", "test/chatgpt-stream.mjs", "test/vision-runtime.mjs", "test/output-truncation.mjs",
2121
"test/provider-model-refresh.mjs", "test/routing.mjs", "test/routing-disabled-account.mjs", "test/routing-antigravity.mjs", "test/desktop.mjs", "test/update-service.mjs",
2222
"test/channel-computers.mjs", "test/channel-computers-isolated-backends.mjs", "test/event-loop-unblocking.mjs", "test/read-state.mjs",
2323
"test/cloudflare-worker.mjs", "test/connectors.mjs", "test/chatgpt-image.mjs", "test/autonomy-platform.mjs",

‎src/client/api.ts‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export type ChannelComputer = {
3939
obligations: Array<{ kind: string; ref: string; mode: "resident" | "wakeable"; details: string; due_at?: number | null }>;
4040
};
4141
export type ChannelMember = { id: number; username: string; display: string; avatar: string };
42-
export type Channel = { id: number; name: string; slug: string; kind: string; topic: string; purpose: string; status: "active" | "archived"; unread: number; favorite?: boolean; members?: ChannelMember[]; agent: ResidentAgent | null; computer?: ChannelComputer | null; personal_main?: boolean; can_manage?: boolean; detailed?: boolean; call_skipper_without_confirmation?: boolean };
42+
export type Channel = { id: number; name: string; slug: string; kind: string; topic: string; purpose: string; status: "active" | "archived"; unread: number; favorite?: boolean; members?: ChannelMember[]; agent: ResidentAgent | null; computer?: ChannelComputer | null; personal_main?: boolean; can_manage?: boolean; detailed?: boolean; call_skipper_without_confirmation?: boolean; session_mode?: boolean; session_sort?: "default" | "active"; session_density?: "default" | "comfy" | "compact" };
4343
export type Bot = { id: number; name: string; model: string; avatar: string; provider_id: number | null; provider_name: string | null; provider_kind: string | null; computers: number[]; prefs: Record<string, string>; agent_id?: number | null; agent_kind?: string | null; agent_status?: string | null; resident_channel_id?: number | null };
4444
export type ThreadFollowup = {
4545
id: number;
@@ -57,9 +57,10 @@ export type ThreadState = {
5757
status: "open" | "waiting" | "resolved" | "failed" | "archived";
5858
title: string;
5959
summary: string;
60+
operational_state?: "working" | "needs_you" | "scheduled" | "failed" | "complete" | "idle" | "archived";
6061
opened_at: number;
6162
updated_at: number;
62-
root: Message;
63+
root: Pick<Message, "id">;
6364
/** Active durable agent wake, pending or currently running (Board Scheduled lane). */
6465
followup?: ThreadFollowup | null;
6566
};
@@ -147,11 +148,13 @@ export type RoutingCombo = { id: string; storageId?: string | null; name: string
147148
export type RoutingUsageEntry = {
148149
at?: number; model?: string; provider?: string; providerName?: string; providerType?: string;
149150
accountAlias?: string | null; status?: number; requests?: number; prompt_tokens?: number;
150-
completion_tokens?: number; cached_tokens?: number; total_tokens?: number; error?: unknown;
151+
completion_tokens?: number; cached_tokens?: number; cache_read_tokens?: number; cache_write_tokens?: number;
152+
uncached_input_tokens?: number; logical_input_tokens?: number; token_semantics?: string; total_tokens?: number; error?: unknown;
151153
};
152154
export type RoutingUsage = {
153155
requests: number; ok: number; errors: number; prompt_tokens: number; completion_tokens: number;
154-
cached_tokens: number; total_tokens: number; byModel: RoutingUsageEntry[];
156+
cached_tokens: number; cache_read_tokens: number; cache_write_tokens: number; uncached_input_tokens: number;
157+
logical_input_tokens: number; token_semantics?: string; total_tokens: number; byModel: RoutingUsageEntry[];
155158
byProvider: RoutingUsageEntry[]; recent: RoutingUsageEntry[];
156159
};
157160
export type RoutingQuotaWindow = { id: string; label: string; usedPercent: number; remainingPercent: number; resetsAt?: number | null };
@@ -168,8 +171,8 @@ export type RoutingState = {
168171
keyedPresets: Array<{ id: string; name: string; baseUrl: string; needsAccountId?: boolean }>;
169172
};
170173

171-
export async function routingAction<T = Record<string, unknown>>(action: string, payload?: unknown): Promise<T> {
172-
return api<T>("/api/routing/action", { body: { action, payload } });
174+
export async function routingAction<T = Record<string, unknown>>(action: string, payload?: unknown, options: { signal?: AbortSignal } = {}): Promise<T> {
175+
return api<T>("/api/routing/action", { body: { action, payload }, signal: options.signal });
173176
}
174177
export type Skill = {
175178
id?: number; slug: string; name: string; description: string; category: string; instructions?: string; assigned?: boolean;
@@ -213,11 +216,17 @@ export function workspacePhotoSrc(photoUrl: string | null | undefined, cacheBust
213216
export const setToken = async (t: string): Promise<void> => { token = t; setAuthenticatedAssetToken(t); await persistSecureSession(t); };
214217
export const clearToken = async (): Promise<void> => { token = ""; setAuthenticatedAssetToken(""); await removeSecureSession(); };
215218

216-
export async function api<T = any>(path: string, opts: { method?: string; body?: unknown; headers?: Record<string, string> } = {}): Promise<T> {
219+
const browserTimeZone = (() => {
220+
try { return Intl.DateTimeFormat().resolvedOptions().timeZone || ""; }
221+
catch { return ""; }
222+
})();
223+
224+
export async function api<T = any>(path: string, opts: { method?: string; body?: unknown; headers?: Record<string, string>; signal?: AbortSignal } = {}): Promise<T> {
217225
const res = await fetch(apiUrl(path), {
218226
method: opts.method || (opts.body !== undefined ? "POST" : "GET"),
219-
headers: { ...(opts.body !== undefined ? { "content-type": "application/json" } : {}), ...(token ? { authorization: `Bearer ${token}` } : {}), ...(opts.headers || {}) },
227+
headers: { ...(opts.body !== undefined ? { "content-type": "application/json" } : {}), ...(token ? { authorization: `Bearer ${token}` } : {}), ...(browserTimeZone ? { "x-1helm-time-zone": browserTimeZone } : {}), ...(opts.headers || {}) },
220228
body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
229+
signal: opts.signal,
221230
});
222231
const data = await res.json().catch(() => ({}));
223232
if (!res.ok) throw new Error((data as { error?: string }).error || `HTTP ${res.status}`);

0 commit comments

Comments
 (0)