@ottimis/jack-provider-sdk 0.1.0 → 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.
- package/dist/backend.d.ts +38 -12
- package/dist/backend.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/usage.js +34 -0
- package/dist/cjs/usage.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +151 -55
- package/dist/provider.d.ts.map +1 -1
- package/dist/usage.d.ts +219 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +33 -0
- package/dist/usage.js.map +1 -0
- package/package.json +5 -3
- package/src/backend.ts +28 -12
- package/src/index.ts +1 -0
- package/src/provider.ts +161 -44
- package/src/usage.ts +228 -0
package/dist/usage.d.ts
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage / billing capability — provider-owned data flow.
|
|
3
|
+
*
|
|
4
|
+
* Each provider knows how to talk to its own billing surface (Claude
|
|
5
|
+
* cookie API for Pro/Max, OpenAI usage endpoints for Codex, Gemini's
|
|
6
|
+
* Google Cloud quotas, …) and how to map its SDK's per-message token
|
|
7
|
+
* counts into a canonical shape. The host runs a generic poll loop and
|
|
8
|
+
* a generic chip — it never special-cases any provider.
|
|
9
|
+
*
|
|
10
|
+
* Two surfaces:
|
|
11
|
+
*
|
|
12
|
+
* - `fetch()` for **account-level** snapshots. Pulled by a host poller
|
|
13
|
+
* on `recommendedPollIntervalSec` cadence (clamped to host bounds).
|
|
14
|
+
* What "account" means is provider-defined: Claude → org, Codex →
|
|
15
|
+
* OpenAI project, Gemini → Cloud Billing project.
|
|
16
|
+
*
|
|
17
|
+
* - `formatSessionMetrics()` for **per-session** translation. The
|
|
18
|
+
* manager already calls `backend.getContextUsage()` after every
|
|
19
|
+
* `assistant` message; that returns a loose `AgentContextUsage`
|
|
20
|
+
* bag. This hook lets the provider lift it into canonical
|
|
21
|
+
* {@link UsageMetric}[] without the host trying to interpret
|
|
22
|
+
* provider-specific fields.
|
|
23
|
+
*
|
|
24
|
+
* Single source of truth: the provider. Host plumbs, never decodes.
|
|
25
|
+
*
|
|
26
|
+
* Optional everywhere — providers without billing visibility (Codex
|
|
27
|
+
* without admin keys, Gemini without OAuth) leave `fetch()` returning
|
|
28
|
+
* an empty `metrics: []`. The capability flag stays `true` if the
|
|
29
|
+
* provider can format per-session metrics, `false` if it has nothing
|
|
30
|
+
* to say at all.
|
|
31
|
+
*/
|
|
32
|
+
import type { AgentContextUsage } from './backend';
|
|
33
|
+
/**
|
|
34
|
+
* Canonical metric kinds. New kinds extend this union additively when a
|
|
35
|
+
* provider has a meaningfully different shape (e.g. a future
|
|
36
|
+
* `quarterly_burn` for enterprise billing). Adding a kind is a minor
|
|
37
|
+
* SDK bump; the renderer's dispatch table grows alongside.
|
|
38
|
+
*/
|
|
39
|
+
export type UsageMetric = TimeWindowMetric | TokenUtilizationMetric | MonthlySpendMetric;
|
|
40
|
+
/**
|
|
41
|
+
* Rolling-window utilization. The classic Claude Pro/Max bucket
|
|
42
|
+
* (5-hour, 7-day) — utilization 0..1 with a hard reset boundary.
|
|
43
|
+
*
|
|
44
|
+
* Optional `used` / `limit` / `unit` carry raw counts when the
|
|
45
|
+
* provider exposes them (Gemini free-tier daily quota: 12 of 50
|
|
46
|
+
* requests). Claude's cookie API gives only `utilization`, so those
|
|
47
|
+
* stay undefined and the chip falls back to "X% of N-hour usage".
|
|
48
|
+
*/
|
|
49
|
+
export type TimeWindowMetric = {
|
|
50
|
+
kind: 'time_window';
|
|
51
|
+
/** Stable, provider-defined key. e.g. `'five_hour'`, `'seven_day_opus'`, `'daily'`. */
|
|
52
|
+
id: string;
|
|
53
|
+
/** Human-readable label for UI. Provider supplies (i18n is its concern). */
|
|
54
|
+
label: string;
|
|
55
|
+
/** Window utilization in [0, 1]. */
|
|
56
|
+
utilization: number;
|
|
57
|
+
/** Optional: raw count consumed in the window (when known). */
|
|
58
|
+
used?: number;
|
|
59
|
+
/** Optional: raw cap of the window (when known). */
|
|
60
|
+
limit?: number;
|
|
61
|
+
/** Optional: unit of `used`/`limit`. Default `'tokens'`. Chip uses for formatting. */
|
|
62
|
+
unit?: 'tokens' | 'requests' | (string & {});
|
|
63
|
+
/** ISO 8601 timestamp when the window resets. */
|
|
64
|
+
resetsAt: string;
|
|
65
|
+
/** Window length in seconds. Used for elapsed-progress UI. */
|
|
66
|
+
windowSeconds: number;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Count-based utilization without a time boundary. Used for context
|
|
70
|
+
* window pressure ("X tokens of Y max") and any cumulative provider
|
|
71
|
+
* metric that doesn't reset on a clock (lifetime / billing-period
|
|
72
|
+
* tokens, etc).
|
|
73
|
+
*
|
|
74
|
+
* `max` is optional — a provider tracking total token consumption
|
|
75
|
+
* without a hard cap (analytics, not gating) leaves it undefined and
|
|
76
|
+
* the chip shows just the count.
|
|
77
|
+
*/
|
|
78
|
+
export type TokenUtilizationMetric = {
|
|
79
|
+
kind: 'token_utilization';
|
|
80
|
+
/** Stable, provider-defined key. e.g. `'context'`, `'session_total'`. */
|
|
81
|
+
id: string;
|
|
82
|
+
/** Human-readable label for UI. */
|
|
83
|
+
label: string;
|
|
84
|
+
/** Tokens consumed. */
|
|
85
|
+
used: number;
|
|
86
|
+
/** Optional cap. Undefined = no cap, chip hides the ratio. */
|
|
87
|
+
max?: number;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Spend on a billing cycle (typically monthly). Only meaningful for
|
|
91
|
+
* providers using API-key auth — subscription users have rolling-window
|
|
92
|
+
* quotas, not $-spend.
|
|
93
|
+
*
|
|
94
|
+
* `budgetUsd` is optional: most users don't set a budget, so the chip
|
|
95
|
+
* shows raw spend without a denominator. When present, chip can render
|
|
96
|
+
* a budget bar.
|
|
97
|
+
*/
|
|
98
|
+
export type MonthlySpendMetric = {
|
|
99
|
+
kind: 'monthly_spend';
|
|
100
|
+
id: string;
|
|
101
|
+
/** Cycle label, e.g. "May 2026" or "Current cycle". */
|
|
102
|
+
label: string;
|
|
103
|
+
spentUsd: number;
|
|
104
|
+
budgetUsd?: number;
|
|
105
|
+
/** ISO 8601 — start of the billing cycle. */
|
|
106
|
+
cycleStart: string;
|
|
107
|
+
/** ISO 8601 — end of the billing cycle. */
|
|
108
|
+
cycleEnd: string;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* One snapshot of provider-side usage data, as returned by
|
|
112
|
+
* {@link UsageApi.fetch}. `metrics` may be empty when the provider has
|
|
113
|
+
* no account-level data to report (Codex without billing key, etc.).
|
|
114
|
+
*/
|
|
115
|
+
export type UsageSnapshot = {
|
|
116
|
+
metrics: UsageMetric[];
|
|
117
|
+
/** ISO 8601 — when this snapshot was observed. */
|
|
118
|
+
observedAt: string;
|
|
119
|
+
/** Verbatim provider payload, kept for debug / future analytics.
|
|
120
|
+
* Never consumed by host or chip directly. */
|
|
121
|
+
raw?: unknown;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Connection / authorization state of the provider's usage surface.
|
|
125
|
+
* Surface in the chip's pop-over so the user knows whether they're
|
|
126
|
+
* tracking real numbers or seeing a cached / disconnected snapshot.
|
|
127
|
+
*/
|
|
128
|
+
export type UsageStatus = {
|
|
129
|
+
connected: boolean;
|
|
130
|
+
/** Optional human-readable identity (org name, email, project id). */
|
|
131
|
+
identity?: string;
|
|
132
|
+
/**
|
|
133
|
+
* Provider-defined auth-mode hint. Lets the renderer adapt copy
|
|
134
|
+
* (e.g. "Connected as API user" vs "Pro subscription"). Stable
|
|
135
|
+
* provider-supplied strings; host doesn't interpret beyond
|
|
136
|
+
* passthrough.
|
|
137
|
+
*/
|
|
138
|
+
authMode?: 'subscription' | 'api_key' | (string & {});
|
|
139
|
+
/** Last error message, when not connected. */
|
|
140
|
+
error?: string;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Result of {@link UsageApi.connect}. The `'choose'` branch covers
|
|
144
|
+
* multi-org / multi-project accounts where the user must pick one
|
|
145
|
+
* (Claude's multi-org case). Generalising to a generic option list
|
|
146
|
+
* means the chip's UI doesn't special-case any provider.
|
|
147
|
+
*/
|
|
148
|
+
export type UsageConnectResult = {
|
|
149
|
+
kind: 'ready';
|
|
150
|
+
identity: string;
|
|
151
|
+
} | {
|
|
152
|
+
kind: 'choose';
|
|
153
|
+
options: UsageConnectOption[];
|
|
154
|
+
} | {
|
|
155
|
+
kind: 'error';
|
|
156
|
+
error: string;
|
|
157
|
+
} | {
|
|
158
|
+
kind: 'cancelled';
|
|
159
|
+
};
|
|
160
|
+
export type UsageConnectOption = {
|
|
161
|
+
id: string;
|
|
162
|
+
label: string;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Context handed to {@link UsageApi.connect}. Currently just a parent
|
|
166
|
+
* window for Electron-coupled flows (Claude opens a child BrowserWindow
|
|
167
|
+
* on `claude.ai/login`). Typed as `unknown` here so the SDK doesn't
|
|
168
|
+
* pull in `electron` as a peer dep — the host narrows to
|
|
169
|
+
* `BrowserWindow` at the call site.
|
|
170
|
+
*/
|
|
171
|
+
export type UsageConnectContext = {
|
|
172
|
+
/** Parent window for any modal flow the provider needs to open. */
|
|
173
|
+
parentWindow?: unknown;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Provider-owned usage capability. Optional on {@link JackProvider};
|
|
177
|
+
* absent = host hides the chip's "Connect" affordance and the
|
|
178
|
+
* capability flag is `false`.
|
|
179
|
+
*/
|
|
180
|
+
export type UsageApi = {
|
|
181
|
+
/** Current connection state — used for chip display + gating. */
|
|
182
|
+
status(): Promise<UsageStatus>;
|
|
183
|
+
/**
|
|
184
|
+
* Open the provider's connect flow. Whatever modality the provider
|
|
185
|
+
* needs (login window, API-key picker, OAuth redirect) lives here.
|
|
186
|
+
*/
|
|
187
|
+
connect(ctx: UsageConnectContext): Promise<UsageConnectResult>;
|
|
188
|
+
/**
|
|
189
|
+
* When `connect()` returned `'choose'`, host calls this with the
|
|
190
|
+
* user's pick. Optional — providers that never choose omit it.
|
|
191
|
+
*/
|
|
192
|
+
selectOption?(optionId: string): Promise<UsageConnectResult>;
|
|
193
|
+
/** Drop credentials and stop any provider-side polling. */
|
|
194
|
+
disconnect(): Promise<void>;
|
|
195
|
+
/**
|
|
196
|
+
* Fetch one fresh account-level snapshot. Empty `metrics: []` is
|
|
197
|
+
* fine when the provider has no billing surface yet — the capability
|
|
198
|
+
* stays `true` for the per-session bridge.
|
|
199
|
+
*/
|
|
200
|
+
fetch(): Promise<UsageSnapshot>;
|
|
201
|
+
/**
|
|
202
|
+
* Recommended poll cadence (seconds). Host clamps to its bounds.
|
|
203
|
+
* Optional — host falls back to its own default if unset.
|
|
204
|
+
*/
|
|
205
|
+
recommendedPollIntervalSec?: number;
|
|
206
|
+
/**
|
|
207
|
+
* Translate the loose {@link AgentContextUsage} the manager pulls from
|
|
208
|
+
* `backend.getContextUsage()` into canonical {@link UsageMetric}[].
|
|
209
|
+
*
|
|
210
|
+
* Pure function (no side effects) — provider knows its own SDK's
|
|
211
|
+
* shape and lifts it. Empty array OK when the raw bag has nothing
|
|
212
|
+
* useful (e.g. fresh session before any message lands).
|
|
213
|
+
*
|
|
214
|
+
* Optional. Providers without per-session token visibility omit it
|
|
215
|
+
* and the chip skips the per-session row.
|
|
216
|
+
*/
|
|
217
|
+
formatSessionMetrics?(raw: AgentContextUsage): UsageMetric[];
|
|
218
|
+
};
|
|
219
|
+
//# sourceMappingURL=usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
|
package/dist/usage.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage / billing capability — provider-owned data flow.
|
|
3
|
+
*
|
|
4
|
+
* Each provider knows how to talk to its own billing surface (Claude
|
|
5
|
+
* cookie API for Pro/Max, OpenAI usage endpoints for Codex, Gemini's
|
|
6
|
+
* Google Cloud quotas, …) and how to map its SDK's per-message token
|
|
7
|
+
* counts into a canonical shape. The host runs a generic poll loop and
|
|
8
|
+
* a generic chip — it never special-cases any provider.
|
|
9
|
+
*
|
|
10
|
+
* Two surfaces:
|
|
11
|
+
*
|
|
12
|
+
* - `fetch()` for **account-level** snapshots. Pulled by a host poller
|
|
13
|
+
* on `recommendedPollIntervalSec` cadence (clamped to host bounds).
|
|
14
|
+
* What "account" means is provider-defined: Claude → org, Codex →
|
|
15
|
+
* OpenAI project, Gemini → Cloud Billing project.
|
|
16
|
+
*
|
|
17
|
+
* - `formatSessionMetrics()` for **per-session** translation. The
|
|
18
|
+
* manager already calls `backend.getContextUsage()` after every
|
|
19
|
+
* `assistant` message; that returns a loose `AgentContextUsage`
|
|
20
|
+
* bag. This hook lets the provider lift it into canonical
|
|
21
|
+
* {@link UsageMetric}[] without the host trying to interpret
|
|
22
|
+
* provider-specific fields.
|
|
23
|
+
*
|
|
24
|
+
* Single source of truth: the provider. Host plumbs, never decodes.
|
|
25
|
+
*
|
|
26
|
+
* Optional everywhere — providers without billing visibility (Codex
|
|
27
|
+
* without admin keys, Gemini without OAuth) leave `fetch()` returning
|
|
28
|
+
* an empty `metrics: []`. The capability flag stays `true` if the
|
|
29
|
+
* provider can format per-session metrics, `false` if it has nothing
|
|
30
|
+
* to say at all.
|
|
31
|
+
*/
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ottimis/jack-provider-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Plugin contract for AI provider integrations in Jack — backend interface, capability matrix, spawner primitives, knowledge context. Consumed both by in-tree providers and external packages.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,12 +29,14 @@
|
|
|
29
29
|
"clean": "rm -rf dist"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@ottimis/jack-chat-core": ">=0.5.5"
|
|
32
|
+
"@ottimis/jack-chat-core": ">=0.5.5",
|
|
33
|
+
"zod": ">=3.22.0"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@ottimis/jack-chat-core": "^0.5.5",
|
|
36
37
|
"@types/node": "^22.14.1",
|
|
37
38
|
"tsx": "^4.19.2",
|
|
38
|
-
"typescript": "^5.8.3"
|
|
39
|
+
"typescript": "^5.8.3",
|
|
40
|
+
"zod": "^4.3.6"
|
|
39
41
|
}
|
|
40
42
|
}
|
package/src/backend.ts
CHANGED
|
@@ -65,10 +65,18 @@ export type AgentSystemPrompt =
|
|
|
65
65
|
| { type: 'preset'; preset: string; append?: string }
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* MCP server configuration
|
|
69
|
-
*
|
|
68
|
+
* MCP server configuration handed to the provider via
|
|
69
|
+
* {@link AgentQueryOptions.mcpServers}. Mirrors the official MCP wire
|
|
70
|
+
* format (the same shape Anthropic, OpenAI, and Google all consume).
|
|
71
|
+
*
|
|
72
|
+
* Replaces the legacy opaque `AgentMcpServerConfig = unknown` so the
|
|
73
|
+
* type system enforces the contract end-to-end and the host can inspect
|
|
74
|
+
* the bag for telemetry / preview without double-translating.
|
|
70
75
|
*/
|
|
71
|
-
export type
|
|
76
|
+
export type McpServerSpec =
|
|
77
|
+
| { type: 'stdio'; command: string; args?: string[]; env?: Record<string, string> }
|
|
78
|
+
| { type: 'http'; url: string; headers?: Record<string, string> }
|
|
79
|
+
| { type: 'sse'; url: string; headers?: Record<string, string> }
|
|
72
80
|
|
|
73
81
|
/** Reasoning-effort knob. Provider-validated; not all providers honor every value. */
|
|
74
82
|
export type AgentEffortLevel = 'low' | 'medium' | 'high' | 'xhigh' | 'max'
|
|
@@ -161,7 +169,7 @@ export type AgentQueryOptions = {
|
|
|
161
169
|
* knowledge sources).
|
|
162
170
|
*/
|
|
163
171
|
additionalDirectories?: string[]
|
|
164
|
-
mcpServers?: Record<string,
|
|
172
|
+
mcpServers?: Record<string, McpServerSpec>
|
|
165
173
|
resume?: string
|
|
166
174
|
/**
|
|
167
175
|
* Initial model for the spawn. Live switches use
|
|
@@ -231,16 +239,24 @@ export interface AgentSession extends AsyncIterable<NormalizedMessage> {
|
|
|
231
239
|
*/
|
|
232
240
|
setModel(model?: string): Promise<void>
|
|
233
241
|
/**
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
242
|
+
* Switch the reasoning-effort tier live, without respawning the child
|
|
243
|
+
* process. Pass `undefined` to clear any override and let the provider
|
|
244
|
+
* fall back to its default. Gated by `CapabilityMatrix.liveEffortSwitch`
|
|
245
|
+
* — providers without live switching declare `false` and the renderer
|
|
246
|
+
* hides the inline Effort dropdown.
|
|
247
|
+
*
|
|
248
|
+
* Replaces the legacy `applyFlagSettings({ effortLevel })` bag — Claude
|
|
249
|
+
* was the only producer and Codex/Gemini both threw `UNSUPPORTED`. The
|
|
250
|
+
* host now calls this method by name and the type system tells the
|
|
251
|
+
* provider author exactly what to wire.
|
|
237
252
|
*/
|
|
238
|
-
|
|
253
|
+
setEffortLevel(effort: AgentEffortLevel | undefined): Promise<void>
|
|
239
254
|
/**
|
|
240
|
-
* Read the effective
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
255
|
+
* Read the effective runtime settings the provider booted with. Today
|
|
256
|
+
* the host only consumes `effective.effortLevel` to populate the
|
|
257
|
+
* Effort dropdown's initial value; the rest of the bag is opaque so
|
|
258
|
+
* providers with richer settings layers can passthrough additional
|
|
259
|
+
* keys without an SDK bump.
|
|
244
260
|
*/
|
|
245
261
|
getSettings(): Promise<AgentSettingsResponse>
|
|
246
262
|
}
|
package/src/index.ts
CHANGED
package/src/provider.ts
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
* it free of provider-specific imports.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import type { AgentBackend, AgentQueryOptions } from './backend'
|
|
19
|
+
import type { AgentBackend, AgentQueryOptions, McpServerSpec } from './backend'
|
|
20
|
+
import type { UsageApi } from './usage'
|
|
21
|
+
import type { ZodType } from 'zod'
|
|
20
22
|
import type {
|
|
21
23
|
ClientToolHandler,
|
|
22
24
|
NormalizedMessage,
|
|
@@ -28,20 +30,48 @@ import type {
|
|
|
28
30
|
export type ProviderId = string
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
33
|
+
* Where the provider sourced a slash command from. Drives the
|
|
34
|
+
* {@link SlashCommandDef} discriminated union below — file-sourced
|
|
35
|
+
* commands carry `body` + `filePath`, builtin and wire-sourced ones
|
|
36
|
+
* don't (they don't *have* a markdown file behind them).
|
|
35
37
|
*/
|
|
36
|
-
export type
|
|
38
|
+
export type SlashCommandScope = 'builtin' | 'wire' | 'user' | 'project' | (string & {})
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Common surface every slash command def carries regardless of source.
|
|
42
|
+
* The renderer uses these for autocomplete + chip rendering.
|
|
43
|
+
*/
|
|
44
|
+
type SlashCommandDefBase = {
|
|
37
45
|
name: string
|
|
38
|
-
scope: 'user' | 'project' | 'builtin'
|
|
39
46
|
description?: string
|
|
40
47
|
argumentHint?: string
|
|
41
|
-
body: string
|
|
42
|
-
filePath: string
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Slash-command definition surfaced by a provider. Three sources can
|
|
52
|
+
* coexist (see {@link SlashCommandSupport}):
|
|
53
|
+
*
|
|
54
|
+
* - `'builtin'` — static catalog the runtime intercepts. The renderer
|
|
55
|
+
* never opens the file (there is none); the executor is the agent.
|
|
56
|
+
* - `'wire'` — pushed live by the agent over the wire (Gemini ACP
|
|
57
|
+
* `available_commands_update`). Same render contract as builtin —
|
|
58
|
+
* no on-disk artifact.
|
|
59
|
+
* - `'user' | 'project'` — file-based commands the user authored
|
|
60
|
+
* (Claude `.claude/commands/foo.md`, future per-provider analogs).
|
|
61
|
+
* `filePath` + `body` are required so the renderer can offer "open
|
|
62
|
+
* in editor" affordances and the host can expand `$ARGUMENTS` /
|
|
63
|
+
* `$N` placeholders.
|
|
64
|
+
*
|
|
65
|
+
* Discriminated by `scope` so consumers narrow before reading the
|
|
66
|
+
* file-only fields. Replaces the legacy uniform shape that forced
|
|
67
|
+
* builtin/wire commands to ship synthetic empty `body: ''` /
|
|
68
|
+
* `filePath: ''`.
|
|
69
|
+
*/
|
|
70
|
+
export type SlashCommandDef =
|
|
71
|
+
| (SlashCommandDefBase & { scope: 'builtin' })
|
|
72
|
+
| (SlashCommandDefBase & { scope: 'wire' })
|
|
73
|
+
| (SlashCommandDefBase & { scope: 'user' | 'project'; body: string; filePath: string })
|
|
74
|
+
|
|
45
75
|
/**
|
|
46
76
|
* Parsed envelope a provider's CLI may wrap slash commands in when it logs
|
|
47
77
|
* them into the session transcript. Claude uses
|
|
@@ -212,6 +242,14 @@ export type CapabilityMatrix = {
|
|
|
212
242
|
resumeSession: boolean
|
|
213
243
|
/** Switch model live without respawn (Claude control request `set_model`). */
|
|
214
244
|
liveModelSwitch: boolean
|
|
245
|
+
/**
|
|
246
|
+
* Switch reasoning-effort tier live without respawn. Drives whether the
|
|
247
|
+
* inline Effort dropdown fires `setEffortLevel()` (true) or requires a
|
|
248
|
+
* spawn-time setting (false → dropdown hidden / annotated). Decoupled
|
|
249
|
+
* from `liveModelSwitch` because Codex has live model but spawn-time
|
|
250
|
+
* effort.
|
|
251
|
+
*/
|
|
252
|
+
liveEffortSwitch: boolean
|
|
215
253
|
/** Switch permission mode live without respawn. */
|
|
216
254
|
livePermissionModeSwitch: boolean
|
|
217
255
|
/**
|
|
@@ -228,6 +266,13 @@ export type CapabilityMatrix = {
|
|
|
228
266
|
* renderer hides it and only shows the post-fact audit log.
|
|
229
267
|
*/
|
|
230
268
|
permissionGranularity: 'callback' | 'sandbox-only'
|
|
269
|
+
/**
|
|
270
|
+
* Provider exposes a usage / billing surface (account-level snapshot
|
|
271
|
+
* via `provider.usage.fetch()` and/or per-session metric translation
|
|
272
|
+
* via `formatSessionMetrics()`). When `false`, the chip hides the
|
|
273
|
+
* usage bars and no Connect affordance is offered.
|
|
274
|
+
*/
|
|
275
|
+
usage: boolean
|
|
231
276
|
}
|
|
232
277
|
|
|
233
278
|
/**
|
|
@@ -353,17 +398,19 @@ export type PrepareSpawnContext = {
|
|
|
353
398
|
}
|
|
354
399
|
|
|
355
400
|
/**
|
|
356
|
-
* MCP server registration in canonical
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
* {@link
|
|
360
|
-
*
|
|
361
|
-
*
|
|
401
|
+
* MCP server registration in canonical wire-format shape. Same type
|
|
402
|
+
* used at both ends of the knowledge pipeline: as
|
|
403
|
+
* {@link KnowledgeContext.mcpServers} (input to the provider) and as
|
|
404
|
+
* {@link AgentQueryOptions.mcpServers} (output from
|
|
405
|
+
* {@link JackProvider.applyKnowledgeContext}). Each provider's
|
|
406
|
+
* applyKnowledgeContext translates the merged context into its native
|
|
407
|
+
* runtime layout (Claude SDK `mcpServers` map; Codex `mcp_servers.toml`;
|
|
408
|
+
* Gemini ACP `session/new { mcpServers }`).
|
|
409
|
+
*
|
|
410
|
+
* Re-exported as `McpServerSpec` from `./backend` — same type, two names
|
|
411
|
+
* for ergonomics in different code paths.
|
|
362
412
|
*/
|
|
363
|
-
export type KnowledgeMcpResolution =
|
|
364
|
-
| { type: 'stdio'; command: string; args?: string[]; env?: Record<string, string> }
|
|
365
|
-
| { type: 'http'; url: string; headers?: Record<string, string> }
|
|
366
|
-
| { type: 'sse'; url: string; headers?: Record<string, string> }
|
|
413
|
+
export type KnowledgeMcpResolution = McpServerSpec
|
|
367
414
|
|
|
368
415
|
/**
|
|
369
416
|
* Provider-neutral container for everything the host has computed about the
|
|
@@ -400,6 +447,24 @@ export type KnowledgeContext = {
|
|
|
400
447
|
* names the renderer maps to React components. Providers that don't
|
|
401
448
|
* declare branding fall back to neutral defaults.
|
|
402
449
|
*/
|
|
450
|
+
/**
|
|
451
|
+
* Curated icon catalog keys the renderer knows how to map to lucide React
|
|
452
|
+
* components. Hybrid closed/open: well-known values get autocomplete;
|
|
453
|
+
* arbitrary strings still type-check (the renderer falls back to a default
|
|
454
|
+
* icon for unknown keys, so a provider can ship a forward-looking key
|
|
455
|
+
* without breaking older hosts).
|
|
456
|
+
*/
|
|
457
|
+
export type ProviderIconKey =
|
|
458
|
+
| 'sparkles'
|
|
459
|
+
| 'cpu'
|
|
460
|
+
| 'gem'
|
|
461
|
+
| 'bot'
|
|
462
|
+
| 'brain'
|
|
463
|
+
| 'star'
|
|
464
|
+
| 'wand'
|
|
465
|
+
| 'zap'
|
|
466
|
+
| (string & {})
|
|
467
|
+
|
|
403
468
|
export type ProviderBranding = {
|
|
404
469
|
/**
|
|
405
470
|
* Primary accent color. Used as a subtle border on the chat composer +
|
|
@@ -412,12 +477,13 @@ export type ProviderBranding = {
|
|
|
412
477
|
*/
|
|
413
478
|
accentColor: string
|
|
414
479
|
/**
|
|
415
|
-
* Curated icon key — one of
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
480
|
+
* Curated icon key — one of {@link ProviderIconKey}. Keeping this a
|
|
481
|
+
* closed/open enum (instead of free-form SVG/asset) means providers
|
|
482
|
+
* don't ship rendering assets and the host stays in control of what
|
|
483
|
+
* shapes can land in the UI. Unknown keys fall back to a default icon
|
|
484
|
+
* in the renderer.
|
|
419
485
|
*/
|
|
420
|
-
iconKey?:
|
|
486
|
+
iconKey?: ProviderIconKey
|
|
421
487
|
}
|
|
422
488
|
|
|
423
489
|
export type JackProvider = {
|
|
@@ -572,16 +638,10 @@ export type JackProvider = {
|
|
|
572
638
|
*
|
|
573
639
|
* Pattern A providers (Claude, Codex) leave this undefined; the host
|
|
574
640
|
* detects the pattern by absence and skips wiring.
|
|
575
|
-
*
|
|
576
|
-
* `ctx` carries the host's correlation ids the provider may want to
|
|
577
|
-
* bridge to wire-driven side channels (e.g. mapping
|
|
578
|
-
* `available_commands_update` notifications back to the renderer's
|
|
579
|
-
* slash command store via the host's session id). Optional for
|
|
580
|
-
* providers that don't need it.
|
|
581
641
|
*/
|
|
582
642
|
attachClientToolHandler?(
|
|
583
643
|
handler: ClientToolHandler,
|
|
584
|
-
ctx
|
|
644
|
+
ctx: ClientToolHandlerAttachContext
|
|
585
645
|
): void
|
|
586
646
|
/**
|
|
587
647
|
* Persisted permission rules manager. The host's
|
|
@@ -590,6 +650,14 @@ export type JackProvider = {
|
|
|
590
650
|
* leave it undefined and the host returns empty snapshots.
|
|
591
651
|
*/
|
|
592
652
|
persistedPermissions?: PersistedPermissionsApi
|
|
653
|
+
/**
|
|
654
|
+
* Usage / billing capability — provider-owned data flow. See
|
|
655
|
+
* {@link UsageApi}. Optional; when undefined the chip degrades to
|
|
656
|
+
* showing nothing (and `capabilities.usage` MUST be `false`). The
|
|
657
|
+
* provider stays the single source of truth: host plumbs, never
|
|
658
|
+
* decodes.
|
|
659
|
+
*/
|
|
660
|
+
usage?: UsageApi
|
|
593
661
|
}
|
|
594
662
|
|
|
595
663
|
/**
|
|
@@ -608,6 +676,34 @@ export type InProcessMcpServerSpec = {
|
|
|
608
676
|
tools: InProcessMcpToolSpec[]
|
|
609
677
|
}
|
|
610
678
|
|
|
679
|
+
/**
|
|
680
|
+
* Context the host hands to {@link JackProvider.attachClientToolHandler}
|
|
681
|
+
* so the provider can bridge wire-driven side channels back to the host
|
|
682
|
+
* (e.g. mapping Gemini's `available_commands_update` notifications to
|
|
683
|
+
* the renderer's per-session slash command store).
|
|
684
|
+
*
|
|
685
|
+
* Today only `sessionId` is consumed. `actorId` is reserved for the
|
|
686
|
+
* future team-tier multi-user mode (north-star: every entity carries an
|
|
687
|
+
* actor id so coordination scales beyond single-user). Adding a new
|
|
688
|
+
* required field here would be a major bump; new optional fields ride
|
|
689
|
+
* on a minor.
|
|
690
|
+
*/
|
|
691
|
+
export type ClientToolHandlerAttachContext = {
|
|
692
|
+
/**
|
|
693
|
+
* Host correlation id for the session being spawned. Required —
|
|
694
|
+
* the provider stores it on its per-spawn slot so wire notifications
|
|
695
|
+
* can route back to the right host-side consumer.
|
|
696
|
+
*/
|
|
697
|
+
sessionId: string
|
|
698
|
+
/**
|
|
699
|
+
* Actor identity placeholder for future multi-user / team-tier
|
|
700
|
+
* support. Today the host always passes `'self'` (or omits) since
|
|
701
|
+
* Jack runs single-user; future remote-agent flows will populate
|
|
702
|
+
* with `'user_xxx@team_yyy'` style strings.
|
|
703
|
+
*/
|
|
704
|
+
actorId?: string
|
|
705
|
+
}
|
|
706
|
+
|
|
611
707
|
/**
|
|
612
708
|
* Behaviour token the provider persists alongside each rule. Mirror of
|
|
613
709
|
* Claude's `permissions.{allow,deny,ask}` arrays — providers with a
|
|
@@ -624,17 +720,33 @@ export type PermissionBehavior = 'allow' | 'deny' | 'ask'
|
|
|
624
720
|
export type PermissionSource = 'user' | 'userLocal' | 'project' | 'projectLocal'
|
|
625
721
|
|
|
626
722
|
/**
|
|
627
|
-
*
|
|
628
|
-
*
|
|
629
|
-
* (
|
|
723
|
+
* Optional human-readable parse hint for {@link PermissionRule}. Providers
|
|
724
|
+
* whose rule grammar has a recognisable "tool" + "pattern" decomposition
|
|
725
|
+
* (Claude's `Bash(npm install)`, `Edit(*.ts)`) populate this so the UI can
|
|
726
|
+
* render two columns instead of a raw string. Providers with a different
|
|
727
|
+
* grammar (Codex `approval_policy` keyed by command prefix) leave it
|
|
728
|
+
* undefined; the UI falls back to displaying `raw`.
|
|
729
|
+
*/
|
|
730
|
+
export type PermissionRuleHumanReadable = {
|
|
731
|
+
/** Best-effort tool name extracted by the provider (e.g. `Bash`, `Edit`). */
|
|
732
|
+
tool?: string
|
|
733
|
+
/** Best-effort pattern extracted by the provider (the bit inside the parens, etc.). */
|
|
734
|
+
pattern?: string
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* One persisted rule as the provider stores it. `raw` is the only
|
|
739
|
+
* field guaranteed across providers — it's the source of truth for
|
|
740
|
+
* round-trip writes (remove/add use the raw string verbatim) and the
|
|
741
|
+
* fallback display when no parse hint is available. The
|
|
742
|
+
* `humanReadable` sidecar is a Claude-style ergonomic split that
|
|
743
|
+
* other providers may opt out of.
|
|
630
744
|
*/
|
|
631
745
|
export type PermissionRule = {
|
|
632
|
-
/**
|
|
633
|
-
tool: string
|
|
634
|
-
/** Content inside the parens (the glob / pattern), or null if the rule has no parens. */
|
|
635
|
-
pattern: string | null
|
|
636
|
-
/** Original string as stored in the settings file — source of truth for round-trip writes. */
|
|
746
|
+
/** Original string as stored by the provider — source of truth for round-trip writes. */
|
|
637
747
|
raw: string
|
|
748
|
+
/** Optional parse hint for two-column UI rendering. */
|
|
749
|
+
humanReadable?: PermissionRuleHumanReadable
|
|
638
750
|
}
|
|
639
751
|
|
|
640
752
|
export type PermissionsSourceBlock = {
|
|
@@ -687,12 +799,17 @@ export type InProcessMcpToolSpec = {
|
|
|
687
799
|
name: string
|
|
688
800
|
description: string
|
|
689
801
|
/**
|
|
690
|
-
* Zod schema for the tool arguments
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
* (
|
|
802
|
+
* Zod schema for the tool arguments — a `Record<fieldName, ZodType>`
|
|
803
|
+
* (zod's "shape" form, what `z.object(...)` accepts). Provider
|
|
804
|
+
* implementations consume it via the SDK helper of their choice
|
|
805
|
+
* (Claude wraps with `tool(name, desc, schema, handler)` from
|
|
806
|
+
* `@anthropic-ai/claude-agent-sdk`).
|
|
807
|
+
*
|
|
808
|
+
* `zod` is a peer dep of this SDK so consumer + provider type-check
|
|
809
|
+
* against the same instance. The host always produces zod; trying
|
|
810
|
+
* to stuff JSON Schema here would silently break Claude's wrapper.
|
|
694
811
|
*/
|
|
695
|
-
schema: Record<string,
|
|
812
|
+
schema: Record<string, ZodType>
|
|
696
813
|
handler: (args: Record<string, unknown>) => Promise<{
|
|
697
814
|
content: Array<{ type: 'text'; text: string }>
|
|
698
815
|
isError?: boolean
|