@wice24/tars-sdk 0.1.8 → 0.2.3
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 +42 -7
- package/dist/types.d.ts +88 -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, 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, 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';
|
|
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;
|
|
@@ -106,6 +124,20 @@ export declare class TarsClient {
|
|
|
106
124
|
ok: boolean;
|
|
107
125
|
}>;
|
|
108
126
|
};
|
|
127
|
+
readonly mcp: {
|
|
128
|
+
/**
|
|
129
|
+
* Dial an MCP server once with the stored credential, list its tools, hang
|
|
130
|
+
* up — no session, nothing journaled. The source of truth for writing a
|
|
131
|
+
* `tools` / `blocked_tools` policy: what the server offers NOW, not what a
|
|
132
|
+
* registry says. Throws `TarsApiError` 404 `missing_credential` when
|
|
133
|
+
* `auth: 'required'` and no credential is stored for the end user or the
|
|
134
|
+
* tenant (none stored, or its refresh failed), 502 with the turn-time code
|
|
135
|
+
* (`mcp_authentication_failed_error` / `mcp_connection_failed_error`) when
|
|
136
|
+
* the dial fails or times out (15 s), and 503 `internal_error` when TARS's
|
|
137
|
+
* own credential store is unavailable.
|
|
138
|
+
*/
|
|
139
|
+
listTools: (input: ListMcpToolsInput) => Promise<McpServerTools>;
|
|
140
|
+
};
|
|
109
141
|
readonly skills: {
|
|
110
142
|
create: (input: {
|
|
111
143
|
slug: string;
|
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) => ({
|
|
@@ -144,6 +155,30 @@ export class TarsClient {
|
|
|
144
155
|
return this.request('DELETE', `/v1/mcp-credentials?${params}`);
|
|
145
156
|
},
|
|
146
157
|
};
|
|
158
|
+
// ── MCP servers ──────────────────────────────────────────────
|
|
159
|
+
mcp = {
|
|
160
|
+
/**
|
|
161
|
+
* Dial an MCP server once with the stored credential, list its tools, hang
|
|
162
|
+
* up — no session, nothing journaled. The source of truth for writing a
|
|
163
|
+
* `tools` / `blocked_tools` policy: what the server offers NOW, not what a
|
|
164
|
+
* registry says. Throws `TarsApiError` 404 `missing_credential` when
|
|
165
|
+
* `auth: 'required'` and no credential is stored for the end user or the
|
|
166
|
+
* tenant (none stored, or its refresh failed), 502 with the turn-time code
|
|
167
|
+
* (`mcp_authentication_failed_error` / `mcp_connection_failed_error`) when
|
|
168
|
+
* the dial fails or times out (15 s), and 503 `internal_error` when TARS's
|
|
169
|
+
* own credential store is unavailable.
|
|
170
|
+
*/
|
|
171
|
+
listTools: (input) => {
|
|
172
|
+
const params = new URLSearchParams({ name: input.name, url: input.url });
|
|
173
|
+
if (input.transport)
|
|
174
|
+
params.set('transport', input.transport);
|
|
175
|
+
if (input.auth)
|
|
176
|
+
params.set('auth', input.auth);
|
|
177
|
+
if (input.endUserId)
|
|
178
|
+
params.set('end_user_id', input.endUserId);
|
|
179
|
+
return this.request('GET', `/v1/mcp-servers/tools?${params}`);
|
|
180
|
+
},
|
|
181
|
+
};
|
|
147
182
|
// ── skills ───────────────────────────────────────────────────
|
|
148
183
|
// Versioned skill bundles (zip with SKILL.md at root), pinned per agent.
|
|
149
184
|
skills = {
|
|
@@ -155,7 +190,7 @@ export class TarsClient {
|
|
|
155
190
|
pushVersion: async (id, zipBytes) => {
|
|
156
191
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/skills/${id}/versions`, {
|
|
157
192
|
method: 'POST',
|
|
158
|
-
headers: {
|
|
193
|
+
headers: { ...this.authHeaders(), 'content-type': 'application/zip' },
|
|
159
194
|
body: zipBytes,
|
|
160
195
|
});
|
|
161
196
|
if (!res.ok)
|
|
@@ -168,7 +203,7 @@ export class TarsClient {
|
|
|
168
203
|
*/
|
|
169
204
|
downloadVersion: async (id, version) => {
|
|
170
205
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/skills/${id}/versions/${version}/content`, {
|
|
171
|
-
headers:
|
|
206
|
+
headers: this.authHeaders(),
|
|
172
207
|
});
|
|
173
208
|
if (!res.ok)
|
|
174
209
|
throw new TarsApiError(res.status, await res.json().catch(() => undefined));
|
|
@@ -289,7 +324,7 @@ export class TarsClient {
|
|
|
289
324
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/files?name=${encodeURIComponent(input.name)}`, {
|
|
290
325
|
method: 'POST',
|
|
291
326
|
headers: {
|
|
292
|
-
|
|
327
|
+
...this.authHeaders(),
|
|
293
328
|
'content-type': input.mime ?? 'application/octet-stream',
|
|
294
329
|
},
|
|
295
330
|
body: bytes,
|
|
@@ -315,7 +350,7 @@ export class TarsClient {
|
|
|
315
350
|
get: (id) => this.request('GET', `/v1/files/${id}`),
|
|
316
351
|
download: async (id) => {
|
|
317
352
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/files/${id}/content`, {
|
|
318
|
-
headers:
|
|
353
|
+
headers: this.authHeaders(),
|
|
319
354
|
});
|
|
320
355
|
if (!res.ok || !res.body) {
|
|
321
356
|
throw new TarsApiError(res.status, await res.json().catch(() => undefined));
|
|
@@ -356,7 +391,7 @@ export class TarsClient {
|
|
|
356
391
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/sessions/${sessionId}/messages`, {
|
|
357
392
|
method: 'POST',
|
|
358
393
|
headers: {
|
|
359
|
-
|
|
394
|
+
...this.authHeaders(),
|
|
360
395
|
'content-type': 'application/json',
|
|
361
396
|
},
|
|
362
397
|
body: JSON.stringify({ text }),
|
|
@@ -373,7 +408,7 @@ export class TarsClient {
|
|
|
373
408
|
async streamEvents(sessionId, after, opts) {
|
|
374
409
|
const qs = `after=${after}` + (opts?.mode ? `&mode=${opts.mode}` : '');
|
|
375
410
|
const res = await this.fetchImpl(`${this.baseUrl}/v1/sessions/${sessionId}/stream?${qs}`, {
|
|
376
|
-
headers:
|
|
411
|
+
headers: this.authHeaders(),
|
|
377
412
|
});
|
|
378
413
|
if (!res.ok || !res.body) {
|
|
379
414
|
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;
|
|
@@ -67,18 +83,46 @@ export type SessionEvent = {
|
|
|
67
83
|
type: 'turn_end';
|
|
68
84
|
reason: 'completed' | 'interrupted' | 'error';
|
|
69
85
|
usage?: {
|
|
86
|
+
/** UNCACHED input tokens only. Cache reads and writes are reported
|
|
87
|
+
* separately below, so the full prompt is the sum of all three. */
|
|
70
88
|
inputTokens?: number;
|
|
71
89
|
outputTokens?: number;
|
|
90
|
+
/** Input tokens served from the provider's prompt cache. */
|
|
72
91
|
cacheReadTokens?: number;
|
|
92
|
+
/** Input tokens written to the provider's prompt cache. */
|
|
73
93
|
cacheWriteTokens?: number;
|
|
74
94
|
};
|
|
75
95
|
});
|
|
76
|
-
export type BuiltInTool = 'bash' | 'read_file' | 'write_file';
|
|
96
|
+
export type BuiltInTool = 'bash' | 'read_file' | 'write_file' | 'edit_file' | 'glob' | 'grep' | 'web_fetch';
|
|
97
|
+
/**
|
|
98
|
+
* Extended-thinking depth. Provider-neutral: TARS maps it to Anthropic's
|
|
99
|
+
* `effort` (with adaptive thinking) or OpenRouter's `reasoning.effort`
|
|
100
|
+
* (`max` → `xhigh`). Omit for the provider default. The reasoning text itself
|
|
101
|
+
* is never streamed or journaled — only its depth is configurable.
|
|
102
|
+
*/
|
|
103
|
+
export type ReasoningEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
104
|
+
export interface ReasoningConfig {
|
|
105
|
+
effort: ReasoningEffort;
|
|
106
|
+
}
|
|
77
107
|
export interface McpServer {
|
|
78
108
|
name: string;
|
|
79
109
|
url: string;
|
|
80
110
|
transport: 'http' | 'sse';
|
|
81
111
|
auth: 'none' | 'required';
|
|
112
|
+
/**
|
|
113
|
+
* Expose only these of the server's tools to the model (its own names, as
|
|
114
|
+
* the server lists them — not the `server__tool` prefixed form). Omitted or
|
|
115
|
+
* null = every tool. Names the server doesn't offer are ignored. Non-empty,
|
|
116
|
+
* ≤256 entries, no duplicates. Mutually exclusive with `blocked_tools`.
|
|
117
|
+
*/
|
|
118
|
+
tools?: string[] | null;
|
|
119
|
+
/**
|
|
120
|
+
* Hide these of the server's tools from the model and expose every other
|
|
121
|
+
* one — the complement of `tools`, for a connector that is on by default
|
|
122
|
+
* and needs a few tools removed without naming the whole inventory. Same
|
|
123
|
+
* validation as `tools`; setting both is a `validation_error`.
|
|
124
|
+
*/
|
|
125
|
+
blocked_tools?: string[] | null;
|
|
82
126
|
}
|
|
83
127
|
export interface ClientTool<I = any> {
|
|
84
128
|
name: string;
|
|
@@ -112,6 +156,7 @@ export interface Agent {
|
|
|
112
156
|
mcp_servers: McpServer[] | null;
|
|
113
157
|
skills: SkillPin[] | null;
|
|
114
158
|
environment: AgentEnvironment | null;
|
|
159
|
+
reasoning: ReasoningConfig | null;
|
|
115
160
|
created_at: string;
|
|
116
161
|
updated_at: string;
|
|
117
162
|
}
|
|
@@ -219,6 +264,28 @@ export interface McpCredentialStatus {
|
|
|
219
264
|
expires_at: string | null;
|
|
220
265
|
updated_at: string;
|
|
221
266
|
}
|
|
267
|
+
/** How `mcp.listTools` names the server: the same fields a declaration
|
|
268
|
+
* carries (so the credential lookup and the dial match a turn's), plus whose
|
|
269
|
+
* credential to use. `transport` defaults to `'http'`, `auth` to `'none'`. */
|
|
270
|
+
export interface ListMcpToolsInput {
|
|
271
|
+
name: string;
|
|
272
|
+
url: string;
|
|
273
|
+
transport?: 'http' | 'sse';
|
|
274
|
+
auth?: 'none' | 'required';
|
|
275
|
+
/** Resolve this end user's credential first, then the tenant-level one;
|
|
276
|
+
* omit for tenant-level only. Only read when `auth` is `'required'`. */
|
|
277
|
+
endUserId?: string;
|
|
278
|
+
}
|
|
279
|
+
/** One tool as the server lists it. `description` is capped at 500
|
|
280
|
+
* characters (an ellipsis marks a cut); `null` when the server gave none. */
|
|
281
|
+
export interface McpToolInfo {
|
|
282
|
+
name: string;
|
|
283
|
+
description: string | null;
|
|
284
|
+
}
|
|
285
|
+
export interface McpServerTools {
|
|
286
|
+
server: string;
|
|
287
|
+
tools: McpToolInfo[];
|
|
288
|
+
}
|
|
222
289
|
export interface AgentVersion {
|
|
223
290
|
version: number;
|
|
224
291
|
name: string;
|
|
@@ -232,6 +299,7 @@ export interface AgentVersion {
|
|
|
232
299
|
export interface CreateAgentInput {
|
|
233
300
|
skills?: SkillPin[];
|
|
234
301
|
environment?: AgentEnvironment;
|
|
302
|
+
reasoning?: ReasoningConfig | null;
|
|
235
303
|
name: string;
|
|
236
304
|
system: string;
|
|
237
305
|
model?: string;
|
|
@@ -260,6 +328,25 @@ export interface SessionInfo {
|
|
|
260
328
|
input_schema: Record<string, unknown>;
|
|
261
329
|
timeout_sec?: number;
|
|
262
330
|
}> | null;
|
|
331
|
+
/**
|
|
332
|
+
* The EFFECTIVE system prompt the session's turns run with — agent base
|
|
333
|
+
* prompt + session system_suffix + skills appendix, fused at creation.
|
|
334
|
+
* Optional: absent from servers predating this field.
|
|
335
|
+
*/
|
|
336
|
+
system_prompt?: string;
|
|
337
|
+
/**
|
|
338
|
+
* The EFFECTIVE thinking depth the session's turns run with (the agent's,
|
|
339
|
+
* or the per-session override). null = provider default; absent from
|
|
340
|
+
* servers predating this field.
|
|
341
|
+
*/
|
|
342
|
+
reasoning?: ReasoningConfig | null;
|
|
343
|
+
/**
|
|
344
|
+
* The un-merged per-session suffix, when a non-empty one was passed at
|
|
345
|
+
* creation. Also null on sessions created before this release: the audit
|
|
346
|
+
* column went unwritten historically (the suffix is still fused into
|
|
347
|
+
* system_prompt there), and old rows cannot be backfilled.
|
|
348
|
+
*/
|
|
349
|
+
system_suffix?: string | null;
|
|
263
350
|
archived?: boolean;
|
|
264
351
|
last_seq?: number;
|
|
265
352
|
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.3",
|
|
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": {
|