@adonis-agora/agent 0.48.0 → 0.50.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/providers/agent_provider.d.ts.map +1 -1
  3. package/dist/providers/agent_provider.js +225 -46
  4. package/dist/providers/agent_provider.js.map +1 -1
  5. package/dist/providers/dashboard_provider.js +1 -1
  6. package/dist/providers/dashboard_provider.js.map +1 -1
  7. package/dist/src/agent-loop.d.ts +18 -0
  8. package/dist/src/agent-loop.d.ts.map +1 -1
  9. package/dist/src/agent-loop.js +52 -8
  10. package/dist/src/agent-loop.js.map +1 -1
  11. package/dist/src/agent-service.d.ts +129 -9
  12. package/dist/src/agent-service.d.ts.map +1 -1
  13. package/dist/src/agent-service.js +284 -8
  14. package/dist/src/agent-service.js.map +1 -1
  15. package/dist/src/chat-queue-service.d.ts +153 -0
  16. package/dist/src/chat-queue-service.d.ts.map +1 -0
  17. package/dist/src/chat-queue-service.js +360 -0
  18. package/dist/src/chat-queue-service.js.map +1 -0
  19. package/dist/src/client/chat-client.d.ts +52 -0
  20. package/dist/src/client/chat-client.d.ts.map +1 -1
  21. package/dist/src/client/chat-client.js +51 -2
  22. package/dist/src/client/chat-client.js.map +1 -1
  23. package/dist/src/client/index.d.ts +1 -1
  24. package/dist/src/client/index.d.ts.map +1 -1
  25. package/dist/src/client/index.js +1 -1
  26. package/dist/src/client/index.js.map +1 -1
  27. package/dist/src/client/sse.d.ts +5 -0
  28. package/dist/src/client/sse.d.ts.map +1 -1
  29. package/dist/src/client/sse.js +5 -1
  30. package/dist/src/client/sse.js.map +1 -1
  31. package/dist/src/define_config.d.ts +3 -1
  32. package/dist/src/define_config.d.ts.map +1 -1
  33. package/dist/src/define_config.js.map +1 -1
  34. package/dist/src/durable/agent-run-context.d.ts +6 -0
  35. package/dist/src/durable/agent-run-context.d.ts.map +1 -1
  36. package/dist/src/durable/agent-run-context.js.map +1 -1
  37. package/dist/src/durable/agent-run-workflow.d.ts.map +1 -1
  38. package/dist/src/durable/agent-run-workflow.js +94 -6
  39. package/dist/src/durable/agent-run-workflow.js.map +1 -1
  40. package/dist/src/durable/durable-agent-runner.d.ts +19 -3
  41. package/dist/src/durable/durable-agent-runner.d.ts.map +1 -1
  42. package/dist/src/durable/durable-agent-runner.js +62 -3
  43. package/dist/src/durable/durable-agent-runner.js.map +1 -1
  44. package/dist/src/elicitation.d.ts +12 -0
  45. package/dist/src/elicitation.d.ts.map +1 -1
  46. package/dist/src/elicitation.js +9 -1
  47. package/dist/src/elicitation.js.map +1 -1
  48. package/dist/src/index.d.ts +8 -5
  49. package/dist/src/index.d.ts.map +1 -1
  50. package/dist/src/index.js +7 -4
  51. package/dist/src/index.js.map +1 -1
  52. package/dist/src/react/use-agent-chat.d.ts.map +1 -1
  53. package/dist/src/react/use-agent-chat.js +15 -1
  54. package/dist/src/react/use-agent-chat.js.map +1 -1
  55. package/dist/src/runners/inline-agent-runner.d.ts +30 -6
  56. package/dist/src/runners/inline-agent-runner.d.ts.map +1 -1
  57. package/dist/src/runners/inline-agent-runner.js +117 -21
  58. package/dist/src/runners/inline-agent-runner.js.map +1 -1
  59. package/dist/src/spi/agent-runner.d.ts +20 -1
  60. package/dist/src/spi/agent-runner.d.ts.map +1 -1
  61. package/dist/src/spi/chat-queue.d.ts +133 -0
  62. package/dist/src/spi/chat-queue.d.ts.map +1 -0
  63. package/dist/src/spi/chat-queue.js +48 -0
  64. package/dist/src/spi/chat-queue.js.map +1 -0
  65. package/dist/src/spi/model-catalog.d.ts +13 -0
  66. package/dist/src/spi/model-catalog.d.ts.map +1 -1
  67. package/dist/src/spi/model-catalog.js.map +1 -1
  68. package/dist/src/spi/quota-provider.d.ts +30 -1
  69. package/dist/src/spi/quota-provider.d.ts.map +1 -1
  70. package/dist/src/spi/quota-provider.js +34 -1
  71. package/dist/src/spi/quota-provider.js.map +1 -1
  72. package/dist/src/stores/ledger-quota-provider.d.ts +10 -1
  73. package/dist/src/stores/ledger-quota-provider.d.ts.map +1 -1
  74. package/dist/src/stores/ledger-quota-provider.js +14 -3
  75. package/dist/src/stores/ledger-quota-provider.js.map +1 -1
  76. package/dist/src/stores/lucid-schema.d.ts +8 -6
  77. package/dist/src/stores/lucid-schema.d.ts.map +1 -1
  78. package/dist/src/stores/lucid-schema.js +34 -7
  79. package/dist/src/stores/lucid-schema.js.map +1 -1
  80. package/dist/src/stores/lucid.d.ts +23 -1
  81. package/dist/src/stores/lucid.d.ts.map +1 -1
  82. package/dist/src/stores/lucid.js +192 -0
  83. package/dist/src/stores/lucid.js.map +1 -1
  84. package/dist/src/stream-events.d.ts +17 -0
  85. package/dist/src/stream-events.d.ts.map +1 -1
  86. package/dist/src/testing/chat-queue-store-contract.d.ts +26 -0
  87. package/dist/src/testing/chat-queue-store-contract.d.ts.map +1 -0
  88. package/dist/src/testing/chat-queue-store-contract.js +162 -0
  89. package/dist/src/testing/chat-queue-store-contract.js.map +1 -0
  90. package/dist/src/testing/in-memory-store.d.ts +20 -1
  91. package/dist/src/testing/in-memory-store.d.ts.map +1 -1
  92. package/dist/src/testing/in-memory-store.js +125 -0
  93. package/dist/src/testing/in-memory-store.js.map +1 -1
  94. package/dist/src/testing/index.d.ts +1 -0
  95. package/dist/src/testing/index.d.ts.map +1 -1
  96. package/dist/src/testing/index.js +1 -0
  97. package/dist/src/testing/index.js.map +1 -1
  98. package/dist/src/tool-presentation.d.ts +5 -0
  99. package/dist/src/tool-presentation.d.ts.map +1 -1
  100. package/dist/src/tool-presentation.js +5 -1
  101. package/dist/src/tool-presentation.js.map +1 -1
  102. package/dist/src/types.d.ts +25 -1
  103. package/dist/src/types.d.ts.map +1 -1
  104. package/dist/stubs/database/migrations/create_agent_tables.stub +2 -2
  105. package/package.json +1 -1
@@ -0,0 +1,133 @@
1
+ import type { Actor, MessageAttachment, PageContext } from '../types.js';
2
+ import { type AgentStore } from './agent-store.js';
3
+ /**
4
+ * Why a thread's queue stopped draining. A paused queue keeps its messages; nothing starts until
5
+ * someone resumes it (`POST <base>/threads/:id/queue/resume`, `chat.queue.resume()`).
6
+ *
7
+ * - `run_failed` the turn before it failed — the next message would likely fail the same way,
8
+ * and the person should see the error before more of their messages are spent.
9
+ * - `cancelled` someone pressed Stop. Stop means stop: the queue does not start behind it.
10
+ * An interrupt (`mode: 'interrupt'`) is the exception — its message starts.
11
+ * - `quota_exceeded` the next message's actor is over budget; resuming later retries the check.
12
+ * - `start_failed` the next message could not be started (the runner refused it).
13
+ */
14
+ export type QueuePauseReason = 'run_failed' | 'cancelled' | 'quota_exceeded' | 'start_failed';
15
+ export interface QueuePause {
16
+ reason: QueuePauseReason;
17
+ /** Human-facing detail (the failure, the quota window), when there is one. */
18
+ message?: string;
19
+ /** ISO-8601 instant the queue paused. */
20
+ at: string;
21
+ }
22
+ /**
23
+ * A message a person sent while a turn was still running on the thread, waiting its turn. It is not
24
+ * part of the transcript until it starts: the loop appends it as the turn's user message, exactly as
25
+ * if it had been sent then. Everything a send carries is captured at enqueue time, resolved and
26
+ * checked there (agent, model, attachments), so a queued message starts with no request around it.
27
+ */
28
+ export interface QueuedMessage {
29
+ id: string;
30
+ threadId: string;
31
+ /** Who queued it. The turn it starts runs as this actor. */
32
+ actor: Actor;
33
+ content: string;
34
+ attachments?: MessageAttachment[];
35
+ agentName?: string;
36
+ model?: string;
37
+ pageContext?: PageContext;
38
+ /**
39
+ * Queued by an interrupt (`POST chat { mode: 'interrupt' }`): the running turn was cancelled to
40
+ * make room for it, so the cancel starts it instead of pausing the queue.
41
+ */
42
+ interrupt?: boolean;
43
+ createdAt: string;
44
+ updatedAt: string;
45
+ }
46
+ /** A queued message as the wire shows it — {@link QueuedMessage} without the actor or thread. */
47
+ export interface QueuedMessageView {
48
+ id: string;
49
+ content: string;
50
+ attachments?: MessageAttachment[];
51
+ agentName?: string;
52
+ model?: string;
53
+ interrupt?: boolean;
54
+ createdAt: string;
55
+ updatedAt: string;
56
+ }
57
+ /**
58
+ * A thread's queue: its waiting messages in the order they will run, and whether it is draining.
59
+ * What `GET <base>/threads/:id/queue` answers, what `ThreadDetail.queue` carries, and what every
60
+ * `queue` stream frame snapshots.
61
+ */
62
+ export interface ChatQueueState {
63
+ items: QueuedMessageView[];
64
+ paused: QueuePause | null;
65
+ }
66
+ export interface EnqueueMessageInput {
67
+ threadId: string;
68
+ actor: Actor;
69
+ content: string;
70
+ attachments?: MessageAttachment[];
71
+ agentName?: string;
72
+ model?: string;
73
+ pageContext?: PageContext;
74
+ interrupt?: boolean;
75
+ /** `'tail'` (default) runs it after everything already waiting; `'head'` runs it next. */
76
+ at?: 'tail' | 'head';
77
+ }
78
+ /** What `PATCH <base>/queue/:messageId` may change. An omitted key leaves the field as it is. */
79
+ export interface QueuedMessagePatch {
80
+ content?: string;
81
+ /** `null` drops every attachment. */
82
+ attachments?: MessageAttachment[] | null;
83
+ }
84
+ /**
85
+ * A store that can hold a thread's queue of waiting messages, and admit ONE run per thread at a time.
86
+ *
87
+ * Probed STRUCTURALLY ({@link isChatQueueStore}), like `ThreadTurnReader`: a store that predates it
88
+ * keeps the old behaviour (a send on a busy thread starts a second, concurrent run). All members or
89
+ * none — a queue without the admission primitives cannot be drained safely across processes.
90
+ *
91
+ * Admission is the thread's active run (`activeRunId` on a thread read), compare-and-set:
92
+ * - {@link claimActiveStream} sets it to `runId` only when it is free, already `runId` (a retried
93
+ * claim is idempotent), or held by `replacing` (a handoff from the run that is settling, or a
94
+ * takeover from a holder the runner reports dead). Exactly one of two racing claims wins.
95
+ * - {@link releaseActiveStream} clears it only when `runId` still holds it — so a run that settles
96
+ * after it handed the thread to the next one cannot clear the next one's claim.
97
+ */
98
+ export interface ChatQueueStore {
99
+ enqueueMessage(input: EnqueueMessageInput): Promise<QueuedMessage>;
100
+ /** The thread's waiting messages, in run order (the head first). */
101
+ listQueue(threadId: string): Promise<QueuedMessage[]>;
102
+ getQueuedMessage(id: string): Promise<QueuedMessage | null>;
103
+ /** `null` when there is no such message (it started, or was removed). */
104
+ updateQueuedMessage(id: string, patch: QueuedMessagePatch): Promise<QueuedMessage | null>;
105
+ /** Move a message to `index` (clamped) in its thread's run order. `false` when it is gone. */
106
+ moveQueuedMessage(id: string, index: number): Promise<boolean>;
107
+ /**
108
+ * Remove a message. `false` when it was already gone — which is also how a drain learns that the
109
+ * head it was about to start was deleted under it, so it must be a real conditional delete.
110
+ */
111
+ removeQueuedMessage(id: string): Promise<boolean>;
112
+ /** Remove every waiting message on the thread; answers how many there were. */
113
+ clearQueue(threadId: string): Promise<number>;
114
+ queuePause(threadId: string): Promise<QueuePause | null>;
115
+ setQueuePause(threadId: string, pause: QueuePause | null): Promise<void>;
116
+ /** The run currently holding the thread, or `null`. */
117
+ activeRunForThread(threadId: string): Promise<string | null>;
118
+ claimActiveStream(threadId: string, runId: string, options?: {
119
+ replacing?: string;
120
+ }): Promise<boolean>;
121
+ releaseActiveStream(threadId: string, runId: string): Promise<boolean>;
122
+ }
123
+ /** Whether `store` implements every {@link ChatQueueStore} member. */
124
+ export declare function isChatQueueStore(store: AgentStore): store is AgentStore & ChatQueueStore;
125
+ /**
126
+ * Release the thread `runId` was streaming — conditionally when the store can compare, so a run
127
+ * that already handed the thread to the next queued turn does not clear that turn's claim; the old
128
+ * unconditional clear on a store that cannot.
129
+ */
130
+ export declare function releaseThreadRun(store: AgentStore, threadId: string, runId: string): Promise<void>;
131
+ /** The wire view of a queued message. */
132
+ export declare function queuedMessageView(message: QueuedMessage): QueuedMessageView;
133
+ //# sourceMappingURL=chat-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-queue.d.ts","sourceRoot":"","sources":["../../../src/spi/chat-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { clearActiveRun } from './agent-store.js';
2
+ const CHAT_QUEUE_METHODS = [
3
+ 'enqueueMessage',
4
+ 'listQueue',
5
+ 'getQueuedMessage',
6
+ 'updateQueuedMessage',
7
+ 'moveQueuedMessage',
8
+ 'removeQueuedMessage',
9
+ 'clearQueue',
10
+ 'queuePause',
11
+ 'setQueuePause',
12
+ 'activeRunForThread',
13
+ 'claimActiveStream',
14
+ 'releaseActiveStream',
15
+ ];
16
+ /** Whether `store` implements every {@link ChatQueueStore} member. */
17
+ export function isChatQueueStore(store) {
18
+ const candidate = store;
19
+ return CHAT_QUEUE_METHODS.every((method) => typeof candidate[method] === 'function');
20
+ }
21
+ /**
22
+ * Release the thread `runId` was streaming — conditionally when the store can compare, so a run
23
+ * that already handed the thread to the next queued turn does not clear that turn's claim; the old
24
+ * unconditional clear on a store that cannot.
25
+ */
26
+ export async function releaseThreadRun(store, threadId, runId) {
27
+ if (isChatQueueStore(store)) {
28
+ await store.releaseActiveStream(threadId, runId);
29
+ return;
30
+ }
31
+ await clearActiveRun(store, threadId, runId);
32
+ }
33
+ /** The wire view of a queued message. */
34
+ export function queuedMessageView(message) {
35
+ return {
36
+ id: message.id,
37
+ content: message.content,
38
+ ...(message.attachments !== undefined && message.attachments.length > 0
39
+ ? { attachments: message.attachments }
40
+ : {}),
41
+ ...(message.agentName !== undefined ? { agentName: message.agentName } : {}),
42
+ ...(message.model !== undefined ? { model: message.model } : {}),
43
+ ...(message.interrupt === true ? { interrupt: true } : {}),
44
+ createdAt: message.createdAt,
45
+ updatedAt: message.updatedAt,
46
+ };
47
+ }
48
+ //# sourceMappingURL=chat-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-queue.js","sourceRoot":"","sources":["../../../src/spi/chat-queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAuInE,MAAM,kBAAkB,GAAG;IACzB,gBAAgB;IAChB,WAAW;IACX,kBAAkB;IAClB,qBAAqB;IACrB,mBAAmB;IACnB,qBAAqB;IACrB,YAAY;IACZ,YAAY;IACZ,eAAe;IACf,oBAAoB;IACpB,mBAAmB;IACnB,qBAAqB;CAC+B,CAAC;AAEvD,sEAAsE;AACtE,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,MAAM,SAAS,GAAG,KAA2C,CAAC;IAC9D,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,CAAC;AACvF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAiB,EACjB,QAAgB,EAChB,KAAa;IAEb,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,KAAK,CAAC,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IACD,MAAM,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,iBAAiB,CAAC,OAAsB;IACtD,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;YACrE,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;YACtC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC;AACJ,CAAC"}
@@ -21,9 +21,22 @@ export interface ModelCatalogProviderGroup {
21
21
  label: string;
22
22
  models: ModelCatalogEntry[];
23
23
  }
24
+ /** The agent always runs on one model: the picker shows it and offers no choice. */
25
+ export interface ModelCatalogLock {
26
+ /** The catalog id every turn runs on. */
27
+ model: string;
28
+ /** Why, in words a picker can show ("This assistant always uses GPT-5"). */
29
+ reason?: string;
30
+ }
24
31
  /** What `GET <base>/models` answers. */
25
32
  export interface ModelCatalogView {
26
33
  providers: ModelCatalogProviderGroup[];
34
+ /**
35
+ * Present when the agent is locked to one model. Every turn runs on `locked.model` — a send's own
36
+ * `model` and a thread's pin included — and a send naming another model is refused (`400`). List
37
+ * the other models as unavailable too, so an older client that ignores the lock cannot pick them.
38
+ */
39
+ locked?: ModelCatalogLock;
27
40
  /** The model a turn runs on when nobody picked one; `null` when the provider decides. */
28
41
  default: string | null;
29
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../../../src/spi/model-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAC;AAExE,mCAAmC;AACnC,MAAM,WAAW,iBAAiB;IAChC,oGAAoG;IACpG,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,wGAAwG;IACxG,SAAS,EAAE,OAAO,CAAC;IACnB,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,0DAA0D;AAC1D,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,yBAAyB,EAAE,CAAC;IACvC,yFAAyF;IACzF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC9E;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CAEvE;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,gBAAgB,GAAG,YAAY,CAInF;AAED,sDAAsD;AACtD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,gBAAgB,EACtB,EAAE,EAAE,MAAM,GACT,iBAAiB,GAAG,SAAS,CAM/B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAIvF;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF"}
1
+ {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../../../src/spi/model-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAC;AAExE,mCAAmC;AACnC,MAAM,WAAW,iBAAiB;IAChC,oGAAoG;IACpG,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,wGAAwG;IACxG,SAAS,EAAE,OAAO,CAAC;IACnB,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,0DAA0D;AAC1D,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAED,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,yBAAyB,EAAE,CAAC;IACvC;;;;OAIG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,yFAAyF;IACzF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC9E;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CAEvE;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,gBAAgB,GAAG,YAAY,CAInF;AAED,sDAAsD;AACtD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,gBAAgB,EACtB,EAAE,EAAE,MAAM,GACT,iBAAiB,GAAG,SAAS,CAM/B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAIvF;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"model-catalog.js","sourceRoot":"","sources":["../../../src/spi/model-catalog.ts"],"names":[],"mappings":"AAoDA,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAC,IAAsB;IACvD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,KAAsC;IACnE,OAAO,OAAQ,KAAsB,CAAC,IAAI,KAAK,UAAU;QACvD,CAAC,CAAE,KAAsB;QACzB,CAAC,CAAC,kBAAkB,CAAC,KAAyB,CAAC,CAAC;AACpD,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,gBAAgB,CAC9B,IAAsB,EACtB,EAAU;IAEV,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;IACxC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAuB,EAAE,KAAa;IACtE,OAAO;QACL,OAAO,EAAE,CAAC,IAAmB,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC;KACvE,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF"}
1
+ {"version":3,"file":"model-catalog.js","sourceRoot":"","sources":["../../../src/spi/model-catalog.ts"],"names":[],"mappings":"AAkEA,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAC,IAAsB;IACvD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,KAAsC;IACnE,OAAO,OAAQ,KAAsB,CAAC,IAAI,KAAK,UAAU;QACvD,CAAC,CAAE,KAAsB;QACzB,CAAC,CAAC,kBAAkB,CAAC,KAAyB,CAAC,CAAC;AACpD,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,gBAAgB,CAC9B,IAAsB,EACtB,EAAU;IAEV,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;IACxC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAuB,EAAE,KAAa;IACtE,OAAO;QACL,OAAO,EAAE,CAAC,IAAmB,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC;KACvE,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF"}
@@ -4,7 +4,11 @@ export type QuotaPeriod = 'day' | 'month';
4
4
  /** One budget window: what was spent in it, and the ceiling when there is one. */
5
5
  export interface QuotaWindow {
6
6
  period: QuotaPeriod;
7
- usedTokens: number;
7
+ /**
8
+ * Tokens used in the window. Absent → the budget does not count tokens (a USD-only spend cap, such
9
+ * as an AI gateway's) — never a fabricated `0`.
10
+ */
11
+ usedTokens?: number;
8
12
  /** Absent → no token ceiling on this window. */
9
13
  limitTokens?: number;
10
14
  usedUsd: number;
@@ -12,6 +16,11 @@ export interface QuotaWindow {
12
16
  limitUsd?: number;
13
17
  /** ISO-8601 instant the window starts over (next UTC midnight, first of next month). */
14
18
  resetsAt?: string;
19
+ /**
20
+ * The soft limit: the share of a ceiling (`0..1`, e.g. `0.8`) past which a client should warn
21
+ * that the budget is running out. Absent → no warning for this window.
22
+ */
23
+ warnAt?: number;
15
24
  }
16
25
  /** Which window stopped the actor, when one did. */
17
26
  export interface QuotaBlock {
@@ -19,11 +28,24 @@ export interface QuotaBlock {
19
28
  /** Words a client can show ("Monthly AI budget reached"). */
20
29
  reason?: string;
21
30
  }
31
+ /** A window past its soft limit ({@link QuotaWindow.warnAt}) but not exhausted. */
32
+ export interface QuotaWarning {
33
+ period: QuotaPeriod;
34
+ /** How much of the window's ceiling is used, `0..1` (the larger of spend and tokens). */
35
+ ratio: number;
36
+ /** Words a client can show ("80% of your monthly AI budget used"). */
37
+ reason?: string;
38
+ }
22
39
  /** What `GET <base>/quota` answers. */
23
40
  export interface QuotaReport {
24
41
  windows: QuotaWindow[];
25
42
  /** Present when a window is exhausted — a send will be refused until it resets. */
26
43
  blocked?: QuotaBlock;
44
+ /**
45
+ * Present when a window crossed its `warnAt` and none is exhausted — the fullest one. A client
46
+ * may also derive it from the windows ({@link quotaWarning}); the server's wins.
47
+ */
48
+ warning?: QuotaWarning;
27
49
  }
28
50
  export interface QuotaQuery {
29
51
  actor: Actor;
@@ -44,6 +66,13 @@ export interface QuotaProvider {
44
66
  }
45
67
  /** The first window whose token or spend ceiling is reached, as a {@link QuotaBlock}. */
46
68
  export declare function exhaustedWindow(windows: readonly QuotaWindow[]): QuotaBlock | undefined;
69
+ /** How much of `window`'s ceilings is used, `0..1+` (the larger of spend and tokens), or `null`. */
70
+ export declare function quotaUsedRatio(window: QuotaWindow): number | null;
71
+ /**
72
+ * The fullest window past its `warnAt`, as a {@link QuotaWarning} — `undefined` when none is, or
73
+ * when one is exhausted (that is `blocked`, not a warning).
74
+ */
75
+ export declare function quotaWarning(windows: readonly QuotaWindow[]): QuotaWarning | undefined;
47
76
  /** The UTC day range (`YYYY-MM-DD`, inclusive) and reset instant of `period` around `now`. */
48
77
  export declare function quotaPeriodRange(period: QuotaPeriod, now: Date): {
49
78
  fromDay: string;
@@ -1 +1 @@
1
- {"version":3,"file":"quota-provider.d.ts","sourceRoot":"","sources":["../../../src/spi/quota-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,OAAO,CAAC;AAE1C,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,WAAW,CAAC;IACpB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uCAAuC;AACvC,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,mFAAmF;IACnF,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,KAAK,CAAC;IACb,kDAAkD;IAClD,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACjD;AAED,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,UAAU,GAAG,SAAS,CAYvF;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,IAAI,GACR;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAetD;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAMtE;AAED,mGAAmG;AACnG,qBAAa,iBAAkB,SAAQ,KAAK;IAExC,QAAQ,CAAC,MAAM,EAAE,WAAW;IAD9B,YACW,MAAM,EAAE,WAAW,EAC5B,OAAO,EAAE,MAAM,EAIhB;CACF"}
1
+ {"version":3,"file":"quota-provider.d.ts","sourceRoot":"","sources":["../../../src/spi/quota-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,OAAO,CAAC;AAE1C,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,WAAW,CAAC;IACpB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mFAAmF;AACnF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,yFAAyF;IACzF,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uCAAuC;AACvC,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,mFAAmF;IACnF,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,KAAK,CAAC;IACb,kDAAkD;IAClD,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACjD;AAED,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,UAAU,GAAG,SAAS,CAavF;AAED,oGAAoG;AACpG,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAajE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,YAAY,GAAG,SAAS,CAYtF;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,IAAI,GACR;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAetD;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAMtE;AAED,mGAAmG;AACnG,qBAAa,iBAAkB,SAAQ,KAAK;IAExC,QAAQ,CAAC,MAAM,EAAE,WAAW;IAD9B,YACW,MAAM,EAAE,WAAW,EAC5B,OAAO,EAAE,MAAM,EAIhB;CACF"}
@@ -1,7 +1,7 @@
1
1
  /** The first window whose token or spend ceiling is reached, as a {@link QuotaBlock}. */
2
2
  export function exhaustedWindow(windows) {
3
3
  for (const window of windows) {
4
- const tokensOut = window.limitTokens !== undefined && window.usedTokens >= window.limitTokens;
4
+ const tokensOut = window.limitTokens !== undefined && (window.usedTokens ?? 0) >= window.limitTokens;
5
5
  const spendOut = window.limitUsd !== undefined && window.usedUsd >= window.limitUsd;
6
6
  if (tokensOut || spendOut) {
7
7
  return {
@@ -12,6 +12,39 @@ export function exhaustedWindow(windows) {
12
12
  }
13
13
  return undefined;
14
14
  }
15
+ /** How much of `window`'s ceilings is used, `0..1+` (the larger of spend and tokens), or `null`. */
16
+ export function quotaUsedRatio(window) {
17
+ const ratios = [];
18
+ if (window.limitUsd !== undefined && window.limitUsd > 0) {
19
+ ratios.push(window.usedUsd / window.limitUsd);
20
+ }
21
+ if (window.limitTokens !== undefined &&
22
+ window.limitTokens > 0 &&
23
+ window.usedTokens !== undefined) {
24
+ ratios.push(window.usedTokens / window.limitTokens);
25
+ }
26
+ return ratios.length === 0 ? null : Math.max(...ratios);
27
+ }
28
+ /**
29
+ * The fullest window past its `warnAt`, as a {@link QuotaWarning} — `undefined` when none is, or
30
+ * when one is exhausted (that is `blocked`, not a warning).
31
+ */
32
+ export function quotaWarning(windows) {
33
+ if (exhaustedWindow(windows) !== undefined)
34
+ return undefined;
35
+ let fullest;
36
+ for (const window of windows) {
37
+ if (window.warnAt === undefined)
38
+ continue;
39
+ const ratio = quotaUsedRatio(window);
40
+ if (ratio === null || ratio < window.warnAt)
41
+ continue;
42
+ if (fullest === undefined || ratio > fullest.ratio) {
43
+ fullest = { period: window.period, ratio };
44
+ }
45
+ }
46
+ return fullest;
47
+ }
15
48
  /** The UTC day range (`YYYY-MM-DD`, inclusive) and reset instant of `period` around `now`. */
16
49
  export function quotaPeriodRange(period, now) {
17
50
  const year = now.getUTCFullYear();
@@ -1 +1 @@
1
- {"version":3,"file":"quota-provider.js","sourceRoot":"","sources":["../../../src/spi/quota-provider.ts"],"names":[],"mappings":"AAmDA,yFAAyF;AACzF,MAAM,UAAU,eAAe,CAAC,OAA+B;IAC7D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,WAAW,CAAC;QAC9F,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC;QACpF,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;YAC1B,OAAO;gBACL,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,IAAI,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,gBAAgB;aACzG,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAC9B,MAAmB,EACnB,GAAS;IAET,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3C,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QACnE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;IACpE,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QACzC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QACtC,QAAQ,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;KAC/D,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAQ,KAAuB,CAAC,MAAM,KAAK,UAAU,CACtD,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAE/B,MAAM;IADjB,YACW,MAAmB,EAC5B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHN,MAAM;QAIf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
1
+ {"version":3,"file":"quota-provider.js","sourceRoot":"","sources":["../../../src/spi/quota-provider.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,14 @@ export interface QuotaLimits {
11
11
  day?: QuotaWindowLimits;
12
12
  month?: QuotaWindowLimits;
13
13
  }
14
+ /** {@link LedgerQuotaProvider}'s tuning beyond the ceilings. */
15
+ export interface LedgerQuotaOptions {
16
+ /**
17
+ * The soft limit: the share of a ceiling (`0..1`) past which the report carries a `warning`.
18
+ * Stamped on every window that has a ceiling. Omit → no warnings.
19
+ */
20
+ warnAt?: number;
21
+ }
14
22
  /**
15
23
  * A {@link QuotaProvider} over the usage ledger: a day window (tokens from `quotaToday`, spend from
16
24
  * `usageBetween` when the store has it), and a month window when the store implements
@@ -24,7 +32,8 @@ export declare class LedgerQuotaProvider implements QuotaProvider {
24
32
  private readonly store;
25
33
  private readonly quota?;
26
34
  private readonly limits;
27
- constructor(store: AgentStore, quota?: QuotaStore | undefined, limits?: QuotaLimits);
35
+ private readonly options;
36
+ constructor(store: AgentStore, quota?: QuotaStore | undefined, limits?: QuotaLimits, options?: LedgerQuotaOptions);
28
37
  report(query: QuotaQuery): Promise<QuotaReport>;
29
38
  private dayWindow;
30
39
  private window;
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-quota-provider.d.ts","sourceRoot":"","sources":["../../../src/stores/ledger-quota-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,EAGjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IAErD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,YACmB,KAAK,EAAE,UAAU,EACjB,KAAK,CAAC,EAAE,UAAU,YAAA,EAClB,MAAM,GAAE,WAAgB,EACvC;IAEE,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAWpD;YAEa,SAAS;IAavB,OAAO,CAAC,MAAM;CAgBf"}
1
+ {"version":3,"file":"ledger-quota-provider.d.ts","sourceRoot":"","sources":["../../../src/stores/ledger-quota-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,EAIjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IAErD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,YACmB,KAAK,EAAE,UAAU,EACjB,KAAK,CAAC,EAAE,UAAU,YAAA,EAClB,MAAM,GAAE,WAAgB,EACxB,OAAO,GAAE,kBAAuB,EAC/C;IAEE,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAgBpD;YAEa,SAAS;IAavB,OAAO,CAAC,MAAM;CAoBf"}
@@ -1,4 +1,4 @@
1
- import { exhaustedWindow, quotaPeriodRange, } from '../spi/quota-provider.js';
1
+ import { exhaustedWindow, quotaPeriodRange, quotaWarning, } from '../spi/quota-provider.js';
2
2
  /**
3
3
  * A {@link QuotaProvider} over the usage ledger: a day window (tokens from `quotaToday`, spend from
4
4
  * `usageBetween` when the store has it), and a month window when the store implements
@@ -12,10 +12,12 @@ export class LedgerQuotaProvider {
12
12
  store;
13
13
  quota;
14
14
  limits;
15
- constructor(store, quota, limits = {}) {
15
+ options;
16
+ constructor(store, quota, limits = {}, options = {}) {
16
17
  this.store = store;
17
18
  this.quota = quota;
18
19
  this.limits = limits;
20
+ this.options = options;
19
21
  }
20
22
  async report(query) {
21
23
  const now = query.now ?? new Date();
@@ -27,7 +29,12 @@ export class LedgerQuotaProvider {
27
29
  windows.push(this.window('month', used.usedTokens, used.costUsd, range.resetsAt));
28
30
  }
29
31
  const blocked = exhaustedWindow(windows);
30
- return { windows, ...(blocked !== undefined ? { blocked } : {}) };
32
+ const warning = quotaWarning(windows);
33
+ return {
34
+ windows,
35
+ ...(blocked !== undefined ? { blocked } : {}),
36
+ ...(warning !== undefined ? { warning } : {}),
37
+ };
31
38
  }
32
39
  async dayWindow(actorRef, now) {
33
40
  const range = quotaPeriodRange('day', now);
@@ -49,6 +56,10 @@ export class LedgerQuotaProvider {
49
56
  usedUsd,
50
57
  ...(limits.usd !== undefined ? { limitUsd: limits.usd } : {}),
51
58
  resetsAt,
59
+ ...(this.options.warnAt !== undefined &&
60
+ (limits.tokens !== undefined || limits.usd !== undefined)
61
+ ? { warnAt: this.options.warnAt }
62
+ : {}),
52
63
  };
53
64
  }
54
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-quota-provider.js","sourceRoot":"","sources":["../../../src/stores/ledger-quota-provider.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EAMf,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAelC;;;;;;;;GAQG;AACH,MAAM,OAAO,mBAAmB;IAEX,KAAK;IACL,KAAK;IACL,MAAM;IAHzB,YACmB,KAAiB,EACjB,KAAkB,EAClB,MAAM,GAAgB,EAAE;qBAFxB,KAAK;qBACL,KAAK;sBACL,MAAM;IACtB,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,KAAiB;QAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,OAAO,GAAkB,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;QACrE,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAC7C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YACjF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACpE,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,GAAS;QACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC3C,MAAM,IAAI,GACR,IAAI,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS;YACnC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;YACrE,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QAChF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QACjF,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACjE,MAAM,CAAC,WAAW,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC;QACrF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,MAAM,CACZ,MAAmB,EACnB,UAAkB,EAClB,OAAe,EACf,QAAgB;QAEhB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACzC,OAAO;YACL,MAAM;YACN,UAAU;YACV,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,OAAO;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,QAAQ;SACT,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"ledger-quota-provider.js","sourceRoot":"","sources":["../../../src/stores/ledger-quota-provider.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { LucidRawRunner } from './lucid.js';
2
2
  /**
3
- * The six agent table names. They match the cross-adapter snake_case contract the reference Drizzle
3
+ * The seven agent table names. They match the cross-adapter snake_case contract the reference Drizzle
4
4
  * store uses, so a dashboard or migration can point at any adapter and see the same physical schema.
5
5
  */
6
6
  export declare const AGENT_TABLES: {
@@ -10,9 +10,11 @@ export declare const AGENT_TABLES: {
10
10
  readonly tokenUsage: 'agent_token_usage';
11
11
  readonly modelPricing: 'agent_model_pricing';
12
12
  readonly runs: 'agent_run';
13
+ /** Messages sent while a turn was running, waiting to run after it (the chat queue). */
14
+ readonly queuedMessages: 'agent_queued_message';
13
15
  };
14
16
  /**
15
- * `CREATE TABLE IF NOT EXISTS` DDL for the six agent tables plus their indexes, one statement per
17
+ * `CREATE TABLE IF NOT EXISTS` DDL for the seven agent tables plus their indexes, one statement per
16
18
  * array element so each can be issued through Lucid's `rawQuery`. Portable across SQLite / Postgres /
17
19
  * MySQL: quoted identifiers, epoch-ms `BIGINT` timestamps, `INTEGER` booleans (0/1) and `TEXT` JSON
18
20
  * columns — no dialect-only types. A real deployment should prefer the bundled migration stub so the
@@ -29,7 +31,7 @@ export declare const AGENT_TABLES: {
29
31
  */
30
32
  export declare function createTableStatements(): string[];
31
33
  /**
32
- * Idempotently provision the six agent tables through Lucid's async raw runner (`CREATE TABLE IF
34
+ * Idempotently provision the seven agent tables through Lucid's async raw runner (`CREATE TABLE IF
33
35
  * NOT EXISTS`), then additively repair a database that predates run tracking by ALTERing in the
34
36
  * `run_id` columns its three older tables are missing.
35
37
  *
@@ -46,15 +48,15 @@ export declare function createTableStatements(): string[];
46
48
  */
47
49
  export declare function createAgentTables(db: LucidRawRunner): Promise<string[]>;
48
50
  /**
49
- * `DROP TABLE IF EXISTS` for the six agent tables, in reverse dependency order so a dialect that
51
+ * `DROP TABLE IF EXISTS` for the seven agent tables, in reverse dependency order so a dialect that
50
52
  * enforces the `REFERENCES` clauses never refuses a drop for a child that still exists. The mirror of
51
53
  * {@link createAgentTables}, and what the published migration's `down()` calls.
52
54
  */
53
55
  export declare function dropTableStatements(): string[];
54
- /** Drop the six agent tables. Destructive and irreversible — this erases every thread and every ledger row. */
56
+ /** Drop the seven agent tables. Destructive and irreversible — this erases every thread and every ledger row. */
55
57
  export declare function dropAgentTables(db: LucidRawRunner): Promise<void>;
56
58
  /**
57
- * Idempotently ensure the six agent tables exist, memoized per db client. This is what the stores
59
+ * Idempotently ensure the seven agent tables exist, memoized per db client. This is what the stores
58
60
  * call on first use when `autoCreateTables` is on (the default) — whichever store touches the
59
61
  * connection first provisions the shared schema, so pricing seeds and governance reads work even
60
62
  * before the first agent run.
@@ -1 +1 @@
1
- {"version":3,"file":"lucid-schema.d.ts","sourceRoot":"","sources":["../../../src/stores/lucid-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,YAAY;aACvB,OAAO,EAAE,cAAc;aACvB,QAAQ,EAAE,eAAe;aACzB,SAAS,EAAE,iBAAiB;aAC5B,UAAU,EAAE,mBAAmB;aAC/B,YAAY,EAAE,qBAAqB;aACnC,IAAI,EAAE,WAAW;CACT,CAAC;AAEX;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CA6GhD;AAmDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA6B7E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAK9C;AAED,+GAA+G;AAC/G,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvE;AAWD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAanE"}
1
+ {"version":3,"file":"lucid-schema.d.ts","sourceRoot":"","sources":["../../../src/stores/lucid-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,YAAY;aACvB,OAAO,EAAE,cAAc;aACvB,QAAQ,EAAE,eAAe;aACzB,SAAS,EAAE,iBAAiB;aAC5B,UAAU,EAAE,mBAAmB;aAC/B,YAAY,EAAE,qBAAqB;aACnC,IAAI,EAAE,WAAW;IACjB,wFAAwF;aACxF,cAAc,EAAE,sBAAsB;CAC9B,CAAC;AAEX;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CA6HhD;AAoDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA6B7E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAW9C;AAED,iHAAiH;AACjH,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAIvE;AAWD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAanE"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The six agent table names. They match the cross-adapter snake_case contract the reference Drizzle
2
+ * The seven agent table names. They match the cross-adapter snake_case contract the reference Drizzle
3
3
  * store uses, so a dashboard or migration can point at any adapter and see the same physical schema.
4
4
  */
5
5
  export const AGENT_TABLES = {
@@ -9,9 +9,11 @@ export const AGENT_TABLES = {
9
9
  tokenUsage: 'agent_token_usage',
10
10
  modelPricing: 'agent_model_pricing',
11
11
  runs: 'agent_run',
12
+ /** Messages sent while a turn was running, waiting to run after it (the chat queue). */
13
+ queuedMessages: 'agent_queued_message',
12
14
  };
13
15
  /**
14
- * `CREATE TABLE IF NOT EXISTS` DDL for the six agent tables plus their indexes, one statement per
16
+ * `CREATE TABLE IF NOT EXISTS` DDL for the seven agent tables plus their indexes, one statement per
15
17
  * array element so each can be issued through Lucid's `rawQuery`. Portable across SQLite / Postgres /
16
18
  * MySQL: quoted identifiers, epoch-ms `BIGINT` timestamps, `INTEGER` booleans (0/1) and `TEXT` JSON
17
19
  * columns — no dialect-only types. A real deployment should prefer the bundled migration stub so the
@@ -41,6 +43,7 @@ export function createTableStatements() {
41
43
  "summary_message_count" INTEGER NOT NULL DEFAULT 0,
42
44
  "active_stream_id" VARCHAR(255) NULL,
43
45
  "model" VARCHAR(255) NULL,
46
+ "queue_pause" TEXT NULL,
44
47
  "created_at" BIGINT NOT NULL,
45
48
  "updated_at" BIGINT NOT NULL,
46
49
  "deleted_at" BIGINT NULL
@@ -134,6 +137,21 @@ export function createTableStatements() {
134
137
  `CREATE INDEX IF NOT EXISTS "${t.runs}_started_idx" ON "${t.runs}" ("started_at")`,
135
138
  `CREATE INDEX IF NOT EXISTS "${t.runs}_actor_started_idx" ON "${t.runs}" ("actor_ref", "started_at")`,
136
139
  `CREATE INDEX IF NOT EXISTS "${t.runs}_status_started_idx" ON "${t.runs}" ("status", "started_at")`,
140
+ `CREATE TABLE IF NOT EXISTS "${t.queuedMessages}" (
141
+ "id" VARCHAR(255) PRIMARY KEY NOT NULL,
142
+ "thread_id" VARCHAR(255) NOT NULL REFERENCES "${t.threads}" ("id") ON DELETE CASCADE,
143
+ "actor" TEXT NOT NULL,
144
+ "content" TEXT NOT NULL,
145
+ "attachments" TEXT NULL,
146
+ "agent_name" VARCHAR(255) NULL,
147
+ "model" VARCHAR(255) NULL,
148
+ "page_context" TEXT NULL,
149
+ "interrupt" INTEGER NOT NULL DEFAULT 0,
150
+ "position" INTEGER NOT NULL,
151
+ "created_at" BIGINT NOT NULL,
152
+ "updated_at" BIGINT NOT NULL
153
+ )`,
154
+ `CREATE INDEX IF NOT EXISTS "${t.queuedMessages}_thread_position_idx" ON "${t.queuedMessages}" ("thread_id", "position")`,
137
155
  ];
138
156
  }
139
157
  /**
@@ -160,6 +178,7 @@ const ADDITIVE_COLUMNS = [
160
178
  { table: AGENT_TABLES.messages, column: 'ui', type: 'TEXT NULL' },
161
179
  { table: AGENT_TABLES.messages, column: 'feedback', type: 'TEXT NULL' },
162
180
  { table: AGENT_TABLES.threads, column: 'model', type: 'VARCHAR(255) NULL' },
181
+ { table: AGENT_TABLES.threads, column: 'queue_pause', type: 'TEXT NULL' },
163
182
  { table: AGENT_TABLES.toolCalls, column: 'approver', type: 'VARCHAR(255) NULL' },
164
183
  { table: AGENT_TABLES.toolCalls, column: 'expires_at', type: 'BIGINT NULL' },
165
184
  { table: AGENT_TABLES.toolCalls, column: 'remember', type: 'INTEGER NULL' },
@@ -184,7 +203,7 @@ async function hasColumn(db, table, column) {
184
203
  }
185
204
  }
186
205
  /**
187
- * Idempotently provision the six agent tables through Lucid's async raw runner (`CREATE TABLE IF
206
+ * Idempotently provision the seven agent tables through Lucid's async raw runner (`CREATE TABLE IF
188
207
  * NOT EXISTS`), then additively repair a database that predates run tracking by ALTERing in the
189
208
  * `run_id` columns its three older tables are missing.
190
209
  *
@@ -230,15 +249,23 @@ export async function createAgentTables(db) {
230
249
  return repairs;
231
250
  }
232
251
  /**
233
- * `DROP TABLE IF EXISTS` for the six agent tables, in reverse dependency order so a dialect that
252
+ * `DROP TABLE IF EXISTS` for the seven agent tables, in reverse dependency order so a dialect that
234
253
  * enforces the `REFERENCES` clauses never refuses a drop for a child that still exists. The mirror of
235
254
  * {@link createAgentTables}, and what the published migration's `down()` calls.
236
255
  */
237
256
  export function dropTableStatements() {
238
257
  const t = AGENT_TABLES;
239
- return [t.runs, t.tokenUsage, t.toolCalls, t.messages, t.modelPricing, t.threads].map((table) => `DROP TABLE IF EXISTS "${table}"`);
258
+ return [
259
+ t.queuedMessages,
260
+ t.runs,
261
+ t.tokenUsage,
262
+ t.toolCalls,
263
+ t.messages,
264
+ t.modelPricing,
265
+ t.threads,
266
+ ].map((table) => `DROP TABLE IF EXISTS "${table}"`);
240
267
  }
241
- /** Drop the six agent tables. Destructive and irreversible — this erases every thread and every ledger row. */
268
+ /** Drop the seven agent tables. Destructive and irreversible — this erases every thread and every ledger row. */
242
269
  export async function dropAgentTables(db) {
243
270
  for (const stmt of dropTableStatements()) {
244
271
  await db.rawQuery(stmt);
@@ -253,7 +280,7 @@ export async function dropAgentTables(db) {
253
280
  */
254
281
  const provisioned = new WeakMap();
255
282
  /**
256
- * Idempotently ensure the six agent tables exist, memoized per db client. This is what the stores
283
+ * Idempotently ensure the seven agent tables exist, memoized per db client. This is what the stores
257
284
  * call on first use when `autoCreateTables` is on (the default) — whichever store touches the
258
285
  * connection first provisions the shared schema, so pricing seeds and governance reads work even
259
286
  * before the first agent run.