@astralform/js 9.2.0 → 9.3.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.cjs +61 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -1
- package/dist/index.d.ts +83 -1
- package/dist/index.js +60 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
VOICE_POLISH_MODES: () => VOICE_POLISH_MODES,
|
|
39
39
|
generateId: () => generateId,
|
|
40
40
|
isEmbeddedResource: () => isEmbeddedResource,
|
|
41
|
+
isToolImageStub: () => isToolImageStub,
|
|
41
42
|
isToolOutputStub: () => isToolOutputStub,
|
|
42
43
|
isVoiceLLMMode: () => isVoiceLLMMode,
|
|
43
44
|
isVoicePolishMode: () => isVoicePolishMode,
|
|
@@ -371,6 +372,11 @@ function isToolOutputStub(value) {
|
|
|
371
372
|
const v = value;
|
|
372
373
|
return v.__stub === "tool_output" && typeof v.call_id === "string" && v.call_id.length > 0;
|
|
373
374
|
}
|
|
375
|
+
function isToolImageStub(value) {
|
|
376
|
+
if (typeof value !== "object" || value === null) return false;
|
|
377
|
+
const v = value;
|
|
378
|
+
return v.__stub === "tool_image" && typeof v.call_id === "string" && v.call_id.length > 0 && typeof v.index === "number" && Number.isInteger(v.index) && v.index >= 0;
|
|
379
|
+
}
|
|
374
380
|
|
|
375
381
|
// src/client.ts
|
|
376
382
|
var DEFAULT_BASE_URL = "https://api.astralform.ai";
|
|
@@ -694,6 +700,13 @@ var AstralformClient = class {
|
|
|
694
700
|
return await response.json();
|
|
695
701
|
});
|
|
696
702
|
}
|
|
703
|
+
/** A GET whose body is binary. Read inside the race, for the reason above. */
|
|
704
|
+
async getBlob(path) {
|
|
705
|
+
return this.withDeadline(async (signal) => {
|
|
706
|
+
const response = await this.send("GET", path, void 0, signal);
|
|
707
|
+
return response.blob();
|
|
708
|
+
});
|
|
709
|
+
}
|
|
697
710
|
async post(path, body) {
|
|
698
711
|
return this.withDeadline(async (signal) => {
|
|
699
712
|
const response = await this.send("POST", path, body, signal);
|
|
@@ -913,6 +926,7 @@ var AstralformClient = class {
|
|
|
913
926
|
const params = new URLSearchParams();
|
|
914
927
|
if (jobId) params.set("job_id", jobId);
|
|
915
928
|
if (options?.toolOutputs === "stub") params.set("tool_outputs", "stub");
|
|
929
|
+
if (options?.toolImages === "stub") params.set("tool_images", "stub");
|
|
916
930
|
const query = params.toString();
|
|
917
931
|
return this.get(
|
|
918
932
|
`/v1/conversations/${encodeURIComponent(conversationId)}/events${query ? `?${query}` : ""}`
|
|
@@ -927,6 +941,25 @@ var AstralformClient = class {
|
|
|
927
941
|
);
|
|
928
942
|
return res.output;
|
|
929
943
|
}
|
|
944
|
+
/**
|
|
945
|
+
* The image behind a {@link ToolImageStub}, as a `Blob` of the preview's bytes.
|
|
946
|
+
*
|
|
947
|
+
* Takes the stub itself and nothing else — the `job_id` scoping that
|
|
948
|
+
* `getToolOutput`'s id form warns about cannot be dropped from a value that
|
|
949
|
+
* carries it. There is deliberately no by-ids form.
|
|
950
|
+
*
|
|
951
|
+
* A `Blob` rather than a URL because the route is authenticated: an `<img
|
|
952
|
+
* src>` cannot send the bearer token, so a browser consumer turns this into
|
|
953
|
+
* an object URL (`URL.createObjectURL`) and revokes it when the image
|
|
954
|
+
* unmounts. The response is `private, immutable`, so a repeat fetch of the
|
|
955
|
+
* same preview is served by the HTTP cache.
|
|
956
|
+
*/
|
|
957
|
+
async getToolImage(conversationId, stub) {
|
|
958
|
+
const query = stub.job_id ? `?job_id=${encodeURIComponent(stub.job_id)}` : "";
|
|
959
|
+
return this.getBlob(
|
|
960
|
+
`/v1/conversations/${encodeURIComponent(conversationId)}/tool-output/${encodeURIComponent(stub.call_id)}/images/${stub.index}${query}`
|
|
961
|
+
);
|
|
962
|
+
}
|
|
930
963
|
async submitToolResult(request) {
|
|
931
964
|
await this.post("/v1/tool-result", request);
|
|
932
965
|
}
|
|
@@ -2801,6 +2834,12 @@ var StreamManager = class _StreamManager {
|
|
|
2801
2834
|
* Defaults to inline, so this is inert until a consumer opts in.
|
|
2802
2835
|
*/
|
|
2803
2836
|
this.toolOutputs = "inline";
|
|
2837
|
+
/**
|
|
2838
|
+
* Whether restore asks for tool image previews inline or as fetch handles.
|
|
2839
|
+
* Separate from `toolOutputs` because the server keeps them separate — see
|
|
2840
|
+
* `ToolImageStub` — and on the same one-setting-both-waves rule.
|
|
2841
|
+
*/
|
|
2842
|
+
this.toolImages = "inline";
|
|
2804
2843
|
this._state = "idle";
|
|
2805
2844
|
this._activeConversationId = null;
|
|
2806
2845
|
this._backgroundJobs = /* @__PURE__ */ new Map();
|
|
@@ -2857,6 +2896,25 @@ var StreamManager = class _StreamManager {
|
|
|
2857
2896
|
setToolOutputMode(mode) {
|
|
2858
2897
|
this.toolOutputs = mode;
|
|
2859
2898
|
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Ask restore for stubbed image previews, fetched on demand.
|
|
2901
|
+
*
|
|
2902
|
+
* The same caution as `setToolOutputMode`, sharper: a consumer that cannot
|
|
2903
|
+
* resolve one (`isToolImageStub`, `client.getToolImage`) finds an `images`
|
|
2904
|
+
* entry with no `url` and draws a broken image where the preview was.
|
|
2905
|
+
*/
|
|
2906
|
+
setToolImageMode(mode) {
|
|
2907
|
+
this.toolImages = mode;
|
|
2908
|
+
}
|
|
2909
|
+
/**
|
|
2910
|
+
* The ONE options object both event waves fetch with — the newest page and
|
|
2911
|
+
* every `loadEarlierTurns` page. Built in one place so an opt-in added here
|
|
2912
|
+
* reaches both by construction: two literals at two call sites is how one
|
|
2913
|
+
* wave would silently keep asking for inline payloads.
|
|
2914
|
+
*/
|
|
2915
|
+
get eventFetchOptions() {
|
|
2916
|
+
return { toolOutputs: this.toolOutputs, toolImages: this.toolImages };
|
|
2917
|
+
}
|
|
2860
2918
|
emit(event) {
|
|
2861
2919
|
for (const handler of this.handlers) {
|
|
2862
2920
|
try {
|
|
@@ -3357,9 +3415,7 @@ var StreamManager = class _StreamManager {
|
|
|
3357
3415
|
const boundary = this.oldestDrawnMessageId;
|
|
3358
3416
|
const eventLists = await Promise.all(
|
|
3359
3417
|
page.jobs.map(
|
|
3360
|
-
(job) => session.client.getConversationEvents(conversationId, job.job_id,
|
|
3361
|
-
toolOutputs: this.toolOutputs
|
|
3362
|
-
}).catch(() => [])
|
|
3418
|
+
(job) => session.client.getConversationEvents(conversationId, job.job_id, this.eventFetchOptions).catch(() => [])
|
|
3363
3419
|
)
|
|
3364
3420
|
);
|
|
3365
3421
|
if (stop()) return 0;
|
|
@@ -3480,9 +3536,7 @@ var StreamManager = class _StreamManager {
|
|
|
3480
3536
|
});
|
|
3481
3537
|
const eventLists = await Promise.all(
|
|
3482
3538
|
replayableJobs.map(
|
|
3483
|
-
(job) => this.session.client.getConversationEvents(conversationId, job.job_id,
|
|
3484
|
-
toolOutputs: this.toolOutputs
|
|
3485
|
-
}).catch(() => [])
|
|
3539
|
+
(job) => this.session.client.getConversationEvents(conversationId, job.job_id, this.eventFetchOptions).catch(() => [])
|
|
3486
3540
|
)
|
|
3487
3541
|
);
|
|
3488
3542
|
if (stopReplay()) return false;
|
|
@@ -3631,6 +3685,7 @@ function parseEmbeddedResource(value) {
|
|
|
3631
3685
|
VOICE_POLISH_MODES,
|
|
3632
3686
|
generateId,
|
|
3633
3687
|
isEmbeddedResource,
|
|
3688
|
+
isToolImageStub,
|
|
3634
3689
|
isToolOutputStub,
|
|
3635
3690
|
isVoiceLLMMode,
|
|
3636
3691
|
isVoicePolishMode,
|