@wice24/tars-sdk 0.1.7 → 0.2.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/index.d.ts +33 -1
- package/dist/index.js +35 -7
- package/dist/types.d.ts +66 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Agent, AgentVersion, ClientTool, CreateAgentInput, FileMeta, McpCredentialInput, McpCredentialStatus, SessionEvent, SessionInfo, SessionListItem, UpdateAgentInput, UploadFileInput, UsageSummary, SessionUsageRow, DailyUsageRow, McpServer, Skill, SkillVersion, ApiKeyInfo, ClientIdentity, ClientRole, PlatformStats, Tenant } from './types.js';
|
|
1
|
+
import type { Agent, AgentVersion, ClientTool, CreateAgentInput, FileMeta, McpCredentialInput, McpCredentialStatus, ReasoningConfig, SessionEvent, ModelInfo, 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
4
|
export declare class TarsApiError extends Error {
|
|
@@ -11,12 +11,28 @@ export interface TarsClientOptions {
|
|
|
11
11
|
baseUrl?: string;
|
|
12
12
|
/** Injectable fetch (tests, custom agents/proxies). Defaults to global fetch. */
|
|
13
13
|
fetchImpl?: typeof globalThis.fetch;
|
|
14
|
+
/**
|
|
15
|
+
* Admin keys only: scope every request to this tenant id (sent as the
|
|
16
|
+
* `X-Tars-Tenant` header). Act-as is READ-ONLY — GETs return the target
|
|
17
|
+
* tenant's data; any write is refused with 403 `act_as_read_only`, and so
|
|
18
|
+
* is live SSE (`sessions.stream` / `resumeStream` — sandbox reattachment is
|
|
19
|
+
* a side effect): read the journal via `sessions.get` / `sessions.events`
|
|
20
|
+
* instead. Non-admin keys get 403 `admin_required`; an unknown tenant id
|
|
21
|
+
* 404s on every call; an empty value 400s. The effective role is always
|
|
22
|
+
* `tenant`, so `admin.*` calls under act-as also get 403 `admin_required`
|
|
23
|
+
* — use a client WITHOUT this option to administrate.
|
|
24
|
+
*/
|
|
25
|
+
actAsTenant?: string;
|
|
14
26
|
}
|
|
15
27
|
export declare class TarsClient {
|
|
16
28
|
private readonly baseUrl;
|
|
17
29
|
private readonly apiKey;
|
|
18
30
|
private readonly fetchImpl;
|
|
31
|
+
private readonly actAsTenant?;
|
|
19
32
|
constructor(options: TarsClientOptions);
|
|
33
|
+
/** Every request path — JSON, uploads, SSE — sends these, so act-as scoping
|
|
34
|
+
* can never silently miss a surface. */
|
|
35
|
+
private authHeaders;
|
|
20
36
|
private request;
|
|
21
37
|
readonly agents: {
|
|
22
38
|
create: (input: CreateAgentInput) => Promise<Agent>;
|
|
@@ -47,6 +63,8 @@ export declare class TarsClient {
|
|
|
47
63
|
/** Appended to the agent's system prompt for this session only. */
|
|
48
64
|
systemSuffix?: string;
|
|
49
65
|
tools?: ClientTool[];
|
|
66
|
+
/** Per-session thinking-depth override (mirrors `model`). */
|
|
67
|
+
reasoning?: ReasoningConfig;
|
|
50
68
|
}) => Promise<TarsSession>;
|
|
51
69
|
list: (opts?: {
|
|
52
70
|
limit?: number;
|
|
@@ -202,6 +220,20 @@ export declare class TarsClient {
|
|
|
202
220
|
* the provider call.
|
|
203
221
|
*/
|
|
204
222
|
providers(): Promise<string[]>;
|
|
223
|
+
/**
|
|
224
|
+
* The models this instance can route AND price — ids are full
|
|
225
|
+
* `provider/model` specs. `openrouter/*` entries mirror OpenRouter's live
|
|
226
|
+
* catalog, so those ids are guaranteed to exist right now; direct entries
|
|
227
|
+
* come from the deployment's curated pricing table. Offer models from this
|
|
228
|
+
* list rather than hardcoding ids that can drift.
|
|
229
|
+
*
|
|
230
|
+
* The list is "what is known now", not "everything routable": `openrouter`
|
|
231
|
+
* entries are absent before the instance's first successful catalog
|
|
232
|
+
* refresh, and a deployment routing only `custom/*` has no priced entries
|
|
233
|
+
* at all. When it comes back empty, fall back to `providers()` plus your
|
|
234
|
+
* own lineup instead of rendering an empty picker.
|
|
235
|
+
*/
|
|
236
|
+
models(): Promise<ModelInfo[]>;
|
|
205
237
|
readonly usage: {
|
|
206
238
|
get: (filter?: {
|
|
207
239
|
from?: string | Date;
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export class TarsClient {
|
|
|
13
13
|
baseUrl;
|
|
14
14
|
apiKey;
|
|
15
15
|
fetchImpl;
|
|
16
|
+
actAsTenant;
|
|
16
17
|
constructor(options) {
|
|
17
18
|
if (!options.apiKey)
|
|
18
19
|
throw new Error('TarsClient: apiKey is required');
|
|
@@ -20,13 +21,22 @@ export class TarsClient {
|
|
|
20
21
|
this.baseUrl = (options.baseUrl ?? 'http://localhost:3001').replace(/\/$/, '');
|
|
21
22
|
// Bind: an unbound global fetch throws "Illegal invocation" in browsers.
|
|
22
23
|
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
24
|
+
this.actAsTenant = options.actAsTenant;
|
|
23
25
|
}
|
|
24
26
|
// ── low-level HTTP ───────────────────────────────────────────
|
|
27
|
+
/** Every request path — JSON, uploads, SSE — sends these, so act-as scoping
|
|
28
|
+
* can never silently miss a surface. */
|
|
29
|
+
authHeaders() {
|
|
30
|
+
return {
|
|
31
|
+
authorization: `Bearer ${this.apiKey}`,
|
|
32
|
+
...(this.actAsTenant ? { 'x-tars-tenant': this.actAsTenant } : {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
25
35
|
async request(method, path, body) {
|
|
26
36
|
const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
27
37
|
method,
|
|
28
38
|
headers: {
|
|
29
|
-
|
|
39
|
+
...this.authHeaders(),
|
|
30
40
|
...(body !== undefined ? { 'content-type': 'application/json' } : {}),
|
|
31
41
|
},
|
|
32
42
|
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
@@ -64,6 +74,7 @@ export class TarsClient {
|
|
|
64
74
|
...(input.metadata ? { metadata: input.metadata } : {}),
|
|
65
75
|
...(input.mcpServers?.length ? { mcp_servers: input.mcpServers } : {}),
|
|
66
76
|
...(input.systemSuffix ? { system_suffix: input.systemSuffix } : {}),
|
|
77
|
+
...(input.reasoning ? { reasoning: input.reasoning } : {}),
|
|
67
78
|
...(input.tools?.length
|
|
68
79
|
? {
|
|
69
80
|
custom_tools: input.tools.map((t) => ({
|
|
@@ -155,7 +166,7 @@ export class TarsClient {
|
|
|
155
166
|
pushVersion: async (id, zipBytes) => {
|
|
156
167
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/skills/${id}/versions`, {
|
|
157
168
|
method: 'POST',
|
|
158
|
-
headers: {
|
|
169
|
+
headers: { ...this.authHeaders(), 'content-type': 'application/zip' },
|
|
159
170
|
body: zipBytes,
|
|
160
171
|
});
|
|
161
172
|
if (!res.ok)
|
|
@@ -168,7 +179,7 @@ export class TarsClient {
|
|
|
168
179
|
*/
|
|
169
180
|
downloadVersion: async (id, version) => {
|
|
170
181
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/skills/${id}/versions/${version}/content`, {
|
|
171
|
-
headers:
|
|
182
|
+
headers: this.authHeaders(),
|
|
172
183
|
});
|
|
173
184
|
if (!res.ok)
|
|
174
185
|
throw new TarsApiError(res.status, await res.json().catch(() => undefined));
|
|
@@ -228,6 +239,23 @@ export class TarsClient {
|
|
|
228
239
|
const body = await this.request('GET', '/v1/providers');
|
|
229
240
|
return body.providers ?? [];
|
|
230
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* The models this instance can route AND price — ids are full
|
|
244
|
+
* `provider/model` specs. `openrouter/*` entries mirror OpenRouter's live
|
|
245
|
+
* catalog, so those ids are guaranteed to exist right now; direct entries
|
|
246
|
+
* come from the deployment's curated pricing table. Offer models from this
|
|
247
|
+
* list rather than hardcoding ids that can drift.
|
|
248
|
+
*
|
|
249
|
+
* The list is "what is known now", not "everything routable": `openrouter`
|
|
250
|
+
* entries are absent before the instance's first successful catalog
|
|
251
|
+
* refresh, and a deployment routing only `custom/*` has no priced entries
|
|
252
|
+
* at all. When it comes back empty, fall back to `providers()` plus your
|
|
253
|
+
* own lineup instead of rendering an empty picker.
|
|
254
|
+
*/
|
|
255
|
+
async models() {
|
|
256
|
+
const body = await this.request('GET', '/v1/models');
|
|
257
|
+
return body.models ?? [];
|
|
258
|
+
}
|
|
231
259
|
// ── usage ────────────────────────────────────────────────────
|
|
232
260
|
usage = {
|
|
233
261
|
// Aggregated token/cost usage for this tenant, with per-model, per-agent,
|
|
@@ -272,7 +300,7 @@ export class TarsClient {
|
|
|
272
300
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/files?name=${encodeURIComponent(input.name)}`, {
|
|
273
301
|
method: 'POST',
|
|
274
302
|
headers: {
|
|
275
|
-
|
|
303
|
+
...this.authHeaders(),
|
|
276
304
|
'content-type': input.mime ?? 'application/octet-stream',
|
|
277
305
|
},
|
|
278
306
|
body: bytes,
|
|
@@ -298,7 +326,7 @@ export class TarsClient {
|
|
|
298
326
|
get: (id) => this.request('GET', `/v1/files/${id}`),
|
|
299
327
|
download: async (id) => {
|
|
300
328
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/files/${id}/content`, {
|
|
301
|
-
headers:
|
|
329
|
+
headers: this.authHeaders(),
|
|
302
330
|
});
|
|
303
331
|
if (!res.ok || !res.body) {
|
|
304
332
|
throw new TarsApiError(res.status, await res.json().catch(() => undefined));
|
|
@@ -339,7 +367,7 @@ export class TarsClient {
|
|
|
339
367
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/sessions/${sessionId}/messages`, {
|
|
340
368
|
method: 'POST',
|
|
341
369
|
headers: {
|
|
342
|
-
|
|
370
|
+
...this.authHeaders(),
|
|
343
371
|
'content-type': 'application/json',
|
|
344
372
|
},
|
|
345
373
|
body: JSON.stringify({ text }),
|
|
@@ -356,7 +384,7 @@ export class TarsClient {
|
|
|
356
384
|
async streamEvents(sessionId, after, opts) {
|
|
357
385
|
const qs = `after=${after}` + (opts?.mode ? `&mode=${opts.mode}` : '');
|
|
358
386
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/sessions/${sessionId}/stream?${qs}`, {
|
|
359
|
-
headers:
|
|
387
|
+
headers: this.authHeaders(),
|
|
360
388
|
});
|
|
361
389
|
if (!res.ok || !res.body) {
|
|
362
390
|
const payload = await res.json().catch(() => undefined);
|
package/dist/types.d.ts
CHANGED
|
@@ -57,7 +57,23 @@ export type SessionEvent = {
|
|
|
57
57
|
} | {
|
|
58
58
|
type: 'connect_required';
|
|
59
59
|
server: string;
|
|
60
|
+
}
|
|
61
|
+
/** Every MCP dial's OUTCOME, successes included (one per server per turn):
|
|
62
|
+
* `connect_required`/`error` cover only the failure paths — this is the
|
|
63
|
+
* diagnostic twin that makes a healthy connector visible. */
|
|
64
|
+
| ({
|
|
65
|
+
type: 'mcp_connect';
|
|
66
|
+
server: string;
|
|
67
|
+
} & ({
|
|
68
|
+
status: 'connected';
|
|
69
|
+
tool_count: number;
|
|
70
|
+
} | {
|
|
71
|
+
status: 'failed';
|
|
72
|
+
code: AgentErrorCode;
|
|
73
|
+
message: string;
|
|
60
74
|
} | {
|
|
75
|
+
status: 'missing_credential';
|
|
76
|
+
})) | {
|
|
61
77
|
type: 'error';
|
|
62
78
|
code: AgentErrorCode;
|
|
63
79
|
message: string;
|
|
@@ -73,7 +89,17 @@ export type SessionEvent = {
|
|
|
73
89
|
cacheWriteTokens?: number;
|
|
74
90
|
};
|
|
75
91
|
});
|
|
76
|
-
export type BuiltInTool = 'bash' | 'read_file' | 'write_file';
|
|
92
|
+
export type BuiltInTool = 'bash' | 'read_file' | 'write_file' | 'edit_file' | 'glob' | 'grep' | 'web_fetch';
|
|
93
|
+
/**
|
|
94
|
+
* Extended-thinking depth. Provider-neutral: TARS maps it to Anthropic's
|
|
95
|
+
* `effort` (with adaptive thinking) or OpenRouter's `reasoning.effort`
|
|
96
|
+
* (`max` → `xhigh`). Omit for the provider default. The reasoning text itself
|
|
97
|
+
* is never streamed or journaled — only its depth is configurable.
|
|
98
|
+
*/
|
|
99
|
+
export type ReasoningEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
100
|
+
export interface ReasoningConfig {
|
|
101
|
+
effort: ReasoningEffort;
|
|
102
|
+
}
|
|
77
103
|
export interface McpServer {
|
|
78
104
|
name: string;
|
|
79
105
|
url: string;
|
|
@@ -112,6 +138,7 @@ export interface Agent {
|
|
|
112
138
|
mcp_servers: McpServer[] | null;
|
|
113
139
|
skills: SkillPin[] | null;
|
|
114
140
|
environment: AgentEnvironment | null;
|
|
141
|
+
reasoning: ReasoningConfig | null;
|
|
115
142
|
created_at: string;
|
|
116
143
|
updated_at: string;
|
|
117
144
|
}
|
|
@@ -129,6 +156,24 @@ export interface SkillVersion {
|
|
|
129
156
|
size_bytes: number;
|
|
130
157
|
created_at: string;
|
|
131
158
|
}
|
|
159
|
+
/** One routable-and-priced model from `GET /v1/models`. Prices are USD per
|
|
160
|
+
* million tokens; `id` is the full `provider/model` spec, usable as-is when
|
|
161
|
+
* creating agents/sessions. The list is "what is known now" — see
|
|
162
|
+
* `TarsClient.models()` for the empty/partial cases. */
|
|
163
|
+
export interface ModelInfo {
|
|
164
|
+
id: string;
|
|
165
|
+
name: string;
|
|
166
|
+
pricing: {
|
|
167
|
+
input: number;
|
|
168
|
+
output: number;
|
|
169
|
+
/** Absent ≠ free: TARS bills an unpublished cache-read price at the
|
|
170
|
+
* `input` rate (conservative upper bound). */
|
|
171
|
+
cache_read?: number;
|
|
172
|
+
/** Absent ≠ free: billed at the `input` rate when unpublished. Providers
|
|
173
|
+
* with genuinely free cache writes report an explicit 0. */
|
|
174
|
+
cache_write?: number;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
132
177
|
export interface ApiKeyInfo {
|
|
133
178
|
id: string;
|
|
134
179
|
key_prefix: string;
|
|
@@ -214,6 +259,7 @@ export interface AgentVersion {
|
|
|
214
259
|
export interface CreateAgentInput {
|
|
215
260
|
skills?: SkillPin[];
|
|
216
261
|
environment?: AgentEnvironment;
|
|
262
|
+
reasoning?: ReasoningConfig | null;
|
|
217
263
|
name: string;
|
|
218
264
|
system: string;
|
|
219
265
|
model?: string;
|
|
@@ -242,6 +288,25 @@ export interface SessionInfo {
|
|
|
242
288
|
input_schema: Record<string, unknown>;
|
|
243
289
|
timeout_sec?: number;
|
|
244
290
|
}> | null;
|
|
291
|
+
/**
|
|
292
|
+
* The EFFECTIVE system prompt the session's turns run with — agent base
|
|
293
|
+
* prompt + session system_suffix + skills appendix, fused at creation.
|
|
294
|
+
* Optional: absent from servers predating this field.
|
|
295
|
+
*/
|
|
296
|
+
system_prompt?: string;
|
|
297
|
+
/**
|
|
298
|
+
* The EFFECTIVE thinking depth the session's turns run with (the agent's,
|
|
299
|
+
* or the per-session override). null = provider default; absent from
|
|
300
|
+
* servers predating this field.
|
|
301
|
+
*/
|
|
302
|
+
reasoning?: ReasoningConfig | null;
|
|
303
|
+
/**
|
|
304
|
+
* The un-merged per-session suffix, when a non-empty one was passed at
|
|
305
|
+
* creation. Also null on sessions created before this release: the audit
|
|
306
|
+
* column went unwritten historically (the suffix is still fused into
|
|
307
|
+
* system_prompt there), and old rows cannot be backfilled.
|
|
308
|
+
*/
|
|
309
|
+
system_suffix?: string | null;
|
|
245
310
|
archived?: boolean;
|
|
246
311
|
last_seq?: number;
|
|
247
312
|
events?: SessionEvent[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wice24/tars-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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": {
|