@astralform/js 5.1.0 → 6.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 +8 -3
- package/dist/index.cjs +32 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -6
- package/dist/index.d.ts +21 -6
- package/dist/index.js +32 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -265,8 +265,13 @@ const id = await session.createNewConversation();
|
|
|
265
265
|
// Switch to an existing conversation (loads messages from backend)
|
|
266
266
|
await session.switchConversation("conversation-id");
|
|
267
267
|
|
|
268
|
-
// Delete a conversation
|
|
269
|
-
|
|
268
|
+
// Delete a conversation. Rejects if the server refused it — a 404 counts as
|
|
269
|
+
// already deleted and resolves, anything else leaves the conversation in place.
|
|
270
|
+
try {
|
|
271
|
+
await session.deleteConversation("conversation-id");
|
|
272
|
+
} catch (err) {
|
|
273
|
+
// Still there: tell the user rather than removing it from your own UI.
|
|
274
|
+
}
|
|
270
275
|
|
|
271
276
|
// Edit and resend from a checkpoint
|
|
272
277
|
await session.resendFromCheckpoint("message-id", "Updated message");
|
|
@@ -357,7 +362,7 @@ import {
|
|
|
357
362
|
AuthenticationError, // 401 — invalid API key
|
|
358
363
|
RateLimitError, // 429 — rate limit exceeded
|
|
359
364
|
LLMNotConfiguredError, // LLM provider not set up
|
|
360
|
-
ServerError, // 5xx or unexpected errors
|
|
365
|
+
ServerError, // 5xx or unexpected errors — carries `status` when it came from a response
|
|
361
366
|
ConnectionError, // Network failures
|
|
362
367
|
StreamAbortedError, // Stream cancelled via disconnect()
|
|
363
368
|
} from "@astralform/js";
|
package/dist/index.cjs
CHANGED
|
@@ -73,9 +73,10 @@ var LLMNotConfiguredError = class extends AstralformError {
|
|
|
73
73
|
}
|
|
74
74
|
};
|
|
75
75
|
var ServerError = class extends AstralformError {
|
|
76
|
-
constructor(message = "Internal server error") {
|
|
76
|
+
constructor(message = "Internal server error", status) {
|
|
77
77
|
super(message, "server_error");
|
|
78
78
|
this.name = "ServerError";
|
|
79
|
+
if (status !== void 0) Object.assign(this, { status });
|
|
79
80
|
}
|
|
80
81
|
};
|
|
81
82
|
var ConnectionError = class extends AstralformError {
|
|
@@ -105,6 +106,16 @@ function generateId() {
|
|
|
105
106
|
return v.toString(16);
|
|
106
107
|
});
|
|
107
108
|
}
|
|
109
|
+
function snakeToCamel(str) {
|
|
110
|
+
return str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
111
|
+
}
|
|
112
|
+
function camelizeKeys(obj) {
|
|
113
|
+
const result = {};
|
|
114
|
+
for (const key of Object.keys(obj)) {
|
|
115
|
+
result[snakeToCamel(key)] = obj[key];
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
108
119
|
|
|
109
120
|
// src/rate-limit.ts
|
|
110
121
|
var DEFAULT_MESSAGE = "Rate limit exceeded";
|
|
@@ -255,7 +266,7 @@ async function* streamJobSSE(options) {
|
|
|
255
266
|
case 429:
|
|
256
267
|
throw createRateLimitErrorFromHttp(response, rawText);
|
|
257
268
|
default:
|
|
258
|
-
throw new ServerError(text || `HTTP ${response.status}
|
|
269
|
+
throw new ServerError(text || `HTTP ${response.status}`, response.status);
|
|
259
270
|
}
|
|
260
271
|
}
|
|
261
272
|
if (!response.body) {
|
|
@@ -526,7 +537,10 @@ var AstralformClient = class {
|
|
|
526
537
|
throw createRateLimitErrorFromHttp(response, text);
|
|
527
538
|
default: {
|
|
528
539
|
const safeText = text ? sanitizeErrorText(text) : "";
|
|
529
|
-
throw new ServerError(
|
|
540
|
+
throw new ServerError(
|
|
541
|
+
safeText || `HTTP ${response.status}`,
|
|
542
|
+
response.status
|
|
543
|
+
);
|
|
530
544
|
}
|
|
531
545
|
}
|
|
532
546
|
}
|
|
@@ -563,13 +577,7 @@ var AstralformClient = class {
|
|
|
563
577
|
const safeLimit = Math.max(1, Math.min(200, Math.floor(Number(limit))));
|
|
564
578
|
const safeOffset = Math.max(0, Math.floor(Number(offset)));
|
|
565
579
|
const raw = await this.get(`/v1/conversations?limit=${safeLimit}&offset=${safeOffset}`);
|
|
566
|
-
return raw.map((c) => (
|
|
567
|
-
id: c.id,
|
|
568
|
-
title: c.title,
|
|
569
|
-
messageCount: c.message_count,
|
|
570
|
-
createdAt: c.created_at,
|
|
571
|
-
updatedAt: c.updated_at
|
|
572
|
-
}));
|
|
580
|
+
return raw.map((c) => camelizeKeys(c));
|
|
573
581
|
}
|
|
574
582
|
async getMessages(conversationId) {
|
|
575
583
|
const raw = await this.get(`/v1/conversations/${encodeURIComponent(conversationId)}/messages`);
|
|
@@ -594,13 +602,7 @@ var AstralformClient = class {
|
|
|
594
602
|
*/
|
|
595
603
|
async renameConversation(id, title) {
|
|
596
604
|
const c = await this.patch(`/v1/conversations/${encodeURIComponent(id)}`, { title });
|
|
597
|
-
return
|
|
598
|
-
id: c.id,
|
|
599
|
-
title: c.title,
|
|
600
|
-
messageCount: c.message_count,
|
|
601
|
-
createdAt: c.created_at,
|
|
602
|
-
updatedAt: c.updated_at
|
|
603
|
-
};
|
|
605
|
+
return camelizeKeys(c);
|
|
604
606
|
}
|
|
605
607
|
async deleteConversation(id) {
|
|
606
608
|
await this.del(`/v1/conversations/${encodeURIComponent(id)}`);
|
|
@@ -613,14 +615,7 @@ var AstralformClient = class {
|
|
|
613
615
|
*/
|
|
614
616
|
async getAgents() {
|
|
615
617
|
const raw = await this.get("/v1/agents");
|
|
616
|
-
return raw.map((a) => (
|
|
617
|
-
name: a.name,
|
|
618
|
-
displayName: a.display_name,
|
|
619
|
-
description: a.description,
|
|
620
|
-
isOrchestrator: a.is_orchestrator,
|
|
621
|
-
isEnabled: a.is_enabled,
|
|
622
|
-
avatarUrl: a.avatar_url
|
|
623
|
-
}));
|
|
618
|
+
return raw.map((a) => camelizeKeys(a));
|
|
624
619
|
}
|
|
625
620
|
/**
|
|
626
621
|
* List the models the caller may pick this turn — expanded from the curated
|
|
@@ -647,12 +642,7 @@ var AstralformClient = class {
|
|
|
647
642
|
}
|
|
648
643
|
async getSkills() {
|
|
649
644
|
const raw = await this.get("/v1/skills");
|
|
650
|
-
return raw.map((s) => (
|
|
651
|
-
name: s.name,
|
|
652
|
-
displayName: s.display_name,
|
|
653
|
-
description: s.description,
|
|
654
|
-
isEnabled: s.is_enabled
|
|
655
|
-
}));
|
|
645
|
+
return raw.map((s) => camelizeKeys(s));
|
|
656
646
|
}
|
|
657
647
|
async getConversationEvents(conversationId, jobId) {
|
|
658
648
|
let url = `/v1/conversations/${encodeURIComponent(conversationId)}/events`;
|
|
@@ -769,13 +759,7 @@ var AstralformClient = class {
|
|
|
769
759
|
// sending them in API-key mode yields 401.
|
|
770
760
|
async listTeams() {
|
|
771
761
|
const raw = await this.get("/v1/teams");
|
|
772
|
-
return raw.map((t) => (
|
|
773
|
-
id: t.id,
|
|
774
|
-
name: t.name,
|
|
775
|
-
slug: t.slug,
|
|
776
|
-
isDefault: t.is_default,
|
|
777
|
-
role: t.role
|
|
778
|
-
}));
|
|
762
|
+
return raw.map((t) => camelizeKeys(t));
|
|
779
763
|
}
|
|
780
764
|
/**
|
|
781
765
|
* List the team-level agents (formerly "projects") the signed-in user can
|
|
@@ -784,14 +768,7 @@ var AstralformClient = class {
|
|
|
784
768
|
*/
|
|
785
769
|
async listAgents(teamId) {
|
|
786
770
|
const raw = await this.get(`/v1/teams/${encodeURIComponent(teamId)}/agents`);
|
|
787
|
-
return raw.map((a) => (
|
|
788
|
-
id: a.id,
|
|
789
|
-
name: a.name,
|
|
790
|
-
teamId: a.team_id,
|
|
791
|
-
createdAt: a.created_at,
|
|
792
|
-
updatedAt: a.updated_at,
|
|
793
|
-
avatarUrl: a.avatar_url ?? null
|
|
794
|
-
}));
|
|
771
|
+
return raw.map((a) => camelizeKeys(a));
|
|
795
772
|
}
|
|
796
773
|
// --- Jobs API ---
|
|
797
774
|
async createJob(request) {
|
|
@@ -828,13 +805,7 @@ var AstralformClient = class {
|
|
|
828
805
|
};
|
|
829
806
|
if (request.comment != null) body.comment = request.comment;
|
|
830
807
|
const raw = await this.post(`/v1/jobs/${encodeURIComponent(jobId)}/feedback`, body);
|
|
831
|
-
return
|
|
832
|
-
id: raw.id,
|
|
833
|
-
jobId: raw.job_id,
|
|
834
|
-
rating: raw.rating,
|
|
835
|
-
comment: raw.comment,
|
|
836
|
-
createdAt: raw.created_at
|
|
837
|
-
};
|
|
808
|
+
return camelizeKeys(raw);
|
|
838
809
|
}
|
|
839
810
|
async getActiveJob(conversationId) {
|
|
840
811
|
const raw = await this.get(`/v1/conversations/${encodeURIComponent(conversationId)}/active-job`);
|
|
@@ -2222,11 +2193,12 @@ var ChatSession = class {
|
|
|
2222
2193
|
/**
|
|
2223
2194
|
* Rename a conversation, server first.
|
|
2224
2195
|
*
|
|
2225
|
-
*
|
|
2226
|
-
*
|
|
2227
|
-
*
|
|
2228
|
-
*
|
|
2229
|
-
*
|
|
2196
|
+
* Server first, like the delete below: a failed rename written locally would
|
|
2197
|
+
* leave the sidebar showing a title the server never accepted, and nothing
|
|
2198
|
+
* refetches a conversation that is already in the loaded list. (The delete
|
|
2199
|
+
* used to be the counter-example here — it dropped the row whatever the
|
|
2200
|
+
* server said, on the theory that a failed one was self-correcting. It was
|
|
2201
|
+
* not: the row stayed deleted locally and alive on the server.)
|
|
2230
2202
|
*
|
|
2231
2203
|
* Mirrors the `title_generated` path: the entry in `conversations` is
|
|
2232
2204
|
* mutated in place, which is what every consumer of the list reads.
|
|
@@ -2242,7 +2214,8 @@ var ChatSession = class {
|
|
|
2242
2214
|
async deleteConversation(id) {
|
|
2243
2215
|
try {
|
|
2244
2216
|
await this.client.deleteConversation(id);
|
|
2245
|
-
} catch {
|
|
2217
|
+
} catch (err) {
|
|
2218
|
+
if (!(err instanceof ServerError) || err.status !== 404) throw err;
|
|
2246
2219
|
}
|
|
2247
2220
|
await this.storage.deleteConversation(id);
|
|
2248
2221
|
if (this.serverConversationIds.delete(id)) {
|