@ragable/sdk 0.7.7 → 0.7.8
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.mts +183 -2
- package/dist/index.d.ts +183 -2
- package/dist/index.js +353 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +348 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2269,6 +2269,72 @@ function decodeJwtExpiry(jwt) {
|
|
|
2269
2269
|
}
|
|
2270
2270
|
}
|
|
2271
2271
|
|
|
2272
|
+
// src/partial-json.ts
|
|
2273
|
+
function tryParsePartialJson(text) {
|
|
2274
|
+
const trimmed = text.trim();
|
|
2275
|
+
if (!trimmed) return void 0;
|
|
2276
|
+
try {
|
|
2277
|
+
return JSON.parse(trimmed);
|
|
2278
|
+
} catch {
|
|
2279
|
+
}
|
|
2280
|
+
const repaired = repairOpenStructures(trimmed);
|
|
2281
|
+
if (!repaired) return void 0;
|
|
2282
|
+
try {
|
|
2283
|
+
return JSON.parse(repaired);
|
|
2284
|
+
} catch {
|
|
2285
|
+
const noTrailingComma = stripTrailingCommas(trimmed);
|
|
2286
|
+
const repaired2 = repairOpenStructures(noTrailingComma);
|
|
2287
|
+
if (!repaired2) return void 0;
|
|
2288
|
+
try {
|
|
2289
|
+
return JSON.parse(repaired2);
|
|
2290
|
+
} catch {
|
|
2291
|
+
return void 0;
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
function repairOpenStructures(text) {
|
|
2296
|
+
const first = text[0];
|
|
2297
|
+
if (first !== "{" && first !== "[") {
|
|
2298
|
+
return text;
|
|
2299
|
+
}
|
|
2300
|
+
const stack = [];
|
|
2301
|
+
let inString = false;
|
|
2302
|
+
let escaped = false;
|
|
2303
|
+
for (let i = 0; i < text.length; i++) {
|
|
2304
|
+
const ch = text[i];
|
|
2305
|
+
if (escaped) {
|
|
2306
|
+
escaped = false;
|
|
2307
|
+
continue;
|
|
2308
|
+
}
|
|
2309
|
+
if (ch === "\\") {
|
|
2310
|
+
escaped = true;
|
|
2311
|
+
continue;
|
|
2312
|
+
}
|
|
2313
|
+
if (ch === '"') {
|
|
2314
|
+
inString = !inString;
|
|
2315
|
+
continue;
|
|
2316
|
+
}
|
|
2317
|
+
if (inString) continue;
|
|
2318
|
+
if (ch === "{") stack.push("}");
|
|
2319
|
+
else if (ch === "[") stack.push("]");
|
|
2320
|
+
else if (ch === "}" || ch === "]") {
|
|
2321
|
+
if (stack.length === 0) return null;
|
|
2322
|
+
stack.pop();
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
let safe = text;
|
|
2326
|
+
if (inString) {
|
|
2327
|
+
safe += '"';
|
|
2328
|
+
}
|
|
2329
|
+
safe = safe.replace(/,\s*$/, "").replace(/:\s*$/, ": null");
|
|
2330
|
+
let suffix = "";
|
|
2331
|
+
for (let i = stack.length - 1; i >= 0; i--) suffix += stack[i];
|
|
2332
|
+
return safe + suffix;
|
|
2333
|
+
}
|
|
2334
|
+
function stripTrailingCommas(text) {
|
|
2335
|
+
return text.replace(/,(\s*[}\]])/g, "$1").replace(/,\s*$/, "");
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2272
2338
|
// src/stream-parts.ts
|
|
2273
2339
|
function normalizeFinishReason(raw) {
|
|
2274
2340
|
switch (raw) {
|
|
@@ -2478,7 +2544,7 @@ var ZERO_USAGE = {
|
|
|
2478
2544
|
completionTokens: 0,
|
|
2479
2545
|
totalTokens: 0
|
|
2480
2546
|
};
|
|
2481
|
-
function buildInferenceRequestBody(params) {
|
|
2547
|
+
function buildInferenceRequestBody(params, responseFormat) {
|
|
2482
2548
|
const body = {
|
|
2483
2549
|
model: params.model,
|
|
2484
2550
|
messages: params.messages
|
|
@@ -2489,8 +2555,18 @@ function buildInferenceRequestBody(params) {
|
|
|
2489
2555
|
if (typeof params.maxTokens === "number") body.max_tokens = params.maxTokens;
|
|
2490
2556
|
if (typeof params.topP === "number") body.top_p = params.topP;
|
|
2491
2557
|
if (params.reasoningEffort) body.reasoning_effort = params.reasoningEffort;
|
|
2558
|
+
if (responseFormat) body.response_format = responseFormat;
|
|
2492
2559
|
return body;
|
|
2493
2560
|
}
|
|
2561
|
+
function buildResponseFormat(params) {
|
|
2562
|
+
const json_schema = {
|
|
2563
|
+
name: params.name ?? "Output",
|
|
2564
|
+
schema: params.schema,
|
|
2565
|
+
strict: params.strict ?? true
|
|
2566
|
+
};
|
|
2567
|
+
if (params.description) json_schema.description = params.description;
|
|
2568
|
+
return { type: "json_schema", json_schema };
|
|
2569
|
+
}
|
|
2494
2570
|
async function consumeInferenceStream(body, broadcast, deferreds) {
|
|
2495
2571
|
const reader = body.getReader();
|
|
2496
2572
|
const decoder = new TextDecoder();
|
|
@@ -2741,6 +2817,190 @@ var RagableBrowserAiClient = class {
|
|
|
2741
2817
|
);
|
|
2742
2818
|
return { text, reasoning, usage, finishReason, toolCalls };
|
|
2743
2819
|
}
|
|
2820
|
+
/**
|
|
2821
|
+
* Stream a JSON-Schema-constrained response. Matches Vercel AI SDK's
|
|
2822
|
+
* `streamObject` shape — returns a synchronous result with `partialObjectStream`
|
|
2823
|
+
* (best-effort incremental parses) and `object` (the final parsed JSON).
|
|
2824
|
+
*
|
|
2825
|
+
* ```ts
|
|
2826
|
+
* const { partialObjectStream, object } = client.ai.streamObject({
|
|
2827
|
+
* model: "accounts/fireworks/models/kimi-k2p5",
|
|
2828
|
+
* schema: {
|
|
2829
|
+
* type: "object",
|
|
2830
|
+
* properties: {
|
|
2831
|
+
* title: { type: "string" },
|
|
2832
|
+
* tags: { type: "array", items: { type: "string" } },
|
|
2833
|
+
* },
|
|
2834
|
+
* required: ["title", "tags"],
|
|
2835
|
+
* },
|
|
2836
|
+
* messages: [{ role: "user", content: "Give me a blog post idea about AI." }],
|
|
2837
|
+
* });
|
|
2838
|
+
* for await (const partial of partialObjectStream) renderPreview(partial);
|
|
2839
|
+
* const final = await object;
|
|
2840
|
+
* ```
|
|
2841
|
+
*/
|
|
2842
|
+
streamObject(params) {
|
|
2843
|
+
return streamObjectFromContext(this.buildContext(), params);
|
|
2844
|
+
}
|
|
2845
|
+
/**
|
|
2846
|
+
* Non-streaming variant of {@link streamObject}. Resolves once the model
|
|
2847
|
+
* finishes; rejects if the final text isn't valid JSON for the schema.
|
|
2848
|
+
*/
|
|
2849
|
+
async generateObject(params) {
|
|
2850
|
+
const result = this.streamObject(params);
|
|
2851
|
+
for await (const _ of result.partialObjectStream) {
|
|
2852
|
+
void _;
|
|
2853
|
+
}
|
|
2854
|
+
const [object, usage, finishReason, toolCalls] = await Promise.all([
|
|
2855
|
+
result.object,
|
|
2856
|
+
result.usage,
|
|
2857
|
+
result.finishReason,
|
|
2858
|
+
result.toolCalls
|
|
2859
|
+
]);
|
|
2860
|
+
return { object, usage, finishReason, toolCalls };
|
|
2861
|
+
}
|
|
2862
|
+
};
|
|
2863
|
+
function streamObjectFromContext(ctx, params) {
|
|
2864
|
+
const textParams = {
|
|
2865
|
+
model: params.model,
|
|
2866
|
+
messages: params.messages,
|
|
2867
|
+
...params.system !== void 0 ? { system: params.system } : {},
|
|
2868
|
+
...typeof params.temperature === "number" ? { temperature: params.temperature } : {},
|
|
2869
|
+
...typeof params.maxTokens === "number" ? { maxTokens: params.maxTokens } : {},
|
|
2870
|
+
...typeof params.topP === "number" ? { topP: params.topP } : {},
|
|
2871
|
+
...params.signal !== void 0 ? { signal: params.signal } : {}
|
|
2872
|
+
};
|
|
2873
|
+
const responseFormat = buildResponseFormat({
|
|
2874
|
+
schema: params.schema,
|
|
2875
|
+
...params.schemaName !== void 0 ? { name: params.schemaName } : {},
|
|
2876
|
+
...params.schemaDescription !== void 0 ? { description: params.schemaDescription } : {}
|
|
2877
|
+
});
|
|
2878
|
+
const overrideCtx = {
|
|
2879
|
+
...ctx,
|
|
2880
|
+
// Wrap fetch to substitute the body. We can't change buildInferenceRequestBody
|
|
2881
|
+
// signature on the call site cleanly, so intercept here.
|
|
2882
|
+
fetch: ((input, init) => {
|
|
2883
|
+
if (init && typeof init.body === "string") {
|
|
2884
|
+
const parsed = JSON.parse(init.body);
|
|
2885
|
+
parsed.response_format = responseFormat;
|
|
2886
|
+
const newInit = { ...init, body: JSON.stringify(parsed) };
|
|
2887
|
+
return ctx.fetch(input, newInit);
|
|
2888
|
+
}
|
|
2889
|
+
return ctx.fetch(input, init);
|
|
2890
|
+
})
|
|
2891
|
+
};
|
|
2892
|
+
const inner = streamInferenceFromContext(overrideCtx, textParams);
|
|
2893
|
+
return wrapStreamTextAsObject(inner);
|
|
2894
|
+
}
|
|
2895
|
+
function wrapStreamTextAsObject(inner) {
|
|
2896
|
+
const partialBroadcast = new PartialObjectBroadcast();
|
|
2897
|
+
const objectDeferred = defer();
|
|
2898
|
+
void (async () => {
|
|
2899
|
+
let acc = "";
|
|
2900
|
+
let lastEmitted = /* @__PURE__ */ Symbol("none");
|
|
2901
|
+
try {
|
|
2902
|
+
for await (const delta of inner.textStream) {
|
|
2903
|
+
acc += delta;
|
|
2904
|
+
const candidate = tryParsePartialJson(acc);
|
|
2905
|
+
if (candidate !== void 0 && !sameSnapshot(candidate, lastEmitted)) {
|
|
2906
|
+
lastEmitted = candidate;
|
|
2907
|
+
partialBroadcast.push(candidate);
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
const finalText = await inner.text;
|
|
2911
|
+
let finalObj;
|
|
2912
|
+
try {
|
|
2913
|
+
finalObj = JSON.parse(finalText);
|
|
2914
|
+
} catch (e) {
|
|
2915
|
+
const err = new RagableError(
|
|
2916
|
+
`Model output is not valid JSON: ${e.message}`,
|
|
2917
|
+
502,
|
|
2918
|
+
{
|
|
2919
|
+
code: "SDK_OBJECT_PARSE_FAILED",
|
|
2920
|
+
raw: finalText.slice(0, 1e3)
|
|
2921
|
+
}
|
|
2922
|
+
);
|
|
2923
|
+
partialBroadcast.fail(err);
|
|
2924
|
+
objectDeferred.reject(err);
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2927
|
+
if (!sameSnapshot(finalObj, lastEmitted)) {
|
|
2928
|
+
partialBroadcast.push(finalObj);
|
|
2929
|
+
}
|
|
2930
|
+
partialBroadcast.end();
|
|
2931
|
+
objectDeferred.resolve(finalObj);
|
|
2932
|
+
} catch (err) {
|
|
2933
|
+
partialBroadcast.fail(err);
|
|
2934
|
+
objectDeferred.reject(err);
|
|
2935
|
+
}
|
|
2936
|
+
})();
|
|
2937
|
+
return {
|
|
2938
|
+
textStream: inner.textStream,
|
|
2939
|
+
partialObjectStream: partialBroadcast.consume(),
|
|
2940
|
+
object: objectDeferred.promise,
|
|
2941
|
+
text: inner.text,
|
|
2942
|
+
usage: inner.usage,
|
|
2943
|
+
finishReason: inner.finishReason,
|
|
2944
|
+
toolCalls: inner.toolCalls
|
|
2945
|
+
};
|
|
2946
|
+
}
|
|
2947
|
+
function sameSnapshot(a, b) {
|
|
2948
|
+
if (a === b) return true;
|
|
2949
|
+
try {
|
|
2950
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
2951
|
+
} catch {
|
|
2952
|
+
return false;
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
var PartialObjectBroadcast = class {
|
|
2956
|
+
constructor() {
|
|
2957
|
+
__publicField(this, "items", []);
|
|
2958
|
+
__publicField(this, "resolved", false);
|
|
2959
|
+
__publicField(this, "error", null);
|
|
2960
|
+
__publicField(this, "waiters", []);
|
|
2961
|
+
}
|
|
2962
|
+
push(item) {
|
|
2963
|
+
this.items.push(item);
|
|
2964
|
+
this.notify();
|
|
2965
|
+
}
|
|
2966
|
+
end() {
|
|
2967
|
+
if (this.resolved) return;
|
|
2968
|
+
this.resolved = true;
|
|
2969
|
+
this.notify();
|
|
2970
|
+
}
|
|
2971
|
+
fail(error) {
|
|
2972
|
+
if (this.resolved) return;
|
|
2973
|
+
this.error = error;
|
|
2974
|
+
this.resolved = true;
|
|
2975
|
+
this.notify();
|
|
2976
|
+
}
|
|
2977
|
+
notify() {
|
|
2978
|
+
const w = this.waiters;
|
|
2979
|
+
this.waiters = [];
|
|
2980
|
+
for (const fn of w) fn();
|
|
2981
|
+
}
|
|
2982
|
+
consume() {
|
|
2983
|
+
const self = this;
|
|
2984
|
+
return {
|
|
2985
|
+
[Symbol.asyncIterator]: () => {
|
|
2986
|
+
let idx = 0;
|
|
2987
|
+
return {
|
|
2988
|
+
next: async () => {
|
|
2989
|
+
while (true) {
|
|
2990
|
+
if (idx < self.items.length) {
|
|
2991
|
+
return { value: self.items[idx++], done: false };
|
|
2992
|
+
}
|
|
2993
|
+
if (self.resolved) {
|
|
2994
|
+
if (self.error) throw self.error;
|
|
2995
|
+
return { value: void 0, done: true };
|
|
2996
|
+
}
|
|
2997
|
+
await new Promise((res) => self.waiters.push(res));
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
};
|
|
3001
|
+
}
|
|
3002
|
+
};
|
|
3003
|
+
}
|
|
2744
3004
|
};
|
|
2745
3005
|
|
|
2746
3006
|
// src/browser.ts
|
|
@@ -3603,6 +3863,63 @@ var RagableBrowserAgentsClient = class {
|
|
|
3603
3863
|
const source = this.runStreamParts(agentName, params);
|
|
3604
3864
|
return createStreamResultFromParts(source);
|
|
3605
3865
|
}
|
|
3866
|
+
/**
|
|
3867
|
+
* Same agent, same tools/instructions/RAG — but constrain the final output
|
|
3868
|
+
* to a JSON Schema. Matches `client.ai.streamObject` exactly so callers can
|
|
3869
|
+
* swap between raw inference and an agent without changing call shape.
|
|
3870
|
+
*
|
|
3871
|
+
* Tool calling and structured output are **compatible**: the model may call
|
|
3872
|
+
* the agent's tools as usual; the final assistant message is the schema-
|
|
3873
|
+
* conformant JSON. The agent's `agents/<name>.json` is unchanged — whether
|
|
3874
|
+
* the run is conversational or structured is decided by the call site.
|
|
3875
|
+
*
|
|
3876
|
+
* ```ts
|
|
3877
|
+
* const { partialObjectStream, object } = client.agents.runObject<Plan>(
|
|
3878
|
+
* "planner",
|
|
3879
|
+
* {
|
|
3880
|
+
* messages: [{ role: "user", content: "Plan a 3-day trip to Kyoto." }],
|
|
3881
|
+
* schema: {
|
|
3882
|
+
* type: "object",
|
|
3883
|
+
* properties: {
|
|
3884
|
+
* days: {
|
|
3885
|
+
* type: "array",
|
|
3886
|
+
* items: { type: "object", properties: { date: { type: "string" }, activities: { type: "array", items: { type: "string" } } } },
|
|
3887
|
+
* },
|
|
3888
|
+
* },
|
|
3889
|
+
* required: ["days"],
|
|
3890
|
+
* },
|
|
3891
|
+
* },
|
|
3892
|
+
* );
|
|
3893
|
+
* for await (const p of partialObjectStream) renderPreview(p);
|
|
3894
|
+
* console.log(await object);
|
|
3895
|
+
* ```
|
|
3896
|
+
*/
|
|
3897
|
+
runObject(agentName, params) {
|
|
3898
|
+
const responseFormat = buildResponseFormat({
|
|
3899
|
+
schema: params.schema,
|
|
3900
|
+
...params.schemaName !== void 0 ? { name: params.schemaName } : {},
|
|
3901
|
+
...params.schemaDescription !== void 0 ? { description: params.schemaDescription } : {}
|
|
3902
|
+
});
|
|
3903
|
+
const sourceParts = this.runStreamParts(agentName, {
|
|
3904
|
+
messages: params.messages,
|
|
3905
|
+
...params.signal !== void 0 ? { signal: params.signal } : {},
|
|
3906
|
+
responseFormat
|
|
3907
|
+
});
|
|
3908
|
+
const inner = createStreamResultFromParts(sourceParts);
|
|
3909
|
+
return wrapStreamTextAsObject(inner);
|
|
3910
|
+
}
|
|
3911
|
+
/** Non-streaming variant of {@link runObject}. */
|
|
3912
|
+
async generateObject(agentName, params) {
|
|
3913
|
+
const result = this.runObject(agentName, params);
|
|
3914
|
+
for await (const _ of result.partialObjectStream) void _;
|
|
3915
|
+
const [object, usage, finishReason, toolCalls] = await Promise.all([
|
|
3916
|
+
result.object,
|
|
3917
|
+
result.usage,
|
|
3918
|
+
result.finishReason,
|
|
3919
|
+
result.toolCalls
|
|
3920
|
+
]);
|
|
3921
|
+
return { object, usage, finishReason, toolCalls };
|
|
3922
|
+
}
|
|
3606
3923
|
async *runStreamParts(agentName, params) {
|
|
3607
3924
|
const { messages } = params;
|
|
3608
3925
|
if (!Array.isArray(messages) || messages.length === 0) {
|
|
@@ -3624,12 +3941,33 @@ var RagableBrowserAgentsClient = class {
|
|
|
3624
3941
|
role: m.role,
|
|
3625
3942
|
content: m.content
|
|
3626
3943
|
}));
|
|
3627
|
-
const
|
|
3944
|
+
const headers = new Headers(this.options.headers);
|
|
3945
|
+
headers.set("Content-Type", "application/json");
|
|
3946
|
+
const body = {
|
|
3628
3947
|
message: last.content,
|
|
3629
3948
|
...history.length > 0 ? { history } : {},
|
|
3630
|
-
...params.
|
|
3631
|
-
}
|
|
3632
|
-
|
|
3949
|
+
...params.responseFormat ? { response_format: params.responseFormat } : {}
|
|
3950
|
+
};
|
|
3951
|
+
const response = await this.fetchImpl(
|
|
3952
|
+
this.toUrl(
|
|
3953
|
+
this.websiteAgentPath(
|
|
3954
|
+
`/agents/${encodeURIComponent(agentName)}/chat/stream`
|
|
3955
|
+
)
|
|
3956
|
+
),
|
|
3957
|
+
{
|
|
3958
|
+
method: "POST",
|
|
3959
|
+
headers,
|
|
3960
|
+
body: JSON.stringify(body),
|
|
3961
|
+
...params.signal !== void 0 ? { signal: params.signal } : {}
|
|
3962
|
+
}
|
|
3963
|
+
);
|
|
3964
|
+
if (!response.ok) {
|
|
3965
|
+
const payload = await parseMaybeJsonBody(response);
|
|
3966
|
+
const message = extractErrorMessage(payload, response.statusText);
|
|
3967
|
+
throw new RagableError(message, response.status, payload);
|
|
3968
|
+
}
|
|
3969
|
+
if (!response.body) return;
|
|
3970
|
+
for await (const event of readSseStream(response.body)) {
|
|
3633
3971
|
const mapped = mapAgentEvent(event);
|
|
3634
3972
|
if (mapped) yield mapped;
|
|
3635
3973
|
}
|
|
@@ -3866,6 +4204,7 @@ export {
|
|
|
3866
4204
|
assertPostgrestSuccess,
|
|
3867
4205
|
bindFetch,
|
|
3868
4206
|
buildInferenceRequestBody,
|
|
4207
|
+
buildResponseFormat,
|
|
3869
4208
|
collectAssistantTextFromUiSegments,
|
|
3870
4209
|
collectionRecordToRowWithMeta,
|
|
3871
4210
|
collectionRecordsToRowWithMeta,
|
|
@@ -3893,7 +4232,10 @@ export {
|
|
|
3893
4232
|
runAgentChatStream,
|
|
3894
4233
|
runAgentChatStreamForUi,
|
|
3895
4234
|
runAgentChatStreamLenient,
|
|
4235
|
+
streamObjectFromContext,
|
|
3896
4236
|
toRagableResult,
|
|
3897
|
-
|
|
4237
|
+
tryParsePartialJson,
|
|
4238
|
+
unwrapPostgrest,
|
|
4239
|
+
wrapStreamTextAsObject
|
|
3898
4240
|
};
|
|
3899
4241
|
//# sourceMappingURL=index.mjs.map
|