@astralform/js 1.2.0 → 3.0.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/README.md +6 -6
- package/dist/index.cjs +44 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -22
- package/dist/index.d.ts +38 -22
- package/dist/index.js +44 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ session.disconnect();
|
|
|
57
57
|
import { ChatSession } from "@astralform/js";
|
|
58
58
|
|
|
59
59
|
const session = new ChatSession({
|
|
60
|
-
apiKey: "your-api-key", // Required — Astralform
|
|
60
|
+
apiKey: "your-api-key", // Required — Astralform agent API key
|
|
61
61
|
userId: "user-123", // Required — identifies the end user
|
|
62
62
|
baseURL: "http://localhost:8000", // Optional — defaults to https://api.astralform.ai
|
|
63
63
|
fetch: customFetch, // Optional — custom fetch implementation
|
|
@@ -72,7 +72,7 @@ Subscribe to events with `.on()`, which returns an unsubscribe function. The SDK
|
|
|
72
72
|
const unsubscribe = session.on((event) => {
|
|
73
73
|
switch (event.type) {
|
|
74
74
|
case "connected":
|
|
75
|
-
// Session connected,
|
|
75
|
+
// Session connected, agent status and tools loaded
|
|
76
76
|
break;
|
|
77
77
|
|
|
78
78
|
// --- Turn lifecycle ---
|
|
@@ -212,10 +212,10 @@ import { ChatSession, parseEmbeddedResource } from "@astralform/js";
|
|
|
212
212
|
|
|
213
213
|
await session.connect();
|
|
214
214
|
|
|
215
|
-
// Gate registration on the
|
|
216
|
-
if (session.
|
|
215
|
+
// Gate registration on the agent's configured protocol.
|
|
216
|
+
if (session.agentStatus?.uiComponents.enabled) {
|
|
217
217
|
session.protocols.register({
|
|
218
|
-
mimeType: session.
|
|
218
|
+
mimeType: session.agentStatus.uiComponents.mimeType!,
|
|
219
219
|
render: (payload) => {
|
|
220
220
|
/* framework-specific render */
|
|
221
221
|
},
|
|
@@ -305,7 +305,7 @@ const client = new AstralformClient({
|
|
|
305
305
|
});
|
|
306
306
|
|
|
307
307
|
// REST endpoints
|
|
308
|
-
const status = await client.
|
|
308
|
+
const status = await client.getAgentStatus();
|
|
309
309
|
const conversations = await client.getConversations();
|
|
310
310
|
const messages = await client.getMessages("conversation-id");
|
|
311
311
|
const agents = await client.getAgents();
|
package/dist/index.cjs
CHANGED
|
@@ -66,7 +66,7 @@ var RateLimitError = class extends AstralformError {
|
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
68
|
var LLMNotConfiguredError = class extends AstralformError {
|
|
69
|
-
constructor(message = "LLM provider not configured for this
|
|
69
|
+
constructor(message = "LLM provider not configured for this agent") {
|
|
70
70
|
super(message, "llm_not_configured");
|
|
71
71
|
this.name = "LLMNotConfiguredError";
|
|
72
72
|
}
|
|
@@ -338,11 +338,11 @@ var AstralformClient = class {
|
|
|
338
338
|
"accessToken is required and must be a non-empty string in user-token mode"
|
|
339
339
|
);
|
|
340
340
|
}
|
|
341
|
-
const
|
|
341
|
+
const agentId = typeof config.agentId === "string" && config.agentId.length > 0 ? config.agentId : null;
|
|
342
342
|
this.auth = {
|
|
343
343
|
kind: "user_token",
|
|
344
344
|
accessToken: config.accessToken,
|
|
345
|
-
|
|
345
|
+
agentId,
|
|
346
346
|
endUserId: typeof config.endUserId === "string" && config.endUserId.length > 0 ? config.endUserId : null
|
|
347
347
|
};
|
|
348
348
|
}
|
|
@@ -364,17 +364,17 @@ var AstralformClient = class {
|
|
|
364
364
|
this.auth = { ...this.auth, accessToken };
|
|
365
365
|
}
|
|
366
366
|
/**
|
|
367
|
-
* Swap the active
|
|
368
|
-
* current developer has access to the new
|
|
367
|
+
* Swap the active agent for a user-token client. The backend verifies the
|
|
368
|
+
* current developer has access to the new agent; a 403 comes back if not.
|
|
369
369
|
*/
|
|
370
|
-
|
|
370
|
+
updateAgentId(agentId) {
|
|
371
371
|
if (this.auth.kind !== "user_token") {
|
|
372
|
-
throw new Error("
|
|
372
|
+
throw new Error("updateAgentId is only valid in user-token mode");
|
|
373
373
|
}
|
|
374
|
-
if (!
|
|
375
|
-
throw new Error("
|
|
374
|
+
if (!agentId || typeof agentId !== "string") {
|
|
375
|
+
throw new Error("agentId must be a non-empty string");
|
|
376
376
|
}
|
|
377
|
-
this.auth = { ...this.auth,
|
|
377
|
+
this.auth = { ...this.auth, agentId };
|
|
378
378
|
}
|
|
379
379
|
/**
|
|
380
380
|
* Set (or clear) the end-user override for user-token mode.
|
|
@@ -396,13 +396,13 @@ var AstralformClient = class {
|
|
|
396
396
|
return this.auth.kind === "user_token" ? this.auth.endUserId : null;
|
|
397
397
|
}
|
|
398
398
|
/**
|
|
399
|
-
* Active
|
|
400
|
-
* was constructed without one). For API-key mode the
|
|
399
|
+
* Active agent for user-token mode, or `null` if pre-pick (client
|
|
400
|
+
* was constructed without one). For API-key mode the agent is baked
|
|
401
401
|
* into the key, so this getter returns `null` there too — use
|
|
402
402
|
* `authMode` to disambiguate.
|
|
403
403
|
*/
|
|
404
|
-
get
|
|
405
|
-
return this.auth.kind === "user_token" ? this.auth.
|
|
404
|
+
get agentId() {
|
|
405
|
+
return this.auth.kind === "user_token" ? this.auth.agentId : null;
|
|
406
406
|
}
|
|
407
407
|
/** Which auth mode this client was constructed with. */
|
|
408
408
|
get authMode() {
|
|
@@ -424,8 +424,8 @@ var AstralformClient = class {
|
|
|
424
424
|
const headers = {
|
|
425
425
|
Authorization: `Bearer ${this.auth.accessToken}`
|
|
426
426
|
};
|
|
427
|
-
if (this.auth.
|
|
428
|
-
headers["X-
|
|
427
|
+
if (this.auth.agentId) {
|
|
428
|
+
headers["X-Agent-ID"] = this.auth.agentId;
|
|
429
429
|
}
|
|
430
430
|
if (this.auth.endUserId) {
|
|
431
431
|
headers["X-End-User-ID"] = this.auth.endUserId;
|
|
@@ -480,8 +480,9 @@ var AstralformClient = class {
|
|
|
480
480
|
async getHealth() {
|
|
481
481
|
return this.get("/v1/health");
|
|
482
482
|
}
|
|
483
|
-
|
|
484
|
-
|
|
483
|
+
// Agent readiness check, scoped to the client's active agent via X-Agent-ID.
|
|
484
|
+
async getAgentStatus() {
|
|
485
|
+
const raw = await this.get("/v1/agent/status");
|
|
485
486
|
const ui = raw.ui_components ?? {};
|
|
486
487
|
return {
|
|
487
488
|
isReady: raw.is_ready,
|
|
@@ -523,6 +524,12 @@ var AstralformClient = class {
|
|
|
523
524
|
async deleteConversation(id) {
|
|
524
525
|
await this.del(`/v1/conversations/${encodeURIComponent(id)}`);
|
|
525
526
|
}
|
|
527
|
+
/**
|
|
528
|
+
* List the AI personas (sub-agents) available INSIDE the client's active
|
|
529
|
+
* agent workspace — orchestrator + specialists, addressed per message via
|
|
530
|
+
* `ChatStreamRequest.agent_name`. Not to be confused with `listAgents()`,
|
|
531
|
+
* which enumerates the team-level agents a signed-in user can open.
|
|
532
|
+
*/
|
|
526
533
|
async getAgents() {
|
|
527
534
|
const raw = await this.get("/v1/agents");
|
|
528
535
|
return raw.map((a) => ({
|
|
@@ -644,8 +651,8 @@ var AstralformClient = class {
|
|
|
644
651
|
}
|
|
645
652
|
// --- Account-scoped discovery (user-token mode) ---
|
|
646
653
|
//
|
|
647
|
-
// Lets a signed-in user pick which team/
|
|
648
|
-
// Backend gates these on OIDC user context (no X-
|
|
654
|
+
// Lets a signed-in user pick which team/agent they want to act on.
|
|
655
|
+
// Backend gates these on OIDC user context (no X-Agent-ID required) —
|
|
649
656
|
// sending them in API-key mode yields 401.
|
|
650
657
|
async listTeams() {
|
|
651
658
|
const raw = await this.get("/v1/teams");
|
|
@@ -657,14 +664,19 @@ var AstralformClient = class {
|
|
|
657
664
|
role: t.role
|
|
658
665
|
}));
|
|
659
666
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
667
|
+
/**
|
|
668
|
+
* List the team-level agents (formerly "projects") the signed-in user can
|
|
669
|
+
* open — the pickable workspaces under a team. Not to be confused with
|
|
670
|
+
* `getAgents()`, which lists the AI personas inside the active agent.
|
|
671
|
+
*/
|
|
672
|
+
async listAgents(teamId) {
|
|
673
|
+
const raw = await this.get(`/v1/teams/${encodeURIComponent(teamId)}/agents`);
|
|
674
|
+
return raw.map((a) => ({
|
|
675
|
+
id: a.id,
|
|
676
|
+
name: a.name,
|
|
677
|
+
teamId: a.team_id,
|
|
678
|
+
createdAt: a.created_at,
|
|
679
|
+
updatedAt: a.updated_at
|
|
668
680
|
}));
|
|
669
681
|
}
|
|
670
682
|
// --- Jobs API ---
|
|
@@ -1207,7 +1219,7 @@ var ChatSession = class {
|
|
|
1207
1219
|
/**
|
|
1208
1220
|
* Pluggable UI protocol adapters. Consumers register a framework-
|
|
1209
1221
|
* specific adapter (e.g. React) for each MIME type they can render,
|
|
1210
|
-
* typically gated on ``session.
|
|
1222
|
+
* typically gated on ``session.agentStatus.uiComponents.protocol``.
|
|
1211
1223
|
* ``ToolBlock``-style consumers look up the adapter for an incoming
|
|
1212
1224
|
* embedded resource and hand off rendering.
|
|
1213
1225
|
*/
|
|
@@ -1217,7 +1229,7 @@ var ChatSession = class {
|
|
|
1217
1229
|
this.conversations = [];
|
|
1218
1230
|
this.messages = [];
|
|
1219
1231
|
this.isStreaming = false;
|
|
1220
|
-
this.
|
|
1232
|
+
this.agentStatus = null;
|
|
1221
1233
|
this.agents = [];
|
|
1222
1234
|
this.skills = [];
|
|
1223
1235
|
this.enabledClientTools = /* @__PURE__ */ new Set();
|
|
@@ -1260,13 +1272,13 @@ var ChatSession = class {
|
|
|
1260
1272
|
}
|
|
1261
1273
|
async connect() {
|
|
1262
1274
|
const [status, conversations, agents, skills] = await Promise.allSettled([
|
|
1263
|
-
this.client.
|
|
1275
|
+
this.client.getAgentStatus(),
|
|
1264
1276
|
this.client.getConversations(),
|
|
1265
1277
|
this.client.getAgents().catch(() => []),
|
|
1266
1278
|
this.client.getSkills().catch(() => [])
|
|
1267
1279
|
]);
|
|
1268
1280
|
if (status.status === "fulfilled") {
|
|
1269
|
-
this.
|
|
1281
|
+
this.agentStatus = status.value;
|
|
1270
1282
|
}
|
|
1271
1283
|
if (conversations.status === "fulfilled") {
|
|
1272
1284
|
this.conversations = conversations.value;
|