aegis-desktop 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,289 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta
6
+ http-equiv="Content-Security-Policy"
7
+ content="default-src 'none'; script-src 'self'; style-src 'self' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data:"
8
+ />
9
+ <title>AEGIS Desktop</title>
10
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12
+ <link
13
+ href="https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,400&family=Syne:wght@400;600;700;800&family=Ubuntu:ital,wght@0,400;0,500;0,700;1,400&display=swap"
14
+ rel="stylesheet"
15
+ />
16
+ <link rel="stylesheet" href="style.css" />
17
+ </head>
18
+ <body>
19
+ <header class="topbar">
20
+ <h1>AEGIS <span class="accent">Desktop</span></h1>
21
+ <div class="conn">
22
+ <span class="dot" id="conn-dot"></span>
23
+ <span id="conn-text">connecting…</span>
24
+ </div>
25
+ <div class="spacer"></div>
26
+ <button type="button" id="new-chat" class="ghost-btn">New chat</button>
27
+ </header>
28
+
29
+ <main>
30
+ <aside class="side">
31
+ <section class="card">
32
+ <h2>Status</h2>
33
+ <dl>
34
+ <dt>app</dt><dd id="st-app">–</dd>
35
+ <dt>client</dt><dd id="st-client">–</dd>
36
+ <dt>endpoint</dt><dd id="st-base">–</dd>
37
+ <dt>key</dt><dd id="st-key">–</dd>
38
+ <dt>plan</dt><dd id="st-plan">–</dd>
39
+ <dt>balance</dt><dd id="st-balance">–</dd>
40
+ </dl>
41
+ <div class="api-key-row">
42
+ <input
43
+ type="password"
44
+ id="api-key-input"
45
+ placeholder="AEGIS API key"
46
+ autocomplete="off"
47
+ />
48
+ <button type="button" id="api-key-save" class="ghost-btn">Save</button>
49
+ <button type="button" id="api-key-verify" class="ghost-btn">Verify</button>
50
+ </div>
51
+ <p class="hint" id="api-key-hint"></p>
52
+ </section>
53
+
54
+ <section class="card">
55
+ <h2>Model</h2>
56
+ <label for="class-select">Provider class</label>
57
+ <select id="class-select"></select>
58
+
59
+ <label for="model-select">Model</label>
60
+ <select id="model-select"></select>
61
+ <select id="model-preset" hidden title="Quick-fill a known model + base URL"></select>
62
+ <input
63
+ type="text"
64
+ id="model-input"
65
+ placeholder="type a model id — e.g. gpt-4o-mini"
66
+ autocomplete="off"
67
+ hidden
68
+ />
69
+
70
+ <label for="max-tokens">Max tokens</label>
71
+ <div class="max-tokens-row">
72
+ <select id="max-tokens">
73
+ <option value="1024">1k</option>
74
+ <option value="4096" selected>4k</option>
75
+ <option value="16384">16k</option>
76
+ <option value="64000">64k</option>
77
+ <option value="300000">300k</option>
78
+ </select>
79
+ <label
80
+ class="flow-toggle"
81
+ for="max-tokens-adaptive"
82
+ title="Automatically use the highest output ceiling the selected model supports, up to 300k tokens, instead of the fixed choice above."
83
+ >
84
+ <input type="checkbox" id="max-tokens-adaptive" />
85
+ <span>adaptive</span>
86
+ </label>
87
+ </div>
88
+
89
+ <label
90
+ class="flow-toggle"
91
+ for="autonomous-toggle"
92
+ id="autonomous-toggle-wrap"
93
+ hidden
94
+ title="Let the model work autonomously: fan out to multiple reasoning workers and synthesize their findings into one answer. Aegis Cloud models only."
95
+ >
96
+ <input type="checkbox" id="autonomous-toggle" />
97
+ <span>work autonomously</span>
98
+ </label>
99
+ <div id="autonomous-controls" class="autonomous-controls" hidden>
100
+ <label for="autonomous-effort">Effort</label>
101
+ <select id="autonomous-effort">
102
+ <option value="low">low</option>
103
+ <option value="medium">medium</option>
104
+ <option value="high" selected>high</option>
105
+ </select>
106
+ <label for="autonomous-workers">Workers</label>
107
+ <input type="number" id="autonomous-workers" min="1" max="8" step="1" value="3" />
108
+ </div>
109
+ <p class="hint" id="model-hint"></p>
110
+ </section>
111
+
112
+ <section class="card">
113
+ <h2>Provider settings</h2>
114
+ <div id="settings-list"></div>
115
+ <p class="hint" id="settings-hint"></p>
116
+ </section>
117
+
118
+ <section class="card">
119
+ <h2>Sessions</h2>
120
+ <button type="button" id="sessions-refresh" class="ghost-btn">Refresh</button>
121
+ <button type="button" id="sync-now" class="ghost-btn">Sync now</button>
122
+ <ul class="sessions-list" id="sessions-list"></ul>
123
+ <p class="hint" id="sessions-hint"></p>
124
+ <p class="hint" id="sync-status"></p>
125
+ </section>
126
+
127
+ <section class="card">
128
+ <!-- The heading is the click target for the full memory inspector.
129
+ The button lives *inside* the h2 (not the reverse) because a
130
+ <button> may only contain phrasing content, and <h2> is not. -->
131
+ <h2>
132
+ <button
133
+ type="button"
134
+ class="card-title-btn"
135
+ id="memory-open"
136
+ title="Open the memory inspector — every entry with its source, tags and topics"
137
+ >
138
+ <span>Memory</span>
139
+ <span class="ctb-expand" aria-hidden="true">⤢</span>
140
+ </button>
141
+ </h2>
142
+ <form id="memory-search-form" class="memory-search">
143
+ <input
144
+ type="text"
145
+ id="memory-query"
146
+ placeholder="Search memory…"
147
+ autocomplete="off"
148
+ />
149
+ <button type="submit" id="memory-search-btn">Search</button>
150
+ </form>
151
+ <ul class="memory-results" id="memory-results"></ul>
152
+ <textarea
153
+ id="memory-entry"
154
+ rows="2"
155
+ placeholder="Save a note to memory…"
156
+ ></textarea>
157
+ <button type="button" id="memory-save-btn" class="btn-block">Save to memory</button>
158
+ <button type="button" id="memory-import-btn" class="btn-block">
159
+ Import from other AI tools…
160
+ </button>
161
+ <p class="hint" id="memory-hint"></p>
162
+ </section>
163
+ </aside>
164
+
165
+ <section class="chat">
166
+ <!-- Inert template: cloned into #messages by renderWelcome() so the
167
+ welcome markup lives in exactly one place and survives the
168
+ innerHTML clears in newChat()/openSession(). -->
169
+ <template id="welcome-template">
170
+ <div class="chat-welcome" id="chat-welcome">
171
+ <div class="chat-greeting-row">
172
+ <div class="glyph">✦</div>
173
+ <div class="title" id="chat-greeting">Hello</div>
174
+ </div>
175
+ <div class="sub">
176
+ Ask anything — or start with one of these.
177
+ </div>
178
+ <div class="chat-quick-actions">
179
+ <button class="chat-quick-pill" type="button" data-quick="Write a ">
180
+ <span class="qp-ic">✎</span>Write code
181
+ </button>
182
+ <button class="chat-quick-pill" type="button" data-quick="Explain how ">
183
+ <span class="qp-ic">✦</span>Explain a concept
184
+ </button>
185
+ <button
186
+ class="chat-quick-pill"
187
+ type="button"
188
+ data-quick="Help me debug this error:&#10;&#10;"
189
+ >
190
+ <span class="qp-ic">🐛</span>Debug an error
191
+ </button>
192
+ <button
193
+ class="chat-quick-pill"
194
+ type="button"
195
+ data-quick="Compare two approaches to "
196
+ >
197
+ <span class="qp-ic">⇄</span>Weigh two options
198
+ </button>
199
+ <button
200
+ class="chat-quick-pill"
201
+ type="button"
202
+ data-quick="Help me plan "
203
+ >
204
+ <span class="qp-ic">⊞</span>Plan a project
205
+ </button>
206
+ </div>
207
+ <div class="hints">
208
+ Enter to send · Shift+Enter for a newline · the discovery lane adds
209
+ two extra paths to every answer
210
+ </div>
211
+ </div>
212
+ </template>
213
+ <div class="messages" id="messages" aria-live="polite"></div>
214
+ <form class="composer" id="composer">
215
+ <textarea
216
+ id="prompt"
217
+ rows="2"
218
+ placeholder="Message AEGIS… (Enter to send, Shift+Enter for a newline)"
219
+ ></textarea>
220
+ <div class="composer-side">
221
+ <label
222
+ class="flow-toggle"
223
+ for="explore-toggle"
224
+ title="After every answer, send the AI down two extra paths — an alternative angle and an unexpected discovery — shown as a horizontal discovery lane."
225
+ >
226
+ <input type="checkbox" id="explore-toggle" checked />
227
+ <span>discovery lane</span>
228
+ </label>
229
+ <button type="submit" id="send">Send</button>
230
+ </div>
231
+ </form>
232
+ </section>
233
+ </main>
234
+
235
+ <!-- Memory inspector: full-viewport translucent overlay opened from the
236
+ sidebar Memory heading. Markup is static and populated by
237
+ renderMemoryOverlay() — this renderer runs under CSP `script-src 'self'`,
238
+ so inline handlers would be dropped silently. -->
239
+ <div class="memory-overlay" id="memory-overlay" hidden>
240
+ <div class="memory-backdrop" id="memory-backdrop"></div>
241
+ <div
242
+ class="memory-panel"
243
+ role="dialog"
244
+ aria-modal="true"
245
+ aria-labelledby="memory-panel-title"
246
+ >
247
+ <header class="memory-panel-head">
248
+ <h2 id="memory-panel-title">Memory</h2>
249
+ <span class="memory-count" id="memory-count"></span>
250
+ <div class="spacer"></div>
251
+ <button type="button" id="memory-close" class="ghost-btn" title="Close (Esc)">
252
+ Close
253
+ </button>
254
+ </header>
255
+
256
+ <form class="memory-filters" id="memory-filters">
257
+ <input
258
+ type="text"
259
+ id="memory-overlay-query"
260
+ placeholder="Filter by text, tag, topic or source…"
261
+ autocomplete="off"
262
+ />
263
+ <button type="submit">Filter</button>
264
+ <button type="button" id="memory-filters-clear" class="ghost-btn">Clear</button>
265
+ </form>
266
+
267
+ <div class="memory-chips" id="memory-chips"></div>
268
+
269
+ <div class="memory-scroll">
270
+ <ul class="memory-list" id="memory-list"></ul>
271
+ </div>
272
+
273
+ <div class="memory-actions">
274
+ <textarea
275
+ id="memory-overlay-entry"
276
+ rows="2"
277
+ placeholder="Save a note to memory…"
278
+ ></textarea>
279
+ <button type="button" id="memory-overlay-save" class="btn-block">
280
+ Save to memory
281
+ </button>
282
+ </div>
283
+ </div>
284
+ </div>
285
+
286
+ <script src="max-tokens.js"></script>
287
+ <script src="app.js"></script>
288
+ </body>
289
+ </html>
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Pure per-model max-tokens ceiling math (plan Phase 5, product-plan §6.3).
5
+ * Standalone from app.js so it's requireable from a plain Node test without
6
+ * pulling in DOM/window.aegis — app.js only calls into it.
7
+ */
8
+
9
+ const FLAT_CEILING = 300000;
10
+
11
+ function maxTokensCeiling(meta) {
12
+ const raw = meta && Number(meta.max_output);
13
+ return Number.isFinite(raw) && raw > 0 ? Math.min(FLAT_CEILING, raw) : FLAT_CEILING;
14
+ }
15
+
16
+ if (typeof module !== 'undefined' && module.exports) {
17
+ module.exports = { maxTokensCeiling, FLAT_CEILING };
18
+ }