@wice24/tars-sdk 0.2.4 → 0.3.1
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/index.d.ts +86 -12
- package/dist/index.js +73 -9
- package/dist/types.d.ts +128 -3
- package/package.json +10 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { Agent, AgentVersion, ClientTool, CreateAgentInput, FileMeta, ListMcpToolsInput, McpCredentialInput, McpCredentialStatus, McpServerTools, ReasoningConfig, SessionEvent, ModelInfo, SessionInfo, SessionListItem, UpdateAgentInput, UploadFileInput, UsageSummary, SessionUsageRow, DailyUsageRow, McpServer, Skill, SkillVersion, ApiKeyInfo, ClientIdentity, ClientRole, PlatformStats, Tenant } from './types.js';
|
|
1
|
+
import type { Agent, AgentVersion, ClientTool, CompactResult, CreateAgentInput, FileMeta, ListMcpToolsInput, McpCredentialInput, McpCredentialStatus, McpServerTools, ReasoningConfig, SessionEvent, ModelInfo, ProviderKeys, ProviderStatusReport, SessionInfo, SessionListItem, UpdateAgentInput, UploadFileInput, UsageSummary, SessionUsageRow, DailyUsageRow, McpServer, Skill, SkillVersion, ApiKeyInfo, ClientIdentity, ClientRole, PlatformStats, Tenant } from './types.js';
|
|
2
2
|
type ToolHandler = (input: any) => unknown | Promise<unknown>;
|
|
3
3
|
export * from './types.js';
|
|
4
|
+
/** The providers `providerKeys` accepts. */
|
|
5
|
+
export declare const KEYED_PROVIDERS: readonly ["anthropic", "openai", "openrouter", "tensorx"];
|
|
4
6
|
export declare class TarsApiError extends Error {
|
|
5
7
|
readonly status: number;
|
|
6
8
|
readonly body: unknown;
|
|
@@ -15,20 +17,35 @@ export interface TarsClientOptions {
|
|
|
15
17
|
* Admin keys only: scope every request to this tenant id (sent as the
|
|
16
18
|
* `X-Tars-Tenant` header). Act-as is READ-ONLY — GETs return the target
|
|
17
19
|
* tenant's data; any write is refused with 403 `act_as_read_only`, and so
|
|
18
|
-
* is live SSE (`
|
|
19
|
-
* a side effect): read the journal via `sessions.get` /
|
|
20
|
-
* instead. Non-admin keys get 403 `admin_required`; an unknown tenant id
|
|
20
|
+
* is live SSE (`streamEvents` / `TarsSession.stream` / `resume` — sandbox
|
|
21
|
+
* reattachment is a side effect): read the journal via `sessions.get` /
|
|
22
|
+
* `sessions.events` instead. Non-admin keys get 403 `admin_required`; an unknown tenant id
|
|
21
23
|
* 404s on every call; an empty value 400s. The effective role is always
|
|
22
24
|
* `tenant`, so `admin.*` calls under act-as also get 403 `admin_required`
|
|
23
25
|
* — use a client WITHOUT this option to administrate.
|
|
24
26
|
*/
|
|
25
27
|
actAsTenant?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Your own LLM provider keys, by provider (`openrouter`, `openai`,
|
|
30
|
+
* `anthropic`, `tensorx`). Sent with EVERY request (one
|
|
31
|
+
* `x-tars-key-<provider>` header each) and used for that request's model
|
|
32
|
+
* calls — session turns, completions, the model catalog — so usage bills to
|
|
33
|
+
* your provider accounts. TARS never stores them. A provider you omit
|
|
34
|
+
* routes on the instance's key only while that instance's cutover fallback
|
|
35
|
+
* is on; otherwise its models are refused with 400
|
|
36
|
+
* `provider_not_configured`. Check with `providerStatus()`.
|
|
37
|
+
*
|
|
38
|
+
* SERVER-SIDE clients only: in a browser these keys would ship to every
|
|
39
|
+
* user of your app.
|
|
40
|
+
*/
|
|
41
|
+
providerKeys?: ProviderKeys;
|
|
26
42
|
}
|
|
27
43
|
export declare class TarsClient {
|
|
28
44
|
private readonly baseUrl;
|
|
29
45
|
private readonly apiKey;
|
|
30
46
|
private readonly fetchImpl;
|
|
31
47
|
private readonly actAsTenant?;
|
|
48
|
+
private readonly providerKeyHeaders;
|
|
32
49
|
constructor(options: TarsClientOptions);
|
|
33
50
|
/** Every request path — JSON, uploads, SSE — sends these, so act-as scoping
|
|
34
51
|
* can never silently miss a surface. */
|
|
@@ -41,11 +58,15 @@ export declare class TarsClient {
|
|
|
41
58
|
}) => Promise<Agent[]>;
|
|
42
59
|
get: (id: string) => Promise<Agent>;
|
|
43
60
|
update: (id: string, patch: UpdateAgentInput) => Promise<Agent>;
|
|
61
|
+
/** Archived agents refuse new sessions (409) and updates; existing
|
|
62
|
+
* sessions keep running. */
|
|
44
63
|
archive: (id: string) => Promise<{
|
|
45
64
|
ok: boolean;
|
|
65
|
+
status: "archived";
|
|
46
66
|
}>;
|
|
47
67
|
unarchive: (id: string) => Promise<{
|
|
48
68
|
ok: boolean;
|
|
69
|
+
status: "active";
|
|
49
70
|
}>;
|
|
50
71
|
versions: (id: string) => Promise<AgentVersion[]>;
|
|
51
72
|
};
|
|
@@ -79,6 +100,20 @@ export declare class TarsClient {
|
|
|
79
100
|
rename: (id: string, title: string) => Promise<{
|
|
80
101
|
ok: boolean;
|
|
81
102
|
}>;
|
|
103
|
+
/**
|
|
104
|
+
* One page of the session's journal — the same events `get()` inlines,
|
|
105
|
+
* for incremental readers on long sessions. `afterSeq` is the last seq
|
|
106
|
+
* you hold (-1 = from the start); `limit` 1..1000 (default 500).
|
|
107
|
+
* `has_more` says another page follows. Allowed under act-as, unlike the
|
|
108
|
+
* live stream.
|
|
109
|
+
*/
|
|
110
|
+
events: (id: string, opts?: {
|
|
111
|
+
afterSeq?: number;
|
|
112
|
+
limit?: number;
|
|
113
|
+
}) => Promise<{
|
|
114
|
+
events: SessionEvent[];
|
|
115
|
+
has_more: boolean;
|
|
116
|
+
}>;
|
|
82
117
|
/** Replace the session's extra MCP server set (takes effect next turn;
|
|
83
118
|
* 409s while a turn is in flight). */
|
|
84
119
|
setMcpServers: (id: string, servers: McpServer[]) => Promise<{
|
|
@@ -95,6 +130,17 @@ export declare class TarsClient {
|
|
|
95
130
|
ok: boolean;
|
|
96
131
|
interrupted: boolean;
|
|
97
132
|
}>;
|
|
133
|
+
/**
|
|
134
|
+
* Compact the session's context now: the older history is folded into a
|
|
135
|
+
* checkpoint summary and the recent tail kept verbatim — what the
|
|
136
|
+
* platform does on its own as a session nears its model's context
|
|
137
|
+
* window (the `compaction` event either way). Idle sessions only
|
|
138
|
+
* (`turn_in_progress` otherwise). `instructions` is an optional focus
|
|
139
|
+
* for the summary ("keep every SQL statement verbatim").
|
|
140
|
+
*/
|
|
141
|
+
compact: (id: string, opts?: {
|
|
142
|
+
instructions?: string;
|
|
143
|
+
}) => Promise<CompactResult>;
|
|
98
144
|
usage: (id: string) => Promise<{
|
|
99
145
|
session_id: string;
|
|
100
146
|
model: string;
|
|
@@ -146,12 +192,17 @@ export declare class TarsClient {
|
|
|
146
192
|
list: () => Promise<Skill[]>;
|
|
147
193
|
get: (id: string) => Promise<Skill>;
|
|
148
194
|
versions: (id: string) => Promise<SkillVersion[]>;
|
|
149
|
-
/** Upload a new immutable version from zip bytes.
|
|
195
|
+
/** Upload a new immutable version from zip bytes. `name` / `description`
|
|
196
|
+
* are what SKILL.md's front matter declared (null when absent); `files`
|
|
197
|
+
* counts the bundle's entries. */
|
|
150
198
|
pushVersion: (id: string, zipBytes: Uint8Array) => Promise<{
|
|
151
199
|
skill_id: string;
|
|
152
200
|
slug: string;
|
|
153
201
|
version: number;
|
|
202
|
+
name: string | null;
|
|
203
|
+
description: string | null;
|
|
154
204
|
files: number;
|
|
205
|
+
size_bytes: number;
|
|
155
206
|
}>;
|
|
156
207
|
/**
|
|
157
208
|
* Download one immutable version's zip bytes — exactly what `pushVersion`
|
|
@@ -160,12 +211,14 @@ export declare class TarsClient {
|
|
|
160
211
|
downloadVersion: (id: string, version: number) => Promise<Uint8Array>;
|
|
161
212
|
};
|
|
162
213
|
readonly apiKeys: {
|
|
214
|
+
/** Mint another key for this tenant. `key` is returned ONCE. */
|
|
163
215
|
create: (input?: {
|
|
164
216
|
name?: string;
|
|
165
217
|
}) => Promise<{
|
|
166
218
|
id: string;
|
|
167
219
|
key: string;
|
|
168
220
|
key_prefix: string;
|
|
221
|
+
name: string | null;
|
|
169
222
|
}>;
|
|
170
223
|
list: () => Promise<ApiKeyInfo[]>;
|
|
171
224
|
revoke: (id: string) => Promise<{
|
|
@@ -224,24 +277,37 @@ export declare class TarsClient {
|
|
|
224
277
|
usage: {
|
|
225
278
|
input_tokens: number;
|
|
226
279
|
output_tokens: number;
|
|
280
|
+
cache_read_tokens: number;
|
|
281
|
+
cache_write_tokens: number;
|
|
282
|
+
cost_usd?: number;
|
|
283
|
+
cost_source?: "provider";
|
|
284
|
+
upstream_cost_usd?: number;
|
|
227
285
|
};
|
|
228
286
|
}>;
|
|
229
287
|
};
|
|
230
288
|
/**
|
|
231
|
-
* Which model providers
|
|
232
|
-
* `openrouter`, `custom`)
|
|
233
|
-
*
|
|
234
|
-
*
|
|
289
|
+
* Which model providers YOU can route now (`anthropic`, `openai`,
|
|
290
|
+
* `openrouter`, `tensorx`, `custom`): those you passed in `providerKeys`,
|
|
291
|
+
* plus the instance's while its cutover fallback is on, plus `custom` on an
|
|
292
|
+
* instance pointed at a local runtime. Ask before OFFERING models: a picker
|
|
293
|
+
* listing GPT models without an OpenAI key produces turns that all fail.
|
|
235
294
|
*/
|
|
236
295
|
providers(): Promise<string[]>;
|
|
296
|
+
/**
|
|
297
|
+
* Every provider with whether you can route it and on whose key
|
|
298
|
+
* (`request` = your `providerKeys`, `instance` = the deployment's), plus
|
|
299
|
+
* whether the instance still falls back to its own keys. What a settings
|
|
300
|
+
* page shows: all providers, the inactive ones disabled.
|
|
301
|
+
*/
|
|
302
|
+
providerStatus(): Promise<ProviderStatusReport>;
|
|
237
303
|
/**
|
|
238
304
|
* The models this instance can route AND price — ids are full
|
|
239
|
-
* `provider/model` specs. `openrouter/*` entries mirror
|
|
240
|
-
*
|
|
305
|
+
* `provider/model` specs. `openrouter/*` and `tensorx/*` entries mirror
|
|
306
|
+
* those providers' live catalogs, so those ids exist right now; direct entries
|
|
241
307
|
* come from the deployment's curated pricing table. Offer models from this
|
|
242
308
|
* list rather than hardcoding ids that can drift.
|
|
243
309
|
*
|
|
244
|
-
* The list is "what is known now", not "everything routable":
|
|
310
|
+
* The list is "what is known now", not "everything routable": catalog
|
|
245
311
|
* entries are absent before the instance's first successful catalog
|
|
246
312
|
* refresh, and a deployment routing only `custom/*` has no priced entries
|
|
247
313
|
* at all. When it comes back empty, fall back to `providers()` plus your
|
|
@@ -276,6 +342,8 @@ export declare class TarsClient {
|
|
|
276
342
|
fileId: string;
|
|
277
343
|
mountPath?: string;
|
|
278
344
|
}): Promise<{
|
|
345
|
+
ok: boolean;
|
|
346
|
+
file_id: string;
|
|
279
347
|
mount_path: string;
|
|
280
348
|
size_bytes: number;
|
|
281
349
|
}>;
|
|
@@ -310,6 +378,8 @@ export declare class TarsSession {
|
|
|
310
378
|
after?: number;
|
|
311
379
|
}): AsyncGenerator<SessionEvent>;
|
|
312
380
|
mountFile(fileId: string, mountPath?: string): Promise<{
|
|
381
|
+
ok: boolean;
|
|
382
|
+
file_id: string;
|
|
313
383
|
mount_path: string;
|
|
314
384
|
size_bytes: number;
|
|
315
385
|
}>;
|
|
@@ -324,6 +394,10 @@ export declare class TarsSession {
|
|
|
324
394
|
ok: boolean;
|
|
325
395
|
interrupted: boolean;
|
|
326
396
|
}>;
|
|
397
|
+
/** Compact the context now — see `TarsClient.sessions.compact`. */
|
|
398
|
+
compact(opts?: {
|
|
399
|
+
instructions?: string;
|
|
400
|
+
}): Promise<CompactResult>;
|
|
327
401
|
destroy(): Promise<{
|
|
328
402
|
ok: boolean;
|
|
329
403
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export * from './types.js';
|
|
2
|
+
/** The providers `providerKeys` accepts. */
|
|
3
|
+
export const KEYED_PROVIDERS = ['anthropic', 'openai', 'openrouter', 'tensorx'];
|
|
2
4
|
export class TarsApiError extends Error {
|
|
3
5
|
status;
|
|
4
6
|
body;
|
|
@@ -14,6 +16,7 @@ export class TarsClient {
|
|
|
14
16
|
apiKey;
|
|
15
17
|
fetchImpl;
|
|
16
18
|
actAsTenant;
|
|
19
|
+
providerKeyHeaders;
|
|
17
20
|
constructor(options) {
|
|
18
21
|
if (!options.apiKey)
|
|
19
22
|
throw new Error('TarsClient: apiKey is required');
|
|
@@ -22,6 +25,13 @@ export class TarsClient {
|
|
|
22
25
|
// Bind: an unbound global fetch throws "Illegal invocation" in browsers.
|
|
23
26
|
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
24
27
|
this.actAsTenant = options.actAsTenant;
|
|
28
|
+
const unknown = Object.keys(options.providerKeys ?? {}).filter((p) => !KEYED_PROVIDERS.includes(p));
|
|
29
|
+
if (unknown.length > 0) {
|
|
30
|
+
throw new Error(`TarsClient: unknown providerKeys ${unknown.join(', ')} (expected ${KEYED_PROVIDERS.join(', ')})`);
|
|
31
|
+
}
|
|
32
|
+
this.providerKeyHeaders = Object.fromEntries(Object.entries(options.providerKeys ?? {})
|
|
33
|
+
.filter(([, key]) => typeof key === 'string' && key.trim() !== '')
|
|
34
|
+
.map(([provider, key]) => [`x-tars-key-${provider}`, key.trim()]));
|
|
25
35
|
}
|
|
26
36
|
// ── low-level HTTP ───────────────────────────────────────────
|
|
27
37
|
/** Every request path — JSON, uploads, SSE — sends these, so act-as scoping
|
|
@@ -30,6 +40,7 @@ export class TarsClient {
|
|
|
30
40
|
return {
|
|
31
41
|
authorization: `Bearer ${this.apiKey}`,
|
|
32
42
|
...(this.actAsTenant ? { 'x-tars-tenant': this.actAsTenant } : {}),
|
|
43
|
+
...this.providerKeyHeaders,
|
|
33
44
|
};
|
|
34
45
|
}
|
|
35
46
|
async request(method, path, body) {
|
|
@@ -56,6 +67,8 @@ export class TarsClient {
|
|
|
56
67
|
},
|
|
57
68
|
get: (id) => this.request('GET', `/v1/agents/${id}`),
|
|
58
69
|
update: (id, patch) => this.request('PATCH', `/v1/agents/${id}`, patch),
|
|
70
|
+
/** Archived agents refuse new sessions (409) and updates; existing
|
|
71
|
+
* sessions keep running. */
|
|
59
72
|
archive: (id) => this.request('POST', `/v1/agents/${id}/archive`),
|
|
60
73
|
unarchive: (id) => this.request('POST', `/v1/agents/${id}/unarchive`),
|
|
61
74
|
versions: async (id) => {
|
|
@@ -104,6 +117,22 @@ export class TarsClient {
|
|
|
104
117
|
return { sessions: res.sessions, nextCursor: res.next_cursor };
|
|
105
118
|
},
|
|
106
119
|
rename: (id, title) => this.request('PATCH', `/v1/sessions/${id}`, { title }),
|
|
120
|
+
/**
|
|
121
|
+
* One page of the session's journal — the same events `get()` inlines,
|
|
122
|
+
* for incremental readers on long sessions. `afterSeq` is the last seq
|
|
123
|
+
* you hold (-1 = from the start); `limit` 1..1000 (default 500).
|
|
124
|
+
* `has_more` says another page follows. Allowed under act-as, unlike the
|
|
125
|
+
* live stream.
|
|
126
|
+
*/
|
|
127
|
+
events: async (id, opts) => {
|
|
128
|
+
const params = new URLSearchParams();
|
|
129
|
+
if (opts?.afterSeq !== undefined)
|
|
130
|
+
params.set('after_seq', String(opts.afterSeq));
|
|
131
|
+
if (opts?.limit)
|
|
132
|
+
params.set('limit', String(opts.limit));
|
|
133
|
+
const qs = params.size ? `?${params}` : '';
|
|
134
|
+
return this.request('GET', `/v1/sessions/${id}/events${qs}`);
|
|
135
|
+
},
|
|
107
136
|
/** Replace the session's extra MCP server set (takes effect next turn;
|
|
108
137
|
* 409s while a turn is in flight). */
|
|
109
138
|
setMcpServers: (id, servers) => this.request('PATCH', `/v1/sessions/${id}`, { mcp_servers: servers }),
|
|
@@ -120,6 +149,15 @@ export class TarsClient {
|
|
|
120
149
|
}),
|
|
121
150
|
/** Abort the in-flight turn, if any. Idempotent. */
|
|
122
151
|
interrupt: (id) => this.request('POST', `/v1/sessions/${id}/interrupt`),
|
|
152
|
+
/**
|
|
153
|
+
* Compact the session's context now: the older history is folded into a
|
|
154
|
+
* checkpoint summary and the recent tail kept verbatim — what the
|
|
155
|
+
* platform does on its own as a session nears its model's context
|
|
156
|
+
* window (the `compaction` event either way). Idle sessions only
|
|
157
|
+
* (`turn_in_progress` otherwise). `instructions` is an optional focus
|
|
158
|
+
* for the summary ("keep every SQL statement verbatim").
|
|
159
|
+
*/
|
|
160
|
+
compact: (id, opts) => this.request('POST', `/v1/sessions/${id}/compact`, opts ?? {}),
|
|
123
161
|
usage: (id) => this.request('GET', `/v1/sessions/${id}/usage`),
|
|
124
162
|
get: (id) => this.request('GET', `/v1/sessions/${id}`),
|
|
125
163
|
// Re-open an existing session (e.g. after a page refresh or on another
|
|
@@ -176,6 +214,8 @@ export class TarsClient {
|
|
|
176
214
|
params.set('auth', input.auth);
|
|
177
215
|
if (input.endUserId)
|
|
178
216
|
params.set('end_user_id', input.endUserId);
|
|
217
|
+
if (input.schemas)
|
|
218
|
+
params.set('schemas', '1');
|
|
179
219
|
return this.request('GET', `/v1/mcp-servers/tools?${params}`);
|
|
180
220
|
},
|
|
181
221
|
};
|
|
@@ -186,7 +226,9 @@ export class TarsClient {
|
|
|
186
226
|
list: async () => (await this.request('GET', '/v1/skills')).skills,
|
|
187
227
|
get: (id) => this.request('GET', `/v1/skills/${id}`),
|
|
188
228
|
versions: async (id) => (await this.request('GET', `/v1/skills/${id}/versions`)).versions,
|
|
189
|
-
/** Upload a new immutable version from zip bytes.
|
|
229
|
+
/** Upload a new immutable version from zip bytes. `name` / `description`
|
|
230
|
+
* are what SKILL.md's front matter declared (null when absent); `files`
|
|
231
|
+
* counts the bundle's entries. */
|
|
190
232
|
pushVersion: async (id, zipBytes) => {
|
|
191
233
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/skills/${id}/versions`, {
|
|
192
234
|
method: 'POST',
|
|
@@ -212,6 +254,7 @@ export class TarsClient {
|
|
|
212
254
|
};
|
|
213
255
|
// ── api keys / identity ──────────────────────────────────────
|
|
214
256
|
apiKeys = {
|
|
257
|
+
/** Mint another key for this tenant. `key` is returned ONCE. */
|
|
215
258
|
create: (input) => this.request('POST', '/v1/api-keys', { ...(input?.name ? { name: input.name } : {}) }),
|
|
216
259
|
list: async () => (await this.request('GET', '/v1/api-keys')).keys,
|
|
217
260
|
revoke: (id) => this.request('DELETE', `/v1/api-keys/${id}`),
|
|
@@ -244,7 +287,14 @@ export class TarsClient {
|
|
|
244
287
|
};
|
|
245
288
|
// ── completions / providers (any key) ────────────────────────
|
|
246
289
|
// Cheap non-session completion (titles and other one-shots) — routed
|
|
247
|
-
// through the same provider seam as agent turns
|
|
290
|
+
// through the same provider seam as agent turns, on this client's
|
|
291
|
+
// `providerKeys` (400 `provider_not_configured` when the model's provider
|
|
292
|
+
// is not routable). `maxTokens` defaults to 256 and is capped at 1024;
|
|
293
|
+
// `model` defaults to `openrouter/anthropic/claude-haiku-4-5`. In `usage`,
|
|
294
|
+
// the cache counts make a caching claim checkable from outside; `cost_usd`
|
|
295
|
+
// is present only when the provider reported a bill (`cost_source:
|
|
296
|
+
// 'provider'`), and `upstream_cost_usd`, under BYOK through OpenRouter, is
|
|
297
|
+
// what the vendor charged the key's owner.
|
|
248
298
|
completions = {
|
|
249
299
|
create: (input) => this.request('POST', '/v1/completions', {
|
|
250
300
|
prompt: input.prompt,
|
|
@@ -254,23 +304,33 @@ export class TarsClient {
|
|
|
254
304
|
}),
|
|
255
305
|
};
|
|
256
306
|
/**
|
|
257
|
-
* Which model providers
|
|
258
|
-
* `openrouter`, `custom`)
|
|
259
|
-
*
|
|
260
|
-
*
|
|
307
|
+
* Which model providers YOU can route now (`anthropic`, `openai`,
|
|
308
|
+
* `openrouter`, `tensorx`, `custom`): those you passed in `providerKeys`,
|
|
309
|
+
* plus the instance's while its cutover fallback is on, plus `custom` on an
|
|
310
|
+
* instance pointed at a local runtime. Ask before OFFERING models: a picker
|
|
311
|
+
* listing GPT models without an OpenAI key produces turns that all fail.
|
|
261
312
|
*/
|
|
262
313
|
async providers() {
|
|
263
314
|
const body = await this.request('GET', '/v1/providers');
|
|
264
315
|
return body.providers ?? [];
|
|
265
316
|
}
|
|
317
|
+
/**
|
|
318
|
+
* Every provider with whether you can route it and on whose key
|
|
319
|
+
* (`request` = your `providerKeys`, `instance` = the deployment's), plus
|
|
320
|
+
* whether the instance still falls back to its own keys. What a settings
|
|
321
|
+
* page shows: all providers, the inactive ones disabled.
|
|
322
|
+
*/
|
|
323
|
+
async providerStatus() {
|
|
324
|
+
return this.request('GET', '/v1/providers/status');
|
|
325
|
+
}
|
|
266
326
|
/**
|
|
267
327
|
* The models this instance can route AND price — ids are full
|
|
268
|
-
* `provider/model` specs. `openrouter/*` entries mirror
|
|
269
|
-
*
|
|
328
|
+
* `provider/model` specs. `openrouter/*` and `tensorx/*` entries mirror
|
|
329
|
+
* those providers' live catalogs, so those ids exist right now; direct entries
|
|
270
330
|
* come from the deployment's curated pricing table. Offer models from this
|
|
271
331
|
* list rather than hardcoding ids that can drift.
|
|
272
332
|
*
|
|
273
|
-
* The list is "what is known now", not "everything routable":
|
|
333
|
+
* The list is "what is known now", not "everything routable": catalog
|
|
274
334
|
* entries are absent before the instance's first successful catalog
|
|
275
335
|
* refresh, and a deployment routing only `custom/*` has no priced entries
|
|
276
336
|
* at all. When it comes back empty, fall back to `providers()` plus your
|
|
@@ -508,6 +568,10 @@ export class TarsSession {
|
|
|
508
568
|
interrupt() {
|
|
509
569
|
return this.client.sessions.interrupt(this.info.id);
|
|
510
570
|
}
|
|
571
|
+
/** Compact the context now — see `TarsClient.sessions.compact`. */
|
|
572
|
+
compact(opts) {
|
|
573
|
+
return this.client.sessions.compact(this.info.id, opts);
|
|
574
|
+
}
|
|
511
575
|
destroy() {
|
|
512
576
|
return this.client.sessions.destroy(this.info.id);
|
|
513
577
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -67,6 +67,12 @@ export type SessionEvent = {
|
|
|
67
67
|
} & ({
|
|
68
68
|
status: 'connected';
|
|
69
69
|
tool_count: number;
|
|
70
|
+
/** Estimated tokens this server's kept tool definitions (names,
|
|
71
|
+
* descriptions, input schemas) add to every request of the turn,
|
|
72
|
+
* at ~4 chars/token — size connectors against each other and
|
|
73
|
+
* against the rest of the prompt. Absent on rows journaled
|
|
74
|
+
* before 0.3.0. */
|
|
75
|
+
schema_tokens?: number;
|
|
70
76
|
/** The tool names the model received from this server (its own
|
|
71
77
|
* unprefixed names, in server order) — what `tool_count` counts.
|
|
72
78
|
* Absent on rows journaled by servers before 0.2.4. */
|
|
@@ -90,7 +96,44 @@ export type SessionEvent = {
|
|
|
90
96
|
message: string;
|
|
91
97
|
server?: string;
|
|
92
98
|
retry_status: 'terminal' | 'exhausted';
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Context compaction: the older history was folded into a summary
|
|
102
|
+
* checkpoint and the recent tail kept verbatim, so the session stays under
|
|
103
|
+
* the model's context window. Nested discriminant on `status`, like
|
|
104
|
+
* mcp_connect: `started` opens the (possibly long) summarization,
|
|
105
|
+
* `completed` carries the checkpoint the model now runs on, `failed` says
|
|
106
|
+
* the history is unchanged. `reason`: `auto` = the threshold check before
|
|
107
|
+
* a model call, `overflow` = the provider rejected the prompt as too long,
|
|
108
|
+
* `manual` = `sessions.compact()`.
|
|
109
|
+
*/
|
|
110
|
+
| ({
|
|
111
|
+
type: 'compaction';
|
|
112
|
+
reason: CompactionReason;
|
|
113
|
+
} & ({
|
|
114
|
+
status: 'started';
|
|
93
115
|
} | {
|
|
116
|
+
status: 'completed';
|
|
117
|
+
/** The checkpoint text the model sees in place of the summarized
|
|
118
|
+
* messages — the tenant-visible record of what was kept. */
|
|
119
|
+
summary: string;
|
|
120
|
+
/** Estimated prompt tokens before and after (chars/4 over the
|
|
121
|
+
* history; the provider's own count lands on the next turn_end). */
|
|
122
|
+
tokens_before: number;
|
|
123
|
+
tokens_after: number;
|
|
124
|
+
/** How many history messages the summary replaced, and how many
|
|
125
|
+
* recent ones stayed verbatim after it. */
|
|
126
|
+
summarized_messages: number;
|
|
127
|
+
kept_messages: number;
|
|
128
|
+
/** The model that wrote the summary; `fallback` when the
|
|
129
|
+
* summarizer failed during overflow recovery and a deterministic
|
|
130
|
+
* checkpoint (the dropped requests, listed) was written instead. */
|
|
131
|
+
model: string;
|
|
132
|
+
} | {
|
|
133
|
+
status: 'failed';
|
|
134
|
+
code: AgentErrorCode;
|
|
135
|
+
message: string;
|
|
136
|
+
})) | {
|
|
94
137
|
type: 'turn_end';
|
|
95
138
|
reason: 'completed' | 'interrupted' | 'error';
|
|
96
139
|
usage?: {
|
|
@@ -102,13 +145,39 @@ export type SessionEvent = {
|
|
|
102
145
|
cacheReadTokens?: number;
|
|
103
146
|
/** Input tokens written to the provider's prompt cache. */
|
|
104
147
|
cacheWriteTokens?: number;
|
|
148
|
+
/** The LAST model step's full prompt size (uncached + cache read +
|
|
149
|
+
* cache write) as the provider counted it — what the next turn
|
|
150
|
+
* starts from, and the exact figure for a context gauge. The
|
|
151
|
+
* buckets above are SUMS over the turn's steps. Absent on turns
|
|
152
|
+
* that ended before a step completed. */
|
|
153
|
+
contextTokens?: number;
|
|
105
154
|
};
|
|
106
155
|
});
|
|
156
|
+
/** Why a compaction ran — see the `compaction` event. */
|
|
157
|
+
export type CompactionReason = 'auto' | 'overflow' | 'manual';
|
|
158
|
+
/** `sessions.compact()` — the no-op success (`compacted: false`) means the
|
|
159
|
+
* history was too short to fold; a summarizer failure is a thrown
|
|
160
|
+
* `TarsApiError` (502, code `compaction_failed`) and leaves the history as
|
|
161
|
+
* is. */
|
|
162
|
+
export type CompactResult = {
|
|
163
|
+
ok: true;
|
|
164
|
+
compacted: true;
|
|
165
|
+
/** Estimated prompt tokens before and after (chars/4 over the history). */
|
|
166
|
+
tokens_before: number;
|
|
167
|
+
tokens_after: number;
|
|
168
|
+
summarized_messages: number;
|
|
169
|
+
kept_messages: number;
|
|
170
|
+
} | {
|
|
171
|
+
ok: true;
|
|
172
|
+
compacted: false;
|
|
173
|
+
reason: 'nothing_to_compact';
|
|
174
|
+
};
|
|
107
175
|
export type BuiltInTool = 'bash' | 'read_file' | 'write_file' | 'edit_file' | 'glob' | 'grep' | 'web_fetch';
|
|
108
176
|
/**
|
|
109
177
|
* Extended-thinking depth. Provider-neutral: TARS maps it to Anthropic's
|
|
110
|
-
* `effort` (with adaptive thinking)
|
|
111
|
-
* (`max` → `xhigh`)
|
|
178
|
+
* `effort` (with adaptive thinking), OpenRouter's `reasoning.effort`
|
|
179
|
+
* (`max` → `xhigh`), or TensorX's `reasoning_effort` (`xhigh`/`max` →
|
|
180
|
+
* `high`; models there may ignore it). Omit for the provider default. The reasoning text itself
|
|
112
181
|
* is never streamed or journaled — only its depth is configurable.
|
|
113
182
|
*/
|
|
114
183
|
export type ReasoningEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
@@ -177,6 +246,9 @@ export interface Skill {
|
|
|
177
246
|
display_title: string;
|
|
178
247
|
latest_version: number;
|
|
179
248
|
created_at: string;
|
|
249
|
+
/** Present on `get()` / `list()`; the `create()` echo omits both. */
|
|
250
|
+
client_id?: string;
|
|
251
|
+
updated_at?: string;
|
|
180
252
|
}
|
|
181
253
|
export interface SkillVersion {
|
|
182
254
|
version: number;
|
|
@@ -185,6 +257,24 @@ export interface SkillVersion {
|
|
|
185
257
|
size_bytes: number;
|
|
186
258
|
created_at: string;
|
|
187
259
|
}
|
|
260
|
+
/** Providers a client brings its own key for (`TarsClientOptions.providerKeys`). */
|
|
261
|
+
export type KeyedProvider = 'anthropic' | 'openai' | 'openrouter' | 'tensorx';
|
|
262
|
+
/** Every routable provider; `custom` is configured per instance, never per client. */
|
|
263
|
+
export type ProviderName = KeyedProvider | 'custom';
|
|
264
|
+
export type ProviderKeys = Partial<Record<KeyedProvider, string>>;
|
|
265
|
+
export interface ProviderStatus {
|
|
266
|
+
provider: ProviderName;
|
|
267
|
+
/** Can this client route a model on it right now? */
|
|
268
|
+
active: boolean;
|
|
269
|
+
/** Whose key would route it: yours (`request`), the instance's, or none. */
|
|
270
|
+
source: 'request' | 'instance' | null;
|
|
271
|
+
}
|
|
272
|
+
export interface ProviderStatusReport {
|
|
273
|
+
providers: ProviderStatus[];
|
|
274
|
+
/** True while the instance still routes providers you sent no key for on
|
|
275
|
+
* its own keys (the cutover fallback). */
|
|
276
|
+
instance_fallback: boolean;
|
|
277
|
+
}
|
|
188
278
|
/** One routable-and-priced model from `GET /v1/models`. Prices are USD per
|
|
189
279
|
* million tokens; `id` is the full `provider/model` spec, usable as-is when
|
|
190
280
|
* creating agents/sessions. The list is "what is known now" — see
|
|
@@ -192,6 +282,9 @@ export interface SkillVersion {
|
|
|
192
282
|
export interface ModelInfo {
|
|
193
283
|
id: string;
|
|
194
284
|
name: string;
|
|
285
|
+
/** Context window in tokens, when the provider's catalog publishes one
|
|
286
|
+
* (OpenRouter, TensorX). Absent for the direct routes. */
|
|
287
|
+
context_window?: number;
|
|
195
288
|
pricing: {
|
|
196
289
|
input: number;
|
|
197
290
|
output: number;
|
|
@@ -274,6 +367,9 @@ export interface McpCredentialStatus {
|
|
|
274
367
|
auth_type: 'bearer' | 'oauth';
|
|
275
368
|
expires_at: string | null;
|
|
276
369
|
updated_at: string;
|
|
370
|
+
/** Can TARS renew this credential itself? `false` on an oauth credential
|
|
371
|
+
* means it will dead-end at `connect_required` when it expires. */
|
|
372
|
+
refreshable: boolean;
|
|
277
373
|
}
|
|
278
374
|
/** How `mcp.listTools` names the server: the same fields a declaration
|
|
279
375
|
* carries (so the credential lookup and the dial match a turn's), plus whose
|
|
@@ -286,12 +382,34 @@ export interface ListMcpToolsInput {
|
|
|
286
382
|
/** Resolve this end user's credential first, then the tenant-level one;
|
|
287
383
|
* omit for tenant-level only. Only read when `auth` is `'required'`. */
|
|
288
384
|
endUserId?: string;
|
|
385
|
+
/** Also return each tool's `input_schema` and its FULL description — the
|
|
386
|
+
* exact definition the model is shown, for weighing a connector's prompt
|
|
387
|
+
* cost per tool. Off (default): picker shape, descriptions capped. */
|
|
388
|
+
schemas?: boolean;
|
|
289
389
|
}
|
|
290
390
|
/** One tool as the server lists it. `description` is capped at 500
|
|
291
|
-
* characters (an ellipsis marks a cut)
|
|
391
|
+
* characters (an ellipsis marks a cut) unless `schemas` was requested;
|
|
392
|
+
* `null` when the server gave none. */
|
|
393
|
+
/** The MCP spec's tool annotations, as the server sent them (these five
|
|
394
|
+
* keys only). Hints for grouping and labelling tools in a picker, never
|
|
395
|
+
* guarantees: a policy (`tools` / `blocked_tools`) must not trust them. */
|
|
396
|
+
export interface McpToolAnnotations {
|
|
397
|
+
title?: string;
|
|
398
|
+
readOnlyHint?: boolean;
|
|
399
|
+
destructiveHint?: boolean;
|
|
400
|
+
idempotentHint?: boolean;
|
|
401
|
+
openWorldHint?: boolean;
|
|
402
|
+
}
|
|
292
403
|
export interface McpToolInfo {
|
|
293
404
|
name: string;
|
|
294
405
|
description: string | null;
|
|
406
|
+
/** Human-readable name: the tool's `title`, else `annotations.title`,
|
|
407
|
+
* else null when the server gave neither. */
|
|
408
|
+
title: string | null;
|
|
409
|
+
/** The server's annotations; null when it sent none. */
|
|
410
|
+
annotations: McpToolAnnotations | null;
|
|
411
|
+
/** The input JSON Schema as listed — present only with `schemas: true`. */
|
|
412
|
+
input_schema?: Record<string, unknown>;
|
|
295
413
|
}
|
|
296
414
|
export interface McpServerTools {
|
|
297
415
|
server: string;
|
|
@@ -337,9 +455,12 @@ export interface SessionClientTool {
|
|
|
337
455
|
* given turn is in that turn's `mcp_connect` event (`tools` / `filtered_out`).
|
|
338
456
|
*/
|
|
339
457
|
export interface SessionToolSurface {
|
|
458
|
+
/** `input_schema`: the JSON Schema (draft-7) the model is shown for the
|
|
459
|
+
* tool — size it to know what the built-ins cost in context. */
|
|
340
460
|
builtin: Array<{
|
|
341
461
|
name: BuiltInTool;
|
|
342
462
|
description: string;
|
|
463
|
+
input_schema: Record<string, unknown>;
|
|
343
464
|
}>;
|
|
344
465
|
client: SessionClientTool[];
|
|
345
466
|
mcp_servers: McpServer[];
|
|
@@ -459,8 +580,12 @@ export interface DailyUsageRow {
|
|
|
459
580
|
}
|
|
460
581
|
export interface SessionListItem {
|
|
461
582
|
id: string;
|
|
583
|
+
/** A `SessionStatus` value (typed loosely for compatibility). */
|
|
462
584
|
status: string;
|
|
463
585
|
turn_state: TurnState;
|
|
586
|
+
/** Only meaningful with `includeArchived`; absent from servers predating
|
|
587
|
+
* this field. */
|
|
588
|
+
archived?: boolean;
|
|
464
589
|
model: string;
|
|
465
590
|
agent_id: string | null;
|
|
466
591
|
end_user_id: string | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wice24/tars-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Client SDK for TARS — the self-hosted managed-agents platform (sessions, streaming turns, client tools, MCP credentials, skills, files, usage, tenant administration)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -12,13 +12,6 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"dist"
|
|
14
14
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "tsc -p tsconfig.build.json",
|
|
17
|
-
"typecheck": "tsc --noEmit",
|
|
18
|
-
"test": "vitest run",
|
|
19
|
-
"test:watch": "vitest",
|
|
20
|
-
"test:coverage": "vitest run --coverage"
|
|
21
|
-
},
|
|
22
15
|
"devDependencies": {
|
|
23
16
|
"typescript": "^6.0.3",
|
|
24
17
|
"@types/node": "^26.1.0",
|
|
@@ -40,5 +33,12 @@
|
|
|
40
33
|
"mcp",
|
|
41
34
|
"anthropic",
|
|
42
35
|
"sdk"
|
|
43
|
-
]
|
|
44
|
-
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.build.json",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"test:watch": "vitest",
|
|
42
|
+
"test:coverage": "vitest run --coverage"
|
|
43
|
+
}
|
|
44
|
+
}
|