@alashi/cli 0.14.0 → 0.15.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.
- package/assets/v1/chat.js +249 -55
- package/assets/v1/system.css +40 -0
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +272 -78
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{store-DoAGOynU.mjs → store-dipRcfKX.mjs} +815 -47
- package/dist/store-dipRcfKX.mjs.map +1 -0
- package/package.json +3 -3
- package/templates/basic-app/index.mjs +1 -1
- package/templates/basic-app/package.json +1 -1
- package/dist/store-DoAGOynU.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AIProvider, AppContext, AppDefinition, AppManifest, AppSdkError, ConfigObject, ModelTokenUsage } from "@alashi/apps-sdk";
|
|
1
|
+
import { AIProvider, AgentEvent, AppContext, AppDefinition, AppManifest, AppSdkError, AppUsageSummary, ApprovalDecision, ApprovalScope, ConfigObject, ModelTokenUsage, UsageDay, UsageMonth, UsageQuery, UsageTurn } from "@alashi/apps-sdk";
|
|
2
2
|
import { Context, Hono, MiddlewareHandler } from "hono";
|
|
3
3
|
//#region src/sources.d.ts
|
|
4
4
|
type AppSourceSpec = {
|
|
@@ -81,6 +81,41 @@ interface GlobalConfig {
|
|
|
81
81
|
* A cap is enforcement, so it lives where only the host can set it.
|
|
82
82
|
*/
|
|
83
83
|
budgets?: Record<string, AppBudget>;
|
|
84
|
+
/**
|
|
85
|
+
* Seconds before a pending tool approval is auto-denied; default 300.
|
|
86
|
+
* Host policy like `budgets`: an app can never extend its own window.
|
|
87
|
+
*/
|
|
88
|
+
approvalTimeoutSeconds?: number;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* One tool-approval request, as surfaced to the user and logged in
|
|
92
|
+
* `apps/<name>/approvals.json`. `conversationId` is present for chat-born
|
|
93
|
+
* approvals; a cron/app-route approval has none and only shows up in the
|
|
94
|
+
* host-wide pending list.
|
|
95
|
+
*/
|
|
96
|
+
interface ApprovalRecord {
|
|
97
|
+
approvalId: string;
|
|
98
|
+
app: string;
|
|
99
|
+
conversationId?: string;
|
|
100
|
+
tool: string;
|
|
101
|
+
input: unknown;
|
|
102
|
+
requestedAt: string;
|
|
103
|
+
expiresAt: string;
|
|
104
|
+
status: "pending" | "allowed" | "denied" | "timeout";
|
|
105
|
+
decidedAt?: string;
|
|
106
|
+
scope?: ApprovalScope;
|
|
107
|
+
}
|
|
108
|
+
/** The persisted approval decision log for an app (capped, oldest dropped first). */
|
|
109
|
+
interface ApprovalLog {
|
|
110
|
+
approvals: ApprovalRecord[];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Always-allow grants for an app's ask-tier tools (`apps/<name>/grants.json`).
|
|
114
|
+
* OS bookkeeping like jobs.json — deliberately not a config.json key, which
|
|
115
|
+
* would restart the app (dropping its warm session) on every grant.
|
|
116
|
+
*/
|
|
117
|
+
interface GrantsState {
|
|
118
|
+
tools: string[];
|
|
84
119
|
}
|
|
85
120
|
interface Conversation {
|
|
86
121
|
id: string;
|
|
@@ -106,33 +141,6 @@ interface JobState {
|
|
|
106
141
|
lastRun: Record<string, string>;
|
|
107
142
|
runs: JobRun[];
|
|
108
143
|
}
|
|
109
|
-
/** Tokens and cost one model consumed within a usage bucket (a day or a month). */
|
|
110
|
-
interface ModelUsageTotals {
|
|
111
|
-
inputTokens: number;
|
|
112
|
-
outputTokens: number;
|
|
113
|
-
cacheReadInputTokens: number;
|
|
114
|
-
cacheCreationInputTokens: number;
|
|
115
|
-
costUsd: number;
|
|
116
|
-
}
|
|
117
|
-
/** One UTC day of AI spend for an app. */
|
|
118
|
-
interface UsageDay {
|
|
119
|
-
/** UTC calendar day, `YYYY-MM-DD`. */
|
|
120
|
-
date: string;
|
|
121
|
-
/** Sum of the `costUsd` the provider reported for that day's turns. */
|
|
122
|
-
costUsd: number;
|
|
123
|
-
/** Turns that reported cost or token usage (turns without either are not counted). */
|
|
124
|
-
turns: number;
|
|
125
|
-
/** Per-model token/cost totals, keyed by the engine's model id. Absent for days recorded before token metering. */
|
|
126
|
-
models?: Record<string, ModelUsageTotals>;
|
|
127
|
-
}
|
|
128
|
-
/** One UTC calendar month of AI spend; months are never pruned. */
|
|
129
|
-
interface UsageMonth {
|
|
130
|
-
/** UTC calendar month, `YYYY-MM`. */
|
|
131
|
-
month: string;
|
|
132
|
-
costUsd: number;
|
|
133
|
-
turns: number;
|
|
134
|
-
models?: Record<string, ModelUsageTotals>;
|
|
135
|
-
}
|
|
136
144
|
/**
|
|
137
145
|
* Host-side AI spend for an app: daily series (oldest first, trimmed to the
|
|
138
146
|
* retention window) plus monthly rollups that survive daily pruning so
|
|
@@ -143,6 +151,19 @@ interface UsageState {
|
|
|
143
151
|
days: UsageDay[];
|
|
144
152
|
months?: UsageMonth[];
|
|
145
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* One metered AI turn, as stored on a single line of `apps/<name>/turns.jsonl`
|
|
156
|
+
* — the SDK's `UsageTurn`, which is exactly what `ctx.usage.turns()` returns.
|
|
157
|
+
* Kept under a host name because the ledger, not the SDK, is where these lines
|
|
158
|
+
* live.
|
|
159
|
+
*
|
|
160
|
+
* The append-only ledger `usage.json` is a fold over: it carries enough to
|
|
161
|
+
* reproduce every day/month bucket (cost *and* per-model tokens) plus the
|
|
162
|
+
* session attribution the aggregates throw away. `sessionId`, `model`, and
|
|
163
|
+
* `modelUsage` are omitted when the engine did not report them; `costUsd` is
|
|
164
|
+
* always present and is `0` for a turn that reported tokens but no cost.
|
|
165
|
+
*/
|
|
166
|
+
type TurnRecord = UsageTurn;
|
|
146
167
|
/** A long-lived bearer credential; only the sha256 of the secret is stored. */
|
|
147
168
|
interface AuthTokenRecord {
|
|
148
169
|
id: string;
|
|
@@ -194,7 +215,10 @@ declare class Store {
|
|
|
194
215
|
appRecordPath(name: string): string;
|
|
195
216
|
appChatStatePath(name: string): string;
|
|
196
217
|
appJobStatePath(name: string): string;
|
|
218
|
+
appApprovalLogPath(name: string): string;
|
|
219
|
+
appGrantsPath(name: string): string;
|
|
197
220
|
appUsagePath(name: string): string;
|
|
221
|
+
appTurnsPath(name: string): string;
|
|
198
222
|
registryCachePath(name: string): string;
|
|
199
223
|
readGlobalConfig(): Promise<GlobalConfig>;
|
|
200
224
|
writeGlobalConfig(config: GlobalConfig): Promise<void>;
|
|
@@ -204,10 +228,28 @@ declare class Store {
|
|
|
204
228
|
writeAppConfig(name: string, config: ConfigObject): Promise<void>;
|
|
205
229
|
readChatState(name: string): Promise<ChatState>;
|
|
206
230
|
writeChatState(name: string, state: ChatState): Promise<void>;
|
|
231
|
+
readApprovalLog(name: string): Promise<ApprovalLog>;
|
|
232
|
+
writeApprovalLog(name: string, log: ApprovalLog): Promise<void>;
|
|
233
|
+
readGrants(name: string): Promise<GrantsState>;
|
|
234
|
+
writeGrants(name: string, state: GrantsState): Promise<void>;
|
|
207
235
|
readJobState(name: string): Promise<JobState>;
|
|
208
236
|
writeJobState(name: string, state: JobState): Promise<void>;
|
|
209
237
|
readUsageState(name: string): Promise<UsageState>;
|
|
210
238
|
writeUsageState(name: string, state: UsageState): Promise<void>;
|
|
239
|
+
/** Appends one line to the app's turn ledger, creating the container if needed. */
|
|
240
|
+
appendTurnRecord(name: string, record: TurnRecord): Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* Every parseable line of the app's turn ledger, in file order (oldest
|
|
243
|
+
* first); an absent file reads as no turns.
|
|
244
|
+
*
|
|
245
|
+
* An append-only log written across crashes and hand edits will eventually
|
|
246
|
+
* contain a truncated or malformed line. One bad line must cost only itself,
|
|
247
|
+
* so unparseable lines — and lines without an `at` timestamp, which nothing
|
|
248
|
+
* downstream could place in time — are skipped rather than thrown on.
|
|
249
|
+
*/
|
|
250
|
+
readTurnRecords(name: string): Promise<TurnRecord[]>;
|
|
251
|
+
/** Replaces the app's turn ledger atomically (tmp file + rename), for compaction. */
|
|
252
|
+
writeTurnRecords(name: string, records: TurnRecord[]): Promise<void>;
|
|
211
253
|
get authStatePath(): string;
|
|
212
254
|
readAuthState(): Promise<AuthState>;
|
|
213
255
|
writeAuthState(state: AuthState): Promise<void>;
|
|
@@ -332,72 +374,131 @@ declare const USAGE_RETENTION_DAYS = 90;
|
|
|
332
374
|
declare function utcDay(at?: Date): string;
|
|
333
375
|
/** Money for humans: sub-dollar spend needs the extra digits, larger sums don't. */
|
|
334
376
|
declare function formatUsd(value: number): string;
|
|
335
|
-
/** One turn's metering as reported by the engine;
|
|
377
|
+
/** One turn's metering as reported by the engine; every part may be missing. */
|
|
336
378
|
interface TurnUsage {
|
|
337
379
|
costUsd?: number;
|
|
338
380
|
/** Per-turn token/cost deltas keyed by model id (provider-neutral). */
|
|
339
381
|
modelUsage?: Record<string, ModelTokenUsage>;
|
|
382
|
+
/** Provider session the turn belonged to, for the per-turn ledger. */
|
|
383
|
+
sessionId?: string;
|
|
384
|
+
/** Model the session ran on, as reported by the engine's session event. */
|
|
385
|
+
model?: string;
|
|
340
386
|
}
|
|
341
|
-
/**
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
* through `ctx.ai`, so an app that tracks its own costs elsewhere can be
|
|
363
|
-
* unrecorded here while still reporting real spend of its own.
|
|
364
|
-
*/
|
|
365
|
-
recorded: boolean;
|
|
366
|
-
/** Daily series, oldest first; days with no spend are absent. */
|
|
367
|
-
days: UsageDay[];
|
|
368
|
-
/** Monthly rollups, oldest first; never pruned, so trends outlive the daily window. */
|
|
369
|
-
months: UsageMonth[];
|
|
370
|
-
}
|
|
387
|
+
/**
|
|
388
|
+
* Filters for {@link UsageRecorder.turns}; both are optional and ANDed. The
|
|
389
|
+
* SDK's `UsageQuery` — the same object an app passes to `ctx.usage.turns()`,
|
|
390
|
+
* which is this reader with the app's own name already bound.
|
|
391
|
+
*/
|
|
392
|
+
type TurnQuery = UsageQuery;
|
|
393
|
+
/**
|
|
394
|
+
* A summary of an app's recorded spend, as served by GET
|
|
395
|
+
* /api/apps/:name/usage and returned by `ctx.usage.summary()` — the SDK's
|
|
396
|
+
* `AppUsageSummary`, aliased rather than restated so the endpoint, the
|
|
397
|
+
* dashboard, and the app contract can never drift apart.
|
|
398
|
+
*
|
|
399
|
+
* The field that carries meaning beyond its type is `recorded`: it says
|
|
400
|
+
* whether the host has ever metered a turn for this app (monthly rollups
|
|
401
|
+
* persist, so it survives the daily retention window). False means "no data at
|
|
402
|
+
* all" — not the same thing as a measured zero, and never to be rendered as
|
|
403
|
+
* `$0.0000`. The host meters only sessions an app opens through `ctx.ai`, so an
|
|
404
|
+
* app that tracks its own costs elsewhere can be unrecorded here while still
|
|
405
|
+
* reporting real spend of its own.
|
|
406
|
+
*/
|
|
407
|
+
type UsageSummary = AppUsageSummary;
|
|
371
408
|
/**
|
|
372
409
|
* Per-app AI spend and token usage, persisted as OS bookkeeping in the app
|
|
373
|
-
* container
|
|
374
|
-
*
|
|
375
|
-
*
|
|
410
|
+
* container next to jobs.json and chat.json, in two files:
|
|
411
|
+
*
|
|
412
|
+
* - `apps/<name>/turns.jsonl` — the ledger: one line per metered turn,
|
|
413
|
+
* append-only, oldest first, carrying the session attribution the
|
|
414
|
+
* aggregates throw away.
|
|
415
|
+
* - `apps/<name>/usage.json` — a fold over that ledger: a per-UTC-day series
|
|
416
|
+
* trimmed to the retention window, plus per-month rollups kept forever.
|
|
417
|
+
*
|
|
418
|
+
* The two are written together inside one per-app queue, so a turn can never
|
|
419
|
+
* land in one and not the other, and concurrent turns can neither lose an
|
|
420
|
+
* update nor interleave a half-written line. Each app has its own queue, so a
|
|
421
|
+
* slow write for one app never delays another.
|
|
376
422
|
*
|
|
377
423
|
* Cost and per-model tokens arrive from the `result` event, whose fields the
|
|
378
424
|
* SDK contract marks optional: engines that report neither simply contribute
|
|
379
|
-
* nothing.
|
|
380
|
-
* update, and each app has its own queue so a slow write for one app never
|
|
381
|
-
* delays another.
|
|
425
|
+
* nothing.
|
|
382
426
|
*/
|
|
383
427
|
declare class UsageRecorder {
|
|
384
428
|
private readonly store;
|
|
385
429
|
private readonly retentionDays;
|
|
386
|
-
/** Serializes usage.json read-modify-write per app. */
|
|
430
|
+
/** Serializes the usage.json read-modify-write and ledger append per app. */
|
|
387
431
|
private readonly queues;
|
|
432
|
+
/** Apps whose ledger has already been compacted in this process. */
|
|
433
|
+
private readonly compacted;
|
|
388
434
|
constructor(store: Store, retentionDays?: number);
|
|
389
435
|
/**
|
|
390
|
-
*
|
|
391
|
-
* and month of `at`. A missing, non-finite, or
|
|
392
|
-
* ignored; a turn that reports neither valid cost nor
|
|
393
|
-
* not counted and nothing is written, so a
|
|
394
|
-
* cannot corrupt the totals.
|
|
436
|
+
* Appends the turn to the app's ledger and adds its cost and token usage to
|
|
437
|
+
* the totals for the UTC day and month of `at`. A missing, non-finite, or
|
|
438
|
+
* negative `costUsd` is ignored; a turn that reports neither valid cost nor
|
|
439
|
+
* any model usage is not counted and nothing is written at all, so a
|
|
440
|
+
* provider that omits metering cannot corrupt the totals.
|
|
441
|
+
*
|
|
442
|
+
* Both writes happen in the same queued unit of work, ledger first: if the
|
|
443
|
+
* aggregate write then fails, the ledger is *ahead* of usage.json and
|
|
444
|
+
* `rebuild()` can recover the turn. The other order would lose it.
|
|
395
445
|
*/
|
|
396
446
|
record(appName: string, turn: TurnUsage, at?: Date): Promise<void>;
|
|
397
447
|
/** The app's recorded usage, oldest first, with expired days filtered out. */
|
|
398
448
|
read(appName: string, at?: Date): Promise<Required<UsageState>>;
|
|
399
449
|
/** Today's spend plus the daily/monthly series, for the dashboard and the usage endpoints. */
|
|
400
450
|
summary(appName: string, at?: Date): Promise<UsageSummary>;
|
|
451
|
+
/**
|
|
452
|
+
* The app's metered turns, oldest first, with expired lines excluded.
|
|
453
|
+
*
|
|
454
|
+
* `since` is an inclusive lower bound compared lexically against the ISO
|
|
455
|
+
* `at` (so a plain `YYYY-MM-DD` works as "from that day on"), `sessionId`
|
|
456
|
+
* narrows to one provider session, and both are ANDed. This is the one
|
|
457
|
+
* reader for the ledger: everything that needs per-turn detail goes through
|
|
458
|
+
* it rather than parsing the file itself.
|
|
459
|
+
*/
|
|
460
|
+
turns(appName: string, query?: TurnQuery, at?: Date): Promise<TurnRecord[]>;
|
|
461
|
+
/**
|
|
462
|
+
* Rewrites the app's ledger without the lines that have aged out of the
|
|
463
|
+
* retention window (the same window usage.json days use). Unparseable lines
|
|
464
|
+
* are dropped by the same rewrite, since only parsed records are written
|
|
465
|
+
* back.
|
|
466
|
+
*
|
|
467
|
+
* Runs inside the per-app queue, so it can never race a turn being
|
|
468
|
+
* appended. Pure bookkeeping: callers should treat a failure as noise, not
|
|
469
|
+
* as a reason to fail whatever they were doing.
|
|
470
|
+
*/
|
|
471
|
+
compact(appName: string, at?: Date): Promise<void>;
|
|
472
|
+
/**
|
|
473
|
+
* Rebuilds usage.json from turns.jsonl, for when the two have drifted apart
|
|
474
|
+
* (a lost write, a crash mid-fold, a hand edit). The result is exactly what
|
|
475
|
+
* the incremental fold in `record()` would have produced from the same
|
|
476
|
+
* lines: same day and month buckets, same turn counts, same per-model
|
|
477
|
+
* totals, same rounding.
|
|
478
|
+
*
|
|
479
|
+
* Caveat, by construction: the ledger is pruned at `retentionDays` but
|
|
480
|
+
* usage.json months are kept forever, so months the ledger no longer covers
|
|
481
|
+
* cannot be recomputed. Those keep their existing rollup and only the
|
|
482
|
+
* months the ledger does cover are replaced — a rebuild never silently
|
|
483
|
+
* erases older history. The one month that is *partially* covered (the one
|
|
484
|
+
* the retention cutoff falls in) is replaced by its in-window part, which is
|
|
485
|
+
* all the ledger can still account for.
|
|
486
|
+
*
|
|
487
|
+
* Returns the state it wrote.
|
|
488
|
+
*/
|
|
489
|
+
rebuild(appName: string, at?: Date): Promise<Required<UsageState>>;
|
|
490
|
+
/** The oldest UTC day still inside the retention window at `at`. */
|
|
491
|
+
private cutoff;
|
|
492
|
+
private inWindow;
|
|
493
|
+
/** The compaction body; assumes it is already inside the app's queue. */
|
|
494
|
+
private compactNow;
|
|
495
|
+
/**
|
|
496
|
+
* Trims the ledger on the app's first append of the process, so a host that
|
|
497
|
+
* is never restarted still sheds expired lines. Compaction is bookkeeping
|
|
498
|
+
* and must never break a turn, so a failure is swallowed — the next process
|
|
499
|
+
* tries again, and meanwhile `turns()` filters expired lines out anyway.
|
|
500
|
+
*/
|
|
501
|
+
private compactOnce;
|
|
401
502
|
private apply;
|
|
402
503
|
/**
|
|
403
504
|
* One-time migration for files written before monthly rollups existed:
|
|
@@ -629,6 +730,78 @@ interface ResolvedApp {
|
|
|
629
730
|
/** Finds an app by name across configured registries (refreshing caches). */
|
|
630
731
|
declare function resolveApp(store: Store, appName: string): Promise<ResolvedApp>;
|
|
631
732
|
//#endregion
|
|
733
|
+
//#region src/approvals.d.ts
|
|
734
|
+
type ApprovalRequired = Extract<AgentEvent, {
|
|
735
|
+
type: "approval_required";
|
|
736
|
+
}>;
|
|
737
|
+
type ApprovalResolved = Extract<AgentEvent, {
|
|
738
|
+
type: "approval_resolved";
|
|
739
|
+
}>;
|
|
740
|
+
/**
|
|
741
|
+
* Host-wide bookkeeping for interactive tool approvals. Sessions wrapped by
|
|
742
|
+
* `superviseSession` register every `approval_required` here, so chat turns
|
|
743
|
+
* and cron jobs alike show up in one pending list; decisions flow back through
|
|
744
|
+
* `respond()` to the provider, and every outcome is appended to the app's
|
|
745
|
+
* `approvals.json` log. The registry also arms the host's timeout policy:
|
|
746
|
+
* a request nobody decides is denied after {@link DEFAULT_APPROVAL_TIMEOUT_MS}
|
|
747
|
+
* (overridable via `approvalTimeoutSeconds` in the global config — host
|
|
748
|
+
* policy, like budgets).
|
|
749
|
+
*
|
|
750
|
+
* Always-allow grants (`grants.json`) are written here too, so ask→allow
|
|
751
|
+
* promotion stays inside manifest bounds in one place.
|
|
752
|
+
*/
|
|
753
|
+
declare class ApprovalRegistry {
|
|
754
|
+
#private;
|
|
755
|
+
constructor(store: Store, options?: {
|
|
756
|
+
timeoutMs?: number;
|
|
757
|
+
});
|
|
758
|
+
/** Applies the host-config timeout override; safe to fire-and-forget at boot. */
|
|
759
|
+
init(): Promise<void>;
|
|
760
|
+
/** Registers a provider-born approval request and arms the auto-deny timer. */
|
|
761
|
+
track(app: string, event: ApprovalRequired, respond: (decision: ApprovalDecision) => Promise<void>): void;
|
|
762
|
+
/** Attaches the conversation a chat-born approval belongs to (cron ones have none). */
|
|
763
|
+
annotate(approvalId: string, fields: {
|
|
764
|
+
conversationId: string;
|
|
765
|
+
}): void;
|
|
766
|
+
/** The pending or settled record, for endpoint lookups. */
|
|
767
|
+
get(approvalId: string): ApprovalRecord | undefined;
|
|
768
|
+
/** Snapshots of pending records, optionally narrowed; newest last. */
|
|
769
|
+
pending(filter?: {
|
|
770
|
+
app?: string;
|
|
771
|
+
conversationId?: string;
|
|
772
|
+
}): ApprovalRecord[];
|
|
773
|
+
/**
|
|
774
|
+
* Applies a user decision: settles the record, then forwards the decision to
|
|
775
|
+
* the session that is suspended on it. Returns 'unknown' for an id this host
|
|
776
|
+
* never saw and 'resolved' for one already decided, so the endpoint can tell
|
|
777
|
+
* 404 from 409.
|
|
778
|
+
*/
|
|
779
|
+
respond(approvalId: string, decision: ApprovalDecision): "ok" | "unknown" | "resolved";
|
|
780
|
+
/**
|
|
781
|
+
* Observes a provider-side resolution (session closed, interrupt) arriving
|
|
782
|
+
* through the event stream. A registry-initiated decision already settled
|
|
783
|
+
* the record, so this is a no-op for it.
|
|
784
|
+
*/
|
|
785
|
+
resolved(event: ApprovalResolved): void;
|
|
786
|
+
/**
|
|
787
|
+
* Marks an approval whose session's event stream ended without a resolution
|
|
788
|
+
* (crash, abrupt close) as denied, so nothing stays pending forever.
|
|
789
|
+
*/
|
|
790
|
+
abandon(approvalId: string): void;
|
|
791
|
+
/** Reads the app's always-allow grants. */
|
|
792
|
+
grants(app: string): Promise<string[]>;
|
|
793
|
+
/**
|
|
794
|
+
* Persists an always-allow grant. Validated against the manifest's askTools:
|
|
795
|
+
* a grant can promote ask→allow but never allow a tool the manifest did not
|
|
796
|
+
* declare askable.
|
|
797
|
+
*/
|
|
798
|
+
addGrant(app: string, tool: string, askTools: string[]): Promise<void>;
|
|
799
|
+
/** Clears timers and denies everything still pending (host shutdown). */
|
|
800
|
+
close(): void;
|
|
801
|
+
/** Resolves when all queued approvals.json writes have landed (tests). */
|
|
802
|
+
flush(): Promise<void>;
|
|
803
|
+
}
|
|
804
|
+
//#endregion
|
|
632
805
|
//#region src/runtime.d.ts
|
|
633
806
|
/**
|
|
634
807
|
* Builds the AppContext for an installed app: merges the config layers
|
|
@@ -641,10 +814,13 @@ declare function resolveApp(store: Store, appName: string): Promise<ResolvedApp>
|
|
|
641
814
|
* while required keys are missing the scoped provider fails closed.
|
|
642
815
|
*
|
|
643
816
|
* When a `usage` recorder is supplied, every session opened through the
|
|
644
|
-
* returned context reports its per-turn cost to it,
|
|
645
|
-
*
|
|
817
|
+
* returned context reports its per-turn cost to it, the app's host-set daily
|
|
818
|
+
* spend cap (if any) is enforced on every createSession, and `ctx.usage` reads
|
|
819
|
+
* back the app's own ledger. Without one there is no metering, no cap, and
|
|
820
|
+
* `ctx.usage` answers "nothing recorded" — the member is required by the
|
|
821
|
+
* contract, so it is always present.
|
|
646
822
|
*/
|
|
647
|
-
declare function buildAppContext(store: Store, manifest: AppManifest, provider: AIProvider, usage?: UsageRecorder): Promise<AppContext>;
|
|
823
|
+
declare function buildAppContext(store: Store, manifest: AppManifest, provider: AIProvider, usage?: UsageRecorder, approvals?: ApprovalRegistry): Promise<AppContext>;
|
|
648
824
|
//#endregion
|
|
649
825
|
//#region src/scheduler.d.ts
|
|
650
826
|
interface SchedulableApp {
|
|
@@ -733,14 +909,32 @@ interface ServerOptions {
|
|
|
733
909
|
* GET /api/apps/:name/usage recorded AI spend: today's total, a daily series,
|
|
734
910
|
* per-model token totals, monthly rollups,
|
|
735
911
|
* `recorded`, and the budget status
|
|
912
|
+
* GET /api/apps/:name/turns the per-turn ledger that summary folds: `{ turns }`,
|
|
913
|
+
* oldest first, each with `at`, `costUsd`, and the
|
|
914
|
+
* session/model attribution the buckets drop.
|
|
915
|
+
* ?since=<timestamp> (inclusive) and ?session=<id>
|
|
916
|
+
* narrow it, ANDed; an unreadable `since` is a 400
|
|
736
917
|
* GET /api/apps/:name/budget today's spend against the app's daily cap,
|
|
737
918
|
* plus `recorded`
|
|
738
919
|
* PUT /api/apps/:name/budget { dailyUsd: number | null } -> set or clear the cap
|
|
739
920
|
* (a host setting; apps cannot set their own)
|
|
740
|
-
* POST /api/apps/:name/chat { message, conversationId? } ->
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
-
*
|
|
921
|
+
* POST /api/apps/:name/chat { message, conversationId? } -> 202 { conversationId };
|
|
922
|
+
* the turn runs detached and its AgentEvents are published
|
|
923
|
+
* on the conversation's event bus (omit conversationId to
|
|
924
|
+
* start a new conversation; the id is also echoed in the
|
|
925
|
+
* x-conversation-id response header; 402 when the app is
|
|
926
|
+
* over its daily spend cap)
|
|
927
|
+
* GET /api/apps/:name/chat/:conversationId/events standing SSE from the conversation
|
|
928
|
+
* bus: replay from Last-Event-ID (or ?lastEventId=), then
|
|
929
|
+
* live; a scrolled-out id gets a `resync` event first
|
|
930
|
+
* GET /api/apps/:name/chat/:conversationId/pending-approvals reconnect snapshot of
|
|
931
|
+
* undecided tool approvals for this conversation
|
|
932
|
+
* POST /api/apps/:name/chat/:conversationId/approvals/:approvalId
|
|
933
|
+
* { behavior: "allow"|"deny", scope?, message? } -> decide a
|
|
934
|
+
* pending approval (scope "always" persists a grant);
|
|
935
|
+
* 404 unknown/expired, 409 already decided
|
|
936
|
+
* GET /api/approvals host-wide pending tool approvals (chat and cron alike)
|
|
937
|
+
* POST /api/approvals/:approvalId decide a pending approval regardless of source
|
|
744
938
|
* GET /api/apps/:name/chat/conversations conversations, most recent first
|
|
745
939
|
* POST /api/apps/:name/chat/conversations { sessionId?, title? } -> create a conversation,
|
|
746
940
|
* optionally adopting an existing provider session (e.g. an
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/sources.ts","../src/store.ts","../src/auth.ts","../src/usage.ts","../src/budget.ts","../src/compat.ts","../src/installer.ts","../src/loader.ts","../src/portability.ts","../src/registry.ts","../src/runtime.ts","../src/scheduler.ts","../src/server.ts"],"mappings":";;;KAQY;EACN;EAAa;EAAa;;EAC1B;EAAe;;;KAGT,YAAY;EAAkB;EAAkB;;iBAE5C,eAAe,cAAc;;iBAwBvB,YAAY,MAAM,eAAe,kBAAkB;;iBAanD,aAAa,MAAM,eAAe,kBAAkB;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/sources.ts","../src/store.ts","../src/auth.ts","../src/usage.ts","../src/budget.ts","../src/compat.ts","../src/installer.ts","../src/loader.ts","../src/portability.ts","../src/registry.ts","../src/approvals.ts","../src/runtime.ts","../src/scheduler.ts","../src/server.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as UsageRecorder, C as BudgetExceededError, D as budgetStatusFor, E as budgetStatus, F as createAuthMiddleware, I as isConsoleRequest, L as registerAuthRoutes, M as utcDay, N as AuthService, O as setAppBudget, P as SESSION_COOKIE, R as requiredLevel, S as BUDGET_EXCEEDED_CODE, T as assertWithinBudget, _ as fetchSource, a as EXPORT_FORMAT_VERSION, b as loadApp, c as installApp, d as updateApp, f as addRegistry, g as resolveApp, h as removeRegistry, j as formatUsd, k as USAGE_RETENTION_DAYS, l as installDependencies, m as refreshRegistry, n as createServer, o as exportApp, p as readCachedIndex, r as buildAppContext, s as importApp, t as Store, u as removeApp, v as parseSourceArg, w as appBudget, x as checkSdkCompatibility, y as updateSource } from "./store-
|
|
1
|
+
import { A as UsageRecorder, C as BudgetExceededError, D as budgetStatusFor, E as budgetStatus, F as createAuthMiddleware, I as isConsoleRequest, L as registerAuthRoutes, M as utcDay, N as AuthService, O as setAppBudget, P as SESSION_COOKIE, R as requiredLevel, S as BUDGET_EXCEEDED_CODE, T as assertWithinBudget, _ as fetchSource, a as EXPORT_FORMAT_VERSION, b as loadApp, c as installApp, d as updateApp, f as addRegistry, g as resolveApp, h as removeRegistry, j as formatUsd, k as USAGE_RETENTION_DAYS, l as installDependencies, m as refreshRegistry, n as createServer, o as exportApp, p as readCachedIndex, r as buildAppContext, s as importApp, t as Store, u as removeApp, v as parseSourceArg, w as appBudget, x as checkSdkCompatibility, y as updateSource } from "./store-dipRcfKX.mjs";
|
|
2
2
|
export { AuthService, BUDGET_EXCEEDED_CODE, BudgetExceededError, EXPORT_FORMAT_VERSION, SESSION_COOKIE, Store, USAGE_RETENTION_DAYS, UsageRecorder, addRegistry, appBudget, assertWithinBudget, budgetStatus, budgetStatusFor, buildAppContext, checkSdkCompatibility, createAuthMiddleware, createServer, exportApp, fetchSource, formatUsd, importApp, installApp, installDependencies, isConsoleRequest, loadApp, parseSourceArg, readCachedIndex, refreshRegistry, registerAuthRoutes, removeApp, removeRegistry, requiredLevel, resolveApp, setAppBudget, updateApp, updateSource, utcDay };
|